From b20ab2779027cf872d857252b7d9f4355701a83f Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Jul 2023 16:35:20 +0900 Subject: [PATCH 01/15] lsfd: initialize the ipc table before loading lists of unix socket peers via netlink diag Loading the lists is done in initialize_classes(). Signed-off-by: Masatake YAMATO --- misc-utils/lsfd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index 7d1d381fd8d..13f6282c7e1 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -2290,11 +2290,15 @@ int main(int argc, char *argv[]) if (scols_table_get_column_by_name(ctl.tb, "XMODE")) ctl.show_xmode = 1; - /* collect data */ + /* collect data + * + * The call initialize_ipc_table() must come before + * initialize_classes. + */ initialize_nodevs(); + initialize_ipc_table(); initialize_classes(); initialize_devdrvs(); - initialize_ipc_table(); collect_processes(&ctl, pids, n_pids); free(pids); From 046c5d5a2f4b0b8344cf0cad7e05a68a1e313710 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 4 Aug 2023 00:51:49 +0900 Subject: [PATCH 02/15] lsfd: make the sock_xinfo layer be able to prepare an ipc_class for a given socket Signed-off-by: Masatake YAMATO --- misc-utils/lsfd-sock.c | 21 ++++++++++++++++++++- misc-utils/lsfd-sock.h | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/misc-utils/lsfd-sock.c b/misc-utils/lsfd-sock.c index 5ed133e6523..7da2f61e589 100644 --- a/misc-utils/lsfd-sock.c +++ b/misc-utils/lsfd-sock.c @@ -28,7 +28,23 @@ static void attach_sock_xinfo(struct file *file) { struct sock *sock = (struct sock *)file; + sock->xinfo = get_sock_xinfo(file->stat.st_ino); + if (sock->xinfo) { + struct ipc *ipc = get_ipc(file); + if (ipc) + add_endpoint(&sock->endpoint, ipc); + } +} + +static const struct ipc_class *sock_get_ipc_class(struct file *file) +{ + struct sock *sock = (struct sock *)file; + + if (sock->xinfo && sock->xinfo->class->get_ipc_class) + return sock->xinfo->class->get_ipc_class(sock->xinfo, sock); + + return NULL; } static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), @@ -116,13 +132,13 @@ static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), static void init_sock_content(struct file *file) { int fd; + struct sock *sock = (struct sock *)file; assert(file); fd = file->association; if (fd >= 0 || fd == -ASSOC_MEM || fd == -ASSOC_SHM) { - struct sock *sock = (struct sock *)file; char path[PATH_MAX] = {'\0'}; char buf[256]; ssize_t len; @@ -143,6 +159,8 @@ static void init_sock_content(struct file *file) sock->protoname = xstrdup(buf); } } + + init_endpoint(&sock->endpoint); } static void free_sock_content(struct file *file) @@ -173,4 +191,5 @@ const struct file_class sock_class = { .free_content = free_sock_content, .initialize_class = initialize_sock_class, .finalize_class = finalize_sock_class, + .get_ipc_class = sock_get_ipc_class, }; diff --git a/misc-utils/lsfd-sock.h b/misc-utils/lsfd-sock.h index 61bdaeb7e3a..50360b70351 100644 --- a/misc-utils/lsfd-sock.h +++ b/misc-utils/lsfd-sock.h @@ -43,6 +43,7 @@ struct sock { struct file file; char *protoname; struct sock_xinfo *xinfo; + struct ipc_endpoint endpoint; }; struct sock_xinfo_class { @@ -60,6 +61,7 @@ struct sock_xinfo_class { int, size_t, char **str); + struct ipc_class *(*get_ipc_class)(struct sock_xinfo *, struct sock *); void (*free)(struct sock_xinfo *); }; From f9771d8d71b1b98f6c30b5c631a2301f0315f440 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 4 Aug 2023 01:10:58 +0900 Subject: [PATCH 03/15] lsfd: fill ENDPOINTS column of unix socket using UNIX_DIAG_PEER information An example output: # ./lsfd -Q '((PID == 1) || (PID == 1896)) && (TYPE == "UNIX-STREAM") && ((FD == 1) || (FD == 278))' -o+ENDPOINTS COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME ENDPOINTS systemd 1 root 278 rw---m UNIX-STREAM sockfs 9 37012 state=connected path=/run/systemd/journal/stdout 1896,ModemManager,1 ModemManager 1896 root 1 rw---- UNIX-STREAM sockfs 9 43126 state=connected 1,systemd,278 1870458,systemd-journal,68 Signed-off-by: Masatake YAMATO --- misc-utils/lsfd-sock-xinfo.c | 103 ++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c index 3e7ff94eee4..301da278893 100644 --- a/misc-utils/lsfd-sock-xinfo.c +++ b/misc-utils/lsfd-sock-xinfo.c @@ -393,11 +393,18 @@ static void send_diag_request(int diagsd, void *req, size_t req_size, /* * UNIX */ +struct unix_ipc { + struct ipc ipc; + ino_t inode; + ino_t ipeer; +}; + struct unix_xinfo { struct sock_xinfo sock; int acceptcon; /* flags */ uint16_t type; uint8_t st; + struct unix_ipc *unix_ipc; char path[ UNIX_PATH_MAX + 1 /* for @ */ @@ -475,15 +482,76 @@ static bool unix_get_listening(struct sock_xinfo *sock_xinfo, return ux->acceptcon; } +static unsigned int unix_get_hash(struct file *file) +{ + return (unsigned int)(file->stat.st_ino % UINT_MAX); +} + +static bool unix_is_suitable_ipc(struct ipc *ipc, struct file *file) +{ + return ((struct unix_ipc *)ipc)->inode == file->stat.st_ino; +} + +/* For looking up an ipc struct for a sock inode, we need a sock strcuct + * for the inode. See the signature o get_ipc(). + * + * However, there is a case that we have no sock strcuct for the inode; + * in the context we know only the sock inode. + * For the case, unix_make_dumy_sock() provides the way to make a + * dummy sock struct for the inode. + */ +static void unix_make_dumy_sock(struct sock *original, ino_t ino, struct sock *dummy) +{ + *dummy = *original; + dummy->file.stat.st_ino = ino; +} + +static struct ipc_class unix_ipc_class = { + .size = sizeof(struct unix_ipc), + .get_hash = unix_get_hash, + .is_suitable_ipc = unix_is_suitable_ipc, + .free = NULL, +}; + +static struct ipc_class *unix_get_ipc_class(struct sock_xinfo *sock_xinfo __attribute__((__unused__)), + struct sock *sock __attribute__((__unused__))) +{ + return &unix_ipc_class; +} + +static inline char *unix_xstrendpoint(struct sock *sock) +{ + char *str = NULL; + xasprintf(&str, "%d,%s,%d", + sock->file.proc->pid, sock->file.proc->command, sock->file.association); + return str; +} + +static struct ipc *unix_get_peer_ipc(struct unix_xinfo *ux, + struct sock *sock) +{ + struct unix_ipc *unix_ipc; + struct sock dummy_peer_sock; + + unix_ipc = ux->unix_ipc; + if (!unix_ipc) + return NULL; + + unix_make_dumy_sock(sock, unix_ipc->ipeer, &dummy_peer_sock); + return get_ipc(&dummy_peer_sock.file); +} + static bool unix_fill_column(struct proc *proc __attribute__((__unused__)), struct sock_xinfo *sock_xinfo, - struct sock *sock __attribute__((__unused__)), + struct sock *sock, struct libscols_line *ln __attribute__((__unused__)), int column_id, size_t column_index __attribute__((__unused__)), char **str) { struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo; + struct ipc *peer_ipc; + struct list_head *e; switch (column_id) { case COL_UNIX_PATH: @@ -492,6 +560,24 @@ static bool unix_fill_column(struct proc *proc __attribute__((__unused__)), return true; } break; + case COL_ENDPOINTS: + peer_ipc = unix_get_peer_ipc(ux, sock); + if (!peer_ipc) + break; + + list_for_each_backwardly(e, &peer_ipc->endpoints) { + struct sock *peer_sock = list_entry(e, struct sock, endpoint.endpoints); + char *estr; + + if (*str) + xstrputc(str, '\n'); + estr = unix_xstrendpoint(peer_sock); + xstrappend(str, estr); + free(estr); + } + if (*str) + return true; + break; } return false; @@ -503,6 +589,7 @@ static const struct sock_xinfo_class unix_xinfo_class = { .get_state = unix_get_state, .get_listening = unix_get_listening, .fill_column = unix_fill_column, + .get_ipc_class = unix_get_ipc_class, .free = NULL, }; @@ -588,6 +675,7 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), size_t rta_len; ino_t inode; struct sock_xinfo *xinfo; + struct unix_xinfo *unix_xinfo; if (diag->udiag_family != AF_UNIX) return false; @@ -605,6 +693,7 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), if (xinfo->class != &unix_xinfo_class) return true; + unix_xinfo = (struct unix_xinfo *)xinfo; rta_len = nlmsg_len - NLMSG_LENGTH(sizeof(*diag)); for (struct rtattr *attr = (struct rtattr *)(diag + 1); @@ -616,6 +705,16 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), case UNIX_DIAG_NAME: unix_refill_name(xinfo, RTA_DATA(attr), len); break; + + case UNIX_DIAG_PEER: + if (len < 4) + break; + + 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)); + add_ipc(&unix_xinfo->unix_ipc->ipc, inode % UINT_MAX); + break; } } return true; @@ -626,7 +725,7 @@ static void load_xinfo_from_diag_unix(int diagsd, ino_t netns) struct unix_diag_req udr = { .sdiag_family = AF_UNIX, .udiag_states = -1, /* set the all bits. */ - .udiag_show = UDIAG_SHOW_NAME, + .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER, }; send_diag_request(diagsd, &udr, sizeof(udr), handle_diag_unix, netns); From 27c7778aeb70047e89a8028d19b5cf001db1a91f Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 21:07:02 +0900 Subject: [PATCH 04/15] lsfd: (man) document the ENDPOINT column for UNIX socket Signed-off-by: Masatake YAMATO --- misc-utils/lsfd.1.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc-utils/lsfd.1.adoc b/misc-utils/lsfd.1.adoc index 0aab4906f45..4149aabdf9f 100644 --- a/misc-utils/lsfd.1.adoc +++ b/misc-utils/lsfd.1.adoc @@ -188,6 +188,9 @@ write mode of the endpoint. eventfd type::: _PID_,_COMMAND_,_ASSOC_ +UNIX-STREAM::: +_PID_,_COMMAND_,_ASSOC_ + EVENTFD.ID <``number``>:: Eventfd ID. From 98d1485de9c5fdc81d424e59eb7da47d21405555 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 9 Oct 2023 15:29:40 +0900 Subject: [PATCH 05/15] tests: (lsfd::mkfds-socketpair) make a case for testing DGRAM a subtest and add a subtest for STREAM Signed-off-by: Masatake YAMATO --- ...kfds-socketpair => mkfds-socketpair-DGRAM} | 0 tests/expected/lsfd/mkfds-socketpair-STREAM | 3 +++ tests/ts/lsfd/mkfds-socketpair | 22 +++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) rename tests/expected/lsfd/{mkfds-socketpair => mkfds-socketpair-DGRAM} (100%) create mode 100644 tests/expected/lsfd/mkfds-socketpair-STREAM diff --git a/tests/expected/lsfd/mkfds-socketpair b/tests/expected/lsfd/mkfds-socketpair-DGRAM similarity index 100% rename from tests/expected/lsfd/mkfds-socketpair rename to tests/expected/lsfd/mkfds-socketpair-DGRAM diff --git a/tests/expected/lsfd/mkfds-socketpair-STREAM b/tests/expected/lsfd/mkfds-socketpair-STREAM new file mode 100644 index 00000000000..d8ba4d0bc50 --- /dev/null +++ b/tests/expected/lsfd/mkfds-socketpair-STREAM @@ -0,0 +1,3 @@ +3 rw- SOCK sockfs UNIX +4 rw- SOCK sockfs UNIX +ASSOC,MODE,STTYPE,SOURCE,SOCK.PROTONAME: 0 diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair index 64984d94642..e8c9be0be53 100755 --- a/tests/ts/lsfd/mkfds-socketpair +++ b/tests/ts/lsfd/mkfds-socketpair @@ -33,6 +33,7 @@ FD0=3 FD1=4 EXPR= +ts_init_subtest "DGRAM" { coproc MKFDS { "$TS_HELPER_MKFDS" socketpair $FD0 $FD1 socktype=DGRAM; } if read -u ${MKFDS[0]} PID; then @@ -42,7 +43,24 @@ EXPR= echo DONE >&"${MKFDS[1]}" fi - wait ${MKFDS_PID} -} > $TS_OUTPUT 2>&1 +} > "$TS_OUTPUT" 2>&1 + +wait ${MKFDS_PID} +ts_finalize_subtest + +ts_init_subtest "STREAM" +{ + coproc MKFDS { "$TS_HELPER_MKFDS" socketpair $FD0 $FD1 socktype=STREAM; } + if read -u ${MKFDS[0]} PID; then + EXPR='(PID == '"${PID}"') and ((FD == '"$FD0"') or (FD == '"$FD1"'))' + ${TS_CMD_LSFD} -n -o ASSOC,MODE,STTYPE,SOURCE,SOCK.PROTONAME -Q "${EXPR}" | sed -e 's/UNIX-STREAM/UNIX/' + echo 'ASSOC,MODE,STTYPE,SOURCE,SOCK.PROTONAME': ${PIPESTATUS[0]} + + echo DONE >&"${MKFDS[1]}" + fi +} > "$TS_OUTPUT" 2>&1 + +wait ${MKFDS_PID} +ts_finalize_subtest ts_finalize From b3563457dbe009628a61e012a6accf7fcca803d2 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 4 Aug 2023 01:29:53 +0900 Subject: [PATCH 06/15] tests: (lsfd) add a case for testing ENDPOINTS column of UNIX-STREAM sockets Signed-off-by: Masatake YAMATO --- .../lsfd/mkfds-socketpair-STREAM-ENDPOINT | 3 +++ tests/ts/lsfd/mkfds-socketpair | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT diff --git a/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT b/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT new file mode 100644 index 00000000000..ad015d8dec1 --- /dev/null +++ b/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT @@ -0,0 +1,3 @@ +3 rw- SOCK sockfs 1,test_mkfds,4 +4 rw- SOCK sockfs 1,test_mkfds,3 +ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS: 0 diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair index e8c9be0be53..9883f0ac98b 100755 --- a/tests/ts/lsfd/mkfds-socketpair +++ b/tests/ts/lsfd/mkfds-socketpair @@ -63,4 +63,28 @@ ts_init_subtest "STREAM" wait ${MKFDS_PID} ts_finalize_subtest +mkfds_socketpair_stream_endpoint() +{ + ts_init_subtest "STREAM-ENDPOINT" + if [ "$QEMU_USER" == "1" ]; then + ts_skip_subtest "running under qemu-user emulation" + return + fi + { + coproc MKFDS { "$TS_HELPER_MKFDS" socketpair $FD0 $FD1 socktype=STREAM; } + if read -u ${MKFDS[0]} PID; then + EXPR='(FD == '"$FD0"') or (FD == '"$FD1"')' + ${TS_CMD_LSFD} -p "${PID}" -n -o ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS -Q "${EXPR}" | sed -e "s/${PID}/1/g" + echo 'ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS': ${PIPESTATUS[0]} + + echo DONE >&"${MKFDS[1]}" + fi + } > "$TS_OUTPUT" 2>&1 + + wait ${MKFDS_PID} + ts_finalize_subtest +} + +mkfds_socketpair_stream_endpoint + ts_finalize From f4479119177f7453b46c6a2180d97f88c9cbe4af Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:00:41 +0900 Subject: [PATCH 07/15] lsfd: call xinfo backend method before calling socket generic method when filling columns Signed-off-by: Masatake YAMATO --- misc-utils/lsfd-sock.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/misc-utils/lsfd-sock.c b/misc-utils/lsfd-sock.c index 7da2f61e589..ee0aa737a65 100644 --- a/misc-utils/lsfd-sock.c +++ b/misc-utils/lsfd-sock.c @@ -55,6 +55,15 @@ static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), { char *str = NULL; struct sock *sock = (struct sock *)file; + + if (sock->xinfo && sock->xinfo->class + && sock->xinfo->class->fill_column) { + if (sock->xinfo->class->fill_column(proc, sock->xinfo, sock, ln, + column_id, column_index, + &str)) + goto out; + } + switch(column_id) { case COL_TYPE: if (!sock->protoname) @@ -112,16 +121,10 @@ static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), : "0"); break; default: - if (sock->xinfo && sock->xinfo->class - && sock->xinfo->class->fill_column) { - if (sock->xinfo->class->fill_column(proc, sock->xinfo, sock, ln, - column_id, column_index, - &str)) - break; - } return false; } + out: if (!str) err(EXIT_FAILURE, _("failed to add output data")); if (scols_line_refer_data(ln, column_index, str)) From 426ff07f9a54503c5d8646a1589d4d7a7018d740 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:03:06 +0900 Subject: [PATCH 08/15] lsfd: add SOCK.SHUTDOWN column An example output: # ./lsfd -p1 -Q '(TYPE == "UNIX-STREAM")' -o+SOCK.SHUTDOWN systemd 1 root 443 rw---m UNIX-STREAM sockfs 9 183103884 state=connected path=/run/systemd/journal/stdout r- systemd 1 root 462 rw---- UNIX-STREAM sockfs 9 11172039 state=listen path=/run/libvirt/libvirt-sock rw Signed-off-by: Masatake YAMATO --- misc-utils/lsfd-sock-xinfo.c | 33 ++++++++++++++++++++++++++++++++- misc-utils/lsfd-sock.c | 3 +++ misc-utils/lsfd.c | 3 +++ misc-utils/lsfd.h | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c index 301da278893..a0e82026d77 100644 --- a/misc-utils/lsfd-sock-xinfo.c +++ b/misc-utils/lsfd-sock-xinfo.c @@ -404,6 +404,9 @@ struct unix_xinfo { int acceptcon; /* flags */ uint16_t type; uint8_t st; +#define is_shutdown_mask_set(mask) ((mask) & (1 << 2)) +#define set_shutdown_mask(mask) ((mask) |= (1 << 2)) + uint8_t shutdown_mask:3; struct unix_ipc *unix_ipc; char path[ UNIX_PATH_MAX @@ -519,6 +522,19 @@ static struct ipc_class *unix_get_ipc_class(struct sock_xinfo *sock_xinfo __attr return &unix_ipc_class; } +static bool unix_shutdown_chars(struct unix_xinfo *ux, char rw[2]) +{ + uint8_t mask = ux->shutdown_mask; + + if (is_shutdown_mask_set(mask)) { + rw[0] = ((mask & (1 << 0))? '-': 'r'); + rw[1] = ((mask & (1 << 1))? '-': 'w'); + return true; + } + + return false; +} + static inline char *unix_xstrendpoint(struct sock *sock) { char *str = NULL; @@ -552,6 +568,7 @@ static bool unix_fill_column(struct proc *proc __attribute__((__unused__)), struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo; struct ipc *peer_ipc; struct list_head *e; + char shutdown_chars[3] = { 0 }; switch (column_id) { case COL_UNIX_PATH: @@ -578,6 +595,12 @@ static bool unix_fill_column(struct proc *proc __attribute__((__unused__)), if (*str) return true; break; + case COL_SOCK_SHUTDOWN: + if (unix_shutdown_chars(ux, shutdown_chars)) { + *str = xstrdup(shutdown_chars); + return true; + } + break; } return false; @@ -706,6 +729,14 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), unix_refill_name(xinfo, RTA_DATA(attr), len); break; + case UNIX_DIAG_SHUTDOWN: + if (len < 1) + break; + + unix_xinfo->shutdown_mask = *(uint8_t *)RTA_DATA(attr); + set_shutdown_mask(unix_xinfo->shutdown_mask); + break; + case UNIX_DIAG_PEER: if (len < 4) break; @@ -725,7 +756,7 @@ static void load_xinfo_from_diag_unix(int diagsd, ino_t netns) struct unix_diag_req udr = { .sdiag_family = AF_UNIX, .udiag_states = -1, /* set the all bits. */ - .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER, + .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UNIX_DIAG_SHUTDOWN, }; send_diag_request(diagsd, &udr, sizeof(udr), handle_diag_unix, netns); diff --git a/misc-utils/lsfd-sock.c b/misc-utils/lsfd-sock.c index ee0aa737a65..4c75e6eaf96 100644 --- a/misc-utils/lsfd-sock.c +++ b/misc-utils/lsfd-sock.c @@ -120,6 +120,9 @@ static bool sock_fill_column(struct proc *proc __attribute__((__unused__)), ? "1" : "0"); break; + case COL_SOCK_SHUTDOWN: + str = xstrdup("??"); + break; default: return false; } diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index 13f6282c7e1..7bd24d26771 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -296,6 +296,9 @@ static const struct colinfo infos[] = { [COL_SOCK_PROTONAME] = { "SOCK.PROTONAME", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("protocol name") }, + [COL_SOCK_SHUTDOWN] = { "SOCK.SHUTDOWN", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, + N_("shutdown state of socket ([-r?][-w?])") }, [COL_SOCK_STATE] = { "SOCK.STATE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("State of socket") }, diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h index 9cf87f83085..c9c975392fc 100644 --- a/misc-utils/lsfd.h +++ b/misc-utils/lsfd.h @@ -99,6 +99,7 @@ enum { COL_SOCK_LISTENING, COL_SOCK_NETNS, COL_SOCK_PROTONAME, + COL_SOCK_SHUTDOWN, COL_SOCK_STATE, COL_SOCK_TYPE, COL_SOURCE, From 0536fd829ad21d4d66ec03f2ca883125f306c6f9 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:15:59 +0900 Subject: [PATCH 09/15] lsfd: (man) write about SOCK.SHUTDOWN column Signed-off-by: Masatake YAMATO --- misc-utils/lsfd.1.adoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/misc-utils/lsfd.1.adoc b/misc-utils/lsfd.1.adoc index 4149aabdf9f..02e34e7b574 100644 --- a/misc-utils/lsfd.1.adoc +++ b/misc-utils/lsfd.1.adoc @@ -423,6 +423,19 @@ Inode identifying network namespace where the socket belongs to. SOCK.PROTONAME <``string``>:: Protocol name. +SOCK.SHUTDOWN <``string``>:: +Shutdown state of socket. ++ +[-r?]::: +If the first character is _r_, the receptions are allowed. +If it is _-_, the receptions are disallowed. +If it is _?_, the state is unknown. ++ +[-w?]::: +If the second character is _w_, the transmissions are allowed. +If it is _-_, the transmissions are disallowed. +If it is _?_, the state is unknown. + SOCK.STATE <``string``>:: State of socket. From cd30dd6f86bb0f9a82b618490a2853de8b2ad08a Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:19:51 +0900 Subject: [PATCH 10/15] lsfd: don't capitalize the help strings for the columns Signed-off-by: Masatake YAMATO --- misc-utils/lsfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index 7bd24d26771..921216235d7 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -301,10 +301,10 @@ static const struct colinfo infos[] = { N_("shutdown state of socket ([-r?][-w?])") }, [COL_SOCK_STATE] = { "SOCK.STATE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, - N_("State of socket") }, + N_("state of socket") }, [COL_SOCK_TYPE] = { "SOCK.TYPE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, - N_("Type of socket") }, + N_("type of socket") }, [COL_SOURCE] = { "SOURCE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("file system, partition, or device containing file") }, From ef46aa41a12bc34480c305f7d30c8ce2e7fe9781 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 21:44:13 +0900 Subject: [PATCH 11/15] tests: (test_mkfds::socketpair) add "halfclose" parameter Signed-off-by: Masatake YAMATO --- tests/helpers/test_mkfds.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index db61727e2c5..8a1388adff4 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -894,6 +894,12 @@ static void *make_socketpair(const struct factory *factory, struct fdesc fdescs[ int sd[2]; struct arg socktype = decode_arg("socktype", factory->params, argc, argv); int isocktype; + struct arg halfclose = decode_arg("halfclose", factory->params, argc, argv); + bool bhalfclose; + + bhalfclose = ARG_BOOLEAN(halfclose); + free_arg(&halfclose); + if (strcmp(ARG_STRING(socktype), "STREAM") == 0) isocktype = SOCK_STREAM; else if (strcmp(ARG_STRING(socktype), "DGRAM") == 0) @@ -909,6 +915,15 @@ static void *make_socketpair(const struct factory *factory, struct fdesc fdescs[ if (socketpair(AF_UNIX, isocktype, 0, sd) < 0) err(EXIT_FAILURE, "failed to make socket pair"); + if (bhalfclose) { + if (shutdown(sd[0], SHUT_RD) < 0) + err(EXIT_FAILURE, + "failed to shutdown the read end of the 1st socket"); + if (shutdown(sd[1], SHUT_WR) < 0) + err(EXIT_FAILURE, + "failed to shutdown the write end of the 2nd socket"); + } + for (int i = 0; i < 2; i++) { if (sd[i] != fdescs[i].fd) { if (dup2(sd[i], fdescs[i].fd) < 0) { @@ -3160,6 +3175,12 @@ static const struct factory factories[] = { .desc = "STREAM, DGRAM, or SEQPACKET", .defv.string = "STREAM", }, + { + .name = "halfclose", + .type = PTYPE_BOOLEAN, + .desc = "Shutdown the read end of the 1st socket, the write end of the 2nd socket", + .defv.boolean = false, + }, PARAM_END }, }, From 750ad7ceb138c759f24adff7e823063df24414fe Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:35:46 +0900 Subject: [PATCH 12/15] tests: (lsfd) add a case for testing SOCK.SHUTDOWN column Signed-off-by: Masatake YAMATO --- .../mkfds-socketpair-STREAM-SHUTDOWN-STATE | 3 +++ tests/ts/lsfd/mkfds-socketpair | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/expected/lsfd/mkfds-socketpair-STREAM-SHUTDOWN-STATE diff --git a/tests/expected/lsfd/mkfds-socketpair-STREAM-SHUTDOWN-STATE b/tests/expected/lsfd/mkfds-socketpair-STREAM-SHUTDOWN-STATE new file mode 100644 index 00000000000..a7a285ce469 --- /dev/null +++ b/tests/expected/lsfd/mkfds-socketpair-STREAM-SHUTDOWN-STATE @@ -0,0 +1,3 @@ +3 rw- SOCK sockfs -w +4 rw- SOCK sockfs r- +ASSOC,MODE,STTYPE,SOURCE,SOCK.SHUTDOWN: 0 diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair index 9883f0ac98b..ef354526bf4 100755 --- a/tests/ts/lsfd/mkfds-socketpair +++ b/tests/ts/lsfd/mkfds-socketpair @@ -85,6 +85,29 @@ mkfds_socketpair_stream_endpoint() ts_finalize_subtest } +mkfds_socketpair_stream_shutdown_state() +{ + ts_init_subtest "STREAM-SHUTDOWN-STATE" + if [ "$QEMU_USER" == "1" ]; then + ts_skip_subtest "running under qemu-user emulation" + return + fi + { + coproc MKFDS { "$TS_HELPER_MKFDS" socketpair $FD0 $FD1 socktype=STREAM halfclose=1; } + if read -u ${MKFDS[0]} PID; then + EXPR='(FD == '"$FD0"') or (FD == '"$FD1"')' + ${TS_CMD_LSFD} -p "${PID}" -n -o ASSOC,MODE,STTYPE,SOURCE,SOCK.SHUTDOWN -Q "${EXPR}" + echo 'ASSOC,MODE,STTYPE,SOURCE,SOCK.SHUTDOWN': ${PIPESTATUS[0]} + + echo DONE >&"${MKFDS[1]}" + fi + } > "$TS_OUTPUT" 2>&1 + + wait ${MKFDS_PID} + ts_finalize_subtest +} + mkfds_socketpair_stream_endpoint +mkfds_socketpair_stream_shutdown_state ts_finalize From 3f3da329201d3e30ca01de9d0b24132f7f9f36bc Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:50:21 +0900 Subject: [PATCH 13/15] lsfd: append SOCK.SHUTDOWN value to ENDPOINTS column of UNIX-STREAM sockets An example output: # ./lsfd -Q '((PID == 1) || (PID == 1896)) && (TYPE == "UNIX-STREAM") && ((FD == 1) || (FD == 278))' -o+ENDPOINTS COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME ENDPOINTS systemd 1 root 278 rw---m UNIX-STREAM sockfs 9 37012 state=connected path=/run/systemd/journal/stdout 1896,ModemManager,1-w ModemManager 1896 root 1 rw---- UNIX-STREAM sockfs 9 43126 state=connected 1,systemd,278r- 1870458,systemd-journal,68r- Signed-off-by: Masatake YAMATO --- misc-utils/lsfd-sock-xinfo.c | 12 ++++++++++-- tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c index a0e82026d77..7ea8f2efe2b 100644 --- a/misc-utils/lsfd-sock-xinfo.c +++ b/misc-utils/lsfd-sock-xinfo.c @@ -538,8 +538,16 @@ static bool unix_shutdown_chars(struct unix_xinfo *ux, char rw[2]) static inline char *unix_xstrendpoint(struct sock *sock) { char *str = NULL; - xasprintf(&str, "%d,%s,%d", - sock->file.proc->pid, sock->file.proc->command, sock->file.association); + char shutdown_chars[3] = { 0 }; + + if (!unix_shutdown_chars(((struct unix_xinfo *)sock->xinfo), shutdown_chars)) { + shutdown_chars[0] = '?'; + shutdown_chars[1] = '?'; + } + xasprintf(&str, "%d,%s,%d%c%c", + sock->file.proc->pid, sock->file.proc->command, sock->file.association, + shutdown_chars[0], shutdown_chars[1]); + return str; } diff --git a/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT b/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT index ad015d8dec1..02f6498a967 100644 --- a/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT +++ b/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT @@ -1,3 +1,3 @@ -3 rw- SOCK sockfs 1,test_mkfds,4 -4 rw- SOCK sockfs 1,test_mkfds,3 +3 rw- SOCK sockfs 1,test_mkfds,4rw +4 rw- SOCK sockfs 1,test_mkfds,3rw ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS: 0 From b0dbcec023e7108171c5b6f44556529c82bc1812 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 21:52:00 +0900 Subject: [PATCH 14/15] tests: (lsfd) extend the mkfds-socketpair case to test ENDPOINTS with SOCK.SHUTDOWN info Signed-off-by: Masatake YAMATO --- ...mkfds-socketpair-STREAM-ENDPOINT-halfclose | 3 +++ tests/ts/lsfd/mkfds-socketpair | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT-halfclose diff --git a/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT-halfclose b/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT-halfclose new file mode 100644 index 00000000000..72fa0525767 --- /dev/null +++ b/tests/expected/lsfd/mkfds-socketpair-STREAM-ENDPOINT-halfclose @@ -0,0 +1,3 @@ +3 rw- SOCK sockfs 1,test_mkfds,4r- +4 rw- SOCK sockfs 1,test_mkfds,3-w +ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS: 0 diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair index ef354526bf4..38f9279cebe 100755 --- a/tests/ts/lsfd/mkfds-socketpair +++ b/tests/ts/lsfd/mkfds-socketpair @@ -107,7 +107,30 @@ mkfds_socketpair_stream_shutdown_state() ts_finalize_subtest } +mkfds_socketpair_stream_endpoint_halfclose() +{ + ts_init_subtest "STREAM-ENDPOINT-halfclose" + if [ "$QEMU_USER" == "1" ]; then + ts_skip_subtest "running under qemu-user emulation" + return + fi + { + coproc MKFDS { "$TS_HELPER_MKFDS" socketpair $FD0 $FD1 socktype=STREAM halfclose=1; } + if read -u ${MKFDS[0]} PID; then + EXPR='(FD == '"$FD0"') or (FD == '"$FD1"')' + ${TS_CMD_LSFD} -p "${PID}" -n -o ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS -Q "${EXPR}" | sed -e "s/${PID}/1/g" + echo 'ASSOC,MODE,STTYPE,SOURCE,ENDPOINTS': ${PIPESTATUS[0]} + + echo DONE >&"${MKFDS[1]}" + fi + } > "$TS_OUTPUT" 2>&1 + + wait ${MKFDS_PID} + ts_finalize_subtest +} + mkfds_socketpair_stream_endpoint mkfds_socketpair_stream_shutdown_state +mkfds_socketpair_stream_endpoint_halfclose ts_finalize From d58cd0f7eac2056ec80fdf9fae60887726d77b1f Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 2 Oct 2023 23:56:47 +0900 Subject: [PATCH 15/15] lsfd: (man) update the description of ENDPOINTS column of UNIX-Stream sockets Signed-off-by: Masatake YAMATO --- misc-utils/lsfd.1.adoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/misc-utils/lsfd.1.adoc b/misc-utils/lsfd.1.adoc index 02e34e7b574..1f7e889d46c 100644 --- a/misc-utils/lsfd.1.adoc +++ b/misc-utils/lsfd.1.adoc @@ -189,7 +189,10 @@ eventfd type::: _PID_,_COMMAND_,_ASSOC_ UNIX-STREAM::: -_PID_,_COMMAND_,_ASSOC_ +_PID_,_COMMAND_,_ASSOC_[-r?][-w?] ++ +About the last characters ([-r?][-w?]), see the description +of _SOCK.SHUTDOWN_. EVENTFD.ID <``number``>:: Eventfd ID.