2 * lsns(8) - list system namespaces
4 * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
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.
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.
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
28 #include <sys/types.h>
30 #include <libsmartcols.h>
33 #ifdef HAVE_LINUX_NET_NAMESPACE_H
35 #include <sys/socket.h>
36 #include <linux/netlink.h>
37 #include <linux/rtnetlink.h>
38 #include <linux/net_namespace.h>
41 #include "pathnames.h"
46 #include "closestream.h"
48 #include "procutils.h"
50 #include "namespace.h"
56 static UL_DEBUG_DEFINE_MASK(lsns
);
57 UL_DEBUG_DEFINE_MASKNAMES(lsns
) = UL_DEBUG_EMPTY_MASKNAMES
;
59 #define LSNS_DEBUG_INIT (1 << 1)
60 #define LSNS_DEBUG_PROC (1 << 2)
61 #define LSNS_DEBUG_NS (1 << 3)
62 #define LSNS_DEBUG_ALL 0xFFFF
64 #define LSNS_NETNS_UNUSABLE -2
66 #define DBG(m, x) __UL_DBG(lsns, LSNS_DEBUG_, m, x)
67 #define ON_DBG(m, x) __UL_DBG_CALL(lsns, LSNS_DEBUG_, m, x)
69 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(lsns)
72 static struct idcache
*uid_cache
= NULL
;
91 const char *name
; /* header */
92 double whint
; /* width hint (N < 1 is in percent of termwidth) */
93 int flags
; /* SCOLS_FL_* */
97 /* columns descriptions */
98 static const struct colinfo infos
[] = {
99 [COL_NS
] = { "NS", 10, SCOLS_FL_RIGHT
, N_("namespace identifier (inode number)") },
100 [COL_TYPE
] = { "TYPE", 5, 0, N_("kind of namespace") },
101 [COL_PATH
] = { "PATH", 0, 0, N_("path to the namespace")},
102 [COL_NPROCS
] = { "NPROCS", 5, SCOLS_FL_RIGHT
, N_("number of processes in the namespace") },
103 [COL_PID
] = { "PID", 5, SCOLS_FL_RIGHT
, N_("lowest PID in the namespace") },
104 [COL_PPID
] = { "PPID", 5, SCOLS_FL_RIGHT
, N_("PPID of the PID") },
105 [COL_COMMAND
] = { "COMMAND", 0, SCOLS_FL_TRUNC
, N_("command line of the PID")},
106 [COL_UID
] = { "UID", 0, SCOLS_FL_RIGHT
, N_("UID of the PID")},
107 [COL_USER
] = { "USER", 0, 0, N_("username of the PID")},
108 [COL_NETNSID
] = { "NETNSID", 0, SCOLS_FL_RIGHT
, N_("namespace ID as used by network subsystem")},
109 [COL_NSFS
] = { "NSFS", 0, SCOLS_FL_WRAP
, N_("nsfs mountpoint (usually used network subsystem)")}
112 static int columns
[ARRAY_SIZE(infos
) * 2];
113 static size_t ncolumns
;
125 static char *ns_names
[] = {
126 [LSNS_ID_MNT
] = "mnt",
127 [LSNS_ID_NET
] = "net",
128 [LSNS_ID_PID
] = "pid",
129 [LSNS_ID_UTS
] = "uts",
130 [LSNS_ID_IPC
] = "ipc",
131 [LSNS_ID_USER
] = "user",
132 [LSNS_ID_CGROUP
] = "cgroup"
135 struct lsns_namespace
{
137 int type
; /* LSNS_* */
141 struct lsns_process
*proc
;
143 struct list_head namespaces
; /* lsns->processes member */
144 struct list_head processes
; /* head of lsns_process *siblings */
147 struct lsns_process
{
148 pid_t pid
; /* process PID */
149 pid_t ppid
; /* parent's PID */
150 pid_t tpid
; /* thread group */
154 ino_t ns_ids
[ARRAY_SIZE(ns_names
)];
155 struct list_head ns_siblings
[ARRAY_SIZE(ns_names
)];
157 struct list_head processes
; /* list of processes */
159 struct libscols_line
*outline
;
160 struct lsns_process
*parent
;
166 struct list_head processes
;
167 struct list_head namespaces
;
169 pid_t fltr_pid
; /* filter out by PID */
170 ino_t fltr_ns
; /* filter out by namespace */
171 int fltr_types
[ARRAY_SIZE(ns_names
)];
174 unsigned int raw
: 1,
182 struct libmnt_table
*tab
;
185 struct netnsid_cache
{
188 struct list_head netnsids
;
191 static struct list_head netnsids_cache
;
193 static int netlink_fd
= -1;
195 static void lsns_init_debug(void)
197 __UL_INIT_DEBUG(lsns
, LSNS_DEBUG_
, 0, LSNS_DEBUG
);
200 static int ns_name2type(const char *name
)
204 for (i
= 0; i
< ARRAY_SIZE(ns_names
); i
++) {
205 if (strcmp(ns_names
[i
], name
) == 0)
211 static int column_name_to_id(const char *name
, size_t namesz
)
217 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++) {
218 const char *cn
= infos
[i
].name
;
220 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
223 warnx(_("unknown column: %s"), name
);
227 static int has_column(int id
)
231 for (i
= 0; i
< ncolumns
; i
++) {
232 if (columns
[i
] == id
)
238 static inline int get_column_id(int num
)
241 assert((size_t) num
< ncolumns
);
242 assert(columns
[num
] < (int) ARRAY_SIZE(infos
));
247 static inline const struct colinfo
*get_column_info(unsigned num
)
249 return &infos
[ get_column_id(num
) ];
252 static int get_ns_ino(int dir
, const char *nsname
, ino_t
*ino
)
257 snprintf(path
, sizeof(path
), "ns/%s", nsname
);
259 if (fstatat(dir
, path
, &st
, 0) != 0)
265 static int parse_proc_stat(FILE *fp
, pid_t
*pid
, char *state
, pid_t
*ppid
)
267 char *line
= NULL
, *p
;
271 if (getline(&line
, &len
, fp
) < 0) {
276 p
= strrchr(line
, ')');
278 sscanf(line
, "%d (", pid
) != 1 ||
279 sscanf(p
, ") %c %d*[^\n]", state
, ppid
) != 2) {
290 #ifdef HAVE_LINUX_NET_NAMESPACE_H
291 static int netnsid_cache_find(ino_t netino
, int *netnsid
)
295 list_for_each(p
, &netnsids_cache
) {
296 struct netnsid_cache
*e
= list_entry(p
,
297 struct netnsid_cache
,
299 if (e
->ino
== netino
) {
308 static void netnsid_cache_add(ino_t netino
, int netnsid
)
310 struct netnsid_cache
*e
;
312 e
= xcalloc(1, sizeof(*e
));
315 INIT_LIST_HEAD(&e
->netnsids
);
316 list_add(&e
->netnsids
, &netnsids_cache
);
319 static int get_netnsid_via_netlink_send_request(int target_fd
)
321 unsigned char req
[NLMSG_SPACE(sizeof(struct rtgenmsg
))
322 + RTA_SPACE(sizeof(int32_t))];
324 struct nlmsghdr
*nlh
= (struct nlmsghdr
*)req
;
325 struct rtgenmsg
*rt
= NLMSG_DATA(req
);
326 struct rtattr
*rta
= (struct rtattr
*)
327 (req
+ NLMSG_SPACE(sizeof(struct rtgenmsg
)));
328 int32_t *fd
= RTA_DATA(rta
);
330 nlh
->nlmsg_len
= sizeof(req
);
331 nlh
->nlmsg_flags
= NLM_F_REQUEST
;
332 nlh
->nlmsg_type
= RTM_GETNSID
;
333 rt
->rtgen_family
= AF_UNSPEC
;
334 rta
->rta_type
= NETNSA_FD
;
335 rta
->rta_len
= RTA_SPACE(sizeof(int32_t));
338 if (send(netlink_fd
, req
, sizeof(req
), 0) < 0)
343 static int get_netnsid_via_netlink_recv_response(int *netnsid
)
345 unsigned char res
[NLMSG_SPACE(sizeof(struct rtgenmsg
))
346 + ((RTA_SPACE(sizeof(int32_t))
347 < RTA_SPACE(sizeof(struct nlmsgerr
)))
348 ? RTA_SPACE(sizeof(struct nlmsgerr
))
349 : RTA_SPACE(sizeof(int32_t)))];
352 struct nlmsghdr
*nlh
;
355 reslen
= recv(netlink_fd
, res
, sizeof(res
), 0);
359 nlh
= (struct nlmsghdr
*)res
;
360 if (!(NLMSG_OK(nlh
, reslen
)
361 && nlh
->nlmsg_type
== RTM_NEWNSID
))
364 rtalen
= NLMSG_PAYLOAD(nlh
, sizeof(struct rtgenmsg
));
365 rta
= (struct rtattr
*)(res
+ NLMSG_SPACE(sizeof(struct rtgenmsg
)));
366 if (!(RTA_OK(rta
, rtalen
)
367 && rta
->rta_type
== NETNSA_NSID
))
370 *netnsid
= *(int *)RTA_DATA(rta
);
375 static int get_netnsid_via_netlink(int dir
, const char *path
)
381 return LSNS_NETNS_UNUSABLE
;
383 target_fd
= openat(dir
, path
, O_RDONLY
);
385 return LSNS_NETNS_UNUSABLE
;
387 if (get_netnsid_via_netlink_send_request(target_fd
) < 0) {
388 netnsid
= LSNS_NETNS_UNUSABLE
;
392 if (get_netnsid_via_netlink_recv_response(&netnsid
) < 0) {
393 netnsid
= LSNS_NETNS_UNUSABLE
;
402 static int get_netnsid(int dir
, ino_t netino
)
406 if (!netnsid_cache_find(netino
, &netnsid
)) {
407 netnsid
= get_netnsid_via_netlink(dir
, "ns/net");
408 netnsid_cache_add(netino
, netnsid
);
414 static int get_netnsid(int dir
__attribute__((__unused__
)),
415 ino_t netino
__attribute__((__unused__
)))
417 return LSNS_NETNS_UNUSABLE
;
419 #endif /* HAVE_LINUX_NET_NAMESPACE_H */
421 static int read_process(struct lsns
*ls
, pid_t pid
)
423 struct lsns_process
*p
= NULL
;
431 DBG(PROC
, ul_debug("reading %d", (int) pid
));
433 snprintf(buf
, sizeof(buf
), "/proc/%d", pid
);
438 p
= xcalloc(1, sizeof(*p
));
443 p
->netnsid
= LSNS_NETNS_UNUSABLE
;
445 if (fstat(dirfd(dir
), &st
) == 0) {
447 add_uid(uid_cache
, st
.st_uid
);
450 fd
= openat(dirfd(dir
), "stat", O_RDONLY
);
455 if (!(f
= fdopen(fd
, "r"))) {
459 rc
= parse_proc_stat(f
, &p
->pid
, &p
->state
, &p
->ppid
);
464 for (i
= 0; i
< ARRAY_SIZE(p
->ns_ids
); i
++) {
465 INIT_LIST_HEAD(&p
->ns_siblings
[i
]);
467 if (!ls
->fltr_types
[i
])
470 rc
= get_ns_ino(dirfd(dir
), ns_names
[i
], &p
->ns_ids
[i
]);
471 if (rc
&& rc
!= -EACCES
&& rc
!= -ENOENT
)
473 if (i
== LSNS_ID_NET
)
474 p
->netnsid
= get_netnsid(dirfd(dir
), p
->ns_ids
[i
]);
478 INIT_LIST_HEAD(&p
->processes
);
480 DBG(PROC
, ul_debugobj(p
, "new pid=%d", p
->pid
));
481 list_add_tail(&p
->processes
, &ls
->processes
);
491 static int read_processes(struct lsns
*ls
)
493 struct proc_processes
*proc
= NULL
;
497 DBG(PROC
, ul_debug("opening /proc"));
499 if (!(proc
= proc_open_processes())) {
504 while (proc_next_pid(proc
, &pid
) == 0) {
505 rc
= read_process(ls
, pid
);
506 if (rc
&& rc
!= -EACCES
&& rc
!= -ENOENT
)
511 DBG(PROC
, ul_debug("closing /proc"));
512 proc_close_processes(proc
);
516 static struct lsns_namespace
*get_namespace(struct lsns
*ls
, ino_t ino
)
520 list_for_each(p
, &ls
->namespaces
) {
521 struct lsns_namespace
*ns
= list_entry(p
, struct lsns_namespace
, namespaces
);
529 static int namespace_has_process(struct lsns_namespace
*ns
, pid_t pid
)
533 list_for_each(p
, &ns
->processes
) {
534 struct lsns_process
*proc
= list_entry(p
, struct lsns_process
, ns_siblings
[ns
->type
]);
536 if (proc
->pid
== pid
)
542 static struct lsns_namespace
*add_namespace(struct lsns
*ls
, int type
, ino_t ino
)
544 struct lsns_namespace
*ns
= xcalloc(1, sizeof(*ns
));
549 DBG(NS
, ul_debugobj(ns
, "new %s[%ju]", ns_names
[type
], (uintmax_t)ino
));
551 INIT_LIST_HEAD(&ns
->processes
);
552 INIT_LIST_HEAD(&ns
->namespaces
);
557 list_add_tail(&ns
->namespaces
, &ls
->namespaces
);
561 static int add_process_to_namespace(struct lsns
*ls
, struct lsns_namespace
*ns
, struct lsns_process
*proc
)
565 DBG(NS
, ul_debugobj(ns
, "add process [%p] pid=%d to %s[%ju]",
566 proc
, proc
->pid
, ns_names
[ns
->type
], (uintmax_t)ns
->id
));
568 list_for_each(p
, &ls
->processes
) {
569 struct lsns_process
*xproc
= list_entry(p
, struct lsns_process
, processes
);
571 if (xproc
->pid
== proc
->ppid
) /* my parent */
572 proc
->parent
= xproc
;
573 else if (xproc
->ppid
== proc
->pid
) /* my child */
574 xproc
->parent
= proc
;
577 list_add_tail(&proc
->ns_siblings
[ns
->type
], &ns
->processes
);
580 if (!ns
->proc
|| ns
->proc
->pid
> proc
->pid
)
586 static int cmp_namespaces(struct list_head
*a
, struct list_head
*b
,
587 __attribute__((__unused__
)) void *data
)
589 struct lsns_namespace
*xa
= list_entry(a
, struct lsns_namespace
, namespaces
),
590 *xb
= list_entry(b
, struct lsns_namespace
, namespaces
);
592 return cmp_numbers(xa
->id
, xb
->id
);
595 static int netnsid_xasputs(char **str
, int netnsid
)
598 return xasprintf(str
, "%d", netnsid
);
599 #ifdef NETNSA_NSID_NOT_ASSIGNED
600 else if (netnsid
== NETNSA_NSID_NOT_ASSIGNED
)
601 return xasprintf(str
, "%s", "unassigned");
607 static int read_namespaces(struct lsns
*ls
)
611 DBG(NS
, ul_debug("reading namespace"));
613 list_for_each(p
, &ls
->processes
) {
615 struct lsns_namespace
*ns
;
616 struct lsns_process
*proc
= list_entry(p
, struct lsns_process
, processes
);
618 for (i
= 0; i
< ARRAY_SIZE(proc
->ns_ids
); i
++) {
619 if (proc
->ns_ids
[i
] == 0)
621 if (!(ns
= get_namespace(ls
, proc
->ns_ids
[i
]))) {
622 ns
= add_namespace(ls
, i
, proc
->ns_ids
[i
]);
626 add_process_to_namespace(ls
, ns
, proc
);
630 list_sort(&ls
->namespaces
, cmp_namespaces
, NULL
);
635 static int is_nsfs_root(struct libmnt_fs
*fs
, void *data
)
637 if (!mnt_fs_match_fstype(fs
, "nsfs") || !mnt_fs_get_root(fs
))
640 return (strcmp(mnt_fs_get_root(fs
), (char *)data
) == 0);
643 static int is_path_included(const char *path_set
, const char *elt
,
651 tmp
= strstr(path_set
, elt
);
655 elt_len
= strlen(elt
);
656 path_set_len
= strlen(path_set
);
658 /* path_set includes only elt or
659 * path_set includes elt as the first element.
662 && ((path_set_len
== elt_len
)
663 || (path_set
[elt_len
] == sep
)))
666 /* path_set includes elt at the middle
667 * or as the last element.
669 if ((*(tmp
- 1) == sep
)
670 && ((*(tmp
+ elt_len
) == sep
)
671 || (*(tmp
+ elt_len
) == '\0')))
677 static int nsfs_xasputs(char **str
,
678 struct lsns_namespace
*ns
,
679 struct libmnt_table
*tab
,
682 struct libmnt_iter
*itr
= mnt_new_iter(MNT_ITER_FORWARD
);
684 struct libmnt_fs
*fs
= NULL
;
686 xasprintf(&expected_root
, "%s:[%ju]", ns_names
[ns
->type
], (uintmax_t)ns
->id
);
689 while (mnt_table_find_next_fs(tab
, itr
, is_nsfs_root
,
690 expected_root
, &fs
) == 0) {
692 const char *tgt
= mnt_fs_get_target(fs
);
695 xasprintf(str
, "%s", tgt
);
697 else if (!is_path_included(*str
, tgt
, sep
)) {
700 xasprintf(&tmp
, "%s%c%s", *str
, sep
, tgt
);
710 static void add_scols_line(struct lsns
*ls
, struct libscols_table
*table
,
711 struct lsns_namespace
*ns
, struct lsns_process
*proc
)
714 struct libscols_line
*line
;
719 line
= scols_table_new_line(table
,
720 ls
->tree
&& proc
->parent
? proc
->parent
->outline
: NULL
);
722 warn(_("failed to add line to output"));
726 for (i
= 0; i
< ncolumns
; i
++) {
729 switch (get_column_id(i
)) {
731 xasprintf(&str
, "%ju", (uintmax_t)ns
->id
);
734 xasprintf(&str
, "%d", (int) proc
->pid
);
737 xasprintf(&str
, "%d", (int) proc
->ppid
);
740 xasprintf(&str
, "%s", ns_names
[ns
->type
]);
743 xasprintf(&str
, "%d", ns
->nprocs
);
746 str
= proc_get_command(proc
->pid
);
748 str
= proc_get_command_name(proc
->pid
);
751 xasprintf(&str
, "/proc/%d/ns/%s", (int) proc
->pid
, ns_names
[ns
->type
]);
754 xasprintf(&str
, "%d", (int) proc
->uid
);
757 xasprintf(&str
, "%s", get_id(uid_cache
, proc
->uid
)->name
);
760 if (ns
->type
== LSNS_ID_NET
)
761 netnsid_xasputs(&str
, proc
->netnsid
);
764 nsfs_xasputs(&str
, ns
, ls
->tab
, ls
->no_wrap
? ',' : '\n');
770 if (str
&& scols_line_refer_data(line
, i
, str
) != 0)
774 proc
->outline
= line
;
777 static struct libscols_table
*init_scols_table(struct lsns
*ls
)
779 struct libscols_table
*tab
;
782 tab
= scols_new_table();
784 warn(_("failed to initialize output table"));
788 scols_table_enable_raw(tab
, ls
->raw
);
789 scols_table_enable_json(tab
, ls
->json
);
790 scols_table_enable_noheadings(tab
, ls
->no_headings
);
793 scols_table_set_name(tab
, "namespaces");
795 for (i
= 0; i
< ncolumns
; i
++) {
796 const struct colinfo
*col
= get_column_info(i
);
797 int flags
= col
->flags
;
798 struct libscols_column
*cl
;
801 flags
&= ~SCOLS_FL_TRUNC
;
802 if (ls
->tree
&& get_column_id(i
) == COL_COMMAND
)
803 flags
|= SCOLS_FL_TREE
;
805 flags
&= ~SCOLS_FL_WRAP
;
807 cl
= scols_table_new_column(tab
, col
->name
, col
->whint
, flags
);
809 warnx(_("failed to initialize output column"));
812 if (!ls
->no_wrap
&& get_column_id(i
) == COL_NSFS
) {
813 scols_column_set_wrapfunc(cl
,
814 scols_wrapnl_chunksize
,
815 scols_wrapnl_nextchunk
,
817 scols_column_set_safechars(cl
, "\n");
823 scols_unref_table(tab
);
827 static int show_namespaces(struct lsns
*ls
)
829 struct libscols_table
*tab
;
833 tab
= init_scols_table(ls
);
837 list_for_each(p
, &ls
->namespaces
) {
838 struct lsns_namespace
*ns
= list_entry(p
, struct lsns_namespace
, namespaces
);
840 if (ls
->fltr_pid
!= 0 && !namespace_has_process(ns
, ls
->fltr_pid
))
843 add_scols_line(ls
, tab
, ns
, ns
->proc
);
846 scols_print_table(tab
);
847 scols_unref_table(tab
);
851 static void show_process(struct lsns
*ls
, struct libscols_table
*tab
,
852 struct lsns_process
*proc
, struct lsns_namespace
*ns
)
855 * create a tree from parent->child relation, but only if the parent is
856 * within the same namespace
860 && !proc
->parent
->outline
861 && proc
->parent
->ns_ids
[ns
->type
] == proc
->ns_ids
[ns
->type
])
862 show_process(ls
, tab
, proc
->parent
, ns
);
864 add_scols_line(ls
, tab
, ns
, proc
);
868 static int show_namespace_processes(struct lsns
*ls
, struct lsns_namespace
*ns
)
870 struct libscols_table
*tab
;
873 tab
= init_scols_table(ls
);
877 list_for_each(p
, &ns
->processes
) {
878 struct lsns_process
*proc
= list_entry(p
, struct lsns_process
, ns_siblings
[ns
->type
]);
881 show_process(ls
, tab
, proc
, ns
);
885 scols_print_table(tab
);
886 scols_unref_table(tab
);
890 static void __attribute__((__noreturn__
)) usage(void)
895 fputs(USAGE_HEADER
, out
);
898 _(" %s [options] [<namespace>]\n"), program_invocation_short_name
);
900 fputs(USAGE_SEPARATOR
, out
);
901 fputs(_("List system namespaces.\n"), out
);
903 fputs(USAGE_OPTIONS
, out
);
904 fputs(_(" -J, --json use JSON output format\n"), out
);
905 fputs(_(" -l, --list use list format output\n"), out
);
906 fputs(_(" -n, --noheadings don't print headings\n"), out
);
907 fputs(_(" -o, --output <list> define which output columns to use\n"), out
);
908 fputs(_(" -p, --task <pid> print process namespaces\n"), out
);
909 fputs(_(" -r, --raw use the raw output format\n"), out
);
910 fputs(_(" -u, --notruncate don't truncate text in columns\n"), out
);
911 fputs(_(" -W, --nowrap don't use multi-line representation\n"), out
);
912 fputs(_(" -t, --type <name> namespace type (mnt, net, ipc, user, pid, uts, cgroup)\n"), out
);
914 fputs(USAGE_SEPARATOR
, out
);
915 printf(USAGE_HELP_OPTIONS(24));
917 fputs(USAGE_COLUMNS
, out
);
918 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++)
919 fprintf(out
, " %11s %s\n", infos
[i
].name
, _(infos
[i
].help
));
921 printf(USAGE_MAN_TAIL("lsns(8)"));
927 int main(int argc
, char *argv
[])
933 static const struct option long_opts
[] = {
934 { "json", no_argument
, NULL
, 'J' },
935 { "task", required_argument
, NULL
, 'p' },
936 { "help", no_argument
, NULL
, 'h' },
937 { "output", required_argument
, NULL
, 'o' },
938 { "notruncate", no_argument
, NULL
, 'u' },
939 { "version", no_argument
, NULL
, 'V' },
940 { "noheadings", no_argument
, NULL
, 'n' },
941 { "nowrap", no_argument
, NULL
, 'W' },
942 { "list", no_argument
, NULL
, 'l' },
943 { "raw", no_argument
, NULL
, 'r' },
944 { "type", required_argument
, NULL
, 't' },
948 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
952 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
955 setlocale(LC_ALL
, "");
956 bindtextdomain(PACKAGE
, LOCALEDIR
);
958 atexit(close_stdout
);
961 memset(&ls
, 0, sizeof(ls
));
963 INIT_LIST_HEAD(&ls
.processes
);
964 INIT_LIST_HEAD(&ls
.namespaces
);
965 INIT_LIST_HEAD(&netnsids_cache
);
967 while ((c
= getopt_long(argc
, argv
,
968 "Jlp:o:nruhVt:W", long_opts
, NULL
)) != -1) {
970 err_exclusive_options(c
, long_opts
, excl
, excl_st
);
983 printf(UTIL_LINUX_VERSION
);
986 ls
.fltr_pid
= strtos32_or_err(optarg
, _("invalid PID argument"));
994 ls
.no_wrap
= ls
.raw
= 1;
1001 int type
= ns_name2type(optarg
);
1003 errx(EXIT_FAILURE
, _("unknown namespace type: %s"), optarg
);
1004 ls
.fltr_types
[type
] = 1;
1006 if (type
== LSNS_ID_NET
)
1014 errtryhelp(EXIT_FAILURE
);
1018 if (!ls
.fltr_ntypes
) {
1021 for (i
= 0; i
< ARRAY_SIZE(ns_names
); i
++)
1022 ls
.fltr_types
[i
] = 1;
1025 if (optind
< argc
) {
1027 errx(EXIT_FAILURE
, _("--task is mutually exclusive with <namespace>"));
1028 ls
.fltr_ns
= strtou64_or_err(argv
[optind
], _("invalid namespace argument"));
1029 ls
.tree
= ls
.list
? 0 : 1;
1032 columns
[ncolumns
++] = COL_PID
;
1033 columns
[ncolumns
++] = COL_PPID
;
1034 columns
[ncolumns
++] = COL_USER
;
1035 columns
[ncolumns
++] = COL_COMMAND
;
1040 columns
[ncolumns
++] = COL_NS
;
1041 columns
[ncolumns
++] = COL_TYPE
;
1042 columns
[ncolumns
++] = COL_NPROCS
;
1043 columns
[ncolumns
++] = COL_PID
;
1044 columns
[ncolumns
++] = COL_USER
;
1046 columns
[ncolumns
++] = COL_NETNSID
;
1047 columns
[ncolumns
++] = COL_NSFS
;
1049 columns
[ncolumns
++] = COL_COMMAND
;
1052 if (outarg
&& string_add_to_idarray(outarg
, columns
, ARRAY_SIZE(columns
),
1053 &ncolumns
, column_name_to_id
) < 0)
1054 return EXIT_FAILURE
;
1056 scols_init_debug(0);
1058 uid_cache
= new_idcache();
1060 err(EXIT_FAILURE
, _("failed to allocate UID cache"));
1062 #ifdef HAVE_LINUX_NET_NAMESPACE_H
1063 if (has_column(COL_NETNSID
))
1064 netlink_fd
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
1066 if (has_column(COL_NSFS
)) {
1067 ls
.tab
= mnt_new_table_from_file(_PATH_PROC_MOUNTINFO
);
1069 err(MNT_EX_FAIL
, _("failed to parse %s"), _PATH_PROC_MOUNTINFO
);
1072 r
= read_processes(&ls
);
1074 r
= read_namespaces(&ls
);
1077 struct lsns_namespace
*ns
= get_namespace(&ls
, ls
.fltr_ns
);
1080 errx(EXIT_FAILURE
, _("not found namespace: %ju"), (uintmax_t) ls
.fltr_ns
);
1081 r
= show_namespace_processes(&ls
, ns
);
1083 r
= show_namespaces(&ls
);
1086 mnt_free_table(ls
.tab
);
1087 if (netlink_fd
>= 0)
1089 free_idcache(uid_cache
);
1090 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;