]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/lsns.c
Merge branch 'bobbyboy5069-date-pad' of https://github.com/bobbyboy5069/util-linux
[thirdparty/util-linux.git] / sys-utils / lsns.c
1 /*
2 * lsns(8) - list system namespaces
3 *
4 * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <stdio.h>
21 #include <string.h>
22 #include <getopt.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <dirent.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <wchar.h>
30 #include <libsmartcols.h>
31 #include <libmount.h>
32
33 #ifdef HAVE_LINUX_NET_NAMESPACE_H
34 # include <stdbool.h>
35 # include <sys/socket.h>
36 # include <linux/netlink.h>
37 # include <linux/rtnetlink.h>
38 # include <linux/net_namespace.h>
39 #endif
40
41 #ifdef HAVE_LINUX_NSFS_H
42 # include <linux/nsfs.h>
43 # if defined(NS_GET_NSTYPE) && defined(NS_GET_OWNER_UID)
44 # define USE_NS_GET_API 1
45 # endif
46 #endif
47
48 #include "pathnames.h"
49 #include "nls.h"
50 #include "xalloc.h"
51 #include "c.h"
52 #include "list.h"
53 #include "closestream.h"
54 #include "optutils.h"
55 #include "procfs.h"
56 #include "strutils.h"
57 #include "namespace.h"
58 #include "idcache.h"
59 #include "fileutils.h"
60
61 #include "debug.h"
62
63 static UL_DEBUG_DEFINE_MASK(lsns);
64 UL_DEBUG_DEFINE_MASKNAMES(lsns) = UL_DEBUG_EMPTY_MASKNAMES;
65
66 #define LSNS_DEBUG_INIT (1 << 1)
67 #define LSNS_DEBUG_PROC (1 << 2)
68 #define LSNS_DEBUG_NS (1 << 3)
69 #define LSNS_DEBUG_ALL 0xFFFF
70
71 #define LSNS_NETNS_UNUSABLE -2
72
73 #define DBG(m, x) __UL_DBG(lsns, LSNS_DEBUG_, m, x)
74 #define ON_DBG(m, x) __UL_DBG_CALL(lsns, LSNS_DEBUG_, m, x)
75
76 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(lsns)
77 #include "debugobj.h"
78
79 static struct idcache *uid_cache = NULL;
80
81 /* column IDs */
82 enum {
83 COL_NS = 0,
84 COL_TYPE,
85 COL_PATH,
86 COL_NPROCS,
87 COL_PID,
88 COL_PPID,
89 COL_COMMAND,
90 COL_UID,
91 COL_USER,
92 COL_NETNSID,
93 COL_NSFS,
94 COL_PNS, /* parent namespace */
95 COL_ONS, /* owner namespace */
96 };
97
98 /* column names */
99 struct colinfo {
100 const char *name; /* header */
101 double whint; /* width hint (N < 1 is in percent of termwidth) */
102 int flags; /* SCOLS_FL_* */
103 const char *help;
104 int json_type;
105 };
106
107 /* columns descriptions */
108 static const struct colinfo infos[] = {
109 [COL_NS] = { "NS", 10, SCOLS_FL_RIGHT, N_("namespace identifier (inode number)"), SCOLS_JSON_NUMBER },
110 [COL_TYPE] = { "TYPE", 5, 0, N_("kind of namespace") },
111 [COL_PATH] = { "PATH", 0, 0, N_("path to the namespace")},
112 [COL_NPROCS] = { "NPROCS", 5, SCOLS_FL_RIGHT, N_("number of processes in the namespace"), SCOLS_JSON_NUMBER },
113 [COL_PID] = { "PID", 5, SCOLS_FL_RIGHT, N_("lowest PID in the namespace"), SCOLS_JSON_NUMBER },
114 [COL_PPID] = { "PPID", 5, SCOLS_FL_RIGHT, N_("PPID of the PID"), SCOLS_JSON_NUMBER },
115 [COL_COMMAND] = { "COMMAND", 0, SCOLS_FL_TRUNC, N_("command line of the PID")},
116 [COL_UID] = { "UID", 0, SCOLS_FL_RIGHT, N_("UID of the PID"), SCOLS_JSON_NUMBER},
117 [COL_USER] = { "USER", 0, 0, N_("username of the PID")},
118 [COL_NETNSID] = { "NETNSID", 0, SCOLS_FL_RIGHT, N_("namespace ID as used by network subsystem")},
119 [COL_NSFS] = { "NSFS", 0, SCOLS_FL_WRAP, N_("nsfs mountpoint (usually used network subsystem)")},
120 [COL_PNS] = { "PNS", 10, SCOLS_FL_RIGHT, N_("parent namespace identifier (inode number)"), SCOLS_JSON_NUMBER },
121 [COL_ONS] = { "ONS", 10, SCOLS_FL_RIGHT, N_("owner namespace identifier (inode number)"), SCOLS_JSON_NUMBER },
122 };
123
124 static int columns[ARRAY_SIZE(infos) * 2];
125 static size_t ncolumns;
126
127 enum {
128 LSNS_ID_MNT = 0,
129 LSNS_ID_NET,
130 LSNS_ID_PID,
131 LSNS_ID_UTS,
132 LSNS_ID_IPC,
133 LSNS_ID_USER,
134 LSNS_ID_CGROUP,
135 LSNS_ID_TIME
136 };
137
138 static char *ns_names[] = {
139 [LSNS_ID_MNT] = "mnt",
140 [LSNS_ID_NET] = "net",
141 [LSNS_ID_PID] = "pid",
142 [LSNS_ID_UTS] = "uts",
143 [LSNS_ID_IPC] = "ipc",
144 [LSNS_ID_USER] = "user",
145 [LSNS_ID_CGROUP] = "cgroup",
146 [LSNS_ID_TIME] = "time"
147 };
148
149 enum {
150 RELA_PARENT,
151 RELA_OWNER,
152 MAX_RELA
153 };
154
155 struct lsns_namespace {
156 ino_t id;
157 int type; /* LSNS_* */
158 int nprocs;
159 int netnsid;
160 ino_t related_id[MAX_RELA];
161
162 struct lsns_process *proc;
163
164 struct lsns_namespace *related_ns[MAX_RELA];
165 struct libscols_line *ns_outline;
166 uid_t uid_fallback; /* refer this member if `proc' is NULL. */
167
168 struct list_head namespaces; /* lsns->processes member */
169 struct list_head processes; /* head of lsns_process *siblings */
170 };
171
172 struct lsns_process {
173 pid_t pid; /* process PID */
174 pid_t ppid; /* parent's PID */
175 pid_t tpid; /* thread group */
176 char state;
177 uid_t uid;
178
179 ino_t ns_ids[ARRAY_SIZE(ns_names)];
180 ino_t ns_pids[ARRAY_SIZE(ns_names)];
181 ino_t ns_oids[ARRAY_SIZE(ns_names)];
182
183 struct list_head ns_siblings[ARRAY_SIZE(ns_names)];
184
185 struct list_head processes; /* list of processes */
186
187 struct libscols_line *outline;
188 struct lsns_process *parent;
189
190 int netnsid;
191 };
192
193
194 enum {
195 LSNS_TREE_NONE,
196 LSNS_TREE_PROCESS,
197 LSNS_TREE_OWNER,
198 LSNS_TREE_PARENT,
199 };
200
201 struct lsns {
202 struct list_head processes;
203 struct list_head namespaces;
204
205 pid_t fltr_pid; /* filter out by PID */
206 ino_t fltr_ns; /* filter out by namespace */
207 int fltr_types[ARRAY_SIZE(ns_names)];
208 int fltr_ntypes;
209
210 unsigned int raw : 1,
211 json : 1,
212 tree : 2,
213 no_trunc : 1,
214 no_headings: 1,
215 no_wrap : 1;
216
217
218 struct libmnt_table *tab;
219 };
220
221 struct netnsid_cache {
222 ino_t ino;
223 int id;
224 struct list_head netnsids;
225 };
226
227 static struct list_head netnsids_cache;
228
229 static int netlink_fd = -1;
230
231 static void lsns_init_debug(void)
232 {
233 __UL_INIT_DEBUG_FROM_ENV(lsns, LSNS_DEBUG_, 0, LSNS_DEBUG);
234 }
235
236 static int ns_name2type(const char *name)
237 {
238 size_t i;
239
240 for (i = 0; i < ARRAY_SIZE(ns_names); i++) {
241 if (strcmp(ns_names[i], name) == 0)
242 return i;
243 }
244 return -1;
245 }
246
247 static int column_name_to_id(const char *name, size_t namesz)
248 {
249 size_t i;
250
251 assert(name);
252
253 for (i = 0; i < ARRAY_SIZE(infos); i++) {
254 const char *cn = infos[i].name;
255
256 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
257 return i;
258 }
259 warnx(_("unknown column: %s"), name);
260 return -1;
261 }
262
263 static int has_column(int id)
264 {
265 size_t i;
266
267 for (i = 0; i < ncolumns; i++) {
268 if (columns[i] == id)
269 return 1;
270 }
271 return 0;
272 }
273
274 static inline int get_column_id(int num)
275 {
276 assert(num >= 0);
277 assert((size_t) num < ncolumns);
278 assert(columns[num] < (int) ARRAY_SIZE(infos));
279
280 return columns[num];
281 }
282
283 static inline const struct colinfo *get_column_info(unsigned num)
284 {
285 return &infos[ get_column_id(num) ];
286 }
287
288 static int get_ns_ino(int dir, const char *nsname, ino_t *ino, ino_t *pino, ino_t *oino)
289 {
290 struct stat st;
291 char path[16];
292
293 snprintf(path, sizeof(path), "ns/%s", nsname);
294
295 if (fstatat(dir, path, &st, 0) != 0)
296 return -errno;
297 *ino = st.st_ino;
298
299 *pino = 0;
300 *oino = 0;
301
302 #ifdef USE_NS_GET_API
303 int fd, pfd, ofd;
304 fd = openat(dir, path, 0);
305 if (fd < 0)
306 return -errno;
307 if (strcmp(nsname, "pid") == 0 || strcmp(nsname, "user") == 0) {
308 if ((pfd = ioctl(fd, NS_GET_PARENT)) < 0) {
309 if (errno == EPERM)
310 goto user;
311 close(fd);
312 return -errno;
313 }
314 if (fstat(pfd, &st) < 0) {
315 close(pfd);
316 close(fd);
317 return -errno;
318 }
319 *pino = st.st_ino;
320 close(pfd);
321 }
322 user:
323 if ((ofd = ioctl(fd, NS_GET_USERNS)) < 0) {
324 if (errno == EPERM)
325 goto out;
326 close(fd);
327 return -errno;
328 }
329 if (fstat(ofd, &st) < 0) {
330 close(ofd);
331 close(fd);
332 return -errno;
333 }
334 *oino = st.st_ino;
335 close(ofd);
336 out:
337 close(fd);
338 #endif
339 return 0;
340 }
341
342 static int parse_proc_stat(FILE *fp, pid_t *pid, char *state, pid_t *ppid)
343 {
344 char *line = NULL, *p;
345 size_t len = 0;
346 int rc;
347
348 if (getline(&line, &len, fp) < 0) {
349 rc = -errno;
350 goto error;
351 }
352
353 p = strrchr(line, ')');
354 if (p == NULL ||
355 sscanf(line, "%d (", pid) != 1 ||
356 sscanf(p, ") %c %d*[^\n]", state, ppid) != 2) {
357 rc = -EINVAL;
358 goto error;
359 }
360 rc = 0;
361
362 error:
363 free(line);
364 return rc;
365 }
366
367 #ifdef HAVE_LINUX_NET_NAMESPACE_H
368 static int netnsid_cache_find(ino_t netino, int *netnsid)
369 {
370 struct list_head *p;
371
372 list_for_each(p, &netnsids_cache) {
373 struct netnsid_cache *e = list_entry(p,
374 struct netnsid_cache,
375 netnsids);
376 if (e->ino == netino) {
377 *netnsid = e->id;
378 return 1;
379 }
380 }
381
382 return 0;
383 }
384
385 static void netnsid_cache_add(ino_t netino, int netnsid)
386 {
387 struct netnsid_cache *e;
388
389 e = xcalloc(1, sizeof(*e));
390 e->ino = netino;
391 e->id = netnsid;
392 INIT_LIST_HEAD(&e->netnsids);
393 list_add(&e->netnsids, &netnsids_cache);
394 }
395
396 static int get_netnsid_via_netlink_send_request(int target_fd)
397 {
398 unsigned char req[NLMSG_SPACE(sizeof(struct rtgenmsg))
399 + RTA_SPACE(sizeof(int32_t))];
400
401 struct nlmsghdr *nlh = (struct nlmsghdr *)req;
402 struct rtgenmsg *rt = NLMSG_DATA(req);
403 struct rtattr *rta = (struct rtattr *)
404 (req + NLMSG_SPACE(sizeof(struct rtgenmsg)));
405 int32_t *fd = RTA_DATA(rta);
406
407 nlh->nlmsg_len = sizeof(req);
408 nlh->nlmsg_flags = NLM_F_REQUEST;
409 nlh->nlmsg_type = RTM_GETNSID;
410 rt->rtgen_family = AF_UNSPEC;
411 rta->rta_type = NETNSA_FD;
412 rta->rta_len = RTA_SPACE(sizeof(int32_t));
413 *fd = target_fd;
414
415 if (send(netlink_fd, req, sizeof(req), 0) < 0)
416 return -1;
417 return 0;
418 }
419
420 static int get_netnsid_via_netlink_recv_response(int *netnsid)
421 {
422 unsigned char res[NLMSG_SPACE(sizeof(struct rtgenmsg))
423 + ((RTA_SPACE(sizeof(int32_t))
424 < RTA_SPACE(sizeof(struct nlmsgerr)))
425 ? RTA_SPACE(sizeof(struct nlmsgerr))
426 : RTA_SPACE(sizeof(int32_t)))];
427 int rtalen;
428 ssize_t reslen;
429
430 struct nlmsghdr *nlh;
431 struct rtattr *rta;
432
433 reslen = recv(netlink_fd, res, sizeof(res), 0);
434 if (reslen < 0)
435 return -1;
436
437 nlh = (struct nlmsghdr *)res;
438 if (!(NLMSG_OK(nlh, (size_t)reslen)
439 && nlh->nlmsg_type == RTM_NEWNSID))
440 return -1;
441
442 rtalen = NLMSG_PAYLOAD(nlh, sizeof(struct rtgenmsg));
443 rta = (struct rtattr *)(res + NLMSG_SPACE(sizeof(struct rtgenmsg)));
444 if (!(RTA_OK(rta, rtalen)
445 && rta->rta_type == NETNSA_NSID))
446 return -1;
447
448 *netnsid = *(int *)RTA_DATA(rta);
449
450 return 0;
451 }
452
453 static int get_netnsid_via_netlink(int dir, const char *path)
454 {
455 int netnsid;
456 int target_fd;
457
458 if (netlink_fd < 0)
459 return LSNS_NETNS_UNUSABLE;
460
461 target_fd = openat(dir, path, O_RDONLY);
462 if (target_fd < 0)
463 return LSNS_NETNS_UNUSABLE;
464
465 if (get_netnsid_via_netlink_send_request(target_fd) < 0) {
466 netnsid = LSNS_NETNS_UNUSABLE;
467 goto out;
468 }
469
470 if (get_netnsid_via_netlink_recv_response(&netnsid) < 0) {
471 netnsid = LSNS_NETNS_UNUSABLE;
472 goto out;
473 }
474
475 out:
476 close(target_fd);
477 return netnsid;
478 }
479
480 static int get_netnsid(int dir, ino_t netino)
481 {
482 int netnsid;
483
484 if (!netnsid_cache_find(netino, &netnsid)) {
485 netnsid = get_netnsid_via_netlink(dir, "ns/net");
486 netnsid_cache_add(netino, netnsid);
487 }
488
489 return netnsid;
490 }
491 #else
492 static int get_netnsid(int dir __attribute__((__unused__)),
493 ino_t netino __attribute__((__unused__)))
494 {
495 return LSNS_NETNS_UNUSABLE;
496 }
497 #endif /* HAVE_LINUX_NET_NAMESPACE_H */
498
499 static int read_process(struct lsns *ls, pid_t pid)
500 {
501 struct lsns_process *p = NULL;
502 char buf[BUFSIZ];
503 DIR *dir;
504 int rc = 0, fd;
505 FILE *f = NULL;
506 size_t i;
507 struct stat st;
508
509 DBG(PROC, ul_debug("reading %d", (int) pid));
510
511 snprintf(buf, sizeof(buf), "/proc/%d", pid);
512 dir = opendir(buf);
513 if (!dir)
514 return -errno;
515
516 p = xcalloc(1, sizeof(*p));
517 p->netnsid = LSNS_NETNS_UNUSABLE;
518
519 if (fstat(dirfd(dir), &st) == 0) {
520 p->uid = st.st_uid;
521 add_uid(uid_cache, st.st_uid);
522 }
523
524 fd = openat(dirfd(dir), "stat", O_RDONLY);
525 if (fd < 0) {
526 rc = -errno;
527 goto done;
528 }
529 if (!(f = fdopen(fd, "r"))) {
530 rc = -errno;
531 goto done;
532 }
533 rc = parse_proc_stat(f, &p->pid, &p->state, &p->ppid);
534 if (rc < 0)
535 goto done;
536 rc = 0;
537
538 for (i = 0; i < ARRAY_SIZE(p->ns_ids); i++) {
539 INIT_LIST_HEAD(&p->ns_siblings[i]);
540
541 if (!ls->fltr_types[i])
542 continue;
543
544 rc = get_ns_ino(dirfd(dir), ns_names[i], &p->ns_ids[i],
545 &p->ns_pids[i], &p->ns_oids[i]);
546 if (rc && rc != -EACCES && rc != -ENOENT)
547 goto done;
548 if (i == LSNS_ID_NET)
549 p->netnsid = get_netnsid(dirfd(dir), p->ns_ids[i]);
550 rc = 0;
551 }
552
553 INIT_LIST_HEAD(&p->processes);
554
555 DBG(PROC, ul_debugobj(p, "new pid=%d", p->pid));
556 list_add_tail(&p->processes, &ls->processes);
557 done:
558 if (f)
559 fclose(f);
560 closedir(dir);
561 if (rc)
562 free(p);
563 return rc;
564 }
565
566 static int read_processes(struct lsns *ls)
567 {
568 DIR *dir;
569 struct dirent *d;
570 int rc = 0;
571
572 DBG(PROC, ul_debug("opening /proc"));
573
574 dir = opendir(_PATH_PROC);
575 if (!dir)
576 return -errno;
577
578 while ((d = xreaddir(dir))) {
579 pid_t pid = 0;
580
581 if (procfs_dirent_get_pid(d, &pid) != 0)
582 continue;
583
584 /* TODO: use ul_new_procfs_path(pid, NULL) to read files from /proc/pid/
585 */
586 rc = read_process(ls, pid);
587 if (rc && rc != -EACCES && rc != -ENOENT)
588 break;
589 rc = 0;
590 }
591
592 DBG(PROC, ul_debug("closing /proc"));
593 closedir(dir);
594 return rc;
595 }
596
597 static struct lsns_namespace *get_namespace(struct lsns *ls, ino_t ino)
598 {
599 struct list_head *p;
600
601 list_for_each(p, &ls->namespaces) {
602 struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces);
603
604 if (ns->id == ino)
605 return ns;
606 }
607 return NULL;
608 }
609
610 static int namespace_has_process(struct lsns_namespace *ns, pid_t pid)
611 {
612 struct list_head *p;
613
614 list_for_each(p, &ns->processes) {
615 struct lsns_process *proc = list_entry(p, struct lsns_process, ns_siblings[ns->type]);
616
617 if (proc->pid == pid)
618 return 1;
619 }
620 return 0;
621 }
622
623 static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino,
624 ino_t parent_ino, ino_t owner_ino)
625 {
626 struct lsns_namespace *ns = xcalloc(1, sizeof(*ns));
627
628 if (!ns)
629 return NULL;
630
631 DBG(NS, ul_debugobj(ns, "new %s[%ju]", ns_names[type], (uintmax_t)ino));
632
633 INIT_LIST_HEAD(&ns->processes);
634 INIT_LIST_HEAD(&ns->namespaces);
635
636 ns->type = type;
637 ns->id = ino;
638 ns->related_id[RELA_PARENT] = parent_ino;
639 ns->related_id[RELA_OWNER] = owner_ino;
640
641 list_add_tail(&ns->namespaces, &ls->namespaces);
642 return ns;
643 }
644
645 static int add_process_to_namespace(struct lsns *ls, struct lsns_namespace *ns, struct lsns_process *proc)
646 {
647 struct list_head *p;
648
649 DBG(NS, ul_debugobj(ns, "add process [%p] pid=%d to %s[%ju]",
650 proc, proc->pid, ns_names[ns->type], (uintmax_t)ns->id));
651
652 list_for_each(p, &ls->processes) {
653 struct lsns_process *xproc = list_entry(p, struct lsns_process, processes);
654
655 if (xproc->pid == proc->ppid) /* my parent */
656 proc->parent = xproc;
657 else if (xproc->ppid == proc->pid) /* my child */
658 xproc->parent = proc;
659 }
660
661 list_add_tail(&proc->ns_siblings[ns->type], &ns->processes);
662 ns->nprocs++;
663
664 if (!ns->proc || ns->proc->pid > proc->pid)
665 ns->proc = proc;
666
667 return 0;
668 }
669
670 static int cmp_namespaces(struct list_head *a, struct list_head *b,
671 __attribute__((__unused__)) void *data)
672 {
673 struct lsns_namespace *xa = list_entry(a, struct lsns_namespace, namespaces),
674 *xb = list_entry(b, struct lsns_namespace, namespaces);
675
676 return cmp_numbers(xa->id, xb->id);
677 }
678
679 static int netnsid_xasputs(char **str, int netnsid)
680 {
681 if (netnsid >= 0)
682 return xasprintf(str, "%d", netnsid);
683 #ifdef NETNSA_NSID_NOT_ASSIGNED
684 if (netnsid == NETNSA_NSID_NOT_ASSIGNED)
685 return xasprintf(str, "%s", "unassigned");
686 #endif
687 return 0;
688 }
689
690 #ifdef USE_NS_GET_API
691 static int clone_type_to_lsns_type(int clone_type)
692 {
693 switch (clone_type) {
694 case CLONE_NEWNS:
695 return LSNS_ID_MNT;
696 case CLONE_NEWCGROUP:
697 return LSNS_ID_CGROUP;
698 case CLONE_NEWUTS:
699 return LSNS_ID_UTS;
700 case CLONE_NEWIPC:
701 return LSNS_ID_IPC;
702 case CLONE_NEWUSER:
703 return LSNS_ID_USER;
704 case CLONE_NEWPID:
705 return LSNS_ID_PID;
706 case CLONE_NEWNET:
707 return LSNS_ID_NET;
708 default:
709 return -1;
710 }
711 }
712
713 static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, ino_t ino)
714 {
715 int fd_owner = -1, fd_parent = -1;
716 struct stat st_owner, st_parent;
717 ino_t ino_owner = 0, ino_parent = 0;
718 struct lsns_namespace *ns;
719 int clone_type, lsns_type;
720
721 clone_type = ioctl(fd, NS_GET_NSTYPE);
722 if (clone_type < 0)
723 return NULL;
724 lsns_type = clone_type_to_lsns_type(clone_type);
725 if (lsns_type < 0)
726 return NULL;
727
728 fd_owner = ioctl(fd, NS_GET_USERNS);
729 if (fd_owner < 0)
730 goto parent;
731 if (fstat(fd_owner, &st_owner) < 0)
732 goto parent;
733 ino_owner = st_owner.st_ino;
734
735 parent:
736 fd_parent = ioctl(fd, NS_GET_PARENT);
737 if (fd_parent < 0)
738 goto add_ns;
739 if (fstat(fd_parent, &st_parent) < 0)
740 goto add_ns;
741 ino_parent = st_parent.st_ino;
742
743 add_ns:
744 ns = add_namespace(ls, lsns_type, ino, ino_parent, ino_owner);
745 ioctl(fd, NS_GET_OWNER_UID, &ns->uid_fallback);
746 add_uid(uid_cache, ns->uid_fallback);
747
748 if ((lsns_type == LSNS_ID_USER || lsns_type == LSNS_ID_PID)
749 && ino_parent != ino && ino_parent != 0) {
750 ns->related_ns[RELA_PARENT] = get_namespace(ls, ino_parent);
751 if (!ns->related_ns[RELA_PARENT]) {
752 ns->related_ns[RELA_PARENT] = add_namespace_for_nsfd(ls, fd_parent, ino_parent);
753 if (ino_parent == ino_owner)
754 ns->related_ns[RELA_OWNER] = ns->related_ns[RELA_PARENT];
755 }
756 }
757
758 if (ns->related_ns[RELA_OWNER] == NULL && ino_owner != 0) {
759 ns->related_ns[RELA_OWNER] = get_namespace(ls, ino_owner);
760 if (!ns->related_ns[RELA_OWNER])
761 ns->related_ns[RELA_OWNER] = add_namespace_for_nsfd(ls, fd_owner, ino_owner);
762 }
763
764 if (fd_owner >= 0)
765 close(fd_owner);
766 if (fd_parent >= 0)
767 close(fd_parent);
768
769 return ns;
770 }
771
772 static void interpolate_missing_namespaces(struct lsns *ls, struct lsns_namespace *orphan, int rela)
773 {
774 const int cmd[MAX_RELA] = {
775 [RELA_PARENT] = NS_GET_PARENT,
776 [RELA_OWNER] = NS_GET_USERNS
777 };
778 char buf[BUFSIZ];
779 int fd_orphan, fd_missing;
780 struct stat st;
781
782 orphan->related_ns[rela] = get_namespace(ls, orphan->related_id[rela]);
783 if (orphan->related_ns[rela])
784 return;
785
786 snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", orphan->proc->pid, ns_names[orphan->type]);
787 fd_orphan = open(buf, O_RDONLY);
788 if (fd_orphan < 0)
789 return;
790
791 fd_missing = ioctl(fd_orphan, cmd[rela]);
792 close(fd_orphan);
793 if (fd_missing < 0)
794 return;
795
796 if (fstat(fd_missing, &st) < 0
797 || st.st_ino != orphan->related_id[rela]) {
798 close(fd_missing);
799 return;
800 }
801
802 orphan->related_ns[rela] = add_namespace_for_nsfd(ls, fd_missing, orphan->related_id[rela]);
803 close(fd_missing);
804 }
805
806 static void read_related_namespaces(struct lsns *ls)
807 {
808 struct list_head *p;
809 struct lsns_namespace *orphan[2] = {NULL, NULL};
810 int rela;
811
812 list_for_each(p, &ls->namespaces) {
813 struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces);
814 struct list_head *pp;
815 list_for_each(pp, &ls->namespaces) {
816 struct lsns_namespace *pns = list_entry(pp, struct lsns_namespace, namespaces);
817 if (ns->type == LSNS_ID_USER
818 || ns->type == LSNS_ID_PID) {
819 if (ns->related_id[RELA_PARENT] == pns->id)
820 ns->related_ns[RELA_PARENT] = pns;
821 if (ns->related_id[RELA_OWNER] == pns->id)
822 ns->related_ns[RELA_OWNER] = pns;
823 if (ns->related_ns[RELA_PARENT] && ns->related_ns[RELA_OWNER])
824 break;
825 } else {
826 if (ns->related_id[RELA_OWNER] == pns->id) {
827 ns->related_ns[RELA_OWNER] = pns;
828 break;
829 }
830 }
831 }
832
833 /* lsns scans /proc/[0-9]+ for finding namespaces.
834 * So if a namespace has no process, lsns cannot
835 * find it. Here we call it a missing namespace.
836 *
837 * If the id for a related namesspce is known but
838 * namespace for the id is not found, there must
839 * be orphan namespaces. A missing namespace is an
840 * owner or a parent of the orphan namespace.
841 */
842 for (rela = 0; rela < MAX_RELA; rela++) {
843 if (ns->related_id[rela] != 0
844 && ns->related_ns[rela] == NULL) {
845 ns->related_ns[rela] = orphan[rela];
846 orphan[rela] = ns;
847 }
848 }
849 }
850
851 for (rela = 0; rela < MAX_RELA; rela++) {
852 while (orphan[rela]) {
853 struct lsns_namespace *current = orphan[rela];
854 orphan[rela] = orphan[rela]->related_ns[rela];
855 current->related_ns[rela] = NULL;
856 interpolate_missing_namespaces(ls, current, rela);
857 }
858 }
859 }
860
861 #endif /* USE_NS_GET_API */
862
863 static int read_namespaces(struct lsns *ls)
864 {
865 struct list_head *p;
866
867 DBG(NS, ul_debug("reading namespace"));
868
869 list_for_each(p, &ls->processes) {
870 size_t i;
871 struct lsns_namespace *ns;
872 struct lsns_process *proc = list_entry(p, struct lsns_process, processes);
873
874 for (i = 0; i < ARRAY_SIZE(proc->ns_ids); i++) {
875 if (proc->ns_ids[i] == 0)
876 continue;
877 if (!(ns = get_namespace(ls, proc->ns_ids[i]))) {
878 ns = add_namespace(ls, i, proc->ns_ids[i],
879 proc->ns_pids[i], proc->ns_oids[i]);
880 if (!ns)
881 return -ENOMEM;
882 }
883 add_process_to_namespace(ls, ns, proc);
884 }
885 }
886
887 #ifdef USE_NS_GET_API
888 if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
889 read_related_namespaces(ls);
890 #endif
891 list_sort(&ls->namespaces, cmp_namespaces, NULL);
892
893 return 0;
894 }
895
896 static int is_nsfs_root(struct libmnt_fs *fs, void *data)
897 {
898 if (!mnt_fs_match_fstype(fs, "nsfs") || !mnt_fs_get_root(fs))
899 return 0;
900
901 return (strcmp(mnt_fs_get_root(fs), (char *)data) == 0);
902 }
903
904 static int is_path_included(const char *path_set, const char *elt,
905 const char sep)
906 {
907 size_t elt_len;
908 size_t path_set_len;
909 char *tmp;
910
911
912 tmp = strstr(path_set, elt);
913 if (!tmp)
914 return 0;
915
916 elt_len = strlen(elt);
917 path_set_len = strlen(path_set);
918
919 /* path_set includes only elt or
920 * path_set includes elt as the first element.
921 */
922 if (tmp == path_set
923 && ((path_set_len == elt_len)
924 || (path_set[elt_len] == sep)))
925 return 1;
926
927 /* path_set includes elt at the middle
928 * or as the last element.
929 */
930 if ((*(tmp - 1) == sep)
931 && ((*(tmp + elt_len) == sep)
932 || (*(tmp + elt_len) == '\0')))
933 return 1;
934
935 return 0;
936 }
937
938 static int nsfs_xasputs(char **str,
939 struct lsns_namespace *ns,
940 struct libmnt_table *tab,
941 char sep)
942 {
943 struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
944 char *expected_root;
945 struct libmnt_fs *fs = NULL;
946
947 xasprintf(&expected_root, "%s:[%ju]", ns_names[ns->type], (uintmax_t)ns->id);
948 *str = NULL;
949
950 while (mnt_table_find_next_fs(tab, itr, is_nsfs_root,
951 expected_root, &fs) == 0) {
952
953 const char *tgt = mnt_fs_get_target(fs);
954
955 if (!*str)
956 xasprintf(str, "%s", tgt);
957
958 else if (!is_path_included(*str, tgt, sep)) {
959 char *tmp = NULL;
960
961 xasprintf(&tmp, "%s%c%s", *str, sep, tgt);
962 free(*str);
963 *str = tmp;
964 }
965 }
966 free(expected_root);
967 mnt_free_iter(itr);
968
969 return 1;
970 }
971 static void add_scols_line(struct lsns *ls, struct libscols_table *table,
972 struct lsns_namespace *ns, struct lsns_process *proc)
973 {
974 size_t i;
975 struct libscols_line *line;
976
977 assert(ns);
978 assert(table);
979
980 line = scols_table_new_line(table,
981 (ls->tree == LSNS_TREE_PROCESS && proc) && proc->parent ? proc->parent->outline:
982 (ls->tree == LSNS_TREE_PARENT) && ns->related_ns[RELA_PARENT] ? ns->related_ns[RELA_PARENT]->ns_outline:
983 (ls->tree == LSNS_TREE_OWNER) && ns->related_ns[RELA_OWNER] ? ns->related_ns[RELA_OWNER]->ns_outline:
984 NULL);
985 if (!line) {
986 warn(_("failed to add line to output"));
987 return;
988 }
989
990 for (i = 0; i < ncolumns; i++) {
991 char *str = NULL;
992
993 switch (get_column_id(i)) {
994 case COL_NS:
995 xasprintf(&str, "%ju", (uintmax_t)ns->id);
996 break;
997 case COL_PID:
998 if (proc)
999 xasprintf(&str, "%d", (int) proc->pid);
1000 break;
1001 case COL_PPID:
1002 if (proc)
1003 xasprintf(&str, "%d", (int) proc->ppid);
1004 break;
1005 case COL_TYPE:
1006 xasprintf(&str, "%s", ns_names[ns->type]);
1007 break;
1008 case COL_NPROCS:
1009 xasprintf(&str, "%d", ns->nprocs);
1010 break;
1011 case COL_COMMAND:
1012 if (!proc)
1013 break;
1014 str = pid_get_cmdline(proc->pid);
1015 if (!str)
1016 str = pid_get_cmdname(proc->pid);
1017 break;
1018 case COL_PATH:
1019 if (!proc)
1020 break;
1021 xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]);
1022 break;
1023 case COL_UID:
1024 xasprintf(&str, "%d", proc? (int) proc->uid: (int) ns->uid_fallback);
1025 break;
1026 case COL_USER:
1027 xasprintf(&str, "%s", get_id(uid_cache, proc? proc->uid: ns->uid_fallback)->name);
1028 break;
1029 case COL_NETNSID:
1030 if (!proc)
1031 break;
1032 if (ns->type == LSNS_ID_NET)
1033 netnsid_xasputs(&str, proc->netnsid);
1034 break;
1035 case COL_NSFS:
1036 nsfs_xasputs(&str, ns, ls->tab, ls->no_wrap ? ',' : '\n');
1037 break;
1038 case COL_PNS:
1039 xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_PARENT]);
1040 break;
1041 case COL_ONS:
1042 xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_OWNER]);
1043 break;
1044 default:
1045 break;
1046 }
1047
1048 if (str && scols_line_refer_data(line, i, str) != 0)
1049 err_oom();
1050 }
1051
1052 if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
1053 ns->ns_outline = line;
1054 else if (proc)
1055 proc->outline = line;
1056 }
1057
1058 static struct libscols_table *init_scols_table(struct lsns *ls)
1059 {
1060 struct libscols_table *tab;
1061 size_t i;
1062
1063 tab = scols_new_table();
1064 if (!tab) {
1065 warn(_("failed to initialize output table"));
1066 return NULL;
1067 }
1068
1069 scols_table_enable_raw(tab, ls->raw);
1070 scols_table_enable_json(tab, ls->json);
1071 scols_table_enable_noheadings(tab, ls->no_headings);
1072
1073 if (ls->json)
1074 scols_table_set_name(tab, "namespaces");
1075
1076 for (i = 0; i < ncolumns; i++) {
1077 const struct colinfo *col = get_column_info(i);
1078 int flags = col->flags;
1079 struct libscols_column *cl;
1080
1081 if (ls->no_trunc)
1082 flags &= ~SCOLS_FL_TRUNC;
1083 if (ls->tree == LSNS_TREE_PROCESS && get_column_id(i) == COL_COMMAND)
1084 flags |= SCOLS_FL_TREE;
1085 if (ls->no_wrap)
1086 flags &= ~SCOLS_FL_WRAP;
1087 if ((ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
1088 && get_column_id(i) == COL_NS) {
1089 flags |= SCOLS_FL_TREE;
1090 flags &= ~SCOLS_FL_RIGHT;
1091 }
1092
1093 cl = scols_table_new_column(tab, col->name, col->whint, flags);
1094 if (cl == NULL) {
1095 warnx(_("failed to initialize output column"));
1096 goto err;
1097 }
1098 if (ls->json)
1099 scols_column_set_json_type(cl, col->json_type);
1100
1101 if (!ls->no_wrap && get_column_id(i) == COL_NSFS) {
1102 scols_column_set_wrapfunc(cl,
1103 scols_wrapnl_chunksize,
1104 scols_wrapnl_nextchunk,
1105 NULL);
1106 scols_column_set_safechars(cl, "\n");
1107 }
1108 }
1109
1110 return tab;
1111 err:
1112 scols_unref_table(tab);
1113 return NULL;
1114 }
1115
1116 static void show_namespace(struct lsns *ls, struct libscols_table *tab,
1117 struct lsns_namespace *ns, struct lsns_process *proc)
1118 {
1119 /*
1120 * create a tree from owner->owned and/or parent->child relation
1121 */
1122 if (ls->tree == LSNS_TREE_OWNER
1123 && ns->related_ns[RELA_OWNER]
1124 && !ns->related_ns[RELA_OWNER]->ns_outline)
1125 show_namespace(ls, tab, ns->related_ns[RELA_OWNER], ns->related_ns[RELA_OWNER]->proc);
1126 else if (ls->tree == LSNS_TREE_PARENT) {
1127 if (ns->related_ns[RELA_PARENT]) {
1128 if (!ns->related_ns[RELA_PARENT]->ns_outline)
1129 show_namespace(ls, tab, ns->related_ns[RELA_PARENT], ns->related_ns[RELA_PARENT]->proc);
1130 }
1131 else if (ns->related_ns[RELA_OWNER] && !ns->related_ns[RELA_OWNER]->ns_outline)
1132 show_namespace(ls, tab, ns->related_ns[RELA_OWNER], ns->related_ns[RELA_OWNER]->proc);
1133 }
1134
1135 add_scols_line(ls, tab, ns, proc);
1136 }
1137
1138 static int show_namespaces(struct lsns *ls)
1139 {
1140 struct libscols_table *tab;
1141 struct list_head *p;
1142 int rc = 0;
1143
1144 tab = init_scols_table(ls);
1145 if (!tab)
1146 return -ENOMEM;
1147
1148 list_for_each(p, &ls->namespaces) {
1149 struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces);
1150
1151 if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid))
1152 continue;
1153
1154 if (!ns->ns_outline)
1155 show_namespace(ls, tab, ns, ns->proc);
1156 }
1157
1158 scols_print_table(tab);
1159 scols_unref_table(tab);
1160 return rc;
1161 }
1162
1163 static void show_process(struct lsns *ls, struct libscols_table *tab,
1164 struct lsns_process *proc, struct lsns_namespace *ns)
1165 {
1166 /*
1167 * create a tree from parent->child relation, but only if the parent is
1168 * within the same namespace
1169 */
1170 if (ls->tree == LSNS_TREE_PROCESS
1171 && proc->parent
1172 && !proc->parent->outline
1173 && proc->parent->ns_ids[ns->type] == proc->ns_ids[ns->type])
1174 show_process(ls, tab, proc->parent, ns);
1175
1176 add_scols_line(ls, tab, ns, proc);
1177 }
1178
1179
1180 static int show_namespace_processes(struct lsns *ls, struct lsns_namespace *ns)
1181 {
1182 struct libscols_table *tab;
1183 struct list_head *p;
1184
1185 tab = init_scols_table(ls);
1186 if (!tab)
1187 return -ENOMEM;
1188
1189 list_for_each(p, &ns->processes) {
1190 struct lsns_process *proc = list_entry(p, struct lsns_process, ns_siblings[ns->type]);
1191
1192 if (!proc->outline)
1193 show_process(ls, tab, proc, ns);
1194 }
1195
1196
1197 scols_print_table(tab);
1198 scols_unref_table(tab);
1199 return 0;
1200 }
1201
1202 static void free_lsns_process(struct lsns_process *lsns_p)
1203 {
1204 free(lsns_p);
1205 }
1206
1207 static void free_netnsid_caches(struct netnsid_cache *cache)
1208 {
1209 free(cache);
1210 }
1211
1212 static void free_lsns_namespace(struct lsns_namespace *lsns_n)
1213 {
1214 free(lsns_n);
1215 }
1216
1217 static void free_all(struct lsns *ls)
1218 {
1219 list_free(&ls->processes, struct lsns_process, processes, free_lsns_process);
1220 list_free(&netnsids_cache, struct netnsid_cache, netnsids, free_netnsid_caches);
1221 list_free(&ls->namespaces, struct lsns_namespace, namespaces, free_lsns_namespace);
1222 }
1223
1224 static void __attribute__((__noreturn__)) usage(void)
1225 {
1226 FILE *out = stdout;
1227 size_t i;
1228
1229 fputs(USAGE_HEADER, out);
1230
1231 fprintf(out,
1232 _(" %s [options] [<namespace>]\n"), program_invocation_short_name);
1233
1234 fputs(USAGE_SEPARATOR, out);
1235 fputs(_("List system namespaces.\n"), out);
1236
1237 fputs(USAGE_OPTIONS, out);
1238 fputs(_(" -J, --json use JSON output format\n"), out);
1239 fputs(_(" -l, --list use list format output\n"), out);
1240 fputs(_(" -n, --noheadings don't print headings\n"), out);
1241 fputs(_(" -o, --output <list> define which output columns to use\n"), out);
1242 fputs(_(" --output-all output all columns\n"), out);
1243 fputs(_(" -p, --task <pid> print process namespaces\n"), out);
1244 fputs(_(" -r, --raw use the raw output format\n"), out);
1245 fputs(_(" -u, --notruncate don't truncate text in columns\n"), out);
1246 fputs(_(" -W, --nowrap don't use multi-line representation\n"), out);
1247 fputs(_(" -t, --type <name> namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out);
1248 fputs(_(" -T, --tree <rel> use tree format (parent, owner, or process)\n"), out);
1249
1250 fputs(USAGE_SEPARATOR, out);
1251 printf(USAGE_HELP_OPTIONS(24));
1252
1253 fputs(USAGE_COLUMNS, out);
1254 for (i = 0; i < ARRAY_SIZE(infos); i++)
1255 fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help));
1256
1257 printf(USAGE_MAN_TAIL("lsns(8)"));
1258
1259 exit(EXIT_SUCCESS);
1260 }
1261
1262
1263 int main(int argc, char *argv[])
1264 {
1265 struct lsns ls;
1266 int c, force_list = 0;
1267 int r = 0;
1268 char *outarg = NULL;
1269 enum {
1270 OPT_OUTPUT_ALL = CHAR_MAX + 1
1271 };
1272 static const struct option long_opts[] = {
1273 { "json", no_argument, NULL, 'J' },
1274 { "task", required_argument, NULL, 'p' },
1275 { "help", no_argument, NULL, 'h' },
1276 { "output", required_argument, NULL, 'o' },
1277 { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
1278 { "notruncate", no_argument, NULL, 'u' },
1279 { "version", no_argument, NULL, 'V' },
1280 { "noheadings", no_argument, NULL, 'n' },
1281 { "nowrap", no_argument, NULL, 'W' },
1282 { "list", no_argument, NULL, 'l' },
1283 { "raw", no_argument, NULL, 'r' },
1284 { "type", required_argument, NULL, 't' },
1285 { "tree", optional_argument, NULL, 'T' },
1286 { NULL, 0, NULL, 0 }
1287 };
1288
1289 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
1290 { 'J','r' },
1291 { 'l','T' },
1292 { 0 }
1293 };
1294 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1295 int is_net = 0;
1296
1297 setlocale(LC_ALL, "");
1298 bindtextdomain(PACKAGE, LOCALEDIR);
1299 textdomain(PACKAGE);
1300 close_stdout_atexit();
1301
1302 lsns_init_debug();
1303 memset(&ls, 0, sizeof(ls));
1304
1305 INIT_LIST_HEAD(&ls.processes);
1306 INIT_LIST_HEAD(&ls.namespaces);
1307 INIT_LIST_HEAD(&netnsids_cache);
1308
1309 while ((c = getopt_long(argc, argv,
1310 "Jlp:o:nruhVt:T::W", long_opts, NULL)) != -1) {
1311
1312 err_exclusive_options(c, long_opts, excl, excl_st);
1313
1314 switch(c) {
1315 case 'J':
1316 ls.json = 1;
1317 break;
1318 case 'l':
1319 force_list = 1;
1320 break;
1321 case 'o':
1322 outarg = optarg;
1323 break;
1324 case OPT_OUTPUT_ALL:
1325 for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
1326 columns[ncolumns] = ncolumns;
1327 break;
1328 case 'p':
1329 ls.fltr_pid = strtos32_or_err(optarg, _("invalid PID argument"));
1330 break;
1331 case 'n':
1332 ls.no_headings = 1;
1333 break;
1334 case 'r':
1335 ls.no_wrap = ls.raw = 1;
1336 break;
1337 case 'u':
1338 ls.no_trunc = 1;
1339 break;
1340 case 't':
1341 {
1342 int type = ns_name2type(optarg);
1343 if (type < 0)
1344 errx(EXIT_FAILURE, _("unknown namespace type: %s"), optarg);
1345 ls.fltr_types[type] = 1;
1346 ls.fltr_ntypes++;
1347 if (type == LSNS_ID_NET)
1348 is_net = 1;
1349 break;
1350 }
1351 case 'W':
1352 ls.no_wrap = 1;
1353 break;
1354 case 'T':
1355 ls.tree = LSNS_TREE_OWNER;
1356 if (optarg) {
1357 if (*optarg == '=')
1358 optarg++;
1359 if (strcmp (optarg, "parent") == 0)
1360 ls.tree = LSNS_TREE_PARENT;
1361 else if (strcmp (optarg, "process") == 0)
1362 ls.tree = LSNS_TREE_PROCESS;
1363 else if (strcmp (optarg, "owner") != 0)
1364 errx(EXIT_FAILURE, _("unknown tree type: %s"), optarg);
1365 }
1366 break;
1367
1368 case 'h':
1369 usage();
1370 case 'V':
1371 print_version(EXIT_SUCCESS);
1372 default:
1373 errtryhelp(EXIT_FAILURE);
1374 }
1375 }
1376
1377 if (!ls.fltr_ntypes) {
1378 size_t i;
1379
1380 for (i = 0; i < ARRAY_SIZE(ns_names); i++)
1381 ls.fltr_types[i] = 1;
1382 }
1383
1384 if (optind < argc) {
1385 if (ls.fltr_pid)
1386 errx(EXIT_FAILURE, _("--task is mutually exclusive with <namespace>"));
1387 ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument"));
1388 if (!ls.tree && !force_list)
1389 ls.tree = LSNS_TREE_PROCESS;
1390
1391 if (!ncolumns) {
1392 columns[ncolumns++] = COL_PID;
1393 columns[ncolumns++] = COL_PPID;
1394 columns[ncolumns++] = COL_USER;
1395 columns[ncolumns++] = COL_COMMAND;
1396 }
1397 }
1398
1399 if (!ncolumns) {
1400 columns[ncolumns++] = COL_NS;
1401 columns[ncolumns++] = COL_TYPE;
1402 columns[ncolumns++] = COL_NPROCS;
1403 columns[ncolumns++] = COL_PID;
1404 columns[ncolumns++] = COL_USER;
1405 if (is_net) {
1406 columns[ncolumns++] = COL_NETNSID;
1407 columns[ncolumns++] = COL_NSFS;
1408 }
1409 columns[ncolumns++] = COL_COMMAND;
1410
1411 if (!ls.tree && !force_list)
1412 ls.tree = LSNS_TREE_PROCESS;
1413 }
1414
1415 #ifndef USE_NS_GET_API
1416 if (ls.tree && ls.tree != LSNS_TREE_PROCESS)
1417 errx(EXIT_FAILURE, _("--tree={parent|owner} is unsupported for your system"));
1418 #endif
1419 if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
1420 &ncolumns, column_name_to_id) < 0)
1421 return EXIT_FAILURE;
1422
1423 scols_init_debug(0);
1424
1425 uid_cache = new_idcache();
1426 if (!uid_cache)
1427 err(EXIT_FAILURE, _("failed to allocate UID cache"));
1428
1429 #ifdef HAVE_LINUX_NET_NAMESPACE_H
1430 if (has_column(COL_NETNSID))
1431 netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1432 #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 }
1438
1439 r = read_processes(&ls);
1440 if (!r)
1441 r = read_namespaces(&ls);
1442 if (!r) {
1443 if (ls.fltr_ns) {
1444 struct lsns_namespace *ns = get_namespace(&ls, ls.fltr_ns);
1445
1446 if (!ns)
1447 errx(EXIT_FAILURE, _("not found namespace: %ju"), (uintmax_t) ls.fltr_ns);
1448 r = show_namespace_processes(&ls, ns);
1449 } else
1450 r = show_namespaces(&ls);
1451 }
1452
1453 mnt_free_table(ls.tab);
1454 if (netlink_fd >= 0)
1455 close(netlink_fd);
1456 free_idcache(uid_cache);
1457
1458 free_all(&ls);
1459
1460 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1461 }