]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
nsenter: add --wdns to change working directory
authorKarel Zak <kzak@redhat.com>
Mon, 22 Nov 2021 12:18:54 +0000 (13:18 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 22 Nov 2021 12:18:54 +0000 (13:18 +0100)
The current --wd=<dir> changes CWD to the path which is opened
*before* nsenter calls setns(). It may be useful if you want to use in
namespace something from your current namespace.  In this case, the
option --wd works like a "tunnel" between namespaces.

For some other use-cases, this is useless and you want to be sure that
CWD always points to the target namespace. For this purpose this patch
implements --wdns <dir>.

Example:

 Setup the namespaces:

  # unshare --mount
  # mount /dev/sdc /mnt/A
  # touch /mnt/A/fooooo
  # echo $$
  2425872

 Enter the namespace from another session:

  # nsenter --all --target 2425872 --wd=/mnt/A ls -a
  .  ..

  # nsenter --all --target 2425872 --wdns=/mnt/A ls -a
  .  ..  fooooo  lost+found

Fixes: https://github.com/util-linux/util-linux/issues/1500
Signed-off-by: Karel Zak <kzak@redhat.com>
bash-completion/nsenter
sys-utils/nsenter.1.adoc
sys-utils/nsenter.c

index 8ee74612e11741845cdef81ac9ee6050dbef9fde..d3cb23f0b12ee8b7a5ebfb4444462ca6142fbf8d 100644 (file)
@@ -48,6 +48,7 @@ _nsenter_module()
                                --preserve-credentials
                                --root=
                                --wd=
+                               --wdns=
                                --no-fork
                                --help
                                --version
index e1d32dbc60f462395ffb55e50000a842c41bbc6d..3df926810ab649b33cc83e561bbf5ed97258fb86 100644 (file)
@@ -113,10 +113,13 @@ Set the user ID which will be used in the entered namespace. *nsenter* always se
 Don't modify UID and GID when enter user namespace. The default is to drops supplementary groups and sets GID and UID to 0.
 
 *-r*, *--root*[=_directory_]::
-Set the root directory. If no directory is specified, set the root directory to the root directory of the target process. If directory is specified, set the root directory to the specified directory.
+Set the root directory. If no directory is specified, set the root directory to the root directory of the target process. If directory is specified, set the root directory to the specified directory. The specified _directory_ is open before it switches to the requested namespaces.
 
 *-w*, *--wd*[=_directory_]::
-Set the working directory. If no directory is specified, set the working directory to the working directory of the target process. If directory is specified, set the working directory to the specified directory.
+Set the working directory. If no directory is specified, set the working directory to the working directory of the target process. If directory is specified, set the working directory to the specified directory. The specified _directory_ is open before it switches to the requested namespaces, it means the specified directory works as "tunnel" to the current namespace. See also *--wdns*.
+
+*-W*, *--wdns*[=_directory_]::
+Set the working directory. The _directory_ is open after switch to the requested namespaces and after chroot call. The options *--wd* and *--wdns* are mutually exclusive.
 
 *-F*, *--no-fork*::
 Do not fork before exec'ing the specified program. By default, when entering a PID namespace, *nsenter* calls *fork* before calling *exec* so that any children will also be in the newly entered PID namespace.
index 7805703cbbe535d397a32b94f75a880e9711572b..440bf3b9f877b5e6522b5335530cc2e07f717df5 100644 (file)
@@ -41,6 +41,7 @@
 #include "closestream.h"
 #include "namespace.h"
 #include "exec_shell.h"
+#include "optutils.h"
 
 static struct namespace_file {
        int nstype;
@@ -93,6 +94,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_("     --preserve-credentials do not touch uids or gids\n"), out);
        fputs(_(" -r, --root[=<dir>]     set the root directory\n"), out);
        fputs(_(" -w, --wd[=<dir>]       set the working directory\n"), out);
+       fputs(_(" -W. --wdns <dir>       set the working directory in namespace\n"), out);
        fputs(_(" -F, --no-fork          do not fork before exec'ing <program>\n"), out);
 #ifdef HAVE_LIBSELINUX
        fputs(_(" -Z, --follow-context   set SELinux context according to --target PID\n"), out);
@@ -243,6 +245,7 @@ int main(int argc, char *argv[])
                { "setgid", required_argument, NULL, 'G' },
                { "root", optional_argument, NULL, 'r' },
                { "wd", optional_argument, NULL, 'w' },
+               { "wdns", optional_argument, NULL, 'W' },
                { "no-fork", no_argument, NULL, 'F' },
                { "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED },
 #ifdef HAVE_LIBSELINUX
@@ -250,12 +253,18 @@ int main(int argc, char *argv[])
 #endif
                { NULL, 0, NULL, 0 }
        };
+       static const ul_excl_t excl[] = {       /* rows and cols in ASCII order */
+               { 'W', 'w' },
+               { 0 }
+       };
+       int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
 
        struct namespace_file *nsfile;
        int c, pass, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
        bool do_rd = false, do_wd = false, force_uid = false, force_gid = false;
        bool do_all = false;
        int do_fork = -1; /* unknown yet */
+       char *wdns = NULL;
        uid_t uid = 0;
        gid_t gid = 0;
 #ifdef HAVE_LIBSELINUX
@@ -268,8 +277,11 @@ int main(int argc, char *argv[])
        close_stdout_atexit();
 
        while ((c =
-               getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::FZ",
+               getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::W:FZ",
                            longopts, NULL)) != -1) {
+
+               err_exclusive_options(c, longopts, excl, excl_st);
+
                switch (c) {
                case 'a':
                        do_all = true;
@@ -349,6 +361,9 @@ int main(int argc, char *argv[])
                        else
                                do_wd = true;
                        break;
+               case 'W':
+                       wdns = optarg;
+                       break;
                case OPT_PRESERVE_CRED:
                        preserve_cred = 1;
                        break;
@@ -455,7 +470,7 @@ int main(int argc, char *argv[])
        }
 
        /* Remember the current working directory if I'm not changing it */
-       if (root_fd >= 0 && wd_fd < 0) {
+       if (root_fd >= 0 && wd_fd < 0 && wdns == NULL) {
                wd_fd = open(".", O_RDONLY);
                if (wd_fd < 0)
                        err(EXIT_FAILURE,
@@ -477,6 +492,14 @@ int main(int argc, char *argv[])
                root_fd = -1;
        }
 
+       /* working directory specified as in-namespace path */
+       if (wdns) {
+               wd_fd = open(wdns, O_RDONLY);
+               if (wd_fd < 0)
+                       err(EXIT_FAILURE,
+                           _("cannot open current working directory"));
+       }
+
        /* Change the working directory */
        if (wd_fd >= 0) {
                if (fchdir(wd_fd) < 0)