2 * rdev.c -- readdev() function for lsof library
7 * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
8 * 47907. All rights reserved.
10 * Written by Victor A. Abell
12 * This software is not subject to any license of the American Telephone
13 * and Telegraph Company or the Regents of the University of California.
15 * Permission is granted to anyone to use this software for any purpose on
16 * any computer system, and to alter it and redistribute it freely, subject
17 * to the following restrictions:
19 * 1. Neither the authors nor Purdue University are responsible for any
20 * consequences of the use of this software.
22 * 2. The origin of this software must not be misrepresented, either by
23 * explicit claim or by omission. Credit to the authors and Purdue
24 * University must appear in documentation and sources.
26 * 3. Altered versions must be plainly marked as such, and must not be
27 * misrepresented as being the original software.
29 * 4. This notice may not be removed or altered.
33 #include "../machine.h"
35 #if defined(USE_LIB_READDEV)
38 static char copyright[] =
39 "@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
40 static char *rcsid = "$Id: rdev.c,v 1.12 2008/10/21 16:13:23 abe Exp $";
41 # endif /* !defined(lint) */
46 _PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm));
50 * To use this source file:
52 * 1. Define DIRTYPE as:
54 * #define DIRTYPE direct
55 * or #define DIRTYPE dirent
57 * 2. Define HASDNAMLEN if struct DIRTYPE has a d_namlen element, giving
58 * the length of d_name.
60 * 3. Define the RDEV_EXPDEV macro to apply special handling to device
61 * numbers, as required. For example, for EP/IX 2.1.1:
63 * #define RDEV_EXPDEV(n) expdev(n)
65 * to use the expdev() function to expand device numbers. If
66 * no RDEV_EXPDEV macro is defined, it defaults to:
68 * #define RDEV_EXPDEV(n) (n)
70 * 4. Define HASBLKDEV to request that information on S_IFBLK devices be
71 * recorded in BDevtp[].
73 * Define NOWARNBLKDEV to suppress the issuance of a warning when no
74 * block devices are found.
76 * 5. Define RDEV_STATFN to be a stat function other than stat() or lstat()
79 * #define RDEV_STATFN private_stat
81 * 6. Define HAS_STD_CLONE to request that clone device information be stored
82 * in standard clone structures (defined in lsof.h and addressed via
83 * Clone). If HAS_STD_CLONE is defined, these must also be defined:
85 * a. Define CLONEMAJ to be the name of the constant or
86 * variable that defines the clone major device -- e.g.,
88 * #define CLONEMAJ CloneMaj
90 * b. Define HAVECLONEMAJ to be the name of the variable that
91 * contains the status of the clone major device -- e.g.,
93 * #define HAVECLONEMAJ HaveCloneMaj
95 * Define HAS_STD_CLONE to be 1 if readdev() is expected to build the
96 * clone table, the clone table is cached (if HASDCACHE is defined), and
97 * there is a function to clear the cache table when the device table must
98 * be reloaded. (See dvch.c for naming the clone cache build and clear
103 # if !defined(RDEV_EXPDEV)
104 #define RDEV_EXPDEV(n) (n)
105 # endif /* !defined(RDEV_EXPDEV) */
107 # if !defined(RDEV_STATFN)
108 # if defined(USE_STAT)
109 #define RDEV_STATFN stat
110 # else /* !defined(USE_STAT) */
111 #define RDEV_STATFN lstat
112 # endif /* defined(USE_STAT) */
113 # endif /* !defined(RDEV_STATFN) */
117 * readdev() - read device names, modes and types
122 int skip; /* skip device cache read if 1 */
125 # if defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
127 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
129 # if defined(HASDCACHE)
131 # endif /* defined(HASDCACHE) */
136 char *fp = (char *)NULL;
139 # if defined(HASBLKDEV)
141 # endif /* defined(HASBLKDEV) */
143 char *path = (char *)NULL;
150 # if defined(HASDCACHE)
152 * Read device cache, as directed.
155 if (DCstate == 2 || DCstate == 3) {
156 if ((dcrd = read_dcache()) == 0)
161 # endif /* defined(HASDCACHE) */
164 Dstk = (char **)NULL;
165 (void) stkdir("/dev");
167 * Unstack the next /dev or /dev/<subdirectory> directory.
169 while (--Dstkx >= 0) {
170 if (!(dfp = OpenDir(Dstk[Dstkx]))) {
172 # if defined(WARNDEVACCESS)
174 (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn);
175 safestrprt(Dstk[Dstkx], stderr, 1);
177 # endif /* defined(WARNDEVACCESS) */
179 (void) free((FREE_P *)Dstk[Dstkx]);
180 Dstk[Dstkx] = (char *)NULL;
184 (void) free((FREE_P *)path);
187 if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1,
190 (void) fprintf(stderr, "%s: no space for: ", Pn);
191 safestrprt(Dstk[Dstkx], stderr, 1);
194 (void) free((FREE_P *)Dstk[Dstkx]);
195 Dstk[Dstkx] = (char *)NULL;
197 * Scan the directory.
199 for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
200 if (dp->d_ino == 0 || dp->d_name[0] == '.')
203 * Form the full path name and get its status.
206 # if defined(HASDNAMLEN)
207 dnamlen = (int)dp->d_namlen;
208 # else /* !defined(HASDNAMLEN) */
209 dnamlen = (int)strlen(dp->d_name);
210 # endif /* defined(HASDNAMLEN) */
213 (void) free((FREE_P *)fp);
216 if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen,
217 (char *)NULL, -1, (MALLOC_S *)NULL)))
219 (void) fprintf(stderr, "%s: no space for: ", Pn);
220 safestrprt(path, stderr, 0);
221 safestrprtn(dp->d_name, dnamlen, stderr, 1);
224 if (RDEV_STATFN(fp, &sb) != 0) {
225 if (errno == ENOENT) /* a sym link to nowhere? */
228 # if defined(WARNDEVACCESS)
230 int errno_save = errno;
232 (void) fprintf(stderr, "%s: can't stat ", Pn);
233 safestrprt(fp, stderr, 0);
234 (void) fprintf(stderr, ": %s\n", strerror(errno_save));
236 # endif /* defined(WARNDEVACCESS) */
241 * If it's a subdirectory, stack its name for later
244 if ((sb.st_mode & S_IFMT) == S_IFDIR) {
248 if ((sb.st_mode & S_IFMT) == S_IFCHR) {
251 * Save character device information in Devtp[].
256 Devtp = (struct l_dev *)malloc(
257 (MALLOC_S)(sizeof(struct l_dev)*Ndev));
259 Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
260 (MALLOC_S)(sizeof(struct l_dev)*Ndev));
262 (void) fprintf(stderr,
263 "%s: no space for character device\n", Pn);
267 Devtp[i].rdev = RDEV_EXPDEV(sb.st_rdev);
268 Devtp[i].inode = (INODETYPE)sb.st_ino;
269 if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
270 (void) fprintf(stderr,
271 "%s: no space for device name: ", Pn);
272 safestrprt(fp, stderr, 1);
277 # if defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
278 if (HAVECLONEMAJ && GET_MAJ_DEV(Devtp[i].rdev) == CLONEMAJ)
282 * Record clone device information.
284 if (!(c = (struct clone *)malloc(sizeof(struct clone))))
286 (void) fprintf(stderr,
287 "%s: no space for clone device: ", Pn);
288 safestrprt(fp, stderr, 1);
295 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
300 # if defined(HASBLKDEV)
301 if ((sb.st_mode & S_IFMT) == S_IFBLK) {
304 * Save block device information in BDevtp[].
309 BDevtp = (struct l_dev *)malloc(
310 (MALLOC_S)(sizeof(struct l_dev)*BNdev));
312 BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
313 (MALLOC_S)(sizeof(struct l_dev)*BNdev));
315 (void) fprintf(stderr,
316 "%s: no space for block device\n", Pn);
322 BDevtp[j].inode = (INODETYPE)sb.st_ino;
323 BDevtp[j].rdev = RDEV_EXPDEV(sb.st_rdev);
327 # endif /* defined(HASBLKDEV) */
330 (void) CloseDir(dfp);
333 * Free any allocated space.
336 (void) free((FREE_P *)Dstk);
337 Dstk = (char **)NULL;
340 (void) free((FREE_P *)fp);
342 (void) free((FREE_P *)path);
344 # if defined(HASBLKDEV)
346 * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
347 * sizes; allocate and build sort pointer lists; and sort the tables by
353 BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
354 (MALLOC_S)(sizeof(struct l_dev) * BNdev));
356 if (!(BSdev = (struct l_dev **)malloc(
357 (MALLOC_S)(sizeof(struct l_dev *) * BNdev))))
359 (void) fprintf(stderr,
360 "%s: no space for block device sort pointers\n", Pn);
363 for (j = 0; j < BNdev; j++) {
364 BSdev[j] = &BDevtp[j];
366 (void) qsort((QSORT_P *)BSdev, (size_t)BNdev,
367 (size_t)sizeof(struct l_dev *), compdev);
368 BNdev = rmdupdev(&BSdev, BNdev, "block");
371 # if !defined(NOWARNBLKDEV)
374 (void) fprintf(stderr,
375 "%s: WARNING: no block devices found\n", Pn);
377 # endif /* !defined(NOWARNBLKDEV) */
378 # endif /* defined(HASBLKDEV) */
383 Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
384 (MALLOC_S)(sizeof(struct l_dev) * Ndev));
386 if (!(Sdev = (struct l_dev **)malloc(
387 (MALLOC_S)(sizeof(struct l_dev *) * Ndev))))
389 (void) fprintf(stderr,
390 "%s: no space for character device sort pointers\n", Pn);
393 for (i = 0; i < Ndev; i++) {
396 (void) qsort((QSORT_P *)Sdev, (size_t)Ndev,
397 (size_t)sizeof(struct l_dev *), compdev);
398 Ndev = rmdupdev(&Sdev, Ndev, "char");
400 (void) fprintf(stderr, "%s: no character devices found\n", Pn);
404 # if defined(HASDCACHE)
406 * Write device cache file, as required.
408 if (DCstate == 1 || (DCstate == 3 && dcrd))
410 # endif /* defined(HASDCACHE) */
415 # if defined(HASDCACHE)
417 * rereaddev() - reread device names, modes and types
425 # if defined(DCACHE_CLR)
427 # endif /* defined(DCACHE_CLR) */
432 #endif /* defined(HASDCACHE) */
436 * rmdupdev() - remove duplicate (major/minor/inode) devices
441 struct l_dev ***dp; /* device table pointers address */
442 int n; /* number of pointers */
443 char *nm; /* device table name for error message */
446 # if defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
447 struct clone *c, *cp;
448 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
453 for (i = j = 0, p = *dp; i < n ;) {
454 for (k = i + 1; k < n; k++) {
455 if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode)
458 # if defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
460 * See if we're deleting a duplicate clone device. If so,
461 * delete its clone table entry.
463 for (c = Clone, cp = (struct clone *)NULL;
467 if (&Devtp[c->dx] != p[k])
473 (void) free((FREE_P *)c);
476 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
486 if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp,
487 (MALLOC_S)(j * sizeof(struct l_dev *)))))
489 (void) fprintf(stderr, "%s: can't realloc %s device pointers\n",
497 # if defined(HASDCACHE)
499 * vfy_dev() - verify a device table entry (usually when DCunsafe == 1)
501 * Note: rereads entire device table when an entry can't be verified.
506 struct l_dev *dp; /* device table pointer */
510 if (!DCunsafe || dp->v)
512 if (RDEV_STATFN(dp->name, &sb) != 0
513 || dp->rdev != RDEV_EXPDEV(sb.st_rdev)
514 || dp->inode != sb.st_ino) {
521 # endif /* defined(HASDCACHE) */
522 #else /* !defined(USE_LIB_READDEV) */
523 char rdev_d1[] = "d"; char *rdev_d2 = rdev_d1;
524 #endif /* defined(USE_LIB_READDEV) */