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
--- /dev/null
+/*
+ * 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 <yamato@redhat.com>
+ *
+ * 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 <sched.h> /* for setns(2) */
+#include <search.h>
+
+#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);
+}
#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,
}
}
+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,
};
--- /dev/null
+/*
+ * lsfd(1) - list file descriptors
+ *
+ * Copyright (C) 2022 Red Hat, Inc. All rights reserved.
+ * Written by Masatake YAMATO <yamato@redhat.com>
+ *
+ * Very generally based on lsof(8) by Victor A. Abell <abe@purdue.edu>
+ * 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 <sys/stat.h>
+
+/*
+ * 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 */
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 */
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);
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;
collect_processes(&ctl, pids, n_pids);
free(pids);
+ attach_xinfos(&ctl.procs);
+
convert(&ctl.procs, &ctl);
/* print */
#include <inttypes.h>
#include "list.h"
+#include "path.h"
#include "strutils.h"
/*
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);
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 */
'lsfd-cdev.c',
'lsfd-bdev.c',
'lsfd-sock.c',
+ 'lsfd-sock.h',
+ 'lsfd-sock-xinfo.c',
'lsfd-unkn.c',
'lsfd-fifo.c',
)