2 * dvch.c -- device cache functions 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(HASDCACHE)
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) */
46 * dvch.c - module that contains common device cache functions
48 * The caller may define the following:
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
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.
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.
69 * DVCH_CHOWN if the dialect has no fchown() function, so
70 * chown() must be used instead.
72 * DVCH_DEVPATH if the path to the device directory isn't "/dev".
74 * DVCH_EXPDEV if st_rdev must be expanded with the expdev()
75 * macro before use. (This is an EP/IX artifact.)
77 * HASBLKDEV if block device information is stored in BDevtp[].
85 # if !defined(DVCH_DEVPATH)
86 #define DVCH_DEVPATH "/dev"
87 # endif /* !defined(DVCH_DEVPATH) */
93 static int crctbl[CRC_TBLL]; /* crc partial results table */
97 * Local function prototypes
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) */
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) */
119 # if defined(HASBLKDEV)
121 * alloc_bdcache() - allocate block device cache
127 if (!(BDevtp = (struct l_dev *)calloc((MALLOC_S)BNdev,
128 sizeof(struct l_dev))))
130 (void) fprintf(stderr, "%s: no space for block devices\n", Pn);
133 if (!(BSdev = (struct l_dev **)malloc((MALLOC_S)(sizeof(struct l_dev *)
136 (void) fprintf(stderr, "%s: no space for block device pointers\n",
141 # endif /* defined(HASBLKDEV) */
145 * alloc_dcache() - allocate device cache
151 if (!(Devtp = (struct l_dev *)calloc((MALLOC_S)Ndev,
152 sizeof(struct l_dev))))
154 (void) fprintf(stderr, "%s: no space for devices\n", Pn);
157 if (!(Sdev = (struct l_dev **)malloc((MALLOC_S)(sizeof(struct l_dev *)
160 (void) fprintf(stderr, "%s: no space for device pointers\n",
168 * clr_devtab() - clear the device tables and free their space
177 for (i = 0; i < Ndev; i++) {
179 (void) free((FREE_P *)Devtp[i].name);
180 Devtp[i].name = (char *)NULL;
183 (void) free((FREE_P *)Devtp);
184 Devtp = (struct l_dev *)NULL;
187 (void) free((FREE_P *)Sdev);
188 Sdev = (struct l_dev **)NULL;
192 # if defined(HASBLKDEV)
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;
200 (void) free((FREE_P *)BDevtp);
201 BDevtp = (struct l_dev *)NULL;
204 (void) free((FREE_P *)BSdev);
205 BSdev = (struct l_dev **)NULL;
208 # endif /* defined(HASBLKDEV) */
213 # if defined(DCACHE_CLR_LOCAL)
215 * clr_sect() - clear cached standard clone sections
221 struct clone *c, *c1;
224 for (c = Clone; c; c = c1) {
226 (void) free((FREE_P *)c);
228 Clone = (struct clone *)NULL;
231 # endif /* defined(DCACHE_CLR_LOCAL) */
235 * crc(b, l, s) - compute a crc for a block of bytes
240 char *b; /* block address */
242 unsigned *s; /* sum */
244 char *cp; /* character pointer */
245 char *lm; /* character limit pointer */
246 unsigned sum; /* check sum */
252 sum ^= ((int) *cp++) & 0xff;
253 sum = (sum >> 8) ^ crctbl[sum & 0xff];
260 * crcbld - build the CRC-16 partial results table
266 int bit; /* temporary bit value */
267 unsigned entry; /* entry under construction */
268 int i; /* polynomial table index */
269 int j; /* bit shift count */
271 for(i = 0; i < CRC_TBLL; i++) {
273 for (j = 1; j <= CRC_BITS; j++) {
285 * dcpath() - define device cache file paths
290 int rw; /* read (1) or write (2) mode */
291 int npw; /* inhibit (0) or enable (1) no
292 * path warning message */
294 char buf[MAXPATHLEN+1], *cp1, *cp2, hn[MAXPATHLEN+1];
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 */
304 * Release any space reserved by previous path calls to dcpath().
307 (void) free((FREE_P *)DCpath[1]);
308 DCpath[1] = (char *)NULL;
311 (void) free((FREE_P *)DCpath[3]);
312 DCpath[3] = (char *)NULL;
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.
320 if (Myuid == 0 || rw == 1 || (!Setuidroot && !Setgid))
321 DCpath[0] = DCpathArg;
323 DCpath[0] = (char *)NULL;
325 # if defined(HASENVDC)
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.
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);
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);
348 # endif /* defined(HASENVDC) */
350 # if defined(HASSYSDC)
352 * If HASSYSDC is defined, record the path of the system-wide device
353 * cache file, unless the mode is write.
356 DCpath[2] = HASSYSDC;
358 DCpath[2] = (char *)NULL;
359 # endif /* defined(HASSYSDC) */
361 # if defined(HASPERSDC)
363 * If HASPERSDC is defined, form a personal device cache path by
364 * interpreting the conversions specified in it.
366 * Get (HASPERSDCPATH) from the environment and add it to the home directory
369 for (cp1 = HASPERSDC, endf = i = 0; *cp1 && !endf; cp1++) {
373 * If the format character isn't a `%', copy it.
375 if (i < (int)sizeof(buf)) {
384 * `%' starts a conversion; the next character specifies
385 * the conversion type.
391 * Two consecutive `%' characters convert to one `%'
392 * character in the output.
396 if (i < (int)sizeof(buf))
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.
408 * If neither the effective nor the real UID is root, path
411 * This allows HASPERSDC to specify one path for non-root
412 * UIDs and another for the root (effective or real) UID.
416 if (Setuidroot || !Myuid)
423 * ``%h'' converts to the home directory.
427 if (!p && !(p = getpwuid(Myuid))) {
429 (void) fprintf(stderr,
430 "%s: WARNING: can't get home dir for UID: %d\n",
435 if ((i + (l = strlen(p->pw_dir))) >= (int)sizeof(buf)) {
439 (void) strcpy(&buf[i], p->pw_dir);
441 if (i > 0 && buf[i - 1] == '/' && *(cp1 + 1)) {
444 * If the home directory ends in a '/' and the next format
445 * character is a '/', delete the '/' at the end of the home
454 * ``%l'' converts to the full host name.
456 * ``%L'' converts to the first component (characters up
457 * to the first `.') of the host name.
462 if (gethostname(hn, sizeof(hn) - 1) < 0) {
464 (void) fprintf(stderr,
465 "%s: WARNING: no gethostname for %%l or %%L: %s\n",
466 Pn, strerror(errno));
470 hn[sizeof(hn) - 1] = '\0';
471 if (*cp1 == 'L' && (cp2 = strchr(hn, '.')) && cp2 > hn)
474 if ((j + i) < (int)sizeof(buf)) {
475 (void) strcpy(&buf[i], hn);
482 * ``%p'' converts to the contents of LSOFPERSDCPATH, followed
485 * It is ignored when:
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.
494 # if defined(HASPERSDCPATH)
495 if ((cp2 = getenv(HASPERSDCPATH))
496 && (l = strlen(cp2)) > 0
499 && (rw == 1 || !Setgid))
501 if (i && buf[i - 1] == '/' && *cp2 == '/') {
505 if ((i + l) < ((int)sizeof(buf) - 1)) {
506 (void) strcpy(&buf[i], cp2);
508 if (buf[i - 1] != '/') {
509 if (i < ((int)sizeof(buf) - 2)) {
520 (void) fprintf(stderr,
521 "%s: WARNING: ignoring environment: %s",
523 safestrprt(cp2, stderr, 1);
528 # else /* !defined(HASPERSDCPATH) */
530 (void) fprintf(stderr,
531 "%s: WARNING: HASPERSDCPATH disabled: %s\n",
535 # endif /* defined(HASPERSDCPATH) */
540 * ``%u'' converts to the login name of the real UID of the
545 if (!p && !(p = getpwuid(Myuid))) {
547 (void) fprintf(stderr,
548 "%s: WARNING: can't get login name for UID: %d\n",
553 if ((i + (l = strlen(p->pw_name))) >= (int)sizeof(buf)) {
557 (void) strcpy(&buf[i], p->pw_name);
562 * ``%U'' converts to the real UID of the lsof process.
566 (void) snpf(hn, sizeof(hn), "%d", (int)Myuid);
567 if ((i + (l = strlen(hn))) >= (int)sizeof(buf))
570 (void) strcpy(&buf[i], hn);
576 (void) fprintf(stderr,
577 "%s: WARNING: bad conversion (%%%c): %s\n",
578 Pn, *cp1, HASPERSDC);
581 if (endf || ierr > 1)
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.
592 if (ierr == 2 && !Fwarn)
593 (void) fprintf(stderr,
594 "%s: WARNING: device cache path too large: %s\n",
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].
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);
612 # endif /* defined(HASPERSDC) */
615 * Quit if there was a malloc() error. The appropriate error message
616 * will have been issued to stderr.
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.
625 for (i = 0; i < MAXDCPATH; i++) {
630 (void) fprintf(stderr,
631 "%s: WARNING: can't form any device cache path\n", Pn);
637 * open_dcache() - open device cache file
642 int m; /* mode: 1 = read; 2 = write */
643 int r; /* create DCpath[] if 0, reuse if 1 */
644 struct stat *s; /* stat() receiver */
647 char *w = (char *)NULL;
649 * Get the device cache file paths.
652 if ((DCpathX = dcpath(m, 1)) < 0)
656 * Switch to the requested open() action.
662 * Check for access permission.
664 if (!is_readable(DCpath[DCpathX], 0)) {
665 if (DCpathX == 2 && errno == ENOENT)
668 (void) fprintf(stderr, ACCESSERRFMT,
669 Pn, DCpath[DCpathX], strerror(errno));
675 if ((DCfd = open(DCpath[DCpathX], O_RDONLY, 0)) < 0) {
676 if (DCstate == 3 && errno == ENOENT)
680 (void) fprintf(stderr,
681 "%s: WARNING: can't open %s: %s\n",
682 Pn, DCpath[DCpathX], strerror(errno));
685 if (stat(DCpath[DCpathX], s) != 0) {
689 (void) fprintf(stderr,
690 "%s: WARNING: can't stat(%s): %s\n",
691 Pn, DCpath[DCpathX], strerror(errno));
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);
701 } else if ((s->st_mode & S_IFMT) != S_IFREG)
702 w = "isn't a regular file";
703 else if (!s->st_size)
707 (void) fprintf(stderr,
708 "%s: WARNING: %s %s.\n", Pn, DCpath[DCpathX], w);
715 * Open for writing: first unlink any previous version; then
716 * open exclusively, specifying it's an error if the file exists.
718 if (unlink(DCpath[DCpathX]) < 0) {
719 if (errno != ENOENT) {
721 (void) fprintf(stderr,
722 "%s: WARNING: can't unlink %s: %s\n",
723 Pn, DCpath[DCpathX], strerror(errno));
727 if ((DCfd = open(DCpath[DCpathX], O_RDWR|O_CREAT|O_EXCL, 0600)) < 0)
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.
733 if (Myuid && Setuidroot) {
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) */
743 (void) fprintf(stderr,
744 "%s: WARNING: can't change ownerships of %s: %s\n",
745 Pn, DCpath[DCpathX], strerror(errno));
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]);
762 (void) fprintf(stderr, "%s: internal error: open_dcache=%d\n",
771 * read_dcache() - read device cache file
777 char buf[MAXPATHLEN*2], cbuf[64], *cp;
779 struct stat sb, devsb;
781 * Open the device cache file.
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
787 if ((ov = open_dcache(1, 0, &sb)) != 0) {
789 if (ov == 2 && DCpath[3]) {
791 if (open_dcache(1, 1, &sb) != 0)
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.
802 if (stat(DVCH_DEVPATH, &devsb) != 0) {
804 (void) fprintf(stderr,
805 "%s: WARNING: can't stat(%s): %s\n",
806 Pn, DVCH_DEVPATH, strerror(errno));
808 if (sb.st_mtime <= devsb.st_mtime || sb.st_ctime <= devsb.st_ctime)
811 if (!(DCfs = fdopen(DCfd, "r"))) {
813 (void) fprintf(stderr,
814 "%s: WARNING: can't fdopen(%s)\n", Pn, DCpath[DCpathX]);
820 * Read the section count line; initialize the CRC table;
821 * validate the section count line.
823 if (!fgets(buf, sizeof(buf), DCfs)) {
827 (void) fprintf(stderr,
828 "%s: WARNING: can't fread %s: %s\n", Pn, DCpath[DCpathX],
836 # if defined(DCACHE_CLR)
838 # endif /* defined(DCACHE_CLR) */
844 (void) crc(buf, strlen(buf), &DCcksum);
848 # if defined(HASBLKDEV)
851 # endif /* defined(HASBLKDEV) */
853 # if defined(DCACHE_CLONE)
856 # endif /* defined(DCACHE_CLONE) */
858 # if defined(DCACHE_PSEUDO)
861 # endif /* defined(DCACHE_PSEUDO) */
863 (void) snpf(cbuf, sizeof(cbuf), "%d section%s", i, cp);
865 (void) snpf(&cbuf[len], sizeof(cbuf) - len, ", dev=%lx\n",
867 if (!strncmp(buf, cbuf, len) && (buf[len] == '\n')) {
869 (void) fprintf(stderr,
870 "%s: WARNING: no /dev device in %s: line ", Pn,
872 safestrprt(buf, stderr, 1+4+8);
876 if (strcmp(buf, cbuf)) {
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);
886 * Read device section header and validate it.
888 if (!fgets(buf, sizeof(buf), DCfs))
890 (void) crc(buf, strlen(buf), &DCcksum);
891 len = strlen("device section: ");
892 if (strncmp(buf, "device section: ", len) != 0) {
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);
904 * Compute the device count; allocate Sdev[] and Devtp[] space.
906 if ((Ndev = atoi(&buf[len])) < 1)
910 * Read the device lines and store their information in Devtp[].
911 * Construct the Sdev[] pointers to Devtp[].
913 for (i = 0; i < Ndev; i++) {
914 if (!fgets(buf, sizeof(buf), DCfs)) {
916 (void) fprintf(stderr,
917 "%s: WARNING: can't read device %d from %s\n",
918 Pn, i + 1, DCpath[DCpathX]);
921 (void) crc(buf, strlen(buf), &DCcksum);
923 * Convert hexadecimal device number.
925 if (!(cp = x2dev(buf, &Devtp[i].rdev)) || *cp != ' ') {
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);
935 * Convert inode number.
937 for (cp++, Devtp[i].inode = (INODETYPE)0; *cp != ' '; cp++) {
938 if (*cp < '0' || *cp > '9') {
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);
947 Devtp[i].inode = (INODETYPE)((Devtp[i].inode * 10)
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[].
955 if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
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);
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);
975 # if defined(HASBLKDEV)
977 * Read block device section header and validate it.
979 if (!fgets(buf, sizeof(buf), DCfs))
981 (void) crc(buf, strlen(buf), &DCcksum);
982 len = strlen("block device section: ");
983 if (strncmp(buf, "block device section: ", len) != 0) {
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);
993 * Compute the block device count; allocate BSdev[] and BDevtp[] space.
995 if ((BNdev = atoi(&buf[len])) > 0) {
998 * Read the block device lines and store their information in BDevtp[].
999 * Construct the BSdev[] pointers to BDevtp[].
1001 for (i = 0; i < BNdev; i++) {
1002 if (!fgets(buf, sizeof(buf), DCfs)) {
1004 (void) fprintf(stderr,
1005 "%s: WARNING: can't read block device %d from %s\n",
1006 Pn, i + 1, DCpath[DCpathX]);
1009 (void) crc(buf, strlen(buf), &DCcksum);
1011 * Convert hexadecimal device number.
1013 if (!(cp = x2dev(buf, &BDevtp[i].rdev)) || *cp != ' ') {
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);
1023 * Convert inode number.
1025 for (cp++, BDevtp[i].inode = (INODETYPE)0; *cp != ' '; cp++) {
1026 if (*cp < '0' || *cp > '9') {
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);
1035 BDevtp[i].inode = (INODETYPE)((BDevtp[i].inode * 10)
1036 + (int)(*cp - '0'));
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[].
1043 if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
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);
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);
1060 BSdev[i] = &BDevtp[i];
1063 # endif /* defined(HASBLKDEV) */
1065 # if defined(DCACHE_CLONE)
1067 * Read the clone section.
1069 if (DCACHE_CLONE(1))
1071 # endif /* defined(DCACHE_CLONE) */
1073 # if defined(DCACHE_PSEUDO)
1075 * Read the pseudo section.
1077 if (DCACHE_PSEUDO(1))
1079 # endif /* defined(DCACHE_PSEUDO) */
1082 * Read and check the CRC section; it must be the last thing in the file.
1084 (void) snpf(cbuf, sizeof(cbuf), "CRC section: %x\n", DCcksum);
1085 if (!fgets(buf, sizeof(buf), DCfs) || strcmp(buf, cbuf) != 0) {
1087 (void) fprintf(stderr,
1088 "%s: WARNING: bad CRC section in %s: line ",
1089 Pn, DCpath[DCpathX]);
1090 safestrprt(buf, stderr, 1+4+8);
1094 if (fgets(buf, sizeof(buf), DCfs)) {
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);
1104 * Check one device entry at random -- the randomness based on our
1107 i = (int)(Mypid % Ndev);
1108 if (stat(Devtp[i].name, &sb) != 0
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) */
1116 || sb.st_ino != Devtp[i].inode) {
1118 (void) fprintf(stderr,
1119 "%s: WARNING: device cache mismatch: %s\n",
1124 * Close the device cache file and return OK.
1126 (void) fclose(DCfs);
1128 DCfs = (FILE *)NULL;
1133 # if defined(DCACHE_CLONE_LOCAL)
1135 * rw_clone_sect() - read/write the device cache file clone section
1140 int m; /* mode: 1 = read; 2 = write */
1142 char buf[MAXPATHLEN*2], *cp, *cp1;
1150 * Read the clone section header and validate it.
1152 if (!fgets(buf, sizeof(buf), DCfs)) {
1156 (void) fprintf(stderr,
1157 "%s: bad clone section header in %s: line ",
1158 Pn, DCpath[DCpathX]);
1159 safestrprt(buf, stderr, 1+4+8);
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;
1170 * Read the clone section lines and create the Clone list.
1172 for (i = 0; i < n; i++) {
1173 if (fgets(buf, sizeof(buf), DCfs) == NULL) {
1175 (void) fprintf(stderr,
1176 "%s: no %d clone line in %s: line ", Pn, i + 1,
1178 safestrprt(buf, stderr, 1+4+8);
1182 (void) crc(buf, strlen(buf), &DCcksum);
1184 * Assemble Devtp[] index and make sure it's correct.
1186 for (cp = buf, j = 0; *cp != ' '; cp++) {
1187 if (*cp < '0' || *cp > '9') {
1191 (void) fprintf(stderr,
1192 "%s: clone %d: bad cached device index: line ",
1194 safestrprt(buf, stderr, 1+4+8);
1198 j = (j * 10) + (int)(*cp - '0');
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;
1205 * Allocate and complete a clone structure.
1207 if (!(c = (struct clone *)malloc(sizeof(struct clone)))) {
1208 (void) fprintf(stderr,
1209 "%s: clone %d: no space for cached clone: line ", Pn,
1211 safestrprt(buf, stderr, 1+4+8);
1219 } else if (m == 2) {
1222 * Write the clone section header.
1224 for (c = Clone, n = 0; c; c = c->next, n++)
1226 (void) snpf(buf, sizeof(buf), "clone section: %d\n", n);
1227 if (wr2DCfd(buf, &DCcksum))
1230 * Write the clone section lines.
1232 for (c = Clone; c; c = c->next) {
1233 for (dp = &Devtp[c->dx], j = 0; j < Ndev; j++) {
1239 (void) fprintf(stderr,
1240 "%s: can't make index for clone: ", Pn);
1241 safestrprt(dp->name, stderr, 1);
1243 (void) unlink(DCpath[DCpathX]);
1248 (void) snpf(buf, sizeof(buf), "%d %s\n", j, dp->name);
1249 if (wr2DCfd(buf, &DCcksum))
1255 * A shouldn't-happen case: mode neither 1 nor 2.
1257 (void) fprintf(stderr, "%s: internal rw_clone_sect error: %d\n",
1260 return(1); /* This useless return(1) keeps some
1261 * compilers happy. */
1263 # endif /* defined(DCACHE_CLONE_LOCAL) */
1267 * write_dcache() - write device cache file
1273 char buf[MAXPATHLEN*2], *cp;
1278 * Open the cache file; set up the CRC table; write the section count.
1280 if (open_dcache(2, 0, &sb))
1285 # if defined(HASBLKDEV)
1288 # endif /* defined(HASBLKDEV) */
1290 # if defined(DCACHE_CLONE)
1293 # endif /* defined(DCACHE_CLONE) */
1295 # if defined(DCACHE_PSEUDO)
1298 # endif /* defined(DCACHE_PSEUDO) */
1300 (void) snpf(buf, sizeof(buf), "%d section%s, dev=%lx\n", i, cp,
1304 if (wr2DCfd(buf, &DCcksum))
1307 * Write the device section from the contents of Sdev[] and Devtp[].
1309 (void) snpf(buf, sizeof(buf), "device section: %d\n", Ndev);
1310 if (wr2DCfd(buf, &DCcksum))
1312 for (i = 0; i < Ndev; 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))
1320 # if defined(HASBLKDEV)
1322 * Write the block device section from the contents of BSdev[] and BDevtp[].
1324 (void) snpf(buf, sizeof(buf), "block device section: %d\n", BNdev);
1325 if (wr2DCfd(buf, &DCcksum))
1328 for (i = 0; i < BNdev; 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))
1336 # endif /* defined(HASBLKDEV) */
1338 # if defined(DCACHE_CLONE)
1340 * Write the clone section.
1342 if (DCACHE_CLONE(2))
1344 # endif /* defined(DCACHE_CLONE) */
1346 # if defined(DCACHE_PSEUDO)
1348 * Write the pseudo section.
1350 if (DCACHE_PSEUDO(2))
1352 # endif /* defined(DCACHE_PSEUDO) */
1355 * Write the CRC section and close the file.
1357 (void) snpf(buf, sizeof(buf), "CRC section: %x\n", DCcksum);
1358 if (wr2DCfd(buf, (unsigned *)NULL))
1360 if (close(DCfd) != 0) {
1362 (void) fprintf(stderr,
1363 "%s: WARNING: can't close %s: %s\n",
1364 Pn, DCpath[DCpathX], strerror(errno));
1365 (void) unlink(DCpath[DCpathX]);
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
1382 * wr2DCfd() - write to the DCfd file descriptor
1387 char *b; /* buffer */
1388 unsigned *c; /* checksum receiver */
1394 (void) crc(b, bl, c);
1396 if ((bw = write(DCfd, b, bl)) < 0) {
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]);
1411 #else /* !defined(HASDCACHE) */
1412 char dvch_d1[] = "d"; char *dvch_d2 = dvch_d1;
1413 #endif /* defined(HASDCACHE) */