2 * main.c - common main function for lsof
4 * V. Abell, Purdue University
9 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
10 * 47907. All rights reserved.
12 * Written by Victor A. Abell
14 * This software is not subject to any license of the American Telephone
15 * and Telegraph Company or the Regents of the University of California.
17 * Permission is granted to anyone to use this software for any purpose on
18 * any computer system, and to alter it and redistribute it freely, subject
19 * to the following restrictions:
21 * 1. Neither the authors nor Purdue University are responsible for any
22 * consequences of the use of this software.
24 * 2. The origin of this software must not be misrepresented, either by
25 * explicit claim or by omission. Credit to the authors and Purdue
26 * University must appear in documentation and sources.
28 * 3. Altered versions must be plainly marked as such, and must not be
29 * misrepresented as being the original software.
31 * 4. This notice may not be removed or altered.
35 static char copyright[] =
36 "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
37 static char *rcsid = "$Id: main.c,v 1.59 2018/03/26 21:50:45 abe Exp $";
48 static int GObk[] = { 1, 1 }; /* option backspace values */
49 static char GOp; /* option prefix -- '+' or '-' */
50 static char *GOv = (char *)NULL; /* option `:' value pointer */
51 static int GOx1 = 1; /* first opt[][] index */
52 static int GOx2 = 0; /* second opt[][] index */
55 _PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, int *err));
56 _PROTOTYPE(static char *sv_fmt_str,(char *f));
60 * main() - main function for lsof
68 int ad, c, i, n, rv, se1, se2, ss;
73 char *fmtr = (char *)NULL;
77 struct nwad *np, *npn;
82 struct lproc **slp = (struct lproc **)NULL;
84 struct str_lst *str, *strt;
88 #if defined(HAS_STRFTIME)
89 char *fmt = (char *)NULL;
90 size_t fmtl = (size_t)0;
91 #endif /* defined(HAS_STRFTIME) */
95 #endif /* defined(HASZONES) */
97 #if defined(HASSELINUX)
99 * This stanza must be immediately before the "Save progam name." code, since
100 * it contains code itself.
104 CntxStatus = is_selinux_enabled() ? 1 : 0;
105 #endif /* defined(HASSELINUX) */
110 if ((Pn = strrchr(argv[0], '/')))
115 * Close enough file descriptors above 2 that library functions will have
118 * Make sure stderr, stdout, and stdin are open descriptors. Open /dev/null
119 * for ones that aren't. Be terse.
121 * Make sure umask allows lsof to define its own file permissions.
124 if ((MaxFd = (int) GET_MAX_FD()) < 53)
127 #if defined(HAS_CLOSEFROM)
129 #else /* !defined(HAS_CLOSEFROM) */
130 for (i = 3; i < MaxFd; i++)
132 #endif /* !defined(HAS_CLOSEFROM) */
134 while (((i = open("/dev/null", O_RDWR, 0)) >= 0) && (i < 2))
142 #if defined(HASSETLOCALE)
144 * Set locale to environment's definition.
146 (void) setlocale(LC_CTYPE, "");
147 #endif /* defined(HASSETLOCALE) */
150 * Common initialization.
153 if ((Mygid = (gid_t)getgid()) != getegid())
156 if ((Myuid = (uid_t)getuid()) && !Euid)
158 if (!(Namech = (char *)malloc(MAXPATHLEN + 1))) {
159 (void) fprintf(stderr, "%s: no space for name buffer\n", Pn);
162 Namechl = (size_t)(MAXPATHLEN + 1);
164 * Create option mask.
166 (void) snpf(options, sizeof(options),
167 "?a%sbc:%sD:d:%s%sf:F:g:hi:%s%slL:%s%snNo:Op:Pr:%ss:S:tT:u:UvVwx:%s%s%s",
169 #if defined(HAS_AFS) && defined(HASAOPT)
171 #else /* !defined(HAS_AFS) || !defined(HASAOPT) */
173 #endif /* defined(HAS_AFS) && defined(HASAOPT) */
175 #if defined(HASNCACHE)
177 #else /* !defined(HASNCACHE) */
179 #endif /* defined(HASNCACHE) */
183 #else /* !defined(HASEOPT) */
185 #endif /* defined(HASEOPT) */
187 #if defined(HASEPTOPTS)
189 #else /* !defined(HASEPTOPTS) */
191 #endif /* defined(HASEPTOPTS) */
195 #else /* !defined(HASKOPT) */
197 #endif /* defined(HASKOPT) */
199 #if defined(HASTASKS)
201 #else /* !defined(HASTASKS) */
203 #endif /* defined(HASTASKS) */
205 #if defined(HASMOPT) || defined(HASMNTSUP)
207 #else /* !defined(HASMOPT) && !defined(HASMNTSUP) */
209 #endif /* defined(HASMOPT) || defined(HASMNTSUP) */
211 #if defined(HASNORPC_H)
213 #else /* !defined(HASNORPC_H) */
215 #endif /* defined(HASNORPC_H) */
219 #else /* !defined(HASPPID) */
221 #endif /* defined(HASPPID) */
224 # if defined(HASXOPT_ROOT)
225 (Myuid == 0) ? "X" : "",
226 # else /* !defined(HASXOPT_ROOT) */
228 # endif /* defined(HASXOPT_ROOT) */
229 #else /* !defined(HASXOPT) */
231 #endif /* defined(HASXOPT) */
233 #if defined(HASZONES)
235 #else /* !defined(HASZONES) */
237 #endif /* defined(HASZONES) */
239 #if defined(HASSELINUX)
241 #else /* !defined(HASSELINUX) */
243 #endif /* defined(HASSELINUX) */
247 * Loop through options.
249 while ((c = GetOpt(argc, argv, options, &rv)) != EOF) {
259 #if defined(HAS_AFS) && defined(HASAOPT)
261 if (!GOv || *GOv == '-' || *GOv == '+') {
262 (void) fprintf(stderr, "%s: -A not followed by path\n", Pn);
271 #endif /* defined(HAS_AFS) && defined(HASAOPT) */
278 if (!GOv || (*GOv == '-') || (*GOv == '+')
279 || !isdigit((int)*GOv))
281 (void) fprintf(stderr,
282 "%s: +c not followed by width number\n", Pn);
289 CmdLim = TaskCmdLim = atoi(GOv);
291 #if defined(MAXSYSCMDL)
292 if (CmdLim > MAXSYSCMDL) {
293 (void) fprintf(stderr,
294 "%s: +c %d > what system provides (%d)\n",
295 Pn, CmdLim, MAXSYSCMDL);
298 #endif /* defined(MAXSYSCMDL) */
303 if (GOv && (*GOv == '/')) {
304 if (enter_cmd_rx(GOv))
307 if (enter_str_lst("-c", GOv, &Cmdl, &Cmdni, &Cmdnx))
310 #if defined(MAXSYSCMDL)
311 else if (Cmdl->len > MAXSYSCMDL) {
312 (void) fprintf(stderr, "%s: \"-c ", Pn);
313 (void) safestrprt(Cmdl->str, stderr, 2);
314 (void) fprintf(stderr, "\" length (%d) > what system",
316 (void) fprintf(stderr, " provides (%d)\n",
318 Cmdl->len = 0; /* (to avoid later error report) */
321 #endif /* defined(MAXSYSCMDL) */
326 #if defined(HASNCACHE)
328 Fncache = (GOp == '-') ? 0 : 1;
331 #endif /* defined(HASNCACHE) */
334 if (enter_dir(GOv, 0))
347 if (enter_dir(GOv, 1))
355 #if defined(HASDCACHE)
356 if (ctrl_dcache(GOv))
358 #else /* !defined(HASDCACHE) */
359 (void) fprintf(stderr, "%s: unsupported option: -D\n", Pn);
361 #endif /* defined(HASDCACHE) */
368 if (enter_efsys(GOv, ((GOp == '+') ? 1 : 0)))
371 #endif /* defined(HASEOPT) */
373 #if defined(HASEPTOPTS)
375 FeptE = (GOp == '+') ? 2 : 1;
377 #endif /* defined(HASEPTOPTS) */
380 if (!GOv || *GOv == '-' || *GOv == '+') {
381 Ffilesys = (GOp == '+') ? 2 : 1;
389 #if defined(HASFSTRUCT)
390 for (; *GOv; GOv++) {
393 # if !defined(HASNOFSCOUNT)
400 Fsv &= (unsigned char)~FSV_CT;
402 # endif /* !defined(HASNOFSCOUNT) */
404 # if !defined(HASNOFSADDR)
411 Fsv &= (unsigned char)~FSV_FA;
413 # endif /* !defined(HASNOFSADDR) */
415 # if !defined(HASNOFSFLAGS)
422 Fsv &= (unsigned char)~FSV_FG;
423 FsvFlagX = (*GOv == 'G') ? 1 : 0;
425 # endif /* !defined(HASNOFSFLAGS) */
427 # if !defined(HASNOFSNADDR)
434 Fsv &= (unsigned char)~FSV_NI;
436 # endif /* !defined(HASNOFSNADDR */
439 (void) fprintf(stderr,
440 "%s: unknown file struct option: %c\n", Pn, *GOv);
444 #else /* !defined(HASFSTRUCT) */
445 (void) fprintf(stderr,
446 "%s: unknown string for %cf: %s\n", Pn, GOp, GOv);
448 #endif /* defined(HASFSTRUCT) */
452 if (!GOv || *GOv == '-' || *GOv == '+'
453 || strcmp(GOv, "0") == 0) {
455 if (*GOv == '-' || *GOv == '+') {
458 } else if (*GOv == '0')
461 for (i = 0; FieldSel[i].nm; i++) {
463 #if !defined(HASPPID)
464 if (FieldSel[i].id == LSOF_FID_PPID)
466 #endif /* !defined(HASPPID) */
468 #if !defined(HASTASKS)
469 if (FieldSel[i].id == LSOF_FID_TCMD)
471 #endif /* !defined(HASTASKS) */
473 #if !defined(HASFSTRUCT)
474 if (FieldSel[i].id == LSOF_FID_CT
475 || FieldSel[i].id == LSOF_FID_FA
476 || FieldSel[i].id == LSOF_FID_FG
477 || FieldSel[i].id == LSOF_FID_NI)
479 #endif /* !defined(HASFSTRUCT) */
481 #if defined(HASSELINUX)
482 if ((FieldSel[i].id == LSOF_FID_CNTX) && !CntxStatus)
484 #else /* !defined(HASSELINUX) */
485 if (FieldSel[i].id == LSOF_FID_CNTX)
487 #endif /* !defined(HASSELINUX) */
489 if (FieldSel[i].id == LSOF_FID_RDEV)
490 continue; /* for compatibility */
492 #if !defined(HASTASKS)
493 if (FieldSel[i].id == LSOF_FID_TID)
495 #endif /* !defined(HASTASKS) */
497 #if !defined(HASZONES)
498 if (FieldSel[i].id == LSOF_FID_ZONE)
500 #endif /* !defined(HASZONES) */
503 if (FieldSel[i].opt && FieldSel[i].ov)
504 *(FieldSel[i].opt) |= FieldSel[i].ov;
507 #if defined(HASFSTRUCT)
508 Ffield = FsvFlagX = 1;
509 #else /* !defined(HASFSTRUCT) */
511 #endif /* defined(HASFSTRUCT) */
515 if (strcmp(GOv, "?") == 0) {
519 for (; *GOv; GOv++) {
520 for (i = 0; FieldSel[i].nm; i++) {
522 #if !defined(HASPPID)
523 if (FieldSel[i].id == LSOF_FID_PPID)
525 #endif /* !defined(HASPPID) */
527 #if !defined(HASTASKS)
528 if (FieldSel[i].id == LSOF_FID_TCMD)
530 #endif /* !defined(HASTASKS) */
532 #if !defined(HASFSTRUCT)
533 if (FieldSel[i].id == LSOF_FID_CT
534 || FieldSel[i].id == LSOF_FID_FA
535 || FieldSel[i].id == LSOF_FID_FG
536 || FieldSel[i].id == LSOF_FID_NI)
538 #endif /* !defined(HASFSTRUCT) */
540 #if !defined(HASTASKS)
541 if (FieldSel[i].id == LSOF_FID_TID)
543 #endif /* !defined(HASTASKS) */
545 if (FieldSel[i].id == *GOv) {
547 if (FieldSel[i].opt && FieldSel[i].ov)
548 *(FieldSel[i].opt) |= FieldSel[i].ov;
550 #if defined(HASFSTRUCT)
551 if (i == LSOF_FIX_FG)
553 #endif /* defined(HASFSTRUCT) */
555 if (i == LSOF_FIX_TERM)
560 if ( ! FieldSel[i].nm) {
561 (void) fprintf(stderr,
562 "%s: unknown field: %c\n", Pn, *GOv);
570 if (*GOv == '-' || *GOv == '+') {
573 } else if (enter_id(PGID, GOv))
583 if (!GOv || *GOv == '-' || *GOv == '+') {
592 if (enter_network_address(GOv))
598 if (!GOv || *GOv == '-' || *GOv == '+') {
599 (void) fprintf(stderr, "%s: -k not followed by path\n", Pn);
608 #endif /* defined(HASKOPT) */
610 #if defined(HASTASKS)
612 if (!GOv || *GOv == '-' || *GOv == '+') {
621 if (!strcasecmp(GOv, "i")) {
624 Selflags &= ~SELTASK;
626 (void) fprintf(stderr,
627 "%s: -K not followed by i (but by %s)\n", Pn, GOv);
632 #endif /* defined(HASTASKS) */
638 Fnlink = (GOp == '+') ? 1 : 0;
639 if (!GOv || *GOv == '-' || *GOv == '+') {
647 for (cp = GOv, l = 0l, n = 0; *cp; cp++) {
648 if (!isdigit((unsigned char)*cp))
650 l = (l * 10l) + ((long)*cp - (long)'0');
655 (void) fprintf(stderr,
656 "%s: no number may follow -L\n", Pn);
660 Selflags |= SELNLINK;
670 #if defined(HASMOPT) || defined(HASMNTSUP)
674 # if defined(HASMOPT)
675 if (!GOv || *GOv == '-' || *GOv == '+') {
676 (void) fprintf(stderr,
677 "%s: -m not followed by path\n", Pn);
685 # else /* !defined(HASMOPT) */
686 (void) fprintf(stderr, "%s: -m not supported\n", Pn);
688 # endif /* defined(HASMOPT) */
690 } else if (GOp == '+') {
692 # if defined(HASMNTSUP)
693 if (!GOv || *GOv == '-' || *GOv == '+') {
703 # else /* !defined(HASMNTSUP) */
704 (void) fprintf(stderr, "%s: +m not supported\n", Pn);
706 # endif /* defined(HASMNTSUP) */
709 (void) fprintf(stderr, "%s: %cm not supported\n", Pn, GOp);
713 #endif /* defined(HASMOPT) || defined(HASMNTSUP) */
715 #if !defined(HASNORPC_H)
717 FportMap = (GOp == '+') ? 1 : 0;
719 #endif /* !defined(HASNORPC_H) */
722 Fhost = (GOp == '-') ? 0 : 1;
728 if (!GOv || *GOv == '-' || *GOv == '+') {
736 for (cp = GOv, i = n = 0; *cp; cp++) {
737 if (!isdigit((unsigned char)*cp))
739 i = (i * 10) + ((int)*cp - '0');
752 Fovhd = (GOp == '-') ? 1 : 0;
755 if (enter_id(PID, GOv))
759 Fport = (GOp == '-') ? 0 : 1;
764 if (!GOv || *GOv == '-' || *GOv == '+') {
772 for (cp = GOv, i = n = 0; *cp; cp++) {
773 if (!isdigit((unsigned char)*cp))
775 i = (i * 10) + ((int)*cp - '0');
784 while(*cp && (*cp == ' '))
786 if (*cp != LSOF_FID_MARK) {
792 #if defined(HAS_STRFTIME)
795 * Collect the strftime(3) format and test it.
798 if ((fmtl = strlen(cp) + 1) < 1) {
799 (void) fprintf(stderr, "%s: <fmt> too short: \"%s\"\n",
804 fmtl = (fmtl * 8) + 1;
805 if (!(fmtr = (char *)malloc((MALLOC_S)fmtl))) {
806 (void) fprintf(stderr,
807 "%s: no space (%d) for <fmt> result: \"%s\"\n",
811 if (util_strftime(fmtr, fmtl - 1, fmt) < 1) {
812 (void) fprintf(stderr, "%s: illegal <fmt>: \"%s\"\n",
818 #else /* !defined(HAS_STRFTIME) */
819 (void) fprintf(stderr, "%s: m<fmt> not supported: \"%s\"\n",
822 #endif /* defined(HAS_STRFTIME) */
830 #endif /* defined(HASPPID) */
834 #if defined(HASTCPUDPSTATE)
835 if (!GOv || *GOv == '-' || *GOv == '+') {
842 if (enter_state_spec(GOv))
845 #else /* !defined(HASTCPUDPSTATE) */
847 #endif /* defined(HASTCPUDPSTATE) */
851 if (!GOv || *GOv == '-' || *GOv == '+') {
859 for (cp = GOv, i = n = 0; *cp; cp++) {
860 if (!isdigit((unsigned char)*cp))
862 i = (i * 10) + ((int)*cp - '0');
873 if (TmLimit < TMLIMMIN) {
874 (void) fprintf(stderr,
875 "%s: WARNING: -S time (%d) changed to %d\n",
876 Pn, TmLimit, TMLIMMIN);
884 if (!GOv || *GOv == '-' || *GOv == '+') {
885 Ftcptpi = (GOp == '-') ? 0 : TCPTPI_STATE;
892 for (Ftcptpi = 0; *GOv; GOv++) {
895 #if defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT)
897 Ftcptpi |= TCPTPI_FLAGS;
899 #endif /* defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT) */
901 #if defined(HASTCPTPIQ)
903 Ftcptpi |= TCPTPI_QUEUES;
905 #endif /* defined(HASTCPTPIQ) */
908 Ftcptpi |= TCPTPI_STATE;
911 #if defined(HASTCPTPIW)
913 Ftcptpi |= TCPTPI_WINDOWS;
915 #endif /* defined(HASTCPTPIW) */
918 (void) fprintf(stderr,
919 "%s: unsupported TCP/TPI info selection: %c\n",
939 Fwarn = (GOp == '+') ? 0 : 1;
942 if (!GOv || *GOv == '-' || *GOv == '+') {
950 for (; *GOv; GOv++) {
953 Fxover |= XO_FILESYS;
956 Fxover |= XO_SYMLINK;
959 (void) fprintf(stderr,
960 "%s: unknown cross-over option: %c\n",
970 Fxopt = Fxopt ? 0 : 1;
972 #endif /* defined(HASXOPT) */
974 #if defined(HASZONES)
977 if (GOv && (*GOv != '-') && (*GOv != '+')) {
980 * Add to the zone name argument hash.
982 if (enter_zone_arg(GOv))
989 #endif /* defined(HASZONES) */
991 #if defined(HASSELINUX)
994 (void) fprintf(stderr, "%s: -Z limited to SELinux\n", Pn);
998 if (GOv && (*GOv != '-') && (*GOv != '+')) {
1001 * Add to the context name argument hash.
1003 if (enter_cntx_arg(GOv))
1011 #endif /* defined(HASSELINUX) */
1014 (void) fprintf(stderr, "%s: unknown option (%c)\n", Pn, c);
1019 * If IgnTasks is set, remove SELTASK from SelAll and SelProc.
1021 SelAll = IgnTasks ? (SELALL & ~SELTASK) : SELALL;
1022 SelProc = IgnTasks ? (SELPROC & ~SELTASK) : SELPROC;
1024 * Check for argument consistency.
1026 if (Cmdnx && Cmdni) {
1029 * Check for command inclusion/exclusion conflicts.
1031 for (str = Cmdl; str; str = str->next) {
1033 for (strt = Cmdl; strt; strt = strt->next) {
1035 if (!strcmp(str->str, strt->str)) {
1036 (void) fprintf(stderr,
1037 "%s: -c^%s and -c%s conflict.\n",
1038 Pn, str->str, strt->str);
1047 #if defined(HASTCPUDPSTATE)
1048 if (TcpStXn && TcpStIn) {
1051 * Check for excluded and included TCP states.
1053 for (i = 0; i < TcpNstates; i++) {
1054 if (TcpStX[i] && TcpStI[i]) {
1055 (void) fprintf(stderr,
1056 "%s: can't include and exclude TCP state: %s\n",
1062 if (UdpStXn && UdpStIn) {
1065 * Check for excluded and included UDP states.
1067 for (i = 0; i < UdpNstates; i++) {
1068 if (UdpStX[i] && UdpStI[i]) {
1069 (void) fprintf(stderr,
1070 "%s: can't include and exclude UDP state: %s\n",
1076 #endif /* defined(HASTCPUDPSTATE) */
1078 if (Fsize && Foffset) {
1079 (void) fprintf(stderr, "%s: -o and -s are mutually exclusive\n",
1085 (void) fprintf(stderr,
1086 "%s: -F and -t are mutually exclusive\n", Pn);
1089 FieldSel[LSOF_FIX_PID].st = 1;
1091 #if defined(HAS_STRFTIME)
1095 * The field output marker format can't contain "%n" new line
1098 for (cp = strchr(fmt, '%'); cp; cp = strchr(cp, '%')) {
1100 (void) fprintf(stderr,
1101 "%s: %%n illegal in -r m<fmt> when -F has", Pn);
1102 (void) fprintf(stderr,
1103 " been specified: \"%s\"\n", fmt);
1106 } else if (*cp == '%')
1110 #endif /* defined(HAS_STRFTIME) */
1113 if (Fxover && !xover) {
1114 (void) fprintf(stderr, "%s: -x must accompany +d or +D\n", Pn);
1118 #if defined(HASEOPT)
1122 * If there are file systems specified by -e options, check them.
1124 efsys_list_t *ep; /* Efsysl pointer */
1125 struct mounts *mp, *mpw; /* local mount table pointers */
1127 if ((mp = readmnt())) {
1128 for (ep = Efsysl; ep; ep = ep->next) {
1129 for (mpw = mp; mpw; mpw = mpw->next) {
1130 if (!strcmp(mpw->dir, ep->path)) {
1136 (void) fprintf(stderr,
1137 "%s: \"-e %s\" is not a mounted file system.\n",
1144 #endif /* defined(HASEOPT) */
1146 if (DChelp || err || Fhelp || fh || version)
1147 usage(err ? 1 : 0, fh, version);
1149 * Reduce the size of Suid[], if necessary.
1151 if (Suid && Nuid && Nuid < Mxuid) {
1152 if (!(Suid = (struct seluid *)realloc((MALLOC_P *)Suid,
1153 (MALLOC_S)(sizeof(struct seluid) * Nuid))))
1155 (void) fprintf(stderr, "%s: can't realloc UID table\n", Pn);
1161 * Compute the selection flags.
1163 if ((Cmdl && Cmdni) || CmdRx)
1166 #if defined(HASSELINUX)
1168 Selflags |= SELCNTX;
1169 #endif /* defined(HASSELINUX) */
1179 if (Npgid && Npgidi)
1180 Selflags |= SELPGID;
1183 if (Nuid && Nuidincl)
1188 #if defined(HASZONES)
1190 Selflags |= SELZONE;
1191 #endif /* defined(HASZONES) */
1195 if (Selflags == 0) {
1197 (void) fprintf(stderr,
1198 "%s: no select options to AND via -a\n", Pn);
1203 if (GOx1 >= argc && (Selflags & (SELNA|SELNET)) != 0
1204 && (Selflags & ~(SELNA|SELNET)) == 0)
1209 * Get the device for DEVDEV_PATH.
1211 if (stat(DEVDEV_PATH, &sb)) {
1213 if ((ad = strcmp(DEVDEV_PATH, "/dev"))) {
1214 if ((ss = stat("/dev", &sb)))
1223 (void) fprintf(stderr, "%s: can't stat(%s): %s\n", Pn,
1224 DEVDEV_PATH, strerror(se1));
1226 (void) fprintf(stderr, "%s: can't stat(/dev): %s\n", Pn,
1234 * Process the file arguments.
1237 if (ck_file_arg(GOx1, argc, argv, Ffilesys, 0, (struct stat *)NULL))
1241 * Do dialect-specific initialization.
1247 #if defined(WILLDROPGID)
1249 * If this process isn't setuid(root), but it is setgid(not_real_gid),
1250 * relinquish the setgid power. (If it hasn't already been done.)
1253 #endif /* defined(WILLDROPGID) */
1256 #if defined(HASDCACHE)
1258 * If there is a device cache, prepare the device table.
1262 #endif /* defined(HASDCACHE) */
1265 * Define the size and offset print formats.
1267 (void) snpf(options, sizeof(options), "%%%su", INODEPSPEC);
1268 InodeFmt_d = sv_fmt_str(options);
1269 (void) snpf(options, sizeof(options), "%%#%sx", INODEPSPEC);
1270 InodeFmt_x = sv_fmt_str(options);
1271 (void) snpf(options, sizeof(options), "0t%%%su", SZOFFPSPEC);
1272 SzOffFmt_0t = sv_fmt_str(options);
1273 (void) snpf(options, sizeof(options), "%%%su", SZOFFPSPEC);
1274 SzOffFmt_d = sv_fmt_str(options);
1275 (void) snpf(options, sizeof(options), "%%*%su", SZOFFPSPEC);
1276 SzOffFmt_dv = sv_fmt_str(options);
1277 (void) snpf(options, sizeof(options), "%%#%sx", SZOFFPSPEC);
1278 SzOffFmt_x = sv_fmt_str(options);
1280 #if defined(HASMNTSUP)
1282 * Report mount supplement information, as requested.
1288 #endif /* defined(HASMNTSUP) */
1291 * Gather and report process information every RptTm seconds.
1298 * Gather information about processes.
1302 * If the local process table has more than one entry, sort it by PID.
1306 len = (MALLOC_S)(Nlproc * sizeof(struct lproc *));
1309 slp = (struct lproc **)malloc(len);
1311 slp = (struct lproc **)realloc((MALLOC_P *)slp, len);
1313 (void) fprintf(stderr,
1314 "%s: no space for %d sort pointers\n", Pn, Nlproc);
1318 for (i = 0; i < Nlproc; i++) {
1321 (void) qsort((QSORT_P *)slp, (size_t)Nlproc,
1322 (size_t)sizeof(struct lproc *), comppid);
1326 #if defined(HASNCACHE)
1328 * If using the kernel name cache, force its reloading.
1331 #endif /* defined(HASNCACHE) */
1333 #if defined(HASEPTOPTS)
1335 * If endpoint info has been requested, make sure it is coded for
1338 * Lf contents must be preserved, since they may point to a
1339 * malloc()'d area, and since Lf is used throughout the printing
1340 * of the selected processes.
1345 * Scan all selected processes.
1347 for (i = 0; i < Nlproc; i++) {
1348 Lp = (Nlproc > 1) ? slp[i] : &Lproc[i];
1351 * For processes that have been selected for printing
1352 * and have files that are the end point(s) of pipe(s),
1353 * process the file endpoints.
1355 if (Lp->pss && (Lp->ept & EPT_PIPE))
1356 (void) process_pinfo(0);
1358 # if defined(HASUXSOCKEPT)
1360 * For processes that have been selected for printing
1361 * and have files that are the end point(s) of UNIX
1362 * socket(s), process the file endpoints.
1364 if (Lp->pss && (Lp->ept & EPT_UXS))
1365 (void) process_uxsinfo(0);
1366 # endif /* defined(HASUXSOCKEPT) */
1368 # if defined(HASPTYEPT)
1370 * For processes that have been selected for printing
1371 * and have files that are the end point(s) of pseudo-
1372 * terminal files(s), process the file endpoints.
1374 if (Lp->pss && (Lp->ept & EPT_PTY))
1375 (void) process_ptyinfo(0);
1376 # endif /* defined(HASPTYEPT) */
1380 * In a second pass, look for unselected endpoint files,
1381 * possibly selecting them for printing.
1383 for (i = 0; i < Nlproc; i++) {
1384 Lp = (Nlproc > 1) ? slp[i] : &Lproc[i];
1387 * Process pipe endpoints.
1389 if (Lp->ept & EPT_PIPE_END)
1390 (void) process_pinfo(1);
1392 # if defined(HASUXSOCKEPT)
1394 * Process UNIX socket endpoints.
1396 if (Lp->ept & EPT_UXS_END)
1397 (void) process_uxsinfo(1);
1398 # endif /* defined(HASUXSOCKEPT) */
1400 # if defined(HASPTYEPT)
1402 * Process pseudo-terminal endpoints.
1404 if (Lp->ept & EPT_PTY_END)
1405 (void) process_ptyinfo(1);
1406 # endif /* defined(HASPTYEPT) */
1411 #endif /* defined(HASEPTOPTS) */
1414 * Print the selected processes and count them.
1416 * Lf contents must be preserved, since they may point to a
1417 * malloc()'d area, and since Lf is used throughout the print
1420 for (lf = Lf, print_init(); PrPass < 2; PrPass++) {
1421 for (i = n = 0; i < Nlproc; i++) {
1422 Lp = (Nlproc > 1) ? slp[i] : &Lproc[i];
1427 if (RptTm && PrPass)
1428 (void) free_lproc(Lp);
1434 * If a repeat time is set, sleep for the specified time.
1436 * If conditional repeat mode is in effect, see if it's time to exit.
1440 #if defined(HASEPTOPTS)
1441 (void) clear_pinfo();
1443 # if defined(HASUXSOCKEPT)
1444 (void) clear_uxsinfo();
1445 # endif /* defined(HASUXSOCKEPT) */
1447 # if defined(HASPTYEPT)
1448 (void) clear_ptyinfo();
1449 # endif /* defined(HASPTYEPT) */
1450 #endif /* defined(HASEPTOPTS) */
1459 #if defined(HAS_STRFTIME)
1463 * Format the marker line.
1465 (void) util_strftime(fmtr, fmtl - 1, fmt);
1466 fmtr[fmtl - 1] = '\0';
1468 #endif /* defined(HAS_STRFTIME) */
1471 putchar(LSOF_FID_MARK);
1473 #if defined(HAS_STRFTIME)
1475 (void) printf("%s", fmtr);
1476 #endif /* defined(HAS_STRFTIME) */
1478 putchar(Terminator);
1479 if (Terminator != '\n')
1483 #if defined(HAS_STRFTIME)
1487 #endif /* defined(HAS_STRFTIME) */
1492 (void) fflush(stdout);
1494 (void) sleep(RptTm);
1500 * See if all requested information was displayed. Return zero if it
1501 * was; one, if not. If -V was specified, report what was not displayed.
1505 for (str = Cmdl; str; str = str->next) {
1508 * Check command specifications.
1514 (void) printf("%s: command not located: ", Pn);
1515 safestrprt(str->str, stdout, 1);
1518 for (i = 0; i < NCmdRxU; i++) {
1521 * Check command regular expressions.
1527 (void) printf("%s: no command found for regex: ", Pn);
1528 safestrprt(CmdRx[i].exp, stdout, 1);
1531 for (sfp = Sfile; sfp; sfp = sfp->next) {
1534 * Check file specifications.
1540 (void) printf("%s: no file%s use located: ", Pn,
1541 sfp->type ? "" : " system");
1542 safestrprt(sfp->aname, stdout, 1);
1546 #if defined(HASPROCFS)
1548 * Report on proc file system search results.
1550 if (Procsrch && !Procfind) {
1553 (void) printf("%s: no file system use located: ", Pn);
1554 safestrprt(Mtprocfs ? Mtprocfs->dir : HASPROCFS, stdout, 1);
1558 struct procfsid *pfi;
1560 for (pfi = Procfsid; pfi; pfi = pfi->next) {
1564 (void) printf("%s: no file use located: ", Pn);
1565 safestrprt(pfi->nm, stdout, 1);
1570 #endif /* defined(HASPROCFS) */
1575 * Check Internet address specifications.
1577 * If any Internet address derived from the same argument was found,
1578 * consider all derivations found. If no derivation from the same
1579 * argument was found, report only the first failure.
1582 for (; np; np = np->next) {
1583 if (!(cp = np->arg))
1585 for (npn = np->next; npn; npn = npn->next) {
1588 if (!strcmp(cp, npn->arg)) {
1591 * If either of the duplicate specifications was found,
1592 * mark them both found. If neither was found, mark all
1593 * but the first one found.
1604 for (np = Nwad; np; np = np->next) {
1605 if (!np->f && (cp = np->arg)) {
1608 (void) printf("%s: Internet address not located: ", Pn);
1609 safestrprt(cp ? cp : "(unknown)", stdout, 1);
1614 if (Fnet && Fnet < 2) {
1617 * Report no Internet files located.
1621 (void) printf("%s: no Internet files located\n", Pn);
1624 #if defined(HASTCPUDPSTATE)
1628 * Check for included TCP states not located.
1630 for (i = 0; i < TcpNstates; i++) {
1631 if (TcpStI[i] == 1) {
1634 (void) printf("%s: TCP state not located: %s\n",
1642 * Check for included UDP states not located.
1644 for (i = 0; i < UdpNstates; i++) {
1645 if (UdpStI[i] == 1) {
1648 (void) printf("%s: UDP state not located: %s\n",
1653 #endif /* defined(HASTCPUDPSTATE) */
1655 if (Fnfs && Fnfs < 2) {
1658 * Report no NFS files located.
1662 (void) printf("%s: no NFS files located\n", Pn);
1664 for (i = 0; i < Npid; i++) {
1667 * Check inclusionary process ID specifications.
1669 if (Spid[i].f || Spid[i].x)
1673 (void) printf("%s: process ID not located: %d\n",
1677 #if defined(HASTASKS)
1678 if (Ftask && Ftask < 2) {
1681 * Report no tasks located.
1685 (void) printf("%s: no tasks located\n", Pn);
1687 #endif /* defined(HASTASKS) */
1689 #if defined(HASZONES)
1693 * Check zone argument results.
1695 for (i = 0; i < HASHZONE; i++) {
1696 for (zp = ZoneArg[i]; zp; zp = zp->next) {
1700 (void) printf("%s: zone not located: ", Pn);
1701 safestrprt(zp->zn, stdout, 1);
1707 #endif /* defined(HASZONES) */
1709 #if defined(HASSELINUX)
1713 * Check context argument results.
1715 for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
1719 (void) printf("%s: context not located: ", Pn);
1720 safestrprt(cntxp->cntx, stdout, 1);
1725 #endif /* defined(HASSELINUX) */
1727 for (i = 0; i < Npgid; i++) {
1730 * Check inclusionary process group ID specifications.
1732 if (Spgid[i].f || Spgid[i].x)
1736 (void) printf("%s: process group ID not located: %d\n",
1739 for (i = 0; i < Nuid; i++) {
1742 * Check inclusionary user ID specifications.
1744 if (Suid[i].excl || Suid[i].f)
1749 (void) printf("%s: login name (UID %lu) not located: ",
1750 Pn, (unsigned long)Suid[i].uid);
1751 safestrprt(Suid[i].lnm, stdout, 1);
1753 (void) printf("%s: user ID not located: %lu\n", Pn,
1754 (unsigned long)Suid[i].uid);
1762 return(rv); /* to make code analyzers happy */
1767 * GetOpt() -- Local get option
1769 * Liberally adapted from the public domain AT&T getopt() source,
1770 * distributed at the 1985 UNIFORM conference in Dallas
1772 * The modifications allow `?' to be an option character and allow
1773 * the caller to decide that an option that may be followed by a
1774 * value doesn't have one -- e.g., has a default instead.
1778 GetOpt(ct, opt, rules, err)
1779 int ct; /* option count */
1780 char *opt[]; /* options */
1781 char *rules; /* option rules */
1782 int *err; /* error return */
1785 register char *cp = (char *)NULL;
1790 * Move to a new entry of the option array.
1794 * Option list has been exhausted;
1795 * Next option doesn't start with `-' or `+';
1796 * Next option has nothing but `-' or `+';
1797 * Next option is ``--'' or ``++''.
1800 || (opt[GOx1][0] != '-' && opt[GOx1][0] != '+')
1803 if (strcmp(opt[GOx1], "--") == 0 || strcmp(opt[GOx1], "++") == 0) {
1811 * Flag `:' option character as an error.
1813 * Check for a rule on this option character.
1816 if ((c = opt[GOx1][GOx2]) == ':') {
1817 (void) fprintf(stderr,
1818 "%s: colon is an illegal option character.\n", Pn);
1820 } else if (!(cp = strchr(rules, c))) {
1821 (void) fprintf(stderr, "%s: illegal option character: %c\n", Pn, c);
1827 * An error was detected.
1829 * Advance to the next option character.
1831 * Return the character causing the error.
1833 if (opt[GOx1][++GOx2] == '\0') {
1839 if (*(cp + 1) == ':') {
1842 * The option may have a following value. The caller decides
1845 * Save the position of the possible value in case the caller
1846 * decides it does not belong to the option and wants it
1847 * reconsidered as an option character. The caller does that
1849 * GOx1 = GObk[0]; GOx2 = GObk[1];
1851 * Don't indicate that an option of ``--'' is a possible value.
1853 * Finally, on the assumption that the caller will decide that
1854 * the possible value belongs to the option, position to the
1855 * option following the possible value, so that the next call
1856 * to GetOpt() will find it.
1858 if(opt[GOx1][GOx2 + 1] != '\0') {
1861 GOv = &opt[GOx1++][GOx2];
1862 } else if (++GOx1 >= ct)
1868 if (strcmp(GOv, "--") == 0)
1877 * The option character stands alone with no following value.
1879 * Advance to the next option character.
1881 if (opt[GOx1][++GOx2] == '\0') {
1888 * Return the option character.
1895 * sv_fmt_str() - save format string
1900 char *f; /* format string */
1905 l = (MALLOC_S)(strlen(f) + 1);
1906 if (!(cp = (char *)malloc(l))) {
1907 (void) fprintf(stderr,
1908 "%s: can't allocate %d bytes for format: %s\n", Pn, (int)l, f);
1911 (void) snpf(cp, l, "%s", f);