diff options
Diffstat (limited to 'dialects/sun/ddev.c')
-rw-r--r-- | dialects/sun/ddev.c | 1143 |
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); +} |