]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_start.c
b1b3ca5da2a5359c2111d386c5914b80677ec40f
[mirror_lxc.git] / src / lxc / tools / lxc_start.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "config.h"
4
5 #include <arpa/inet.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <libgen.h>
9 #include <net/if.h>
10 #include <netinet/in.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/param.h>
16 #include <sys/socket.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <sys/utsname.h>
20 #include <unistd.h>
21
22 #include "lxc.h"
23
24 #include "arguments.h"
25 #include "caps.h"
26 #include "confile.h"
27 #include "log.h"
28
29 lxc_log_define(lxc_start, lxc);
30
31 static int my_parser(struct lxc_arguments *args, int c, char *arg);
32 static int ensure_path(char **confpath, const char *path);
33
34 static struct lxc_list defines;
35
36 static const struct option my_longopts[] = {
37 {"daemon", no_argument, 0, 'd'},
38 {"foreground", no_argument, 0, 'F'},
39 {"rcfile", required_argument, 0, 'f'},
40 {"define", required_argument, 0, 's'},
41 {"console", required_argument, 0, 'c'},
42 {"console-log", required_argument, 0, 'L'},
43 {"close-all-fds", no_argument, 0, 'C'},
44 {"pidfile", required_argument, 0, 'p'},
45 {"share-net", required_argument, 0, OPT_SHARE_NET},
46 {"share-ipc", required_argument, 0, OPT_SHARE_IPC},
47 {"share-uts", required_argument, 0, OPT_SHARE_UTS},
48 {"share-pid", required_argument, 0, OPT_SHARE_PID},
49 LXC_COMMON_OPTIONS
50 };
51
52 static struct lxc_arguments my_args = {
53 .progname = "lxc-start",
54 .help = "\
55 --name=NAME -- COMMAND\n\
56 \n\
57 lxc-start start COMMAND in specified container NAME\n\
58 \n\
59 Options :\n\
60 -n, --name=NAME NAME of the container\n\
61 -d, --daemon Daemonize the container (default)\n\
62 -F, --foreground Start with the current tty attached to /dev/console\n\
63 -p, --pidfile=FILE Create a file with the process id\n\
64 -f, --rcfile=FILE Load configuration file FILE\n\
65 -c, --console=FILE Use specified FILE for the container console\n\
66 -L, --console-log=FILE Log container console output to FILE\n\
67 -C, --close-all-fds If any fds are inherited, close them\n\
68 Note: --daemon implies --close-all-fds\n\
69 -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
70 --share-[net|ipc|uts|pid]=NAME Share a namespace with another container or pid\n\
71 ",
72 .options = my_longopts,
73 .parser = my_parser,
74 .checker = NULL,
75 .log_priority = "ERROR",
76 .log_file = "none",
77 .daemonize = 1,
78 .pidfile = NULL,
79 };
80
81 static int my_parser(struct lxc_arguments *args, int c, char *arg)
82 {
83 switch (c) {
84 case 'c':
85 args->console = arg;
86 break;
87 case 'L':
88 args->console_log = arg;
89 break;
90 case 'd':
91 args->daemonize = 1;
92 break;
93 case 'F':
94 args->daemonize = 0;
95 break;
96 case 'f':
97 args->rcfile = arg;
98 break;
99 case 'C':
100 args->close_all_fds = true;
101 break;
102 case 's':
103 return lxc_config_define_add(&defines, arg);
104 case 'p':
105 args->pidfile = arg;
106 break;
107 case OPT_SHARE_NET:
108 args->share_ns[LXC_NS_NET] = arg;
109 break;
110 case OPT_SHARE_IPC:
111 args->share_ns[LXC_NS_IPC] = arg;
112 break;
113 case OPT_SHARE_UTS:
114 args->share_ns[LXC_NS_UTS] = arg;
115 break;
116 case OPT_SHARE_PID:
117 args->share_ns[LXC_NS_PID] = arg;
118 break;
119 }
120 return 0;
121 }
122
123 static int ensure_path(char **confpath, const char *path)
124 {
125 int fd;
126 char *fullpath = NULL;
127
128 if (path) {
129 if (access(path, W_OK)) {
130 fd = creat(path, 0600);
131 if (fd < 0 && errno != EEXIST) {
132 ERROR("Failed to create '%s'", path);
133 return -1;
134 }
135
136 if (fd >= 0)
137 close(fd);
138 }
139
140 fullpath = realpath(path, NULL);
141 if (!fullpath) {
142 ERROR("Failed to get the real path of '%s'", path);
143 return -1;
144 }
145
146 *confpath = fullpath;
147 }
148
149 return 0;
150 }
151
152 int __attribute__((weak, alias("lxc_start_main"))) main(int argc, char *argv[]);
153 int lxc_start_main(int argc, char *argv[])
154 {
155 const char *lxcpath;
156 char *const *args;
157 struct lxc_container *c;
158 struct lxc_log log;
159 int err = EXIT_FAILURE;
160 char *rcfile = NULL;
161 char *const default_args[] = {
162 "/sbin/init",
163 NULL,
164 };
165
166 lxc_list_init(&defines);
167
168 if (lxc_caps_init())
169 exit(err);
170
171 if (lxc_arguments_parse(&my_args, argc, argv))
172 exit(err);
173
174 if (!my_args.argc)
175 args = default_args;
176 else
177 args = my_args.argv;
178
179 log.name = my_args.name;
180 log.file = my_args.log_file;
181 log.level = my_args.log_priority;
182 log.prefix = my_args.progname;
183 log.quiet = my_args.quiet;
184 log.lxcpath = my_args.lxcpath[0];
185
186 if (lxc_log_init(&log))
187 exit(err);
188
189 lxcpath = my_args.lxcpath[0];
190 if (access(lxcpath, O_RDONLY) < 0) {
191 ERROR("You lack access to %s", lxcpath);
192 exit(err);
193 }
194
195 /*
196 * rcfile possibilities:
197 * 1. rcfile from random path specified in cli option
198 * 2. rcfile not specified, use $lxcpath/$lxcname/config
199 * 3. rcfile not specified and does not exist.
200 */
201 /* rcfile is specified in the cli option */
202 if (my_args.rcfile) {
203 rcfile = (char *)my_args.rcfile;
204
205 c = lxc_container_new(my_args.name, lxcpath);
206 if (!c) {
207 ERROR("Failed to create lxc_container");
208 exit(err);
209 }
210
211 c->clear_config(c);
212
213 if (!c->load_config(c, rcfile)) {
214 ERROR("Failed to load rcfile");
215 lxc_container_put(c);
216 exit(err);
217 }
218
219 c->configfile = strdup(my_args.rcfile);
220 if (!c->configfile) {
221 ERROR("Out of memory setting new config filename");
222 goto out;
223 }
224 } else {
225 int rc;
226
227 rc = asprintf(&rcfile, "%s/%s/config", lxcpath, my_args.name);
228 if (rc == -1) {
229 ERROR("Failed to allocate memory");
230 exit(err);
231 }
232
233 /* container configuration does not exist */
234 if (access(rcfile, F_OK)) {
235 free(rcfile);
236 rcfile = NULL;
237 }
238
239 c = lxc_container_new(my_args.name, lxcpath);
240 if (!c) {
241 ERROR("Failed to create lxc_container");
242 exit(err);
243 }
244 }
245
246 /* We do not check here whether the container is defined, because we
247 * support volatile containers. Which means the container does not need
248 * to be created for it to be started. You can just pass a configuration
249 * file as argument and start the container right away.
250 */
251 if (!c->may_control(c)) {
252 ERROR("Insufficent privileges to control %s", c->name);
253 goto out;
254 }
255
256 if (c->is_running(c)) {
257 ERROR("Container is already running");
258 err = EXIT_SUCCESS;
259 goto out;
260 }
261
262 /*
263 * We should use set_config_item() over &defines, which would handle
264 * unset c->lxc_conf for us and let us not use lxc_config_define_load()
265 */
266 if (!c->lxc_conf) {
267 ERROR("No container config specified");
268 goto out;
269 }
270
271 if (!lxc_config_define_load(&defines, c))
272 goto out;
273
274 if (!rcfile && !strcmp("/sbin/init", args[0])) {
275 ERROR("Executing '/sbin/init' with no configuration file may crash the host");
276 goto out;
277 }
278
279 if (my_args.pidfile)
280 if (ensure_path(&c->pidfile, my_args.pidfile) < 0) {
281 ERROR("Failed to ensure pidfile '%s'", my_args.pidfile);
282 goto out;
283 }
284
285 if (my_args.console)
286 if (!c->set_config_item(c, "lxc.console.path", my_args.console))
287 goto out;
288
289 if (my_args.console_log)
290 if (!c->set_config_item(c, "lxc.console.logfile", my_args.console_log))
291 goto out;
292
293 if (!lxc_setup_shared_ns(&my_args, c))
294 goto out;
295
296 if (!my_args.daemonize)
297 c->want_daemonize(c, false);
298
299 if (my_args.close_all_fds)
300 c->want_close_all_fds(c, true);
301
302 if (args == default_args)
303 err = c->start(c, 0, NULL) ? EXIT_SUCCESS : EXIT_FAILURE;
304 else
305 err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE;
306 if (err) {
307 ERROR("The container failed to start");
308
309 if (my_args.daemonize)
310 ERROR("To get more details, run the container in foreground mode");
311
312 ERROR("Additional information can be obtained by setting the "
313 "--logfile and --logpriority options");
314
315 err = c->error_num;
316 lxc_container_put(c);
317 exit(err);
318 }
319
320 out:
321 lxc_container_put(c);
322 exit(err);
323 }