]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/start.c
2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "../config.h"
35 #include <sys/param.h>
37 #include <sys/mount.h>
38 #include <sys/types.h>
39 #include <sys/prctl.h>
40 #include <sys/capability.h>
45 #ifdef HAVE_SYS_SIGNALFD_H
46 # include <sys/signalfd.h>
48 # ifndef __NR_signalfd4
49 /* assume kernel headers are too old */
51 # define __NR_signalfd4 327
53 # define __NR_signalfd4 289
55 # define __NR_signalfd4 313
57 # define __NR_signalfd4 322
61 # ifndef __NR_signalfd
62 /* assume kernel headers are too old */
64 # define __NR_signalfd 321
66 # define __NR_signalfd 282
68 # define __NR_signalfd 305
70 # define __NR_signalfd 316
74 int signalfd(int fd
, const sigset_t
*mask
, int flags
)
78 retval
= syscall (__NR_signalfd4
, fd
, mask
, _NSIG
/ 8, flags
);
79 if (errno
== ENOSYS
&& flags
== 0)
80 retval
= syscall (__NR_signalfd
, fd
, mask
, _NSIG
/ 8);
85 #if !HAVE_DECL_PR_CAPBSET_DROP
86 #define PR_CAPBSET_DROP 24
95 LXC_TTY_HANDLER(SIGINT
);
96 LXC_TTY_HANDLER(SIGQUIT
);
98 static int setup_sigchld_fd(sigset_t
*oldmask
)
103 if (sigprocmask(SIG_BLOCK
, NULL
, &mask
)) {
104 lxc_log_syserror("failed to get mask signal");
108 if (sigaddset(&mask
, SIGCHLD
) || sigprocmask(SIG_BLOCK
, &mask
, oldmask
)) {
109 lxc_log_syserror("failed to set mask signal");
113 fd
= signalfd(-1, &mask
, 0);
115 lxc_log_syserror("failed to create the signal fd");
119 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
)) {
120 lxc_log_syserror("failed to set sigfd to close-on-exec");
128 static int setup_tty_service(const char *name
, int *ttyfd
)
131 struct sockaddr_un addr
= { 0 };
132 char *offset
= &addr
.sun_path
[1];
134 strcpy(offset
, name
);
135 addr
.sun_path
[0] = '\0';
137 fd
= lxc_af_unix_open(addr
.sun_path
, SOCK_STREAM
, 0);
141 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
)) {
142 lxc_log_syserror("failed to close-on-exec flag");
152 static int sigchld_handler(int fd
, void *data
,
153 struct lxc_epoll_descr
*descr
)
157 waitpid(*pid
, NULL
, 0);
162 static int ttyclient_handler(int fd
, void *data
,
163 struct lxc_epoll_descr
*descr
)
166 struct lxc_tty_info
*tty_info
= data
;
168 for (i
= 0; i
< tty_info
->nbtty
; i
++) {
170 if (tty_info
->pty_info
[i
].busy
!= fd
)
173 lxc_mainloop_del_handler(descr
, fd
);
174 tty_info
->pty_info
[i
].busy
= 0;
181 static int ttyservice_handler(int fd
, void *data
,
182 struct lxc_epoll_descr
*descr
)
184 int conn
, ttynum
, val
= 1, ret
= -1;
185 struct lxc_tty_info
*tty_info
= data
;
187 conn
= accept(fd
, NULL
, 0);
189 lxc_log_syserror("failed to accept tty client");
193 if (setsockopt(conn
, SOL_SOCKET
, SO_PASSCRED
, &val
, sizeof(val
))) {
194 lxc_log_syserror("failed to enable credential on socket");
198 if (lxc_af_unix_rcv_credential(conn
, &ttynum
, sizeof(ttynum
)))
201 if (ttynum
<= 0 || ttynum
> tty_info
->nbtty
)
204 /* fixup index array (eg. tty1 is index 0) */
207 if (tty_info
->pty_info
[ttynum
].busy
)
210 if (lxc_af_unix_send_fd(conn
, tty_info
->pty_info
[ttynum
].master
,
212 lxc_log_error("failed to send tty to client");
216 if (lxc_mainloop_add_handler(descr
, conn
,
217 ttyclient_handler
, tty_info
)) {
218 lxc_log_error("failed to add tty client handler");
222 tty_info
->pty_info
[ttynum
].busy
= conn
;
233 static int mainloop(const char *name
, pid_t pid
, int sigfd
,
234 const struct lxc_tty_info
*tty_info
)
236 int nfds
, ttyfd
= -1, ret
= -1;
237 struct lxc_epoll_descr descr
;
239 if (tty_info
->nbtty
&& setup_tty_service(name
, &ttyfd
)) {
240 lxc_log_error("failed to create the tty service point");
244 /* sigfd + nb tty + tty service
245 * if tty is enabled */
246 nfds
= tty_info
->nbtty
+ 1 + tty_info
->nbtty
? 1 : 0;
248 if (lxc_mainloop_open(nfds
, &descr
)) {
249 lxc_log_error("failed to create mainloop");
253 if (lxc_mainloop_add_handler(&descr
, sigfd
, sigchld_handler
, &pid
)) {
254 lxc_log_error("failed to add handler for the signal");
255 goto out_mainloop_open
;
258 if (tty_info
->nbtty
) {
259 if (lxc_mainloop_add_handler(&descr
, ttyfd
,
262 lxc_log_error("failed to add handler for the tty");
263 goto out_mainloop_open
;
267 ret
= lxc_mainloop(&descr
);
273 lxc_mainloop_close(&descr
);
281 int lxc_start(const char *name
, char *argv
[])
283 struct lxc_tty_info tty_info
= { 0 };
285 char init
[MAXPATHLEN
];
286 char tty
[MAXPATHLEN
];
288 int fd
, sigfd
, lock
, sv
[2], sync
= 0, err
= -LXC_ERROR_INTERNAL
;
292 lock
= lxc_get_lock(name
);
296 /* Begin the set the state to STARTING*/
297 if (lxc_setstate(name
, STARTING
)) {
298 lxc_log_error("failed to set state '%s'",
299 lxc_state2str(STARTING
));
303 /* If we are not attached to a tty, disable it */
304 if (ttyname_r(0, tty
, sizeof(tty
)))
307 if (lxc_create_tty(name
, &tty_info
)) {
308 lxc_log_error("failed to create the ttys");
312 /* the signal fd has to be created before forking otherwise
313 * if the child process exits before we setup the signal fd,
314 * the event will be lost and the command will be stuck */
315 sigfd
= setup_sigchld_fd(&oldmask
);
317 lxc_log_error("failed to set sigchild fd handler");
321 /* Synchro socketpair */
322 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, sv
)) {
323 lxc_log_syserror("failed to create communication socketpair");
327 /* Avoid signals from terminal */
328 LXC_TTY_ADD_HANDLER(SIGINT
);
329 LXC_TTY_ADD_HANDLER(SIGQUIT
);
331 clone_flags
= CLONE_NEWPID
|CLONE_NEWIPC
|CLONE_NEWNS
;
332 if (conf_has_utsname(name
))
333 clone_flags
|= CLONE_NEWUTS
;
334 if (conf_has_network(name
))
335 clone_flags
|= CLONE_NEWNET
;
337 /* Create a process in a new set of namespaces */
338 pid
= fork_ns(clone_flags
);
340 lxc_log_syserror("failed to fork into a new namespace");
346 if (sigprocmask(SIG_SETMASK
, &oldmask
, NULL
)) {
347 lxc_log_syserror("failed to set sigprocmask");
353 /* Be sure we don't inherit this after the exec */
354 fcntl(sv
[0], F_SETFD
, FD_CLOEXEC
);
356 /* Tell our father he can begin to configure the container */
357 if (write(sv
[0], &sync
, sizeof(sync
)) < 0) {
358 lxc_log_syserror("failed to write socket");
362 /* Wait for the father to finish the configuration */
363 if (read(sv
[0], &sync
, sizeof(sync
)) < 0) {
364 lxc_log_syserror("failed to read socket");
368 /* Setup the container, ip, names, utsname, ... */
369 err
= lxc_setup(name
, tty
, &tty_info
);
371 lxc_log_error("failed to setup the container");
372 if (write(sv
[0], &err
, sizeof(err
)) < 0)
373 lxc_log_syserror("failed to write the socket");
377 if (prctl(PR_CAPBSET_DROP
, CAP_SYS_BOOT
, 0, 0, 0)) {
378 lxc_log_syserror("failed to remove CAP_SYS_BOOT capability");
382 execvp(argv
[0], argv
);
383 lxc_log_syserror("failed to exec %s", argv
[0]);
385 err
= LXC_ERROR_WRONG_COMMAND
;
386 /* If the exec fails, tell that to our father */
387 if (write(sv
[0], &err
, sizeof(err
)) < 0)
388 lxc_log_syserror("failed to write the socket");
396 /* Wait for the child to be ready */
397 if (read(sv
[1], &sync
, sizeof(sync
)) < 0) {
398 lxc_log_syserror("failed to read the socket");
402 if (lxc_link_nsgroup(name
, pid
))
403 lxc_log_warning("cgroupfs not found: cgroup disabled");
405 /* Create the network configuration */
406 if (clone_flags
& CLONE_NEWNET
&& conf_create_network(name
, pid
)) {
407 lxc_log_error("failed to create the configured network");
408 goto err_create_network
;
411 /* Tell the child to continue its initialization */
412 if (write(sv
[1], &sync
, sizeof(sync
)) < 0) {
413 lxc_log_syserror("failed to write the socket");
417 /* Wait for the child to exec or returning an error */
418 err
= read(sv
[1], &sync
, sizeof(sync
));
420 lxc_log_error("failed to read the socket");
426 waitpid(pid
, NULL
, 0);
427 goto err_child_failed
;
430 asprintf(&val
, "%d\n", pid
);
432 snprintf(init
, MAXPATHLEN
, LXCPATH
"/%s/init", name
);
434 fd
= open(init
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
);
436 lxc_log_syserror("failed to open '%s'", init
);
440 if (write(fd
, val
, strlen(val
)) < 0) {
441 lxc_log_syserror("failed to write the init pid");
447 if (lxc_setstate(name
, RUNNING
)) {
448 lxc_log_error("failed to set state to %s",
449 lxc_state2str(RUNNING
));
450 goto err_state_failed
;
453 if (mainloop(name
, pid
, sigfd
, &tty_info
)) {
454 lxc_log_error("mainloop exited with an error");
455 goto err_mailoop_failed
;
458 if (lxc_setstate(name
, STOPPING
))
459 lxc_log_error("failed to set state %s", lxc_state2str(STOPPING
));
461 if (clone_flags
& CLONE_NEWNET
&& conf_destroy_network(name
))
462 lxc_log_error("failed to destroy the network");
466 if (lxc_setstate(name
, STOPPED
))
467 lxc_log_error("failed to set state %s", lxc_state2str(STOPPED
));
469 lxc_delete_tty(&tty_info
);
470 lxc_unlink_nsgroup(name
);
474 LXC_TTY_DEL_HANDLER(SIGQUIT
);
475 LXC_TTY_DEL_HANDLER(SIGINT
);
486 if (clone_flags
& CLONE_NEWNET
)
487 conf_destroy_network(name
);
491 if (lxc_setstate(name
, ABORTING
))
492 lxc_log_error("failed to set state %s", lxc_state2str(STOPPED
));