summaryrefslogtreecommitdiff
path: root/dialects/sun/ddev.c
diff options
context:
space:
mode:
Diffstat (limited to 'dialects/sun/ddev.c')
-rw-r--r--dialects/sun/ddev.c1143
1 files changed, 1143 insertions, 0 deletions
diff --git a/dialects/sun/ddev.c b/dialects/sun/ddev.c
new file mode 100644
index 0000000..83bd2ce
--- /dev/null
+++ b/dialects/sun/ddev.c
@@ -0,0 +1,1143 @@
+/*
+ * ddev.c - Solaris device support 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: ddev.c,v 1.20 2005/08/08 19:55:41 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#define LIKE_BLK_SPEC "like block special"
+#define LIKE_CHR_SPEC "like character special"
+
+
+/*
+ * Local static values
+ */
+
+static int Devx = 0; /* current Devtp[] index */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static void make_devtp,(struct stat *s, char *p));
+_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, int ty));
+
+
+/*
+ * make_devtp() - make Devtp[] entry
+ */
+
+static void
+make_devtp(s, p)
+ struct stat *s; /* device lstat() buffer */
+ char *p; /* device path name */
+{
+
+/*
+ * Make room for another Devtp[] entry.
+ */
+ if (Devx >= 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);
+ }
+ }
+/*
+ * Store the device number, inode number, and name in the Devtp[] entry.
+ */
+ Devtp[Devx].inode = (INODETYPE)s->st_ino;
+ if (!(Devtp[Devx].name = mkstrcpy(p, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr, "%s: no space for /dev/", Pn);
+ safestrprt(p, stderr, 1);
+ Exit(1);
+ }
+ Devtp[Devx].rdev = s->st_rdev;
+ Devtp[Devx].v = 0;
+ Devx++;
+}
+
+
+/*
+ * printdevname() - print block or character device name
+ */
+
+int
+printdevname(dev, rdev, f, nty)
+ dev_t *dev; /* device */
+ dev_t *rdev; /* raw device */
+ int f; /* 1 = print trailing '\n' */
+ int nty; /* node type: N_BLK or N_CHR */
+{
+ struct clone *c;
+ struct l_dev *dp;
+ struct pseudo *p;
+
+ readdev(0);
+/*
+ * Search device table for a full match.
+ */
+
+#if defined(HASDCACHE)
+
+printchdevname_again:
+
+#endif /* defined(HASDCACHE) */
+
+#if defined(HASBLKDEV)
+ if (nty == N_BLK)
+ dp = lkupbdev(dev, rdev, 1, 0);
+ else
+#endif /* defined(HASBLKDEV) */
+
+ dp = lkupdev(dev, rdev, 1, 0);
+ if (dp) {
+ safestrprt(dp->name, stdout, f);
+ return(1);
+ }
+/*
+ * Search device table for a match without inode number and dev.
+ */
+
+#if defined(HASBLKDEV)
+ if (nty == N_BLK)
+ dp = lkupbdev(&DevDev, rdev, 0, 0);
+ else
+#endif /* defined(HASBLKDEV) */
+
+ dp = lkupdev(&DevDev, rdev, 0, 0);
+ if (dp) {
+
+ /*
+ * A match was found. Record it as a name column addition.
+ */
+ char *cp, *ttl;
+ int len;
+
+ ttl = (nty == N_BLK) ? LIKE_BLK_SPEC : LIKE_CHR_SPEC;
+ len = (int)(1 + strlen(ttl) + 1 + strlen(dp->name) + 1);
+ if (!(cp = (char *)malloc((MALLOC_S)(len + 1)))) {
+ (void) fprintf(stderr, "%s: no nma space for: (%s %s)\n",
+ Pn, ttl, dp->name);
+ Exit(1);
+ }
+ (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name);
+ (void) add_nma(cp, len);
+ (void) free((MALLOC_P *)cp);
+ return(0);
+ }
+/*
+ * Search for clone parent.
+ */
+ if ((nty == N_CHR) && Lf->is_stream && Clone && (*dev == DevDev)) {
+ for (c = Clone; c; c = c->next) {
+ if (GET_MAJ_DEV(*rdev) == GET_MIN_DEV(c->cd.rdev)) {
+
+#if defined(HASDCACHE)
+ if (DCunsafe && !c->cd.v && !vfy_dev(&c->cd))
+ goto printchdevname_again;
+#endif /* defined(HASDCACHE) */
+
+ safestrprt(c->cd.name, stdout, f);
+ return(1);
+ }
+ }
+ }
+/*
+ * Search for pseudo device match on major device only.
+ */
+ if ((nty == N_CHR) && *dev == DevDev) {
+ for (p = Pseudo; p; p = p->next) {
+ if (GET_MAJ_DEV(*rdev) == GET_MAJ_DEV(p->pd.rdev)) {
+
+# if defined(HASDCACHE)
+ if (DCunsafe && !p->pd.v && vfy_dev(&p->pd))
+ goto printchdevname_again;
+# endif /* defined(HASDCACHE) */
+
+ safestrprt(p->pd.name, stdout, f);
+ return(1);
+ }
+ }
+ }
+
+#if defined(HASDCACHE)
+/*
+ * If the device cache is "unsafe" and we haven't found any match, reload
+ * the device cache.
+ */
+ if (DCunsafe) {
+ (void) rereaddev();
+ goto printchdevname_again;
+ }
+#endif /* defined(HASDCACHE) */
+
+ return(0);
+}
+
+
+/*
+ * read_clone() - read Solaris clone device information
+ */
+
+void
+read_clone()
+{
+ struct clone *c;
+ char *cn;
+ DIR *dfp;
+ struct DIRTYPE *dp;
+ char *fp = (char *)NULL;
+ MALLOC_S fpl;
+ char *path;
+ MALLOC_S pl;
+ struct pseudo *p;
+ struct stat sb;
+
+ if (Clone || Pseudo)
+ return;
+/*
+ * Open the /DVCH_DEVPATH/pseudo directory.
+ */
+ if (!(path = mkstrcat(DVCH_DEVPATH, -1, "/", 1, "pseudo ", -1, &pl))) {
+ (void) fprintf(stderr, "%s: no space for %s/pseudo\n",
+ DVCH_DEVPATH, Pn);
+ Exit(1);
+ }
+ path[pl - 1] = '\0';
+ if (!(dfp = OpenDir(path))) {
+
+#if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+ safestrprt(path, stderr, 1);
+ }
+#endif /* defined(WARNDEVACCESS) */
+
+ (void) free((FREE_P *)path);
+ return;
+ }
+ path[pl - 1] = '/';
+/*
+ * 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 stat() it.
+ */
+ if (fp) {
+ (void) free((FREE_P *)fp);
+ fp = (char *)NULL;
+ }
+ if (!(fp = mkstrcat(path, pl, dp->d_name, -1, (char *)NULL, -1,
+ &fpl)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(path, stderr, 0);
+ safestrprt(dp->d_name, stderr, 1);
+ Exit(1);
+ }
+
+#if defined(USE_STAT)
+ if (stat(fp, &sb) != 0)
+#else /* !defined(USE_STAT) */
+ if (lstat(fp, &sb) != 0)
+#endif /* defined(USE_STAT) */
+
+ {
+ 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));
+ }
+ continue;
+ }
+ /*
+ * Skip subdirectories and all but character devices.
+ */
+ if ((sb.st_mode & S_IFMT) == S_IFDIR
+ || (sb.st_mode & S_IFMT) != S_IFCHR)
+ continue;
+ /*
+ * Make Devtp[] entry.
+ */
+ make_devtp(&sb, fp);
+ /*
+ * Create a clone structure entry for "clone*:" devices.
+ *
+ * Make special note of network clones -- tcp, and udp.
+ */
+ if (strncmp(&fp[pl], "clone", 5) == 0) {
+ if (!(cn = strrchr(&fp[pl], ':')))
+ continue;
+ /*
+ * Allocate a clone structure.
+ */
+ if (!(c = (struct clone *)malloc(sizeof(struct clone)))) {
+ (void) fprintf(stderr,
+ "%s: no space for network clone device: ", Pn);
+ safestrprt(fp, stderr, 1);
+ Exit(1);
+ }
+ /*
+ * Allocate space for the path name.
+ */
+ if (!(c->cd.name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr, "%s: no space for clone name: ", Pn);
+ safestrprt(fp, stderr, 1);
+ Exit(1);
+ }
+ /*
+ * Save the inode and device numbers. Clear the verify flag.
+ */
+ c->cd.inode = (INODETYPE)sb.st_ino;
+ c->cd.rdev = sb.st_rdev;
+ c->cd.v = 0;
+ /*
+ * Make special note of a network clone device.
+ */
+ if (!strcmp(++cn, "tcp") || !strcmp(cn, "udp"))
+ c->n = cn - fp;
+ else
+ c->n = 0;
+ /*
+ * Link the new clone entry to the rest.
+ */
+ c->next = Clone;
+ Clone = c;
+ continue;
+ }
+ /*
+ * Save pseudo device information.
+ */
+ if (GET_MIN_DEV(sb.st_rdev) == 0) {
+
+ /*
+ * Allocate space for the pseduo device entry.
+ */
+ if (!(p = (struct pseudo *) malloc(sizeof(struct pseudo)))) {
+ (void) fprintf(stderr,
+ "%s: no space for pseudo device: ", Pn);
+ safestrprt(fp, stderr, 1);
+ Exit(1);
+ }
+ /*
+ * Save the path name, and inode and device numbers. Clear the
+ * verify flag. Link the entry to the pseudo chain.
+ */
+ p->pd.inode = (INODETYPE)sb.st_ino;
+ p->pd.name = fp;
+ fp = (char *)NULL;
+ p->pd.rdev = sb.st_rdev;
+ p->pd.v = 0;
+ p->next = Pseudo;
+ Pseudo = p;
+ }
+ }
+ (void) CloseDir(dfp);
+ if (fp)
+ (void) free((FREE_P *)fp);
+ if (path)
+ (void) free((FREE_P *)path);
+}
+
+
+/*
+ * readdev() - read names, modes and device types of everything in /dev
+ * or /device (Solaris)
+ */
+
+void
+readdev(skip)
+ int skip; /* skip device cache read if 1 */
+{
+
+#if defined(HASDCACHE)
+ int dcrd = 0;
+#endif /* defined(HASDCACHE) */
+
+ DIR *dfp;
+ struct DIRTYPE *dp;
+ char *fp = (char *)NULL;
+ MALLOC_S fpl;
+ int i;
+
+#if defined(HASBLKDEV)
+ int j = 0;
+#endif /* defined(HASBLKDEV) */
+
+ char *path = (char *)NULL;
+ char *ppath = (char *)NULL;
+ MALLOC_S pl;
+ struct stat sb;
+
+ if (Sdev)
+ return;
+
+#if defined(HASDCACHE)
+/*
+ * Read device cache, as directed.
+ */
+ if (!skip) {
+ if (DCstate == 2 || DCstate == 3) {
+ if ((dcrd = read_dcache()) == 0)
+ return;
+ }
+ } else
+ dcrd = 1;
+#endif /* defined(HASDCACHE) */
+
+ if (!(ppath = mkstrcat(DVCH_DEVPATH, -1, "/", 1, "pseudo", -1,
+ (MALLOC_S *)NULL)))
+ {
+ (void) fprintf(stderr, "%s: no space for: %s/pseudo\n",
+ Pn, DVCH_DEVPATH);
+ Exit(1);
+ }
+ read_clone();
+ Dstk = (char **)NULL;
+ Dstkn = Dstkx = 0;
+ (void) stkdir(DVCH_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;
+ }
+ /*
+ * Create a directory name buffer with a trailing slash.
+ */
+ 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.
+ */
+ if (fp) {
+ (void) free((FREE_P *)fp);
+ fp = (char *)NULL;
+ }
+ if (!(fp = mkstrcat(path, pl, dp->d_name, -1, (char *)NULL, -1,
+ &fpl)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(path, stderr, 0);
+ safestrprt(dp->d_name, stderr, 1);
+ Exit(1);
+ }
+
+#if defined(USE_STAT)
+ if (stat(fp, &sb) != 0)
+#else /* !defined(USE_STAT) */
+ if (lstat(fp, &sb) != 0)
+#endif /* defined(USE_STAT) */
+
+ {
+ if (errno == ENOENT) /* symbolic 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 Solaris /DVCH_DEV_PATH/pseudo sub-directory;
+ * it has been examined in read_clone().
+ */
+ if (strcmp(fp, ppath) == 0)
+ continue;
+ (void) stkdir(fp);
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+ /*
+ * Make Devtp[] entry.
+ */
+ make_devtp(&sb, fp);
+ }
+
+#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].rdev = sb.st_rdev;
+ BDevtp[j].inode = (INODETYPE)sb.st_ino;
+ BDevtp[j].name = fp;
+ fp = (char *)NULL;
+ BDevtp[j].v = 0;
+ j++;
+ }
+#endif /* defined(HASBLKDEV) */
+
+ }
+ (void) CloseDir(dfp);
+ }
+/*
+ * Free any allocated space.
+ */
+ if (Dstk) {
+ (void) free((FREE_P *)Dstk);
+ Dstk = (char **)NULL;
+ Dstkn = Dstkx = 0;
+ }
+ if (fp)
+ (void) free((FREE_P *)fp);
+ if (path)
+ (void) free((FREE_P *)path);
+ if (ppath)
+ (void) free((FREE_P *)ppath);
+/*
+ * 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 defined(HASBLKDEV)
+ 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, 0);
+ } else {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: no block devices found\n", Pn);
+ }
+#endif /* defined(HASBLKDEV) */
+
+ if (Ndev) {
+ if (Ndev > Devx) {
+ Ndev = Devx;
+ 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, 1);
+ } else {
+ (void) fprintf(stderr, "%s: no character devices found\n", Pn);
+ Exit(1);
+ }
+
+#if defined(HASDCACHE)
+/*
+ * Write device cache file, as required.
+ */
+ if (DCstate == 1 || (DCstate == 3 && dcrd))
+ write_dcache();
+#endif /* defined(HASDCACHE) */
+
+}
+
+
+/*
+ * clr_sect() - clear cached clone and pseudo sections
+ */
+
+void
+clr_sect()
+{
+ if (Clone) {
+ struct clone *c, *c1;
+
+ for (c = Clone; c; c = c1) {
+ c1 = c->next;
+ if (c->cd.name)
+ (void) free((FREE_P *)c->cd.name);
+ (void) free((FREE_P *)c);
+ }
+ Clone = (struct clone *)NULL;
+ }
+ if (Pseudo) {
+ struct pseudo *p, *p1;
+
+ for (p = Pseudo; p; p = p1) {
+ p1 = p->next;
+ if (p->pd.name)
+ (void) free((FREE_P *)p->pd.name);
+ (void) free((FREE_P *)p);
+ }
+ Pseudo = (struct pseudo *)NULL;
+ }
+}
+
+
+#if defined(HASDCACHE)
+/*
+ * rw_clone_sect() - read/write the device cache file clone section
+ */
+
+int
+rw_clone_sect(m)
+ int m; /* mode: 1 = read; 2 = write */
+{
+ char buf[MAXPATHLEN*2], *cp;
+ struct clone *c;
+ int i, len, n;
+
+ if (m == 1) {
+
+ /*
+ * Read the clone section header and validate it.
+ */
+ if (!fgets(buf, sizeof(buf), DCfs)) {
+
+bad_clone_sect:
+
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad clone section header in %s: ",
+ Pn, DCpath[DCpathX]);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ (void) crc(buf, strlen(buf), &DCcksum);
+ len = strlen("clone section: ");
+ if (strncmp(buf, "clone section: ", len) != 0)
+ goto bad_clone_sect;
+ if ((n = atoi(&buf[len])) < 0)
+ goto bad_clone_sect;
+ /*
+ * Read the clone section lines and create the Clone list.
+ */
+ for (i = 0; i < n; i++) {
+ if (!fgets(buf, sizeof(buf), DCfs)) {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad clone line in %s: ", Pn, DCpath[DCpathX]);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ (void) crc(buf, strlen(buf), &DCcksum);
+ /*
+ * Allocate a clone structure.
+ */
+ if (!(c = (struct clone *)calloc(1, sizeof(struct clone)))) {
+ (void) fprintf(stderr,
+ "%s: no space for cached clone: ", Pn);
+ safestrprt(buf, stderr, 1);
+ Exit(1);
+ }
+ /*
+ * Enter the clone device number.
+ *
+ * New format clone lines (with an inode number) have a leading
+ * space, so that older lsof versions, not expecting them, will
+ * not use the new format lines.
+ */
+ if (buf[0] != ' '
+ || !(cp = x2dev(&buf[1], &c->cd.rdev)) || *cp++ != ' ')
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached clone device: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ /*
+ * Enter the clone network value.
+ */
+ for (c->n = 0; *cp != ' '; cp++) {
+ if (*cp < '0' || *cp > '9') {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached clone network flag: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ c->n = (c->n * 10) + (int)(*cp - '0');
+ }
+ /*
+ * Enter the clone device inode number.
+ */
+ for (c->cd.inode = (INODETYPE)0, ++cp; *cp != ' '; cp++) {
+ if (*cp < '0' || *cp > '9') {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached clone inode number: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ c->cd.inode = (INODETYPE)((c->cd.inode * 10)
+ + (int)(*cp - '0'));
+ }
+ /*
+ * Enter the clone path name.
+ */
+ if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached clone path: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ *(cp + len - 1) = '\0';
+ if (!(c->cd.name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr,
+ "%s: no space for cached clone path: ", Pn);
+ safestrprt(buf, stderr, 1);
+ Exit(1);
+ }
+ c->cd.v = 0;
+ c->next = Clone;
+ Clone = c;
+ }
+ return(0);
+ } else if (m == 2) {
+
+ /*
+ * Write the clone section header.
+ */
+ for (c = Clone, n = 0; c; c = c->next, n++)
+ ;
+ (void) snpf(buf, sizeof(buf), "clone section: %d\n", n);
+ if (wr2DCfd(buf, &DCcksum))
+ return(1);
+ /*
+ * Write the clone section lines.
+ *
+ *
+ * New format clone lines (with an inode number) have a leading
+ * space, so that older lsof versions, not expecting them, will
+ * not use the new format lines.
+ */
+ for (c = Clone; c; c = c->next) {
+ (void) snpf(buf, sizeof(buf), " %lx %d %ld %s\n",
+ (long)c->cd.rdev, c->n, (long)c->cd.inode, c->cd.name);
+ if (wr2DCfd(buf, &DCcksum))
+ return(1);
+ }
+ return(0);
+ }
+/*
+ * A shouldn't-happen case: mode neither 1 nor 2.
+ */
+ (void) fprintf(stderr, "%s: internal rw_clone_sect error: %d\n",
+ Pn, m);
+ Exit(1);
+ return(1); /* to make code analyzers happy */
+}
+
+
+/*
+ * rereaddev() - reread device names, modes and types
+ */
+
+void
+rereaddev()
+{
+ (void) clr_devtab();
+ (void) clr_sect();
+ Devx = 0;
+
+# if defined(DCACHE_CLR)
+ (void) DCACHE_CLR();
+# endif /* defined(DCACHE_CLR) */
+
+ readdev(1);
+ DCunsafe = 0;
+}
+
+
+/*
+ * rw_pseudo_sect() - read/write the device cache pseudo section
+ */
+
+int
+rw_pseudo_sect(m)
+ int m; /* mode: 1 = read; 2 = write */
+{
+ char buf[MAXPATHLEN*2], *cp;
+ struct pseudo *p;
+ int i, len, n;
+
+ if (m == 1) {
+
+ /*
+ * Read the pseudo section header and validate it.
+ */
+ if (!fgets(buf, sizeof(buf), DCfs)) {
+
+bad_pseudo_sect:
+
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad pseudo section header in %s: ",
+ Pn, DCpath[DCpathX]);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ (void) crc(buf, strlen(buf), &DCcksum);
+ len = strlen("pseudo section: ");
+ if (strncmp(buf, "pseudo section: ", len) != 0)
+ goto bad_pseudo_sect;
+ if ((n = atoi(&buf[len])) < 0)
+ goto bad_pseudo_sect;
+ /*
+ * Read the pseudo section lines and create the Pseudo list.
+ */
+ for (i = 0; i < n; i++) {
+ if (!fgets(buf, sizeof(buf), DCfs)) {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad pseudo line in %s: ", Pn, DCpath[DCpathX]);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ (void) crc(buf, strlen(buf), &DCcksum);
+ /*
+ * Allocate a pseudo structure.
+ */
+ if (!(p = (struct pseudo *)calloc(1, sizeof(struct pseudo)))) {
+ (void) fprintf(stderr,
+ "%s: no space for cached pseudo: ", Pn);
+ safestrprt(buf, stderr, 1);
+ Exit(1);
+ }
+ /*
+ * Enter the pseudo device number.
+ *
+ * New format pseudo lines (with an inode number) have a leading
+ * space, so that older lsof versions, not expecting them, will
+ * not use the new format lines.
+ */
+ if (buf[0] != ' '
+ || !(cp = x2dev(&buf[1], &p->pd.rdev)) || *cp++ != ' ')
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached pseudo device: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ /*
+ * Enter the pseudo inode number.
+ */
+ for (p->pd.inode = (INODETYPE)0; *cp != ' '; cp++) {
+ if (*cp < '0' || *cp > '9') {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached pseudo inode number: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ p->pd.inode = (INODETYPE)((p->pd.inode * 10)
+ + (int)(*cp - '0'));
+ }
+ /*
+ * Enter the pseudo path name.
+ *
+ *
+ * New format clone lines (with an inode number) have a leading
+ * space, so that older lsof versions, not expecting them, will
+ * not use the new format lines.
+ */
+ if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: bad cached pseudo path: ", Pn);
+ safestrprt(buf, stderr, 1);
+ }
+ return(1);
+ }
+ if (!(p->pd.name = (char *)malloc(len))) {
+ (void) fprintf(stderr,
+ "%s: no space for cached pseudo path: ", Pn);
+ safestrprt(buf, stderr, 1);
+ Exit(1);
+ }
+ *(cp + len - 1) = '\0';
+ (void) snpf(p->pd.name, len, "%s", cp);
+ p->pd.v = 0;
+ p->next = Pseudo;
+ Pseudo = p;
+ }
+ return(0);
+ } else if (m == 2) {
+
+ /*
+ * Write the pseudo section header.
+ */
+ for (p = Pseudo, n = 0; p; p = p->next, n++)
+ ;
+ (void) snpf(buf, sizeof(buf), "pseudo section: %d\n", n);
+ if (wr2DCfd(buf, &DCcksum))
+ return(1);
+ /*
+ * Write the pseudo section lines.
+ *
+ *
+ * New format pseudo lines (with an inode number) have a leading
+ * space, so that older lsof versions, not expecting them, will
+ * not use the new format lines.
+ */
+ for (p = Pseudo; p; p = p->next) {
+ (void) snpf(buf, sizeof(buf), " %lx %ld %s\n", (long)p->pd.rdev,
+ (long)p->pd.inode, p->pd.name);
+ if (wr2DCfd(buf, &DCcksum))
+ return(1);
+ }
+ return(0);
+ }
+/*
+ * A shouldn't-happen case: mode neither 1 nor 2.
+ */
+ (void) fprintf(stderr, "%s: internal rw_pseudo_sect error: %d\n",
+ Pn, m);
+ return(1);
+}
+
+
+/*
+ * vfy_dev() - verify a device table entry (usually when DCunsafe == 1)
+ *
+ * Note: rereads entire device table when an entry can't be verified.
+ */
+
+int
+vfy_dev(dp)
+ struct l_dev *dp; /* device table pointer */
+{
+ struct stat sb;
+
+ if (!DCunsafe || dp->v)
+ return(1);
+
+#if defined(USE_STAT)
+ if (stat(dp->name, &sb) != 0
+#else /* !defined(USE_STAT) */
+ if (lstat(dp->name, &sb) != 0
+#endif /* defined(USE_STAT) */
+
+ || dp->rdev != sb.st_rdev
+ || dp->inode != (INODETYPE)sb.st_ino) {
+ (void) rereaddev();
+ return(0);
+ }
+ dp->v = 1;
+ return(1);
+}
+#endif /* defined(HASDCACHE) */
+
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int
+rmdupdev(dp, n, ty)
+ struct l_dev ***dp; /* device table pointers address */
+ int n; /* number of pointers */
+ int ty; /* type: 0 = block, 1 = char */
+{
+ struct clone *c, *cp;
+ struct l_dev **d;
+ int i, j, k;
+ struct pseudo *p, *pp;
+
+ for (i = j = 0, d = *dp; i < n ;) {
+ for (k = i + 1; k < n; k++) {
+ if (d[i]->rdev != d[k]->rdev || d[i]->inode != d[k]->inode)
+ break;
+ if (ty == 0)
+ continue;
+ /*
+ * See if we're deleting a duplicate clone device. If so,
+ * delete its clone table entry.
+ */
+ for (c = Clone, cp = (struct clone *)NULL;
+ c;
+ cp = c, c = c->next)
+ {
+ if (c->cd.rdev != d[k]->rdev
+ || c->cd.inode != d[k]->inode
+ || strcmp(c->cd.name, d[k]->name))
+ continue;
+ if (!cp)
+ Clone = c->next;
+ else
+ cp->next = c->next;
+ if (c->cd.name)
+ (void) free((FREE_P *)c->cd.name);
+ (void) free((FREE_P *)c);
+ break;
+ }
+ /*
+ * See if we're deleting a duplicate pseudo device. If so,
+ * delete its pseudo table entry.
+ */
+ for (p = Pseudo, pp = (struct pseudo *)NULL;
+ p;
+ pp = p, p = p->next)
+ {
+ if (p->pd.rdev != d[k]->rdev
+ || p->pd.inode != d[k]->inode
+ || strcmp(p->pd.name, d[k]->name))
+ continue;
+ if (!pp)
+ Pseudo = p->next;
+ else
+ pp->next = p->next;
+ if (p->pd.name)
+ (void) free((FREE_P *)p->pd.name);
+ (void) free((FREE_P *)p);
+ break;
+ }
+ }
+ if (i != j)
+ d[j] = d[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, ty ? "char" : "block");
+ Exit(1);
+ }
+ return(j);
+}