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