From: Masatake YAMATO Date: Tue, 20 Sep 2022 20:25:49 +0000 (+0900) Subject: lsfd: facilitate the way to attach extra info loaded from /proc/net/* to sockets X-Git-Tag: v2.39-rc1~505^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0ee16e433422951bf6374921a5621ae2f9b1c485;p=thirdparty%2Futil-linux.git lsfd: facilitate the way to attach extra info loaded from /proc/net/* to sockets Files under /proc/net/ like unix, tcp, udp, etc. provides extra information about sockets. To unitize these information in lsfd, this change adds stub for loading the information form /proc/net/* and attaching it to struct file presenting sockets. Signed-off-by: Masatake YAMATO --- diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am index dfeff6f4e6..2c9f7ead5c 100644 --- a/misc-utils/Makemodule.am +++ b/misc-utils/Makemodule.am @@ -263,6 +263,8 @@ lsfd_SOURCES = \ misc-utils/lsfd-cdev.c \ misc-utils/lsfd-bdev.c \ misc-utils/lsfd-sock.c \ + misc-utils/lsfd-sock.h \ + misc-utils/lsfd-sock-xinfo.c \ misc-utils/lsfd-unkn.c \ misc-utils/lsfd-fifo.c lsfd_LDADD = $(LDADD) libsmartcols.la libcommon.la diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c new file mode 100644 index 0000000000..804e394127 --- /dev/null +++ b/misc-utils/lsfd-sock-xinfo.c @@ -0,0 +1,180 @@ +/* + * lsfd-sock-xinfo.c - read various information from files under /proc/net/ + * + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * Written by Masatake YAMATO + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include /* for setns(2) */ +#include + +#include "xalloc.h" +#include "nls.h" +#include "libsmartcols.h" + +#include "lsfd.h" +#include "lsfd-sock.h" + +static int self_netns_fd = -1; +struct stat self_netns_sb; + +static void *xinfo_tree; /* for tsearch/tfind */ +static void *netns_tree; + +static int netns_compare(const void *a, const void *b) +{ + if (*(ino_t *)a < *(ino_t *)b) + return -1; + else if (*(ino_t *)a > *(ino_t *)b) + return 1; + else + return 0; +} + +static bool is_sock_xinfo_loaded(ino_t netns) +{ + return tfind(&netns, &netns_tree, netns_compare)? true: false; +} + +static void mark_sock_xinfo_loaded(ino_t ino) +{ + ino_t *netns = xmalloc(sizeof(ino)); + ino_t **tmp; + + *netns = ino; + tmp = tsearch(netns, &netns_tree, netns_compare); + if (tmp == NULL) + errx(EXIT_FAILURE, _("failed to allocate memory")); +} + +static void load_sock_xinfo_no_nsswitch(ino_t netns __attribute__((__unused__))) +{ + /* TODO: load files under /proc/ns */ +} + +static void load_sock_xinfo_with_fd(int fd, ino_t netns) +{ + if (setns (fd, CLONE_NEWNET) == 0) { + load_sock_xinfo_no_nsswitch(netns); + setns (self_netns_fd, CLONE_NEWNET); + } +} + +void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns) +{ + if (self_netns_fd == -1) + return; + + if (!is_sock_xinfo_loaded(netns)) { + int fd; + + mark_sock_xinfo_loaded(netns); + fd = ul_path_open(pc, O_RDONLY, name); + if (fd < 0) + return; + + load_sock_xinfo_with_fd(fd, netns); + close(fd); + } +} + +void initialize_sock_xinfos(void) +{ + struct path_cxt *pc; + DIR *dir; + struct dirent *d; + + self_netns_fd = open("/proc/self/ns/net", O_RDONLY); + + if (self_netns_fd < 0) + load_sock_xinfo_no_nsswitch(0); + else { + if (fstat(self_netns_fd, &self_netns_sb) == 0) { + mark_sock_xinfo_loaded(self_netns_sb.st_ino); + load_sock_xinfo_no_nsswitch(self_netns_sb.st_ino); + } + } + + /* Load /proc/net/{unix,...} of the network namespace + * specified with netns files under /var/run/netns/. + * + * `ip netns' command pins a network namespace on + * /var/run/netns. + */ + pc = ul_new_path("/var/run/netns"); + if (!pc) + err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns")); + dir = ul_path_opendir(pc, NULL); + if (dir == NULL) { + ul_unref_path(pc); + return; + } + while ((d = readdir(dir))) { + struct stat sb; + int fd; + if (ul_path_stat(pc, &sb, 0, d->d_name) < 0) + continue; + if (is_sock_xinfo_loaded(sb.st_ino)) + continue; + mark_sock_xinfo_loaded(sb.st_ino); + fd = ul_path_open(pc, O_RDONLY, d->d_name); + if (fd < 0) + continue; + load_sock_xinfo_with_fd(fd, sb.st_ino); + close(fd); + } + closedir(dir); + ul_unref_path(pc); +} + +static void free_sock_xinfo (void *node) +{ + struct sock_xinfo *xinfo = node; + if (xinfo->class->free) + xinfo->class->free (xinfo); + free(node); +} + +void finalize_sock_xinfos(void) +{ + if (self_netns_fd != -1) + close(self_netns_fd); + tdestroy(netns_tree, free); + tdestroy(xinfo_tree, free_sock_xinfo); +} + +static int xinfo_compare(const void *a, const void *b) +{ + if (((struct sock_xinfo *)a)->inode < ((struct sock_xinfo *)b)->inode) + return -1; + if (((struct sock_xinfo *)a)->inode > ((struct sock_xinfo *)b)->inode) + return 1; + return 0; +} + +struct sock_xinfo *get_sock_xinfo(ino_t netns_inode) +{ + struct sock_xinfo **xinfo = tfind(&netns_inode, &xinfo_tree, xinfo_compare); + + if (xinfo) + return *xinfo; + return NULL; +} + +bool is_nsfs_dev(dev_t dev) +{ + return (dev == self_netns_sb.st_dev); +} diff --git a/misc-utils/lsfd-sock.c b/misc-utils/lsfd-sock.c index c7adbf3582..c768bce5bc 100644 --- a/misc-utils/lsfd-sock.c +++ b/misc-utils/lsfd-sock.c @@ -27,12 +27,20 @@ #include "libsmartcols.h" #include "lsfd.h" +#include "lsfd-sock.h" struct sock { struct file file; char *protoname; + struct sock_xinfo *xinfo; }; +static void attach_sock_xinfo(struct file *file) +{ + struct sock *sock = (struct sock *)file; + sock->xinfo = get_sock_xinfo(file->stat.st_ino); +} + static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), struct file *file, struct libscols_line *ln, @@ -110,10 +118,23 @@ static void free_sock_content(struct file *file) } } +static void initialize_sock_class(void) +{ + initialize_sock_xinfos(); +} + +static void finalize_sock_class(void) +{ + finalize_sock_xinfos(); +} + const struct file_class sock_class = { .super = &file_class, .size = sizeof(struct sock), .fill_column = sock_fill_column, + .attach_xinfo = attach_sock_xinfo, .initialize_content = init_sock_content, .free_content = free_sock_content, + .initialize_class = initialize_sock_class, + .finalize_class = finalize_sock_class, }; diff --git a/misc-utils/lsfd-sock.h b/misc-utils/lsfd-sock.h new file mode 100644 index 0000000000..0a22fc1810 --- /dev/null +++ b/misc-utils/lsfd-sock.h @@ -0,0 +1,49 @@ +/* + * lsfd(1) - list file descriptors + * + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * Written by Masatake YAMATO + * + * Very generally based on lsof(8) by Victor A. Abell + * It supports multiple OSes. lsfd specializes to Linux. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef UTIL_LINUX_LSFD_SOCK_H +#define UTIL_LINUX_LSFD_SOCK_H + +#include + +/* + * xinfo: eXtra inforation about sockets + */ +struct sock_xinfo { + ino_t inode; /* inode in sockfs */ + ino_t netns_inode; /* inode of netns where + the socket belongs to */ + const struct sock_xinfo_class *class; +}; + +struct sock_xinfo_class { + const char *class; + void (*free)(struct sock_xinfo *); +}; + +void initialize_sock_xinfos(void); +void finalize_sock_xinfos(void); + +struct sock_xinfo *get_sock_xinfo(ino_t netns_inode); + +#endif /* UTIL_LINUX_LSFD_SOCK_H */ diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index 0d7e7e58a1..740223e438 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -605,6 +605,8 @@ static struct file *collect_file_symlink(struct path_cxt *pc, if (is_association(f, NS_MNT)) proc->ns_mnt = f->stat.st_ino; + else if (is_association(f, NS_NET)) + load_sock_xinfo(pc, name, f->stat.st_ino); else if (assoc >= 0) { /* file-descriptor based association */ @@ -613,6 +615,9 @@ static struct file *collect_file_symlink(struct path_cxt *pc, if (ul_path_stat(pc, &sb, AT_SYMLINK_NOFOLLOW, name) == 0) f->mode = sb.st_mode; + if (is_nsfs_dev(f->stat.st_dev)) + load_sock_xinfo(pc, name, f->stat.st_ino); + fdinfo = ul_path_fopenf(pc, "r", "fdinfo/%d", assoc); if (fdinfo) { read_fdinfo(f, fdinfo); @@ -1620,6 +1625,22 @@ static void emit_summary(struct lsfd_control *ctl, struct lsfd_counter **counter scols_unref_table(tb); } +static void attach_xinfos(struct list_head *procs) +{ + struct list_head *p; + + list_for_each (p, procs) { + struct proc *proc = list_entry(p, struct proc, procs); + struct list_head *f; + + list_for_each (f, &proc->files) { + struct file *file = list_entry(f, struct file, files); + if (file->class->attach_xinfo) + file->class->attach_xinfo(file); + } + } +} + int main(int argc, char *argv[]) { int c; @@ -1806,6 +1827,8 @@ int main(int argc, char *argv[]) collect_processes(&ctl, pids, n_pids); free(pids); + attach_xinfos(&ctl.procs); + convert(&ctl.procs, &ctl); /* print */ diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h index 41f574ff4a..1633976dd6 100644 --- a/misc-utils/lsfd.h +++ b/misc-utils/lsfd.h @@ -30,6 +30,7 @@ #include #include "list.h" +#include "path.h" #include "strutils.h" /* @@ -145,6 +146,7 @@ struct file_class { int column_id, size_t column_index); int (*handle_fdinfo)(struct file *file, const char *key, const char* value); + void (*attach_xinfo)(struct file *file); void (*initialize_content)(struct file *file); void (*free_content)(struct file *file); struct ipc_class *(*get_ipc_class)(struct file *file); @@ -203,4 +205,10 @@ static inline void xstrputc(char **a, char c) xstrappend(a, b); } +/* + * Net namespace + */ +void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns); +bool is_nsfs_dev(dev_t dev); + #endif /* UTIL_LINUX_LSFD_H */ diff --git a/misc-utils/meson.build b/misc-utils/meson.build index 818232a580..b0dcb801d5 100644 --- a/misc-utils/meson.build +++ b/misc-utils/meson.build @@ -51,6 +51,8 @@ lsfd_sources = files ( 'lsfd-cdev.c', 'lsfd-bdev.c', 'lsfd-sock.c', + 'lsfd-sock.h', + 'lsfd-sock-xinfo.c', 'lsfd-unkn.c', 'lsfd-fifo.c', )