2 * dnode.c - Linux node functions for /proc-based lsof
7 * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
8 * 47907. All rights reserved.
10 * Written by Victor A. Abell
12 * This software is not subject to any license of the American Telephone
13 * and Telegraph Company or the Regents of the University of California.
15 * Permission is granted to anyone to use this software for any purpose on
16 * any computer system, and to alter it and redistribute it freely, subject
17 * to the following restrictions:
19 * 1. Neither the authors nor Purdue University are responsible for any
20 * consequences of the use of this software.
22 * 2. The origin of this software must not be misrepresented, either by
23 * explicit claim or by omission. Credit to the authors and Purdue
24 * University must appear in documentation and sources.
26 * 3. Altered versions must be plainly marked as such, and must not be
27 * misrepresented as being the original software.
29 * 4. This notice may not be removed or altered.
33 static char copyright[] =
34 "@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
35 static char *rcsid = "$Id: dnode.c,v 1.25 2015/07/07 19:46:33 abe Exp $";
46 #define OFFSET_MAX ((off_t)0x7fffffff) /* this is defined in
47 * .../src/fs/locks.c and not
49 #define PIDBUCKS 64 /* PID hash buckets */
50 #define PINFOBUCKS 512 /* pipe info hash buckets */
51 #define HASHPID(pid) (((int)((pid * 31415) >> 3)) & (PIDBUCKS - 1))
52 #define HASHPINFO(ino) (((int)((ino * 31415) >> 3)) & (PINFOBUCKS - 1))
56 * Local structure definitions
72 struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */
76 * Local function prototypes
79 _PROTOTYPE(static void check_lock,(void));
81 #if defined(HASEPTOPTS)
82 _PROTOTYPE(static void enter_pinfo,(void));
83 #endif /* defined(HASEPTOPTS) */
90 #if defined(HASEPTOPTS)
91 static pxinfo_t **Pinfo = (pxinfo_t **)NULL;
92 #endif /* defined(HASEPTOPTS) */
96 * check_lock() - check lock for file *Lf, process *Lp
105 h = HASHPID(Lp->pid);
106 for (lp = LckH[h]; lp; lp = lp->next) {
107 if (Lp->pid == lp->pid
108 && Lf->dev == lp->dev
109 && Lf->inode == lp->inode)
118 #if defined(HASEPTOPTS)
120 * clear_pinfo() -- clear allocated pipe info
126 int h; /* hash index */
127 pxinfo_t *pi, *pp; /* temporary pointers */
131 for (h = 0; h < PINFOBUCKS; h++) {
132 if ((pi = Pinfo[h])) {
135 (void) free((FREE_P *)pi);
138 Pinfo[h] = (pxinfo_t *)NULL;
145 * enter_pinfo() -- enter pipe info
147 * entry Lf = local file structure pointer
148 * Lp = local process structure pointer
154 int h; /* hash result */
155 struct lfile *lf; /* local file structure pointer */
156 struct lproc *lp; /* local proc structure pointer */
157 pxinfo_t *np, *pi, *pe; /* pipe info pointers */
161 * Allocate pipe info hash buckets.
163 if (!(Pinfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *))))
165 (void) fprintf(stderr,
166 "%s: no space for %d pipe info buckets\n", Pn, PINFOBUCKS);
171 * Make sure this is a unique entry.
173 for (h = HASHPINFO(Lf->inode), pi = Pinfo[h], pe = (pxinfo_t *)NULL;
175 pe = pi, pi = pi->next
178 lp = &Lproc[pi->lpx];
179 if (pi->ino == Lf->inode) {
180 if ((lp->pid == Lp->pid) && !strcmp(lf->fd, Lf->fd))
185 * Allocate, fill and link a new pipe info structure to the end of
186 * the pipe inode hash chain.
188 if (!(np = (pxinfo_t *)malloc(sizeof(pxinfo_t)))) {
189 (void) fprintf(stderr,
190 "%s: no space for pipeinfo, PID %d, FD %s\n",
191 Pn, Lp->pid, Lf->fd);
196 np->lpx = Lp - Lproc;
197 np->next = (pxinfo_t *)NULL;
206 * find_pendinfo() -- find pipe end info
210 find_pendinfo(lf, pp)
211 struct lfile *lf; /* pipe's lfile */
212 pxinfo_t *pp; /* previous pipe info (NULL == none) */
214 struct lfile *ef; /* pipe end local file structure */
215 int h; /* hash result */
216 pxinfo_t *pi; /* pipe info pointer */
222 h = HASHPINFO(lf->inode);
226 if (pi->ino == lf->inode) {
228 if (strcmp(lf->fd, ef->fd))
234 return((pxinfo_t *)NULL);
237 #endif /* defined(HASEPTOPTS) */
242 * get_fields() - separate a line into fields
246 get_fields(ln, sep, fr, eb, en)
247 char *ln; /* input line */
248 char *sep; /* separator list */
249 char ***fr; /* field pointer return address */
250 int *eb; /* indexes of fields where blank or an
251 * entry from the separator list may be
252 * embedded and are not separators
254 int en; /* number of entries in eb[] (may be
260 static char **fp = (char **)NULL;
263 for (cp = ln, n = 0; cp && *cp;) {
264 for (bp = cp; *bp && (*bp == ' ' || *bp == '\t'); bp++);
266 if (!*bp || *bp == '\n')
268 for (cp = bp; *cp; cp++) {
273 if (*cp == '\t') /* TAB is always a separator */
278 * See if this field may have an embedded space.
283 for (i = j = 0; i < en; i++) {
296 * See if the character is in the separator list.
298 for (sp = sep; *sp; sp++) {
305 * See if this field may have an embedded separator.
310 for (i = j = 0; i < en; i++) {
326 len = (MALLOC_S)(nfpa * sizeof(char *));
328 fp = (char **)realloc((MALLOC_P *)fp, len);
330 fp = (char **)malloc(len);
332 (void) fprintf(stderr,
333 "%s: can't allocate %d bytes for field pointers.\n",
346 * get_locks() - get lock information from /proc/locks
351 char *p; /* /proc lock path */
353 unsigned long bp, ep;
354 char buf[MAXPATHLEN], *ec, **fp;
356 int ex, i, h, mode, pid;
358 struct llock *lp, *np;
362 static char *vbuf = (char *)NULL;
363 static size_t vsz = (size_t)0;
365 * Destroy previous lock information.
368 for (i = 0; i < PIDBUCKS; i++) {
369 for (lp = LckH[i]; lp; lp = np) {
371 (void) free((FREE_P *)lp);
373 LckH[i] = (struct llock *)NULL;
378 * If first time, allocate the lock PID hash buckets.
380 LckH = (struct llock **)calloc((MALLOC_S)PIDBUCKS,
381 sizeof(struct llock *));
383 (void) fprintf(stderr,
384 "%s: can't allocate %d lock hash bytes\n",
385 Pn, (int)(sizeof(struct llock *) * PIDBUCKS));
390 * Open the /proc lock file, assign a page size buffer to its stream,
393 if (!(ls = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
395 while (fgets(buf, sizeof(buf), ls)) {
396 if (get_fields(buf, ":", &fp, (int *)NULL, 0) < 10)
398 if (!fp[1] || strcmp(fp[1], "->") == 0)
407 else if (*fp[3] == 'W')
414 if (!fp[4] || !*fp[4])
421 if (!fp[5] || !*fp[5]
422 || (maj = strtol(fp[5], &ec, 16)) == LONG_MIN || maj == LONG_MAX
426 if (!fp[6] || !*fp[6]
427 || (min = strtol(fp[6], &ec, 16)) == LONG_MIN || min == LONG_MAX
430 dev = (dev_t)makedev((int)maj, (int)min);
435 if (!fp[7] || !*fp[7]
436 || (inode = strtoull(fp[7], &ec, 0)) == ULONG_MAX
440 * Get lock extent. Convert it and the lock type to a lock character.
442 if (!fp[8] || !*fp[8] || !fp[9] || !*fp[9])
445 if ((bp = strtoul(fp[8], &ec, 0)) == ULONG_MAX || !ec || *ec)
447 if (!strcmp(fp[9], "EOF")) /* for Linux 2.4.x */
451 if ((ep = strtoul(fp[9], &ec, 0)) == ULONG_MAX || !ec || *ec)
454 ex = ((off_t)bp == (off_t)0 && (off_t)ep == OFFSET_MAX) ? 1 : 0;
456 type = ex ? 'W' : 'w';
458 type = ex ? 'R' : 'r';
460 * Look for this lock via the hash buckets.
463 for (lp = LckH[h]; lp; lp = lp->next) {
466 && lp->inode == inode
473 * Allocate a new llock structure and link it to the PID hash bucket.
475 if (!(lp = (struct llock *)malloc(sizeof(struct llock)))) {
476 (void) snpf(buf, sizeof(buf), InodeFmt_d, inode);
477 (void) fprintf(stderr,
478 "%s: can't allocate llock: PID %d; dev %x; inode %s\n",
479 Pn, pid, (int)dev, buf);
494 * process_proc_node() - process file node
498 process_proc_node(p, pbr, s, ss, l, ls)
499 char *p; /* node's readlink() path */
500 char *pbr; /* node's path before readlink() */
501 struct stat *s; /* stat() result for path */
502 int ss; /* *s status -- i.e., SB_* values */
503 struct stat *l; /* lstat() result for FD (NULL for
505 int ls; /* *l status -- i.e., SB_* values */
510 struct mounts *mp = (struct mounts *)NULL;
514 * Set the access mode, if possible.
516 if (l && (ls & SB_MODE) && ((l->st_mode & S_IFMT) == S_IFLNK)) {
517 if ((access = l->st_mode & (S_IRUSR | S_IWUSR)) == S_IRUSR)
519 else if (access == S_IWUSR)
525 * Determine node type.
528 type = s->st_mode & S_IFMT;
531 Lf->ntype = Ntype = N_BLK;
534 Lf->ntype = Ntype = N_CHR;
537 Lf->ntype = Ntype = N_FIFO;
540 /* Lf->ntype = Ntype = N_REGLR; by alloc_lfile() */
541 process_proc_sock(p, pbr, s, ss, l, ls);
544 if (!strcmp(p, "anon_inode"))
545 Lf->ntype = Ntype = N_ANON_INODE;
552 * Save the device. If it is an NFS device, change the node type to N_NFS.
558 if ((Ntype == N_CHR || Ntype == N_BLK)) {
560 Lf->rdev = s->st_rdev;
564 if (Ntype == N_REGLR && (HasNFS == 2)) {
565 for (mp = readmnt(); mp; mp = mp->next) {
566 if ((mp->ty == N_NFS)
567 && (mp->ds & SB_DEV) && Lf->dev_def && (Lf->dev == mp->dev)
568 && (mp->dir && mp->dirl
569 && !strncmp(mp->dir, p, mp->dirl))
571 Lf->ntype = Ntype = N_NFS;
577 * Save the inode number.
580 Lf->inode = (INODETYPE)s->st_ino;
583 #if defined(HASEPTOPTS)
584 if ((Lf->ntype == N_FIFO) && FeptE) {
585 (void) enter_pinfo();
588 #endif /* defined(HASEPTOPTS) */
594 if (Lf->dev_def && (Lf->inp_ty == 1))
597 * Save the file size.
603 if (!Fsize && l && (ls & SB_SIZE) && OffType) {
604 Lf->off = (SZOFFTYPE)l->st_size;
610 if (l && (ls & SB_SIZE) && OffType) {
611 Lf->off = (SZOFFTYPE)l->st_size;
614 } else if (!Foffset || Fsize) {
616 Lf->sz = (SZOFFTYPE)s->st_size;
622 * Record the link count.
624 if (Fnlink && (ss & SB_NLINK)) {
625 Lf->nlink = (long)s->st_nlink;
627 if (Nlink && (Lf->nlink < Nlink))
631 * Format the type name.
657 if (Ntype == N_ANON_INODE)
660 (void) snpf(Lf->type, sizeof(Lf->type), "%04o",
661 ((type >> 12) & 0xf));
668 (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn);
670 * Record an NFS file selection.
672 if (Ntype == N_NFS && Fnfs)
675 * Test for specified file.
678 && is_file_named(1, p, mp,
679 ((type == S_IFCHR) || (type == S_IFBLK)) ? 1 : 0))
682 * If no NAME information has been stored, store the path.
684 * Store the remote host and mount point for an NFS file.
687 (void) snpf(Namech, Namechl, "%s", p);
688 if ((Ntype == N_NFS) && mp && mp->fsname) {
690 (void) snpf(cp, sz, " (%s)", mp->fsname);