/* * 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); }