]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsns: show persistent namespace, add --persistent
authorKarel Zak <kzak@redhat.com>
Tue, 8 Nov 2022 09:09:28 +0000 (10:09 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 8 Nov 2022 09:09:28 +0000 (10:09 +0100)
* show persistent namespaces (without processes) by default
* add option --persistent only these namespaces

Fixes: https://github.com/util-linux/util-linux/issues/1881
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/lsns.8.adoc
sys-utils/lsns.c

index bcbc90911d28918d4b0dbe5c8521587f2a02b329..0e57ba84770357441014b254c28e2ebbbea0256f 100644 (file)
@@ -48,6 +48,10 @@ The default list of columns may be extended if _list_ is specified in the format
 *--output-all*::
 Output all available columns.
 
+*-P*, *--persistent*::
+Display only the namespaces without processes (aka persistent namespaces), created by bind mounting
+/proc/pid/ns/type files to a filesystem path.
+
 *-p*, *--task* _PID_::
 Display only the namespaces held by the process with this _PID_.
 
index 86c19c1a8543ce74dc695df9699cde7efe18d261..1f3c88201b4e0b18bdccb2bb6c1119b9891b8550 100644 (file)
@@ -210,6 +210,7 @@ struct lsns {
        unsigned int raw        : 1,
                     json       : 1,
                     tree       : 2,
+                    persist    : 1,
                     no_trunc   : 1,
                     no_headings: 1,
                     no_wrap    : 1;
@@ -722,7 +723,7 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in
        if (clone_type < 0)
                return NULL;
        lsns_type = clone_type_to_lsns_type(clone_type);
-       if (lsns_type < 0)
+       if (lsns_type < 0 || ls->fltr_types[lsns_type] == 0)
                return NULL;
 
        fd_owner = ioctl(fd, NS_GET_USERNS);
@@ -858,6 +859,42 @@ static void read_related_namespaces(struct lsns *ls)
        }
 }
 
+static int read_persistent_namespaces(struct lsns *ls)
+{
+       struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
+       struct libmnt_fs *fs = NULL;
+
+       while (mnt_table_next_fs(ls->tab, itr, &fs) == 0) {
+               const char *root;
+               char *p, *end = NULL;
+               ino_t ino;
+               int fd;
+
+               if (!mnt_fs_match_fstype(fs, "nsfs"))
+                       continue;
+               root = mnt_fs_get_root(fs);
+               if (!root || !(p = strchr(root, '[')))
+                       continue;
+
+               errno = 0;
+               ino = strtoumax(++p, &end, 10);
+               if (!end || *end != ']' || errno != 0)
+                       continue;
+               if (get_namespace(ls, ino))
+                       continue;
+
+               fd = open(mnt_fs_get_target(fs), O_RDONLY);
+               if (fd < 0)
+                       continue;
+
+               add_namespace_for_nsfd(ls, fd, ino);
+               close(fd);
+       }
+
+       mnt_free_iter(itr);
+       return 0;
+}
+
 #endif /* USE_NS_GET_API */
 
 static int read_namespaces(struct lsns *ls)
@@ -885,6 +922,8 @@ static int read_namespaces(struct lsns *ls)
        }
 
 #ifdef USE_NS_GET_API
+       read_persistent_namespaces(ls);
+
        if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
                read_related_namespaces(ls);
 #endif
@@ -1150,6 +1189,8 @@ static int show_namespaces(struct lsns *ls)
 
                if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid))
                        continue;
+               if (ls->persist && ns->nprocs != 0)
+                       continue;
 
                if (!ns->ns_outline)
                        show_namespace(ls, tab, ns, ns->proc);
@@ -1240,6 +1281,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -n, --noheadings       don't print headings\n"), out);
        fputs(_(" -o, --output <list>    define which output columns to use\n"), out);
        fputs(_("     --output-all       output all columns\n"), out);
+       fputs(_(" -P, --persistent       namespaces without processes\n"), out);
        fputs(_(" -p, --task <pid>       print process namespaces\n"), out);
        fputs(_(" -r, --raw              use the raw output format\n"), out);
        fputs(_(" -u, --notruncate       don't truncate text in columns\n"), out);
@@ -1275,6 +1317,7 @@ int main(int argc, char *argv[])
                { "help",       no_argument,       NULL, 'h' },
                { "output",     required_argument, NULL, 'o' },
                { "output-all", no_argument,       NULL, OPT_OUTPUT_ALL },
+               { "persistent", no_argument,       NULL, 'P' },
                { "notruncate", no_argument,       NULL, 'u' },
                { "version",    no_argument,       NULL, 'V' },
                { "noheadings", no_argument,       NULL, 'n' },
@@ -1288,6 +1331,7 @@ int main(int argc, char *argv[])
 
        static const ul_excl_t excl[] = {       /* rows and cols in ASCII order */
                { 'J','r' },
+               { 'P','p' },
                { 'l','T' },
                { 0 }
        };
@@ -1307,7 +1351,7 @@ int main(int argc, char *argv[])
        INIT_LIST_HEAD(&netnsids_cache);
 
        while ((c = getopt_long(argc, argv,
-                               "Jlp:o:nruhVt:T::W", long_opts, NULL)) != -1) {
+                               "JlPp:o:nruhVt:T::W", long_opts, NULL)) != -1) {
 
                err_exclusive_options(c, long_opts, excl, excl_st);
 
@@ -1325,6 +1369,9 @@ int main(int argc, char *argv[])
                        for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
                                columns[ncolumns] = ncolumns;
                        break;
+               case 'P':
+                       ls.persist = 1;
+                       break;
                case 'p':
                        ls.fltr_pid = strtos32_or_err(optarg, _("invalid PID argument"));
                        break;
@@ -1430,11 +1477,9 @@ int main(int argc, char *argv[])
        if (has_column(COL_NETNSID))
                netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 #endif
-       if (has_column(COL_NSFS)) {
-               ls.tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
-               if (!ls.tab)
-                       err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
-       }
+       ls.tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
+       if (!ls.tab)
+               err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
 
        r = read_processes(&ls);
        if (!r)