diff options
Diffstat (limited to 'dialects/uw/dproc.c')
-rw-r--r-- | dialects/uw/dproc.c | 650 |
1 files changed, 650 insertions, 0 deletions
diff --git a/dialects/uw/dproc.c b/dialects/uw/dproc.c new file mode 100644 index 0000000..0a48d28 --- /dev/null +++ b/dialects/uw/dproc.c @@ -0,0 +1,650 @@ +/* + * dproc.c - SCO UnixWare process access functions for lsof + */ + + +/* + * Copyright 1996 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 1996 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dproc.c,v 1.14 2002/10/08 20:18:34 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local static values + */ + +static int Np; /* occupied P[] count */ +static int Npa = 0; /* allocated P[] count */ +static struct proc *P = (struct proc *)NULL; + /* proc table */ +static KA_T Pract; /* kernel's practive address */ +static KA_T Sgdnops; /* kernel's segdev_ops address */ +static KA_T Sgvnops; /* kernel's segvn_ops address */ +static struct var Var; /* kernel variables */ + + +/* + * Local definitions + */ + +#define PROCINCR 32 /* increment for increasing P[] */ + + +/* + * Local function prototypes. + */ + +_PROTOTYPE(static int get_clonemaj,(void)); +_PROTOTYPE(static void read_proc,(void)); +_PROTOTYPE(static void get_kernel_access,(void)); +_PROTOTYPE(static void readfsinfo,(void)); +_PROTOTYPE(static void process_text,(KA_T pa)); + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + struct cred cr; + struct execinfo ex; + static struct fd_entry *fe; + struct fd_entry *f; + KA_T fa; + int i, nf; + MALLOC_S len; + static int nfea = 0; + struct proc *p; + int pgid, pid, px; + struct pid pids; + short pss, sf; + uid_t uid; + +#if UNIXWAREV>=70103 + struct pollx plx; +#endif /* UNIXWAREV>=70103 */ + +/* + * Examine proc structures and their associated information. + */ + (void) read_proc(); + for (p = P, px = 0; px < Np; p++, px++) { + if ((p->p_flag & P_DESTROY) || (p->p_flag & P_GONE) + || !p->p_pidp + +#if !defined(HAS_P_PGID) + || !p->p_pgidp +#endif /* !defined(HAS_P_PGID) */ + + || !p->p_cred || !p->p_execinfo) + continue; + /* + * Get Process ID, Process group ID, and User ID. + */ + if (!p->p_pidp + || kread((KA_T)p->p_pidp, (char *)&pids, sizeof(pids))) + continue; + pid = (int)pids.pid_id; + +#if defined(HAS_P_PGID) + pgid = (int)p->p_pgid; +#else /* !defined(HAS_P_PGID) */ + if (!p->p_pgidp + || kread((KA_T)p->p_pgidp, (char *)&pids, sizeof(pids))) + continue; + pgid = (int)pids.pid_id; +#endif /* defined(HAS_P_PGID) */ + + if (!p->p_cred + || kread((KA_T)p->p_cred, (char *)&cr, sizeof(cr))) + continue; + uid = cr.cr_uid; + if (is_proc_excl(pid, pgid, (UID_ARG)uid, &pss, &sf)) + continue; + /* + * Get the execution information -- for the command name. + */ + if (!p->p_execinfo + || kread((KA_T)p->p_execinfo, (char *)&ex, sizeof(ex))) + continue; + /* + * Allocate a local process structure. + */ + if (is_cmd_excl(ex.ei_comm, &pss, &sf)) + continue; + alloc_lproc(pid, pgid, (int)p->p_ppid, (UID_ARG)uid, ex.ei_comm, + (int)pss, (int)sf); + Plf = NULL; + /* + * Save current working directory information. + */ + if (p->p_cdir) { + alloc_lfile(CWD, -1); + process_node((KA_T)p->p_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (p->p_rdir) { + alloc_lfile(RTD, -1); + process_node((KA_T)p->p_rdir); + if (Lf->sf) + link_lfile(); + } + /* + * Print information on the text file. + */ + if (Sgvnops && p->p_as) + process_text((KA_T)p->p_as); + /* + * Save information on file descriptors. + */ + if (!p->p_fdtab.fdt_entrytab || (nf = p->p_fdtab.fdt_sizeused) < 1) + continue; + len = (MALLOC_S)(nf * sizeof(struct fd_entry)); + if (nf > nfea) { + if (fe) + fe = (struct fd_entry *)realloc((MALLOC_P *)fe, len); + else + fe = (struct fd_entry *)malloc(len); + if (!fe) { + (void) fprintf(stderr, + "%s: PID %d; no space for %d file descriptors\n", + Pn, pid, nf); + Exit(1); + } + nfea = nf; + } + if (kread((KA_T)p->p_fdtab.fdt_entrytab, (char *)fe, len)) + continue; + for (f = fe, i = 0; i < nf; f++, i++) { + if ((fa = (KA_T)f->fd_file) && (f->fd_status & FD_INUSE)) { + +#if UNIXWAREV>=70103 + if (f->fd_flag & FPOLLED) { + if (kread(fa, (char *)&plx, sizeof(plx)) + || !(fa = (KA_T)plx.px_fp)) + continue; + } +#endif /* UNIXWAREV>=70103 */ + + alloc_lfile(NULL, i); + process_file(fa); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) + Lf->pof = (long)f->fd_flag; +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_clonemaj() - get clone major device number + */ + +static int +get_clonemaj() +{ + KA_T v; + +#if UNIXWAREV<70000 + char buf[32]; + struct cdevsw *c, *cd; + int i, sz; + MALLOC_S len; + int rv = 0; +/* + * Read the cdevsw[] size and allocate temporary space for it. + */ + if (get_Nl_value("ncdev", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&sz, sizeof(sz)) || !sz) + return(rv); + len = (MALLOC_S)(sz * sizeof(struct cdevsw)); + if (!(cd = (struct cdevsw *)malloc(len))) { + (void) fprintf(stderr, "%s: can't allocate %d bytes for cdevsw\n", + Pn); + Exit(1); + } +/* + * Read the cdevsw[] from kernel memory. + */ + if (get_Nl_value("cdev", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)cd, (int)len)) { + (void) free((MALLOC_P *)cd); + return(rv); + } +/* + * Scan the cdevsw[], reading it's names, looking for "clone". + * Record its cdevsw[] index (i.e., major device number). + */ + len = sizeof(buf) - 1; + buf[len] = '\0'; + for (c = cd, i = 0; i < sz; c++, i++) { + if (!c->d_name + || kread((KA_T)c->d_name, buf, len) + || strcmp(buf, "clone") != 0) + continue; + CloneMaj = i; + HaveCloneMaj = rv = 1; + break; + } + (void) free((MALLOC_P *)cd); + return(rv); +#else /* UNIXWAREV>=70000 */ +/* + * At UnixWare 7 the clone major device is found in the kernel's + * clonemajor variable. + */ + if (get_Nl_value("cmaj", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&CloneMaj, sizeof(CloneMaj))) + return(0); + return((HaveCloneMaj = 1)); +#endif /* UNIXWAREV<70000 */ + +} + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + KA_T v; +/* + * Check kernel version. + */ + (void) ckkv("UW", (char *)NULL, LSOF_VSTR, (char *)NULL); + +#if defined(WILLDROPGID) +/* + * If kernel memory isn't coming from KMEM, drop setgid permission + * before attempting to open the (Memory) file. + */ + if (Memory) + (void) dropgid(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the non-KMEM memory file is readable. + */ + if (Memory && !is_readable(Memory, 1)) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Open kernel memory access. + */ + if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) { + (void) fprintf(stderr, "%s: can't open %s: %s\n", Pn, + Memory ? Memory : KMEM, strerror(errno)); + Exit(1); + } + +#if defined(WILLDROPGID) +/* + * Drop setgid permission, if necessary. + */ + if (!Memory) + (void) dropgid(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the name list file is readable. + */ + if (Nmlst && !is_readable(Nmlst, 1)) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Access kernel symbols and values. + */ + (void) build_Nl(Drive_Nl); + if (nlist(Nmlst ? Nmlst : N_UNIX, Nl) < 0) { + (void) fprintf(stderr, "%s: can't read kernel name list from %s\n", + Pn, Nmlst ? Nmlst : N_UNIX); + Exit(1); + } + if (get_Nl_value("var", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&Var, sizeof(Var))) { + (void) fprintf(stderr, + "%s: can't read system configuration info\n", Pn); + Exit(1); + } + if (get_Nl_value("proc", Drive_Nl, &Pract) < 0 || !Pract) { + (void) fprintf(stderr, + "%s: can't find active process chain pointer\n", Pn); + Exit(1); + } + if (get_Nl_value("sgdnops", Drive_Nl, &Sgdnops) < 0 || !Sgdnops) + Sgdnops = (unsigned long)0; + if (get_Nl_value("sgvnops", Drive_Nl, &Sgvnops) < 0 || !Sgvnops) + Sgvnops = (unsigned long)0; +/* + * Identify the clone major device number. + */ + if (!get_clonemaj()) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING; can't identify major clone device number\n", + Pn); + } +} + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); + readfsinfo(); +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + READLEN_T br; + +#if UNIXWAREV<7000 + if (lseek(Kd, (long)addr, L_SET) == (long)-1L) + return(-1); + br = (READLEN_T) read(Kd, buf, len); +#else /* UNIXWAREV>=7000 */ + br = (READLEN_T) pread(Kd, buf, len, (off_t)addr); +#endif /* UNIXWAREV<7000 */ + + return((br == len) ? 0 : 1); +} + + +/* + * process_text() - process text access information + */ + +static void +process_text(pa) + KA_T pa; /* kernel address space description + * pointer */ +{ + struct as as; + struct segdev_data dv; + char *fd; + int i, j, k, l; + struct seg s; + KA_T v[MAXSEGS]; + struct segvn_data vn; + KA_T vp; +/* + * Get address space description. + */ + if (kread(pa, (char *)&as, sizeof(as))) + return; +/* + * Loop through the segments. The loop should stop when the segment + * pointer returns to its starting point, but just in case, it's stopped + * when MAXSEGS have been recorded or 2*MAXSEGS have been examined. + */ + s.s_next = as.a_segs; + for (i = j = k = 0; i < MAXSEGS && j < 2*MAXSEGS; j++) { + if (!s.s_next || kread((KA_T)s.s_next, (char *)&s, sizeof(s))) + break; + fd = (char *)NULL; + vp = (KA_T)NULL; + if (Sgvnops == (KA_T)s.s_ops && s.s_data) { + + /* + * Process a virtual node segment. + */ + if (kread((KA_T)s.s_data, (char *)&vn, sizeof(vn))) + break; + if ((vp = (KA_T)vn.svd_vp)) { + if ((vn.svd_flags & SEGVN_PGPROT) + || (vn.svd_prot & PROT_EXEC)) + fd = " txt"; + else + fd = " mem"; + } + } else if (Sgdnops == (KA_T)s.s_ops && s.s_data) { + + /* + * Process a special device segment. + */ + if (kread((KA_T)s.s_data, (char *)&dv, sizeof(dv))) + break; + if ((vp = (KA_T)dv.vp)) + fd = "mmap"; + } + if (fd && vp) { + + /* + * Process the vnode pointer. First make sure it's unique. + */ + for (l = 0; l < k; l++) { + if (v[l] == vp) + break; + } + if (l >= k) { + alloc_lfile(fd, -1); + process_node(vp); + if (Lf->sf) { + link_lfile(); + i++; + } + } + v[k++] = vp; + } + /* + * Follow the segment link to the starting point in the address + * space description. (The i and j counters place an absolute + * limit on the loop.) + */ + if (s.s_next == as.a_segs) + break; + } +} + + +/* + * readfsinfo() - read file system information + */ + +static void +readfsinfo() +{ + char buf[FSTYPSZ+1]; + int i, len; + + if ((Fsinfomax = sysfs(GETNFSTYP)) == -1) { + (void) fprintf(stderr, "%s: sysfs(GETNFSTYP) error: %s\n", + Pn, strerror(errno)); + Exit(1); + } + if (Fsinfomax == 0) + return; + if (!(Fsinfo = (char **)malloc((MALLOC_S)(Fsinfomax * sizeof(char *))))) + { + (void) fprintf(stderr, "%s: no space for sysfs info\n", Pn); + Exit(1); + } + for (i = 1; i <= Fsinfomax; i++) { + if (sysfs(GETFSTYP, i, buf) == -1) { + (void) fprintf(stderr, "%s: sysfs(GETFSTYP) error: %s\n", + Pn, strerror(errno)); + Exit(1); + } + buf[FSTYPSZ] = '\0'; + len = strlen(buf) + 1; + if (!(Fsinfo[i-1] = (char *)malloc((MALLOC_S)len))) { + (void) fprintf(stderr, + "%s: no space for file system entry %s\n", Pn, buf); + Exit(1); + } + (void) snpf(Fsinfo[i-1], len, "%s", buf); + } +} + + +/* + * read_proc() - read the process table + */ + +static void +read_proc() +{ + MALLOC_S len; + struct proc *p; + KA_T pa; + char tbuf[32]; + int try; + + if (!P) { + + /* + * Allocate initial space for local proc table. + */ + if ((Npa = Var.v_proc) < 1) { + (void) fprintf(stderr, "%s: bad proc table size: %d\n", + Pn, Var.v_proc); + Exit(1); + } + Npa += PROCINCR; + len = (MALLOC_S)(Npa * sizeof(struct proc)); + if (!(P = (struct proc *)malloc(len))) { + (void) fprintf(stderr, "%s: no space for %d proc structures\n", + Pn, Npa); + Exit(1); + } + } +/* + * Scan the active process chain. + */ + for (try = 0; try < PROCTRYLM; try++) { + + /* + * Read the active process chain head. + */ + pa = (KA_T)NULL; + if (!Pract || kread((KA_T)Pract, (char *)&pa, sizeof(pa)) || !pa) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: active proc chain ptr err; addr=%s, val=%s\n", + Pn, print_kptr(Pract, tbuf, sizeof(tbuf)), + print_kptr(pa, (char *)NULL, 0)); + continue; + } + /* + * Follow the active process chain, accumulating proc structures. + */ + for (Np = 0, p = P; pa;) { + if (Np >= Npa) { + + /* + * Allocate more proc table space. + */ + Npa += PROCINCR; + len = (MALLOC_S)(Npa * sizeof(struct proc)); + if (!(P = (struct proc *)realloc((MALLOC_P *)P, len))) { + (void) fprintf(stderr, + "%s: can't realloc %d proc table entries (%d)\n", + Pn, Npa, len); + Exit(1); + } + p = &P[Np]; + } + if (kread(pa, (char *)p, sizeof(struct proc))) + break; + pa = (KA_T)p->p_next; + if ((p->p_flag & P_DESTROY) || (p->p_flag & P_GONE) + || !p->p_pidp + +#if !defined(HAS_P_PGID) + || !p->p_pgidp +#endif /* !defined(HAS_P_PGID) */ + + || !p->p_cred || !p->p_execinfo) + continue; + Np++; + p++; + } + /* + * See if enough processes were accumulated. + */ + if (Np >= PROCMIN) + break; + } +/* + * Quit if not enough proc structures could be collected. + */ + if (try >= PROCTRYLM) { + (void) fprintf(stderr, "%s: can't read proc table\n", Pn); + Exit(1); + } + if (Np < Npa && !RptTm) { + + /* + * If not repeating, reduce the local proc table size to a minimum. + */ + len = (MALLOC_S)(Np * sizeof(struct proc)); + if (!(P = (struct proc *)realloc((MALLOC_P *)P, len))) { + (void) fprintf(stderr, + "%s: can't reduce proc table to %d entries\n", Pn, Np); + Exit(1); + } + Npa = Np; + } +} |