From: Masatake YAMATO Date: Wed, 1 Nov 2023 17:47:35 +0000 (+0900) Subject: lsfd: fill ENDPOINTS column for pty devices X-Git-Tag: v2.40-rc1~165^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=52e94d61b09a05f7ee5ef0dddf75e9c69b3f0368;p=thirdparty%2Futil-linux.git lsfd: fill ENDPOINTS column for pty devices An example output: $ ./lsfd -o+ENDPOINTS -Q '(COMMAND =~ "tmux") and ((SOURCE == "ptmx") or (SOURCE =~ "pts:.*"))' COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME ENDPOINTS tmux: client 3717086 yamato 0 rw---- CHR pts:9 27 12 /dev/pts/9 2143274,xfce4-terminal,34rw tmux: client 3717086 yamato 1 rw---- CHR pts:9 27 12 /dev/pts/9 2143274,xfce4-terminal,34rw tmux: client 3717086 yamato 2 rw---- CHR pts:9 27 12 /dev/pts/9 2143274,xfce4-terminal,34rw tmux: server 3717088 yamato 5 rw---m CHR pts:9 27 12 /dev/pts/9 2143274,xfce4-terminal,34rw tmux: server 3717088 yamato 8 rw---m CHR ptmx 24 208 tty-index=16 3717089,zsh,0rw 3717089,zsh,1rw 3717089,zsh,2rw 3717089,zsh,10rw $ ./lsfd -o+ENDPOINTS -Q '(PID == 3717089) and (FD == 0)' COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME ENDPOINTS zsh 3717089 yamato 0 rw---- CHR pts:16 27 19 /dev/pts/16 3717088,tmux: server,8rw Signed-off-by: Masatake YAMATO --- diff --git a/misc-utils/lsfd-cdev.c b/misc-utils/lsfd-cdev.c index 0f47169f83..63f95ed516 100644 --- a/misc-utils/lsfd-cdev.c +++ b/misc-utils/lsfd-cdev.c @@ -35,7 +35,8 @@ struct ttydrv { unsigned long major; unsigned long minor_start, minor_end; char *name; - bool is_ptmx; + unsigned int is_ptmx: 1; + unsigned int is_pts: 1; }; struct cdev { @@ -164,9 +165,12 @@ static struct ttydrv *new_ttydrv(unsigned int major, ttydrv->minor_start = minor_start; ttydrv->minor_end = minor_end; ttydrv->name = xstrdup(name); - ttydrv->is_ptmx = false; + ttydrv->is_ptmx = 0; if (strcmp(name, "ptmx") == 0) - ttydrv->is_ptmx = true; + ttydrv->is_ptmx = 1; + ttydrv->is_pts = 0; + if (strcmp(name, "pts") == 0) + ttydrv->is_pts = 1; return ttydrv; } @@ -177,6 +181,11 @@ static void free_ttydrv(struct ttydrv *ttydrv) free(ttydrv); } +static bool is_pty(const struct ttydrv *ttydrv) +{ + return ttydrv->is_ptmx || ttydrv->is_pts; +} + static struct ttydrv *read_ttydrv(const char *line) { const char *p; @@ -435,9 +444,11 @@ static struct cdev_ops cdev_tun_ops = { * tty devices */ struct ttydata { + struct cdev *cdev; const struct ttydrv *drv; #define NO_TTY_INDEX -1 int tty_index; /* used only in ptmx devices */ + struct ipc_endpoint endpoint; }; static bool cdev_tty_probe(struct cdev *cdev) { @@ -449,6 +460,7 @@ static bool cdev_tty_probe(struct cdev *cdev) { return false; data = xmalloc(sizeof(struct ttydata)); + data->cdev = cdev; data->drv = ttydrv; data->tty_index = NO_TTY_INDEX; cdev->cdev_data = data; @@ -477,6 +489,16 @@ static char * cdev_tty_get_name(struct cdev *cdev) return str; } +static inline char *cdev_tty_xstrendpoint(struct file *file) +{ + char *str = NULL; + xasprintf(&str, "%d,%s,%d%c%c", + file->proc->pid, file->proc->command, file->association, + (file->mode & S_IRUSR)? 'r': '-', + (file->mode & S_IWUSR)? 'w': '-'); + return str; +} + static bool cdev_tty_fill_column(struct proc *proc __attribute__((__unused__)), struct cdev *cdev, struct libscols_line *ln __attribute__((__unused__)), @@ -501,6 +523,30 @@ static bool cdev_tty_fill_column(struct proc *proc __attribute__((__unused__)), return true; } return false; + case COL_ENDPOINTS: + if (is_pty(data->drv)) { + struct ttydata *this = data; + struct list_head *e; + foreach_endpoint(e, data->endpoint) { + char *estr; + struct ttydata *other = list_entry(e, struct ttydata, endpoint.endpoints); + if (this == other) + continue; + + if ((this->drv->is_ptmx && !other->drv->is_pts) + || (this->drv->is_pts && !other->drv->is_ptmx)) + continue; + + if (*str) + xstrputc(str, '\n'); + estr = cdev_tty_xstrendpoint(&other->cdev->file); + xstrappend(str, estr); + free(estr); + } + if (*str) + return true; + } + return false; default: return false; } @@ -526,13 +572,81 @@ static int cdev_tty_handle_fdinfo(struct cdev *cdev, const char *key, const char return 0; } +struct cdev_pty_ipc { + struct ipc ipc; + int tty_index; +}; + +static unsigned int cdev_pty_get_hash(struct file *file) +{ + struct cdev *cdev = (struct cdev *)file; + struct ttydata *data = cdev->cdev_data; + + return data->drv->is_ptmx? + (unsigned int)data->tty_index: + (unsigned int)minor(file->stat.st_rdev); +} + +static bool cdev_pty_is_suitable_ipc(struct ipc *ipc, struct file *file) +{ + struct cdev *cdev = (struct cdev *)file; + struct ttydata *data = cdev->cdev_data; + struct cdev_pty_ipc *cdev_pty_ipc = (struct cdev_pty_ipc *)ipc; + + return (data->drv->is_ptmx)? + cdev_pty_ipc->tty_index == (int)data->tty_index: + cdev_pty_ipc->tty_index == (int)minor(file->stat.st_rdev); +} + +static const struct ipc_class *cdev_tty_get_ipc_class(struct cdev *cdev) +{ + static const struct ipc_class cdev_pty_ipc_class = { + .size = sizeof(struct cdev_pty_ipc), + .get_hash = cdev_pty_get_hash, + .is_suitable_ipc = cdev_pty_is_suitable_ipc, + }; + + struct ttydata *data = cdev->cdev_data; + + if (is_pty(data->drv)) + return &cdev_pty_ipc_class; + + return NULL; +} + +static void cdev_tty_attach_xinfo(struct cdev *cdev) +{ + struct ttydata *data = cdev->cdev_data; + struct ipc *ipc; + unsigned int hash; + + + if (! is_pty(data->drv)) + return; + + init_endpoint(&data->endpoint); + ipc = get_ipc(&cdev->file); + if (ipc) + goto link; + + ipc = new_ipc(cdev_tty_get_ipc_class(cdev)); + hash = cdev_pty_get_hash(&cdev->file); + ((struct cdev_pty_ipc *)ipc)->tty_index = (int)hash; + + add_ipc(ipc, hash); + link: + add_endpoint(&data->endpoint, ipc); +} + static struct cdev_ops cdev_tty_ops = { .parent = &cdev_generic_ops, .probe = cdev_tty_probe, .free = cdev_tty_free, .get_name = cdev_tty_get_name, .fill_column = cdev_tty_fill_column, + .attach_xinfo = cdev_tty_attach_xinfo, .handle_fdinfo = cdev_tty_handle_fdinfo, + .get_ipc_class = cdev_tty_get_ipc_class, }; static const struct cdev_ops *cdev_ops[] = { diff --git a/misc-utils/lsfd.1.adoc b/misc-utils/lsfd.1.adoc index 1e9d6acb76..aef76ec5e3 100644 --- a/misc-utils/lsfd.1.adoc +++ b/misc-utils/lsfd.1.adoc @@ -180,6 +180,7 @@ with the fd: FIFO type::: mqueue type::: +ptmx and pts sources::: _PID_,_COMMAND_,_ASSOC_[-r][-w] + The last characters ([-r][-w]) represents the read and/or