| 1 | /* |
| 2 | * Copyright (c) 1990 The Regents of the University of California. |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms are permitted provided |
| 6 | * that: (1) source distributions retain this entire copyright notice and |
| 7 | * comment, and (2) distributions including binaries display the following |
| 8 | * acknowledgement: ``This product includes software developed by the |
| 9 | * University of California, Berkeley and its contributors'' in the |
| 10 | * documentation or other materials provided with the distribution and in |
| 11 | * all advertising materials mentioning features or use of this software. |
| 12 | * Neither the name of the University nor the names of its contributors may |
| 13 | * be used to endorse or promote products derived from this software without |
| 14 | * specific prior written permission. |
| 15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
| 16 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
| 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| 18 | */ |
| 19 | |
| 20 | #ifndef lint |
| 21 | static char sccsid[] = "@(#)preen.c 5.5 (Berkeley) 7/20/90"; |
| 22 | #endif /* not lint */ |
| 23 | |
| 24 | #include <sys/param.h> |
| 25 | #include <sys/stat.h> |
| 26 | #include <sys/wait.h> |
| 27 | #include <fstab.h> |
| 28 | #include <string.h> |
| 29 | #include <stdio.h> |
| 30 | #include <stdlib.h> |
| 31 | #include <ctype.h> |
| 32 | |
| 33 | char *rawname(), *unrawname(), *blockcheck(); |
| 34 | |
| 35 | struct part { |
| 36 | struct part *next; /* forward link of partitions on disk */ |
| 37 | char *name; /* device name */ |
| 38 | char *fsname; /* mounted filesystem name */ |
| 39 | long auxdata; /* auxillary data for application */ |
| 40 | } *badlist, **badnext = &badlist; |
| 41 | |
| 42 | struct disk { |
| 43 | char *name; /* disk base name */ |
| 44 | struct disk *next; /* forward link for list of disks */ |
| 45 | struct part *part; /* head of list of partitions on disk */ |
| 46 | int pid; /* If != 0, pid of proc working on */ |
| 47 | } *disks; |
| 48 | |
| 49 | int nrun, ndisks; |
| 50 | char hotroot; |
| 51 | |
| 52 | checkfstab(preen, maxrun, docheck, chkit) |
| 53 | int preen, maxrun; |
| 54 | int (*docheck)(), (*chkit)(); |
| 55 | { |
| 56 | register struct fstab *fsp; |
| 57 | register struct disk *dk, *nextdisk; |
| 58 | register struct part *pt; |
| 59 | int ret, pid, retcode, passno, sumstatus, status; |
| 60 | long auxdata; |
| 61 | char *name; |
| 62 | |
| 63 | sumstatus = 0; |
| 64 | for (passno = 1; passno <= 2; passno++) { |
| 65 | if (setfsent() == 0) { |
| 66 | fprintf(stderr, "Can't open checklist file: %s\n", |
| 67 | _PATH_FSTAB); |
| 68 | return (8); |
| 69 | } |
| 70 | while ((fsp = getfsent()) != 0) { |
| 71 | if ((auxdata = (*docheck)(fsp)) == 0) |
| 72 | continue; |
| 73 | if (preen == 0 || passno == 1 && fsp->fs_passno == 1) { |
| 74 | if (name = blockcheck(fsp->fs_spec)) { |
| 75 | if (sumstatus = (*chkit)(name, |
| 76 | fsp->fs_file, auxdata)) |
| 77 | return (sumstatus); |
| 78 | } else if (preen) |
| 79 | return (8); |
| 80 | } else if (passno == 2 && fsp->fs_passno > 1) { |
| 81 | if ((name = blockcheck(fsp->fs_spec)) == NULL) { |
| 82 | fprintf(stderr, "BAD DISK NAME %s\n", |
| 83 | fsp->fs_spec); |
| 84 | sumstatus |= 8; |
| 85 | continue; |
| 86 | } |
| 87 | addpart(name, fsp->fs_file, auxdata); |
| 88 | } |
| 89 | } |
| 90 | if (preen == 0) |
| 91 | return (0); |
| 92 | } |
| 93 | if (preen) { |
| 94 | if (maxrun == 0) |
| 95 | maxrun = ndisks; |
| 96 | if (maxrun > ndisks) |
| 97 | maxrun = ndisks; |
| 98 | nextdisk = disks; |
| 99 | for (passno = 0; passno < maxrun; ++passno) { |
| 100 | while (ret = startdisk(nextdisk, chkit) && nrun > 0) |
| 101 | sleep(10); |
| 102 | if (ret) |
| 103 | return (ret); |
| 104 | nextdisk = nextdisk->next; |
| 105 | } |
| 106 | while ((pid = wait(&status)) != -1) { |
| 107 | for (dk = disks; dk; dk = dk->next) |
| 108 | if (dk->pid == pid) |
| 109 | break; |
| 110 | if (dk == 0) { |
| 111 | printf("Unknown pid %d\n", pid); |
| 112 | continue; |
| 113 | } |
| 114 | if (WIFEXITED(status)) |
| 115 | retcode = WEXITSTATUS(status); |
| 116 | else |
| 117 | retcode = 0; |
| 118 | if (WIFSIGNALED(status)) { |
| 119 | printf("%s (%s): EXITED WITH SIGNAL %d\n", |
| 120 | dk->part->name, dk->part->fsname, |
| 121 | WTERMSIG(status)); |
| 122 | retcode = 8; |
| 123 | } |
| 124 | if (retcode != 0) { |
| 125 | sumstatus |= retcode; |
| 126 | *badnext = dk->part; |
| 127 | badnext = &dk->part->next; |
| 128 | dk->part = dk->part->next; |
| 129 | *badnext = NULL; |
| 130 | } else |
| 131 | dk->part = dk->part->next; |
| 132 | dk->pid = 0; |
| 133 | nrun--; |
| 134 | if (dk->part == NULL) |
| 135 | ndisks--; |
| 136 | |
| 137 | if (nextdisk == NULL) { |
| 138 | if (dk->part) { |
| 139 | while (ret = startdisk(dk, chkit) && |
| 140 | nrun > 0) |
| 141 | sleep(10); |
| 142 | if (ret) |
| 143 | return (ret); |
| 144 | } |
| 145 | } else if (nrun < maxrun && nrun < ndisks) { |
| 146 | for ( ;; ) { |
| 147 | if ((nextdisk = nextdisk->next) == NULL) |
| 148 | nextdisk = disks; |
| 149 | if (nextdisk->part != NULL && |
| 150 | nextdisk->pid == 0) |
| 151 | break; |
| 152 | } |
| 153 | while (ret = startdisk(nextdisk, chkit) && |
| 154 | nrun > 0) |
| 155 | sleep(10); |
| 156 | if (ret) |
| 157 | return (ret); |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | if (sumstatus) { |
| 162 | if (badlist == 0) |
| 163 | return (sumstatus); |
| 164 | fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", |
| 165 | badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); |
| 166 | for (pt = badlist; pt; pt = pt->next) |
| 167 | fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname, |
| 168 | pt->next ? ", " : "\n"); |
| 169 | return (sumstatus); |
| 170 | } |
| 171 | (void)endfsent(); |
| 172 | return (0); |
| 173 | } |
| 174 | |
| 175 | struct disk * |
| 176 | finddisk(name) |
| 177 | char *name; |
| 178 | { |
| 179 | register struct disk *dk, **dkp; |
| 180 | register char *p; |
| 181 | size_t len; |
| 182 | |
| 183 | for (p = name + strlen(name) - 1; p >= name; --p) |
| 184 | if (isdigit(*p)) { |
| 185 | len = p - name + 1; |
| 186 | break; |
| 187 | } |
| 188 | if (p < name) |
| 189 | len = strlen(name); |
| 190 | |
| 191 | for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) { |
| 192 | if (strncmp(dk->name, name, len) == 0 && |
| 193 | dk->name[len] == 0) |
| 194 | return (dk); |
| 195 | } |
| 196 | if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) { |
| 197 | fprintf(stderr, "out of memory"); |
| 198 | exit (8); |
| 199 | } |
| 200 | dk = *dkp; |
| 201 | if ((dk->name = malloc(len + 1)) == NULL) { |
| 202 | fprintf(stderr, "out of memory"); |
| 203 | exit (8); |
| 204 | } |
| 205 | (void)strncpy(dk->name, name, len); |
| 206 | dk->name[len] = '\0'; |
| 207 | dk->part = NULL; |
| 208 | dk->next = NULL; |
| 209 | dk->pid = 0; |
| 210 | ndisks++; |
| 211 | return (dk); |
| 212 | } |
| 213 | |
| 214 | addpart(name, fsname, auxdata) |
| 215 | char *name, *fsname; |
| 216 | long auxdata; |
| 217 | { |
| 218 | struct disk *dk = finddisk(name); |
| 219 | register struct part *pt, **ppt = &dk->part; |
| 220 | |
| 221 | for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next) |
| 222 | if (strcmp(pt->name, name) == 0) { |
| 223 | printf("%s in fstab more than once!\n", name); |
| 224 | return; |
| 225 | } |
| 226 | if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) { |
| 227 | fprintf(stderr, "out of memory"); |
| 228 | exit (8); |
| 229 | } |
| 230 | pt = *ppt; |
| 231 | if ((pt->name = malloc(strlen(name) + 1)) == NULL) { |
| 232 | fprintf(stderr, "out of memory"); |
| 233 | exit (8); |
| 234 | } |
| 235 | (void)strcpy(pt->name, name); |
| 236 | if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) { |
| 237 | fprintf(stderr, "out of memory"); |
| 238 | exit (8); |
| 239 | } |
| 240 | (void)strcpy(pt->fsname, fsname); |
| 241 | pt->next = NULL; |
| 242 | pt->auxdata = auxdata; |
| 243 | } |
| 244 | |
| 245 | startdisk(dk, checkit) |
| 246 | register struct disk *dk; |
| 247 | int (*checkit)(); |
| 248 | { |
| 249 | register struct part *pt = dk->part; |
| 250 | |
| 251 | dk->pid = fork(); |
| 252 | if (dk->pid < 0) { |
| 253 | perror("fork"); |
| 254 | return (8); |
| 255 | } |
| 256 | if (dk->pid == 0) |
| 257 | exit((*checkit)(pt->name, pt->fsname, pt->auxdata)); |
| 258 | nrun++; |
| 259 | return (0); |
| 260 | } |
| 261 | |
| 262 | char * |
| 263 | blockcheck(name) |
| 264 | char *name; |
| 265 | { |
| 266 | struct stat stslash, stblock, stchar; |
| 267 | char *raw; |
| 268 | int retried = 0; |
| 269 | |
| 270 | hotroot = 0; |
| 271 | if (stat("/", &stslash) < 0) { |
| 272 | perror("/"); |
| 273 | printf("Can't stat root\n"); |
| 274 | return (0); |
| 275 | } |
| 276 | retry: |
| 277 | if (stat(name, &stblock) < 0) { |
| 278 | perror(name); |
| 279 | printf("Can't stat %s\n", name); |
| 280 | return (0); |
| 281 | } |
| 282 | if ((stblock.st_mode & S_IFMT) == S_IFBLK) { |
| 283 | if (stslash.st_dev == stblock.st_rdev) |
| 284 | hotroot++; |
| 285 | raw = rawname(name); |
| 286 | if (stat(raw, &stchar) < 0) { |
| 287 | perror(raw); |
| 288 | printf("Can't stat %s\n", raw); |
| 289 | return (name); |
| 290 | } |
| 291 | if ((stchar.st_mode & S_IFMT) == S_IFCHR) { |
| 292 | return (raw); |
| 293 | } else { |
| 294 | printf("%s is not a character device\n", raw); |
| 295 | return (name); |
| 296 | } |
| 297 | } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { |
| 298 | name = unrawname(name); |
| 299 | retried++; |
| 300 | goto retry; |
| 301 | } |
| 302 | printf("Can't make sense out of name %s\n", name); |
| 303 | return (0); |
| 304 | } |
| 305 | |
| 306 | char * |
| 307 | unrawname(name) |
| 308 | char *name; |
| 309 | { |
| 310 | char *dp; |
| 311 | struct stat stb; |
| 312 | |
| 313 | if ((dp = rindex(name, '/')) == 0) |
| 314 | return (name); |
| 315 | if (stat(name, &stb) < 0) |
| 316 | return (name); |
| 317 | if ((stb.st_mode & S_IFMT) != S_IFCHR) |
| 318 | return (name); |
| 319 | if (*(dp + 1) != 'r') |
| 320 | return (name); |
| 321 | (void)strcpy(dp + 1, dp + 2); |
| 322 | return (name); |
| 323 | } |
| 324 | |
| 325 | char * |
| 326 | rawname(name) |
| 327 | char *name; |
| 328 | { |
| 329 | static char rawbuf[32]; |
| 330 | char *dp; |
| 331 | |
| 332 | if ((dp = rindex(name, '/')) == 0) |
| 333 | return (0); |
| 334 | *dp = 0; |
| 335 | (void)strcpy(rawbuf, name); |
| 336 | *dp = '/'; |
| 337 | (void)strcat(rawbuf, "/r"); |
| 338 | (void)strcat(rawbuf, dp + 1); |
| 339 | return (rawbuf); |
| 340 | } |