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