/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.96.1
dialects/linux/dnode.c
980 строк
20 KB
Masatake YAMATO
[linux] delete unused file static variables "copyright"
29 апр 2022, 12:59
29 апр 2022, 12:59
f033e7e
Код
Авторство
О чём код?
/* * dnode.c - Linux node functions for /proc-based lsof */ /* * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #include "lsof.h" #if defined(HASEPTOPTS) && defined(HASPTYEPT) #include <linux/major.h> #endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ /* * Local definitions */ #define OFFSET_MAX ((off_t)0x7fffffff) /* this is defined in * .../src/fs/locks.c and not * in a header file */ #define PIDBUCKS 64 /* PID hash buckets */ #define PINFOBUCKS 512 /* pipe info hash buckets */ #define HASHPID(pid) (((int)((pid * 31415) >> 3)) & (PIDBUCKS - 1)) #define HASHPINFO(ino) (((int)((ino * 31415) >> 3)) & (PINFOBUCKS - 1)) /* * Local structure definitions */ struct llock { int pid; dev_t dev; INODETYPE inode; char type; struct llock *next; }; /* * Local definitions */ struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */ /* * Local function prototypes */ _PROTOTYPE(static void check_lock,(void)); #if defined(HASEPTOPTS) _PROTOTYPE(static void enter_pinfo,(void)); #endif /* defined(HASEPTOPTS) */ /* * Local storage */ #if defined(HASEPTOPTS) static pxinfo_t **Pinfo = (pxinfo_t **)NULL; /* pipe endpoint hash buckets */ # if defined(HASPTYEPT) static pxinfo_t **PtyInfo = (pxinfo_t **)NULL; /* pseudoterminal endpoint hash * buckets */ # endif /* defined(HASPTYEPT) */ static pxinfo_t **PSXMQinfo = (pxinfo_t **)NULL;/* posix msg queue endpoint hash buckets */ static pxinfo_t **EvtFDinfo = (pxinfo_t **)NULL;/* envetfd endpoint hash buckets */ #endif /* defined(HASEPTOPTS) */ /* * check_lock() - check lock for file *Lf, process *Lp */ static void check_lock() { int h; struct llock *lp; h = HASHPID(Lp->pid); for (lp = LckH[h]; lp; lp = lp->next) { if (Lp->pid == lp->pid && Lf->dev == lp->dev && Lf->inode == lp->inode) { Lf->lock = lp->type; return; } } } #if defined(HASEPTOPTS) static void endpoint_pxinfo_hash(pxinfo_t **pinfo_hash, const size_t nbuckets, void (* free_elt) (void *)) { int h; /* hash index */ pxinfo_t *pi, *pp; /* temporary pointers */ if (!pinfo_hash) return; for (h = 0; h < nbuckets; h++) { if ((pi = pinfo_hash[h])) { do { pp = pi->next; (void) (* free_elt) ((FREE_P *)pi); pi = pp; } while (pi); pinfo_hash[h] = (pxinfo_t *)NULL; } } } static void endpoint_enter(pxinfo_t **pinfo_hash, const char *table_name, int id) { int h; struct lfile *lf; /* local file structure pointer */ struct lproc *lp; /* local proc structure pointer */ pxinfo_t *np, *pi, *pe; /* inode hash pointers */ /* * Make sure this is a unique entry. */ for (h = HASHPINFO(id), pi = pinfo_hash[h], pe = (pxinfo_t *)NULL; pi; pe = pi, pi = pi->next ) { lf = pi->lf; lp = &Lproc[pi->lpx]; if (pi->ino == id) { if ((lp->pid == Lp->pid) && !strcmp(lf->fd, Lf->fd)) return; } } /* * Allocate, fill and link a new pipe info structure used for pty * to the end of the pty device hash chain. */ if (!(np = (pxinfo_t *)malloc(sizeof(pxinfo_t)))) { (void) fprintf(stderr, "%s: no space for pipeinfo for %s, PID %d, FD %s\n", table_name, Pn, Lp->pid, Lf->fd); Error(); } np->ino = id; np->lf = Lf; np->lpx = Lp - Lproc; np->next = (pxinfo_t *)NULL; if (pe) pe->next = np; else pinfo_hash[h] = np; } static pxinfo_t * endpoint_find(pxinfo_t **pinfo_hash, int (* is_acceptable) (pxinfo_t *, int, struct lfile *), int pid, struct lfile *lf, int id, pxinfo_t *pp) { int h; /* hash result */ pxinfo_t *pi; /* pipe info pointer */ if (pinfo_hash) { if (pp) pi = pp; else { h = HASHPINFO(id); pi = pinfo_hash[h]; } while (pi) { if (pi->ino == id && is_acceptable(pi, pid, lf)) return (pi); pi = pi->next; } } return ((pxinfo_t *)NULL); } /* * endpoint_accept_other_than_self() -- a helper function return true if * fd associated with pi is not the same as fd associated with lf. */ static int endpoint_accept_other_than_self(pxinfo_t *pi, int pid, struct lfile *lf) { struct lfile *ef = pi->lf; struct lproc *ep = &Lproc[pi->lpx]; return (strcmp(lf->fd, ef->fd)) || (pid != ep->pid); } /* * clear_pinfo() -- clear allocated pipe info */ void clear_pinfo() { endpoint_pxinfo_hash(Pinfo, PINFOBUCKS, free); } /* * enter_pinfo() -- enter pipe info * * entry Lf = local file structure pointer * Lp = local process structure pointer */ static void enter_pinfo() { if (!Pinfo) { /* * Allocate pipe info hash buckets. */ if (!(Pinfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) { (void) fprintf(stderr, "%s: no space for %d pipe info buckets\n", Pn, PINFOBUCKS); Error(); } } endpoint_enter(Pinfo, "pipeinfo", Lf->inode); } /* * find_pepti() -- find pipe end point info */ pxinfo_t * find_pepti(pid, lf, pp) int pid; /* pid of the process owning lf */ struct lfile *lf; /* pipe's lfile */ pxinfo_t *pp; /* previous pipe info (NULL == none) */ { return endpoint_find(Pinfo, endpoint_accept_other_than_self, pid, lf, lf->inode, pp); } #if defined(HASPTYEPT) /* * clear_ptyinfo() -- clear allocated pseudoterminal info */ void clear_ptyinfo() { endpoint_pxinfo_hash(PtyInfo, PINFOBUCKS, free); } /* * enter_ptmxi() -- enter pty info * * entry Lf = local file structure pointer * Lp = local process structure pointer */ void enter_ptmxi(mn) int mn; /* minor number of device */ { /* * Allocate pipe info hash buckets (but used for pty). */ if (!PtyInfo) { if (!(PtyInfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) { (void) fprintf(stderr, "%s: no space for %d pty info buckets\n", Pn, PINFOBUCKS); Error(); } } endpoint_enter(PtyInfo, "pty", mn); } /* * ptyepti_accept_ptmx() -- a helper function return whether lfile is pty ptmx or not */ static int ptyepti_accept_ptmx(pxinfo_t *pi, int pid, struct lfile *lf) { struct lfile *ef = pi->lf; return is_pty_ptmx(ef->rdev); } /* * ptyepti_accept_slave() -- a helper function returns whether lfile is pty slave or not */ static int ptyepti_accept_slave(pxinfo_t *pi, int pid, struct lfile *lf) { struct lfile *ef = pi->lf; return is_pty_slave(GET_MAJ_DEV(ef->rdev)); } /* * find_ptyepti() -- find pseudoterminal end point info */ pxinfo_t * find_ptyepti(pid, lf, m, pp) int pid; struct lfile *lf; /* pseudoterminal's lfile */ int m; /* minor number type: * 0 == use tty_index * 1 == use minor device */ pxinfo_t *pp; /* previous pseudoterminal info * (NULL == none) */ { return endpoint_find(PtyInfo, m ? ptyepti_accept_ptmx : ptyepti_accept_slave, pid, lf, m ? GET_MIN_DEV(lf->rdev) : lf->tty_index, pp); } /* * is_pty_slave() -- is a pseudoterminal a slave device */ int is_pty_slave(sm) int sm; /* slave major device number */ { /* linux/Documentation/admin-guide/devices.txt ------------------------------------------- 136-143 char Unix98 PTY slaves 0 = /dev/pts/0 First Unix98 pseudo-TTY 1 = /dev/pts/1 Second Unix98 pseudo-TTY ... These device nodes are automatically generated with the proper permissions and modes by mounting the devpts filesystem onto /dev/pts with the appropriate mount options (distribution dependent, however, on *most* distributions the appropriate options are "mode=0620,gid=<gid of the "tty" group>".) */ if ((UNIX98_PTY_SLAVE_MAJOR <= sm) && (sm < (UNIX98_PTY_SLAVE_MAJOR + UNIX98_PTY_MAJOR_COUNT)) ) { return 1; } return 0; } /* * is_pty_ptmx() -- is a pseudoterminal a master clone device */ int is_pty_ptmx(dev) dev_t dev; /* device number */ { if ((GET_MAJ_DEV(dev) == TTYAUX_MAJOR) && (GET_MIN_DEV(dev) == 2)) return 1; return 0; } #endif /* defined(HASPTYEPT) */ /* * clear_psxmqinfo -- clear allocate posix mq info */ void clear_psxmqinfo() { endpoint_pxinfo_hash(PSXMQinfo, PINFOBUCKS, free); } /* * enter_psxmqinfo() -- enter posix mq info * * entry Lf = local file structure pointer * Lp = local process structure pointer */ void enter_psxmqinfo() { if (!PSXMQinfo) { /* * Allocate posix mq info hash buckets. */ if (!(PSXMQinfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) { (void) fprintf(stderr, "%s: no space for %d posix mq info buckets\n", Pn, PINFOBUCKS); Error(); } } endpoint_enter(PSXMQinfo, "psxmqinfo", Lf->inode); } /* * find_psxmqinfo() -- find posix mq end point info */ pxinfo_t * find_psxmqinfo(pid, lf, pp) int pid; /* pid of the process owning lf */ struct lfile *lf; /* posix mq's lfile */ pxinfo_t *pp; /* previous posix mq info (NULL == none) */ { return endpoint_find(PSXMQinfo, endpoint_accept_other_than_self, pid, lf, lf->inode, pp); } /* * clear_evtfdinfo -- clear allocate eventfd info */ void clear_evtfdinfo() { endpoint_pxinfo_hash(EvtFDinfo, PINFOBUCKS, free); } /* * enter_evtfdinfo() -- enter eventfd info * * entry Lf = local file structure pointer * Lp = local process structure pointer */ void enter_evtfdinfo(int id) { if (!EvtFDinfo) { /* * Allocate eventfd info hash buckets. */ if (!(EvtFDinfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) { (void) fprintf(stderr, "%s: no space for %d envet fd info buckets\n", Pn, PINFOBUCKS); Error(); } } endpoint_enter(EvtFDinfo, "evtfdinfo", id); } /* * find_evtfdinfo() -- find eventfd end point info */ pxinfo_t * find_evtfdinfo(pid, lf, pp) int pid; /* pid of the process owning lf */ struct lfile *lf; /* eventfd's lfile */ pxinfo_t *pp; /* previous eventfd info (NULL == none) */ { void *r = endpoint_find(EvtFDinfo, endpoint_accept_other_than_self, pid, lf, lf->eventfd_id, pp); return r; } #endif /* defined(HASEPTOPTS) */ /* * get_fields() - separate a line into fields */ int get_fields(ln, sep, fr, eb, en) char *ln; /* input line */ char *sep; /* separator list */ char ***fr; /* field pointer return address */ int *eb; /* indexes of fields where blank or an * entry from the separator list may be * embedded and are not separators * (may be NULL) */ int en; /* number of entries in eb[] (may be * zero) */ { char *bp, *cp, *sp; int i, j, n; MALLOC_S len; static char **fp = (char **)NULL; static int nfpa = 0; for (cp = ln, n = 0; cp && *cp;) { for (bp = cp; *bp && (*bp == ' ' || *bp == '\t'); bp++); ; if (!*bp || *bp == '\n') break; for (cp = bp; *cp; cp++) { if (*cp == '\n') { *cp = '\0'; break; } if (*cp == '\t') /* TAB is always a separator */ break; if (*cp == ' ') { /* * See if this field may have an embedded space. */ if (!eb || !en) break; else { for (i = j = 0; i < en; i++) { if (eb[i] == n) { j = 1; break; } } if (!j) break; } } if (sep) { /* * See if the character is in the separator list. */ for (sp = sep; *sp; sp++) { if (*sp == *cp) break; } if (*sp) { /* * See if this field may have an embedded separator. */ if (!eb || !en) break; else { for (i = j = 0; i < en; i++) { if (eb[i] == n) { j = 1; break; } } if (!j) break; } } } } if (*cp) *cp++ = '\0'; if (n >= nfpa) { nfpa += 32; len = (MALLOC_S)(nfpa * sizeof(char *)); if (fp) fp = (char **)realloc((MALLOC_P *)fp, len); else fp = (char **)malloc(len); if (!fp) { (void) fprintf(stderr, "%s: can't allocate %d bytes for field pointers.\n", Pn, (int)len); Error(); } } fp[n++] = bp; } *fr = fp; return(n); } /* * get_locks() - get lock information from /proc/locks */ void get_locks(p) char *p; /* /proc lock path */ { unsigned long bp, ep; char buf[MAXPATHLEN], *ec, **fp; dev_t dev; int ex, i, h, mode, pid; INODETYPE inode; struct llock *lp, *np; FILE *ls; long maj, min; char type; static char *vbuf = (char *)NULL; static size_t vsz = (size_t)0; /* * Destroy previous lock information. */ if (LckH) { for (i = 0; i < PIDBUCKS; i++) { for (lp = LckH[i]; lp; lp = np) { np = lp->next; (void) free((FREE_P *)lp); } LckH[i] = (struct llock *)NULL; } } else { /* * If first time, allocate the lock PID hash buckets. */ LckH = (struct llock **)calloc((MALLOC_S)PIDBUCKS, sizeof(struct llock *)); if (!LckH) { (void) fprintf(stderr, "%s: can't allocate %d lock hash bytes\n", Pn, (int)(sizeof(struct llock *) * PIDBUCKS)); Error(); } } /* * Open the /proc lock file, assign a page size buffer to its stream, * and read it. */ if (!(ls = open_proc_stream(p, "r", &vbuf, &vsz, 0))) return; while (fgets(buf, sizeof(buf), ls)) { if (get_fields(buf, ":", &fp, (int *)NULL, 0) < 10) continue; if (!fp[1] || strcmp(fp[1], "->") == 0) continue; /* * Get lock type. */ if (!fp[3]) continue; if (*fp[3] == 'R') mode = 0; else if (*fp[3] == 'W') mode = 1; else continue; /* * Get PID. */ if (!fp[4] || !*fp[4]) continue; pid = atoi(fp[4]); /* * Get device number. */ ec = (char *)NULL; if (!fp[5] || !*fp[5] || (maj = strtol(fp[5], &ec, 16)) == LONG_MIN || maj == LONG_MAX || !ec || *ec) continue; ec = (char *)NULL; if (!fp[6] || !*fp[6] || (min = strtol(fp[6], &ec, 16)) == LONG_MIN || min == LONG_MAX || !ec || *ec) continue; dev = (dev_t)makedev((int)maj, (int)min); /* * Get inode number. */ ec = (char *)NULL; if (!fp[7] || !*fp[7] || (inode = strtoull(fp[7], &ec, 0)) == ULONG_MAX || !ec || *ec) continue; /* * Get lock extent. Convert it and the lock type to a lock character. */ if (!fp[8] || !*fp[8] || !fp[9] || !*fp[9]) continue; ec = (char *)NULL; if ((bp = strtoul(fp[8], &ec, 0)) == ULONG_MAX || !ec || *ec) continue; if (!strcmp(fp[9], "EOF")) /* for Linux 2.4.x */ ep = OFFSET_MAX; else { ec = (char *)NULL; if ((ep = strtoul(fp[9], &ec, 0)) == ULONG_MAX || !ec || *ec) continue; } ex = ((off_t)bp == (off_t)0 && (off_t)ep == OFFSET_MAX) ? 1 : 0; if (mode) type = ex ? 'W' : 'w'; else type = ex ? 'R' : 'r'; /* * Look for this lock via the hash buckets. */ h = HASHPID(pid); for (lp = LckH[h]; lp; lp = lp->next) { if (lp->pid == pid && lp->dev == dev && lp->inode == inode && lp->type == type) break; } if (lp) continue; /* * Allocate a new llock structure and link it to the PID hash bucket. */ if (!(lp = (struct llock *)malloc(sizeof(struct llock)))) { (void) snpf(buf, sizeof(buf), InodeFmt_d, inode); (void) fprintf(stderr, "%s: can't allocate llock: PID %d; dev %x; inode %s\n", Pn, pid, (int)dev, buf); Error(); } lp->pid = pid; lp->dev = dev; lp->inode = inode; lp->type = type; lp->next = LckH[h]; LckH[h] = lp; } (void) fclose(ls); } /* * process_proc_node() - process file node */ void process_proc_node(p, pbr, s, ss, l, ls) char *p; /* node's readlink() path */ char *pbr; /* node's path before readlink() */ 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 */ { mode_t access; mode_t type = 0; char *cp; struct mounts *mp = (struct mounts *)NULL; size_t sz; char *tn; /* * Set the access mode, if possible. */ if (l && (ls & SB_MODE) && ((l->st_mode & S_IFMT) == S_IFLNK)) { if ((access = l->st_mode & (S_IRUSR | S_IWUSR)) == S_IRUSR) Lf->access = 'r'; else if (access == S_IWUSR) Lf->access = 'w'; else Lf->access = 'u'; } /* * Determine node type. */ if (ss & SB_MODE) { type = s->st_mode & S_IFMT; switch (type) { case S_IFBLK: Lf->ntype = Ntype = N_BLK; break; case S_IFCHR: Lf->ntype = Ntype = N_CHR; break; case S_IFIFO: Lf->ntype = Ntype = N_FIFO; break; case S_IFSOCK: /* Lf->ntype = Ntype = N_REGLR; by alloc_lfile() */ process_proc_sock(p, pbr, s, ss, l, ls); return; case 0: if (!strcmp(p, "anon_inode")) Lf->ntype = Ntype = N_ANON_INODE; break; } } if (Selinet) return; /* * Save the device. If it is an NFS device, change the node type to N_NFS. */ if (ss & SB_DEV) { Lf->dev = s->st_dev; Lf->dev_def = 1; } if ((Ntype == N_CHR || Ntype == N_BLK)) { if (ss & SB_RDEV) { Lf->rdev = s->st_rdev; Lf->rdev_def = 1; #if defined(HASEPTOPTS) && defined(HASPTYEPT) if (FeptE && (Ntype == N_CHR) && is_pty_slave(GET_MAJ_DEV(Lf->rdev)) ) { enter_ptmxi(GET_MIN_DEV(Lf->rdev)); Lf->sf |= SELPTYINFO; } #endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ } } if (Ntype == N_REGLR && (HasNFS == 2)) { for (mp = readmnt(); mp; mp = mp->next) { if ((mp->ty == N_NFS) && (mp->ds & SB_DEV) && Lf->dev_def && (Lf->dev == mp->dev) && (mp->dir && mp->dirl && !strncmp(mp->dir, p, mp->dirl)) ) { Lf->ntype = Ntype = N_NFS; break; } } } /* * Save the inode number. */ if (ss & SB_INO) { Lf->inode = (INODETYPE)s->st_ino; Lf->inp_ty = 1; #if defined(HASEPTOPTS) if ((Lf->ntype == N_FIFO) && FeptE) { (void) enter_pinfo(); Lf->sf |= SELPINFO; } else if ((Lf->dev == MqueueDev) && FeptE) { (void) enter_psxmqinfo(); Lf->sf |= SELPSXMQINFO; } #endif /* defined(HASEPTOPTS) */ } /* * Check for a lock. */ if (Lf->dev_def && (Lf->inp_ty == 1)) (void) check_lock(); /* * Save the file size. */ switch (Ntype) { case N_BLK: case N_CHR: case N_FIFO: if (!Fsize && l && (ls & SB_SIZE) && OffType) { Lf->off = (SZOFFTYPE)l->st_size; Lf->off_def = 1; } break; default: if (Foffset) { if (l && (ls & SB_SIZE) && OffType) { Lf->off = (SZOFFTYPE)l->st_size; Lf->off_def = 1; } } else if (!Foffset || Fsize) { if (ss & SB_SIZE) { Lf->sz = (SZOFFTYPE)s->st_size; Lf->sz_def = 1; } } } /* * Record the link count. */ if (Fnlink && (ss & SB_NLINK)) { Lf->nlink = (long)s->st_nlink; Lf->nlink_def = 1; if (Nlink && (Lf->nlink < Nlink)) Lf->sf |= SELNLINK; } /* * Format the type name. */ if (ss & SB_MODE) { switch (type) { case S_IFBLK: tn = "BLK"; break; case S_IFCHR: tn = "CHR"; break; case S_IFDIR: tn = "DIR"; break; case S_IFIFO: tn = "FIFO"; break; case S_IFREG: if (Lf->dev == MqueueDev) tn = "PSXMQ"; else tn = "REG"; break; case S_IFLNK: tn = "LINK"; break; case S_ISVTX: tn = "VTXT"; break; default: if (Ntype == N_ANON_INODE) tn = "a_inode"; else { (void) snpf(Lf->type, sizeof(Lf->type), "%04o", ((type >> 12) & 0xf)); tn = (char *)NULL; } } } else tn = "unknown"; if (tn) (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn); /* * Record an NFS file selection. */ if (Ntype == N_NFS && Fnfs) Lf->sf |= SELNFS; /* * Test for specified file. */ if (Sfile && is_file_named(1, p, mp, ((type == S_IFCHR) || (type == S_IFBLK)) ? 1 : 0)) Lf->sf |= SELNM; /* * If no NAME information has been stored, store the path. * * Store the remote host and mount point for an NFS file. */ if (!Namech[0]) { (void) snpf(Namech, Namechl, "%s", p); if ((Ntype == N_NFS) && mp && mp->fsname) { cp = endnm(&sz); (void) snpf(cp, sz, " (%s)", mp->fsname); } } if (Namech[0]) enter_nm(Namech); }