]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsns: print namespace tree based on the relationship (parent/child or owner/owned)
authorMasatake YAMATO <yamato@redhat.com>
Thu, 15 Apr 2021 09:03:57 +0000 (18:03 +0900)
committerKarel Zak <kzak@redhat.com>
Mon, 24 May 2021 11:39:52 +0000 (13:39 +0200)
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 <yamato@redhat.com>
sys-utils/lsns.8.adoc
sys-utils/lsns.c

index ab7e7aea888fc838f63d9571e55a2a5004319ea2..77875223bd78731be211499e19d0be89936327c3 100644 (file)
@@ -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.
 
index 8e25ff1831b9a70c30752c24bdbe83cad7143c9b..23a2eabacc00dd7e262d41e24439555f9ca548c9 100644 (file)
@@ -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 <name>      namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out);
+       fputs(_(" -T, --nstree <rel>     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();