Define LSOF_CC to system CC
[platform/upstream/lsof.git] / lib / dvch.c
1 /*
2  * dvch.c -- device cache functions 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(HASDCACHE)
36
37 # if    !defined(lint)
38 static char copyright[] =
39 "@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
40 static char *rcsid = "$Id: dvch.c,v 1.16 2008/10/21 16:12:36 abe Exp $";
41 # endif /* !defined(lint) */
42
43 #include "../lsof.h"
44
45 /*
46  * dvch.c - module that contains common device cache functions
47  *
48  * The caller may define the following:
49  *
50  *      DCACHE_CLONE    is the name of the function that reads and writes the
51  *                      clone section of the device cache file.  The clone
52  *                      section follows the device section.  If DCACHE_CLONE
53  *                      isn't defined, but HAS_STD_CLONE is defined to be 1,
54  *                      DCACHE_CLONE defaults to the local static function
55  *                      rw_clone_sect() that reads and writes a standard
56  *                      clone cache.
57  *
58  *      DCACHE_CLR      is the name of the function that clears the clone and
59  *                      pseudo caches when reading the device cache fails.   If
60  *                      DCACHE_CLR isn't defined, but HAS_STD_CLONE is defined
61  *                      to be 1, DCACHE_CLR defaults to the local static
62  *                      function clr_sect() that clears a standard clone cache.
63  *
64  *      DCACHE_PSEUDO   is the name of the function that reads and writes
65  *                      the pseudo section of the device cache file.  The
66  *                      pseudo section follows the device section and the
67  *                      clone section, if there is one.
68  *
69  *      DVCH_CHOWN      if the dialect has no fchown() function, so
70  *                      chown() must be used instead.
71  *
72  *      DVCH_DEVPATH    if the path to the device directory isn't "/dev".
73  *
74  *      DVCH_EXPDEV     if st_rdev must be expanded with the expdev()
75  *                      macro before use.  (This is an EP/IX artifact.)
76  *
77  *      HASBLKDEV       if block device information is stored in BDevtp[].
78  */
79
80
81 /*
82  * Local definitions
83  */
84
85 # if    !defined(DVCH_DEVPATH)
86 #define DVCH_DEVPATH    "/dev"
87 # endif /* !defined(DVCH_DEVPATH) */
88
89 /*
90  * Local storage
91  */
92
93 static int crctbl[CRC_TBLL];            /* crc partial results table */
94
95
96 /*
97  * Local function prototypes
98  */
99
100 #undef  DCACHE_CLR_LOCAL
101 # if    !defined(DCACHE_CLR)
102 #  if   defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
103 #define DCACHE_CLR              clr_sect
104 #define DCACHE_CLR_LOCAL        1
105 _PROTOTYPE(static void clr_sect,(void));
106 #  endif        /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
107 # endif /* !defined(DCACHE_CLR) */
108
109 #undef  DCACHE_CLONE_LOCAL
110 # if    !defined(DCACHE_CLONE)
111 #  if   defined(HAS_STD_CLONE) && HAS_STD_CLONE==1
112 #define DCACHE_CLONE            rw_clone_sect
113 #define DCACHE_CLONE_LOCAL      1
114 _PROTOTYPE(static int rw_clone_sect,(int m));
115 #  endif        /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
116 # endif /*!defined(DCACHE_CLONE) */
117
118
119 # if    defined(HASBLKDEV)
120 /*
121  * alloc_bdcache() - allocate block device cache
122  */
123
124 void
125 alloc_bdcache()
126 {
127         if (!(BDevtp = (struct l_dev *)calloc((MALLOC_S)BNdev,
128                                        sizeof(struct l_dev))))
129         {
130             (void) fprintf(stderr, "%s: no space for block devices\n", Pn);
131             Exit(1);
132         }
133         if (!(BSdev = (struct l_dev **)malloc((MALLOC_S)(sizeof(struct l_dev *)
134                                        * BNdev))))
135         {
136             (void) fprintf(stderr, "%s: no space for block device pointers\n",
137                 Pn);
138             Exit(1);
139         }
140 }
141 # endif /* defined(HASBLKDEV) */
142
143
144 /*
145  * alloc_dcache() - allocate device cache
146  */
147
148 void
149 alloc_dcache()
150 {
151         if (!(Devtp = (struct l_dev *)calloc((MALLOC_S)Ndev,
152                                       sizeof(struct l_dev))))
153         {
154             (void) fprintf(stderr, "%s: no space for devices\n", Pn);
155             Exit(1);
156         }
157         if (!(Sdev = (struct l_dev **)malloc((MALLOC_S)(sizeof(struct l_dev *)
158                                       * Ndev))))
159         {
160             (void) fprintf(stderr, "%s: no space for device pointers\n",
161                 Pn);
162             Exit(1);
163         }
164 }
165
166
167 /*
168  * clr_devtab() - clear the device tables and free their space
169  */
170
171 void
172 clr_devtab()
173 {
174         int i;
175
176         if (Devtp) {
177             for (i = 0; i < Ndev; i++) {
178                 if (Devtp[i].name) {
179                     (void) free((FREE_P *)Devtp[i].name);
180                     Devtp[i].name = (char *)NULL;
181                 }
182             }
183             (void) free((FREE_P *)Devtp);
184             Devtp = (struct l_dev *)NULL;
185         }
186         if (Sdev) {
187             (void) free((FREE_P *)Sdev);
188             Sdev = (struct l_dev **)NULL;
189         }
190         Ndev = 0;
191
192 # if    defined(HASBLKDEV)
193         if (BDevtp) {
194             for (i = 0; i < BNdev; i++) {
195                 if (BDevtp[i].name) {
196                     (void) free((FREE_P *)BDevtp[i].name);
197                     BDevtp[i].name = (char *)NULL;
198                 }
199             }
200             (void) free((FREE_P *)BDevtp);
201             BDevtp = (struct l_dev *)NULL;
202         }
203         if (BSdev) {
204             (void) free((FREE_P *)BSdev);
205             BSdev = (struct l_dev **)NULL;
206         }
207         BNdev = 0;
208 # endif /* defined(HASBLKDEV) */
209
210 }
211
212
213 # if    defined(DCACHE_CLR_LOCAL)
214 /*
215  * clr_sect() - clear cached standard clone sections
216  */
217
218 static void
219 clr_sect()
220 {
221         struct clone *c, *c1;
222
223         if (Clone) {
224             for (c = Clone; c; c = c1) {
225                 c1 = c->next;
226                 (void) free((FREE_P *)c);
227             }
228             Clone = (struct clone *)NULL;
229         }
230 }
231 # endif /* defined(DCACHE_CLR_LOCAL) */
232
233
234 /*
235  * crc(b, l, s) - compute a crc for a block of bytes
236  */
237
238 void
239 crc(b, l, s)
240         char *b;                        /* block address */
241         int  l;                         /* length */
242         unsigned *s;                    /* sum */
243 {
244         char *cp;                       /* character pointer */
245         char *lm;                       /* character limit pointer */
246         unsigned sum;                   /* check sum */
247
248         cp = b;
249         lm = cp + l;
250         sum = *s;
251         do {
252                 sum ^= ((int) *cp++) & 0xff;
253                 sum = (sum >> 8) ^ crctbl[sum & 0xff];
254         } while (cp < lm);
255         *s = sum;
256 }
257
258
259 /*
260  * crcbld - build the CRC-16 partial results table
261  */
262
263 void
264 crcbld()
265 {
266         int bit;                        /* temporary bit value */
267         unsigned entry;                 /* entry under construction */
268         int i;                          /* polynomial table index */
269         int j;                          /* bit shift count */
270
271         for(i = 0; i < CRC_TBLL; i++) {
272                 entry = i;
273                 for (j = 1; j <= CRC_BITS; j++) {
274                         bit = entry & 1;
275                         entry >>= 1;
276                         if (bit)
277                                 entry ^= CRC_POLY;
278                 }
279                 crctbl[i] = entry;
280         }
281 }
282
283
284 /*
285  * dcpath() - define device cache file paths
286  */
287
288 int
289 dcpath(rw, npw)
290         int rw;                         /* read (1) or write (2) mode */
291         int npw;                        /* inhibit (0) or enable (1) no
292                                          * path warning message */
293 {
294         char buf[MAXPATHLEN+1], *cp1, *cp2, hn[MAXPATHLEN+1];
295         int endf;
296         int i, j;
297         int l = 0;
298         int ierr = 0;                   /* intermediate error state */
299         int merr = 0;                   /* malloc error state */
300         struct passwd *p = (struct passwd *)NULL;
301         static short wenv = 1;          /* HASENVDC warning state */
302         static short wpp = 1;           /* HASPERSDCPATH warning state */
303 /*
304  * Release any space reserved by previous path calls to dcpath().
305  */
306         if (DCpath[1]) {
307             (void) free((FREE_P *)DCpath[1]);
308             DCpath[1] = (char *)NULL;
309         }
310         if (DCpath[3]) {
311             (void) free((FREE_P *)DCpath[3]);
312             DCpath[3] = (char *)NULL;
313         }
314 /*
315  * If a path was specified via -D, it's character address will have been
316  * stored in DCpathArg by ctrl_dcache().  Use that address if the real UID
317  * of this process is root, or the mode is read, or the process is neither
318  * setuid-root nor setgid.
319  */
320         if (Myuid == 0 || rw == 1 || (!Setuidroot && !Setgid))
321             DCpath[0] = DCpathArg;
322         else
323             DCpath[0] = (char *)NULL;
324
325 # if    defined(HASENVDC)
326 /*
327  * If HASENVDC is defined, get its value from the environment, unless this
328  * is a setuid-root process, or the real UID of the process is 0, or the
329  * mode is write and the process is setgid.
330  */
331         if ((cp1 = getenv(HASENVDC)) && (l = strlen(cp1)) > 0
332         &&  !Setuidroot && Myuid && (rw == 1 || !Setgid)) {
333             if (!(cp2 = mkstrcpy(cp1, (MALLOC_S *)NULL))) {
334                 (void) fprintf(stderr,
335                     "%s: no space for device cache path: %s=", Pn, HASENVDC);
336                 safestrprt(cp1, stderr, 1);
337                 merr = 1;
338             } else
339                 DCpath[1] = cp2;
340         } else if (cp1 && l > 0) {
341             if (!Fwarn && wenv) {
342                 (void) fprintf(stderr,
343                     "%s: WARNING: ignoring environment: %s=", Pn, HASENVDC);
344                 safestrprt(cp1, stderr, 1);
345             }
346             wenv = 0;
347         }
348 # endif /* defined(HASENVDC) */
349
350 # if    defined(HASSYSDC)
351 /*
352  * If HASSYSDC is defined, record the path of the system-wide device
353  * cache file, unless the mode is write.
354  */
355         if (rw != 2)
356             DCpath[2] = HASSYSDC;
357         else
358             DCpath[2] = (char *)NULL;
359 # endif /* defined(HASSYSDC) */
360
361 # if    defined(HASPERSDC)
362 /*
363  * If HASPERSDC is defined, form a personal device cache path by
364  * interpreting the conversions specified in it.
365  *
366  * Get (HASPERSDCPATH) from the environment and add it to the home directory
367  * path, if possible.
368  */
369         for (cp1 = HASPERSDC, endf = i = 0; *cp1 && !endf; cp1++) {
370             if (*cp1 != '%') {
371
372             /*
373              * If the format character isn't a `%', copy it.
374              */
375                 if (i < (int)sizeof(buf)) {
376                     buf[i++] = *cp1;
377                     continue;
378                 } else {
379                     ierr = 2;
380                     break;
381                 }
382              }
383         /*
384          * `%' starts a conversion; the next character specifies
385          * the conversion type.
386          */
387             cp1++;
388             switch (*cp1) {
389
390             /*
391              * Two consecutive `%' characters convert to one `%'
392              * character in the output.
393              */
394
395             case '%':
396                 if (i < (int)sizeof(buf))
397                         buf[i++] = '%';
398                 else
399                         ierr = 2;
400                 break;
401
402             /*
403              * ``%0'' defines a root boundary.  If the effective
404              * (setuid-root) or real UID of the process is root, any
405              * path formed to this point is discarded and path formation
406              * begins with the next character.
407              *
408              * If neither the effective nor the real UID is root, path
409              * formation ends.
410              *
411              * This allows HASPERSDC to specify one path for non-root
412              * UIDs and another for the root (effective or real) UID.
413              */
414
415             case '0':
416                 if (Setuidroot || !Myuid)
417                     i = 0;
418                 else
419                     endf = 1;
420                 break;
421
422             /*
423              * ``%h'' converts to the home directory.
424              */
425         
426             case 'h':
427                 if (!p && !(p = getpwuid(Myuid))) {
428                     if (!Fwarn)
429                         (void) fprintf(stderr,
430                             "%s: WARNING: can't get home dir for UID: %d\n",
431                             Pn, (int)Myuid);
432                     ierr = 1;
433                     break;
434                 }
435                 if ((i + (l = strlen(p->pw_dir))) >= (int)sizeof(buf)) {
436                     ierr = 2;
437                     break;
438                 }
439                 (void) strcpy(&buf[i], p->pw_dir);
440                 i += l;
441                 if (i > 0 && buf[i - 1] == '/' && *(cp1 + 1)) {
442
443                 /*
444                  * If the home directory ends in a '/' and the next format
445                  * character is a '/', delete the '/' at the end of the home
446                  * directory.
447                  */
448                     i--;
449                     buf[i] = '\0';
450                 }
451                 break;
452
453             /*
454              * ``%l'' converts to the full host name.
455              *
456              * ``%L'' converts to the first component (characters up
457              * to the first `.') of the host name.
458              */
459
460             case 'l':
461             case 'L':
462                 if (gethostname(hn, sizeof(hn) - 1) < 0) {
463                     if (!Fwarn)
464                         (void) fprintf(stderr,
465                             "%s: WARNING: no gethostname for %%l or %%L: %s\n",
466                             Pn, strerror(errno));
467                     ierr = 1;
468                     break;
469                 }
470                 hn[sizeof(hn) - 1] = '\0';
471                 if (*cp1 == 'L' && (cp2 = strchr(hn, '.')) && cp2 > hn)
472                     *cp2 = '\0';
473                 j = strlen(hn);
474                 if ((j + i) < (int)sizeof(buf)) {
475                     (void) strcpy(&buf[i], hn);
476                     i += j;
477                 } else
478                     ierr = 2;
479                 break;
480
481             /*
482              * ``%p'' converts to the contents of LSOFPERSDCPATH, followed
483              * by a '/'.
484              *
485              * It is ignored when:
486              *
487              *    The lsof process is setuid-root;
488              *    The real UID of the lsof process is 0;
489              *    The mode is write and the process is setgid.
490              */
491
492             case 'p':
493
494 #  if   defined(HASPERSDCPATH)
495                 if ((cp2 = getenv(HASPERSDCPATH))
496                 &&  (l = strlen(cp2)) > 0
497                 &&  !Setuidroot
498                 &&  Myuid
499                 &&  (rw == 1 || !Setgid))
500                 {
501                     if (i && buf[i - 1] == '/' && *cp2 == '/') {
502                         cp2++;
503                         l--;
504                     }
505                     if ((i + l) < ((int)sizeof(buf) - 1)) {
506                         (void) strcpy(&buf[i], cp2);
507                         i += l;
508                         if (buf[i - 1] != '/') {
509                             if (i < ((int)sizeof(buf) - 2)) {
510                                 buf[i++] = '/';
511                                 buf[i] = '\0';
512                             } else
513                                 ierr = 2;
514                         }
515                     } else
516                         ierr = 2;
517                 } else {
518                     if (cp2 && l > 0)  {
519                         if (!Fwarn && wpp) {
520                             (void) fprintf(stderr,
521                                 "%s: WARNING: ignoring environment: %s",
522                                 Pn, HASPERSDCPATH);
523                             safestrprt(cp2, stderr, 1);
524                         } 
525                         wpp = 0;
526                     }
527                 }
528 #  else /* !defined(HASPERSDCPATH) */
529                 if (!Fwarn && wpp)
530                     (void) fprintf(stderr,
531                         "%s: WARNING: HASPERSDCPATH disabled: %s\n",
532                         Pn, HASPERSDC);
533                 ierr = 1;
534                 wpp = 0;
535 #  endif        /* defined(HASPERSDCPATH) */
536
537                 break;
538
539             /*
540              * ``%u'' converts to the login name of the real UID of the
541              * lsof process.
542              */
543
544             case 'u':
545                 if (!p && !(p = getpwuid(Myuid))) {
546                     if (!Fwarn)
547                         (void) fprintf(stderr,
548                             "%s: WARNING: can't get login name for UID: %d\n",
549                             Pn, (int)Myuid);
550                     ierr = 1;
551                     break;
552                 }
553                 if ((i + (l = strlen(p->pw_name))) >= (int)sizeof(buf)) {
554                     ierr = 2;
555                     break;
556                 }
557                 (void) strcpy(&buf[i], p->pw_name);
558                 i += l;
559                 break;
560
561             /*
562              * ``%U'' converts to the real UID of the lsof process.
563              */
564
565             case 'U':
566                 (void) snpf(hn, sizeof(hn), "%d", (int)Myuid);
567                 if ((i + (l = strlen(hn))) >= (int)sizeof(buf))
568                     ierr = 2;
569                 else {
570                     (void) strcpy(&buf[i], hn);
571                     i += l;
572                 }
573                 break;
574             default:
575                 if (!Fwarn)
576                     (void) fprintf(stderr,
577                         "%s: WARNING: bad conversion (%%%c): %s\n",
578                         Pn, *cp1, HASPERSDC);
579                 ierr = 1;
580             }
581             if (endf || ierr > 1)
582                 break;
583         }
584         if (ierr) {
585
586         /*
587          * If there was an intermediate error of some type, handle it.
588          * A type 1 intermediate error has already been noted with a
589          * warning message.  A type 2 intermediate error requires the
590          * issuing of a buffer overlow warning message.
591          */
592             if (ierr == 2 && !Fwarn)
593                 (void) fprintf(stderr,
594                     "%s: WARNING: device cache path too large: %s\n",
595                     Pn, HASPERSDC);
596             i = 0;
597         }
598         buf[i] = '\0';
599 /*
600  * If there is one, allocate space for the personal device cache path,
601  * copy buf[] to it, and store its pointer in DCpath[3].
602  */
603         if (i) {
604             if (!(cp1 = mkstrcpy(buf, (MALLOC_S *)NULL))) {
605                 (void) fprintf(stderr,
606                     "%s: no space for device cache path: ", Pn);
607                 safestrprt(buf, stderr, 1);
608                 merr = 1;
609             } else
610                 DCpath[3] = cp1;
611         }
612 # endif /* defined(HASPERSDC) */
613
614 /*
615  * Quit if there was a malloc() error.  The appropriate error message
616  * will have been issued to stderr.
617  */
618         if (merr)
619             Exit(1);
620 /*
621  * Return the index of the first defined path.  Since DCpath[] is arranged
622  * in priority order, searching it beginning to end follows priority.
623  * Return an error indication if the search discloses no path name.
624  */
625         for (i = 0; i < MAXDCPATH; i++) {
626             if (DCpath[i])
627                 return(i);
628         }
629         if (!Fwarn && npw)
630             (void) fprintf(stderr,
631                 "%s: WARNING: can't form any device cache path\n", Pn);
632         return(-1);
633 }
634
635
636 /*
637  * open_dcache() - open device cache file
638  */
639
640 int
641 open_dcache(m, r, s)
642         int m;                  /* mode: 1 = read; 2 = write */
643         int r;                  /* create DCpath[] if 0, reuse if 1 */
644         struct stat *s;         /* stat() receiver */
645 {
646         char buf[128];
647         char *w = (char *)NULL;
648 /*
649  * Get the device cache file paths.
650  */
651         if (!r) {
652             if ((DCpathX = dcpath(m, 1)) < 0)
653                 return(1);
654         }
655 /*
656  * Switch to the requested open() action.
657  */
658         switch (m) {
659         case 1:
660
661         /*
662          * Check for access permission.
663          */
664             if (!is_readable(DCpath[DCpathX], 0)) {
665                 if (DCpathX == 2 && errno == ENOENT)
666                     return(2);
667                 if (!Fwarn)
668                     (void) fprintf(stderr, ACCESSERRFMT,
669                         Pn, DCpath[DCpathX], strerror(errno));
670                 return(1);
671             }
672         /*
673          * Open for reading.
674          */
675             if ((DCfd = open(DCpath[DCpathX], O_RDONLY, 0)) < 0) {
676                 if (DCstate == 3 && errno == ENOENT)
677                     return(1);
678
679 cant_open:
680                     (void) fprintf(stderr,
681                         "%s: WARNING: can't open %s: %s\n",
682                         Pn, DCpath[DCpathX], strerror(errno));
683                 return(1);
684             }
685             if (stat(DCpath[DCpathX], s) != 0) {
686
687 cant_stat:
688                 if (!Fwarn)
689                     (void) fprintf(stderr,
690                         "%s: WARNING: can't stat(%s): %s\n",
691                         Pn, DCpath[DCpathX], strerror(errno));
692 close_exit:
693                 (void) close(DCfd);
694                 DCfd = -1;
695                 return(1);
696             }
697             if ((int)(s->st_mode & 07777) != ((DCpathX == 2) ? 0644 : 0600)) {
698                 (void) snpf(buf, sizeof(buf), "doesn't have %04o modes",
699                     (DCpathX == 2) ? 0644 : 0600);
700                 w = buf;
701             } else if ((s->st_mode & S_IFMT) != S_IFREG)
702                 w = "isn't a regular file";
703             else if (!s->st_size)
704                 w = "is empty";
705             if (w) {
706                 if (!Fwarn)
707                     (void) fprintf(stderr,
708                         "%s: WARNING: %s %s.\n", Pn, DCpath[DCpathX], w);
709                 goto close_exit;
710             }
711             return(0);
712         case 2:
713
714         /*
715          * Open for writing: first unlink any previous version; then
716          * open exclusively, specifying it's an error if the file exists.
717          */
718             if (unlink(DCpath[DCpathX]) < 0) {
719                 if (errno != ENOENT) {
720                     if (!Fwarn)
721                         (void) fprintf(stderr,
722                             "%s: WARNING: can't unlink %s: %s\n",
723                             Pn, DCpath[DCpathX], strerror(errno));
724                     return(1);
725                 }
726             }
727             if ((DCfd = open(DCpath[DCpathX], O_RDWR|O_CREAT|O_EXCL, 0600)) < 0)
728                 goto cant_open;
729         /*
730          * If the real user is not root, but the process is setuid-root,
731          * change the ownerships of the file to the real ones.
732          */
733             if (Myuid && Setuidroot) {
734
735 # if    defined(DVCH_CHOWN)
736                 if (chown(DCpath[DCpathX], Myuid, getgid()) < 0)
737 # else  /* !defined(DVCH_CHOWN) */
738                 if (fchown(DCfd, Myuid, getgid()) < 0)
739 # endif /* defined(DVCH_CHOWN) */
740
741                 {
742                     if (!Fwarn)
743                         (void) fprintf(stderr,
744                              "%s: WARNING: can't change ownerships of %s: %s\n",
745                              Pn, DCpath[DCpathX], strerror(errno));
746                 }
747             }
748             if (!Fwarn && DCstate != 1 && !DCunsafe)
749                 (void) fprintf(stderr,
750                     "%s: WARNING: created device cache file: %s\n",
751                         Pn, DCpath[DCpathX]);
752             if (stat(DCpath[DCpathX], s) != 0) {
753                 (void) unlink(DCpath[DCpathX]);
754                 goto cant_stat;
755             }
756             return(0);
757         default:
758
759         /*
760          * Oops!
761          */
762             (void) fprintf(stderr, "%s: internal error: open_dcache=%d\n",
763                 Pn, m);
764             Exit(1);
765         }
766         return(1);
767 }
768
769
770 /*
771  * read_dcache() - read device cache file
772  */
773
774 int
775 read_dcache()
776 {
777         char buf[MAXPATHLEN*2], cbuf[64], *cp;
778         int i, len, ov;
779         struct stat sb, devsb;
780 /*
781  * Open the device cache file.
782  *
783  * If the open at HASSYSDC fails because the file doesn't exist, and
784  * the real UID of this process is not zero, try to open a device cache
785  * file at HASPERSDC.
786  */
787         if ((ov = open_dcache(1, 0, &sb)) != 0) {
788             if (DCpathX == 2) {
789                 if (ov == 2 && DCpath[3]) {
790                     DCpathX = 3;
791                     if (open_dcache(1, 1, &sb) != 0)
792                         return(1);
793                 } else
794                     return(1);
795             } else
796                 return(1);
797         }
798 /*
799  * If the open device cache file's last mtime/ctime isn't greater than
800  * DVCH_DEVPATH's mtime/ctime, ignore it, unless -Dr was specified.
801  */
802         if (stat(DVCH_DEVPATH, &devsb) != 0) {
803             if (!Fwarn)
804                 (void) fprintf(stderr,
805                     "%s: WARNING: can't stat(%s): %s\n",
806                     Pn, DVCH_DEVPATH, strerror(errno));
807         } else {
808             if (sb.st_mtime <= devsb.st_mtime || sb.st_ctime <= devsb.st_ctime)
809                 DCunsafe = 1;
810         }
811         if (!(DCfs = fdopen(DCfd, "r"))) {
812             if (!Fwarn)
813                 (void) fprintf(stderr,
814                     "%s: WARNING: can't fdopen(%s)\n", Pn, DCpath[DCpathX]);
815             (void) close(DCfd);
816             DCfd = -1;
817             return(1);
818         }
819 /*
820  * Read the section count line; initialize the CRC table;
821  * validate the section count line.
822  */
823         if (!fgets(buf, sizeof(buf), DCfs)) {
824
825 cant_read:
826             if (!Fwarn)
827                 (void) fprintf(stderr,
828                     "%s: WARNING: can't fread %s: %s\n", Pn, DCpath[DCpathX],
829                     strerror(errno));
830 read_close:
831                 (void) fclose(DCfs);
832                 DCfd = -1;
833                 DCfs = (FILE *)NULL;
834                 (void) clr_devtab();
835
836 # if    defined(DCACHE_CLR)
837                 (void) DCACHE_CLR();
838 # endif /* defined(DCACHE_CLR) */
839
840                 return(1);
841         }
842         (void) crcbld();
843         DCcksum = 0;
844         (void) crc(buf, strlen(buf), &DCcksum);
845         i = 1;
846         cp = "";
847
848 # if    defined(HASBLKDEV)
849         i++;
850         cp = "s";
851 # endif /* defined(HASBLKDEV) */
852
853 # if    defined(DCACHE_CLONE)
854         i++;
855         cp = "s";
856 # endif /* defined(DCACHE_CLONE) */
857
858 # if    defined(DCACHE_PSEUDO)
859         i++;
860         cp = "s";
861 # endif /* defined(DCACHE_PSEUDO) */
862
863         (void) snpf(cbuf, sizeof(cbuf), "%d section%s", i, cp);
864         len = strlen(cbuf);
865         (void) snpf(&cbuf[len], sizeof(cbuf) - len, ", dev=%lx\n",
866                     (long)DevDev);
867         if (!strncmp(buf, cbuf, len) && (buf[len] == '\n')) {
868             if (!Fwarn) {
869                 (void) fprintf(stderr,
870                     "%s: WARNING: no /dev device in %s: line ", Pn,
871                     DCpath[DCpathX]);
872                 safestrprt(buf, stderr, 1+4+8);
873             }
874             goto read_close;
875         }
876         if (strcmp(buf, cbuf)) {
877             if (!Fwarn) {
878                 (void) fprintf(stderr,
879                     "%s: WARNING: bad section count line in %s: line ",
880                     Pn, DCpath[DCpathX]);
881                 safestrprt(buf, stderr, 1+4+8);
882             }
883             goto read_close;
884         }
885 /*
886  * Read device section header and validate it.
887  */
888         if (!fgets(buf, sizeof(buf), DCfs))
889             goto cant_read;
890         (void) crc(buf, strlen(buf), &DCcksum);
891         len = strlen("device section: ");
892         if (strncmp(buf, "device section: ", len) != 0) {
893
894 read_dhdr:
895             if (!Fwarn) {
896                 (void) fprintf(stderr,
897                     "%s: WARNING: bad device section header in %s: line ",
898                     Pn, DCpath[DCpathX]);
899                 safestrprt(buf, stderr, 1+4+8);
900             }
901             goto read_close;
902         }
903 /*
904  * Compute the device count; allocate Sdev[] and Devtp[] space.
905  */
906         if ((Ndev = atoi(&buf[len])) < 1)
907             goto read_dhdr;
908         alloc_dcache();
909 /*
910  * Read the device lines and store their information in Devtp[].
911  * Construct the Sdev[] pointers to Devtp[].
912  */
913         for (i = 0; i < Ndev; i++) {
914             if (!fgets(buf, sizeof(buf), DCfs)) {
915                 if (!Fwarn)
916                     (void) fprintf(stderr,
917                         "%s: WARNING: can't read device %d from %s\n",
918                         Pn, i + 1, DCpath[DCpathX]);
919                 goto read_close;
920             }
921             (void) crc(buf, strlen(buf), &DCcksum);
922         /*
923          * Convert hexadecimal device number.
924          */
925             if (!(cp = x2dev(buf, &Devtp[i].rdev)) || *cp != ' ') {
926                 if (!Fwarn) {
927                     (void) fprintf(stderr,
928                         "%s: device %d: bad device in %s: line ",
929                         Pn, i + 1, DCpath[DCpathX]);
930                     safestrprt(buf, stderr, 1+4+8);
931                 }
932                 goto read_close;
933             }
934         /*
935          * Convert inode number.
936          */
937             for (cp++, Devtp[i].inode = (INODETYPE)0; *cp != ' '; cp++) {
938                 if (*cp < '0' || *cp > '9') {
939                     if (!Fwarn) {
940                         (void) fprintf(stderr,
941                             "%s: WARNING: device %d: bad inode # in %s: line ",
942                             Pn, i + 1, DCpath[DCpathX]);
943                         safestrprt(buf, stderr, 1+4+8);
944                     }
945                     goto read_close;
946                 }
947                 Devtp[i].inode = (INODETYPE)((Devtp[i].inode * 10)
948                                + (int)(*cp - '0'));
949             }
950         /*
951          * Get path name; allocate space for it; copy it; store the
952          * pointer in Devtp[]; clear verify status; construct the Sdev[]
953          * pointer to Devtp[].
954          */
955             if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
956                 if (!Fwarn) {
957                     (void) fprintf(stderr,
958                         "%s: WARNING: device %d: bad path in %s: line ",
959                         Pn, i + 1, DCpath[DCpathX]);
960                     safestrprt(buf, stderr, 1+4+8);
961                  }
962                  goto read_close;
963             }
964             *(cp + len - 1) = '\0';
965             if (!(Devtp[i].name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
966                 (void) fprintf(stderr,
967                     "%s: device %d: no space for path: line ", Pn, i + 1);
968                 safestrprt(buf, stderr, 1+4+8);
969                 Exit(1);
970             }
971             Devtp[i].v = 0;
972             Sdev[i] = &Devtp[i];
973         }
974
975 # if    defined(HASBLKDEV)
976 /*
977  * Read block device section header and validate it.
978  */
979         if (!fgets(buf, sizeof(buf), DCfs))
980             goto cant_read;
981         (void) crc(buf, strlen(buf), &DCcksum);
982         len = strlen("block device section: ");
983         if (strncmp(buf, "block device section: ", len) != 0) {
984             if (!Fwarn) {
985                 (void) fprintf(stderr,
986                     "%s: WARNING: bad block device section header in %s: line ",
987                     Pn, DCpath[DCpathX]);
988                 safestrprt(buf, stderr, 1+4+8);
989             }
990             goto read_close;
991         }
992 /*
993  * Compute the block device count; allocate BSdev[] and BDevtp[] space.
994  */
995         if ((BNdev = atoi(&buf[len])) > 0) {
996             alloc_bdcache();
997         /*
998          * Read the block device lines and store their information in BDevtp[].
999          * Construct the BSdev[] pointers to BDevtp[].
1000          */
1001             for (i = 0; i < BNdev; i++) {
1002                 if (!fgets(buf, sizeof(buf), DCfs)) {
1003                     if (!Fwarn)
1004                         (void) fprintf(stderr,
1005                             "%s: WARNING: can't read block device %d from %s\n",
1006                             Pn, i + 1, DCpath[DCpathX]);
1007                     goto read_close;
1008                 }
1009                 (void) crc(buf, strlen(buf), &DCcksum);
1010             /*
1011              * Convert hexadecimal device number.
1012              */
1013                 if (!(cp = x2dev(buf, &BDevtp[i].rdev)) || *cp != ' ') {
1014                     if (!Fwarn) {
1015                         (void) fprintf(stderr,
1016                             "%s: block dev %d: bad device in %s: line ",
1017                             Pn, i + 1, DCpath[DCpathX]);
1018                         safestrprt(buf, stderr, 1+4+8);
1019                     }
1020                     goto read_close;
1021                 }
1022             /*
1023              * Convert inode number.
1024              */
1025                 for (cp++, BDevtp[i].inode = (INODETYPE)0; *cp != ' '; cp++) {
1026                     if (*cp < '0' || *cp > '9') {
1027                       if (!Fwarn) {
1028                         (void) fprintf(stderr,
1029                           "%s: WARNING: block dev %d: bad inode # in %s: line ",
1030                           Pn, i + 1, DCpath[DCpathX]);
1031                         safestrprt(buf, stderr, 1+4+8);
1032                       }
1033                       goto read_close;
1034                     }
1035                     BDevtp[i].inode = (INODETYPE)((BDevtp[i].inode * 10)
1036                                     + (int)(*cp - '0'));
1037                 }
1038             /*
1039              * Get path name; allocate space for it; copy it; store the
1040              * pointer in BDevtp[]; clear verify status; construct the BSdev[]
1041              * pointer to BDevtp[].
1042              */
1043                 if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
1044                     if (!Fwarn) {
1045                         (void) fprintf(stderr,
1046                             "%s: WARNING: block dev %d: bad path in %s: line",
1047                             Pn, i + 1, DCpath[DCpathX]);
1048                         safestrprt(buf, stderr, 1+4+8);
1049                     }
1050                     goto read_close;
1051                 }
1052                 *(cp + len - 1) = '\0';
1053                 if (!(BDevtp[i].name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
1054                     (void) fprintf(stderr,
1055                         "%s: block dev %d: no space for path: line", Pn, i + 1);
1056                     safestrprt(buf, stderr, 1+4+8);
1057                     Exit(1);
1058                 }
1059                 BDevtp[i].v = 0;
1060                 BSdev[i] = &BDevtp[i];
1061             }
1062         }
1063 # endif /* defined(HASBLKDEV) */
1064
1065 # if    defined(DCACHE_CLONE)
1066 /*
1067  * Read the clone section.
1068  */
1069         if (DCACHE_CLONE(1))
1070             goto read_close;
1071 # endif /* defined(DCACHE_CLONE) */
1072
1073 # if    defined(DCACHE_PSEUDO)
1074 /*
1075  * Read the pseudo section.
1076  */
1077         if (DCACHE_PSEUDO(1))
1078             goto read_close;
1079 # endif /* defined(DCACHE_PSEUDO) */
1080
1081 /*
1082  * Read and check the CRC section; it must be the last thing in the file.
1083  */
1084         (void) snpf(cbuf, sizeof(cbuf), "CRC section: %x\n", DCcksum);
1085         if (!fgets(buf, sizeof(buf), DCfs) || strcmp(buf, cbuf) != 0) {
1086             if (!Fwarn) {
1087                 (void) fprintf(stderr,
1088                     "%s: WARNING: bad CRC section in %s: line ",
1089                     Pn, DCpath[DCpathX]);
1090                 safestrprt(buf, stderr, 1+4+8);
1091             }
1092             goto read_close;
1093         }
1094         if (fgets(buf, sizeof(buf), DCfs)) {
1095             if (!Fwarn) {
1096                 (void) fprintf(stderr,
1097                     "%s: WARNING: data follows CRC section in %s: line ",
1098                     Pn, DCpath[DCpathX]);
1099                 safestrprt(buf, stderr, 1+4+8);
1100             }
1101             goto read_close;
1102         }
1103 /*
1104  * Check one device entry at random -- the randomness based on our
1105  * PID.
1106  */
1107         i = (int)(Mypid % Ndev);
1108         if (stat(Devtp[i].name, &sb) != 0
1109
1110 # if    defined(DVCH_EXPDEV)
1111         ||  expdev(sb.st_rdev) != Devtp[i].rdev
1112 # else  /* !defined(DVCH_EXPDEV) */
1113         ||  sb.st_rdev != Devtp[i].rdev
1114 # endif /* defined(DVCH_EXPDEV) */
1115
1116         || sb.st_ino != Devtp[i].inode) {
1117             if (!Fwarn)
1118                 (void) fprintf(stderr,
1119                         "%s: WARNING: device cache mismatch: %s\n",
1120                         Pn, Devtp[i].name);
1121             goto read_close;
1122         }
1123 /*
1124  * Close the device cache file and return OK.
1125  */
1126         (void) fclose(DCfs);
1127         DCfd = -1;
1128         DCfs = (FILE *)NULL;
1129         return(0);
1130 }
1131
1132
1133 # if    defined(DCACHE_CLONE_LOCAL)
1134 /*
1135  * rw_clone_sect() - read/write the device cache file clone section
1136  */
1137
1138 static int
1139 rw_clone_sect(m)
1140         int m;                          /* mode: 1 = read; 2 = write */
1141 {
1142         char buf[MAXPATHLEN*2], *cp, *cp1;
1143         struct clone *c;
1144         struct l_dev *dp;
1145         int i, j, len, n;
1146
1147         if (m == 1) {
1148
1149         /*
1150          * Read the clone section header and validate it.
1151          */
1152             if (!fgets(buf, sizeof(buf), DCfs)) {
1153
1154 bad_clone_sect:
1155                 if (!Fwarn) {
1156                     (void) fprintf(stderr,
1157                         "%s: bad clone section header in %s: line ",
1158                         Pn, DCpath[DCpathX]);
1159                     safestrprt(buf, stderr, 1+4+8);
1160                 }
1161                 return(1);
1162             }
1163             (void) crc(buf, strlen(buf), &DCcksum);
1164             len = strlen("clone section: ");
1165             if (strncmp(buf, "clone section: ", len) != 0)
1166                 goto bad_clone_sect;
1167             if ((n = atoi(&buf[len])) < 0)
1168                 goto bad_clone_sect;
1169         /*
1170          * Read the clone section lines and create the Clone list.
1171          */
1172             for (i = 0; i < n; i++) {
1173                 if (fgets(buf, sizeof(buf), DCfs) == NULL) {
1174                     if (!Fwarn) {
1175                         (void) fprintf(stderr,
1176                             "%s: no %d clone line in %s: line ", Pn, i + 1,
1177                             DCpath[DCpathX]);
1178                         safestrprt(buf, stderr, 1+4+8);
1179                     }
1180                     return(1);
1181                 }
1182                 (void) crc(buf, strlen(buf), &DCcksum);
1183             /*
1184              * Assemble Devtp[] index and make sure it's correct.
1185              */
1186                 for (cp = buf, j = 0; *cp != ' '; cp++) {
1187                     if (*cp < '0' || *cp > '9') {
1188
1189 bad_clone_index:
1190                         if (!Fwarn) {
1191                             (void) fprintf(stderr,
1192                                 "%s: clone %d: bad cached device index: line ",
1193                                 Pn, i + 1);
1194                             safestrprt(buf, stderr, 1+4+8);
1195                         }
1196                         return(1);
1197                     }
1198                     j = (j * 10) + (int)(*cp - '0');
1199                 }
1200                 if (j < 0 || j >= Ndev || (cp1 = strchr(++cp, '\n')) == NULL)
1201                     goto bad_clone_index;
1202                 if (strncmp(cp, Devtp[j].name, (cp1 - cp)) != 0)
1203                     goto bad_clone_index;
1204             /*
1205              * Allocate and complete a clone structure.
1206              */
1207                 if (!(c = (struct clone *)malloc(sizeof(struct clone)))) {
1208                     (void) fprintf(stderr,
1209                         "%s: clone %d: no space for cached clone: line ", Pn,
1210                         i + 1);
1211                     safestrprt(buf, stderr, 1+4+8);
1212                     Exit(1);
1213                 }
1214                 c->dx = j;
1215                 c->next = Clone;
1216                 Clone = c;
1217             }
1218             return(0);
1219         } else if (m == 2) {
1220
1221         /*
1222          * Write the clone section header.
1223          */
1224             for (c = Clone, n = 0; c; c = c->next, n++)
1225                 ;
1226             (void) snpf(buf, sizeof(buf), "clone section: %d\n", n);
1227             if (wr2DCfd(buf, &DCcksum))
1228                 return(1);
1229         /*
1230          * Write the clone section lines.
1231          */
1232             for (c = Clone; c; c = c->next) {
1233                 for (dp = &Devtp[c->dx], j = 0; j < Ndev; j++) {
1234                     if (dp == Sdev[j])
1235                         break;
1236                 }
1237                 if (j >= Ndev) {
1238                     if (!Fwarn) {
1239                         (void) fprintf(stderr,
1240                             "%s: can't make index for clone: ", Pn);
1241                         safestrprt(dp->name, stderr, 1);
1242                     }
1243                     (void) unlink(DCpath[DCpathX]);
1244                     (void) close(DCfd);
1245                     DCfd = -1;
1246                     return(1);
1247                 }
1248                 (void) snpf(buf, sizeof(buf), "%d %s\n", j, dp->name);
1249                 if (wr2DCfd(buf, &DCcksum))
1250                     return(1);
1251             }
1252             return(0);
1253         }
1254 /*
1255  * A shouldn't-happen case: mode neither 1 nor 2.
1256  */
1257         (void) fprintf(stderr, "%s: internal rw_clone_sect error: %d\n",
1258             Pn, m);
1259         Exit(1);
1260         return(1);              /* This useless return(1) keeps some
1261                                  * compilers happy. */
1262 }
1263 # endif /* defined(DCACHE_CLONE_LOCAL) */
1264
1265
1266 /*
1267  * write_dcache() - write device cache file
1268  */
1269
1270 void
1271 write_dcache()
1272 {
1273         char buf[MAXPATHLEN*2], *cp;
1274         struct l_dev *dp;
1275         int i;
1276         struct stat sb;
1277 /*
1278  * Open the cache file; set up the CRC table; write the section count.
1279  */
1280         if (open_dcache(2, 0, &sb))
1281                 return;
1282         i = 1;
1283         cp = "";
1284
1285 # if    defined(HASBLKDEV)
1286         i++;
1287         cp = "s";
1288 # endif /* defined(HASBLKDEV) */
1289
1290 # if    defined(DCACHE_CLONE)
1291         i++;
1292         cp = "s";
1293 # endif /* defined(DCACHE_CLONE) */
1294
1295 # if    defined(DCACHE_PSEUDO)
1296         i++;
1297         cp = "s";
1298 # endif /* defined(DCACHE_PSEUDO) */
1299
1300         (void) snpf(buf, sizeof(buf), "%d section%s, dev=%lx\n", i, cp,
1301             (long)DevDev);
1302         (void) crcbld();
1303         DCcksum = 0;
1304         if (wr2DCfd(buf, &DCcksum))
1305                 return;
1306 /*
1307  * Write the device section from the contents of Sdev[] and Devtp[].
1308  */
1309         (void) snpf(buf, sizeof(buf), "device section: %d\n", Ndev);
1310         if (wr2DCfd(buf, &DCcksum))
1311             return;
1312         for (i = 0; i < Ndev; i++) {
1313             dp = Sdev[i];
1314             (void) snpf(buf, sizeof(buf), "%lx %ld %s\n", (long)dp->rdev,
1315                         (long)dp->inode, dp->name);
1316             if (wr2DCfd(buf, &DCcksum))
1317                 return;
1318         }
1319
1320 # if    defined(HASBLKDEV)
1321 /*
1322  * Write the block device section from the contents of BSdev[] and BDevtp[].
1323  */
1324         (void) snpf(buf, sizeof(buf), "block device section: %d\n", BNdev);
1325         if (wr2DCfd(buf, &DCcksum))
1326             return;
1327         if (BNdev) {
1328             for (i = 0; i < BNdev; i++) {
1329                 dp = BSdev[i];
1330                 (void) snpf(buf, sizeof(buf), "%lx %ld %s\n", (long)dp->rdev,
1331                     (long)dp->inode, dp->name);
1332                 if (wr2DCfd(buf, &DCcksum))
1333                     return;
1334             }
1335         }
1336 # endif /* defined(HASBLKDEV) */
1337
1338 # if    defined(DCACHE_CLONE)
1339 /*
1340  * Write the clone section.
1341  */
1342         if (DCACHE_CLONE(2))
1343             return;
1344 # endif /* defined(DCACHE_CLONE) */
1345
1346 # if    defined(DCACHE_PSEUDO)
1347 /*
1348  * Write the pseudo section.
1349  */
1350         if (DCACHE_PSEUDO(2))
1351             return;
1352 # endif /* defined(DCACHE_PSEUDO) */
1353
1354 /*
1355  * Write the CRC section and close the file.
1356  */
1357         (void) snpf(buf, sizeof(buf), "CRC section: %x\n", DCcksum);
1358         if (wr2DCfd(buf, (unsigned *)NULL))
1359                 return;
1360         if (close(DCfd) != 0) {
1361             if (!Fwarn)
1362                 (void) fprintf(stderr,
1363                     "%s: WARNING: can't close %s: %s\n",
1364                     Pn, DCpath[DCpathX], strerror(errno));
1365             (void) unlink(DCpath[DCpathX]);
1366             DCfd = -1;
1367         }
1368         DCfd = -1;
1369 /*
1370  * If the previous reading of the previous device cache file marked it
1371  * "unsafe," drop that marking and record that the device cache file was
1372  * rebuilt.
1373  */
1374         if (DCunsafe) {
1375             DCunsafe = 0;
1376             DCrebuilt = 1;
1377         }
1378 }
1379
1380
1381 /*
1382  * wr2DCfd() - write to the DCfd file descriptor
1383  */
1384
1385 int
1386 wr2DCfd(b, c)
1387         char *b;                        /* buffer */
1388         unsigned *c;                    /* checksum receiver */
1389 {
1390         int bl, bw;
1391
1392         bl = strlen(b);
1393         if (c)
1394             (void) crc(b, bl, c);
1395         while (bl > 0) {
1396             if ((bw = write(DCfd, b, bl)) < 0) {
1397                 if (!Fwarn)
1398                     (void) fprintf(stderr,
1399                         "%s: WARNING: can't write to %s: %s\n",
1400                         Pn, DCpath[DCpathX], strerror(errno));
1401                 (void) unlink(DCpath[DCpathX]);
1402                 (void) close(DCfd);
1403                 DCfd = -1;
1404                 return(1);
1405             }
1406             b += bw;
1407             bl -= bw;
1408         }
1409         return(0);
1410 }
1411 #else   /* !defined(HASDCACHE) */
1412 char dvch_d1[] = "d"; char *dvch_d2 = dvch_d1;
1413 #endif  /* defined(HASDCACHE) */