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 <yamato@redhat.com>
This commit is contained in:
parent
aa049eabb3
commit
e8c56ae2d7
|
@ -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.
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue