From eabbd8b7d5814ca3a064e79a32674e267aebc6e9 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 8 Nov 2022 10:09:28 +0100 Subject: [PATCH] lsns: show persistent namespace, add --persistent * 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 --- sys-utils/lsns.8.adoc | 4 +++ sys-utils/lsns.c | 59 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index bcbc90911d..0e57ba8477 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -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_. diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 86c19c1a85..1f3c88201b 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -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 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 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) -- 2.47.3