| /* |
| * proc.c - common process and file structure functions for lsof |
| */ |
| |
| |
| /* |
| * 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: proc.c,v 1.46 2010/07/29 15:59:28 abe Exp $"; |
| #endif |
| |
| |
| #include "lsof.h" |
| |
| |
| /* |
| * Local function prototypes |
| */ |
| |
| _PROTOTYPE(static int is_file_sel,(struct lproc *lp, struct lfile *lf)); |
| |
| |
| /* |
| * add_nma() - add to NAME column addition |
| */ |
| |
| void |
| add_nma(cp, len) |
| char *cp; /* string to add */ |
| int len; /* string length */ |
| { |
| int nl; |
| |
| if (!cp || !len) |
| return; |
| if (Lf->nma) { |
| nl = (int)strlen(Lf->nma); |
| Lf->nma = (char *)realloc((MALLOC_P *)Lf->nma, |
| (MALLOC_S)(len + nl + 2)); |
| } else { |
| nl = 0; |
| Lf->nma = (char *)malloc((MALLOC_S)(len + 1)); |
| } |
| if (!Lf->nma) { |
| (void) fprintf(stderr, "%s: no name addition space: PID %ld, FD %s", |
| Pn, (long)Lp->pid, Lf->fd); |
| Exit(1); |
| } |
| if (nl) { |
| Lf->nma[nl] = ' '; |
| (void) strncpy(&Lf->nma[nl + 1], cp, len); |
| Lf->nma[nl + 1 + len] = '\0'; |
| } else { |
| (void) strncpy(Lf->nma, cp, len); |
| Lf->nma[len] = '\0'; |
| } |
| } |
| |
| |
| #if defined(HASFSTRUCT) |
| _PROTOTYPE(static char *alloc_fflbuf,(char **bp, int *al, int lr)); |
| |
| |
| /* |
| * alloc_fflbuf() - allocate file flags print buffer |
| */ |
| |
| static char * |
| alloc_fflbuf(bp, al, lr) |
| char **bp; /* current buffer pointer */ |
| int *al; /* current allocated length */ |
| int lr; /* length required */ |
| { |
| int sz; |
| |
| sz = (int)(lr + 1); /* allocate '\0' space */ |
| if (*bp && (sz <= *al)) |
| return(*bp); |
| if (*bp) |
| *bp = (char *)realloc((MALLOC_P *)*bp, (MALLOC_S)sz); |
| else |
| *bp = (char *)malloc((MALLOC_S)sz); |
| if (!*bp) { |
| (void) fprintf(stderr, "%s: no space (%d) for print flags\n", |
| Pn, sz); |
| Exit(1); |
| } |
| *al = sz; |
| return(*bp); |
| } |
| #endif /* defined(HASFSTRUCT) */ |
| |
| |
| /* |
| * alloc_lfile() - allocate local file structure space |
| */ |
| |
| void |
| alloc_lfile(nm, num) |
| char *nm; /* file descriptor name (may be NULL) */ |
| int num; /* file descriptor number -- -1 if |
| * none */ |
| { |
| int fds; |
| |
| if (Lf) { |
| /* |
| * If reusing a previously allocated structure, release any allocated |
| * space it was using. |
| */ |
| if (Lf->dev_ch) |
| (void) free((FREE_P *)Lf->dev_ch); |
| if (Lf->nm) |
| (void) free((FREE_P *)Lf->nm); |
| if (Lf->nma) |
| (void) free((FREE_P *)Lf->nma); |
| |
| #if defined(HASLFILEADD) && defined(CLRLFILEADD) |
| CLRLFILEADD(Lf) |
| #endif /* defined(HASLFILEADD) && defined(CLRLFILEADD) */ |
| |
| /* |
| * Othwerise, allocate a new structure. |
| */ |
| } else if (!(Lf = (struct lfile *)malloc(sizeof(struct lfile)))) { |
| (void) fprintf(stderr, "%s: no local file space at PID %d\n", |
| Pn, Lp->pid); |
| Exit(1); |
| } |
| /* |
| * Initialize the structure. |
| */ |
| Lf->access = Lf->lock = ' '; |
| Lf->dev_def = Lf->inp_ty = Lf->is_com = Lf->is_nfs = Lf->is_stream |
| = Lf->lmi_srch = Lf->nlink_def = Lf->off_def = Lf->sz_def |
| = Lf->rdev_def |
| = (unsigned char)0; |
| Lf->li[0].af = Lf->li[1].af = 0; |
| Lf->lts.type = -1; |
| Lf->nlink = 0l; |
| |
| #if defined(HASMNTSTAT) |
| Lf->mnt_stat = (unsigned char)0; |
| #endif /* defined(HASMNTSTAT) */ |
| |
| #if defined(HASSOOPT) |
| Lf->lts.kai = Lf->lts.ltm = 0; |
| Lf->lts.opt = Lf->lts.qlen = Lf->lts.qlim = Lf->lts.pqlen |
| = (unsigned int)0; |
| Lf->lts.rbsz = Lf->lts.sbsz = (unsigned long)0; |
| Lf->lts.qlens = Lf->lts.qlims = Lf->lts.pqlens = Lf->lts.rbszs |
| = Lf->lts.sbszs = (unsigned char)0; |
| #endif /* defined(HASSOOPT) */ |
| |
| #if defined(HASSOSTATE) |
| Lf->lts.ss = 0; |
| #endif /* defined(HASSOSTATE) */ |
| |
| #if defined(HASTCPOPT) |
| Lf->lts.mss = (unsigned long)0; |
| Lf->lts.msss = (unsigned char)0; |
| Lf->lts.topt = (unsigned int)0; |
| #endif /* defined(HASTCPOPT) */ |
| |
| #if defined(HASTCPTPIQ) |
| Lf->lts.rqs = Lf->lts.sqs = (unsigned char)0; |
| #endif /* defined(HASTCPTPIQ) */ |
| |
| #if defined(HASTCPTPIW) |
| Lf->lts.rws = Lf->lts.wws = (unsigned char)0; |
| #endif /* defined(HASTCPTPIW) */ |
| |
| #if defined(HASFSINO) |
| Lf->fs_ino = 0; |
| #endif /* defined(HASFSINO) */ |
| |
| #if defined(HASVXFS) && defined(HASVXFSDNLC) |
| Lf->is_vxfs = 0; |
| #endif /* defined(HASVXFS) && defined(HASVXFSDNLC) */ |
| |
| Lf->inode = (INODETYPE)0; |
| Lf->off = (SZOFFTYPE)0; |
| if (Lp->pss & PS_PRI) |
| Lf->sf = Lp->sf; |
| else |
| Lf->sf = 0; |
| Lf->iproto[0] = Lf->type[0] = '\0'; |
| if (nm) { |
| (void) strncpy(Lf->fd, nm, FDLEN - 1); |
| Lf->fd[FDLEN - 1] = '\0'; |
| } else if (num >= 0) { |
| if (num < 10000) |
| (void) snpf(Lf->fd, sizeof(Lf->fd), "%4d", num); |
| else |
| (void) snpf(Lf->fd, sizeof(Lf->fd), "*%03d", num % 1000); |
| } else |
| Lf->fd[0] = '\0'; |
| Lf->dev_ch = Lf->fsdir = Lf->fsdev = Lf->nm = Lf->nma = (char *)NULL; |
| Lf->ch = -1; |
| |
| #if defined(HASNCACHE) && HASNCACHE<2 |
| Lf->na = (KA_T)NULL; |
| #endif /* defined(HASNCACHE) && HASNCACHE<2 */ |
| |
| Lf->next = (struct lfile *)NULL; |
| Lf->ntype = Ntype = N_REGLR; |
| Namech[0] = '\0'; |
| |
| #if defined(HASFSTRUCT) |
| Lf->fct = Lf->ffg = Lf->pof = (long)0; |
| Lf->fna = (KA_T)NULL; |
| Lf->fsv = (unsigned char)0; |
| #endif /* defined(HASFSTRUCT) */ |
| |
| #if defined(HASLFILEADD) && defined(SETLFILEADD) |
| /* |
| * Do local initializations. |
| */ |
| SETLFILEADD |
| #endif /* defined(HASLFILEADD) && defined(SETLFILEADD) */ |
| |
| /* |
| * See if the file descriptor has been selected. |
| */ |
| if (!Fdl || (!nm && num < 0)) |
| return; |
| fds = ck_fd_status(nm, num); |
| switch (FdlTy) { |
| case 0: /* inclusion list */ |
| if (fds == 2) |
| Lf->sf |= SELFD; |
| break; |
| case 1: /* exclusion list */ |
| if (fds != 1) |
| Lf->sf |= SELFD; |
| } |
| } |
| |
| |
| /* |
| * alloc_lproc() - allocate local proc structure space |
| */ |
| |
| void |
| alloc_lproc(pid, pgid, ppid, uid, cmd, pss, sf) |
| int pid; /* Process ID */ |
| int pgid; /* process group ID */ |
| int ppid; /* parent process ID */ |
| UID_ARG uid; /* User ID */ |
| char *cmd; /* command */ |
| int pss; /* process select state */ |
| int sf; /* process select flags */ |
| { |
| static int sz = 0; |
| |
| if (!Lproc) { |
| if (!(Lproc = (struct lproc *)malloc( |
| (MALLOC_S)(LPROCINCR * sizeof(struct lproc))))) |
| { |
| (void) fprintf(stderr, |
| "%s: no malloc space for %d local proc structures\n", |
| Pn, LPROCINCR); |
| Exit(1); |
| } |
| sz = LPROCINCR; |
| } else if ((Nlproc + 1) > sz) { |
| sz += LPROCINCR; |
| if (!(Lproc = (struct lproc *)realloc((MALLOC_P *)Lproc, |
| (MALLOC_S)(sz * sizeof(struct lproc))))) |
| { |
| (void) fprintf(stderr, |
| "%s: no realloc space for %d local proc structures\n", |
| Pn, sz); |
| Exit(1); |
| } |
| } |
| Lp = &Lproc[Nlproc++]; |
| Lp->pid = pid; |
| |
| #if defined(HASTASKS) |
| Lp->tid = 0; |
| #endif /* defined(HASTASKS) */ |
| |
| Lp->pgid = pgid; |
| Lp->ppid = ppid; |
| Lp->file = (struct lfile *)NULL; |
| Lp->sf = (short)sf; |
| Lp->pss = (short)pss; |
| Lp->uid = (uid_t)uid; |
| /* |
| * Allocate space for the full command name and copy it there. |
| */ |
| if (!(Lp->cmd = mkstrcpy(cmd, (MALLOC_S *)NULL))) { |
| (void) fprintf(stderr, "%s: PID %d, no space for command name: ", |
| Pn, pid); |
| safestrprt(cmd, stderr, 1); |
| Exit(1); |
| } |
| |
| #if defined(HASZONES) |
| /* |
| * Clear the zone name pointer. The dialect's own code will set it. |
| */ |
| Lp->zn = (char *)NULL; |
| #endif /* defined(HASZONES) */ |
| |
| #if defined(HASSELINUX) |
| /* |
| * Clear the security context pointer. The dialect's own code will |
| * set it. |
| */ |
| Lp->cntx = (char *)NULL; |
| #endif /* defined(HASSELINUX) */ |
| |
| } |
| |
| |
| /* |
| * ck_fd_status() - check FD status |
| * |
| * return: 0 == FD is neither included nor excluded |
| * 1 == FD is excluded |
| * 2 == FD is included |
| */ |
| |
| extern int |
| ck_fd_status(nm, num) |
| char *nm; /* file descriptor name (may be NULL) */ |
| int num; /* file descriptor number -- -1 if |
| * none */ |
| { |
| char *cp; |
| struct fd_lst *fp; |
| |
| if (!(fp = Fdl) || (!nm && num < 0)) |
| return(0); |
| if ((cp = nm)) { |
| while (*cp && *cp == ' ') |
| cp++; |
| } |
| /* |
| * Check for an exclusion match. |
| */ |
| if (FdlTy == 1) { |
| for (; fp; fp = fp->next) { |
| if (cp) { |
| if (fp->nm && strcmp(fp->nm, cp) == 0) |
| return(1); |
| continue; |
| } |
| if (num >= fp->lo && num <= fp->hi) |
| return(1); |
| } |
| return(0); |
| } |
| /* |
| * If Fdl isn't an exclusion list, check for an inclusion match. |
| */ |
| for (; fp; fp = fp->next) { |
| if (cp) { |
| if (fp->nm && strcmp(fp->nm, cp) == 0) |
| return(2); |
| continue; |
| } |
| if (num >= fp->lo && num <= fp->hi) |
| return(2); |
| } |
| return(0); |
| } |
| |
| |
| /* |
| * comppid() - compare PIDs |
| */ |
| |
| int |
| comppid(a1, a2) |
| COMP_P *a1, *a2; |
| { |
| struct lproc **p1 = (struct lproc **)a1; |
| struct lproc **p2 = (struct lproc **)a2; |
| |
| if ((*p1)->pid < (*p2)->pid) |
| return(-1); |
| if ((*p1)->pid > (*p2)->pid) |
| return(1); |
| |
| #if defined(HASTASKS) |
| if ((*p1)->tid < (*p2)->tid) |
| return(-1); |
| if ((*p1)->tid > (*p2)->tid) |
| return(1); |
| #endif /* defined(HASTASKS) */ |
| |
| return(0); |
| } |
| |
| |
| /* |
| * ent_inaddr() - enter Internet addresses |
| */ |
| |
| void |
| ent_inaddr(la, lp, fa, fp, af) |
| unsigned char *la; /* local Internet address */ |
| int lp; /* local port */ |
| unsigned char *fa; /* foreign Internet address -- may |
| * be NULL to indicate no foreign |
| * address is known */ |
| int fp; /* foreign port */ |
| int af; /* address family -- e.g, AF_INET, |
| * AF_INET */ |
| { |
| int m; |
| |
| if (la) { |
| Lf->li[0].af = af; |
| |
| #if defined(HASIPv6) |
| if (af == AF_INET6) |
| Lf->li[0].ia.a6 = *(struct in6_addr *)la; |
| else |
| #endif /* defined(HASIPv6) */ |
| |
| Lf->li[0].ia.a4 = *(struct in_addr *)la; |
| Lf->li[0].p = lp; |
| } else |
| Lf->li[0].af = 0; |
| if (fa) { |
| Lf->li[1].af = af; |
| |
| #if defined(HASIPv6) |
| if (af == AF_INET6) |
| Lf->li[1].ia.a6 = *(struct in6_addr *)fa; |
| else |
| #endif /* defined(HASIPv6) */ |
| |
| Lf->li[1].ia.a4 = *(struct in_addr *)fa; |
| Lf->li[1].p = fp; |
| } else |
| Lf->li[1].af = 0; |
| /* |
| * If network address matching has been selected, check both addresses. |
| */ |
| if ((Selflags & SELNA) && Nwad) { |
| m = (fa && is_nw_addr(fa, fp, af)) ? 1 : 0; |
| m |= (la && is_nw_addr(la, lp, af)) ? 1 : 0; |
| if (m) |
| Lf->sf |= SELNA; |
| } |
| } |
| |
| |
| /* |
| * examine_lproc() - examine local process |
| * |
| * return: 1 = last process |
| */ |
| |
| int |
| examine_lproc() |
| { |
| int sbp = 0; |
| |
| if (RptTm) |
| return(0); |
| /* |
| * List the process if the process is selected and: |
| * |
| * o listing is limited to a single PID selection -- this one; |
| * |
| * o listing is selected by an ANDed option set (not all options) |
| * that includes a single PID selection -- this one. |
| */ |
| if ((Lp->sf & SELPID) && !Selall) { |
| if ((Selflags == SELPID) |
| || (Fand && (Selflags & SELPID))) { |
| sbp = 1; |
| Npuns--; |
| } |
| } |
| if (Lp->pss && Npid == 1 && sbp) { |
| print_init(); |
| (void) print_proc(); |
| PrPass++; |
| if (PrPass < 2) |
| (void) print_proc(); |
| Lp->pss = 0; |
| } |
| /* |
| * Deprecate an unselected (or listed) process. |
| */ |
| if ( ! Lp->pss) { |
| (void) free_lproc(Lp); |
| Nlproc--; |
| } |
| /* |
| * Indicate last-process if listing is limited to PID selections, |
| * and all selected processes have been listed. |
| */ |
| return((sbp && Npuns == 0) ? 1 : 0); |
| } |
| |
| |
| /* |
| * free_lproc() - free lproc entry and its associated malloc'd space |
| */ |
| |
| void |
| free_lproc(lp) |
| struct lproc *lp; |
| { |
| struct lfile *lf, *nf; |
| |
| for (lf = lp->file; lf; lf = nf) { |
| if (lf->dev_ch) { |
| (void) free((FREE_P *)lf->dev_ch); |
| lf->dev_ch = (char *)NULL; |
| } |
| if (lf->nm) { |
| (void) free((FREE_P *)lf->nm); |
| lf->nm = (char *)NULL; |
| } |
| if (lf->nma) { |
| (void) free((FREE_P *)lf->nma); |
| lf->nma = (char *)NULL; |
| } |
| |
| #if defined(HASLFILEADD) && defined(CLRLFILEADD) |
| CLRLFILEADD(lf) |
| #endif /* defined(HASLFILEADD) && defined(CLRLFILEADD) */ |
| |
| nf = lf->next; |
| (void) free((FREE_P *)lf); |
| } |
| lp->file = (struct lfile *)NULL; |
| if (lp->cmd) { |
| (void) free((FREE_P *)lp->cmd); |
| lp->cmd = (char *)NULL; |
| } |
| } |
| |
| |
| /* |
| * is_cmd_excl() - is command excluded? |
| */ |
| |
| int |
| is_cmd_excl(cmd, pss, sf) |
| char *cmd; /* command name */ |
| short *pss; /* process state */ |
| short *sf; /* process select flags */ |
| { |
| int i; |
| struct str_lst *sp; |
| /* |
| * See if the command is excluded by a "-c^<command>" option. |
| */ |
| if (Cmdl && Cmdnx) { |
| for (sp = Cmdl; sp; sp = sp->next) { |
| if (sp->x && !strncmp(sp->str, cmd, sp->len)) |
| return(1); |
| } |
| } |
| /* |
| * The command is not excluded if no command selection was requested, |
| * or if its name matches any -c <command> specification. |
| * |
| */ |
| if ((Selflags & SELCMD) == 0) |
| return(0); |
| for (sp = Cmdl; sp; sp = sp->next) { |
| if (!sp->x && !strncmp(sp->str, cmd, sp->len)) { |
| sp->f = 1; |
| *pss |= PS_PRI; |
| *sf |= SELCMD; |
| return(0); |
| } |
| } |
| /* |
| * The command name doesn't match any -c <command> specification. See if it |
| * matches a -c /RE/[bix] specification. |
| */ |
| for (i = 0; i < NCmdRxU; i++) { |
| if (!regexec(&CmdRx[i].cx, cmd, 0, NULL, 0)) { |
| CmdRx[i].mc = 1; |
| *pss |= PS_PRI; |
| *sf |= SELCMD; |
| return(0); |
| } |
| } |
| /* |
| * The command name matches no -c specification. |
| * |
| * It's excluded if the only selection condition is command name, |
| * or if command name selection is part of an ANDed set. |
| */ |
| if (Selflags == SELCMD) |
| return(1); |
| return (Fand ? 1 : 0); |
| } |
| |
| |
| /* |
| * is_file_sel() - is file selected? |
| */ |
| |
| static int |
| is_file_sel(lp, lf) |
| struct lproc *lp; /* lproc structure pointer */ |
| struct lfile *lf; /* lfile structure pointer */ |
| { |
| if (!lf || !lf->sf) |
| return(0); |
| if (Lf->sf & SELEXCLF) |
| return(0); |
| |
| #if defined(HASSECURITY) && defined(HASNOSOCKSECURITY) |
| if (Myuid && (Myuid != lp->uid)) { |
| if (!(lf->sf & (SELNA | SELNET))) |
| return(0); |
| } |
| #endif /* defined(HASSECURITY) && defined(HASNOSOCKSECURITY) */ |
| |
| if (Selall) |
| return(1); |
| if (Fand && ((lf->sf & Selflags) != Selflags)) |
| return(0); |
| return(1); |
| } |
| |
| |
| /* |
| * is_proc_excl() - is process excluded? |
| */ |
| |
| int |
| |
| #if defined(HASTASKS) |
| is_proc_excl(pid, pgid, uid, pss, sf, tid) |
| #else /* !defined(HASTASKS) */ |
| is_proc_excl(pid, pgid, uid, pss, sf) |
| #endif /* defined(HASTASKS) */ |
| |
| int pid; /* Process ID */ |
| int pgid; /* process group ID */ |
| UID_ARG uid; /* User ID */ |
| short *pss; /* process select state for lproc */ |
| short *sf; /* select flags for lproc */ |
| |
| #if defined(HASTASKS) |
| int tid; /* task ID (not a task if zero) */ |
| #endif /* defined(HASTASKS) */ |
| |
| { |
| int i, j; |
| |
| *pss = *sf = 0; |
| |
| #if defined(HASSECURITY) |
| /* |
| * The process is excluded by virtue of the security option if it |
| * isn't owned by the owner of this lsof process, unless the |
| * HASNOSOCKSECURITY option is also specified. In that case the |
| * selected socket files of any process may be listed. |
| */ |
| # if !defined(HASNOSOCKSECURITY) |
| if (Myuid && Myuid != (uid_t)uid) |
| return(1); |
| # endif /* !defined(HASNOSOCKSECURITY) */ |
| #endif /* defined(HASSECURITY) */ |
| |
| /* |
| * If the excluding of process listing by UID has been specified, see if the |
| * owner of this process is excluded. |
| */ |
| if (Nuidexcl) { |
| for (i = j = 0; (i < Nuid) && (j < Nuidexcl); i++) { |
| if (!Suid[i].excl) |
| continue; |
| if (Suid[i].uid == (uid_t)uid) |
| return(1); |
| j++; |
| } |
| } |
| /* |
| * If the excluding of process listing by PGID has been specified, see if this |
| * PGID is excluded. |
| */ |
| if (Npgidx) { |
| for (i = j = 0; (i < Npgid) && (j < Npgidx); i++) { |
| if (!Spgid[i].x) |
| continue; |
| if (Spgid[i].i == pgid) |
| return(1); |
| j++; |
| } |
| } |
| /* |
| * If the excluding of process listing by PID has been specified, see if this |
| * PID is excluded. |
| */ |
| if (Npidx) { |
| for (i = j = 0; (i < Npid) && (j < Npidx); i++) { |
| if (!Spid[i].x) |
| continue; |
| if (Spid[i].i == pid) |
| return(1); |
| j++; |
| } |
| } |
| /* |
| * If the listing of all processes is selected, then this one is not excluded. |
| * |
| * However, if HASSECURITY and HASNOSOCKSECURITY are both specified, exclude |
| * network selections from the file flags, so that the tests in is_file_sel() |
| * work as expected. |
| */ |
| if (Selall) { |
| *pss = PS_PRI; |
| |
| #if defined(HASSECURITY) && defined(HASNOSOCKSECURITY) |
| *sf = SELALL & ~(SELNA | SELNET); |
| #else /* !defined(HASSECURITY) || !defined(HASNOSOCKSECURITY) */ |
| *sf = SELALL; |
| #endif /* defined(HASSECURITY) && defined(HASNOSOCKSECURITY) */ |
| |
| return(0); |
| } |
| /* |
| * If the listing of processes has been specified by process group ID, see |
| * if this one is included or excluded. |
| */ |
| if (Npgidi && (Selflags & SELPGID)) { |
| for (i = j = 0; (i < Npgid) && (j < Npgidi); i++) { |
| if (Spgid[i].x) |
| continue; |
| if (Spgid[i].i == pgid) { |
| Spgid[i].f = 1; |
| *pss = PS_PRI; |
| *sf = SELPGID; |
| if (Selflags == SELPGID) |
| return(0); |
| break; |
| } |
| j++; |
| } |
| if ((Selflags == SELPGID) && !*sf) |
| return(1); |
| } |
| /* |
| * If the listing of processes has been specified by PID, see if this one is |
| * included or excluded. |
| */ |
| if (Npidi && (Selflags & SELPID)) { |
| for (i = j = 0; (i < Npid) && (j < Npidi); i++) { |
| if (Spid[i].x) |
| continue; |
| if (Spid[i].i == pid) { |
| Spid[i].f = 1; |
| *pss = PS_PRI; |
| *sf |= SELPID; |
| if (Selflags == SELPID) |
| return(0); |
| break; |
| } |
| j++; |
| } |
| if ((Selflags == SELPID) && !*sf) |
| return(1); |
| } |
| /* |
| * If the listing of processes has been specified by UID, see if the owner of |
| * this process has been included. |
| */ |
| if (Nuidincl && (Selflags & SELUID)) { |
| for (i = j = 0; (i < Nuid) && (j < Nuidincl); i++) { |
| if (Suid[i].excl) |
| continue; |
| if (Suid[i].uid == (uid_t)uid) { |
| Suid[i].f = 1; |
| *pss = PS_PRI; |
| *sf |= SELUID; |
| if (Selflags == SELUID) |
| return(0); |
| break; |
| } |
| j++; |
| } |
| if (Selflags == SELUID && (*sf & SELUID) == 0) |
| return(1); |
| } |
| |
| #if defined(HASTASKS) |
| if ((Selflags & SELTASK) && tid) { |
| |
| /* |
| * This is a task and tasks are selected. |
| */ |
| *pss = PS_PRI; |
| *sf |= SELTASK; |
| if ((Selflags == SELTASK) |
| || (Fand && ((*sf & Selflags) == Selflags))) |
| return(0); |
| } |
| #endif /* defined(HASTASKS) */ |
| |
| /* |
| * When neither the process group ID, nor the PID, nor the task, nor the UID |
| * is selected: |
| * |
| * If list option ANDing of process group IDs, PIDs, UIDs or tasks is |
| * specified, the process is excluded; |
| * |
| * Otherwise, it's not excluded by the tests of this function. |
| */ |
| if ( ! *sf) |
| return((Fand && (Selflags & (SELPGID|SELPID|SELUID|SELTASK))) |
| ? 1 : 0); |
| /* |
| * When the process group ID, PID, task or UID is selected and the process |
| * group ID, PID, task or UID list option has been specified: |
| * |
| * If list option ANDing has been specified, and the correct |
| * combination of selections are in place, reply that the process is no |
| * excluded; |
| * or |
| * If list option ANDing has not been specified, reply that the |
| * process is not excluded by the tests of this function. |
| */ |
| if (Selflags & (SELPGID|SELPID|SELUID|SELTASK)) { |
| if (Fand) |
| return(((Selflags & (SELPGID|SELPID|SELUID|SELTASK)) != *sf) |
| ? 1 : 0); |
| return(0); |
| } |
| /* |
| * Finally, when neither the process group ID, nor the PID, nor the UID, nor |
| * the task is selected, and no applicable list option has been specified: |
| * |
| * If list option ANDing has been specified, this process is |
| * excluded; |
| * |
| * Otherwise, it isn't excluded by the tests of this function. |
| */ |
| return(Fand ? 1 : 0); |
| } |
| |
| |
| /* |
| * link_lfile() - link local file structures |
| */ |
| |
| void |
| link_lfile() |
| { |
| if (Lf->sf & SELEXCLF) |
| return; |
| Lp->pss |= PS_SEC; |
| if (Plf) |
| Plf->next = Lf; |
| else |
| Lp->file = Lf; |
| Plf = Lf; |
| if (Fnet && (Lf->sf & SELNET)) |
| Fnet = 2; |
| if (Fnfs && (Lf->sf & SELNFS)) |
| Fnfs = 2; |
| if (Ftask && (Lf->sf & SELTASK)) |
| Ftask = 2; |
| Lf = (struct lfile *)NULL; |
| } |
| |
| |
| #if defined(HASFSTRUCT) |
| /* |
| * print_fflags() - print interpreted f_flag[s] |
| */ |
| |
| char * |
| print_fflags(ffg, pof) |
| long ffg; /* file structure's flags value */ |
| long pof; /* process open files flags value */ |
| { |
| int al, ct, fx; |
| static int bl = 0; |
| static char *bp = (char *)NULL; |
| char *sep; |
| int sepl; |
| struct pff_tab *tp; |
| long wf; |
| char xbuf[64]; |
| /* |
| * Reduce the supplied flags according to the definitions in Pff_tab[] and |
| * Pof_tab[]. |
| */ |
| for (ct = fx = 0; fx < 2; fx++) { |
| if (fx == 0) { |
| sep = ""; |
| sepl = 0; |
| tp = Pff_tab; |
| wf = ffg; |
| } else { |
| sep = ";"; |
| sepl = 1; |
| tp = Pof_tab; |
| wf = pof; |
| } |
| for (; wf && !FsvFlagX; ct += al ) { |
| while (tp->nm) { |
| if (wf & tp->val) |
| break; |
| tp++; |
| } |
| if (!tp->nm) |
| break; |
| al = (int)strlen(tp->nm) + sepl; |
| bp = alloc_fflbuf(&bp, &bl, al + ct); |
| (void) snpf(bp + ct, al + 1, "%s%s", sep, tp->nm); |
| sep = ","; |
| sepl = 1; |
| wf &= ~(tp->val); |
| } |
| /* |
| * If flag bits remain, print them in hex. If hex output was |
| * specified with +fG, print all flag values, including zero, |
| * in hex. |
| */ |
| if (wf || FsvFlagX) { |
| (void) snpf(xbuf, sizeof(xbuf), "0x%lx", wf); |
| al = (int)strlen(xbuf) + sepl; |
| bp = alloc_fflbuf(&bp, &bl, al + ct); |
| (void) snpf(bp + ct, al + 1, "%s%s", sep, xbuf); |
| ct += al; |
| } |
| } |
| /* |
| * Make sure there is at least a NUL terminated reply. |
| */ |
| if (!bp) { |
| bp = alloc_fflbuf(&bp, &bl, 0); |
| *bp = '\0'; |
| } |
| return(bp); |
| } |
| #endif /* defined(HASFSTRUCT) */ |
| |
| |
| /* |
| * print_proc() - print process |
| */ |
| |
| int |
| print_proc() |
| { |
| char buf[128], *cp; |
| int lc, len, st, ty; |
| int rv = 0; |
| unsigned long ul; |
| /* |
| * If nothing in the process has been selected, skip it. |
| */ |
| if (!Lp->pss) |
| return(0); |
| if (Fterse) { |
| |
| #if defined(HASTASKS) |
| /* |
| * If this is a task of a process, skip it. |
| */ |
| if (Lp->tid) |
| return(0); |
| #endif /* defined(HASTASKS) */ |
| |
| /* |
| * The mode is terse and something in the process appears to have |
| * been selected. Make sure of that by looking for a selected file, |
| * so that the HASSECURITY and HASNOSOCKSECURITY option combination |
| * won't produce a false positive result. |
| */ |
| for (Lf = Lp->file; Lf; Lf = Lf->next) { |
| if (is_file_sel(Lp, Lf)) { |
| (void) printf("%d\n", Lp->pid); |
| return(1); |
| } |
| } |
| return(0); |
| } |
| /* |
| * If fields have been selected, output the process-only ones, provided |
| * that some file has also been selected. |
| */ |
| if (Ffield) { |
| for (Lf = Lp->file; Lf; Lf = Lf->next) { |
| if (is_file_sel(Lp, Lf)) |
| break; |
| } |
| if (!Lf) |
| return(rv); |
| rv = 1; |
| (void) printf("%c%d%c", LSOF_FID_PID, Lp->pid, Terminator); |
| |
| #if defined(HASTASKS) |
| if (FieldSel[LSOF_FIX_TID].st && Lp->tid) |
| (void) printf("%c%d%c", LSOF_FID_TID, Lp->tid, Terminator); |
| #endif /* defined(HASTASKS) */ |
| |
| #if defined(HASZONES) |
| if (FieldSel[LSOF_FIX_ZONE].st && Fzone && Lp->zn) |
| (void) printf("%c%s%c", LSOF_FID_ZONE, Lp->zn, Terminator); |
| #endif /* defined(HASZONES) */ |
| |
| #if defined(HASSELINUX) |
| if (FieldSel[LSOF_FIX_CNTX].st && Fcntx && Lp->cntx && CntxStatus) |
| (void) printf("%c%s%c", LSOF_FID_CNTX, Lp->cntx, Terminator); |
| #endif /* defined(HASSELINUX) */ |
| |
| if (FieldSel[LSOF_FIX_PGID].st && Fpgid) |
| (void) printf("%c%d%c", LSOF_FID_PGID, Lp->pgid, Terminator); |
| |
| #if defined(HASPPID) |
| if (FieldSel[LSOF_FIX_PPID].st && Fppid) |
| (void) printf("%c%d%c", LSOF_FID_PPID, Lp->ppid, Terminator); |
| #endif /* defined(HASPPID) */ |
| |
| if (FieldSel[LSOF_FIX_CMD].st) { |
| putchar(LSOF_FID_CMD); |
| safestrprt(Lp->cmd ? Lp->cmd : "(unknown)", stdout, 0); |
| putchar(Terminator); |
| } |
| if (FieldSel[LSOF_FIX_UID].st) |
| (void) printf("%c%d%c", LSOF_FID_UID, (int)Lp->uid, Terminator); |
| if (FieldSel[LSOF_FIX_LOGIN].st) { |
| cp = printuid((UID_ARG)Lp->uid, &ty); |
| if (ty == 0) |
| (void) printf("%c%s%c", LSOF_FID_LOGIN, cp, Terminator); |
| } |
| if (Terminator == '\0') |
| putchar('\n'); |
| } |
| /* |
| * Print files. |
| */ |
| for (Lf = Lp->file; Lf; Lf = Lf->next) { |
| if (!is_file_sel(Lp, Lf)) |
| continue; |
| rv = 1; |
| /* |
| * If no field output selected, print dialects-specific formatted |
| * output. |
| */ |
| if (!Ffield) { |
| print_file(); |
| continue; |
| } |
| /* |
| * Print selected fields. |
| */ |
| lc = st = 0; |
| if (FieldSel[LSOF_FIX_FD].st) { |
| for (cp = Lf->fd; *cp == ' '; cp++) |
| ; |
| if (*cp) { |
| (void) printf("%c%s%c", LSOF_FID_FD, cp, Terminator); |
| lc++; |
| } |
| } |
| if (FieldSel[LSOF_FIX_ACCESS].st) { |
| (void) printf("%c%c%c", |
| LSOF_FID_ACCESS, Lf->access, Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_LOCK].st) { |
| (void) printf("%c%c%c", LSOF_FID_LOCK, Lf->lock, Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_TYPE].st) { |
| for (cp = Lf->type; *cp == ' '; cp++) |
| ; |
| if (*cp) { |
| (void) printf("%c%s%c", LSOF_FID_TYPE, cp, Terminator); |
| lc++; |
| } |
| } |
| |
| #if defined(HASFSTRUCT) |
| if (FieldSel[LSOF_FIX_FA].st && (Fsv & FSV_FA) |
| && (Lf->fsv & FSV_FA)) { |
| (void) printf("%c%s%c", LSOF_FID_FA, |
| print_kptr(Lf->fsa, (char *)NULL, 0), Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_CT].st && (Fsv & FSV_CT) |
| && (Lf->fsv & FSV_CT)) { |
| (void) printf("%c%ld%c", LSOF_FID_CT, Lf->fct, Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_FG].st && (Fsv & FSV_FG) |
| && (Lf->fsv & FSV_FG) && (FsvFlagX || Lf->ffg || Lf->pof)) { |
| (void) printf("%c%s%c", LSOF_FID_FG, |
| print_fflags(Lf->ffg, Lf->pof), Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_NI].st && (Fsv & FSV_NI) |
| && (Lf->fsv & FSV_NI)) { |
| (void) printf("%c%s%c", LSOF_FID_NI, |
| print_kptr(Lf->fna, (char *)NULL, 0), Terminator); |
| lc++; |
| } |
| #endif /* defined(HASFSTRUCT) */ |
| |
| if (FieldSel[LSOF_FIX_DEVCH].st && Lf->dev_ch && Lf->dev_ch[0]) { |
| for (cp = Lf->dev_ch; *cp == ' '; cp++) |
| ; |
| if (*cp) { |
| (void) printf("%c%s%c", LSOF_FID_DEVCH, cp, Terminator); |
| lc++; |
| } |
| } |
| if (FieldSel[LSOF_FIX_DEVN].st && Lf->dev_def) { |
| if (sizeof(unsigned long) > sizeof(dev_t)) |
| ul = (unsigned long)((unsigned int)Lf->dev); |
| else |
| ul = (unsigned long)Lf->dev; |
| (void) printf("%c0x%lx%c", LSOF_FID_DEVN, ul, Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_RDEV].st && Lf->rdev_def) { |
| if (sizeof(unsigned long) > sizeof(dev_t)) |
| ul = (unsigned long)((unsigned int)Lf->rdev); |
| else |
| ul = (unsigned long)Lf->rdev; |
| (void) printf("%c0x%lx%c", LSOF_FID_RDEV, ul, Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_SIZE].st && Lf->sz_def) { |
| putchar(LSOF_FID_SIZE); |
| |
| #if defined(HASPRINTSZ) |
| cp = HASPRINTSZ(Lf); |
| #else /* !defined(HASPRINTSZ) */ |
| (void) snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); |
| cp = buf; |
| #endif /* defined(HASPRINTSZ) */ |
| |
| (void) printf("%s", cp); |
| putchar(Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_OFFSET].st && Lf->off_def) { |
| putchar(LSOF_FID_OFFSET); |
| |
| #if defined(HASPRINTOFF) |
| cp = HASPRINTOFF(Lf, 0); |
| #else /* !defined(HASPRINTOFF) */ |
| (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); |
| cp = buf; |
| #endif /* defined(HASPRINTOFF) */ |
| |
| len = strlen(cp); |
| if (OffDecDig && len > (OffDecDig + 2)) { |
| |
| #if defined(HASPRINTOFF) |
| cp = HASPRINTOFF(Lf, 1); |
| #else /* !defined(HASPRINTOFF) */ |
| (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); |
| cp = buf; |
| #endif /* defined(HASPRINTOFF) */ |
| |
| } |
| (void) printf("%s", cp); |
| putchar(Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_INODE].st && Lf->inp_ty == 1) { |
| putchar(LSOF_FID_INODE); |
| (void) printf(InodeFmt_d, Lf->inode); |
| putchar(Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_NLINK].st && Lf->nlink_def) { |
| (void) printf("%c%ld%c", LSOF_FID_NLINK, Lf->nlink, Terminator); |
| lc++; |
| } |
| if (FieldSel[LSOF_FIX_PROTO].st && Lf->inp_ty == 2) { |
| for (cp = Lf->iproto; *cp == ' '; cp++) |
| ; |
| if (*cp) { |
| (void) printf("%c%s%c", LSOF_FID_PROTO, cp, Terminator); |
| lc++; |
| } |
| } |
| if (FieldSel[LSOF_FIX_STREAM].st && Lf->nm && Lf->is_stream) { |
| if (strncmp(Lf->nm, "STR:", 4) == 0 |
| || strcmp(Lf->iproto, "STR") == 0) { |
| putchar(LSOF_FID_STREAM); |
| printname(0); |
| putchar(Terminator); |
| lc++; |
| st++; |
| } |
| } |
| if (st == 0 && FieldSel[LSOF_FIX_NAME].st) { |
| putchar(LSOF_FID_NAME); |
| printname(0); |
| putchar(Terminator); |
| lc++; |
| } |
| if (Lf->lts.type >= 0 && FieldSel[LSOF_FIX_TCPTPI].st) { |
| print_tcptpi(0); |
| lc++; |
| } |
| if (Terminator == '\0' && lc) |
| putchar('\n'); |
| } |
| return(rv); |
| } |