From: Masatake YAMATO Date: Thu, 15 Apr 2021 09:03:57 +0000 (+0900) Subject: lsns: print namespace tree based on the relationship (parent/child or owner/owned) X-Git-Tag: v2.38-rc1~486^2~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e8c56ae2d77e27b444d35d29b168e2212077e71c;p=thirdparty%2Futil-linux.git lsns: print namespace tree based on the relationship (parent/child or owner/owned) Introduce new option -T[parent|owner]|--nstree[=parent|=owner]. With this change, lsns prints parent/child relationship tree if "-T parent" is given and owner/owned relationship tree if "-T owner is given. Passing only "-T" is same as passing "-Towner." Example sessions: # ./lsns -Tparent -ons,type,pns| head -20 NS TYPE PNS 4026531837 user 0 ├─4026532508 user 4026531837 ├─4026532609 user 4026531837 ├─4026532610 user 4026531837 ├─4026532629 user 4026531837 ├─4026532705 user 4026531837 ├─4026532901 user 4026531837 ├─4026533090 user 4026531837 ├─4026533185 user 4026531837 ├─4026533280 user 4026531837 └─4026533468 user 4026531837 4026531835 cgroup 0 4026531836 pid 0 └─4026533038 pid 4026531836 ├─4026532934 pid 4026533038 ├─4026533715 pid 4026533038 ├─4026533716 pid 4026533038 ... # ./lsns -Towner -ons,type,ons| head -20 NS TYPE ONS 4026531837 user 0 ├─4026531835 cgroup 4026531837 ├─4026531836 pid 4026531837 ├─4026531838 uts 4026531837 ├─4026531839 ipc 4026531837 ├─4026531840 mnt 4026531837 ├─4026531861 mnt 4026531837 ├─4026532001 net 4026531837 ├─4026532219 mnt 4026531837 ├─4026532357 mnt 4026531837 ├─4026532383 net 4026531837 ├─4026532475 mnt 4026531837 ├─4026532476 mnt 4026531837 ├─4026532504 mnt 4026531837 ├─4026532508 user 4026531837 │ ├─4026532509 ipc 4026532508 │ └─4026532511 net 4026532508 ├─4026532573 mnt 4026531837 ├─4026532574 mnt 4026531837 Signed-off-by: Masatake YAMATO --- diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index ab7e7aea88..77875223bd 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -63,6 +63,12 @@ Do not truncate text in columns. *-W*, *--nowrap*:: Do not use multi-line text in columns. +*-T*, *--nstree* _rel_:: +Print namespace tree(s). +If *parent* is given as _rel_, print tree(s) constructed by the parent/child relationship. +If *owner* is given, print tree(s) constructed by the owner/owned relationship. +The result can be forests because *lsns* cannot track a namespace having no process. + *-V*, *--version*:: Display version information and exit. diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 8e25ff1831..23a2eabacc 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -152,6 +152,10 @@ struct lsns_namespace { struct lsns_process *proc; + struct lsns_namespace *parentns; + struct lsns_namespace *ownerns; + struct libscols_line *ns_outline; + struct list_head namespaces; /* lsns->processes member */ struct list_head processes; /* head of lsns_process *siblings */ }; @@ -177,6 +181,11 @@ struct lsns_process { int netnsid; }; +enum { + LSNS_NSTREE_OWNER = 1, + LSNS_NSTREE_PARENT, +}; + struct lsns { struct list_head processes; struct list_head namespaces; @@ -192,7 +201,9 @@ struct lsns { list : 1, no_trunc : 1, no_headings: 1, - no_wrap : 1; + no_wrap : 1, + nstree : 2; + struct libmnt_table *tab; }; @@ -684,6 +695,30 @@ static int read_namespaces(struct lsns *ls) } } + if (ls->nstree) { + list_for_each(p, &ls->namespaces) { + struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces); + struct list_head *pp; + list_for_each(pp, &ls->namespaces) { + struct lsns_namespace *pns = list_entry(pp, struct lsns_namespace, namespaces); + if (ns->type == LSNS_ID_USER + || ns->type == LSNS_ID_PID) { + if (ns->parentid == pns->id) + ns->parentns = pns; + if (ns->ownerid == pns->id) + ns->ownerns = pns; + if (ns->parentns && ns->ownerns) + break; + } else { + if (ns->ownerid == pns->id) { + ns->ownerns = pns; + break; + } + } + } + } + } + list_sort(&ls->namespaces, cmp_namespaces, NULL); return 0; @@ -774,7 +809,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, assert(table); line = scols_table_new_line(table, - ls->tree && proc->parent ? proc->parent->outline : NULL); + ls->tree && proc->parent ? proc->parent->outline: + ls->nstree == LSNS_NSTREE_PARENT && ns->parentns ? ns->parentns->ns_outline: + ls->nstree == LSNS_NSTREE_OWNER && ns->ownerns ? ns->ownerns->ns_outline: + NULL); if (!line) { warn(_("failed to add line to output")); return; @@ -834,7 +872,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, err_oom(); } - proc->outline = line; + if (ls->nstree) + ns->ns_outline = line; + else + proc->outline = line; } static struct libscols_table *init_scols_table(struct lsns *ls) @@ -866,6 +907,10 @@ static struct libscols_table *init_scols_table(struct lsns *ls) flags |= SCOLS_FL_TREE; if (ls->no_wrap) flags &= ~SCOLS_FL_WRAP; + if (ls->nstree && get_column_id(i) == COL_NS) { + flags |= SCOLS_FL_TREE; + flags &= ~SCOLS_FL_RIGHT; + } cl = scols_table_new_column(tab, col->name, col->whint, flags); if (cl == NULL) { @@ -890,6 +935,28 @@ err: return NULL; } +static void show_namespace(struct lsns *ls, struct libscols_table *tab, + struct lsns_namespace *ns, struct lsns_process *proc) +{ + /* + * create a tree from owner->owned and/or parent->child relation + */ + if (ls->nstree == LSNS_NSTREE_OWNER + && ns->ownerns + && !ns->ownerns->ns_outline) + show_namespace(ls, tab, ns->ownerns, proc); + else if (ls->nstree == LSNS_NSTREE_PARENT) { + if (ns->parentns) { + if (!ns->parentns->ns_outline) + show_namespace(ls, tab, ns->parentns, proc); + } + else if (ns->ownerns && !ns->ownerns->ns_outline) + show_namespace(ls, tab, ns->ownerns, proc); + } + + add_scols_line(ls, tab, ns, proc); +} + static int show_namespaces(struct lsns *ls) { struct libscols_table *tab; @@ -906,7 +973,8 @@ static int show_namespaces(struct lsns *ls) if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid)) continue; - add_scols_line(ls, tab, ns, ns->proc); + if (!ns->ns_outline) + show_namespace(ls, tab, ns, ns->proc); } scols_print_table(tab); @@ -977,6 +1045,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -u, --notruncate don't truncate text in columns\n"), out); fputs(_(" -W, --nowrap don't use multi-line representation\n"), out); fputs(_(" -t, --type namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out); + fputs(_(" -T, --nstree print namespace tree based on the relationship (parent or owner)\n"), out); fputs(USAGE_SEPARATOR, out); printf(USAGE_HELP_OPTIONS(24)); @@ -1013,6 +1082,7 @@ int main(int argc, char *argv[]) { "list", no_argument, NULL, 'l' }, { "raw", no_argument, NULL, 'r' }, { "type", required_argument, NULL, 't' }, + { "nstree", optional_argument, NULL, 'T' }, { NULL, 0, NULL, 0 } }; @@ -1036,7 +1106,7 @@ int main(int argc, char *argv[]) INIT_LIST_HEAD(&netnsids_cache); while ((c = getopt_long(argc, argv, - "Jlp:o:nruhVt:W", long_opts, NULL)) != -1) { + "Jlp:o:nruhVt:T::W", long_opts, NULL)) != -1) { err_exclusive_options(c, long_opts, excl, excl_st); @@ -1080,6 +1150,15 @@ int main(int argc, char *argv[]) case 'W': ls.no_wrap = 1; break; + case 'T': + ls.nstree = LSNS_NSTREE_OWNER; + if (optarg) { + if (strcmp (optarg, "parent") == 0) + ls.nstree = LSNS_NSTREE_PARENT; + else if (strcmp (optarg, "owner") != 0) + errx(EXIT_FAILURE, _("unknown nstree type: %s"), optarg); + } + break; case 'h': usage();