Define LSOF_CC to system CC
[platform/upstream/lsof.git] / lib / rdev.c
1 /*
2  * rdev.c -- readdev() function for lsof library
3  */
4
5
6 /*
7  * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
8  * 47907.  All rights reserved.
9  *
10  * Written by Victor A. Abell
11  *
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.
14  *
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:
18  *
19  * 1. Neither the authors nor Purdue University are responsible for any
20  *    consequences of the use of this software.
21  *
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.
25  *
26  * 3. Altered versions must be plainly marked as such, and must not be
27  *    misrepresented as being the original software.
28  *
29  * 4. This notice may not be removed or altered.
30  */
31
32
33 #include "../machine.h"
34
35 #if     defined(USE_LIB_READDEV)
36
37 # if    !defined(lint)
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) */
42
43 #include "../lsof.h"
44
45
46 _PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm));
47
48
49 /*
50  * To use this source file:
51  *
52  * 1. Define DIRTYPE as:
53  *
54  *        #define DIRTYPE direct
55  *    or  #define DIRTYPE dirent
56  *
57  * 2. Define HASDNAMLEN if struct DIRTYPE has a d_namlen element, giving
58  *    the length of d_name.
59  *
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:
62  *
63  *      #define RDEV_EXPDEV(n)  expdev(n)
64  *
65  *    to use the expdev() function to expand device numbers.  If
66  *    no RDEV_EXPDEV macro is defined, it defaults to:
67  *
68  *      #define RDEV_EXPDEV(n)  (n)
69  *
70  * 4. Define HASBLKDEV to request that information on S_IFBLK devices be
71  *    recorded in BDevtp[].
72  *
73  *    Define NOWARNBLKDEV to suppress the issuance of a warning when no
74  *    block devices are found.
75  *
76  * 5. Define RDEV_STATFN to be a stat function other than stat() or lstat()
77  *    -- e.g.,
78  *
79  *      #define RDEV_STATFN     private_stat
80  *
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:
84  *
85  *      a.  Define CLONEMAJ to be the name of the constant or
86  *          variable that defines the clone major device -- e.g.,
87  *
88  *              #define CLONEMAJ CloneMaj
89  *
90  *      b.  Define HAVECLONEMAJ to be the name of the variable that
91  *          contains the status of the clone major device -- e.g.,
92  *
93  *              #define HAVECLONEMAJ HaveCloneMaj
94  *
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
99  *    functions.)
100  */
101
102
103 # if    !defined(RDEV_EXPDEV)
104 #define RDEV_EXPDEV(n)          (n)
105 # endif /* !defined(RDEV_EXPDEV) */
106
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) */
114
115
116 /*
117  * readdev() - read device names, modes and types
118  */
119
120 void
121 readdev(skip)
122         int skip;                       /* skip device cache read if 1 */
123 {
124
125 # if    defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
126         struct clone *c;
127 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
128
129 # if    defined(HASDCACHE)
130         int dcrd;
131 # endif /* defined(HASDCACHE) */
132
133         DIR *dfp;
134         int dnamlen;
135         struct DIRTYPE *dp;
136         char *fp = (char *)NULL;
137         int i = 0;
138
139 # if    defined(HASBLKDEV)
140         int j = 0;
141 # endif /* defined(HASBLKDEV) */
142
143         char *path = (char *)NULL;
144         MALLOC_S pl;
145         struct stat sb;
146
147         if (Sdev)
148             return;
149
150 # if    defined(HASDCACHE)
151 /*
152  * Read device cache, as directed.
153  */
154         if (!skip) {
155             if (DCstate == 2 || DCstate == 3) {
156                 if ((dcrd = read_dcache()) == 0)
157                     return;
158             }
159         } else
160             dcrd = 1;
161 # endif /* defined(HASDCACHE) */
162
163         Dstkn = Dstkx = 0;
164         Dstk = (char **)NULL;
165         (void) stkdir("/dev");
166 /*
167  * Unstack the next /dev or /dev/<subdirectory> directory.
168  */
169         while (--Dstkx >= 0) {
170             if (!(dfp = OpenDir(Dstk[Dstkx]))) {
171
172 # if    defined(WARNDEVACCESS)
173                 if (!Fwarn) {
174                     (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn);
175                     safestrprt(Dstk[Dstkx], stderr, 1);
176                 }
177 # endif /* defined(WARNDEVACCESS) */
178
179                 (void) free((FREE_P *)Dstk[Dstkx]);
180                 Dstk[Dstkx] = (char *)NULL;
181                 continue;
182             }
183             if (path) {
184                 (void) free((FREE_P *)path);
185                 path = (char *)NULL;
186             }
187             if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1,
188                                   &pl)))
189             {
190                 (void) fprintf(stderr, "%s: no space for: ", Pn);
191                 safestrprt(Dstk[Dstkx], stderr, 1);
192                 Exit(1);
193             }
194             (void) free((FREE_P *)Dstk[Dstkx]);
195             Dstk[Dstkx] = (char *)NULL;
196         /*
197          * Scan the directory.
198          */
199             for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
200                 if (dp->d_ino == 0 || dp->d_name[0] == '.')
201                     continue;
202             /*
203              * Form the full path name and get its status.
204              */
205
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) */
211
212                 if (fp) {
213                     (void) free((FREE_P *)fp);
214                     fp = (char *)NULL;
215                 }
216                 if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen,
217                                     (char *)NULL, -1, (MALLOC_S *)NULL)))
218                 {
219                     (void) fprintf(stderr, "%s: no space for: ", Pn);
220                     safestrprt(path, stderr, 0);
221                     safestrprtn(dp->d_name, dnamlen, stderr, 1);
222                     Exit(1);
223                 }
224                 if (RDEV_STATFN(fp, &sb) != 0) {
225                     if (errno == ENOENT)        /* a sym link to nowhere? */
226                         continue;
227
228 # if    defined(WARNDEVACCESS)
229                     if (!Fwarn) {
230                         int errno_save = errno;
231
232                         (void) fprintf(stderr, "%s: can't stat ", Pn);
233                         safestrprt(fp, stderr, 0);
234                         (void) fprintf(stderr, ": %s\n", strerror(errno_save));
235                     }
236 # endif /* defined(WARNDEVACCESS) */
237
238                     continue;
239                 }
240             /*
241              * If it's a subdirectory, stack its name for later
242              * processing.
243              */
244                 if ((sb.st_mode & S_IFMT) == S_IFDIR) {
245                     (void) stkdir(fp);
246                     continue;
247                 }
248                 if ((sb.st_mode & S_IFMT) == S_IFCHR) {
249
250                 /*
251                  * Save character device information in Devtp[].
252                  */
253                     if (i >= Ndev) {
254                         Ndev += DEVINCR;
255                         if (!Devtp)
256                             Devtp = (struct l_dev *)malloc(
257                                     (MALLOC_S)(sizeof(struct l_dev)*Ndev));
258                         else
259                             Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
260                                     (MALLOC_S)(sizeof(struct l_dev)*Ndev));
261                         if (!Devtp) {
262                             (void) fprintf(stderr,
263                                 "%s: no space for character device\n", Pn);
264                             Exit(1);
265                         }
266                     }
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);
273                         Exit(1);
274                     }
275                     Devtp[i].v = 0;
276
277 # if    defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
278                     if (HAVECLONEMAJ && GET_MAJ_DEV(Devtp[i].rdev) == CLONEMAJ)
279                     {
280
281                     /*
282                      * Record clone device information.
283                      */
284                         if (!(c = (struct clone *)malloc(sizeof(struct clone))))
285                         {
286                             (void) fprintf(stderr,
287                                 "%s: no space for clone device: ", Pn);
288                             safestrprt(fp, stderr, 1);
289                             Exit(1);
290                         }
291                         c->dx = i;
292                         c->next = Clone;
293                         Clone = c;
294                     }
295 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
296
297                     i++;
298                 }
299
300 # if    defined(HASBLKDEV)
301                 if ((sb.st_mode & S_IFMT) == S_IFBLK) {
302
303                 /*
304                  * Save block device information in BDevtp[].
305                  */
306                     if (j >= BNdev) {
307                         BNdev += DEVINCR;
308                         if (!BDevtp)
309                             BDevtp = (struct l_dev *)malloc(
310                                      (MALLOC_S)(sizeof(struct l_dev)*BNdev));
311                         else
312                             BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
313                                      (MALLOC_S)(sizeof(struct l_dev)*BNdev));
314                         if (!BDevtp) {
315                             (void) fprintf(stderr,
316                                 "%s: no space for block device\n", Pn);
317                             Exit(1);
318                         }
319                     }
320                     BDevtp[j].name = fp;
321                     fp = (char *)NULL;
322                     BDevtp[j].inode = (INODETYPE)sb.st_ino;
323                     BDevtp[j].rdev = RDEV_EXPDEV(sb.st_rdev);
324                     BDevtp[j].v = 0;
325                     j++;
326                 }
327 # endif /* defined(HASBLKDEV) */
328
329             }
330             (void) CloseDir(dfp);
331         }
332 /*
333  * Free any allocated space.
334  */
335         if (!Dstk) {
336             (void) free((FREE_P *)Dstk);
337             Dstk = (char **)NULL;
338         }
339         if (fp)
340             (void) free((FREE_P *)fp);
341         if (path)
342             (void) free((FREE_P *)path);
343
344 # if    defined(HASBLKDEV)
345 /*
346  * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
347  * sizes; allocate and build sort pointer lists; and sort the tables by
348  * device number.
349  */
350         if (BNdev) {
351             if (BNdev > j) {
352                 BNdev = j;
353                 BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
354                          (MALLOC_S)(sizeof(struct l_dev) * BNdev));
355             }
356             if (!(BSdev = (struct l_dev **)malloc(
357                           (MALLOC_S)(sizeof(struct l_dev *) * BNdev))))
358             {
359                 (void) fprintf(stderr,
360                     "%s: no space for block device sort pointers\n", Pn);
361                 Exit(1);
362             }
363             for (j = 0; j < BNdev; j++) {
364                 BSdev[j] = &BDevtp[j];
365             }
366             (void) qsort((QSORT_P *)BSdev, (size_t)BNdev,
367                 (size_t)sizeof(struct l_dev *), compdev);
368             BNdev = rmdupdev(&BSdev, BNdev, "block");
369         }
370         
371 #  if   !defined(NOWARNBLKDEV)
372         else {
373             if (!Fwarn)
374                 (void) fprintf(stderr,
375                     "%s: WARNING: no block devices found\n", Pn);
376         }
377 #  endif        /* !defined(NOWARNBLKDEV) */
378 # endif /* defined(HASBLKDEV) */
379
380         if (Ndev) {
381             if (Ndev > i) {
382                 Ndev = i;
383                 Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
384                         (MALLOC_S)(sizeof(struct l_dev) * Ndev));
385             }
386             if (!(Sdev = (struct l_dev **)malloc(
387                          (MALLOC_S)(sizeof(struct l_dev *) * Ndev))))
388             {
389                 (void) fprintf(stderr,
390                     "%s: no space for character device sort pointers\n", Pn);
391                 Exit(1);
392             }
393             for (i = 0; i < Ndev; i++) {
394                 Sdev[i] = &Devtp[i];
395             }
396             (void) qsort((QSORT_P *)Sdev, (size_t)Ndev,
397                 (size_t)sizeof(struct l_dev *), compdev);
398             Ndev = rmdupdev(&Sdev, Ndev, "char");
399         } else {
400             (void) fprintf(stderr, "%s: no character devices found\n", Pn);
401             Exit(1);
402         }
403
404 # if    defined(HASDCACHE)
405 /*
406  * Write device cache file, as required.
407  */
408         if (DCstate == 1 || (DCstate == 3 && dcrd))
409             write_dcache();
410 # endif /* defined(HASDCACHE) */
411
412 }
413
414
415 # if    defined(HASDCACHE)
416 /*
417  * rereaddev() - reread device names, modes and types
418  */
419
420 void
421 rereaddev()
422 {
423         (void) clr_devtab();
424
425 # if    defined(DCACHE_CLR)
426         (void) DCACHE_CLR();
427 # endif /* defined(DCACHE_CLR) */
428
429         readdev(1);
430         DCunsafe = 0;
431 }
432 #endif  /* defined(HASDCACHE) */
433
434
435 /*
436  * rmdupdev() - remove duplicate (major/minor/inode) devices
437  */
438
439 static int
440 rmdupdev(dp, n, nm)
441         struct l_dev ***dp;     /* device table pointers address */
442         int n;                  /* number of pointers */
443         char *nm;               /* device table name for error message */
444 {
445
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 */
449
450         int i, j, k;
451         struct l_dev **p;
452
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)
456                     break;
457
458 # if    defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
459             /*
460              * See if we're deleting a duplicate clone device.  If so,
461              * delete its clone table entry.
462              */
463                 for (c = Clone, cp = (struct clone *)NULL;
464                      c;
465                      cp = c, c = c->next)
466                 {
467                     if (&Devtp[c->dx] != p[k])
468                         continue;
469                     if (!cp)
470                         Clone = c->next;
471                     else
472                         cp->next = c->next;
473                     (void) free((FREE_P *)c);
474                     break;
475                 }
476 # endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
477
478             }
479             if (i != j)
480                 p[j] = p[i];
481             j++;
482             i = k;
483         }
484         if (n == j)
485             return(n);
486         if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp,
487                     (MALLOC_S)(j * sizeof(struct l_dev *)))))
488         {
489             (void) fprintf(stderr, "%s: can't realloc %s device pointers\n",
490                 Pn, nm);
491             Exit(1);
492         }
493         return(j);
494 }
495
496
497 # if    defined(HASDCACHE)
498 /*
499  * vfy_dev() - verify a device table entry (usually when DCunsafe == 1)
500  *
501  * Note: rereads entire device table when an entry can't be verified.
502  */
503
504 int
505 vfy_dev(dp)
506         struct l_dev *dp;               /* device table pointer */
507 {
508         struct stat sb;
509
510         if (!DCunsafe || dp->v)
511             return(1);
512         if (RDEV_STATFN(dp->name, &sb) != 0
513         ||  dp->rdev != RDEV_EXPDEV(sb.st_rdev)
514         ||  dp->inode != sb.st_ino) {
515            (void) rereaddev();
516            return(0);
517         }
518         dp->v = 1;
519         return(1);
520 }
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) */