static void load_xinfo_from_diag_unix(int diag, ino_t netns_inode);
static void load_xinfo_from_diag_vsock(int diag, ino_t netns_inode);
+static void fill_peers_of_unix_oneway_ipcs(void);
+
static int self_netns_fd = -1;
static struct stat self_netns_sb;
static void *xinfo_tree; /* for tsearch/tfind */
static void *netns_tree;
+static LIST_HEAD(unix_ipcs);
+static void *unix_oneway_ipc_tree; /* for tsearch/tfind */
+
struct iface {
unsigned int index;
char name[IF_NAMESIZE];
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;
- }
+ if (dir == NULL)
+ goto out;
while ((d = readdir(dir))) {
struct stat sb;
int fd;
close(fd);
}
closedir(dir);
+ out:
ul_unref_path(pc);
+
+ fill_peers_of_unix_oneway_ipcs();
}
static void free_sock_xinfo(void *node)
free(node);
}
+static void do_nothing(void *node __attribute__((__unused__)))
+{
+}
+
void finalize_sock_xinfos(void)
{
if (self_netns_fd != -1)
close(self_netns_fd);
tdestroy(netns_tree, netns_free);
tdestroy(xinfo_tree, free_sock_xinfo);
+ tdestroy(unix_oneway_ipc_tree, do_nothing);
}
static int xinfo_compare(const void *a, const void *b)
struct ipc ipc;
ino_t inode;
ino_t ipeer;
+ struct list_head unix_ipcs;
};
struct unix_xinfo {
}
break;
case COL_ENDPOINTS:
+ if (ux->unix_ipc == NULL)
+ break;
+
peer_ipc = unix_get_peer_ipc(ux, sock);
- if (!peer_ipc)
+ if (!peer_ipc && ux->unix_ipc->ipeer != 0)
break;
- unix_fill_column_append_endpoints(peer_ipc, str);
+ if (peer_ipc)
+ unix_fill_column_append_endpoints(peer_ipc, str);
- if (*str)
- xstrputc(str, '\n');
- estr = unix_xstrendpoint(peer_sock);
- xstrappend(str, estr);
- free(estr);
+ if (ux->unix_ipc->ipeer == 0) {
+ struct list_head *e;
+ list_for_each(e, &ux->unix_ipc->unix_ipcs) {
+ struct unix_ipc *peer_unix_ipc = list_entry(e, struct unix_ipc, unix_ipcs);
+ peer_ipc = &peer_unix_ipc->ipc;
+ unix_fill_column_append_endpoints(peer_ipc, str);
+ }
}
+
if (*str)
return true;
break;
ux->path[min_len] = '\0';
}
+static int unix_oneway_ipc_compare(const void *a, const void *b)
+{
+ return ((struct unix_ipc *)a)->inode - ((struct unix_ipc *)b)->inode;
+}
+
+static void add_unix_oneway_ipc(struct unix_ipc *unix_oneway_ipc)
+{
+ struct unix_ipc **tmp = tsearch(unix_oneway_ipc,
+ &unix_oneway_ipc_tree,
+ unix_oneway_ipc_compare);
+
+ if (tmp == NULL)
+ errx(EXIT_FAILURE, _("failed to allocate memory"));
+}
+
+static struct unix_ipc *get_unix_oneway_ipc(ino_t inode)
+{
+ struct unix_ipc key = { .inode = inode };
+ struct unix_ipc **unix_oneway_ipc = tfind(&key,
+ &unix_oneway_ipc_tree,
+ unix_oneway_ipc_compare);
+
+ if (unix_oneway_ipc)
+ return *unix_oneway_ipc;
+ return NULL;
+}
+
static bool handle_diag_unix(ino_t netns __attribute__((__unused__)),
size_t nlmsg_len, void *nlmsg_data)
{
unix_xinfo->unix_ipc = (struct unix_ipc *)new_ipc(&unix_ipc_class);
unix_xinfo->unix_ipc->inode = inode;
unix_xinfo->unix_ipc->ipeer = (ino_t)(*(uint32_t *)RTA_DATA(attr));
+
+ INIT_LIST_HEAD(&unix_xinfo->unix_ipc->unix_ipcs);
+ list_add(&unix_xinfo->unix_ipc->unix_ipcs, &unix_ipcs);
+
add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX);
peer_added = true;
break;
unix_xinfo->unix_ipc = (struct unix_ipc *)new_ipc(&unix_ipc_class);
unix_xinfo->unix_ipc->inode = inode;
unix_xinfo->unix_ipc->ipeer = 0;
+
+ INIT_LIST_HEAD(&unix_xinfo->unix_ipc->unix_ipcs);
+ add_unix_oneway_ipc(unix_xinfo->unix_ipc);
+
add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX);
};
return true;
send_diag_request(diagsd, &udr, sizeof(udr), handle_diag_unix, netns);
}
+static void fill_peers_of_unix_oneway_ipcs(void)
+{
+ struct list_head *e, *enext;
+
+ list_for_each_safe(e, enext, &unix_ipcs) {
+ struct unix_ipc *unix_ipc = list_entry(e, struct unix_ipc, unix_ipcs);
+ struct unix_ipc *unix_oneway_ipc;
+
+ list_del_init(e);
+ if (unix_ipc->ipeer == 0)
+ continue;
+
+ unix_oneway_ipc = get_unix_oneway_ipc(unix_ipc->ipeer);
+ if (unix_oneway_ipc == NULL)
+ continue;
+ list_add(e, &unix_oneway_ipc->unix_ipcs);
+ };
+}
+
/*
* AF_INET
*/