Imported Upstream version 4.89
[platform/upstream/lsof.git] / dialects / linux / dnode.c
1 /*
2  * dnode.c - Linux node functions for /proc-based lsof
3  */
4
5
6 /*
7  * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
8  * 47907.  All rights reserved.
9  *
10  * Written by Victor A. Abell
11  *
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.
14  *
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:
18  *
19  * 1. Neither the authors nor Purdue University are responsible for any
20  *    consequences of the use of this software.
21  *
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.
25  *
26  * 3. Altered versions must be plainly marked as such, and must not be
27  *    misrepresented as being the original software.
28  *
29  * 4. This notice may not be removed or altered.
30  */
31
32 #ifndef lint
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 $";
36 #endif
37
38
39 #include "lsof.h"
40
41
42 /*
43  * Local definitions
44  */
45
46 #define OFFSET_MAX      ((off_t)0x7fffffff)     /* this is defined in
47                                                  * .../src/fs/locks.c and not
48                                                  * in a header file */
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))
53
54
55 /*
56  * Local structure definitions
57  */
58
59 struct llock {
60         int pid;
61         dev_t dev;
62         INODETYPE inode;
63         char type;
64         struct llock *next;
65 };
66
67
68 /*
69  * Local definitions
70  */
71
72 struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */
73
74
75 /*
76  * Local function prototypes
77  */
78
79 _PROTOTYPE(static void check_lock,(void));
80
81 #if     defined(HASEPTOPTS)
82 _PROTOTYPE(static void enter_pinfo,(void));
83 #endif  /* defined(HASEPTOPTS) */
84
85
86 /*
87  * Local storage
88  */
89
90 #if     defined(HASEPTOPTS)
91 static pxinfo_t **Pinfo = (pxinfo_t **)NULL;
92 #endif  /* defined(HASEPTOPTS) */
93
94
95 /*
96  * check_lock() - check lock for file *Lf, process *Lp
97  */
98
99 static void
100 check_lock()
101 {
102         int h;
103         struct llock *lp;
104
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)
110             {
111                 Lf->lock = lp->type;
112                 return;
113             }
114         }
115 }
116
117
118 #if     defined(HASEPTOPTS)
119 /*
120  * clear_pinfo() -- clear allocated pipe info
121  */
122
123 void
124 clear_pinfo()
125 {
126         int h;                          /* hash index */
127         pxinfo_t *pi, *pp;              /* temporary pointers */
128
129         if (!Pinfo)
130             return;
131         for (h = 0; h < PINFOBUCKS; h++) {
132             if ((pi = Pinfo[h])) {
133                 do {
134                     pp = pi->next;
135                     (void) free((FREE_P *)pi);
136                     pi = pp;
137                 } while (pi);
138                 Pinfo[h] = (pxinfo_t *)NULL;
139             }
140         }
141 }
142
143
144 /*
145  * enter_pinfo() -- enter pipe info
146  *
147  *      entry   Lf = local file structure pointer
148  *              Lp = local process structure pointer
149  */
150
151 static void
152 enter_pinfo()
153 {
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 */
158
159         if (!Pinfo) {
160         /*
161          * Allocate pipe info hash buckets.
162          */
163             if (!(Pinfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *))))
164             {
165                 (void) fprintf(stderr,
166                     "%s: no space for %d pipe info buckets\n", Pn, PINFOBUCKS);
167                     Exit(1);
168             }
169         }
170     /*
171      * Make sure this is a unique entry.
172      */
173         for (h = HASHPINFO(Lf->inode), pi = Pinfo[h], pe = (pxinfo_t *)NULL;
174              pi;
175              pe = pi, pi = pi->next
176         ) {
177             lf = pi->lf;
178             lp = &Lproc[pi->lpx];
179             if (pi->ino == Lf->inode) {
180                 if ((lp->pid == Lp->pid) && !strcmp(lf->fd, Lf->fd))
181                     return;
182             }
183         }
184    /*
185     * Allocate, fill and link a new pipe info structure to the end of
186     * the pipe inode hash chain.
187     */
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);
192             Exit(1);
193         }
194         np->ino = Lf->inode;
195         np->lf = Lf;
196         np->lpx = Lp - Lproc;
197         np->next = (pxinfo_t *)NULL;
198         if (pe)
199             pe->next = np;
200         else
201             Pinfo[h] = np;
202 }
203
204
205 /*
206  * find_pendinfo() -- find pipe end info
207  */
208
209 pxinfo_t *
210 find_pendinfo(lf, pp)
211         struct lfile *lf;               /* pipe's lfile */
212         pxinfo_t *pp;                   /* previous pipe info (NULL == none) */
213 {
214         struct lfile *ef;               /* pipe end local file structure */
215         int h;                          /* hash result */
216         pxinfo_t *pi;                   /* pipe info pointer */
217
218         if (Pinfo) {
219             if (pp)
220                 pi = pp;
221              else {
222                 h = HASHPINFO(lf->inode);
223                 pi = Pinfo[h];
224             }
225             while (pi) {
226                 if (pi->ino == lf->inode) {
227                     ef = pi->lf;
228                     if (strcmp(lf->fd, ef->fd))
229                         return(pi);
230                 }
231                 pi = pi->next;
232             }
233         }
234         return((pxinfo_t *)NULL);
235
236 }
237 #endif  /* defined(HASEPTOPTS) */
238
239
240
241 /*
242  * get_fields() - separate a line into fields
243  */
244
245 int
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
253                                          * (may be NULL) */
254         int en;                         /* number of entries in eb[] (may be
255                                          * zero) */
256 {
257         char *bp, *cp, *sp;
258         int i, j, n;
259         MALLOC_S len;
260         static char **fp = (char **)NULL;
261         static int nfpa = 0;
262
263         for (cp = ln, n = 0; cp && *cp;) {
264             for (bp = cp; *bp && (*bp == ' ' || *bp == '\t'); bp++);
265                 ;
266             if (!*bp || *bp == '\n')
267                 break;
268             for (cp = bp; *cp; cp++) {
269                 if (*cp == '\n') {
270                     *cp = '\0';
271                     break;
272                 }
273                 if (*cp == '\t')        /* TAB is always a separator */
274                     break;
275                 if (*cp == ' ')  {
276
277                 /*
278                  * See if this field may have an embedded space.
279                  */
280                     if (!eb || !en)
281                         break;
282                     else {
283                         for (i = j = 0; i < en; i++) {
284                             if (eb[i] == n) {
285                                 j = 1;
286                                 break;
287                             }
288                         }
289                         if (!j)
290                             break;
291                     }
292                 }
293                 if (sep) {
294
295                 /*
296                  * See if the character is in the separator list.
297                  */
298                     for (sp = sep; *sp; sp++) {
299                         if (*sp == *cp)
300                             break;
301                     }
302                     if (*sp) {
303
304                     /*
305                      * See if this field may have an embedded separator.
306                      */
307                         if (!eb || !en)
308                             break;
309                         else {
310                             for (i = j = 0; i < en; i++) {
311                                 if (eb[i] == n) {
312                                     j = 1;
313                                     break;
314                                 }
315                             }
316                             if (!j)
317                                 break;
318                         }
319                     }
320                 }
321             }
322             if (*cp)
323                 *cp++ = '\0';
324             if (n >= nfpa) {
325                 nfpa += 32;
326                 len = (MALLOC_S)(nfpa * sizeof(char *));
327                 if (fp)
328                     fp = (char **)realloc((MALLOC_P *)fp, len);
329                 else
330                     fp = (char **)malloc(len);
331                 if (!fp) {
332                     (void) fprintf(stderr,
333                         "%s: can't allocate %d bytes for field pointers.\n",
334                         Pn, (int)len);
335                     Exit(1);
336                 }
337             }
338             fp[n++] = bp;
339         }
340         *fr = fp;
341         return(n);
342 }
343
344
345 /*
346  * get_locks() - get lock information from /proc/locks
347  */
348
349 void
350 get_locks(p)
351         char *p;                                /* /proc lock path */
352 {
353         unsigned long bp, ep;
354         char buf[MAXPATHLEN], *ec, **fp;
355         dev_t dev;
356         int ex, i, h, mode, pid;
357         INODETYPE inode;
358         struct llock *lp, *np;
359         FILE *ls;
360         long maj, min;
361         char type;
362         static char *vbuf = (char *)NULL;
363         static size_t vsz = (size_t)0;
364 /*
365  * Destroy previous lock information.
366  */
367         if (LckH) {
368             for (i = 0; i < PIDBUCKS; i++) {
369                 for (lp = LckH[i]; lp; lp = np) {
370                     np = lp->next;
371                     (void) free((FREE_P *)lp);
372                 }
373                 LckH[i] = (struct llock *)NULL;
374             }
375         } else {
376
377         /*
378          * If first time, allocate the lock PID hash buckets.
379          */
380             LckH = (struct llock **)calloc((MALLOC_S)PIDBUCKS,
381                                            sizeof(struct llock *));
382             if (!LckH) {
383                 (void) fprintf(stderr,
384                     "%s: can't allocate %d lock hash bytes\n",
385                     Pn, (int)(sizeof(struct llock *) * PIDBUCKS));
386                 Exit(1);
387             }
388         }
389 /*
390  * Open the /proc lock file, assign a page size buffer to its stream,
391  * and read it.
392  */
393         if (!(ls = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
394             return;
395         while (fgets(buf, sizeof(buf), ls)) {
396             if (get_fields(buf, ":", &fp, (int *)NULL, 0) < 10)
397                 continue;
398             if (!fp[1] || strcmp(fp[1], "->") == 0)
399                 continue;
400         /*
401          * Get lock type.
402          */
403             if (!fp[3])
404                 continue;
405             if (*fp[3] == 'R')
406                 mode = 0;
407             else if (*fp[3] == 'W')
408                 mode = 1;
409             else
410                 continue;
411         /*
412          * Get PID.
413          */
414             if (!fp[4] || !*fp[4])
415                 continue;
416             pid = atoi(fp[4]);
417         /*
418          * Get device number.
419          */
420             ec = (char *)NULL;
421             if (!fp[5] || !*fp[5]
422             ||  (maj = strtol(fp[5], &ec, 16)) == LONG_MIN || maj == LONG_MAX
423             ||  !ec || *ec)
424                 continue;
425             ec = (char *)NULL;
426             if (!fp[6] || !*fp[6]
427             ||  (min = strtol(fp[6], &ec, 16)) == LONG_MIN || min == LONG_MAX
428             ||  !ec || *ec)
429                 continue;
430             dev = (dev_t)makedev((int)maj, (int)min);
431         /*
432          * Get inode number.
433          */
434             ec = (char *)NULL;
435             if (!fp[7] || !*fp[7]
436             ||  (inode = strtoull(fp[7], &ec, 0)) == ULONG_MAX
437             ||  !ec || *ec)
438                 continue;
439         /*
440          * Get lock extent.  Convert it and the lock type to a lock character.
441          */
442             if (!fp[8] || !*fp[8] || !fp[9] || !*fp[9])
443                 continue;
444             ec = (char *)NULL;
445             if ((bp = strtoul(fp[8], &ec, 0)) == ULONG_MAX || !ec || *ec)
446                 continue;
447             if (!strcmp(fp[9], "EOF"))          /* for Linux 2.4.x */
448                 ep = OFFSET_MAX;
449             else {
450                 ec = (char *)NULL;
451                 if ((ep = strtoul(fp[9], &ec, 0)) == ULONG_MAX || !ec || *ec)
452                     continue;
453             }
454             ex = ((off_t)bp == (off_t)0 && (off_t)ep == OFFSET_MAX) ? 1 : 0;
455             if (mode)
456                 type = ex ? 'W' : 'w';
457             else
458                 type = ex ? 'R' : 'r';
459         /*
460          * Look for this lock via the hash buckets.
461          */
462             h = HASHPID(pid);
463             for (lp = LckH[h]; lp; lp = lp->next) {
464                 if (lp->pid == pid
465                 &&  lp->dev == dev
466                 &&  lp->inode == inode
467                 &&  lp->type == type)
468                     break;
469             }
470             if (lp)
471                 continue;
472         /*
473          * Allocate a new llock structure and link it to the PID hash bucket.
474          */
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);
480                 Exit(1);
481             }
482             lp->pid = pid;
483             lp->dev = dev;
484             lp->inode = inode;
485             lp->type = type;
486             lp->next = LckH[h];
487             LckH[h] = lp;
488         }
489         (void) fclose(ls);
490 }
491
492
493 /*
494  * process_proc_node() - process file node
495  */
496
497 void
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
504                                          * others) */
505         int ls;                         /* *l status -- i.e., SB_* values */
506 {
507         mode_t access;
508         mode_t type = 0;
509         char *cp;
510         struct mounts *mp = (struct mounts *)NULL;
511         size_t sz;
512         char *tn;
513 /*
514  * Set the access mode, if possible.
515  */
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)
518                 Lf->access = 'r';
519             else if (access == S_IWUSR)
520                 Lf->access = 'w';
521             else
522                 Lf->access = 'u';
523         }
524 /*
525  * Determine node type.
526  */
527         if (ss & SB_MODE) {
528             type = s->st_mode & S_IFMT;
529             switch (type) {
530             case S_IFBLK:
531                 Lf->ntype = Ntype = N_BLK;
532                 break;
533             case S_IFCHR:
534                 Lf->ntype = Ntype = N_CHR;
535                 break;
536             case S_IFIFO:
537                 Lf->ntype = Ntype = N_FIFO;
538                 break;
539             case S_IFSOCK:
540                 /* Lf->ntype = Ntype = N_REGLR;         by alloc_lfile() */
541                 process_proc_sock(p, pbr, s, ss, l, ls);
542                 return;
543             case 0:
544                 if (!strcmp(p, "anon_inode"))
545                    Lf->ntype = Ntype = N_ANON_INODE;
546                 break;
547             }
548         }
549         if (Selinet)
550             return;
551 /*
552  * Save the device.  If it is an NFS device, change the node type to N_NFS.
553  */
554         if (ss & SB_DEV) {
555             Lf->dev = s->st_dev;
556             Lf->dev_def = 1;
557         }
558         if ((Ntype == N_CHR || Ntype == N_BLK)) {
559             if (ss & SB_RDEV) {
560                 Lf->rdev = s->st_rdev;
561                 Lf->rdev_def = 1;
562             }
563         }
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))
570                 ) {
571                     Lf->ntype = Ntype = N_NFS;
572                     break;
573                 }
574             }
575         }
576 /*
577  * Save the inode number.
578  */
579         if (ss & SB_INO) {
580             Lf->inode = (INODETYPE)s->st_ino;
581             Lf->inp_ty = 1;
582
583 #if     defined(HASEPTOPTS)
584             if ((Lf->ntype == N_FIFO) && FeptE) {
585                 (void) enter_pinfo();
586                 Lf->sf |= SELPINFO;
587             }
588 #endif  /* defined(HASEPTOPTS) */
589
590         }
591 /*
592  * Check for a lock.
593  */
594         if (Lf->dev_def && (Lf->inp_ty == 1))
595             (void) check_lock();
596 /*
597  * Save the file size.
598  */
599         switch (Ntype) {
600         case N_BLK:
601         case N_CHR:
602         case N_FIFO:
603             if (!Fsize && l && (ls & SB_SIZE) && OffType) {
604                 Lf->off = (SZOFFTYPE)l->st_size;
605                 Lf->off_def = 1;
606             }
607             break;
608         default:
609             if (Foffset) {
610                 if (l && (ls & SB_SIZE) && OffType) {
611                     Lf->off = (SZOFFTYPE)l->st_size;
612                     Lf->off_def = 1;
613                 }
614             } else if (!Foffset || Fsize) {
615                 if (ss & SB_SIZE) {
616                     Lf->sz = (SZOFFTYPE)s->st_size;
617                     Lf->sz_def = 1;
618                 }
619             }
620         }
621 /*
622  * Record the link count.
623  */
624         if (Fnlink && (ss & SB_NLINK)) {
625             Lf->nlink = (long)s->st_nlink;
626             Lf->nlink_def = 1;
627             if (Nlink && (Lf->nlink < Nlink))
628                 Lf->sf |= SELNLINK;
629         }
630 /*
631  * Format the type name.
632  */
633         if (ss & SB_MODE) {
634             switch (type) {
635             case S_IFBLK:
636                 tn = "BLK";
637                 break;
638             case S_IFCHR:
639                 tn = "CHR";
640                 break;
641             case S_IFDIR:
642                 tn = "DIR";
643                 break;
644             case S_IFIFO:
645                 tn = "FIFO";
646                 break;
647             case S_IFREG:
648                 tn = "REG";
649                 break;
650             case S_IFLNK:
651                 tn = "LINK";
652                 break;
653             case S_ISVTX:
654                 tn = "VTXT";
655                 break;
656             default:
657                 if (Ntype == N_ANON_INODE)
658                     tn = "a_inode";
659                 else {
660                     (void) snpf(Lf->type, sizeof(Lf->type), "%04o",
661                         ((type >> 12) & 0xf));
662                     tn = (char *)NULL;
663                 }
664             }
665         } else
666             tn = "unknown";
667         if (tn)
668             (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn);
669 /*
670  * Record an NFS file selection.
671  */
672         if (Ntype == N_NFS && Fnfs)
673             Lf->sf |= SELNFS;
674 /*
675  * Test for specified file.
676  */
677         if (Sfile
678         && is_file_named(1, p, mp,
679                          ((type == S_IFCHR) || (type == S_IFBLK)) ? 1 : 0))
680             Lf->sf |= SELNM;
681 /*
682  * If no NAME information has been stored, store the path.
683  *
684  * Store the remote host and mount point for an NFS file.
685  */
686         if (!Namech[0]) {
687             (void) snpf(Namech, Namechl, "%s", p);
688             if ((Ntype == N_NFS) && mp && mp->fsname) {
689                 cp = endnm(&sz);
690                 (void) snpf(cp, sz, " (%s)", mp->fsname);
691             }
692         }
693         if (Namech[0])
694             enter_nm(Namech);
695 }