Package: lsof Version: 4.86+dfsg-1 Severity: wishlist Tags: upstream patch lsof does not support mount namespaces of Linux. Instead you just get alof of (stat: No such file or directory) outputs.
Fixing this requires reworking the source to use openat() to still have access to /proc when in a differn't namespace. Only works as root (CAP_SYS_ADMIN). Patch attached. Cheers, Shawn -- System Information: Debian Release: jessie/sid APT prefers unstable APT policy: (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Foreign Architectures: i386 armhf Kernel: Linux 3.13.0-rc2-00123-g70839b6 (SMP w/2 CPU cores; PREEMPT) Locale: LANG=C.UTF-8, LC_CTYPE=C.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages lsof depends on: ii libc6 2.17-97 ii libperl4-corelibs-perl 0.003-1 ii perl 5.18.1-5 lsof recommends no packages. lsof suggests no packages. -- no debconf information
>From 02c75d4d3a60f79fc3a70f6acc3fe16b83d4264c Mon Sep 17 00:00:00 2001 From: Shawn Landden <sh...@churchofgit.com> Date: Mon, 9 Dec 2013 10:42:32 -0800 Subject: [PATCH 2/2] linux: mount namespace support If process we are inspecting is in a differn't mount namespace than we are currently in switch to that namespace before stat()s. Through openat() and fstatat() we are using the original /proc. If mount namespace if differn't than the one lsof was ran in, print the namespace. --- dialects/linux/dproc.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/dialects/linux/dproc.c b/dialects/linux/dproc.c index 7b54756..0f393c1 100644 --- a/dialects/linux/dproc.c +++ b/dialects/linux/dproc.c @@ -74,7 +74,9 @@ static short Cckreg; /* conditional status of regular file static short Ckscko; /* socket file only checking status: * 0 = none * 1 = check only socket files */ - +static short NoNS; /* do not check/switch namespaces if 1*/ +#define NS_READLINK_SIZE 3 + 1 + 12 + 1 +static char lsofmntns[NS_READLINK_SIZE]; /* * Local function prototypes @@ -193,6 +195,8 @@ gather_proc_info() (void) snpf(pidpath, pidpathl, "%s/", PROCFS); } + if (getlinksrcat(dirfd(ps), "self/ns/mnt", lsofmntns, sizeof(lsofmntns)) != 3 || strlen(&lsofmntns[4]) != 12) + NoNS = 1; /* * Get lock information. */ @@ -942,6 +946,7 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid, ps) FILE *ms; static char *vbuf = (char *)NULL; static size_t vsz = (size_t)0; + char nsbuf[NS_READLINK_SIZE]; #if defined(HASSELINUX) cntxlist_t *cntxp; @@ -984,6 +989,47 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid, ps) } ppath[i - 1] = '/'; /* + * Check if PID is in differn't mnt namespace + */ + if (!Ckscko && !NoNS) { + alloc_lfile(" mns", -1); + efs = 0; + if ((getlinksrcat(dirfd(procp), "ns/mnt", pbuf, sizeof(pbuf)) != 3 || strlen(&pbuf[4]) != 12) || + (getlinksrcat(dirfd(ps), "self/ns/mnt", nsbuf, sizeof(nsbuf)) != 3 || strlen(&nsbuf[4]) != 12)) + pn = 0; + else { + if (memcmp(pbuf, nsbuf, sizeof(nsbuf)) != 0) { + int fd; + fd = openat(dirfd(procp), "ns/mnt", O_RDONLY); + if (fd >= 0) { + if (setns(fd, CLONE_NEWNS) < 0) { + if (!Fwarn) { + (void) memset((void *)&sb, 0, sizeof(sb)); + (void) snpf(nmabuf, sizeof(nmabuf), "(setns: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } + ss = fstat(fd, &sb); + close(fd); + } + } + if (memcmp(pbuf, lsofmntns, sizeof(nsbuf)) != 0) + lnk = pn = 1; + else + pn = 0; + } + if (pn) { + (void) process_proc_node(&pbuf[4], + &sb, ss, + (struct stat *)NULL, 0, ps); + if (Lf->sf) + link_lfile(); + } + } + +/* * Process the ID's current working directory info. */ if (!Ckscko) { -- 1.8.5.1
>From 89b10252741b4de7c54474dbabff7e87fa364ea8 Mon Sep 17 00:00:00 2001 From: Shawn Landden <sh...@churchofgit.com> Date: Sat, 7 Dec 2013 12:08:24 -0800 Subject: [PATCH 1/2] linux: open proc entries at beginning of process_id() using openat(2) and friends Requires Linux 2.6.16. This should not change the behavior of lsof. It was highly tempting to restructure much more, so there is only one open() call on /proc and everything else works off that fd. This would allow the removal of alot of string manipulation like the following in gather_proc_info(): /* * Build path to PID's directory. */ if ((pidx + n + 1 + 1) > pidpathl) { pidpathl = pidx + n + 1 + 1 + 64; if (!(pidpath = (char *)realloc((MALLOC_P *)pidpath, pidpathl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for \"%s/%s/\"\n", Pn, (int)pidpathl, PROCFS, dp->d_name); Exit(1); } } (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name); n += (pidx + 1); However I resolved to only change what I need for the next patch. (which is still alot) --- dialects/linux/dnode.c | 5 +- dialects/linux/dproc.c | 302 ++++++++++++++++++++++++++++++++++----------- dialects/linux/dproto.h | 9 +- dialects/linux/dsock.c | 322 +++++++++++++++++++----------------------------- misc.c | 70 ++++++++++- 5 files changed, 436 insertions(+), 272 deletions(-) diff --git a/dialects/linux/dnode.c b/dialects/linux/dnode.c index 3bee053..ec94cbc 100644 --- a/dialects/linux/dnode.c +++ b/dialects/linux/dnode.c @@ -357,13 +357,14 @@ get_locks(p) */ void -process_proc_node(p, s, ss, l, ls) +process_proc_node(p, s, ss, l, ls, ps) char *p; /* node's readlink() path */ struct stat *s; /* stat() result for path */ int ss; /* *s status -- i.e., SB_* values */ struct stat *l; /* lstat() result for FD (NULL for * others) */ int ls; /* *l status -- i.e., SB_* values */ + DIR *ps; /* /proc */ { mode_t access; mode_t type = 0; @@ -399,7 +400,7 @@ process_proc_node(p, s, ss, l, ls) break; case S_IFSOCK: /* Lf->ntype = Ntype = N_REGLR; by alloc_lfile() */ - process_proc_sock(p, s, ss, l, ls); + process_proc_sock(p, s, ss, l, ls, ps); return; } } diff --git a/dialects/linux/dproc.c b/dialects/linux/dproc.c index 24ef256..7b54756 100644 --- a/dialects/linux/dproc.c +++ b/dialects/linux/dproc.c @@ -80,16 +80,17 @@ static short Ckscko; /* socket file only checking status: * Local function prototypes */ -_PROTOTYPE(static int get_fdinfo,(char *p, struct l_fdinfo *fi)); -_PROTOTYPE(static int getlinksrc,(char *ln, char *src, int srcl)); +_PROTOTYPE(static int get_fdinfoat,(int dirfd, char *p, struct l_fdinfo *fi)); +_PROTOTYPE(static int getlinksrcat,(int dirfd, char *ln, char *src, int srcl)); _PROTOTYPE(static int isefsys,(char *path, char *type, int l, efsys_list_t **rep, struct lfile **lfr)); _PROTOTYPE(static int nm2id,(char *nm, int *id, int *idl)); _PROTOTYPE(static int read_id_stat,(int ty, char *p, int id, char **cmd, int *ppid, int *pgid)); -_PROTOTYPE(static void process_proc_map,(char *p, struct stat *s, int ss)); +_PROTOTYPE(static void process_proc_map,(FILE *ms, struct stat *s, int ss, DIR *ps)); _PROTOTYPE(static int process_id,(char *idp, int idpl, char *cmd, UID_ARG uid, - int pid, int ppid, int pgid, int tid)); + int pid, int ppid, int pgid, int tid, + DIR *ps)); _PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss)); @@ -98,6 +99,7 @@ _PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx)); #include <fnmatch.h> +#include <sched.h> /* @@ -174,6 +176,7 @@ gather_proc_info() static int tidpathl = 0; DIR *ts; UID_ARG uid; + int procfd; /* * Do one-time setup. @@ -189,13 +192,12 @@ gather_proc_info() } (void) snpf(pidpath, pidpathl, "%s/", PROCFS); } + /* - * Get lock and net information. + * Get lock information. */ (void) make_proc_path(pidpath, pidx, &path, &pathl, "locks"); (void) get_locks(path); - (void) make_proc_path(pidpath, pidx, &path, &pathl, "net/"); - (void) set_net_paths(path, strlen(path)); /* * If only socket files have been selected, or socket files have been selected * ANDed with other selection options, enable the skipping of regular files. @@ -338,7 +340,7 @@ gather_proc_info() * Attempt to record the task. */ if (!process_id(tidpath, (tx + 1 + nl+ 1), tcmd, uid, - pid, tppid, tpgid, tid)) + pid, tppid, tpgid, tid, ps)) { ht = 1; } @@ -359,7 +361,7 @@ gather_proc_info() && (rv != 1)) { tid = (Fand && ht && pidts && (Selflags & SELTASK)) ? pid : 0; - if ((!process_id(pidpath, n, cmd, uid, pid, ppid, pgid, tid)) + if ((!process_id(pidpath, n, cmd, uid, pid, ppid, pgid, tid, ps)) && tid) { Lp->tid = 0; @@ -370,11 +372,12 @@ gather_proc_info() /* - * get_fdinfo() - get values from /proc/<PID>fdinfo/FD + * get_fdinfoat() - get values from /proc/<PID>/fdinfo/FD */ static int -get_fdinfo(p, fi) +get_fdinfoat(dirfd, p, fi) + int dirfd; /* fd of parent directory */ char *p; /* path to fdinfo file */ struct l_fdinfo *fi; /* pointer to local fdinfo values * return structure */ @@ -390,7 +393,13 @@ get_fdinfo(p, fi) */ if (!fi) return(0); - if (!p || !*p || !(fs = fopen(p, "r"))) + if (!p || !*p) + return(0); + if (dirfd < 0) + fs = fopen(p, "r"); + else + fs = fopenat(dirfd, p, "r"); + if (!fs) return(0); /* * Read the fdinfo file. @@ -435,12 +444,13 @@ get_fdinfo(p, fi) /* - * getlinksrc() - get the source path name for the /proc/<PID>/fd/<FD> link + * getlinksrcat() - get the source path name for the /proc/<PID>/fd/<FD> link */ static int -getlinksrc(ln, src, srcl) +getlinksrcat(dirfd, ln, src, srcl) + int dirfd; /* file descriptor of containing directory */ char *ln; /* link path */ char *src; /* link source path return address */ int srcl; /* length of src[] */ @@ -448,7 +458,7 @@ getlinksrc(ln, src, srcl) char *cp; int ll; - if ((ll = readlink(ln, src, srcl - 1)) < 1 + if ((ll = readlinkat(dirfd, ln, src, srcl - 1)) < 1 || ll >= srcl) return(-1); src[ll] = '\0'; @@ -503,7 +513,7 @@ initialize() if (!OffType) { (void) snpf(path, sizeof(path), "%s/%d/fdinfo/%d", PROCFS, Mypid, fd); - if (get_fdinfo(path, &fi) & FDINFO_POS) { + if (get_fdinfoat(-1, path, &fi) & FDINFO_POS) { if (fi.pos == (off_t)LSTAT_TEST_SEEK) OffType = 2; } @@ -757,8 +767,141 @@ open_proc_stream(p, m, buf, sz, act) return(fs); } +/* + * see fopen(3) + */ +int +fopen_to_open(m) + char *m; +{ + int flags; + + if (strchr(m, '+')) + flags = O_RDWR; + else if (m[0] == 'r') + flags = O_RDONLY; + else if (m[0] == 'w' || m[0] == 'a') + flags = O_WRONLY; + else + return(0); + + if (m[0] == 'a') + flags |= O_APPEND|O_CREAT; + if (m[0] == 'w') + flags |= O_TRUNC|O_CREAT; + + flags |= O_NONBLOCK; + + return flags; +} /* + * fopenat() use open() to back fopen() + */ + +FILE * +fopenat(dirfd, path, mode) + int dirfd; + char *path; + char *mode; +{ + int fd; + int flags = fopen_to_open(mode); + + fd = openat(dirfd, path, flags); + if (fd < 0) + return NULL; + + return fdopen(fd, mode); +} + +/* + * opendirat() use openat() to back opendir() + */ + +DIR * +opendirat(dirfd, path) + int dirfd; + char *path; +{ + int fd; + int flags = O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_CLOEXEC; + + fd = openat(dirfd, path, flags); + if (fd < 0) + return NULL; + + return fdopendir(fd); +} + +/* + * open_proc_streamat() -- open a /proc stream + */ + +FILE * +open_proc_streamat(dirfd, p, m, buf, sz, act) + int dirfd; /* fd of DIR which *p is in */ + char *p; /* pointer to path to open */ + char *m; /* pointer to mode -- e.g., "r" */ + char **buf; /* pointer tp setvbuf() address + * (NULL if none) */ + size_t *sz; /* setvbuf() size (0 if none or if + * getpagesize() desired */ + int act; /* fopen() failure action: + * 0 : return (FILE *)NULL + * <>0 : fprintf() an error message + * and Exit(1) + */ +{ + FILE *fs; /* opened stream */ + static size_t psz = (size_t)0; /* page size */ + size_t tsz; /* temporary size */ +/* + * Open the stream. + */ + if (!(fs = fopenat(dirfd, p, m))) { + if (!act) + return((FILE *)NULL); + (void) fprintf(stderr, "%s: can't fopenat(%d, %s, %s): %s\n", + Pn, dirfd, p, m, strerror(errno)); + Exit(1); + } +/* + * Return the stream if no buffer change is required. + */ + if (!buf) + return(fs); +/* + * Determine the buffer size required. + */ + if (!(tsz = *sz)) { + if (!psz) + psz = getpagesize(); + tsz = psz; + } +/* + * Allocate a buffer for the stream, as required. + */ + if (!*buf) { + if (!(*buf = (char *)malloc((MALLOC_S)tsz))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for %s stream buffer\n", + Pn, (int)tsz, p); + Exit(1); + } + *sz = tsz; + } +/* + * Assign the buffer to the stream. + */ + if (setvbuf(fs, *buf, _IOFBF, tsz)) { + (void) fprintf(stderr, "%s: setvbuf(%s)=%d failure: %s\n", + Pn, p, (int)tsz, strerror(errno)); + Exit(1); + } + return(fs); +} +/* * process_id - process ID: PID or LWP * * return: 0 == ID processed @@ -766,7 +909,7 @@ open_proc_stream(p, m, buf, sz, act) */ static int -process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) +process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid, ps) char *idp; /* pointer to ID's path */ int idpl; /* pointer to ID's path length */ char *cmd; /* pointer to ID's command */ @@ -775,14 +918,15 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) int ppid; /* parent PID */ int pgid; /* parent GID */ int tid; /* task ID, if non-zero */ + DIR *ps; /* open DIR on /proc */ { int av; - static char *dpath = (char *)NULL; - static int dpathl = 0; + static char *dpath = (char *)NULL, *ppath = (char *)NULL; + static int dpathl = 0, ppathl = 0; short efs, enls, enss, lnk, oty, pn, pss, sf; int fd, i, ls, n, ss, sv; struct l_fdinfo fi; - DIR *fdp; + DIR *fdp, *procp, *fdinfop; struct dirent *fp; static char *ipath = (char *)NULL; static int ipathl = 0; @@ -795,6 +939,9 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) static char *pathi = (char *)NULL; static int pathil = 0; int txts = 0; + FILE *ms; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; #if defined(HASSELINUX) cntxlist_t *cntxp; @@ -819,13 +966,30 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) Lp->tid = tid; Plf = (struct lfile *)NULL; /* + * Open /proc/<pid> + */ + if ((i = make_proc_path(idp, idpl, &ppath, &ppathl, "")) < 3) + return(0); + ppath[i - 1] = '\0'; + if (!(procp = opendir(ppath))) { + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "%s (opendir: %s)", + ppath, strerror(errno)); + alloc_lfile("NOFD", -1); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + link_lfile(); + } + return(0); + } + ppath[i - 1] = '/'; +/* * Process the ID's current working directory info. */ if (!Ckscko) { - (void) make_proc_path(idp, idpl, &path, &pathl, "cwd"); alloc_lfile(CWD, -1); efs = 0; - if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + if (getlinksrcat(dirfd(procp), "cwd", pbuf, sizeof(pbuf)) < 1) { if (!Fwarn) { (void) memset((void *)&sb, 0, sizeof(sb)); lnk = ss = 0; @@ -844,10 +1008,10 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } else { ss = SB_ALL; if (HasNFS) { - if ((sv = statsafely(path, &sb))) + if ((sv = statsafelyat(dirfd(procp), "cwd", &sb))) sv = statEx(pbuf, &sb, &ss); } else - sv = stat(path, &sb); + sv = fstatat(dirfd(procp), "cwd", &sb, 0); if (sv) { ss = 0; if (!Fwarn) { @@ -860,9 +1024,11 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } } if (pn) { + if (!lnk) + (void) make_proc_path(ppath, ppathl, &path, &pathl, "cwd"); (void) process_proc_node(lnk ? pbuf : path, &sb, ss, - (struct stat *)NULL, 0); + (struct stat *)NULL, 0, ps); if (Lf->sf) link_lfile(); } @@ -871,9 +1037,8 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) * Process the ID's root directory info. */ if (!Ckscko) { - (void) make_proc_path(idp, idpl, &path, &pathl, "root"); alloc_lfile(RTD, -1); - if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + if (getlinksrcat(dirfd(procp), "root", pbuf, sizeof(pbuf)) < 1) { if (!Fwarn) { (void) memset((void *)&sb, 0, sizeof(sb)); lnk = ss = 0; @@ -891,10 +1056,10 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) else { ss = SB_ALL; if (HasNFS) { - if ((sv = statsafely(path, &sb))) + if ((sv = statsafelyat(dirfd(procp), "root", &sb))) sv = statEx(pbuf, &sb, &ss); } else - sv = stat(path, &sb); + sv = fstatat(dirfd(procp), "root", &sb, 0); if (sv) { ss = 0; if (!Fwarn) { @@ -907,9 +1072,11 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } } if (pn) { + if (!lnk) + (void) make_proc_path(ppath, ppathl, &path, &pathl, "root"); (void) process_proc_node(lnk ? pbuf : path, &sb, ss, - (struct stat *)NULL, 0); + (struct stat *)NULL, 0, ps); if (Lf->sf) link_lfile(); } @@ -919,9 +1086,8 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) */ if (!Ckscko) { txts = 0; - (void) make_proc_path(idp, idpl, &path, &pathl, "exe"); alloc_lfile("txt", -1); - if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + if (getlinksrcat(dirfd(procp), "exe", pbuf, sizeof(pbuf)) < 1) { (void) memset((void *)&sb, 0, sizeof(sb)); lnk = ss = 0; if (!Fwarn) { @@ -941,13 +1107,13 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) else { ss = SB_ALL; if (HasNFS) { - if ((sv = statsafely(path, &sb))) { + if ((sv = statsafelyat(dirfd(procp), "exe", &sb))) { sv = statEx(pbuf, &sb, &ss); if (!sv && (ss & SB_DEV) && (ss & SB_INO)) txts = 1; } } else - sv = stat(path, &sb); + sv = fstatat(dirfd(procp), "exe", &sb, 0); if (sv) { ss = 0; if (!Fwarn) { @@ -961,9 +1127,11 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } } if (pn) { + if (!lnk) + (void) make_proc_path(ppath, ppathl, &path, &pathl, "exe"); (void) process_proc_node(lnk ? pbuf : path, &sb, ss, - (struct stat *)NULL, 0); + (struct stat *)NULL, 0, ps); if (Lf->sf) link_lfile(); } @@ -972,9 +1140,10 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) * Process the ID's memory map info. */ if (!Ckscko) { - (void) make_proc_path(idp, idpl, &path, &pathl, "maps"); - (void) process_proc_map(path, txts ? &sb : (struct stat *)NULL, - txts ? ss : 0); + ms = open_proc_streamat(dirfd(procp), "maps", "r", &vbuf, &vsz, 0); + if (ms) + (void) process_proc_map(ms, txts ? &sb : (struct stat *)NULL, + txts ? ss : 0, ps); } #if defined(HASSELINUX) @@ -1019,18 +1188,10 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) /* * Process the ID's file descriptor directory. */ - if ((i = make_proc_path(idp, idpl, &dpath, &dpathl, "fd/")) < 3) - return(0); - dpath[i - 1] = '\0'; - if ((OffType == 2) - && ((j = make_proc_path(idp, idpl, &ipath, &ipathl, "fdinfo/")) >= 7)) - oty = 1; - else - oty = 0; - if (!(fdp = opendir(dpath))) { + if (!(fdp = opendirat(dirfd(procp), "fd"))) { if (!Fwarn) { - (void) snpf(nmabuf, sizeof(nmabuf), "%s (opendir: %s)", - dpath, strerror(errno)); + (void) snpf(nmabuf, sizeof(nmabuf), "%s (open: %s)", + "fd", strerror(errno)); alloc_lfile("NOFD", -1); nmabuf[sizeof(nmabuf) - 1] = '\0'; (void) add_nma(nmabuf, strlen(nmabuf)); @@ -1038,13 +1199,18 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } return(0); } - dpath[i - 1] = '/'; + + if (OffType == 2) { + oty = 1; + if (!(fdinfop = opendirat(dirfd(procp), "fd"))) + return(0); + } else + oty = 0; while ((fp = readdir(fdp))) { if (nm2id(fp->d_name, &fd, &n)) continue; - (void) make_proc_path(dpath, i, &path, &pathl, fp->d_name); (void) alloc_lfile((char *)NULL, fd); - if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + if (getlinksrcat(dirfd(fdp), fp->d_name, pbuf, sizeof(pbuf)) < 1) { (void) memset((void *)&sb, 0, sizeof(sb)); lnk = ss = 0; if (!Fwarn) { @@ -1062,14 +1228,14 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) pn = 0; } else { if (HasNFS) { - if (lstatsafely(path, &lsb)) { + if (lstatsafelyat(dirfd(fdp), fp->d_name, &lsb)) { (void) statEx(pbuf, &lsb, &ls); enls = errno; } else { enls = 0; ls = SB_ALL; } - if (statsafely(path, &sb)) { + if (statsafelyat(dirfd(fdp), fp->d_name, &sb)) { (void) statEx(pbuf, &sb, &ss); enss = errno; } else { @@ -1077,9 +1243,9 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) ss = SB_ALL; } } else { - ls = lstat(path, &lsb) ? 0 : SB_ALL; + ls = fstatat(dirfd(fdp), fp->d_name, &lsb, AT_SYMLINK_NOFOLLOW) ? 0 : SB_ALL; enls = errno; - ss = stat(path, &sb) ? 0 : SB_ALL; + ss = fstatat(dirfd(fdp), fp->d_name, &sb, 0) ? 0 : SB_ALL; enss = errno; } if (!ls && !Fwarn) { @@ -1107,9 +1273,7 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } if (pn || (efs && lfr && oty)) { if (oty) { - (void) make_proc_path(ipath, j, &pathi, &pathil, - fp->d_name); - if ((av = get_fdinfo(pathi, &fi)) & FDINFO_POS) { + if ((av = get_fdinfoat(dirfd(fdinfop), fp->d_name, &fi)) & FDINFO_POS) { if (efs) { if (Foffset) { lfr->off = (SZOFFTYPE)fi.pos; @@ -1136,13 +1300,17 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) } if (pn) { - process_proc_node(lnk ? pbuf : path, &sb, ss, &lsb, ls); + if (!lnk) + (void) make_proc_path(dpath, dpathl, &path, &pathl, fp->d_name); + process_proc_node(lnk ? pbuf : path, &sb, ss, &lsb, ls, ps); if (Lf->sf) link_lfile(); } } } (void) closedir(fdp); + (void) closedir(fdinfop); + (void) closedir(procp); return(0); } @@ -1152,10 +1320,11 @@ process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid) */ static void -process_proc_map(p, s, ss) - char *p; /* path to process maps file */ +process_proc_map(ms, s, ss, ps) + FILE *ms; /* path to process maps file */ struct stat *s; /* executing text file state buffer */ int ss; /* *s status -- i.e., SB_* values */ + DIR *ps; /* /proc */ { char buf[MAXPATHLEN + 1], *ep, fmtbuf[32], **fp, nmabuf[MAXPATHLEN + 1]; dev_t dev; @@ -1164,7 +1333,6 @@ process_proc_map(p, s, ss) INODETYPE inode; MALLOC_S len; long maj, min; - FILE *ms; int ns = 0; struct stat sb; struct saved_map { @@ -1174,14 +1342,10 @@ process_proc_map(p, s, ss) static struct saved_map *sm = (struct saved_map *)NULL; efsys_list_t *rep; static int sma = 0; - static char *vbuf = (char *)NULL; - static size_t vsz = (size_t)0; /* * Open the /proc/<pid>/maps file, assign a page size buffer to its stream, * and read it/ */ - if (!(ms = open_proc_stream(p, "r", &vbuf, &vsz, 0))) - return; while (fgets(buf, sizeof(buf), ms)) { if ((nf = get_fields(buf, ":", &fp, &eb, 1)) < 7) continue; /* not enough fields */ @@ -1345,7 +1509,7 @@ process_proc_map(p, s, ss) * Record the file's information. */ if (!efs) - process_proc_node(fp[6], &sb, mss, (struct stat *)NULL, 0); + process_proc_node(fp[6], &sb, mss, (struct stat *)NULL, 0, ps); else { /* @@ -1482,7 +1646,7 @@ read_id_stat(ty, p, id, cmd, ppid, pgid) * of its requests to stat() NFS files lose root permission and may fail. * * This function should be used only when links have been successfully - * resolved in the /proc path by getlinksrc(). + * resolved in the /proc path by getlinksrcat(). */ static int diff --git a/dialects/linux/dproto.h b/dialects/linux/dproto.h index 4e5915f..8bd9623 100644 --- a/dialects/linux/dproto.h +++ b/dialects/linux/dproto.h @@ -46,6 +46,9 @@ _PROTOTYPE(extern void get_locks,(char *p)); _PROTOTYPE(extern int is_file_named,(int ty, char *p, struct mounts *mp, int cd)); _PROTOTYPE(extern int make_proc_path,(char *pp, int lp, char **np, int *npl, char *sf)); _PROTOTYPE(extern FILE *open_proc_stream,(char *p, char *mode, char **buf, size_t *sz, int act)); -_PROTOTYPE(extern void process_proc_node,(char *p, struct stat *s, int ss, struct stat *l, int ls)); -_PROTOTYPE(extern void process_proc_sock,(char *p, struct stat *s, int ss, struct stat *l, int ls)); -_PROTOTYPE(extern void set_net_paths,(char *p, int pl)); +_PROTOTYPE(extern FILE *open_proc_streamat,(int dirfd, char *p, char *mode, char **buf, size_t *sz, int act)); +_PROTOTYPE(extern void process_proc_node,(char *p, struct stat *s, int ss, struct stat *l, int ls, DIR *ps)); +_PROTOTYPE(extern void process_proc_sock,(char *p, struct stat *s, int ss, struct stat *l, int ls, DIR *ps)); +_PROTOTYPE(extern int fopen_to_open,(char *m)); +_PROTOTYPE(extern FILE *fopenat,(int dirfd, char *path, char *mode)); +_PROTOTYPE(extern DIR *opendirat,(int dirfd, char *path)); diff --git a/dialects/linux/dsock.c b/dialects/linux/dsock.c index 1fb86b1..b18243c 100644 --- a/dialects/linux/dsock.c +++ b/dialects/linux/dsock.c @@ -37,7 +37,7 @@ static char *rcsid = "$Id: dsock.c,v 1.38 2012/04/10 16:39:50 abe Exp $"; #include "lsof.h" - +#include <stdbool.h> /* * Local definitions @@ -152,7 +152,7 @@ struct uxsin { /* UNIX socket information */ * Local static values */ -static char *AX25path = (char *)NULL; /* path to AX25 /proc information */ +static bool got_ax25 = false; static struct ax25sin **AX25sin = (struct ax25sin **)NULL; /* AX25 socket info, hashed by inode */ static char *ax25st[] = { @@ -163,34 +163,34 @@ static char *ax25st[] = { "RECOVERY" /* 4 */ }; #define NAX25ST (sizeof(ax25st) / sizeof(char *)) -static char *Ipxpath = (char *)NULL; /* path to IPX /proc information */ +static bool got_ipx = false; static struct ipxsin **Ipxsin = (struct ipxsin **)NULL; /* IPX socket info, hashed by inode */ -static char *Nlkpath = (char *)NULL; /* path to Netlink /proc information */ +static bool got_netlink = false; static struct nlksin **Nlksin = (struct nlksin **)NULL; /* Netlink socket info, hashed by * inode */ static struct packin **Packin = (struct packin **)NULL; /* packet info, hashed by inode */ -static char *Packpath = (char *)NULL; /* path to packet /proc information */ -static char *Rawpath = (char *)NULL; /* path to raw socket /proc - * information */ +static bool got_pack = false; +static bool got_raw = false; + static struct rawsin **Rawsin = (struct rawsin **)NULL; /* raw socket info, hashed by inode */ -static char *SCTPPath[] = { /* paths to /proc/net STCP info */ - (char *)NULL, /* 0 = /proc/net/sctp/assocs */ - (char *)NULL /* 1 = /proc/net/sctp/eps */ -}; -#define NSCTPPATHS sizeof(SCTPPath)/sizeof(char *) +static bool got_sctp = false; +#define NSCTPPATHS sizeof(SCTPSfx)/sizeof(char *) static char *SCTPSfx[] = { /* /proc/net suffixes */ "sctp/assocs", /* 0 = /proc/net/sctp/assocs */ "sctp/eps" /* 1 = /proc/net/sctp/eps */ }; static struct sctpsin **SCTPsin = (struct sctpsin **)NULL; /* SCTP info, hashed by inode */ -static char *SockStatPath = (char *)NULL; - /* path to /proc/net socket status */ -static char *TCPpath = (char *)NULL; /* path to TCP /proc information */ +static bool got_tcp = false; +static char *tcpudpprot[] = { + "tcp", + "udp", + "udplite" +}; static struct tcp_udp **TcpUdp = (struct tcp_udp **)NULL; /* IPv4 TCP & UDP info, hashed by * inode */ @@ -199,30 +199,24 @@ static int TcpUdp_bucks = 0; /* dynamically sized hash bucket * be a power of two */ #if defined(HASIPv6) -static char *Raw6path = (char *)NULL; /* path to raw IPv6 /proc information */ +static bool got_raw6 = false; static struct rawsin **Rawsin6 = (struct rawsin **)NULL; /* IPv6 raw socket info, hashed by * inode */ -static char *SockStatPath6 = (char *)NULL; - /* path to /proc/net IPv6 socket - * status */ -static char *TCP6path = (char *)NULL; /* path to IPv6 TCP /proc information */ +static bool got_tcp6 = false; static struct tcp_udp6 **TcpUdp6 = (struct tcp_udp6 **)NULL; /* IPv6 TCP & UDP info, hashed by * inode */ static int TcpUdp6_bucks = 0; /* dynamically sized hash bucket * count for IPv6 TCP and UDP -- will * be a power of two */ -static char *UDP6path = (char *)NULL; /* path to IPv6 UDP /proc information */ -static char *UDPLITE6path = (char *)NULL; - /* path to IPv6 UDPLITE /proc - * information */ +static bool got_udp6 = false; +static bool got_udplite6 = false; #endif /* defined(HASIPv6) */ -static char *UDPpath = (char *)NULL; /* path to UDP /proc information */ -static char *UDPLITEpath = (char *)NULL; - /* path to UDPLITE /proc information */ -static char *UNIXpath = (char *)NULL; /* path to UNIX /proc information */ +static bool got_udp = false; +static bool got_udplite = false; +static bool got_unix = false; static struct uxsin **Uxsin = (struct uxsin **)NULL; /* UNIX socket info, hashed by inode */ @@ -239,15 +233,15 @@ _PROTOTYPE(static struct rawsin *check_raw,(INODETYPE i)); _PROTOTYPE(static struct sctpsin *check_sctp,(INODETYPE i)); _PROTOTYPE(static struct tcp_udp *check_tcpudp,(INODETYPE i, char **p)); _PROTOTYPE(static struct uxsin *check_unix,(INODETYPE i)); -_PROTOTYPE(static void get_ax25,(char *p)); -_PROTOTYPE(static void get_ipx,(char *p)); -_PROTOTYPE(static void get_netlink,(char *p)); -_PROTOTYPE(static void get_pack,(char *p)); -_PROTOTYPE(static void get_raw,(char *p)); -_PROTOTYPE(static void get_sctp,(void)); +_PROTOTYPE(static void get_ax25,(int netfd)); +_PROTOTYPE(static void get_ipx,(int netfd)); +_PROTOTYPE(static void get_netlink,(int netfd)); +_PROTOTYPE(static void get_pack,(int netfd)); +_PROTOTYPE(static void get_raw,(int netfd)); +_PROTOTYPE(static void get_sctp,(int netfd)); _PROTOTYPE(static char *get_sctpaddrs,(char **fp, int i, int nf, int *x)); -_PROTOTYPE(static void get_tcpudp,(char *p, int pr, int clr)); -_PROTOTYPE(static void get_unix,(char *p)); +_PROTOTYPE(static void get_tcpudp,(int netfd, int pr, int clr)); +_PROTOTYPE(static void get_unix,(int netfd)); _PROTOTYPE(static int isainb,(char *a, char *b)); _PROTOTYPE(static void print_ax25info,(struct ax25sin *ap)); _PROTOTYPE(static void print_ipxinfo,(struct ipxsin *ip)); @@ -255,8 +249,8 @@ _PROTOTYPE(static void print_ipxinfo,(struct ipxsin *ip)); #if defined(HASIPv6) _PROTOTYPE(static struct rawsin *check_raw6,(INODETYPE i)); _PROTOTYPE(static struct tcp_udp6 *check_tcpudp6,(INODETYPE i, char **p)); -_PROTOTYPE(static void get_raw6,(char *p)); -_PROTOTYPE(static void get_tcpudp6,(char *p, int pr, int clr)); +_PROTOTYPE(static void get_raw6,(int netfd)); +_PROTOTYPE(static void get_tcpudp6,(int netfd, int pr, int clr)); _PROTOTYPE(static int net6a2in6,(char *as, struct in6_addr *ad)); #endif /* defined(HASIPv6) */ @@ -523,8 +517,8 @@ check_unix(i) */ static void -get_ax25(p) - char *p; /* /proc/net/ipx path */ +get_ax25(netfd) + int netfd; /* /proc/net/ipx path */ { struct ax25sin *ap, *np; FILE *as; @@ -567,7 +561,7 @@ get_ax25(p) * Open the /proc/net/ax25 file, assign a page size buffer to the stream, * and read it. Store AX25 socket info in the AX25sin[] hash buckets. */ - if (!(as = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(as = open_proc_streamat(netfd, "ax25", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, as)) { if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) < 24) @@ -698,8 +692,8 @@ get_ax25(p) */ static void -get_ipx(p) - char *p; /* /proc/net/ipx path */ +get_ipx(netfd) + int netfd; /* /proc/net/ fd */ { char buf[MAXPATHLEN], *ep, **fp, *la, *ra; int fl = 1; @@ -740,7 +734,7 @@ get_ipx(p) * Open the /proc/net/ipx file, assign a page size buffer to the stream, * and read it. Store IPX socket info in the Ipxsin[] hash buckets. */ - if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(xs = open_proc_streamat(netfd, "ipx", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, xs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 7) @@ -761,7 +755,7 @@ get_ipx(p) if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: unsupported format: %s\n", - Pn, p); + Pn, PROCFS "/net/ipx"); } break; } @@ -857,8 +851,8 @@ get_ipx(p) */ static void -get_netlink(p) - char *p; /* /proc/net/netlink path */ +get_netlink(netfd) + int netfd; /* /proc/net/netlink path */ { char buf[MAXPATHLEN], *ep, **fp; int fr = 1; @@ -892,7 +886,7 @@ get_netlink(p) * Open the /proc/net/netlink file, assign a page size buffer to its stream, * and read the file. Store Netlink info in the Nlksin[] hash buckets. */ - if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(xs = open_proc_streamat(netfd, "netlink", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, xs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 10) @@ -908,7 +902,7 @@ get_netlink(p) if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: unsupported format: %s\n", - Pn, p); + Pn, PROCFS "/net/netlink"); } break; } @@ -961,8 +955,8 @@ get_netlink(p) */ static void -get_pack(p) - char *p; /* /proc/net/raw path */ +get_pack(netfd) + int netfd; /* /proc/net/raw path */ { char buf[MAXPATHLEN], *ep, **fp; int fl = 1; @@ -998,7 +992,7 @@ get_pack(p) * Open the /proc/net/packet file, assign a page size buffer to its stream, * and read the file. Store packet info in the Packin[] hash buckets. */ - if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(xs = open_proc_streamat(netfd, "packet", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, xs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 9) @@ -1015,7 +1009,7 @@ get_pack(p) if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: unsupported format: %s\n", - Pn, p); + Pn, PROCFS "/net/packet"); } break; } @@ -1073,8 +1067,8 @@ get_pack(p) */ static void -get_raw(p) - char *p; /* /proc/net/raw path */ +get_raw(netfd) + char netfd; /* /proc/net/raw path */ { char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp; int h; @@ -1114,7 +1108,7 @@ get_raw(p) * Open the /proc/net/raw file, assign a page size buffer to its stream, * and read the file. Store raw socket info in the Rawsin[] hash buckets. */ - if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(xs = open_proc_streamat(netfd, "raw", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, xs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf) @@ -1132,7 +1126,7 @@ get_raw(p) if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: unsupported format: %s\n", - Pn, p); + Pn, PROCFS "/net/raw"); } break; } @@ -1223,7 +1217,8 @@ get_raw(p) */ static void -get_sctp() +get_sctp(netfd) + int netfd; { char buf[MAXPATHLEN], *a, *ep, **fp, *id, *la, *lp, *ra, *rp, *ta; int d, err, fl, h, i, j, nf, ty, x; @@ -1271,7 +1266,7 @@ get_sctp() * and read them. Store SCTP socket info in the SCTPsin[] hash buckets. */ for (i = 0; i < NSCTPPATHS; i++ ) { - if (!(ss = open_proc_stream(SCTPPath[i], "r", &vbuf, &vsz, 0))) + if (!(ss = open_proc_streamat(netfd, SCTPSfx[i], "r", &vbuf, &vsz, 0))) continue; fl = 1; while (fgets(buf, sizeof(buf) - 1, ss)) { @@ -1312,8 +1307,8 @@ get_sctp() if (err) { if (!Fwarn) (void) fprintf(stderr, - "%s: WARNING: unsupported format: %s\n", - Pn, SCTPPath[i]); + "%s: WARNING: unsupported format: %s%s\n", + Pn, PROCFS "/net/", SCTPSfx[i]); break; } fl = 0; @@ -1594,8 +1589,8 @@ get_sctpaddrs(fp, i, nf, x) */ static void -get_tcpudp(p, pr, clr) - char *p; /* /proc/net/{tcp,udp} path */ +get_tcpudp(netfd, pr, clr) + int netfd; /* /proc/net */ int pr; /* protocol: 0 = TCP, 1 = UDP, * 2 = UDPLITE */ int clr; /* 1 == clear the table */ @@ -1631,7 +1626,7 @@ get_tcpudp(p, pr, clr) * count from its "sockets: used" line. */ TcpUdp_bucks = INOBUCKS; - if ((fs = fopen(SockStatPath, "r"))) { + if ((fs = fopenat(netfd, "sockstat", "r"))) { while(fgets(buf, sizeof(buf) - 1, fs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3) continue; @@ -1660,7 +1655,7 @@ get_tcpudp(p, pr, clr) * Open the /proc/net file, assign a page size buffer to the stream, and * read it. */ - if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(fs = open_proc_streamat(netfd, tcpudpprot[pr], "r", &vbuf, &vsz, 0))) return; nf = 12; while(fgets(buf, sizeof(buf) - 1, fs)) { @@ -1679,8 +1674,8 @@ get_tcpudp(p, pr, clr) { if (!Fwarn) { (void) fprintf(stderr, - "%s: WARNING: unsupported format: %s\n", - Pn, p); + "%s: WARNING: unsupported format: %s%s\n", + Pn, PROCFS "/net/", tcpudpprot[pr]); } break; } @@ -1766,8 +1761,8 @@ get_tcpudp(p, pr, clr) */ static void -get_raw6(p) - char *p; /* /proc/net/raw path */ +get_raw6(netfd) + int netfd; /* /proc/net */ { char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp; int h; @@ -1807,7 +1802,7 @@ get_raw6(p) * Open the /proc/net/raw6 file, assign a page size buffer to the stream, * and read it. Store raw6 socket info in the Rawsin6[] hash buckets. */ - if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(xs = open_proc_streamat(netfd, "raw6", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, xs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf) @@ -1825,7 +1820,7 @@ get_raw6(p) if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: unsupported format: %s\n", - Pn, p); + Pn, PROCFS "/net/raw6"); } break; } @@ -1916,8 +1911,8 @@ get_raw6(p) */ static void -get_tcpudp6(p, pr, clr) - char *p; /* /proc/net/{tcp,udp} path */ +get_tcpudp6(netfd, pr, clr) + int netfd; /* /proc/net */ int pr; /* protocol: 0 = TCP, 1 = UDP */ int clr; /* 1 == clear the table */ { @@ -1951,7 +1946,7 @@ get_tcpudp6(p, pr, clr) */ TcpUdp6_bucks = INOBUCKS; h = i = nf = 0; - if ((fs = fopen(SockStatPath6, "r"))) { + if ((fs = fopenat(netfd, "sockstat6", "r"))) { while(fgets(buf, sizeof(buf) - 1, fs)) { if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3) continue; @@ -1992,7 +1987,7 @@ get_tcpudp6(p, pr, clr) * Open the /proc/net file, assign a page size buffer to the stream, * and read it. */ - if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(fs = open_proc_streamat(netfd, tcpudpprot[pr], "r", &vbuf, &vsz, 0))) return; nf = 12; while(fgets(buf, sizeof(buf) - 1, fs)) { @@ -2011,8 +2006,8 @@ get_tcpudp6(p, pr, clr) { if (!Fwarn) { (void) fprintf(stderr, - "%s: WARNING: unsupported format: %s\n", - Pn, p); + "%s: WARNING: unsupported format: %s%s\n", + Pn, PROCFS "/net/", tcpudpprot[pr]); } break; } @@ -2094,8 +2089,8 @@ get_tcpudp6(p, pr, clr) */ static void -get_unix(p) - char *p; /* /proc/net/unix path */ +get_unix(netfd) + int netfd; /* /proc/net */ { char buf[MAXPATHLEN], *ep, **fp, *path, *pcb; int fl = 1; @@ -2133,7 +2128,7 @@ get_unix(p) * Open the /proc/net/unix file, assign a page size buffer to the stream, * read the file's contents, and add them to the Uxsin hash buckets. */ - if (!(us = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + if (!(us = open_proc_streamat(netfd, "unix", "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf) - 1, us)) { if ((nf = get_fields(buf, ":", &fp, (int *)NULL, 0)) < 7) @@ -2156,7 +2151,7 @@ get_unix(p) if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: unsupported format: %s\n", - Pn, p); + Pn, PROCFS "/net/unix"); } break; } @@ -2501,13 +2496,14 @@ print_tcptpi(nl) */ void -process_proc_sock(p, s, ss, l, lss) +process_proc_sock(p, s, ss, l, lss, ps) char *p; /* node's readlink() path */ struct stat *s; /* stat() result for path */ int ss; /* *s status -- i.e, SB_* values */ struct stat *l; /* lstat() result for FD (NULL for * others) */ int lss; /* *l status -- i.e, SB_* values */ + DIR *ps; /* /proc */ { struct ax25sin *ap; char *cp, *path, tbuf[64]; @@ -2522,6 +2518,7 @@ process_proc_sock(p, s, ss, l, lss) struct sctpsin *sp; struct tcp_udp *tp; struct uxsin *up; + int netfd; #if defined(HASIPv6) int af; @@ -2540,10 +2537,13 @@ process_proc_sock(p, s, ss, l, lss) /* * Check for socket's inode presence in the protocol info caches. */ - if (AX25path) { - (void) get_ax25(AX25path); - (void) free((FREE_P *)AX25path); - AX25path = (char *)NULL; + netfd = openat(dirfd(ps), "net", O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_CLOEXEC); + if (netfd < 0) + return; + + if (!got_ax25) { + (void) get_ax25(netfd); + got_ax25 = true; } if ((ss & SB_INO) && (ap = check_ax25((INODETYPE)s->st_ino)) @@ -2564,10 +2564,9 @@ process_proc_sock(p, s, ss, l, lss) print_ax25info(ap); return; } - if (Ipxpath) { - (void) get_ipx(Ipxpath); - (void) free((FREE_P *)Ipxpath); - Ipxpath = (char *)NULL; + if (!got_ipx) { + (void) get_ipx(netfd); + got_ipx = true; } if ((ss & SB_INO) && (ip = check_ipx((INODETYPE)s->st_ino)) @@ -2625,10 +2624,9 @@ process_proc_sock(p, s, ss, l, lss) enter_nm(Namech); return; } - if (Rawpath) { - (void) get_raw(Rawpath); - (void) free((FREE_P *)Rawpath); - Rawpath = (char *)NULL; + if (!got_raw) { + (void) get_raw(netfd); + got_raw = true; } if ((ss & SB_INO) && (rp = check_raw((INODETYPE)s->st_ino)) @@ -2690,10 +2688,9 @@ process_proc_sock(p, s, ss, l, lss) enter_nm(Namech); return; } - if (Nlkpath) { - (void) get_netlink(Nlkpath); - (void) free((FREE_P *) Nlkpath); - Nlkpath = (char *)NULL; + if (!got_netlink) { + (void) get_netlink(netfd); + got_netlink = true; } if ((ss & SB_INO) && (np = check_netlink((INODETYPE)s->st_ino)) @@ -2834,10 +2831,9 @@ process_proc_sock(p, s, ss, l, lss) enter_nm(Namech); return; } - if (Packpath) { - (void) get_pack(Packpath); - (void) free((FREE_P *)Packpath); - Packpath = (char *)NULL; + if (!got_pack) { + (void) get_pack(netfd); + got_pack = true; } if ((ss & SB_INO) && (pp = check_pack((INODETYPE)s->st_ino)) @@ -3214,10 +3210,9 @@ process_proc_sock(p, s, ss, l, lss) enter_nm(Namech); return; } - if (UNIXpath) { - (void) get_unix(UNIXpath); - (void) free((FREE_P *)UNIXpath); - UNIXpath = (char *)NULL; + if (!got_unix) { + (void) get_unix(netfd); + got_unix = true; } if ((ss & SB_INO) && (up = check_unix((INODETYPE)s->st_ino)) @@ -3305,12 +3300,11 @@ process_proc_sock(p, s, ss, l, lss) } #if defined(HASIPv6) - if (Raw6path) { - if (!Fxopt) - (void) get_raw6(Raw6path); - (void) free((FREE_P *)Raw6path); - Raw6path = (char *)NULL; - } + if (!got_raw6) + if (!Fxopt) { + (void) get_raw6(netfd); + got_raw6 = true; + } if (!Fxopt && (ss & SB_INO) && (rp = check_raw6((INODETYPE)s->st_ino)) ) { @@ -3370,23 +3364,20 @@ process_proc_sock(p, s, ss, l, lss) enter_nm(Namech); return; } - if (TCP6path) { + if (!got_tcp6) { if (!Fxopt) - (void) get_tcpudp6(TCP6path, 0, 1); - (void) free((FREE_P *)TCP6path); - TCP6path = (char *)NULL; + (void) get_tcpudp6(netfd, 0, 1); + got_tcp6 = true; } - if (UDP6path) { + if (!got_udp6) { if (!Fxopt) - (void) get_tcpudp6(UDP6path, 1, 0); - (void) free((FREE_P *)UDP6path); - UDP6path = (char *)NULL; + (void) get_tcpudp6(netfd, 1, 0); + got_udp6 = true; } - if (UDPLITE6path) { + if (!got_udplite6) { if (!Fxopt) - (void) get_tcpudp6(UDPLITE6path, 2, 0); - (void) free((FREE_P *)UDPLITE6path); - UDPLITE6path = (char *)NULL; + (void) get_tcpudp6(netfd, 2, 0); + got_udplite6 = true; } if (!Fxopt && (ss & SB_INO) && (tp6 = check_tcpudp6((INODETYPE)s->st_ino, &pr)) @@ -3469,23 +3460,20 @@ process_proc_sock(p, s, ss, l, lss) } #endif /* defined(HASIPv6) */ - if (TCPpath) { + if (!got_tcp) { if (!Fxopt) - (void) get_tcpudp(TCPpath, 0, 1); - (void) free((FREE_P *)TCPpath); - TCPpath = (char *)NULL; + (void) get_tcpudp(netfd, 0, 1); + got_tcp = true; } - if (UDPpath) { + if (!got_udp) { if (!Fxopt) - (void) get_tcpudp(UDPpath, 1, 0); - (void) free((FREE_P *)UDPpath); - UDPpath = (char *)NULL; + (void) get_tcpudp(netfd, 1, 0); + got_udp = true; } - if (UDPLITEpath) { + if (!got_udplite) { if (!Fxopt) - (void) get_tcpudp(UDPLITEpath, 2, 0); - (void) free((FREE_P *)UDPLITEpath); - UDPLITEpath = (char *)NULL; + (void) get_tcpudp(netfd, 2, 0); + got_udplite = true; } if (!Fxopt && (ss & SB_INO) && (tp = check_tcpudp((INODETYPE)s->st_ino, &pr)) @@ -3565,12 +3553,9 @@ process_proc_sock(p, s, ss, l, lss) return; } - if (SCTPPath[0]) { - (void) get_sctp(); - for (i = 0; i < NSCTPPATHS; i++) { - (void) free((FREE_P *)SCTPPath[i]); - SCTPPath[i] = (char *)NULL; - } + if (!got_sctp) { + (void) get_sctp(netfd); + got_sctp = true; } if ((ss & SB_INO) && (sp = check_sctp((INODETYPE)s->st_ino)) ) { @@ -3646,56 +3631,3 @@ process_proc_sock(p, s, ss, l, lss) enter_nm(Fxopt ? "can't identify protocol (-X specified)" : "can't identify protocol"); } - - -/* - * set_net_paths() - set /proc/net paths - */ - -void -set_net_paths(p, pl) - char *p; /* path to /proc/net/ */ - int pl; /* strlen(p) */ -{ - int i; - int pathl; - - pathl = 0; - (void) make_proc_path(p, pl, &AX25path, &pathl, "ax25"); - pathl = 0; - (void) make_proc_path(p, pl, &Ipxpath, &pathl, "ipx"); - pathl = 0; - (void) make_proc_path(p, pl, &Nlkpath, &pathl, "netlink"); - pathl = 0; - (void) make_proc_path(p, pl, &Packpath, &pathl, "packet"); - pathl = 0; - (void) make_proc_path(p, pl, &Rawpath, &pathl, "raw"); - for (i = 0; i < NSCTPPATHS; i++) { - pathl = 0; - (void) make_proc_path(p, pl, &SCTPPath[i], &pathl, SCTPSfx[i]); - } - pathl = 0; - (void) make_proc_path(p, pl, &SockStatPath, &pathl, "sockstat"); - pathl = 0; - (void) make_proc_path(p, pl, &TCPpath, &pathl, "tcp"); - pathl = 0; - (void) make_proc_path(p, pl, &UDPpath, &pathl, "udp"); - pathl = 0; - (void) make_proc_path(p, pl, &UDPLITEpath, &pathl, "udplite"); - -#if defined(HASIPv6) - pathl = 0; - (void) make_proc_path(p, pl, &Raw6path, &pathl, "raw6"); - pathl = 0; - (void) make_proc_path(p, pl, &SockStatPath6, &pathl, "sockstat6"); - pathl = 0; - (void) make_proc_path(p, pl, &TCP6path, &pathl, "tcp6"); - pathl = 0; - (void) make_proc_path(p, pl, &UDP6path, &pathl, "udp6"); - pathl = 0; - (void) make_proc_path(p, pl, &UDPLITE6path, &pathl, "udplite6"); -#endif /* defined(HASIPv6) */ - - pathl = 0; - (void) make_proc_path(p, pl, &UNIXpath, &pathl, "unix"); -} diff --git a/misc.c b/misc.c index 3c1c32b..848aa93 100644 --- a/misc.c +++ b/misc.c @@ -51,6 +51,11 @@ static char *rcsid = "$Id: misc.c,v 1.26 2008/10/21 16:21:41 abe Exp $"; #define MAXSYMLINKS 32 #endif /* !defined(MAXSYMLINKS) */ +typedef struct fstatat_params { + int dirfd; + char *path; + int flags; +} fstatat_params; /* * Local function prototypes @@ -59,8 +64,9 @@ static char *rcsid = "$Id: misc.c,v 1.26 2008/10/21 16:21:41 abe Exp $"; _PROTOTYPE(static void closePipes,(void)); _PROTOTYPE(static int dolstat,(char *path, char *buf, int len)); _PROTOTYPE(static int dostat,(char *path, char *buf, int len)); +_PROTOTYPE(static int dofstatat,(fstatat_params *params, char *buf, int len)); _PROTOTYPE(static int doreadlink,(char *path, char *buf, int len)); -_PROTOTYPE(static int doinchild,(int (*fn)(), char *fp, char *rbuf, int rbln)); +_PROTOTYPE(static int doinchild,(int (*fn)(), void *fp, char *rbuf, int rbln)); #if defined(HASINTSIGNAL) _PROTOTYPE(static int handleint,(int sig)); @@ -239,7 +245,7 @@ compdev(a1, a2) static int doinchild(fn, fp, rbuf, rbln) int (*fn)(); /* function to perform */ - char *fp; /* function parameter */ + void *fp; /* function parameter */ char *rbuf; /* response buffer */ int rbln; /* response buffer length */ { @@ -410,7 +416,6 @@ dolstat(path, rbuf, rbln) return(lstat(path, (struct stat *)rbuf)); } - /* * doreadlink() -- do a readlink() function */ @@ -441,6 +446,24 @@ dostat(path, rbuf, rbln) return(stat(path, (struct stat *)rbuf)); } +/* + * dofstatat() - do a stat() function relative to a dirfd + */ + +static int +dofstatat(params, rbuf, rbln) + fstatat_params *params; /* fstatat() parameters */ + char *rbuf; /* response buffer */ + int rbln; /* response buffer length */ + +/* ARGSUSED */ + +{ + int dirfd = params->dirfd; + char *path = params->path; + int flags = params->flags; + return(fstatat(dirfd, path, (struct stat *)rbuf, flags)); +} #if defined(WILLDROPGID) /* @@ -1013,7 +1036,27 @@ lstatsafely(path, buf) return(doinchild(dolstat, path, (char *)buf, sizeof(struct stat))); } +/* + * lstatsafelyat() - fstatat path safely (i. e., with timeout) + */ +int +lstatsafelyat(dirfd, path, buf) + int dirfd; /* DIR's fd */ + char *path; /* file path */ + struct stat *buf; /* stat buffer address */ +{ + struct fstatat_params params = {dirfd, path, AT_SYMLINK_NOFOLLOW}; + if (Fblock) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: avoiding stat(%s): -b was specified.\n", + Pn, path); + errno = EWOULDBLOCK; + return(1); + } + return(doinchild(dofstatat, ¶ms, (char *)buf, sizeof(struct stat))); +} /* * Readlink() - read and interpret file system symbolic links */ @@ -1545,6 +1588,27 @@ statsafely(path, buf) return(doinchild(dostat, path, (char *)buf, sizeof(struct stat))); } +/* + * statsafelyat() - fstatat path safely (i. e., with timeout) + */ + +int +statsafelyat(dirfd, path, buf) + int dirfd; /* DIR's fd */ + char *path; /* file path */ + struct stat *buf; /* stat buffer address */ +{ + struct fstatat_params params = {dirfd, path, 0}; + if (Fblock) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: avoiding stat(%s): -b was specified.\n", + Pn, path); + errno = EWOULDBLOCK; + return(1); + } + return(doinchild(dofstatat, ¶ms, (char *)buf, sizeof(struct stat))); +} /* * stkdir() - stack directory name -- 1.8.5.1