/* * main.c - common main function for lsof * * V. Abell, Purdue University */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; static char *rcsid = "$Id: main.c,v 1.55 2011/09/07 19:13:49 abe Exp $"; #endif #include "lsof.h" /* * Local definitions */ static int GObk[] = { 1, 1 }; /* option backspace values */ static char GOp; /* option prefix -- '+' or '-' */ static char *GOv = (char *)NULL; /* option `:' value pointer */ static int GOx1 = 1; /* first opt[][] index */ static int GOx2 = 0; /* second opt[][] index */ _PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, int *err)); _PROTOTYPE(static char *sv_fmt_str,(char *f)); /* * main() - main function for lsof */ int main(argc, argv) int argc; char *argv[]; { int ad, c, i, n, rv, se1, se2, ss; char *cp; int err = 0; int ev = 0; int fh = 0; char *fmtr = (char *)NULL; long l; MALLOC_S len; struct lfile *lf; struct nwad *np, *npn; char options[128]; int rc = 0; struct stat sb; struct sfile *sfp; struct lproc **slp = (struct lproc **)NULL; int sp = 0; struct str_lst *str, *strt; int version = 0; int xover = 0; #if defined(HAS_STRFTIME) char *fmt = (char *)NULL; size_t fmtl; #endif /* defined(HAS_STRFTIME) */ #if defined(HASZONES) znhash_t *zp; #endif /* defined(HASZONES) */ #if defined(HASSELINUX) /* * This stanza must be immediately before the "Save progam name." code, since * it contains code itself. */ cntxlist_t *cntxp; CntxStatus = is_selinux_enabled() ? 1 : 0; #endif /* defined(HASSELINUX) */ /* * Save program name. */ if ((Pn = strrchr(argv[0], '/'))) Pn++; else Pn = argv[0]; /* * Close all file descriptors above 2. * * Make sure stderr, stdout, and stdin are open descriptors. Open /dev/null * for ones that aren't. Be terse. * * Make sure umask allows lsof to define its own file permissions. */ for (i = 3, n = GET_MAX_FD(); i < n; i++) (void) close(i); while (((i = open("/dev/null", O_RDWR, 0)) >= 0) && (i < 2)) ; if (i < 0) Exit(1); if (i > 2) (void) close(i); (void) umask(0); #if defined(HASSETLOCALE) /* * Set locale to environment's definition. */ (void) setlocale(LC_CTYPE, ""); #endif /* defined(HASSETLOCALE) */ /* * Common initialization. */ Mypid = getpid(); if ((Mygid = (gid_t)getgid()) != getegid()) Setgid = 1; Euid = geteuid(); if ((Myuid = (uid_t)getuid()) && !Euid) Setuidroot = 1; if (!(Namech = (char *)malloc(MAXPATHLEN + 1))) { (void) fprintf(stderr, "%s: no space for name buffer\n", Pn); Exit(1); } Namechl = (size_t)(MAXPATHLEN + 1); /* * Create option mask. */ (void) snpf(options, sizeof(options), "?a%sbc:%sD:d:%sf:F:g:hi:%s%slL:%s%snNo:Op:Pr:%ss:S:tT:u:UvVwx:%s%s%s", #if defined(HAS_AFS) && defined(HASAOPT) "A:", #else /* !defined(HAS_AFS) || !defined(HASAOPT) */ "", #endif /* defined(HAS_AFS) && defined(HASAOPT) */ #if defined(HASNCACHE) "C", #else /* !defined(HASNCACHE) */ "", #endif /* defined(HASNCACHE) */ #if defined(HASEOPT) "e:", #else /* !defined(HASEOPT) */ "", #endif /* defined(HASEOPT) */ #if defined(HASKOPT) "k:", #else /* !defined(HASKOPT) */ "", #endif /* defined(HASKOPT) */ #if defined(HASTASKS) "K", #else /* !defined(HASTASKS) */ "", #endif /* defined(HASTASKS) */ #if defined(HASMOPT) || defined(HASMNTSUP) "m:", #else /* !defined(HASMOPT) && !defined(HASMNTSUP) */ "", #endif /* defined(HASMOPT) || defined(HASMNTSUP) */ #if defined(HASNORPC_H) "", #else /* !defined(HASNORPC_H) */ "M", #endif /* defined(HASNORPC_H) */ #if defined(HASPPID) "R", #else /* !defined(HASPPID) */ "", #endif /* defined(HASPPID) */ #if defined(HASXOPT) # if defined(HASXOPT_ROOT) (Myuid == 0) ? "X" : "", # else /* !defined(HASXOPT_ROOT) */ "X", # endif /* defined(HASXOPT_ROOT) */ #else /* !defined(HASXOPT) */ "", #endif /* defined(HASXOPT) */ #if defined(HASZONES) "z:", #else /* !defined(HASZONES) */ "", #endif /* defined(HASZONES) */ #if defined(HASSELINUX) "Z:" #else /* !defined(HASSELINUX) */ "" #endif /* defined(HASSELINUX) */ ); /* * Loop through options. */ while ((c = GetOpt(argc, argv, options, &rv)) != EOF) { if (rv) { err = 1; continue; } switch (c) { case 'a': Fand = 1; break; #if defined(HAS_AFS) && defined(HASAOPT) case 'A': if (!GOv || *GOv == '-' || *GOv == '+') { (void) fprintf(stderr, "%s: -A not followed by path\n", Pn); err = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } else AFSApath = GOv; break; #endif /* defined(HAS_AFS) && defined(HASAOPT) */ case 'b': Fblock = 1; break; case 'c': if (GOp == '+') { if (!GOv || (*GOv == '-') || (*GOv == '+') || !isdigit((int)*GOv)) { (void) fprintf(stderr, "%s: +c not followed by width number\n", Pn); err = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } else { CmdLim = atoi(GOv); #if defined(MAXSYSCMDL) if (CmdLim > MAXSYSCMDL) { (void) fprintf(stderr, "%s: +c %d > what system provides (%d)\n", Pn, CmdLim, MAXSYSCMDL); err = 1; } #endif /* defined(MAXSYSCMDL) */ } break; } if (GOv && (*GOv == '/')) { if (enter_cmd_rx(GOv)) err = 1; } else { if (enter_str_lst("-c", GOv, &Cmdl, &Cmdni, &Cmdnx)) err = 1; #if defined(MAXSYSCMDL) else if (Cmdl->len > MAXSYSCMDL) { (void) fprintf(stderr, "%s: \"-c ", Pn); (void) safestrprt(Cmdl->str, stderr, 2); (void) fprintf(stderr, "\" length (%d) > what system", Cmdl->len); (void) fprintf(stderr, " provides (%d)\n", MAXSYSCMDL); Cmdl->len = 0; /* (to avoid later error report) */ err = 1; } #endif /* defined(MAXSYSCMDL) */ } break; #if defined(HASNCACHE) case 'C': Fncache = (GOp == '-') ? 0 : 1; break; #endif /* defined(HASNCACHE) */ #if defined(HASEOPT) case 'e': if (enter_efsys(GOv, ((GOp == '+') ? 1 : 0))) err = 1; break; #endif /* defined(HASEOPT) */ case 'd': if (GOp == '+') { if (enter_dir(GOv, 0)) err = 1; else { Selflags |= SELNM; xover = 1; } } else { if (enter_fd(GOv)) err = 1; } break; case 'D': if (GOp == '+') { if (enter_dir(GOv, 1)) err = 1; else { Selflags |= SELNM; xover = 1; } } else { #if defined(HASDCACHE) if (ctrl_dcache(GOv)) err = 1; #else /* !defined(HASDCACHE) */ (void) fprintf(stderr, "%s: unsupported option: -D\n", Pn); err = 1; #endif /* defined(HASDCACHE) */ } break; case 'f': if (!GOv || *GOv == '-' || *GOv == '+') { Ffilesys = (GOp == '+') ? 2 : 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } #if defined(HASFSTRUCT) for (; *GOv; GOv++) { switch (*GOv) { # if !defined(HASNOFSCOUNT) case 'c': case 'C': if (GOp == '+') { Fsv |= FSV_CT; FsvByf = 1; } else Fsv &= (unsigned char)~FSV_CT; break; # endif /* !defined(HASNOFSCOUNT) */ # if !defined(HASNOFSADDR) case 'f': case 'F': if (GOp == '+') { Fsv |= FSV_FA; FsvByf = 1; } else Fsv &= (unsigned char)~FSV_FA; break; # endif /* !defined(HASNOFSADDR) */ # if !defined(HASNOFSFLAGS) case 'g': case 'G': if (GOp == '+') { Fsv |= FSV_FG; FsvByf = 1; } else Fsv &= (unsigned char)~FSV_FG; FsvFlagX = (*GOv == 'G') ? 1 : 0; break; # endif /* !defined(HASNOFSFLAGS) */ # if !defined(HASNOFSNADDR) case 'n': case 'N': if (GOp == '+') { Fsv |= FSV_NI; FsvByf = 1; } else Fsv &= (unsigned char)~FSV_NI; break; # endif /* !defined(HASNOFSNADDR */ default: (void) fprintf(stderr, "%s: unknown file struct option: %c\n", Pn, *GOv); err++; } } #else /* !defined(HASFSTRUCT) */ (void) fprintf(stderr, "%s: unknown string for %cf: %s\n", Pn, GOp, GOv); err++; #endif /* defined(HASFSTRUCT) */ break; case 'F': if (!GOv || *GOv == '-' || *GOv == '+' || strcmp(GOv, "0") == 0) { if (GOv) { if (*GOv == '-' || *GOv == '+') { GOx1 = GObk[0]; GOx2 = GObk[1]; } else if (*GOv == '0') Terminator = '\0'; } for (i = 0; FieldSel[i].nm; i++) { #if !defined(HASPPID) if (FieldSel[i].id == LSOF_FID_PPID) continue; #endif /* !defined(HASPPID) */ #if !defined(HASFSTRUCT) if (FieldSel[i].id == LSOF_FID_CT || FieldSel[i].id == LSOF_FID_FA || FieldSel[i].id == LSOF_FID_FG || FieldSel[i].id == LSOF_FID_NI) continue; #endif /* !defined(HASFSTRUCT) */ #if defined(HASSELINUX) if ((FieldSel[i].id == LSOF_FID_CNTX) && !CntxStatus) continue; #else /* !defined(HASSELINUX) */ if (FieldSel[i].id == LSOF_FID_CNTX) continue; #endif /* !defined(HASSELINUX) */ if (FieldSel[i].id == LSOF_FID_RDEV) continue; /* for compatibility */ #if !defined(HASTASKS) if (FieldSel[i].id == LSOF_FID_TID) continue; #endif /* !defined(HASTASKS) */ #if !defined(HASZONES) if (FieldSel[i].id == LSOF_FID_ZONE) continue; #endif /* !defined(HASZONES) */ FieldSel[i].st = 1; if (FieldSel[i].opt && FieldSel[i].ov) *(FieldSel[i].opt) |= FieldSel[i].ov; } #if defined(HASFSTRUCT) Ffield = FsvFlagX = 1; #else /* !defined(HASFSTRUCT) */ Ffield = 1; #endif /* defined(HASFSTRUCT) */ break; } if (strcmp(GOv, "?") == 0) { fh = 1; break; } for (; *GOv; GOv++) { for (i = 0; FieldSel[i].nm; i++) { #if !defined(HASPPID) if (FieldSel[i].id == LSOF_FID_PPID) continue; #endif /* !defined(HASPPID) */ #if !defined(HASFSTRUCT) if (FieldSel[i].id == LSOF_FID_CT || FieldSel[i].id == LSOF_FID_FA || FieldSel[i].id == LSOF_FID_FG || FieldSel[i].id == LSOF_FID_NI) continue; #endif /* !defined(HASFSTRUCT) */ #if !defined(HASTASKS) if (FieldSel[i].id == LSOF_FID_TID) continue; #endif /* !defined(HASTASKS) */ if (FieldSel[i].id == *GOv) { FieldSel[i].st = 1; if (FieldSel[i].opt && FieldSel[i].ov) *(FieldSel[i].opt) |= FieldSel[i].ov; #if defined(HASFSTRUCT) if (i == LSOF_FIX_FG) FsvFlagX = 1; #endif /* defined(HASFSTRUCT) */ if (i == LSOF_FIX_TERM) Terminator = '\0'; break; } } if ( ! FieldSel[i].nm) { (void) fprintf(stderr, "%s: unknown field: %c\n", Pn, *GOv); err++; } } Ffield = 1; break; case 'g': if (GOv) { if (*GOv == '-' || *GOv == '+') { GOx1 = GObk[0]; GOx2 = GObk[1]; } else if (enter_id(PGID, GOv)) err = 1; } Fpgid = 1; break; case 'h': case '?': Fhelp = 1; break; case 'i': if (!GOv || *GOv == '-' || *GOv == '+') { Fnet = 1; FnetTy = 0; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } if (enter_network_address(GOv)) err = 1; break; #if defined(HASKOPT) case 'k': if (!GOv || *GOv == '-' || *GOv == '+') { (void) fprintf(stderr, "%s: -k not followed by path\n", Pn); err = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } else Nmlst = GOv; break; #endif /* defined(HASKOPT) */ #if defined(HASTASKS) case 'K': Ftask = 1; Selflags |= SELTASK; break; #endif /* defined(HASTASKS) */ case 'l': Futol = 0; break; case 'L': Fnlink = (GOp == '+') ? 1 : 0; if (!GOv || *GOv == '-' || *GOv == '+') { Nlink = 0l; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } for (cp = GOv, l = 0l, n = 0; *cp; cp++) { if (!isdigit((unsigned char)*cp)) break; l = (l * 10l) + ((long)*cp - (long)'0'); n++; } if (n) { if (GOp != '+') { (void) fprintf(stderr, "%s: no number may follow -L\n", Pn); err = 1; } else { Nlink = l; Selflags |= SELNLINK; } } else Nlink = 0l; if (*cp) { GOx1 = GObk[0]; GOx2 = GObk[1] + n; } break; #if defined(HASMOPT) || defined(HASMNTSUP) case 'm': if (GOp == '-') { # if defined(HASMOPT) if (!GOv || *GOv == '-' || *GOv == '+') { (void) fprintf(stderr, "%s: -m not followed by path\n", Pn); err = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } else Memory = GOv; # else /* !defined(HASMOPT) */ (void) fprintf(stderr, "%s: -m not supported\n", Pn); err = 1; # endif /* defined(HASMOPT) */ } else if (GOp == '+') { # if defined(HASMNTSUP) if (!GOv || *GOv == '-' || *GOv == '+') { MntSup = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } else { MntSup = 2; MntSupP = GOv; } # else /* !defined(HASMNTSUP) */ (void) fprintf(stderr, "%s: +m not supported\n", Pn); err = 1; # endif /* defined(HASMNTSUP) */ } else { (void) fprintf(stderr, "%s: %cm not supported\n", Pn, GOp); err = 1; } break; #endif /* defined(HASMOPT) || defined(HASMNTSUP) */ #if !defined(HASNORPC_H) case 'M': FportMap = (GOp == '+') ? 1 : 0; break; #endif /* !defined(HASNORPC_H) */ case 'n': Fhost = (GOp == '-') ? 0 : 1; break; case 'N': Fnfs = 1; break; case 'o': if (!GOv || *GOv == '-' || *GOv == '+') { Foffset = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } for (cp = GOv, i = n = 0; *cp; cp++) { if (!isdigit((unsigned char)*cp)) break; i = (i * 10) + ((int)*cp - '0'); n++; } if (n) OffDecDig = i; else Foffset = 1; if (*cp) { GOx1 = GObk[0]; GOx2 = GObk[1] + n; } break; case 'O': Fovhd = (GOp == '-') ? 1 : 0; break; case 'p': if (enter_id(PID, GOv)) err = 1; break; case 'P': Fport = (GOp == '-') ? 0 : 1; break; case 'r': if (GOp == '+') ev = rc = 1; if (!GOv || *GOv == '-' || *GOv == '+') { RptTm = RPTTM; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } for (cp = GOv, i = n = 0; *cp; cp++) { if (!isdigit((unsigned char)*cp)) break; i = (i * 10) + ((int)*cp - '0'); n++; } if (n) RptTm = i; else RptTm = RPTTM; if (!*cp) break; while(*cp && (*cp == ' ')) cp++; if (*cp != LSOF_FID_MARK) { GOx1 = GObk[0]; GOx2 = GObk[1] + n; break; } #if defined(HAS_STRFTIME) /* * Collect the strftime(3) format and test it. */ cp++; if ((fmtl = strlen(cp) + 1) < 1) { (void) fprintf(stderr, "%s: too short: \"%s\"\n", Pn, cp); err = 1; } else { fmt = cp; fmtl = (fmtl * 8) + 1; if (!(fmtr = (char *)malloc((MALLOC_S)fmtl))) { (void) fprintf(stderr, "%s: no space (%d) for result: \"%s\"\n", Pn, (int)fmtl, cp); Exit(1); } if (util_strftime(fmtr, fmtl - 1, fmt) < 1) { (void) fprintf(stderr, "%s: illegal : \"%s\"\n", Pn, fmt); err = 1; } } #else /* !defined(HAS_STRFTIME) */ (void) fprintf(stderr, "%s: m not supported: \"%s\"\n", Pn, cp); err = 1; #endif /* defined(HAS_STRFTIME) */ break; #if defined(HASPPID) case 'R': Fppid = 1; break; #endif /* defined(HASPPID) */ case 's': #if defined(HASTCPUDPSTATE) if (!GOv || *GOv == '-' || *GOv == '+') { Fsize = 1; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } else { if (enter_state_spec(GOv)) err = 1; } #else /* !defined(HASTCPUDPSTATE) */ Fsize = 1; #endif /* defined(HASTCPUDPSTATE) */ break; case 'S': if (!GOv || *GOv == '-' || *GOv == '+') { TmLimit = TMLIMIT; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } for (cp = GOv, i = n = 0; *cp; cp++) { if (!isdigit((unsigned char)*cp)) break; i = (i * 10) + ((int)*cp - '0'); n++; } if (n) TmLimit = i; else TmLimit = TMLIMIT; if (*cp) { GOx1 = GObk[0]; GOx2 = GObk[1] + n; } if (TmLimit < TMLIMMIN) { (void) fprintf(stderr, "%s: WARNING: -S time (%d) changed to %d\n", Pn, TmLimit, TMLIMMIN); TmLimit = TMLIMMIN; } break; case 't': Fterse = Fwarn = 1; break; case 'T': if (!GOv || *GOv == '-' || *GOv == '+') { Ftcptpi = (GOp == '-') ? 0 : TCPTPI_STATE; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } for (Ftcptpi = 0; *GOv; GOv++) { switch (*GOv) { #if defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT) case 'f': Ftcptpi |= TCPTPI_FLAGS; break; #endif /* defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT) */ #if defined(HASTCPTPIQ) case 'q': Ftcptpi |= TCPTPI_QUEUES; break; #endif /* defined(HASTCPTPIQ) */ case 's': Ftcptpi |= TCPTPI_STATE; break; #if defined(HASTCPTPIW) case 'w': Ftcptpi |= TCPTPI_WINDOWS; break; #endif /* defined(HASTCPTPIW) */ default: (void) fprintf(stderr, "%s: unsupported TCP/TPI info selection: %c\n", Pn, *GOv); err = 1; } } break; case 'u': if (enter_uid(GOv)) err = 1; break; case 'U': Funix = 1; break; case 'v': version = 1; break; case 'V': Fverbose = 1; break; case 'w': Fwarn = (GOp == '+') ? 0 : 1; break; case 'x': if (!GOv || *GOv == '-' || *GOv == '+') { Fxover = XO_ALL; if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; } else { for (; *GOv; GOv++) { switch (*GOv) { case 'f': Fxover |= XO_FILESYS; break; case 'l': Fxover |= XO_SYMLINK; break; default: (void) fprintf(stderr, "%s: unknown cross-over option: %c\n", Pn, *GOv); err++; } } } break; #if defined(HASXOPT) case 'X': Fxopt = Fxopt ? 0 : 1; break; #endif /* defined(HASXOPT) */ #if defined(HASZONES) case 'z': Fzone = 1; if (GOv && (*GOv != '-') && (*GOv != '+')) { /* * Add to the zone name argument hash. */ if (enter_zone_arg(GOv)) err = 1; } else if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } break; #endif /* defined(HASZONES) */ #if defined(HASSELINUX) case 'Z': if (!CntxStatus) { (void) fprintf(stderr, "%s: -Z limited to SELinux\n", Pn); err = 1; } else { Fcntx = 1; if (GOv && (*GOv != '-') && (*GOv != '+')) { /* * Add to the context name argument hash. */ if (enter_cntx_arg(GOv)) err = 1; } else if (GOv) { GOx1 = GObk[0]; GOx2 = GObk[1]; } } break; #endif /* defined(HASSELINUX) */ default: (void) fprintf(stderr, "%s: unknown option (%c)\n", Pn, c); err = 1; } } /* * Check for argument consistency. */ if (Cmdnx && Cmdni) { /* * Check for command inclusion/exclusion conflicts. */ for (str = Cmdl; str; str = str->next) { if (str->x) { for (strt = Cmdl; strt; strt = strt->next) { if (!strt->x) { if (!strcmp(str->str, strt->str)) { (void) fprintf(stderr, "%s: -c^%s and -c%s conflict.\n", Pn, str->str, strt->str); err++; } } } } } } #if defined(HASTCPUDPSTATE) if (TcpStXn && TcpStIn) { /* * Check for excluded and included TCP states. */ for (i = 0; i < TcpNstates; i++) { if (TcpStX[i] && TcpStI[i]) { (void) fprintf(stderr, "%s: can't include and exclude TCP state: %s\n", Pn, TcpSt[i]); err = 1; } } } if (UdpStXn && UdpStIn) { /* * Check for excluded and included UDP states. */ for (i = 0; i < UdpNstates; i++) { if (UdpStX[i] && UdpStI[i]) { (void) fprintf(stderr, "%s: can't include and exclude UDP state: %s\n", Pn, UdpSt[i]); err = 1; } } } #endif /* defined(HASTCPUDPSTATE) */ if (Fsize && Foffset) { (void) fprintf(stderr, "%s: -o and -s are mutually exclusive\n", Pn); err++; } if (Ffield) { if (Fterse) { (void) fprintf(stderr, "%s: -F and -t are mutually exclusive\n", Pn); err++; } FieldSel[LSOF_FIX_PID].st = 1; #if defined(HAS_STRFTIME) if (fmtr) { /* * The field output marker format can't contain "%n" new line * requests. */ for (cp = strchr(fmt, '%'); cp; cp = strchr(cp, '%')) { if (*++cp == 'n') { (void) fprintf(stderr, "%s: %%n illegal in -r m when -F has", Pn); (void) fprintf(stderr, " been specified: \"%s\"\n", fmt); err++; break; } else if (*cp == '%') cp++; } } #endif /* defined(HAS_STRFTIME) */ } if (Fxover && !xover) { (void) fprintf(stderr, "%s: -x must accompany +d or +D\n", Pn); err++; } #if defined(HASEOPT) if (Efsysl) { /* * If there are file systems specified by -e options, check them. */ efsys_list_t *ep; /* Efsysl pointer */ struct mounts *mp, *mpw; /* local mount table pointers */ if ((mp = readmnt())) { for (ep = Efsysl; ep; ep = ep->next) { for (mpw = mp; mpw; mpw = mpw->next) { if (!strcmp(mpw->dir, ep->path)) { ep->mp = mpw; break; } } if (!ep->mp) { (void) fprintf(stderr, "%s: \"-e %s\" is not a mounted file system.\n", Pn, ep->path); err++; } } } } #endif /* defined(HASEOPT) */ if (DChelp || err || Fhelp || fh || version) usage(err ? 1 : 0, fh, version); /* * Reduce the size of Suid[], if necessary. */ if (Suid && Nuid && Nuid < Mxuid) { if (!(Suid = (struct seluid *)realloc((MALLOC_P *)Suid, (MALLOC_S)(sizeof(struct seluid) * Nuid)))) { (void) fprintf(stderr, "%s: can't realloc UID table\n", Pn); Exit(1); } Mxuid = Nuid; } /* * Compute the selection flags. */ if ((Cmdl && Cmdni) || CmdRx) Selflags |= SELCMD; #if defined(HASSELINUX) if (CntxArg) Selflags |= SELCNTX; #endif /* defined(HASSELINUX) */ if (Fdl) Selflags |= SELFD; if (Fnet) Selflags |= SELNET; if (Fnfs) Selflags |= SELNFS; if (Funix) Selflags |= SELUNX; if (Npgid && Npgidi) Selflags |= SELPGID; if (Npid && Npidi) Selflags |= SELPID; if (Nuid && Nuidincl) Selflags |= SELUID; if (Nwad) Selflags |= SELNA; #if defined(HASZONES) if (ZoneArg) Selflags |= SELZONE; #endif /* defined(HASZONES) */ if (GOx1 < argc) Selflags |= SELNM; if (Selflags == 0) { if (Fand) { (void) fprintf(stderr, "%s: no select options to AND via -a\n", Pn); usage(1, 0, 0); } Selflags = SELALL; } else { if (GOx1 >= argc && (Selflags & (SELNA|SELNET)) != 0 && (Selflags & ~(SELNA|SELNET)) == 0) Selinet = 1; Selall = 0; } /* * Get the device for DEVDEV_PATH. */ if (stat(DEVDEV_PATH, &sb)) { se1 = errno; if ((ad = strcmp(DEVDEV_PATH, "/dev"))) { if ((ss = stat("/dev", &sb))) se2 = errno; else se2 = 0; } else { se2 = 0; ss = 1; } if (ss) { (void) fprintf(stderr, "%s: can't stat(%s): %s\n", Pn, DEVDEV_PATH, strerror(se1)); if (ad) { (void) fprintf(stderr, "%s: can't stat(/dev): %s\n", Pn, strerror(se2)); } Exit(1); } } DevDev = sb.st_dev; /* * Process the file arguments. */ if (GOx1 < argc) { if (ck_file_arg(GOx1, argc, argv, Ffilesys, 0, (struct stat *)NULL)) usage(1, 0, 0); } /* * Do dialect-specific initialization. */ initialize(); if (Sfile) (void) hashSfile(); #if defined(WILLDROPGID) /* * If this process isn't setuid(root), but it is setgid(not_real_gid), * relinquish the setgid power. (If it hasn't already been done.) */ (void) dropgid(); #endif /* defined(WILLDROPGID) */ #if defined(HASDCACHE) /* * If there is a device cache, prepare the device table. */ if (DCstate) readdev(0); #endif /* defined(HASDCACHE) */ /* * Define the size and offset print formats. */ (void) snpf(options, sizeof(options), "%%%su", INODEPSPEC); InodeFmt_d = sv_fmt_str(options); (void) snpf(options, sizeof(options), "%%#%sx", INODEPSPEC); InodeFmt_x = sv_fmt_str(options); (void) snpf(options, sizeof(options), "0t%%%su", SZOFFPSPEC); SzOffFmt_0t = sv_fmt_str(options); (void) snpf(options, sizeof(options), "%%%su", SZOFFPSPEC); SzOffFmt_d = sv_fmt_str(options); (void) snpf(options, sizeof(options), "%%*%su", SZOFFPSPEC); SzOffFmt_dv = sv_fmt_str(options); (void) snpf(options, sizeof(options), "%%#%sx", SZOFFPSPEC); SzOffFmt_x = sv_fmt_str(options); #if defined(HASMNTSUP) /* * Report mount supplement information, as requested. */ if (MntSup == 1) { (void) readmnt(); Exit(0); } #endif /* defined(HASMNTSUP) */ /* * Gather and report process information every RptTm seconds. */ if (RptTm) CkPasswd = 1; do { /* * Gather information about processes. */ gather_proc_info(); /* * If the local process table has more than one entry, sort it by PID. */ if (Nlproc > 1) { if (Nlproc > sp) { len = (MALLOC_S)(Nlproc * sizeof(struct lproc *)); sp = Nlproc; if (!slp) slp = (struct lproc **)malloc(len); else slp = (struct lproc **)realloc((MALLOC_P *)slp, len); if (!slp) { (void) fprintf(stderr, "%s: no space for %d sort pointers\n", Pn, Nlproc); Exit(1); } } for (i = 0; i < Nlproc; i++) { slp[i] = &Lproc[i]; } (void) qsort((QSORT_P *)slp, (size_t)Nlproc, (size_t)sizeof(struct lproc *), comppid); } if ((n = Nlproc)) { #if defined(HASNCACHE) /* * If using the kernel name cache, force its reloading. */ NcacheReload = 1; #endif /* defined(HASNCACHE) */ /* * Print the selected processes and count them. * * Lf contents must be preserved, since they may point to a * malloc()'d area, and since Lf is used throughout the print * process. */ for (lf = Lf, print_init(); PrPass < 2; PrPass++) { for (i = n = 0; i < Nlproc; i++) { Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; if (Lp->pss) { if (print_proc()) n++; } if (RptTm && PrPass) (void) free_lproc(Lp); } } Lf = lf; } /* * If a repeat time is set, sleep for the specified time. * * If conditional repeat mode is in effect, see if it's time to exit. */ if (RptTm) { if (rc) { if (!n) break; else ev = 0; } #if defined(HAS_STRFTIME) if (fmt && fmtr) { /* * Format the marker line. */ (void) util_strftime(fmtr, fmtl - 1, fmt); fmtr[fmtl - 1] = '\0'; } #endif /* defined(HAS_STRFTIME) */ if (Ffield) { putchar(LSOF_FID_MARK); #if defined(HAS_STRFTIME) if (fmtr) (void) printf("%s", fmtr); #endif /* defined(HAS_STRFTIME) */ putchar(Terminator); if (Terminator != '\n') putchar('\n'); } else { #if defined(HAS_STRFTIME) if (fmtr) cp = fmtr; else #endif /* defined(HAS_STRFTIME) */ cp = "======="; puts(cp); } (void) fflush(stdout); (void) childx(); (void) sleep(RptTm); Hdr = Nlproc = 0; CkPasswd = 1; } } while (RptTm); /* * See if all requested information was displayed. Return zero if it * was; one, if not. If -V was specified, report what was not displayed. */ (void) childx(); rv = 0; for (str = Cmdl; str; str = str->next) { /* * Check command specifications. */ if (str->f) continue; rv = 1; if (Fverbose) { (void) printf("%s: command not located: ", Pn); safestrprt(str->str, stdout, 1); } } for (i = 0; i < NCmdRxU; i++) { /* * Check command regular expressions. */ if (CmdRx[i].mc) continue; rv = 1; if (Fverbose) { (void) printf("%s: no command found for regex: ", Pn); safestrprt(CmdRx[i].exp, stdout, 1); } } for (sfp = Sfile; sfp; sfp = sfp->next) { /* * Check file specifications. */ if (sfp->f) continue; rv = 1; if (Fverbose) { (void) printf("%s: no file%s use located: ", Pn, sfp->type ? "" : " system"); safestrprt(sfp->aname, stdout, 1); } } #if defined(HASPROCFS) /* * Report on proc file system search results. */ if (Procsrch && !Procfind) { rv = 1; if (Fverbose) { (void) printf("%s: no file system use located: ", Pn); safestrprt(Mtprocfs ? Mtprocfs->dir : HASPROCFS, stdout, 1); } } { struct procfsid *pfi; for (pfi = Procfsid; pfi; pfi = pfi->next) { if (!pfi->f) { rv = 1; if (Fverbose) { (void) printf("%s: no file use located: ", Pn); safestrprt(pfi->nm, stdout, 1); } } } } #endif /* defined(HASPROCFS) */ if ((np = Nwad)) { /* * Check Internet address specifications. * * If any Internet address derived from the same argument was found, * consider all derivations found. If no derivation from the same * argument was found, report only the first failure. * */ for (; np; np = np->next) { if (!(cp = np->arg)) continue; for (npn = np->next; npn; npn = npn->next) { if (!npn->arg) continue; if (!strcmp(cp, npn->arg)) { /* * If either of the duplicate specifications was found, * mark them both found. If neither was found, mark all * but the first one found. */ if (np->f) npn->f = np->f; else if (npn->f) np->f = npn->f; else npn->f = 1; } } } for (np = Nwad; np; np = np->next) { if (!np->f && (cp = np->arg)) { rv = 1; if (Fverbose) { (void) printf("%s: Internet address not located: ", Pn); safestrprt(cp ? cp : "(unknown)", stdout, 1); } } } } if (Fnet && Fnet < 2) { /* * Report no Internet files located. */ rv = 1; if (Fverbose) (void) printf("%s: no Internet files located\n", Pn); } #if defined(HASTCPUDPSTATE) if (TcpStIn) { /* * Check for included TCP states not located. */ for (i = 0; i < TcpNstates; i++) { if (TcpStI[i] == 1) { rv = 1; if (Fverbose) (void) printf("%s: TCP state not located: %s\n", Pn, TcpSt[i]); } } } if (UdpStIn) { /* * Check for included UDP states not located. */ for (i = 0; i < UdpNstates; i++) { if (UdpStI[i] == 1) { rv = 1; if (Fverbose) (void) printf("%s: UDP state not located: %s\n", Pn, UdpSt[i]); } } } #endif /* defined(HASTCPUDPSTATE) */ if (Fnfs && Fnfs < 2) { /* * Report no NFS files located. */ rv = 1; if (Fverbose) (void) printf("%s: no NFS files located\n", Pn); } for (i = 0; i < Npid; i++) { /* * Check inclusionary process ID specifications. */ if (Spid[i].f || Spid[i].x) continue; rv = 1; if (Fverbose) (void) printf("%s: process ID not located: %d\n", Pn, Spid[i].i); } #if defined(HASTASKS) if (Ftask && Ftask < 2) { /* * Report no tasks located. */ rv = 1; if (Fverbose) (void) printf("%s: no tasks located\n", Pn); } #endif /* defined(HASTASKS) */ #if defined(HASZONES) if (ZoneArg) { /* * Check zone argument results. */ for (i = 0; i < HASHZONE; i++) { for (zp = ZoneArg[i]; zp; zp = zp->next) { if (!zp->f) { rv = 1; if (Fverbose) { (void) printf("%s: zone not located: ", Pn); safestrprt(zp->zn, stdout, 1); } } } } } #endif /* defined(HASZONES) */ #if defined(HASSELINUX) if (CntxArg) { /* * Check context argument results. */ for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) { if (!cntxp->f) { rv = 1; if (Fverbose) { (void) printf("%s: context not located: ", Pn); safestrprt(cntxp->cntx, stdout, 1); } } } } #endif /* defined(HASSELINUX) */ for (i = 0; i < Npgid; i++) { /* * Check inclusionary process group ID specifications. */ if (Spgid[i].f || Spgid[i].x) continue; rv = 1; if (Fverbose) (void) printf("%s: process group ID not located: %d\n", Pn, Spgid[i].i); } for (i = 0; i < Nuid; i++) { /* * Check inclusionary user ID specifications. */ if (Suid[i].excl || Suid[i].f) continue; rv = 1; if (Fverbose) { if (Suid[i].lnm) { (void) printf("%s: login name (UID %lu) not located: ", Pn, (unsigned long)Suid[i].uid); safestrprt(Suid[i].lnm, stdout, 1); } else (void) printf("%s: user ID not located: %lu\n", Pn, (unsigned long)Suid[i].uid); } } if (!rv && rc) rv = ev; if (!rv && ErrStat) rv = 1; Exit(rv); return(rv); /* to make code analyzers happy */ } /* * GetOpt() -- Local get option * * Liberally adapted from the public domain AT&T getopt() source, * distributed at the 1985 UNIFORM conference in Dallas * * The modifications allow `?' to be an option character and allow * the caller to decide that an option that may be followed by a * value doesn't have one -- e.g., has a default instead. */ static int GetOpt(ct, opt, rules, err) int ct; /* option count */ char *opt[]; /* options */ char *rules; /* option rules */ int *err; /* error return */ { register int c; register char *cp = (char *)NULL; if (GOx2 == 0) { /* * Move to a new entry of the option array. * * EOF if: * * Option list has been exhausted; * Next option doesn't start with `-' or `+'; * Next option has nothing but `-' or `+'; * Next option is ``--'' or ``++''. */ if (GOx1 >= ct || (opt[GOx1][0] != '-' && opt[GOx1][0] != '+') || !opt[GOx1][1]) return(EOF); if (strcmp(opt[GOx1], "--") == 0 || strcmp(opt[GOx1], "++") == 0) { GOx1++; return(EOF); } GOp = opt[GOx1][0]; GOx2 = 1; } /* * Flag `:' option character as an error. * * Check for a rule on this option character. */ *err = 0; if ((c = opt[GOx1][GOx2]) == ':') { (void) fprintf(stderr, "%s: colon is an illegal option character.\n", Pn); *err = 1; } else if (!(cp = strchr(rules, c))) { (void) fprintf(stderr, "%s: illegal option character: %c\n", Pn, c); *err = 2; } if (*err) { /* * An error was detected. * * Advance to the next option character. * * Return the character causing the error. */ if (opt[GOx1][++GOx2] == '\0') { GOx1++; GOx2 = 0; } return(c); } if (*(cp + 1) == ':') { /* * The option may have a following value. The caller decides * if it does. * * Save the position of the possible value in case the caller * decides it does not belong to the option and wants it * reconsidered as an option character. The caller does that * with: * GOx1 = GObk[0]; GOx2 = GObk[1]; * * Don't indicate that an option of ``--'' is a possible value. * * Finally, on the assumption that the caller will decide that * the possible value belongs to the option, position to the * option following the possible value, so that the next call * to GetOpt() will find it. */ if(opt[GOx1][GOx2 + 1] != '\0') { GObk[0] = GOx1; GObk[1] = ++GOx2; GOv = &opt[GOx1++][GOx2]; } else if (++GOx1 >= ct) GOv = (char *)NULL; else { GObk[0] = GOx1; GObk[1] = 0; GOv = opt[GOx1]; if (strcmp(GOv, "--") == 0) GOv = (char *)NULL; else GOx1++; } GOx2 = 0; } else { /* * The option character stands alone with no following value. * * Advance to the next option character. */ if (opt[GOx1][++GOx2] == '\0') { GOx2 = 0; GOx1++; } GOv = (char *)NULL; } /* * Return the option character. */ return(c); } /* * sv_fmt_str() - save format string */ static char * sv_fmt_str(f) char *f; /* format string */ { char *cp; MALLOC_S l; l = (MALLOC_S)(strlen(f) + 1); if (!(cp = (char *)malloc(l))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for format: %s\n", Pn, (int)l, f); Exit(1); } (void) snpf(cp, l, "%s", f); return(cp); }