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