]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: allow to set a new root
authorLaurent Vivier <laurent@vivier.eu>
Fri, 5 Oct 2018 11:09:29 +0000 (13:09 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 12 Nov 2018 10:52:14 +0000 (11:52 +0100)
This patch instroduces two new parameters to set the new
root and the new working directory in this new root.

This allows to combine "unshare chroot" in one command,
and doing like this the /proc filesystem is correctly
mounted in the new root with "--mount-proc".

The new parameters are -R, --root and -w, --wd. The names
are the same as for nsenter, except for "-r" that is already
used by "--map-root-user" and replaced by "-R".

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
bash-completion/unshare
sys-utils/unshare.1
sys-utils/unshare.c

index 3fda4a19440802a40549c582f7e1d047938b587b..64aea678419df25f5b6e717ea0649729e95d6f59 100644 (file)
@@ -33,7 +33,9 @@ _unshare_module()
                                --propagation
                                --setgroups
                                --help
-                               --version"
+                               --version
+                               --root
+                               --wd"
                        COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
                        return 0
                        ;;
index 746c41152baf457f00a94bcc640e3ba5c3c9a04d..40cbedbd151d876cfcd0b5537cf41ffd6bf8ef5d 100644 (file)
@@ -186,6 +186,12 @@ the GID map becomes writable by unprivileged processes when
 .BR \%setgroups (2)
 is permanently disabled (with \fBdeny\fR).
 .TP
+.BR \-R, "\-\-root=\fIdir"
+run the command with root directory set to \fIdir\fP.
+.TP
+.BR \-w, "\-\-wd=\fIdir"
+change working directory to \fIdir\fP.
+.TP
 .BR \-V , " \-\-version"
 Display version information and exit.
 .TP
index 661665aeba250c10ea975e3e8a203b6337f8dde1..12ef044f855a530288030b6191d2bcb65adc1197 100644 (file)
@@ -269,6 +269,9 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" --propagation slave|shared|private|unchanged\n"
                "                           modify mount propagation in mount namespace\n"), out);
        fputs(_(" --setgroups allow|deny    control the setgroups syscall in user namespaces\n"), out);
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_(" -R, --root=<dir>          run the command with root directory set to <dir>\n"), out);
+       fputs(_(" -w, --wd=<dir>            change working directory to <dir>\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        printf(USAGE_HELP_OPTIONS(27));
@@ -283,7 +286,7 @@ int main(int argc, char *argv[])
                OPT_MOUNTPROC = CHAR_MAX + 1,
                OPT_PROPAGATION,
                OPT_SETGROUPS,
-               OPT_KILLCHILD
+               OPT_KILLCHILD,
        };
        static const struct option longopts[] = {
                { "help",          no_argument,       NULL, 'h'             },
@@ -303,6 +306,8 @@ int main(int argc, char *argv[])
                { "map-root-user", no_argument,       NULL, 'r'             },
                { "propagation",   required_argument, NULL, OPT_PROPAGATION },
                { "setgroups",     required_argument, NULL, OPT_SETGROUPS   },
+               { "root",          required_argument, NULL, 'R'             },
+               { "wd",            required_argument, NULL, 'w'             },
                { NULL, 0, NULL, 0 }
        };
 
@@ -311,6 +316,8 @@ int main(int argc, char *argv[])
        int c, forkit = 0, maproot = 0;
        int kill_child_signo = 0; /* 0 means --kill-child was not used */
        const char *procmnt = NULL;
+       const char *newroot = NULL;
+       const char *newdir = NULL;
        pid_t pid = 0;
        int fds[2];
        int status;
@@ -323,7 +330,7 @@ int main(int argc, char *argv[])
        textdomain(PACKAGE);
        atexit(close_stdout);
 
-       while ((c = getopt_long(argc, argv, "+fhVmuinpCUr", longopts, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:", longopts, NULL)) != -1) {
                switch (c) {
                case 'f':
                        forkit = 1;
@@ -392,6 +399,12 @@ int main(int argc, char *argv[])
                                kill_child_signo = SIGKILL;
                        }
                        break;
+               case 'R':
+                       newroot = optarg;
+                       break;
+               case 'w':
+                       newdir = optarg;
+                       break;
                default:
                        errtryhelp(EXIT_FAILURE);
                }
@@ -471,10 +484,21 @@ int main(int argc, char *argv[])
        if ((unshare_flags & CLONE_NEWNS) && propagation)
                set_propagation(propagation);
 
-       if (procmnt &&
-           (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 ||
-            mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))
+       if (newroot) {
+               if (chroot(newroot) != 0)
+                       err(EXIT_FAILURE,
+                           _("cannot change root directory to '%s'"), newroot);
+               newdir = newdir ?: "/";
+       }
+       if (newdir && chdir(newdir))
+               err(EXIT_FAILURE, _("cannot chdir to '%s'"), newdir);
+
+       if (procmnt) {
+               if (!newroot && mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0)
+                       err(EXIT_FAILURE, _("umount %s failed"), procmnt);
+               if (mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0)
                        err(EXIT_FAILURE, _("mount %s failed"), procmnt);
+       }
 
        if (optind < argc) {
                execvp(argv[optind], argv + optind);