Imported Upstream version 4.91
[platform/upstream/lsof.git] / dialects / linux / dproc.c
1 /*
2  * dproc.c - Linux process access 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: dproc.c,v 1.31 2018/03/26 21:52:29 abe Exp $";
36 #endif
37
38 #include "lsof.h"
39
40
41 /*
42  * Local definitions
43  */
44
45 #define FDINFO_FLAGS            1       /* fdinfo flags available */
46 #define FDINFO_POS              2       /* fdinfo position available */
47
48 #if     defined(HASEPTOPTS) && defined(HASPTYEPT)
49 #define FDINFO_TTY_INDEX        4       /* fdinfo tty-index available */
50 #endif  /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
51
52 #if     defined(HASEPTOPTS) && defined(HASPTYEPT)
53 #define FDINFO_ALL              (FDINFO_FLAGS | FDINFO_POS | FDINFO_TTY_INDEX)
54 #else   /* !(defined(HASEPTOPTS) && defined(HASPTYEPT)) */
55 #define FDINFO_ALL              (FDINFO_FLAGS | FDINFO_POS )
56 #endif  /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
57
58 #define LSTAT_TEST_FILE         "/"
59 #define LSTAT_TEST_SEEK         1
60
61 #if     !defined(ULLONG_MAX)
62 #define ULLONG_MAX              18446744073709551615ULL
63 #endif  /* !defined(ULLONG_MAX) */
64
65
66 /*
67  * Local structures
68  */
69
70 struct l_fdinfo {
71         int flags;                      /* flags: line value */
72         off_t pos;                      /* pos: line value */
73
74 #if     defined(HASEPTOPTS) && defined(HASPTYEPT)
75         int tty_index;                  /* pty line index */
76 #endif  /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
77
78 };
79
80
81 /*
82  * Local variables
83  */
84
85 static short Cckreg;                    /* conditional status of regular file
86                                          * checking:
87                                          *     0 = unconditionally check
88                                          *     1 = conditionally check */
89 static short Ckscko;                    /* socket file only checking status:
90                                          *     0 = none
91                                          *     1 = check only socket files */
92
93
94 /*
95  * Local function prototypes
96  */
97
98 _PROTOTYPE(static MALLOC_S alloc_cbf,(MALLOC_S len, char **cbf, MALLOC_S cbfa));
99 _PROTOTYPE(static int get_fdinfo,(char *p, int msk, struct l_fdinfo *fi));
100 _PROTOTYPE(static int getlinksrc,(char *ln, char *src, int srcl, char **rest));
101 _PROTOTYPE(static int isefsys,(char *path, char *type, int l,
102                                efsys_list_t **rep, struct lfile **lfr));
103 _PROTOTYPE(static int nm2id,(char *nm, int *id, int *idl));
104 _PROTOTYPE(static int read_id_stat,(char *p, int id, char **cmd, int *ppid,
105                                     int *pgid));
106 _PROTOTYPE(static void process_proc_map,(char *p, struct stat *s, int ss));
107 _PROTOTYPE(static int process_id,(char *idp, int idpl, char *cmd, UID_ARG uid,
108                                   int pid, int ppid, int pgid, int tid,
109                                   char *tcmd));
110 _PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss));
111  
112
113 #if     defined(HASSELINUX)
114 _PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx));
115
116
117 #include <fnmatch.h>
118
119
120 /*
121  * cmp_cntx_eq -- compare program and user security contexts
122  */
123
124 static int
125 cmp_cntx_eq(pcntx, ucntx)
126         char *pcntx;                           /* program context */
127         char *ucntx;                           /* user supplied context */
128 {
129         return !fnmatch(ucntx, pcntx, 0);
130 }
131
132
133 /*
134  * enter_cntx_arg() - enter name ecurity context argument
135  */
136
137 int
138 enter_cntx_arg(cntx)
139         char *cntx;                            /* context */
140 {
141         cntxlist_t *cntxp;
142 /*
143  * Search the argument list for a duplicate.
144  */
145         for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
146             if (!strcmp(cntxp->cntx, cntx)) {
147                 if (!Fwarn) {
148                     (void) fprintf(stderr, "%s: duplicate context: %s\n",
149                         Pn, cntx);
150                 }
151                 return(1);
152             }
153         }
154 /*
155  * Create and link a new context argument list entry.
156  */
157         if (!(cntxp = (cntxlist_t *)malloc((MALLOC_S)sizeof(cntxlist_t)))) {
158             (void) fprintf(stderr, "%s: no space for context: %s\n", Pn, cntx);
159             Exit(1);
160         }
161         cntxp->f = 0;
162         cntxp->cntx = cntx;
163         cntxp->next = CntxArg;
164         CntxArg = cntxp;
165         return(0);
166 }
167 #endif  /* defined(HASSELINUX) */
168
169
170 /*
171  * alloc_cbf() -- allocate a command buffer
172  */
173
174 static MALLOC_S
175 alloc_cbf(len, cbf, cbfa)
176         MALLOC_S len;                           /* required length */
177         char **cbf;                             /* current buffer */
178         MALLOC_S cbfa;                          /* current buffer allocation */
179 {
180         if (*cbf)
181             *cbf = (char *)realloc((MALLOC_P *)*cbf, len);
182         else
183             *cbf = (char *)malloc(len);
184         if (!*cbf) {
185             (void) fprintf(stderr,
186                 "%s: can't allocate command %d bytes\n", Pn, (int)len);
187              Exit(1);
188         }
189         return(len);
190 }
191
192
193 /*
194  * gather_proc_info() -- gather process information
195  */
196
197 void
198 gather_proc_info()
199 {
200         char *cmd, *tcmd;
201         char cmdbuf[MAXPATHLEN];
202         struct dirent *dp;
203         unsigned char ht, pidts;
204         int n, nl, pgid, pid, ppid, prv, rv, tid, tpgid, tppid, tx;
205         static char *path = (char *)NULL;
206         static int pathl = 0;
207         static char *pidpath = (char *)NULL;
208         static MALLOC_S pidpathl = 0;
209         static MALLOC_S pidx = 0;
210         static DIR *ps = (DIR *)NULL;
211         struct stat sb;
212         static char *taskpath = (char *)NULL;
213         static int taskpathl = 0;
214         static char *tidpath = (char *)NULL;
215         static int tidpathl = 0;
216         DIR *ts;
217         UID_ARG uid;
218
219 /*
220  * Do one-time setup.
221  */
222         if (!pidpath) {
223             pidx = strlen(PROCFS) + 1;
224             pidpathl = pidx + 64 + 1;   /* 64 is growth room */
225             if (!(pidpath = (char *)malloc(pidpathl))) {
226                 (void) fprintf(stderr,
227                     "%s: can't allocate %d bytes for \"%s/\"<pid>\n",
228                     Pn, (int)pidpathl, PROCFS);
229                 Exit(1);
230             }
231             (void) snpf(pidpath, pidpathl, "%s/", PROCFS);
232         }
233 /*
234  * Get lock and net information.
235  */
236         (void) make_proc_path(pidpath, pidx, &path, &pathl, "locks");
237         (void) get_locks(path);
238         (void) make_proc_path(pidpath, pidx, &path, &pathl, "net/");
239         (void) set_net_paths(path, strlen(path));
240 /*
241  * If only socket files have been selected, or socket files have been selected
242  * ANDed with other selection options, enable the skipping of regular files.
243  *
244  * If socket files and some process options have been selected, enable
245  * conditional skipping of regular file; i.e., regular files will be skipped
246  * unless they belong to a process selected by one of the specified options.
247  */
248         if (Selflags & SELNW) {
249
250         /*
251          * Some network files selection options have been specified.
252          */
253             if (Fand || !(Selflags & ~SELNW)) {
254
255             /*
256              * Selection ANDing or only network file options have been
257              * specified, so set unconditional skipping of regular files
258              * and socket file only checking.
259              */
260                 Cckreg = 0;
261                 Ckscko = 1;
262             } else {
263
264             /*
265              * If ORed file selection options have been specified, or no ORed
266              * process selection options have been specified, enable
267              * unconditional file checking and clear socket file only checking.
268              *
269              * If only ORed process selection options have been specified,
270              * enable conditional file skipping and socket file only checking.
271              */
272                 if ((Selflags & SELFILE) || !(Selflags & SelProc))
273                     Cckreg = Ckscko = 0;
274                 else
275                     Cckreg = Ckscko = 1;
276             }
277         } else {
278
279         /*
280          * No network file selection options were specified.  Enable
281          * unconditional file checking and clear socket file only checking.
282          */
283             Cckreg = Ckscko = 0;
284         }
285 /*
286  * Read /proc, looking for PID directories.  Open each one and
287  * gather its process and file information.
288  */
289         if (!ps) {
290             if (!(ps = opendir(PROCFS))) {
291                 (void) fprintf(stderr, "%s: can't open %s\n", Pn, PROCFS);
292                 Exit(1);
293             }
294         } else
295             (void) rewinddir(ps);
296         while ((dp = readdir(ps))) {
297             if (nm2id(dp->d_name, &pid, &n))
298                 continue;
299         /*
300          * Build path to PID's directory.
301          */
302             if ((pidx + n + 1 + 1) > pidpathl) {
303                 pidpathl = pidx + n + 1 + 1 + 64;
304                 if (!(pidpath = (char *)realloc((MALLOC_P *)pidpath, pidpathl)))
305                 {
306                     (void) fprintf(stderr,
307                         "%s: can't allocate %d bytes for \"%s/%s/\"\n",
308                         Pn, (int)pidpathl, PROCFS, dp->d_name);
309                     Exit(1);
310                 }
311             }
312             (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name);
313             n += (pidx + 1);
314         /*
315          * Process the PID's stat info.
316          */
317             if (stat(pidpath, &sb))
318                 continue;
319             uid = (UID_ARG)sb.st_uid;
320             ht = pidts = 0;
321         /*
322          * Get the PID's command name.
323          */
324             (void) make_proc_path(pidpath, n, &path, &pathl, "stat");
325             if ((prv = read_id_stat(path, pid, &cmd, &ppid, &pgid)) < 0) 
326                 cmd = "(unknown)";
327
328 #if     defined(HASTASKS)
329         /*
330          * Task reporting has been selected, so save the process' command
331          * string, so that task processing won't change it in the buffer of
332          * read_id_stat().
333          *
334          * Check the tasks of the process first, so that the "-p<PID> -aK"
335          * options work properly.
336          */
337             else if (!IgnTasks && (Selflags & SELTASK)) {
338                 strncpy(cmdbuf, cmd, sizeof(cmdbuf) - 1);
339                 cmdbuf[sizeof(cmdbuf) - 1] = '\0';
340                 cmd = cmdbuf;
341                 (void) make_proc_path(pidpath, n, &taskpath, &taskpathl,
342                                       "task");
343                 tx = n + 4;
344                 if ((ts = opendir(taskpath))) {
345
346                 /*
347                  * Process the PID's tasks.  Record the open files of those
348                  * whose TIDs do not match the PID and which are themselves
349                  * not zombies.
350                  */
351                     while ((dp = readdir(ts))) {
352
353                     /*
354                      * Get the task ID.  Skip the task if its ID matches the
355                      * process PID.
356                      */
357                         if (nm2id(dp->d_name, &tid, &nl))
358                             continue;
359                         if  (tid == pid) {
360                             pidts = 1;
361                             continue;
362                         }
363                     /*
364                      * Form the path for the TID.
365                      */
366                         if ((tx + 1 + nl + 1 + 4) > tidpathl) {
367                             tidpathl = tx + 1 + n + 1 + 4 + 64;
368                             if (tidpath)
369                                 tidpath = (char *)realloc((MALLOC_P *)tidpath,
370                                                           tidpathl);
371                             else
372                                 tidpath = (char *)malloc((MALLOC_S)tidpathl);
373                             if (!tidpath) {
374                                 (void) fprintf(stderr,
375                                     "%s: can't allocate %d task bytes", Pn,
376                                     tidpathl);
377                                 (void) fprintf(stderr, " for \"%s/%s/stat\"\n",
378                                     taskpath, dp->d_name);
379                                 Exit(1);
380                             }
381                         }
382                         (void) snpf(tidpath, tidpathl, "%s/%s/stat", taskpath,
383                             dp->d_name);
384                     /*
385                      * Check the task state.
386                      */
387                         rv = read_id_stat(tidpath, tid, &tcmd, &tppid,
388                                           &tpgid);
389                         if ((rv < 0) || (rv == 1))
390                             continue;
391                     /*
392                      * Attempt to record the task.
393                      */
394                         if (!process_id(tidpath, (tx + 1 + nl+ 1), cmd, uid,
395                                         pid, tppid, tpgid, tid, tcmd))
396                         {
397                             ht = 1;
398                         }
399                     }
400                     (void) closedir(ts);
401                 }
402             }
403 #endif  /* defined(HASTASKS) */
404
405         /*
406          * If the main process is a task and task selection has been specified
407          * along with option ANDing, enter the main process temporarily as a
408          * task, so that the "-aK" option set lists the main process along
409          * with its tasks.
410          */
411             if ((prv >= 0) && (prv != 1)) {
412                 tid = (Fand && ht && pidts && !IgnTasks && (Selflags & SELTASK))
413                     ? pid : 0;
414                 if ((!process_id(pidpath, n, cmd, uid, pid, ppid, pgid, tid,
415                                  (char *)NULL))
416                 &&  tid)
417                 {
418                     Lp->tid = 0;
419                 }
420             }
421         }
422 }
423
424
425 /*
426  * get_fdinfo() - get values from /proc/<PID>fdinfo/FD
427  */
428
429 static int
430 get_fdinfo(p, msk, fi)
431         char *p;                        /* path to fdinfo file */
432         int msk;                        /* mask for information type: e.g.,
433                                          * the FDINFO_* definition */
434         struct l_fdinfo *fi;            /* pointer to local fdinfo values
435                                          * return structure */
436 {
437         char buf[MAXPATHLEN + 1], *ep, **fp;
438         FILE *fs;
439         int rv = 0;
440         unsigned long ul;
441         unsigned long long ull;
442 /*
443  * Signal no values returned (0) if no fdinfo pointer was provided or if the
444  * fdinfo path can't be opened.
445  */
446         if (!fi)
447             return(0);
448
449 #if     defined(HASEPTOPTS) && defined(HASPTYEPT)
450         fi->tty_index = -1;
451 #endif  /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
452
453         if (!p || !*p || !(fs = fopen(p, "r")))
454             return(0);
455 /*
456  * Read the fdinfo file.
457  */
458         while (fgets(buf, sizeof(buf), fs)) {
459             if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 2)
460                 continue;
461             if (!fp[0] || !*fp[0] || !fp[1] || !*fp[1])
462                 continue;
463             if (!strcmp(fp[0], "flags:")) {
464
465             /*
466              * Process a "flags:" line.
467              */
468                 ep = (char *)NULL;
469                 if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX
470                 ||  !ep || *ep)
471                     continue;
472                 fi->flags = (unsigned int)ul;
473                 if ((rv |= FDINFO_FLAGS) == msk)
474                     break;
475             } else if (!strcmp(fp[0], "pos:")) {
476
477             /*
478              * Process a "pos:" line.
479              */
480                 ep = (char *)NULL;
481                 if ((ull = strtoull(fp[1], &ep, 0)) == ULLONG_MAX
482                 ||  !ep || *ep)
483                     continue;
484                 fi->pos = (off_t)ull;
485                 if ((rv |= FDINFO_POS) == FDINFO_ALL)
486                     break;
487
488 #if     defined(HASEPTOPTS) && defined(HASPTYEPT)
489             } else if (!strcmp(fp[0], "tty-index:")) {
490
491             /*
492              * Process a "tty-index:" line.
493              */
494                 ep = (char *)NULL;
495                 if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX
496                 ||  !ep || *ep)
497                      continue;
498                 fi->tty_index = (int)ul;
499                 if (fi->tty_index < 0) {
500
501                 /*
502                  * Oops! If integer overflow occurred, reset the field.
503                  */
504                      fi->tty_index = -1;
505                 }
506                 if ((rv |= FDINFO_TTY_INDEX) == msk)
507                     break;
508 #endif  /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
509
510             }
511         }
512         fclose(fs);
513 /*
514  * Signal via the return value what information was obtained. (0 == none)
515  */
516         return(rv);
517 }
518
519
520 /*
521  * getlinksrc() - get the source path name for the /proc/<PID>/fd/<FD> link
522  */
523
524
525 static int
526 getlinksrc(ln, src, srcl, rest)
527         char *ln;                       /* link path */
528         char *src;                      /* link source path return address */
529         int srcl;                       /* length of src[] */
530         char **rest;                    /* pointer to what follows the ':' in
531                                          * the link source path (NULL if no
532                                          * return requested) */
533 {
534         char *cp;
535         int ll;
536
537         if (rest)
538             *rest = (char *)NULL;
539         if ((ll = readlink(ln, src, srcl - 1)) < 1
540         ||  ll >= srcl)
541             return(-1);
542         src[ll] = '\0';
543         if (*src == '/')
544             return(ll);
545         if ((cp = strchr(src, ':'))) {
546             *cp = '\0';
547             ll = strlen(src);
548             if (rest)
549                 *rest = cp + 1;
550         }
551         return(ll);
552 }
553
554
555 /*
556  * initialize() - perform all initialization
557  */
558
559 void
560 initialize()
561 {
562         int fd;
563         struct l_fdinfo fi;
564         char path[MAXPATHLEN];
565         struct stat sb;
566 /*
567  * Test for -i and -X option conflict.
568  */
569         if (Fxopt && (Fnet || Nwad)) {
570             (void) fprintf(stderr, "%s: -i is useless when -X is specified.\n",
571                 Pn);
572             usage(1, 0, 0);
573         }
574 /*
575  * Open LSTAT_TEST_FILE and seek to byte LSTAT_TEST_SEEK, then lstat the
576  * /proc/<PID>/fd/<FD> for LSTAT_TEST_FILE to see what position is reported.
577  * If the result is LSTAT_TEST_SEEK, enable offset reporting.
578  *
579  * If the result isn't LSTAT_TEST_SEEK, next check the fdinfo file for the
580  * open LSTAT_TEST_FILE file descriptor.  If it exists and contains a "pos:"
581  * value, and if the value is LSTAT_TEST_SEEK, enable offset reporting.
582  */
583         if ((fd = open(LSTAT_TEST_FILE, O_RDONLY)) >= 0) {
584             if (lseek(fd, (off_t)LSTAT_TEST_SEEK, SEEK_SET)
585             == (off_t)LSTAT_TEST_SEEK) {
586                 (void) snpf(path, sizeof(path), "%s/%d/fd/%d", PROCFS, Mypid,
587                             fd);
588                 if (!lstat(path, &sb)) {
589                     if (sb.st_size == (off_t)LSTAT_TEST_SEEK)
590                         OffType = 1;
591                 }
592             }
593             if (!OffType) {
594                 (void) snpf(path, sizeof(path), "%s/%d/fdinfo/%d", PROCFS,
595                             Mypid, fd);
596                 if (get_fdinfo(path, FDINFO_POS, &fi) & FDINFO_POS) {
597                     if (fi.pos == (off_t)LSTAT_TEST_SEEK)
598                         OffType = 2;
599                 }
600             }
601             (void) close(fd);
602         }
603         if (!OffType) {
604             if (Foffset && !Fwarn)
605                 (void) fprintf(stderr,
606                     "%s: WARNING: can't report offset; disregarding -o.\n",
607                     Pn);
608             Foffset = 0;
609             Fsize = 1;
610         }
611         if (Fsv && (OffType != 2)) {
612             if (!Fwarn && FsvByf)
613                 (void) fprintf(stderr,
614                     "%s: WARNING: can't report file flags; disregarding +f.\n",
615                     Pn);
616             Fsv = 0;
617         }
618 /*
619  * Make sure the local mount info table is loaded if doing anything other
620  * than just Internet lookups.  (HasNFS is defined during the loading of the
621  * local mount table.)
622  */
623         if (Selinet == 0)
624             (void) readmnt();
625 }
626
627
628 /*
629  * make_proc_path() - make a path in a /proc directory
630  *
631  * entry:
632  *      pp = pointer to /proc prefix
633  *      lp = length of prefix
634  *      np = pointer to malloc'd buffer to receive new file's path
635  *      nl = length of new file path buffer
636  *      sf = new path's suffix
637  *
638  * return: length of new path
639  *      np = updated with new path
640  *      nl = updated with new path length
641  */
642
643 int
644 make_proc_path(pp, pl, np, nl, sf)
645         char *pp;                       /* path prefix -- e.g., /proc/<pid>/ */
646         int pl;                         /* strlen(pp) */
647         char **np;                      /* malloc'd receiving buffer */
648         int *nl;                        /* strlen(*np) */
649         char *sf;                       /* suffix of new path */
650 {
651         char *cp;
652         MALLOC_S rl, sl;
653
654         sl = strlen(sf);
655         if ((rl = pl + sl + 1) > *nl) {
656             if ((cp = *np))
657                 cp = (char *)realloc((MALLOC_P *)cp, rl);
658             else
659                 cp = (char *)malloc(rl);
660             if (!cp) {
661                 (void) fprintf(stderr,
662                     "%s: can't allocate %d bytes for %s%s\n",
663                     Pn, (int)rl, pp, sf);
664                 Exit(1);
665             }
666             *nl = rl;
667             *np = cp;
668         }
669         (void) snpf(*np, *nl, "%s", pp);
670         (void) snpf(*np + pl, *nl - pl, "%s", sf);
671         return(rl - 1);
672 }
673
674
675 /*
676  * isefsys() -- is path on a file system exempted with -e
677  *
678  * Note: alloc_lfile() must have been called in advance.
679  */
680
681 static int
682 isefsys(path, type, l, rep, lfr)
683         char *path;                     /* path to file */
684         char *type;                     /* unknown file type */
685         int l;                          /* link request: 0 = report
686                                          *               1 = link */
687         efsys_list_t **rep;             /* returned Efsysl pointer, if not
688                                          * NULL */
689         struct lfile **lfr;             /* allocated struct lfile pointer */
690 {
691         efsys_list_t *ep;
692         int ds, len;
693         struct mounts *mp;
694         char nmabuf[MAXPATHLEN + 1];
695
696         len = (int) strlen(path);
697         for (ep = Efsysl; ep; ep = ep->next) {
698
699         /*
700          * Look for a matching exempt file system path at the beginning of
701          * the file path.
702          */
703             if (ep->pathl > len)
704                 continue;
705             if (strncmp(ep->path, path, ep->pathl))
706                 continue;
707         /*
708          * If only reporting, return information as requested.
709          */
710             if (!l) {
711                 if (rep)
712                     *rep = ep;
713                 return(0);
714             }
715         /*
716          * Process an exempt file.
717          */
718             ds = 0;
719             if ((mp = ep->mp)) {
720                 if (mp->ds & SB_DEV) {
721                     Lf->dev = mp->dev;
722                     ds = Lf->dev_def = 1;
723                 }
724                 if (mp->ds & SB_RDEV) {
725                     Lf->rdev = mp->rdev;
726                     ds = Lf->rdev_def = 1;
727                 }
728             }
729             if (!ds)
730                 (void) enter_dev_ch("UNKNOWN");
731             Lf->ntype = N_UNKN;
732             (void) snpf(Lf->type, sizeof(Lf->type), "%s",
733                         (type ? type : "UNKN"));
734             (void) enter_nm(path);
735             (void) snpf(nmabuf, sizeof(nmabuf), "(%ce %s)",
736                 ep->rdlnk ? '+' : '-', ep->path);
737             nmabuf[sizeof(nmabuf) - 1] = '\0';
738             (void) add_nma(nmabuf, strlen(nmabuf));
739             if (Lf->sf) {
740                 if (lfr)
741                     *lfr = Lf;
742                 link_lfile();
743             } else if (lfr)
744                 *lfr = (struct lfile *)NULL;
745             return(0);
746         }
747         return(1);
748 }
749
750
751 /*
752  * nm2id() - convert a name to an integer ID
753  */
754
755 static int
756 nm2id(nm, id, idl)
757         char *nm;                       /* pointer to name */
758         int *id;                        /* pointer to ID receiver */
759         int *idl;                       /* pointer to ID length receiver */
760 {
761         register int tid, tidl;
762
763         for (*id = *idl = tid = tidl = 0; *nm; nm++) {
764
765 #if     defined(__STDC__)       /* { */
766             if (!isdigit((unsigned char)*nm))
767 #else   /* !defined(__STDC__)      } { */
768             if (!isascii(*nm) || !isdigit((unsigned char)*cp))
769 #endif  /* defined(__STDC__)       } */
770
771                 {
772                     return(1);
773                 }
774                 tid = tid * 10 + (int)(*nm - '0');
775                 tidl++;
776         }
777         *id = tid;
778         *idl = tidl;
779         return(0);
780 }
781
782
783 /*
784  * open_proc_stream() -- open a /proc stream
785  */
786
787 FILE *
788 open_proc_stream(p, m, buf, sz, act)
789         char *p;                        /* pointer to path to open */
790         char *m;                        /* pointer to mode -- e.g., "r" */
791         char **buf;                     /* pointer tp setvbuf() address
792                                          * (NULL if none) */
793         size_t *sz;                     /* setvbuf() size (0 if none or if
794                                          * getpagesize() desired */
795         int act;                        /* fopen() failure action:
796                                          *     0 : return (FILE *)NULL
797                                          *   <>0 : fprintf() an error message
798                                          *         and Exit(1)
799                                          */
800 {
801         FILE *fs;                       /* opened stream */
802         static size_t psz = (size_t)0;  /* page size */
803         size_t tsz;                     /* temporary size */
804 /*
805  * Open the stream.
806  */
807         if (!(fs = fopen(p, m))) {
808             if (!act)
809                 return((FILE *)NULL);
810             (void) fprintf(stderr, "%s: can't fopen(%s, \"%s\"): %s\n",
811                 Pn, p, m, strerror(errno));
812             Exit(1);
813         }
814 /*
815  * Return the stream if no buffer change is required.
816  */
817         if (!buf)
818             return(fs);
819 /*
820  * Determine the buffer size required.
821  */
822         if (!(tsz = *sz)) {
823             if (!psz)
824                 psz = getpagesize();
825             tsz = psz;
826         }
827 /*
828  * Allocate a buffer for the stream, as required.
829  */
830         if (!*buf) {
831             if (!(*buf = (char *)malloc((MALLOC_S)tsz))) {
832                 (void) fprintf(stderr,
833                     "%s: can't allocate %d bytes for %s stream buffer\n",
834                     Pn, (int)tsz, p);
835                 Exit(1);
836             }
837             *sz = tsz;
838         }
839 /*
840  * Assign the buffer to the stream.
841  */
842         if (setvbuf(fs, *buf, _IOFBF, tsz)) {
843             (void) fprintf(stderr, "%s: setvbuf(%s)=%d failure: %s\n",
844                 Pn, p, (int)tsz, strerror(errno));
845             Exit(1);
846         }
847         return(fs);
848 }
849
850
851 /*
852  * process_id - process ID: PID or LWP
853  *
854  * return:  0 == ID processed
855  *          1 == ID not processed
856  */
857
858 static int
859 process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid, tcmd)
860         char *idp;                      /* pointer to ID's path */
861         int idpl;                       /* pointer to ID's path length */
862         char *cmd;                      /* pointer to ID's command */
863         UID_ARG uid;                    /* ID's UID */
864         int pid;                        /* ID's PID */
865         int ppid;                       /* parent PID */
866         int pgid;                       /* parent GID */
867         int tid;                        /* task ID, if non-zero */
868         char *tcmd;                     /* task command, if non-NULL) */
869 {
870         int av = 0;
871         static char *dpath = (char *)NULL;
872         static int dpathl = 0;
873         short efs, enls, enss, lnk, oty, pn, pss, sf;
874         int fd, i, ls, n, ss, sv;
875         struct l_fdinfo fi;
876         DIR *fdp;
877         struct dirent *fp;
878         static char *ipath = (char *)NULL;
879         static int ipathl = 0;
880         int j = 0;
881         struct lfile *lfr;
882         struct stat lsb, sb;
883         char nmabuf[MAXPATHLEN + 1], pbuf[MAXPATHLEN + 1];
884         static char *path = (char *)NULL;
885         static int pathl = 0;
886         static char *pathi = (char *)NULL;
887         static int pathil = 0;
888         char *rest;
889         int txts = 0;
890
891 #if     defined(HASSELINUX)
892         cntxlist_t *cntxp;
893 #endif  /* defined(HASSELINUX) */
894
895 /*
896  * See if process is excluded.
897  */
898         if (is_proc_excl(pid, pgid, uid, &pss, &sf, tid)
899         ||  is_cmd_excl(cmd, &pss, &sf))
900         {
901
902 #if     defined(HASEPTOPTS)
903             if (!FeptE)
904                 return(1);
905 #else   /* !defined(HASEPTOPTS) */
906             return(1);
907 #endif  /* defined(HASEPTOPTS) */
908
909         }
910         if (Cckreg && !FeptE) {
911
912         /*
913          * If conditional checking of regular files is enabled, enable
914          * socket file only checking, based on the process' selection
915          * status.
916          */
917             Ckscko = (sf & SelProc) ? 0 : 1;
918         }
919         alloc_lproc(pid, pgid, ppid, uid, cmd, (int)pss, (int)sf);
920         Plf = (struct lfile *)NULL;
921
922 #if     defined(HASTASKS)
923 /*
924  * Enter task information.
925  */
926         Lp->tid = tid;
927         if (tid && tcmd) {
928             if (!(Lp->tcmd = mkstrcpy(tcmd, (MALLOC_S *)NULL))) {
929                 (void) fprintf(stderr,
930                     "%s: PID %d, TID %d, no space for task name: ",
931                     Pn, pid, tid);
932                 safestrprt(tcmd, stderr, 1);
933                 Exit(1);
934             }
935         }
936 #endif  /* defined(HASTASKS) */
937
938 /*
939  * Process the ID's current working directory info.
940  */
941         efs = 0;
942         if (!Ckscko) {
943             (void) make_proc_path(idp, idpl, &path, &pathl, "cwd");
944             alloc_lfile(CWD, -1);
945             if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
946                 if (!Fwarn) {
947                     zeromem((char *)&sb, sizeof(sb));
948                     lnk = ss = 0;
949                     (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
950                         strerror(errno));
951                     nmabuf[sizeof(nmabuf) - 1] = '\0';
952                     (void) add_nma(nmabuf, strlen(nmabuf));
953                     pn = 1;
954                 } else
955                     pn = 0;
956             } else {
957                 lnk = pn = 1;
958                 if (Efsysl && !isefsys(pbuf, "UNKNcwd", 1, NULL, &lfr)) {
959                     efs = 1;
960                     pn = 0;
961                 } else {
962                     ss = SB_ALL;
963                     if (HasNFS) {
964                         if ((sv = statsafely(path, &sb)))
965                         sv = statEx(pbuf, &sb, &ss);
966                     } else
967                         sv = stat(path, &sb);
968                     if (sv) {
969                         ss = 0;
970                         if (!Fwarn) {
971                             (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
972                                 strerror(errno));
973                             nmabuf[sizeof(nmabuf) - 1] = '\0';
974                             (void) add_nma(nmabuf, strlen(nmabuf));
975                         }
976                     }
977                 }
978             }
979             if (pn) {
980                 (void) process_proc_node(lnk ? pbuf : path,
981                                          path, &sb, ss,
982                                          (struct stat *)NULL, 0);
983                 if (Lf->sf)
984                     link_lfile();
985             }
986         }
987 /*
988  * Process the ID's root directory info.
989  */
990         lnk = ss = 0;
991         if (!Ckscko) {
992             (void) make_proc_path(idp, idpl, &path, &pathl, "root");
993             alloc_lfile(RTD, -1);
994             if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
995                 if (!Fwarn) {
996                     zeromem((char *)&sb, sizeof(sb));
997                     (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
998                         strerror(errno));
999                     nmabuf[sizeof(nmabuf) - 1] = '\0';
1000                     (void) add_nma(nmabuf, strlen(nmabuf));
1001                     pn = 1;
1002                 } else
1003                     pn = 0;
1004             } else {
1005                 lnk = pn = 1;
1006                 if (Efsysl && !isefsys(pbuf, "UNKNrtd", 1, NULL, NULL))
1007                     pn = 0;
1008                 else {
1009                     ss = SB_ALL;
1010                     if (HasNFS) {
1011                         if ((sv = statsafely(path, &sb)))
1012                             sv = statEx(pbuf, &sb, &ss);
1013                     } else
1014                         sv = stat(path, &sb);
1015                     if (sv) {
1016                         ss = 0;
1017                         if (!Fwarn) {
1018                             (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
1019                                 strerror(errno));
1020                             nmabuf[sizeof(nmabuf) - 1] = '\0';
1021                             (void) add_nma(nmabuf, strlen(nmabuf));
1022                         }
1023                     }
1024                 }
1025             }
1026             if (pn) {
1027                 (void) process_proc_node(lnk ? pbuf : path,
1028                                          path, &sb, ss,
1029                                          (struct stat *)NULL, 0);
1030                 if (Lf->sf)
1031                     link_lfile();
1032             }
1033         }
1034 /*
1035  * Process the ID's execution info.
1036  */
1037         lnk = ss = txts = 0;
1038         if (!Ckscko) {
1039             (void) make_proc_path(idp, idpl, &path, &pathl, "exe");
1040             alloc_lfile("txt", -1);
1041             if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
1042                 zeromem((void *)&sb, sizeof(sb));
1043                 if (!Fwarn) {
1044                     if ((errno != ENOENT) || uid) {
1045                         (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
1046                             strerror(errno));
1047                         nmabuf[sizeof(nmabuf) - 1] = '\0';
1048                         (void) add_nma(nmabuf, strlen(nmabuf));
1049                     }
1050                     pn = 1;
1051                 } else
1052                     pn = 0;
1053             } else {
1054                 lnk = pn = 1;
1055                 if (Efsysl && !isefsys(pbuf, "UNKNtxt", 1, NULL, NULL))
1056                     pn = 0;
1057                 else {
1058                     ss = SB_ALL;
1059                     if (HasNFS) {
1060                         if ((sv = statsafely(path, &sb))) {
1061                             sv = statEx(pbuf, &sb,  &ss);
1062                             if (!sv && (ss & SB_DEV) && (ss & SB_INO))
1063                                 txts = 1;
1064                         }
1065                     } else
1066                         sv = stat(path, &sb);
1067                     if (sv) {
1068                         ss = 0;
1069                         if (!Fwarn) {
1070                             (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
1071                                 strerror(errno));
1072                             nmabuf[sizeof(nmabuf) - 1] = '\0';
1073                             (void) add_nma(nmabuf, strlen(nmabuf));
1074                         }
1075                     } else
1076                         txts = 1;
1077                 }
1078             }
1079             if (pn) {
1080                 (void) process_proc_node(lnk ? pbuf : path,
1081                                          path, &sb, ss,
1082                                          (struct stat *)NULL, 0);
1083                 if (Lf->sf)
1084                     link_lfile();
1085             }
1086         }
1087 /*
1088  * Process the ID's memory map info.
1089  */
1090         if (!Ckscko) {
1091             (void) make_proc_path(idp, idpl, &path, &pathl, "maps");
1092             (void) process_proc_map(path, txts ? &sb : (struct stat *)NULL,
1093                                     txts ? ss : 0);
1094         }
1095
1096 #if     defined(HASSELINUX)
1097 /*
1098  * Process the PID's SELinux context.
1099  */
1100         if (Fcntx) {
1101
1102         /*
1103          * If the -Z (cntx) option was specified, match the valid contexts.
1104          */
1105             errno = 0;
1106             if (getpidcon(pid, &Lp->cntx) == -1) {
1107                 Lp->cntx = (char *)NULL;
1108                 if (!Fwarn) {
1109                     (void) snpf(nmabuf, sizeof(nmabuf),
1110                         "(getpidcon: %s)", strerror(errno));
1111                     if (!(Lp->cntx = strdup(nmabuf))) {
1112                         (void) fprintf(stderr,
1113                             "%s: no context error space: PID %ld",
1114                             Pn, (long)Lp->pid);
1115                         Exit(1);
1116                     }
1117                 }
1118             } else if (CntxArg) {
1119
1120             /*
1121              * See if context includes the process.
1122              */
1123                 for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
1124                     if (cmp_cntx_eq(Lp->cntx, cntxp->cntx)) {
1125                         cntxp->f = 1;
1126                         Lp->pss |= PS_PRI;
1127                         Lp->sf |= SELCNTX;
1128                         break;
1129                     }
1130                 }
1131             }
1132         }
1133 #endif  /* defined(HASSELINUX) */
1134
1135 /*
1136  * Process the ID's file descriptor directory.
1137  */
1138         if ((i = make_proc_path(idp, idpl, &dpath, &dpathl, "fd/")) < 3)
1139             return(0);
1140         dpath[i - 1] = '\0';
1141         if ((OffType == 2)
1142         &&  ((j = make_proc_path(idp, idpl, &ipath, &ipathl, "fdinfo/")) >= 7))
1143             oty = 1;
1144         else
1145             oty = 0;
1146         if (!(fdp = opendir(dpath))) {
1147             if (!Fwarn) {
1148                 (void) snpf(nmabuf, sizeof(nmabuf), "%s (opendir: %s)",
1149                     dpath, strerror(errno));
1150                 alloc_lfile("NOFD", -1);
1151                 nmabuf[sizeof(nmabuf) - 1] = '\0';
1152                 (void) add_nma(nmabuf, strlen(nmabuf));
1153                 link_lfile();
1154             }
1155             return(0);
1156         }
1157         dpath[i - 1] = '/';
1158         while ((fp = readdir(fdp))) {
1159             if (nm2id(fp->d_name, &fd, &n))
1160                 continue;
1161             (void) make_proc_path(dpath, i, &path, &pathl, fp->d_name);
1162             (void) alloc_lfile((char *)NULL, fd);
1163             if (getlinksrc(path, pbuf, sizeof(pbuf), &rest) < 1) {
1164                 zeromem((char *)&sb, sizeof(sb));
1165                 lnk = ss = 0;
1166                 if (!Fwarn) {
1167                     (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
1168                         strerror(errno));
1169                     nmabuf[sizeof(nmabuf) - 1] = '\0';
1170                     (void) add_nma(nmabuf, strlen(nmabuf));
1171                     pn = 1;
1172                 } else
1173                     pn = 0;
1174             } else {
1175                 lnk = 1;
1176                 if (Efsysl && !isefsys(pbuf, "UNKNfd", 1, NULL, &lfr)) {
1177                     efs = 1;
1178                     pn = 0;
1179                 } else {
1180                     if (HasNFS) {
1181                         if (lstatsafely(path, &lsb)) {
1182                             (void) statEx(pbuf, &lsb, &ls);
1183                             enls = errno;
1184                         } else {
1185                             enls = 0;
1186                             ls = SB_ALL;
1187                         }
1188                         if (statsafely(path, &sb)) {
1189                             (void) statEx(pbuf, &sb, &ss);
1190                             enss = errno;
1191                         } else {
1192                             enss = 0;
1193                             ss = SB_ALL;
1194                         }
1195                     } else {
1196                         ls = lstat(path, &lsb) ? 0 : SB_ALL;
1197                         enls = errno;
1198                         ss = stat(path, &sb) ? 0 : SB_ALL;
1199                         enss = errno;
1200                     }
1201                     if (!ls && !Fwarn) {
1202                         (void) snpf(nmabuf, sizeof(nmabuf), "lstat: %s)",
1203                             strerror(enls));
1204                         nmabuf[sizeof(nmabuf) - 1] = '\0';
1205                         (void) add_nma(nmabuf, strlen(nmabuf));
1206                     }
1207                     if (!ss && !Fwarn) {
1208                         (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
1209                             strerror(enss));
1210                         nmabuf[sizeof(nmabuf) - 1] = '\0';
1211                         (void) add_nma(nmabuf, strlen(nmabuf));
1212                     }
1213                     if (Ckscko) {
1214                         if ((ss & SB_MODE)
1215                         &&  ((sb.st_mode & S_IFMT) == S_IFSOCK))
1216                         {
1217                             pn = 1;
1218                         } else
1219                             pn = 0;
1220                     } else
1221                         pn = 1;
1222                 }
1223             }
1224             if (pn || (efs && lfr && oty)) {
1225                 if (oty) {
1226                     (void) make_proc_path(ipath, j, &pathi, &pathil,
1227                                           fp->d_name);
1228                     if ((av = get_fdinfo(pathi,FDINFO_ALL,&fi)) & FDINFO_POS) {
1229                         if (efs) {
1230                             if (Foffset) {
1231                                 lfr->off = (SZOFFTYPE)fi.pos;
1232                                 lfr->off_def = 1;
1233                             }
1234                         } else {
1235                             ls |= SB_SIZE;
1236                             lsb.st_size = fi.pos;
1237                         }
1238                     } else
1239                         ls &= ~SB_SIZE;
1240
1241 #if     !defined(HASNOFSFLAGS)
1242                     if ((av & FDINFO_FLAGS) && (Fsv & FSV_FG)) {
1243                         if (efs) {
1244                             lfr->ffg = (long)fi.flags;
1245                             lfr->fsv |= FSV_FG;
1246                         } else {
1247                             Lf->ffg = (long)fi.flags;
1248                             Lf->fsv |= FSV_FG;
1249                         }
1250                      }
1251 # endif /* !defined(HASNOFSFLAGS) */
1252
1253                 }
1254                 if (pn) {
1255                     process_proc_node(lnk ? pbuf : path, path, &sb, ss, &lsb,
1256                                       ls);
1257                     if ((Lf->ntype == N_ANON_INODE) && rest && *rest)
1258                         enter_nm(rest);
1259
1260 #if     defined(HASEPTOPTS) && defined(HASPTYEPT)
1261                     else if (FeptE
1262                          &&  Lf->rdev_def
1263                          &&  is_pty_ptmx(Lf->rdev)
1264                          &&  (av & FDINFO_TTY_INDEX)
1265                     ) {
1266                             enter_ptmxi(fi.tty_index);
1267                             Lf->tty_index = fi.tty_index;
1268                             Lf->sf |= SELPTYINFO;
1269                     }
1270 #endif  /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
1271
1272                     if (Lf->sf)
1273                         link_lfile();
1274                 }
1275             }
1276         }
1277         (void) closedir(fdp);
1278         return(0);
1279 }
1280
1281
1282 /*
1283  * process_proc_map() - process the memory map of a process
1284  */
1285
1286 static void
1287 process_proc_map(p, s, ss)
1288         char *p;                        /* path to process maps file */
1289         struct stat *s;                 /* executing text file state buffer */
1290         int ss;                         /* *s status -- i.e., SB_* values */
1291 {
1292         char buf[MAXPATHLEN + 1], *ep, fmtbuf[32], **fp, nmabuf[MAXPATHLEN + 1];
1293         dev_t dev;
1294         int ds, efs, en, i, mss, nf, sv;
1295         int eb = 6;
1296         INODETYPE inode;
1297         MALLOC_S len;
1298         long maj, min;
1299         FILE *ms;
1300         int ns = 0;
1301         struct stat sb;
1302         struct saved_map {
1303             dev_t dev;
1304             INODETYPE inode;
1305         };
1306         static struct saved_map *sm = (struct saved_map *)NULL;
1307         efsys_list_t *rep;
1308         static int sma = 0;
1309         static char *vbuf = (char *)NULL;
1310         static size_t vsz = (size_t)0;
1311 /*
1312  * Open the /proc/<pid>/maps file, assign a page size buffer to its stream,
1313  * and read it/
1314  */
1315         if (!(ms = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
1316             return;
1317         while (fgets(buf, sizeof(buf), ms)) {
1318             if ((nf = get_fields(buf, ":", &fp, &eb, 1)) < 7)
1319                 continue;                       /* not enough fields */
1320             if (!fp[6] || !*fp[6])
1321                 continue;                       /* no path name */
1322         /*
1323          * See if the path ends in " (deleted)".  If it does, strip the
1324          * " (deleted)" characters and remember that they were there.
1325          */
1326             if (((ds = (int)strlen(fp[6])) > 10)
1327             &&  !strcmp(fp[6] + ds - 10, " (deleted)"))
1328             {
1329                 *(fp[6] + ds - 10) = '\0';
1330             } else
1331                 ds = 0;
1332         /*
1333          * Assemble the major and minor device numbers.
1334          */
1335             ep = (char *)NULL;
1336             if (!fp[3] || !*fp[3]
1337             ||  (maj = strtol(fp[3], &ep, 16)) == LONG_MIN || maj == LONG_MAX
1338             ||  !ep || *ep)
1339                 continue;
1340             ep = (char *)NULL;
1341             if (!fp[4] || !*fp[4]
1342             ||  (min = strtol(fp[4], &ep, 16)) == LONG_MIN || min == LONG_MAX
1343             ||  !ep || *ep)
1344                 continue;
1345         /*
1346          * Assemble the device and inode numbers.  If they are both zero, skip
1347          * the entry.
1348          */
1349             dev = (dev_t)makedev((int)maj, (int)min);
1350             if (!fp[5] || !*fp[5])
1351                 continue;
1352             ep = (char *)NULL;
1353             if ((inode = strtoull(fp[5], &ep, 0)) == ULLONG_MAX
1354             ||  !ep || *ep)
1355                 continue;
1356             if (!dev && !inode)
1357                 continue;
1358         /*
1359          * See if the device + inode pair match that of the executable.
1360          * If they do, skip this map entry.
1361          */
1362             if (s && (ss & SB_DEV) && (ss & SB_INO)
1363             &&  (dev == s->st_dev) && (inode == (INODETYPE)s->st_ino))
1364                 continue;
1365         /*
1366          * See if this device + inode pair has already been processed as
1367          * a map entry.
1368          */
1369             for (i = 0; i < ns; i++) {
1370                 if (dev == sm[i].dev && inode == sm[i].inode)
1371                     break;
1372             }
1373             if (i < ns)
1374                 continue;
1375         /*
1376          * Record the processing of this map entry's device and inode pair.
1377          */
1378             if (ns >= sma) {
1379                 sma += 10;
1380                 len = (MALLOC_S)(sma * sizeof(struct saved_map));
1381                 if (sm)
1382                     sm = (struct saved_map *)realloc(sm, len);
1383                 else
1384                     sm = (struct saved_map *)malloc(len);
1385                 if (!sm) {
1386                     (void) fprintf(stderr,
1387                         "%s: can't allocate %d bytes for saved maps, PID %d\n",
1388                         Pn, (int)len, Lp->pid);
1389                     Exit(1);
1390                 }
1391             }
1392             sm[ns].dev = dev;
1393             sm[ns++].inode = inode;
1394         /*
1395          * Allocate space for the mapped file, then get stat(2) information
1396          * for it.  Skip the stat(2) operation if this is on an exempt file
1397          * system.
1398          */
1399             alloc_lfile("mem", -1);
1400             if (Efsysl && !isefsys(fp[6], (char *)NULL, 0, &rep, NULL))
1401                 efs = sv = 1;
1402             else
1403                 efs = 0;
1404             if (!efs) {
1405                 if (HasNFS)
1406                     sv = statsafely(fp[6], &sb);
1407                 else
1408                     sv = stat(fp[6], &sb);
1409             }
1410             if (sv || efs) {
1411                 en = errno;
1412             /*
1413              * Applying stat(2) to the file was not possible (file is on an
1414              * exempt file system) or stat(2) failed, so manufacture a partial
1415              * stat(2) reply from the process' maps file entry.
1416              *
1417              * If the file has been deleted, reset its type to "DEL";
1418              * otherwise generate a stat() error name addition.
1419              */
1420                 zeromem((char *)&sb, sizeof(sb));
1421                 sb.st_dev = dev;
1422                 sb.st_ino = (ino_t)inode;
1423                 sb.st_mode = S_IFREG;
1424                 mss = SB_DEV | SB_INO | SB_MODE;
1425                 if (ds)
1426                     alloc_lfile("DEL", -1);
1427                 else if (!efs && !Fwarn) {
1428                     (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
1429                         strerror(en));
1430                     nmabuf[sizeof(nmabuf) - 1] = '\0';
1431                     (void) add_nma(nmabuf, strlen(nmabuf));
1432                 }
1433             } else if ((sb.st_dev != dev) || ((INODETYPE)sb.st_ino != inode)) {
1434
1435             /*
1436              * The stat(2) device and inode numbers don't match those obtained
1437              * from the process' maps file.
1438              *
1439              * If the file has been deleted, reset its type to "DEL"; otherwise
1440              * generate inconsistency name additions.
1441              *
1442              * Manufacture a partial stat(2) reply from the maps file
1443              * information.
1444              */
1445                 if (ds)
1446                     alloc_lfile("DEL", -1);
1447                 else if (!Fwarn) {
1448                     char *sep;
1449
1450                     if (sb.st_dev != dev) {
1451                         (void) snpf(nmabuf, sizeof(nmabuf),
1452                             "(path dev=%d,%d%s",
1453                             GET_MAJ_DEV(sb.st_dev), GET_MIN_DEV(sb.st_dev),
1454                             ((INODETYPE)sb.st_ino == inode) ? ")" : ",");
1455                         nmabuf[sizeof(nmabuf) - 1] = '\0';
1456                         (void) add_nma(nmabuf, strlen(nmabuf));
1457                         sep = "";
1458                     } else
1459                         sep = "(path ";
1460                     if ((INODETYPE)sb.st_ino != inode) {
1461                         (void) snpf(fmtbuf, sizeof(fmtbuf), "%%sinode=%s)",
1462                             InodeFmt_d);
1463                         (void) snpf(nmabuf, sizeof(nmabuf), fmtbuf,
1464                             sep, (INODETYPE)sb.st_ino);
1465                         nmabuf[sizeof(nmabuf) - 1] = '\0';
1466                         (void) add_nma(nmabuf, strlen(nmabuf));
1467                     }
1468                 }
1469                 zeromem((char *)&sb, sizeof(sb));
1470                 sb.st_dev = dev;
1471                 sb.st_ino = (ino_t)inode;
1472                 sb.st_mode = S_IFREG;
1473                 mss = SB_DEV | SB_INO | SB_MODE;
1474             } else
1475                 mss = SB_ALL;
1476         /*
1477          * Record the file's information.
1478          */
1479             if (!efs)
1480                 process_proc_node(fp[6], fp[6], &sb, mss, (struct stat *)NULL,
1481                                   0);
1482             else {
1483
1484             /*
1485              * If this file is on an exempt file system, complete the lfile
1486              * structure, but change its type and add the exemption note to
1487              * the NAME column.
1488              */
1489                 Lf->dev = sb.st_dev;
1490                 Lf->inode = (ino_t)sb.st_ino;
1491                 Lf->dev_def = Lf->inp_ty = 1;
1492                 (void) enter_nm(fp[6]);
1493                 (void) snpf(Lf->type, sizeof(Lf->type), "%s",
1494                             (ds ? "UNKNdel" : "UNKNmem"));
1495                 (void) snpf(nmabuf, sizeof(nmabuf), "(%ce %s)",
1496                     rep->rdlnk ? '+' : '-', rep->path);
1497                 nmabuf[sizeof(nmabuf) - 1] = '\0';
1498                 (void) add_nma(nmabuf, strlen(nmabuf));
1499             }
1500             if (Lf->sf)
1501                 link_lfile();
1502         }
1503         (void) fclose(ms);
1504 }
1505
1506
1507 /*
1508  * read_id_stat() - read ID (PID or LWP ID) status
1509  *
1510  * return: -1 == ID is unavailable
1511  *          0 == ID OK
1512  *          1 == ID is a zombie
1513  *          2 == ID is a thread
1514  */
1515
1516 static int
1517 read_id_stat(p, id, cmd, ppid, pgid)
1518         char *p;                        /* path to status file */
1519         int id;                         /* ID: PID or LWP */
1520         char **cmd;                     /* malloc'd command name */
1521         int *ppid;                      /* returned parent PID for PID type */
1522         int *pgid;                      /* returned process group ID for PID
1523                                          * type */
1524 {
1525         char buf[MAXPATHLEN], *cp, *cp1, **fp;
1526         int ch, cx, es, nf, pc;
1527         static char *cbf = (char *)NULL;
1528         static MALLOC_S cbfa = 0;
1529         FILE *fs;
1530         static char *vbuf = (char *)NULL;
1531         static size_t vsz = (size_t)0;
1532 /*
1533  * Open the stat file path, assign a page size buffer to its stream,
1534  * and read the file's first line.
1535  */
1536         if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
1537             return(-1);
1538         if (!(cp = fgets(buf, sizeof(buf), fs))) {
1539
1540 read_id_stat_exit:
1541
1542             (void) fclose(fs);
1543             return(-1);
1544         }
1545 /*
1546  * Skip to the first field, and make sure it is a matching ID.
1547  */
1548         cp1 = cp;
1549         while (*cp && (*cp != ' ') && (*cp != '\t'))
1550             cp++;
1551         if (*cp)
1552             *cp = '\0';
1553         if (atoi(cp1) != id)
1554             goto read_id_stat_exit;
1555 /*
1556  * The second field should contain the command, enclosed in parentheses.
1557  * If it also has embedded '\n' characters, replace them with '?' characters,
1558  * accumulating command characters until a closing parentheses appears.
1559  *
1560  */
1561         for (++cp; *cp && (*cp == ' '); cp++)
1562                 ;
1563         if (!cp || (*cp != '('))
1564             goto read_id_stat_exit;
1565         cp++;
1566         pc = 1;                 /* start the parenthesis balance count at 1 */
1567 /*
1568  * Enter the command characters safely.  Supply them from the initial read
1569  * of the stat file line, a '\n' if the initial read didn't yield a ')'
1570  * command closure, or by reading the rest of the command a character at
1571  * a time from the stat file.  Count embedded '(' characters and balance
1572  * them with embedded ')' characters.  The opening '(' starts the balance
1573  * count at one.
1574  */
1575         for (cx = es = 0;;) {
1576             if (!es)
1577                 ch = *cp++;
1578             else {
1579                 if ((ch = fgetc(fs)) == EOF)
1580                     goto read_id_stat_exit;
1581             }
1582             if (ch == '(')              /* a '(' advances the balance count */
1583                 pc++;
1584             if (ch == ')') {
1585             
1586             /*
1587              * Balance parentheses when a closure is encountered.  When
1588              * they are balanced, this is the end of the command.
1589              */
1590                 pc--;
1591                 if (!pc)
1592                     break;
1593             }
1594             if ((cx + 2) > cbfa)
1595                 cbfa = alloc_cbf((cx + 2), &cbf, cbfa);
1596             cbf[cx] = ch;
1597             cx++;
1598             cbf[cx] = '\0';
1599             if (!es && !*cp)
1600                 es = 1;         /* Switch to fgetc() when a '\0' appears. */
1601         }
1602         *cmd = cbf;
1603 /*
1604  * Read the remainder of the stat line if it was necessary to read command
1605  * characters individually from the stat file.
1606  *
1607  * Separate the reminder into fields.
1608  */
1609         if (es)
1610             cp = fgets(buf, sizeof(buf), fs);
1611         (void) fclose(fs);
1612         if (!cp || !*cp)
1613             return(-1);
1614         if ((nf = get_fields(cp, (char *)NULL, &fp, (int *)NULL, 0)) < 3)
1615             return(-1);
1616 /*
1617  * Convert and return parent process (fourth field) and process group (fifth
1618  * field) IDs.
1619  */
1620         if (fp[1] && *fp[1])
1621             *ppid = atoi(fp[1]);
1622         else
1623             return(-1);
1624         if (fp[2] && *fp[2])
1625             *pgid = atoi(fp[2]);
1626         else
1627             return(-1);
1628 /*
1629  * Check the state in the third field.  If it is 'Z', return that indication.
1630  */
1631         if (fp[0] && !strcmp(fp[0], "Z"))
1632             return(1);
1633         else if (fp[0] && !strcmp(fp[0], "T"))
1634             return(2);
1635         return(0);
1636 }
1637
1638
1639 /*
1640  * statEx() - extended stat() to get device numbers when a "safe" stat has
1641  *            failed and the system has an NFS mount
1642  *
1643  * Note: this function was suggested by Paul Szabo as a way to get device
1644  *       numbers for NFS files when an NFS mount point has the root_squash
1645  *       option set.  In that case, even if lsof is setuid(root), the identity
1646  *       of its requests to stat() NFS files lose root permission and may fail.
1647  *
1648  *       This function should be used only when links have been successfully
1649  *       resolved in the /proc path by getlinksrc().
1650  */
1651
1652 static int
1653 statEx(p, s, ss)
1654         char *p;                        /* file path */
1655         struct stat *s;                 /* stat() result -- NULL if none
1656                                          * wanted */
1657         int *ss;                        /* stat() status --  SB_* values */
1658 {
1659         static size_t ca = 0;
1660         static char *cb = NULL;
1661         char *cp;
1662         int ensv = ENOENT;
1663         struct stat sb;
1664         int st = 0;
1665         size_t sz;
1666 /*
1667  * Make a copy of the path.
1668  */
1669         sz = strlen(p);
1670         if ((sz + 1) > ca) {
1671             if (cb)
1672                 cb = (char *)realloc((MALLOC_P *)cb, sz + 1);
1673             else
1674                 cb = (char *)malloc(sz + 1);
1675             if (!cb) {
1676                 (void) fprintf(stderr,
1677                     "%s: PID %ld: no statEx path space: %s\n",
1678                     Pn, (long)Lp->pid, p);
1679                 Exit(1);
1680             }
1681             ca = sz + 1;
1682         }
1683         (void) strcpy(cb, p);
1684 /*
1685  * Trim trailing leaves from the end of the path one at a time and do a safe
1686  * stat() on each trimmed result.  Stop when a safe stat() succeeds or doesn't
1687  * fail because of EACCES or EPERM.
1688  */
1689         for (cp = strrchr(cb, '/'); cp && (cp != cb);) {
1690             *cp = '\0';
1691             if (!statsafely(cb, &sb)) {
1692                 st = 1;
1693                 break;
1694             }
1695             ensv = errno;
1696             if ((ensv != EACCES) && (ensv != EPERM))
1697                 break;
1698             cp = strrchr(cb, '/');
1699         }
1700 /*
1701  * If a stat() on a trimmed result succeeded, form partial results containing
1702  * only the device and raw device numbers.
1703  */
1704         zeromem((char *)s, sizeof(struct stat));
1705         if (st) {
1706             errno = 0;
1707             s->st_dev = sb.st_dev;
1708             s->st_rdev = sb.st_rdev;
1709             *ss = SB_DEV | SB_RDEV;
1710             return(0);
1711         }
1712         errno = ensv;
1713         *ss = 0;
1714         return(1);
1715 }