1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
26 #include <sys/syscall.h>
27 #include <sys/mount.h>
33 #include <sys/prctl.h>
34 #include <sys/capability.h>
36 #include <sys/epoll.h>
38 #include <sys/signalfd.h>
42 #include <sys/socket.h>
44 #include <systemd/sd-daemon.h>
51 #include "cgroup-util.h"
53 #include "loopback-setup.h"
55 static char *arg_directory
= NULL
;
56 static char *arg_user
= NULL
;
57 static char **arg_controllers
= NULL
;
58 static bool arg_private_network
= false;
59 static bool arg_boot
= false;
61 static int help(void) {
63 printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
64 "Spawn a minimal namespace container for debugging, testing and building.\n\n"
65 " -h --help Show this help\n"
66 " -D --directory=NAME Root directory for the container\n"
67 " -b --boot Boot up full system (i.e. invoke init)\n"
68 " -u --user=USER Run the command under specified user or uid\n"
69 " -C --controllers=LIST Put the container in specified comma-separated cgroup hierarchies\n"
70 " --private-network Disable network in container\n",
71 program_invocation_short_name
);
76 static int parse_argv(int argc
, char *argv
[]) {
79 ARG_PRIVATE_NETWORK
= 0x100
82 static const struct option options
[] = {
83 { "help", no_argument
, NULL
, 'h' },
84 { "directory", required_argument
, NULL
, 'D' },
85 { "user", required_argument
, NULL
, 'u' },
86 { "controllers", required_argument
, NULL
, 'C' },
87 { "private-network", no_argument
, NULL
, ARG_PRIVATE_NETWORK
},
88 { "boot", no_argument
, NULL
, 'b' },
97 while ((c
= getopt_long(argc
, argv
, "+hD:u:C:b", options
, NULL
)) >= 0) {
107 arg_directory
= canonicalize_file_name(optarg
);
108 if (!arg_directory
) {
109 log_error("Failed to canonicalize root directory.");
117 if (!(arg_user
= strdup(optarg
))) {
118 log_error("Failed to duplicate user name.");
125 strv_free(arg_controllers
);
126 arg_controllers
= strv_split(optarg
, ",");
127 if (!arg_controllers
) {
128 log_error("Failed to split controllers list.");
131 strv_uniq(arg_controllers
);
135 case ARG_PRIVATE_NETWORK
:
136 arg_private_network
= true;
147 log_error("Unknown option code %c", c
);
155 static int mount_all(const char *dest
) {
157 typedef struct MountPoint
{
166 static const MountPoint mount_table
[] = {
167 { "proc", "/proc", "proc", NULL
, MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, true },
168 { "/proc/sys", "/proc/sys", "bind", NULL
, MS_BIND
, true }, /* Bind mount first */
169 { "/proc/sys", "/proc/sys", "bind", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, true }, /* Then, make it r/o */
170 { "/sys", "/sys", "bind", NULL
, MS_BIND
, true }, /* Bind mount first */
171 { "/sys", "/sys", "bind", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, true }, /* Then, make it r/o */
172 { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID
|MS_STRICTATIME
, true },
173 { "/dev/pts", "/dev/pts", "bind", NULL
, MS_BIND
, true },
174 { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID
|MS_NODEV
|MS_STRICTATIME
, true },
176 { "/sys/fs/selinux", "/sys/fs/selinux", "bind", NULL
, MS_BIND
, false }, /* Bind mount first */
177 { "/sys/fs/selinux", "/sys/fs/selinux", "bind", NULL
, MS_BIND
|MS_RDONLY
|MS_REMOUNT
, false }, /* Then, make it r/o */
185 for (k
= 0; k
< ELEMENTSOF(mount_table
); k
++) {
188 if (asprintf(&where
, "%s/%s", dest
, mount_table
[k
].where
) < 0) {
189 log_error("Out of memory");
197 t
= path_is_mount_point(where
, false);
199 log_error("Failed to detect whether %s is a mount point: %s", where
, strerror(-t
));
208 mkdir_p(where
, 0755);
210 if (mount(mount_table
[k
].what
,
213 mount_table
[k
].flags
,
214 mount_table
[k
].options
) < 0 &&
215 mount_table
[k
].fatal
) {
217 log_error("mount(%s) failed: %m", where
);
229 static int setup_timezone(const char *dest
) {
234 /* Fix the timezone, if possible */
235 if (asprintf(&where
, "%s/etc/localtime", dest
) < 0) {
236 log_error("Out of memory");
240 if (mount("/etc/localtime", where
, "bind", MS_BIND
, NULL
) >= 0)
241 mount("/etc/localtime", where
, "bind", MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
);
245 if (asprintf(&where
, "%s/etc/timezone", dest
) < 0) {
246 log_error("Out of memory");
250 if (mount("/etc/timezone", where
, "bind", MS_BIND
, NULL
) >= 0)
251 mount("/etc/timezone", where
, "bind", MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
);
258 static int copy_devnodes(const char *dest
) {
260 static const char devnodes
[] =
278 NULSTR_FOREACH(d
, devnodes
) {
280 char *from
= NULL
, *to
= NULL
;
282 asprintf(&from
, "/dev/%s", d
);
283 asprintf(&to
, "%s/dev/%s", dest
, d
);
286 log_error("Failed to allocate devnode path");
299 if (stat(from
, &st
) < 0) {
301 if (errno
!= ENOENT
) {
302 log_error("Failed to stat %s: %m", from
);
307 } else if (!S_ISCHR(st
.st_mode
) && !S_ISBLK(st
.st_mode
)) {
309 log_error("%s is not a char or block device, cannot copy.", from
);
313 } else if (mknod(to
, st
.st_mode
, st
.st_rdev
) < 0) {
315 log_error("mknod(%s) failed: %m", dest
);
329 static int setup_dev_console(const char *dest
, const char *console
) {
340 if (stat(console
, &st
) < 0) {
341 log_error("Failed to stat %s: %m", console
);
345 } else if (!S_ISCHR(st
.st_mode
)) {
346 log_error("/dev/console is not a char device.");
351 r
= chmod_and_chown(console
, 0600, 0, 0);
353 log_error("Failed to correct access mode for TTY: %s", strerror(-r
));
357 if (asprintf(&to
, "%s/dev/console", dest
) < 0) {
358 log_error("Out of memory");
363 /* We need to bind mount the right tty to /dev/console since
364 * ptys can only exist on pts file systems. To have something
365 * to bind mount things on we create a device node first, that
366 * has the right major/minor (note that the major minor
367 * doesn't actually matter here, since we mount it over
370 if (mknod(to
, (st
.st_mode
& ~07777) | 0600, st
.st_rdev
) < 0) {
371 log_error("mknod() for /dev/console failed: %m");
376 if (mount(console
, to
, "bind", MS_BIND
, NULL
) < 0) {
377 log_error("Bind mount for /dev/console failed: %m");
389 static int setup_kmsg(const char *dest
, int kmsg_socket
) {
390 char *from
= NULL
, *to
= NULL
;
394 struct cmsghdr cmsghdr
;
395 uint8_t buf
[CMSG_SPACE(sizeof(int))];
398 struct cmsghdr
*cmsg
;
401 assert(kmsg_socket
>= 0);
405 /* We create the kmsg FIFO as /dev/kmsg, but immediately
406 * delete it after bind mounting it to /proc/kmsg. While FIFOs
407 * on the reading side behave very similar to /proc/kmsg,
408 * their writing side behaves differently from /dev/kmsg in
409 * that writing blocks when nothing is reading. In order to
410 * avoid any problems with containers deadlocking due to this
411 * we simply make /dev/kmsg unavailable to the container. */
412 if (asprintf(&from
, "%s/dev/kmsg", dest
) < 0) {
413 log_error("Out of memory");
418 if (asprintf(&to
, "%s/proc/kmsg", dest
) < 0) {
419 log_error("Out of memory");
424 if (mkfifo(from
, 0600) < 0) {
425 log_error("mkfifo() for /dev/kmsg failed: %m");
430 r
= chmod_and_chown(from
, 0600, 0, 0);
432 log_error("Failed to correct access mode for /dev/kmsg: %s", strerror(-r
));
436 if (mount(from
, to
, "bind", MS_BIND
, NULL
) < 0) {
437 log_error("Bind mount for /proc/kmsg failed: %m");
442 fd
= open(from
, O_RDWR
|O_NDELAY
|O_CLOEXEC
);
444 log_error("Failed to open fifo: %m");
452 mh
.msg_control
= &control
;
453 mh
.msg_controllen
= sizeof(control
);
455 cmsg
= CMSG_FIRSTHDR(&mh
);
456 cmsg
->cmsg_level
= SOL_SOCKET
;
457 cmsg
->cmsg_type
= SCM_RIGHTS
;
458 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
459 memcpy(CMSG_DATA(cmsg
), &fd
, sizeof(int));
461 mh
.msg_controllen
= cmsg
->cmsg_len
;
463 /* Store away the fd in the socket, so that it stays open as
464 * long as we run the child */
465 k
= sendmsg(kmsg_socket
, &mh
, MSG_DONTWAIT
|MSG_NOSIGNAL
);
466 close_nointr_nofail(fd
);
469 log_error("Failed to send FIFO fd: %m");
474 /* And now make the FIFO unavailable as /dev/kmsg... */
485 static int setup_hostname(void) {
489 hn
= file_name_from_path(arg_directory
);
495 hostname_cleanup(hn
);
498 if (sethostname(hn
, strlen(hn
)) < 0)
507 static int drop_capabilities(void) {
508 static const unsigned long retain
[] = {
518 CAP_NET_BIND_SERVICE
,
534 for (l
= 0; l
<= cap_last_cap(); l
++) {
537 for (i
= 0; i
< ELEMENTSOF(retain
); i
++)
541 if (i
< ELEMENTSOF(retain
))
544 if (prctl(PR_CAPBSET_DROP
, l
) < 0) {
545 log_error("PR_CAPBSET_DROP failed: %m");
553 static int is_os_tree(const char *path
) {
556 /* We use /bin/sh as flag file if something is an OS */
558 if (asprintf(&p
, "%s/bin/sh", path
) < 0)
564 return r
< 0 ? 0 : 1;
567 static int process_pty(int master
, sigset_t
*mask
) {
569 char in_buffer
[LINE_MAX
], out_buffer
[LINE_MAX
];
570 size_t in_buffer_full
= 0, out_buffer_full
= 0;
571 struct epoll_event stdin_ev
, stdout_ev
, master_ev
, signal_ev
;
572 bool stdin_readable
= false, stdout_writable
= false, master_readable
= false, master_writable
= false;
573 int ep
= -1, signal_fd
= -1, r
;
575 fd_nonblock(STDIN_FILENO
, 1);
576 fd_nonblock(STDOUT_FILENO
, 1);
577 fd_nonblock(master
, 1);
579 if ((signal_fd
= signalfd(-1, mask
, SFD_NONBLOCK
|SFD_CLOEXEC
)) < 0) {
580 log_error("signalfd(): %m");
585 if ((ep
= epoll_create1(EPOLL_CLOEXEC
)) < 0) {
586 log_error("Failed to create epoll: %m");
592 stdin_ev
.events
= EPOLLIN
|EPOLLET
;
593 stdin_ev
.data
.fd
= STDIN_FILENO
;
596 stdout_ev
.events
= EPOLLOUT
|EPOLLET
;
597 stdout_ev
.data
.fd
= STDOUT_FILENO
;
600 master_ev
.events
= EPOLLIN
|EPOLLOUT
|EPOLLET
;
601 master_ev
.data
.fd
= master
;
604 signal_ev
.events
= EPOLLIN
;
605 signal_ev
.data
.fd
= signal_fd
;
607 if (epoll_ctl(ep
, EPOLL_CTL_ADD
, STDIN_FILENO
, &stdin_ev
) < 0 ||
608 epoll_ctl(ep
, EPOLL_CTL_ADD
, STDOUT_FILENO
, &stdout_ev
) < 0 ||
609 epoll_ctl(ep
, EPOLL_CTL_ADD
, master
, &master_ev
) < 0 ||
610 epoll_ctl(ep
, EPOLL_CTL_ADD
, signal_fd
, &signal_ev
) < 0) {
611 log_error("Failed to regiser fds in epoll: %m");
617 struct epoll_event ev
[16];
621 if ((nfds
= epoll_wait(ep
, ev
, ELEMENTSOF(ev
), -1)) < 0) {
623 if (errno
== EINTR
|| errno
== EAGAIN
)
626 log_error("epoll_wait(): %m");
633 for (i
= 0; i
< nfds
; i
++) {
634 if (ev
[i
].data
.fd
== STDIN_FILENO
) {
636 if (ev
[i
].events
& (EPOLLIN
|EPOLLHUP
))
637 stdin_readable
= true;
639 } else if (ev
[i
].data
.fd
== STDOUT_FILENO
) {
641 if (ev
[i
].events
& (EPOLLOUT
|EPOLLHUP
))
642 stdout_writable
= true;
644 } else if (ev
[i
].data
.fd
== master
) {
646 if (ev
[i
].events
& (EPOLLIN
|EPOLLHUP
))
647 master_readable
= true;
649 if (ev
[i
].events
& (EPOLLOUT
|EPOLLHUP
))
650 master_writable
= true;
652 } else if (ev
[i
].data
.fd
== signal_fd
) {
653 struct signalfd_siginfo sfsi
;
656 if ((n
= read(signal_fd
, &sfsi
, sizeof(sfsi
))) != sizeof(sfsi
)) {
659 log_error("Failed to read from signalfd: invalid block size");
664 if (errno
!= EINTR
&& errno
!= EAGAIN
) {
665 log_error("Failed to read from signalfd: %m");
671 if (sfsi
.ssi_signo
== SIGWINCH
) {
674 /* The window size changed, let's forward that. */
675 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) >= 0)
676 ioctl(master
, TIOCSWINSZ
, &ws
);
685 while ((stdin_readable
&& in_buffer_full
<= 0) ||
686 (master_writable
&& in_buffer_full
> 0) ||
687 (master_readable
&& out_buffer_full
<= 0) ||
688 (stdout_writable
&& out_buffer_full
> 0)) {
690 if (stdin_readable
&& in_buffer_full
< LINE_MAX
) {
692 if ((k
= read(STDIN_FILENO
, in_buffer
+ in_buffer_full
, LINE_MAX
- in_buffer_full
)) < 0) {
694 if (errno
== EAGAIN
|| errno
== EPIPE
|| errno
== ECONNRESET
|| errno
== EIO
)
695 stdin_readable
= false;
697 log_error("read(): %m");
702 in_buffer_full
+= (size_t) k
;
705 if (master_writable
&& in_buffer_full
> 0) {
707 if ((k
= write(master
, in_buffer
, in_buffer_full
)) < 0) {
709 if (errno
== EAGAIN
|| errno
== EPIPE
|| errno
== ECONNRESET
|| errno
== EIO
)
710 master_writable
= false;
712 log_error("write(): %m");
718 assert(in_buffer_full
>= (size_t) k
);
719 memmove(in_buffer
, in_buffer
+ k
, in_buffer_full
- k
);
724 if (master_readable
&& out_buffer_full
< LINE_MAX
) {
726 if ((k
= read(master
, out_buffer
+ out_buffer_full
, LINE_MAX
- out_buffer_full
)) < 0) {
728 if (errno
== EAGAIN
|| errno
== EPIPE
|| errno
== ECONNRESET
|| errno
== EIO
)
729 master_readable
= false;
731 log_error("read(): %m");
736 out_buffer_full
+= (size_t) k
;
739 if (stdout_writable
&& out_buffer_full
> 0) {
741 if ((k
= write(STDOUT_FILENO
, out_buffer
, out_buffer_full
)) < 0) {
743 if (errno
== EAGAIN
|| errno
== EPIPE
|| errno
== ECONNRESET
|| errno
== EIO
)
744 stdout_writable
= false;
746 log_error("write(): %m");
752 assert(out_buffer_full
>= (size_t) k
);
753 memmove(out_buffer
, out_buffer
+ k
, out_buffer_full
- k
);
754 out_buffer_full
-= k
;
762 close_nointr_nofail(ep
);
765 close_nointr_nofail(signal_fd
);
770 int main(int argc
, char *argv
[]) {
772 int r
= EXIT_FAILURE
, k
;
773 char *oldcg
= NULL
, *newcg
= NULL
;
774 char **controller
= NULL
;
776 const char *console
= NULL
;
777 struct termios saved_attr
, raw_attr
;
779 bool saved_attr_valid
= false;
781 int kmsg_socket_pair
[2] = { -1, -1 };
783 log_parse_environment();
786 if ((r
= parse_argv(argc
, argv
)) <= 0)
792 p
= path_make_absolute_cwd(arg_directory
);
796 arg_directory
= get_current_dir_name();
798 if (!arg_directory
) {
799 log_error("Failed to determine path");
803 path_kill_slashes(arg_directory
);
805 if (geteuid() != 0) {
806 log_error("Need to be root.");
810 if (sd_booted() <= 0) {
811 log_error("Not running on a systemd system.");
815 if (path_equal(arg_directory
, "/")) {
816 log_error("Spawning container on root directory not supported.");
820 if (is_os_tree(arg_directory
) <= 0) {
821 log_error("Directory %s doesn't look like an OS root directory. Refusing.", arg_directory
);
825 if ((k
= cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER
, 0, &oldcg
)) < 0) {
826 log_error("Failed to determine current cgroup: %s", strerror(-k
));
830 if (asprintf(&newcg
, "%s/nspawn-%lu", oldcg
, (unsigned long) getpid()) < 0) {
831 log_error("Failed to allocate cgroup path.");
835 k
= cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER
, newcg
, 0);
837 log_error("Failed to create cgroup: %s", strerror(-k
));
841 STRV_FOREACH(controller
,arg_controllers
) {
842 k
= cg_create_and_attach(*controller
, newcg
, 0);
844 log_warning("Failed to create cgroup in controller %s: %s", *controller
, strerror(-k
));
847 if ((master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
)) < 0) {
848 log_error("Failed to acquire pseudo tty: %m");
852 if (!(console
= ptsname(master
))) {
853 log_error("Failed to determine tty name: %m");
857 log_info("Spawning namespace container on %s (console is %s).", arg_directory
, console
);
859 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) >= 0)
860 ioctl(master
, TIOCSWINSZ
, &ws
);
862 if (unlockpt(master
) < 0) {
863 log_error("Failed to unlock tty: %m");
867 if (tcgetattr(STDIN_FILENO
, &saved_attr
) < 0) {
868 log_error("Failed to get terminal attributes: %m");
872 saved_attr_valid
= true;
874 raw_attr
= saved_attr
;
875 cfmakeraw(&raw_attr
);
876 raw_attr
.c_lflag
&= ~ECHO
;
878 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &raw_attr
) < 0) {
879 log_error("Failed to set terminal attributes: %m");
883 if (socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_NONBLOCK
|SOCK_CLOEXEC
, 0, kmsg_socket_pair
) < 0) {
884 log_error("Failed to create kmsg socket pair");
888 assert_se(sigemptyset(&mask
) == 0);
889 sigset_add_many(&mask
, SIGCHLD
, SIGWINCH
, SIGTERM
, SIGINT
, -1);
890 assert_se(sigprocmask(SIG_BLOCK
, &mask
, NULL
) == 0);
892 pid
= syscall(__NR_clone
, SIGCHLD
|CLONE_NEWIPC
|CLONE_NEWNS
|CLONE_NEWPID
|CLONE_NEWUTS
|(arg_private_network
? CLONE_NEWNET
: 0), NULL
);
895 log_error("clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m");
897 log_error("clone() failed: %m");
905 const char *home
= NULL
;
906 uid_t uid
= (uid_t
) -1;
907 gid_t gid
= (gid_t
) -1;
908 const char *envp
[] = {
909 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
910 "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
918 envp
[2] = strv_find_prefix(environ
, "TERM=");
920 close_nointr_nofail(master
);
922 close_nointr(STDIN_FILENO
);
923 close_nointr(STDOUT_FILENO
);
924 close_nointr(STDERR_FILENO
);
926 close_all_fds(&kmsg_socket_pair
[1], 1);
928 reset_all_signal_handlers();
930 assert_se(sigemptyset(&mask
) == 0);
931 assert_se(sigprocmask(SIG_SETMASK
, &mask
, NULL
) == 0);
936 if (prctl(PR_SET_PDEATHSIG
, SIGKILL
) < 0)
939 /* Mark / as private, in case somebody marked it shared */
940 if (mount(NULL
, "/", NULL
, MS_PRIVATE
|MS_REC
, NULL
) < 0)
943 if (mount_all(arg_directory
) < 0)
946 if (copy_devnodes(arg_directory
) < 0)
949 if (setup_dev_console(arg_directory
, console
) < 0)
952 if (setup_kmsg(arg_directory
, kmsg_socket_pair
[1]) < 0)
955 close_nointr_nofail(kmsg_socket_pair
[1]);
957 if (setup_timezone(arg_directory
) < 0)
960 if (chdir(arg_directory
) < 0) {
961 log_error("chdir(%s) failed: %m", arg_directory
);
965 if (open_terminal("dev/console", O_RDWR
) != STDIN_FILENO
||
966 dup2(STDIN_FILENO
, STDOUT_FILENO
) != STDOUT_FILENO
||
967 dup2(STDIN_FILENO
, STDERR_FILENO
) != STDERR_FILENO
)
970 if (mount(arg_directory
, "/", "bind", MS_BIND
, NULL
) < 0) {
971 log_error("mount(MS_MOVE) failed: %m");
975 if (chroot(".") < 0) {
976 log_error("chroot() failed: %m");
980 if (chdir("/") < 0) {
981 log_error("chdir() failed: %m");
989 if (drop_capabilities() < 0)
994 if (get_user_creds((const char**)&arg_user
, &uid
, &gid
, &home
) < 0) {
995 log_error("get_user_creds() failed: %m");
999 if (mkdir_parents(home
, 0775) < 0) {
1000 log_error("mkdir_parents() failed: %m");
1004 if (safe_mkdir(home
, 0775, uid
, gid
) < 0) {
1005 log_error("safe_mkdir() failed: %m");
1009 if (initgroups((const char*)arg_user
, gid
) < 0) {
1010 log_error("initgroups() failed: %m");
1014 if (setresgid(gid
, gid
, gid
) < 0) {
1015 log_error("setregid() failed: %m");
1019 if (setresuid(uid
, uid
, uid
) < 0) {
1020 log_error("setreuid() failed: %m");
1025 if ((asprintf((char**)(envp
+ 3), "HOME=%s", home
? home
: "/root") < 0) ||
1026 (asprintf((char**)(envp
+ 4), "USER=%s", arg_user
? arg_user
: "root") < 0) ||
1027 (asprintf((char**)(envp
+ 5), "LOGNAME=%s", arg_user
? arg_user
: "root") < 0)) {
1028 log_error("Out of memory");
1038 /* Automatically search for the init system */
1040 l
= 1 + argc
- optind
;
1041 a
= newa(char*, l
+ 1);
1042 memcpy(a
+ 1, argv
+ optind
, l
* sizeof(char*));
1044 a
[0] = (char*) "/usr/lib/systemd/systemd";
1045 execve(a
[0], a
, (char**) envp
);
1047 a
[0] = (char*) "/lib/systemd/systemd";
1048 execve(a
[0], a
, (char**) envp
);
1050 a
[0] = (char*) "/sbin/init";
1051 execve(a
[0], a
, (char**) envp
);
1052 } else if (argc
> optind
)
1053 execvpe(argv
[optind
], argv
+ optind
, (char**) envp
);
1055 chdir(home
? home
: "/root");
1056 execle("/bin/bash", "-bash", NULL
, (char**) envp
);
1059 log_error("execv() failed: %m");
1062 _exit(EXIT_FAILURE
);
1065 if (process_pty(master
, &mask
) < 0)
1068 if (saved_attr_valid
) {
1069 tcsetattr(STDIN_FILENO
, TCSANOW
, &saved_attr
);
1070 saved_attr_valid
= false;
1073 r
= wait_for_terminate_and_warn(argc
> optind
? argv
[optind
] : "bash", pid
);
1079 if (saved_attr_valid
)
1080 tcsetattr(STDIN_FILENO
, TCSANOW
, &saved_attr
);
1083 close_nointr_nofail(master
);
1085 close_pipe(kmsg_socket_pair
);
1088 cg_attach(SYSTEMD_CGROUP_CONTROLLER
, oldcg
, 0);
1091 cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER
, newcg
, true);
1093 free(arg_directory
);
1094 strv_free(arg_controllers
);