Skip to content

Commit eabbd8b

Browse files
committed
lsns: show persistent namespace, add --persistent
* show persistent namespaces (without processes) by default * add option --persistent only these namespaces Fixes: #1881 Signed-off-by: Karel Zak <kzak@redhat.com>
1 parent f6e2e07 commit eabbd8b

2 files changed

Lines changed: 56 additions & 7 deletions

File tree

sys-utils/lsns.8.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ The default list of columns may be extended if _list_ is specified in the format
4848
*--output-all*::
4949
Output all available columns.
5050

51+
*-P*, *--persistent*::
52+
Display only the namespaces without processes (aka persistent namespaces), created by bind mounting
53+
/proc/pid/ns/type files to a filesystem path.
54+
5155
*-p*, *--task* _PID_::
5256
Display only the namespaces held by the process with this _PID_.
5357

sys-utils/lsns.c

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct lsns {
210210
unsigned int raw : 1,
211211
json : 1,
212212
tree : 2,
213+
persist : 1,
213214
no_trunc : 1,
214215
no_headings: 1,
215216
no_wrap : 1;
@@ -722,7 +723,7 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in
722723
if (clone_type < 0)
723724
return NULL;
724725
lsns_type = clone_type_to_lsns_type(clone_type);
725-
if (lsns_type < 0)
726+
if (lsns_type < 0 || ls->fltr_types[lsns_type] == 0)
726727
return NULL;
727728

728729
fd_owner = ioctl(fd, NS_GET_USERNS);
@@ -858,6 +859,42 @@ static void read_related_namespaces(struct lsns *ls)
858859
}
859860
}
860861

862+
static int read_persistent_namespaces(struct lsns *ls)
863+
{
864+
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
865+
struct libmnt_fs *fs = NULL;
866+
867+
while (mnt_table_next_fs(ls->tab, itr, &fs) == 0) {
868+
const char *root;
869+
char *p, *end = NULL;
870+
ino_t ino;
871+
int fd;
872+
873+
if (!mnt_fs_match_fstype(fs, "nsfs"))
874+
continue;
875+
root = mnt_fs_get_root(fs);
876+
if (!root || !(p = strchr(root, '[')))
877+
continue;
878+
879+
errno = 0;
880+
ino = strtoumax(++p, &end, 10);
881+
if (!end || *end != ']' || errno != 0)
882+
continue;
883+
if (get_namespace(ls, ino))
884+
continue;
885+
886+
fd = open(mnt_fs_get_target(fs), O_RDONLY);
887+
if (fd < 0)
888+
continue;
889+
890+
add_namespace_for_nsfd(ls, fd, ino);
891+
close(fd);
892+
}
893+
894+
mnt_free_iter(itr);
895+
return 0;
896+
}
897+
861898
#endif /* USE_NS_GET_API */
862899

863900
static int read_namespaces(struct lsns *ls)
@@ -885,6 +922,8 @@ static int read_namespaces(struct lsns *ls)
885922
}
886923

887924
#ifdef USE_NS_GET_API
925+
read_persistent_namespaces(ls);
926+
888927
if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
889928
read_related_namespaces(ls);
890929
#endif
@@ -1150,6 +1189,8 @@ static int show_namespaces(struct lsns *ls)
11501189

11511190
if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid))
11521191
continue;
1192+
if (ls->persist && ns->nprocs != 0)
1193+
continue;
11531194

11541195
if (!ns->ns_outline)
11551196
show_namespace(ls, tab, ns, ns->proc);
@@ -1240,6 +1281,7 @@ static void __attribute__((__noreturn__)) usage(void)
12401281
fputs(_(" -n, --noheadings don't print headings\n"), out);
12411282
fputs(_(" -o, --output <list> define which output columns to use\n"), out);
12421283
fputs(_(" --output-all output all columns\n"), out);
1284+
fputs(_(" -P, --persistent namespaces without processes\n"), out);
12431285
fputs(_(" -p, --task <pid> print process namespaces\n"), out);
12441286
fputs(_(" -r, --raw use the raw output format\n"), out);
12451287
fputs(_(" -u, --notruncate don't truncate text in columns\n"), out);
@@ -1275,6 +1317,7 @@ int main(int argc, char *argv[])
12751317
{ "help", no_argument, NULL, 'h' },
12761318
{ "output", required_argument, NULL, 'o' },
12771319
{ "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
1320+
{ "persistent", no_argument, NULL, 'P' },
12781321
{ "notruncate", no_argument, NULL, 'u' },
12791322
{ "version", no_argument, NULL, 'V' },
12801323
{ "noheadings", no_argument, NULL, 'n' },
@@ -1288,6 +1331,7 @@ int main(int argc, char *argv[])
12881331

12891332
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
12901333
{ 'J','r' },
1334+
{ 'P','p' },
12911335
{ 'l','T' },
12921336
{ 0 }
12931337
};
@@ -1307,7 +1351,7 @@ int main(int argc, char *argv[])
13071351
INIT_LIST_HEAD(&netnsids_cache);
13081352

13091353
while ((c = getopt_long(argc, argv,
1310-
"Jlp:o:nruhVt:T::W", long_opts, NULL)) != -1) {
1354+
"JlPp:o:nruhVt:T::W", long_opts, NULL)) != -1) {
13111355

13121356
err_exclusive_options(c, long_opts, excl, excl_st);
13131357

@@ -1325,6 +1369,9 @@ int main(int argc, char *argv[])
13251369
for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
13261370
columns[ncolumns] = ncolumns;
13271371
break;
1372+
case 'P':
1373+
ls.persist = 1;
1374+
break;
13281375
case 'p':
13291376
ls.fltr_pid = strtos32_or_err(optarg, _("invalid PID argument"));
13301377
break;
@@ -1430,11 +1477,9 @@ int main(int argc, char *argv[])
14301477
if (has_column(COL_NETNSID))
14311478
netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
14321479
#endif
1433-
if (has_column(COL_NSFS)) {
1434-
ls.tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
1435-
if (!ls.tab)
1436-
err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
1437-
}
1480+
ls.tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
1481+
if (!ls.tab)
1482+
err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
14381483

14391484
r = read_processes(&ls);
14401485
if (!r)

0 commit comments

Comments
 (0)