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 */
};
int netnsid;
};
+enum {
+ LSNS_NSTREE_OWNER = 1,
+ LSNS_NSTREE_PARENT,
+};
+
struct lsns {
struct list_head processes;
struct list_head namespaces;
list : 1,
no_trunc : 1,
no_headings: 1,
- no_wrap : 1;
+ no_wrap : 1,
+ nstree : 2;
+
struct libmnt_table *tab;
};
}
}
+ 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;
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;
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)
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) {
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;
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);
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));
{ "list", no_argument, NULL, 'l' },
{ "raw", no_argument, NULL, 'r' },
{ "type", required_argument, NULL, 't' },
+ { "nstree", optional_argument, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
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);
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();