summaryrefslogtreecommitdiff
path: root/dialects/uw/dproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'dialects/uw/dproc.c')
-rw-r--r--dialects/uw/dproc.c650
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;
+ }
+}