summaryrefslogtreecommitdiff
path: root/dialects/darwin/kmem/ddev.c
diff options
context:
space:
mode:
Diffstat (limited to 'dialects/darwin/kmem/ddev.c')
-rw-r--r--dialects/darwin/kmem/ddev.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/dialects/darwin/kmem/ddev.c b/dialects/darwin/kmem/ddev.c
new file mode 100644
index 0000000..fc6ce28
--- /dev/null
+++ b/dialects/darwin/kmem/ddev.c
@@ -0,0 +1,479 @@
+/*
+ * ddev.c - Darwin device support functions for /dev/kmem-based 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: ddev.c,v 1.5 2006/03/27 23:24:50 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#if defined(DVCH_DEVPATH)
+#define DDEV_DEVPATH DVCH_DEVPATH
+#else /* !defined(DVCH_DEVPATH) */
+#define DDEV_DEVPATH "/dev"
+#endif /* defined(DVCH_DEVPATH) */
+
+#if defined(USE_STAT)
+#define STATFN stat
+#else /* !defined(USE_STAT) */
+#define STATFN lstat
+#endif /* defined(USE_STAT) */
+
+
+/*
+ * Local static variables.
+ */
+
+static dev_t *ADev = (dev_t *) NULL; /* device numbers besides DevDev found
+ * inside DDEV_DEVPATH */
+static int ADevA = 0; /* entries allocated to ADev[] */
+static int ADevU = 0; /* entries used in ADev[] */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm));
+_PROTOTYPE(static void saveADev,(struct stat *s));
+
+
+#if defined(HASSPECDEVD)
+/*
+ * HASSPECDEVD() -- process stat(2) result to see if the device number is
+ * inside DDEV_DEVPATH "/"
+ *
+ * exit: s->st_dev changed to DevDev, as required
+ */
+
+void
+HASSPECDEVD(p, s)
+ char *p; /* file path */
+ struct stat *s; /* stat(2) result for file */
+{
+ int i;
+
+ switch (s->st_mode & S_IFMT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ if (s->st_dev == DevDev)
+ return;
+ (void) readdev(0);
+ if (!ADev)
+ return;
+ for (i = 0; i < ADevU; i++) {
+ if (s->st_dev == ADev[i]) {
+ s->st_dev = DevDev;
+ return;
+ }
+ }
+ }
+}
+#endif /* defined(HASSPECDEVD) */
+
+
+/*
+ * readdev() - read device names, modes and types
+ */
+
+void
+readdev(skip)
+ int skip; /* skip device cache read if 1 --
+ * ignored since device cache not
+ * used */
+{
+ DIR *dfp;
+ int dnamlen;
+ struct dirent *dp;
+ char *fp = (char *)NULL;
+ char *path = (char *)NULL;
+ int i = 0;
+ int j = 0;
+ MALLOC_S pl, sz;
+ struct stat sb;
+/*
+ * Read device names but once.
+ */
+ if (Sdev)
+ return;
+/*
+ * Prepare to scan DDEV_DEVPATH.
+ */
+ Dstkn = Dstkx = 0;
+ Dstk = (char **)NULL;
+ (void) stkdir(DDEV_DEVPATH);
+/*
+ * Unstack the next directory.
+ */
+ while (--Dstkx >= 0) {
+ if (!(dfp = OpenDir(Dstk[Dstkx]))) {
+
+# if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+ safestrprt(Dstk[Dstkx], stderr, 1);
+ }
+# endif /* defined(WARNDEVACCESS) */
+
+ (void) free((FREE_P *)Dstk[Dstkx]);
+ Dstk[Dstkx] = (char *)NULL;
+ continue;
+ }
+ if (path) {
+ (void) free((FREE_P *)path);
+ path = (char *)NULL;
+ }
+ if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1,
+ &pl)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(Dstk[Dstkx], stderr, 1);
+ Exit(1);
+ }
+ (void) free((FREE_P *)Dstk[Dstkx]);
+ Dstk[Dstkx] = (char *)NULL;
+ /*
+ * Scan the directory.
+ */
+ for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+ if (dp->d_ino == 0 || dp->d_name[0] == '.')
+ continue;
+ /*
+ * Form the full path name and get its status.
+ */
+ dnamlen = (int)dp->d_namlen;
+ if (fp) {
+ (void) free((FREE_P *)fp);
+ fp = (char *)NULL;
+ }
+ if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen,
+ (char *)NULL, -1, (MALLOC_S *)NULL)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(path, stderr, 0);
+ safestrprtn(dp->d_name, dnamlen, stderr, 1);
+ Exit(1);
+ }
+ if (STATFN(fp, &sb) != 0) {
+ if (errno == ENOENT) /* a sym link to nowhere? */
+ continue;
+
+# if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ int errno_save = errno;
+
+ (void) fprintf(stderr, "%s: can't stat ", Pn);
+ safestrprt(fp, stderr, 0);
+ (void) fprintf(stderr, ": %s\n", strerror(errno_save));
+ }
+# endif /* defined(WARNDEVACCESS) */
+
+ continue;
+ }
+ /*
+ * If it's a subdirectory, stack its name for later
+ * processing.
+ */
+ if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+
+ /*
+ * Skip /dev/fd.
+ */
+ if (strcmp(fp, "/dev/fd"))
+ (void) stkdir(fp);
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFLNK) {
+
+ /*
+ * Ignore symbolic links.
+ */
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+ /*
+ * Save character device information in Devtp[].
+ */
+ if (i >= Ndev) {
+ Ndev += DEVINCR;
+ if (!Devtp)
+ Devtp = (struct l_dev *)malloc(
+ (MALLOC_S)(sizeof(struct l_dev)*Ndev));
+ else
+ Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
+ (MALLOC_S)(sizeof(struct l_dev)*Ndev));
+ if (!Devtp) {
+ (void) fprintf(stderr,
+ "%s: no space for character device\n", Pn);
+ Exit(1);
+ }
+ }
+ Devtp[i].rdev = sb.st_rdev;
+ Devtp[i].inode = (INODETYPE)sb.st_ino;
+ if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr,
+ "%s: no space for device name: ", Pn);
+ safestrprt(fp, stderr, 1);
+ Exit(1);
+ }
+ Devtp[i].v = 0;
+ i++;
+ }
+
+# if defined(HASBLKDEV)
+ if ((sb.st_mode & S_IFMT) == S_IFBLK) {
+
+ /*
+ * Save block device information in BDevtp[].
+ */
+ if (j >= BNdev) {
+ BNdev += DEVINCR;
+ if (!BDevtp)
+ BDevtp = (struct l_dev *)malloc(
+ (MALLOC_S)(sizeof(struct l_dev)*BNdev));
+ else
+ BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
+ (MALLOC_S)(sizeof(struct l_dev)*BNdev));
+ if (!BDevtp) {
+ (void) fprintf(stderr,
+ "%s: no space for block device\n", Pn);
+ Exit(1);
+ }
+ }
+ BDevtp[j].name = fp;
+ fp = (char *)NULL;
+ BDevtp[j].inode = (INODETYPE)sb.st_ino;
+ BDevtp[j].rdev = sb.st_rdev;
+ BDevtp[j].v = 0;
+ j++;
+ }
+# endif /* defined(HASBLKDEV) */
+
+ /*
+ * Save a possible new st_dev number within DDEV_DEVPATH.
+ */
+ if (sb.st_dev != DevDev)
+ (void) saveADev(&sb);
+ }
+ (void) CloseDir(dfp);
+ }
+/*
+ * Free any unneeded space that was allocated.
+ */
+ if (ADev && (ADevU < ADevA)) {
+
+ /*
+ * Reduce space allocated to additional DDEV_DEVPATH device numbers.
+ */
+ if (!ADevU) {
+
+ /*
+ * If no space was used, free the entire allocation.
+ */
+ (void) free((FREE_P *)ADev);
+ ADev = (dev_t *)NULL;
+ ADevA = 0;
+ } else {
+
+ /*
+ * Reduce the allocation to what was used.
+ */
+ sz = (MALLOC_S)(ADevU * sizeof(dev_t));
+ if (!(ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz))) {
+ (void) fprintf(stderr, "%s: can't reduce ADev[]\n", Pn);
+ Exit(1);
+ }
+ }
+ }
+ if (!Dstk) {
+ (void) free((FREE_P *)Dstk);
+ Dstk = (char **)NULL;
+ }
+ if (fp)
+ (void) free((FREE_P *)fp);
+ if (path)
+ (void) free((FREE_P *)path);
+
+# if defined(HASBLKDEV)
+/*
+ * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
+ * sizes; allocate and build sort pointer lists; and sort the tables by
+ * device number.
+ */
+ if (BNdev) {
+ if (BNdev > j) {
+ BNdev = j;
+ BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
+ (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+ }
+ if (!(BSdev = (struct l_dev **)malloc(
+ (MALLOC_S)(sizeof(struct l_dev *) * BNdev))))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for block device sort pointers\n", Pn);
+ Exit(1);
+ }
+ for (j = 0; j < BNdev; j++) {
+ BSdev[j] = &BDevtp[j];
+ }
+ (void) qsort((QSORT_P *)BSdev, (size_t)BNdev,
+ (size_t)sizeof(struct l_dev *), compdev);
+ BNdev = rmdupdev(&BSdev, BNdev, "block");
+ }
+
+# if !defined(NOWARNBLKDEV)
+ else {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: no block devices found\n", Pn);
+ }
+# endif /* !defined(NOWARNBLKDEV) */
+# endif /* defined(HASBLKDEV) */
+
+ if (Ndev) {
+ if (Ndev > i) {
+ Ndev = i;
+ Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
+ (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+ }
+ if (!(Sdev = (struct l_dev **)malloc(
+ (MALLOC_S)(sizeof(struct l_dev *) * Ndev))))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for character device sort pointers\n", Pn);
+ Exit(1);
+ }
+ for (i = 0; i < Ndev; i++) {
+ Sdev[i] = &Devtp[i];
+ }
+ (void) qsort((QSORT_P *)Sdev, (size_t)Ndev,
+ (size_t)sizeof(struct l_dev *), compdev);
+ Ndev = rmdupdev(&Sdev, Ndev, "char");
+ } else {
+ (void) fprintf(stderr, "%s: no character devices found\n", Pn);
+ Exit(1);
+ }
+}
+
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int
+rmdupdev(dp, n, nm)
+ struct l_dev ***dp; /* device table pointers address */
+ int n; /* number of pointers */
+ char *nm; /* device table name for error message */
+{
+ int i, j, k;
+ struct l_dev **p;
+
+ for (i = j = 0, p = *dp; i < n ;) {
+ for (k = i + 1; k < n; k++) {
+ if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode)
+ break;
+ }
+ if (i != j)
+ p[j] = p[i];
+ j++;
+ i = k;
+ }
+ if (n == j)
+ return(n);
+ if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp,
+ (MALLOC_S)(j * sizeof(struct l_dev *)))))
+ {
+ (void) fprintf(stderr, "%s: can't realloc %s device pointers\n",
+ Pn, nm);
+ Exit(1);
+ }
+ return(j);
+}
+
+
+/*
+ * saveADev() - save additional device number appearing inside DDEV_DEVPATH
+ */
+
+static void
+saveADev(s)
+ struct stat *s; /* stat(2) buffer for file */
+{
+ int i;
+ MALLOC_S sz;
+/*
+ * Process VCHR files.
+ *
+ * Optionally process VBLK files.
+ */
+
+#if defined(HASBLKDEV)
+ if (((s->st_mode & S_IFMT) != S_IFBLK)
+ && ((s->st_mode & S_IFMT) != S_IFCHR))
+#else /* !defined(HASBLKDEV) */
+ if ((s->st_mode & S_IFCHR) != S_IFCHR)
+#endif /* defined(HASBLKDEV) */
+
+ return;
+/*
+ * See if this is a new VBLK or VCHR st_dev value for ADev[].
+ */
+ for (i = 0; i < ADevU; i++) {
+ if (s->st_dev == ADev[i])
+ return;
+ }
+/*
+ * This is a new device number to add to ADev[].
+ */
+ if (ADevU >= ADevA) {
+ ADevA += 16;
+ sz = (MALLOC_S)(ADevA * sizeof(dev_t));
+ if (ADev)
+ ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz);
+ else
+ ADev = (dev_t *)malloc(sz);
+ if (!ADev) {
+ (void) fprintf(stderr, "%s: no space for ADev[]\n", Pn);
+ Exit(1);
+ }
+ }
+ ADev[ADevU++] = s->st_dev;
+}