hush: do not assign to readonly VAR in "VAR=VAL CMD" syntax too
[oweals/busybox.git] / util-linux / unshare.c
index f1a9cdf194c43f4d66d15d55860b890c03272255..875e3f86e3048336e9c8ca6dfdc50b034a6e4734 100644 (file)
@@ -6,16 +6,16 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
-
 //config:config UNSHARE
 //config:      bool "unshare"
 //config:      default y
-//config:      depends on LONG_OPTS && !NOMMU
+//config:      depends on !NOMMU
 //config:      select PLATFORM_LINUX
+//config:      select LONG_OPTS
 //config:      help
 //config:        Run program with some namespaces unshared from parent.
 
-// depends on LONG_OPTS: it is awkward to exclude code which handles --propagation
+// needs LONG_OPTS: it is awkward to exclude code which handles --propagation
 // and --setgroups based on LONG_OPTS, so instead applet requires LONG_OPTS.
 // depends on !NOMMU: we need fork()
 
 //usage:#define unshare_trivial_usage
 //usage:       "[OPTIONS] [PROG [ARGS]]"
 //usage:#define unshare_full_usage "\n"
-//usage:     "\n       -m, --mount[=FILE]      Unshare mount namespace"
-//usage:     "\n       -u, --uts[=FILE]        Unshare UTS namespace (hostname etc.)"
-//usage:     "\n       -i, --ipc[=FILE]        Unshare System V IPC namespace"
-//usage:     "\n       -n, --net[=FILE]        Unshare network namespace"
-//usage:     "\n       -p, --pid[=FILE]        Unshare PID namespace"
-//usage:     "\n       -U, --user[=FILE}       Unshare user namespace"
-//usage:     "\n       -f, --fork              Fork before execing PROG"
-//usage:     "\n       -r, --map-root-user     Map current user to root (implies -u)"
+//usage:     "\n       -m,--mount[=FILE]       Unshare mount namespace"
+//usage:     "\n       -u,--uts[=FILE]         Unshare UTS namespace (hostname etc.)"
+//usage:     "\n       -i,--ipc[=FILE]         Unshare System V IPC namespace"
+//usage:     "\n       -n,--net[=FILE]         Unshare network namespace"
+//usage:     "\n       -p,--pid[=FILE]         Unshare PID namespace"
+//usage:     "\n       -U,--user[=FILE]        Unshare user namespace"
+//usage:     "\n       -f,--fork               Fork before execing PROG"
+//usage:     "\n       -r,--map-root-user      Map current user to root (implies -U)"
 //usage:     "\n       --mount-proc[=DIR]      Mount /proc filesystem first (implies -m)"
 //usage:     "\n       --propagation slave|shared|private|unchanged"
 //usage:     "\n                               Modify mount propagation in mount namespace"
 //usage:     "\n       --setgroups allow|deny  Control the setgroups syscall in user namespaces"
 
 #include <sched.h>
+#ifndef CLONE_NEWUTS
+# define CLONE_NEWUTS  0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+# define CLONE_NEWIPC  0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+# define CLONE_NEWUSER 0x10000000
+#endif
+#ifndef CLONE_NEWPID
+# define CLONE_NEWPID  0x20000000
+#endif
+#ifndef CLONE_NEWNET
+# define CLONE_NEWNET  0x40000000
+#endif
+
 #include <sys/mount.h>
+#ifndef MS_REC
+# define MS_REC     (1 << 14)
+#endif
+#ifndef MS_PRIVATE
+# define MS_PRIVATE (1 << 18)
+#endif
+#ifndef MS_SLAVE
+# define MS_SLAVE   (1 << 19)
+#endif
+#ifndef MS_SHARED
+# define MS_SHARED  (1 << 20)
+#endif
+
 #include "libbb.h"
 
 static void mount_or_die(const char *source, const char *target,
@@ -57,22 +86,6 @@ static void mount_or_die(const char *source, const char *target,
        }
 }
 
-// TODO: move to libbb
-static int wait_for_exitstatus(pid_t pid)
-{
-       int exit_status, n;
-
-       n = safe_waitpid(pid, &exit_status, 0);
-       if (n < 0)
-               bb_perror_msg_and_die("waitpid");
-       return exit_status;
-}
-
-/*
- * Longest possible path to a procfs file used in unshare. Must be able to
- * contain the '/proc/' string, the '/ns/user' string which is the longest
- * namespace name and a 32-bit integer representing the process ID.
- */
 #define PATH_PROC_SETGROUPS    "/proc/self/setgroups"
 #define PATH_PROC_UIDMAP       "/proc/self/uid_map"
 #define PATH_PROC_GIDMAP       "/proc/self/gid_map"
@@ -90,7 +103,7 @@ enum {
        OPT_mount       = 1 << 0,
        OPT_uts         = 1 << 1,
        OPT_ipc         = 1 << 2,
-       OPT_network     = 1 << 3,
+       OPT_net         = 1 << 3,
        OPT_pid         = 1 << 4,
        OPT_user        = 1 << 5, /* OPT_user, NS_USR_POS, and ns_list[] index must match! */
        OPT_fork        = 1 << 6,
@@ -124,12 +137,12 @@ static const struct namespace_descr ns_list[] = {
  * we are forced to use "fake" letters for them.
  * '+': stop at first non-option.
  */
-static const char opt_str[] = "+muinpU""fr""\xfd::""\xfe:""\xff:";
+static const char opt_str[] ALIGN1 = "+muinpU""fr""\xfd::""\xfe:""\xff:";
 static const char unshare_longopts[] ALIGN1 =
        "mount\0"               Optional_argument       "\xf0"
        "uts\0"                 Optional_argument       "\xf1"
        "ipc\0"                 Optional_argument       "\xf2"
-       "network\0"             Optional_argument       "\xf3"
+       "net\0"                 Optional_argument       "\xf3"
        "pid\0"                 Optional_argument       "\xf4"
        "user\0"                Optional_argument       "\xf5"
        "fork\0"                No_argument             "f"
@@ -297,7 +310,7 @@ int unshare_main(int argc UNUSED_PARAM, char **argv)
 
        if (fdp.wr >= 0) {
                close(fdp.wr); /* Release child */
-               /*close(fdp.rd);*/
+               close(fdp.rd); /* should close fd, to not confuse exec'ed PROG */
        }
 
        if (need_mount) {
@@ -323,14 +336,7 @@ int unshare_main(int argc UNUSED_PARAM, char **argv)
         * that'll become PID 1 in this new namespace.
         */
        if (opts & OPT_fork) {
-               pid_t pid = xfork();
-               if (pid > 0) {
-                       /* Parent */
-                       int exit_status = wait_for_exitstatus(pid);
-                       if (WIFSIGNALED(exit_status))
-                               kill_myself_with_sig(WTERMSIG(exit_status));
-                       return WEXITSTATUS(exit_status);
-               }
+               xvfork_parent_waits_and_exits();
                /* Child continues */
        }
 
@@ -370,11 +376,5 @@ int unshare_main(int argc UNUSED_PARAM, char **argv)
                mount_or_die("proc", proc_mnt_target, "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV);
        }
 
-       if (argv[0]) {
-               BB_EXECVP_or_die(argv);
-       }
-       /* unshare from util-linux 2.27.1, despite not documenting it,
-        * runs a login shell (argv0="-sh") if no PROG is given
-        */
-       run_shell(getenv("SHELL"), /*login:*/ 1, NULL, NULL);
+       exec_prog_or_SHELL(argv);
 }