]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/lsfd-sock-xinfo.c
lsfd: facilitate the way to attach extra info loaded from /proc/net/* to sockets
[thirdparty/util-linux.git] / misc-utils / lsfd-sock-xinfo.c
CommitLineData
0ee16e43
MY
1/*
2 * lsfd-sock-xinfo.c - read various information from files under /proc/net/
3 *
4 * Copyright (C) 2022 Red Hat, Inc. All rights reserved.
5 * Written by Masatake YAMATO <yamato@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <sched.h> /* for setns(2) */
22#include <search.h>
23
24#include "xalloc.h"
25#include "nls.h"
26#include "libsmartcols.h"
27
28#include "lsfd.h"
29#include "lsfd-sock.h"
30
31static int self_netns_fd = -1;
32struct stat self_netns_sb;
33
34static void *xinfo_tree; /* for tsearch/tfind */
35static void *netns_tree;
36
37static int netns_compare(const void *a, const void *b)
38{
39 if (*(ino_t *)a < *(ino_t *)b)
40 return -1;
41 else if (*(ino_t *)a > *(ino_t *)b)
42 return 1;
43 else
44 return 0;
45}
46
47static bool is_sock_xinfo_loaded(ino_t netns)
48{
49 return tfind(&netns, &netns_tree, netns_compare)? true: false;
50}
51
52static void mark_sock_xinfo_loaded(ino_t ino)
53{
54 ino_t *netns = xmalloc(sizeof(ino));
55 ino_t **tmp;
56
57 *netns = ino;
58 tmp = tsearch(netns, &netns_tree, netns_compare);
59 if (tmp == NULL)
60 errx(EXIT_FAILURE, _("failed to allocate memory"));
61}
62
63static void load_sock_xinfo_no_nsswitch(ino_t netns __attribute__((__unused__)))
64{
65 /* TODO: load files under /proc/ns */
66}
67
68static void load_sock_xinfo_with_fd(int fd, ino_t netns)
69{
70 if (setns (fd, CLONE_NEWNET) == 0) {
71 load_sock_xinfo_no_nsswitch(netns);
72 setns (self_netns_fd, CLONE_NEWNET);
73 }
74}
75
76void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns)
77{
78 if (self_netns_fd == -1)
79 return;
80
81 if (!is_sock_xinfo_loaded(netns)) {
82 int fd;
83
84 mark_sock_xinfo_loaded(netns);
85 fd = ul_path_open(pc, O_RDONLY, name);
86 if (fd < 0)
87 return;
88
89 load_sock_xinfo_with_fd(fd, netns);
90 close(fd);
91 }
92}
93
94void initialize_sock_xinfos(void)
95{
96 struct path_cxt *pc;
97 DIR *dir;
98 struct dirent *d;
99
100 self_netns_fd = open("/proc/self/ns/net", O_RDONLY);
101
102 if (self_netns_fd < 0)
103 load_sock_xinfo_no_nsswitch(0);
104 else {
105 if (fstat(self_netns_fd, &self_netns_sb) == 0) {
106 mark_sock_xinfo_loaded(self_netns_sb.st_ino);
107 load_sock_xinfo_no_nsswitch(self_netns_sb.st_ino);
108 }
109 }
110
111 /* Load /proc/net/{unix,...} of the network namespace
112 * specified with netns files under /var/run/netns/.
113 *
114 * `ip netns' command pins a network namespace on
115 * /var/run/netns.
116 */
117 pc = ul_new_path("/var/run/netns");
118 if (!pc)
119 err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns"));
120 dir = ul_path_opendir(pc, NULL);
121 if (dir == NULL) {
122 ul_unref_path(pc);
123 return;
124 }
125 while ((d = readdir(dir))) {
126 struct stat sb;
127 int fd;
128 if (ul_path_stat(pc, &sb, 0, d->d_name) < 0)
129 continue;
130 if (is_sock_xinfo_loaded(sb.st_ino))
131 continue;
132 mark_sock_xinfo_loaded(sb.st_ino);
133 fd = ul_path_open(pc, O_RDONLY, d->d_name);
134 if (fd < 0)
135 continue;
136 load_sock_xinfo_with_fd(fd, sb.st_ino);
137 close(fd);
138 }
139 closedir(dir);
140 ul_unref_path(pc);
141}
142
143static void free_sock_xinfo (void *node)
144{
145 struct sock_xinfo *xinfo = node;
146 if (xinfo->class->free)
147 xinfo->class->free (xinfo);
148 free(node);
149}
150
151void finalize_sock_xinfos(void)
152{
153 if (self_netns_fd != -1)
154 close(self_netns_fd);
155 tdestroy(netns_tree, free);
156 tdestroy(xinfo_tree, free_sock_xinfo);
157}
158
159static int xinfo_compare(const void *a, const void *b)
160{
161 if (((struct sock_xinfo *)a)->inode < ((struct sock_xinfo *)b)->inode)
162 return -1;
163 if (((struct sock_xinfo *)a)->inode > ((struct sock_xinfo *)b)->inode)
164 return 1;
165 return 0;
166}
167
168struct sock_xinfo *get_sock_xinfo(ino_t netns_inode)
169{
170 struct sock_xinfo **xinfo = tfind(&netns_inode, &xinfo_tree, xinfo_compare);
171
172 if (xinfo)
173 return *xinfo;
174 return NULL;
175}
176
177bool is_nsfs_dev(dev_t dev)
178{
179 return (dev == self_netns_sb.st_dev);
180}