unsigned int raw : 1,
json : 1,
tree : 2,
+ persist : 1,
no_trunc : 1,
no_headings: 1,
no_wrap : 1;
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);
}
}
+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)
}
#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
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);
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);
{ "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' },
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
{ 'J','r' },
+ { 'P','p' },
{ 'l','T' },
{ 0 }
};
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);
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;
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)