141098Smckusick /* 241098Smckusick * Copyright (c) 1990 The Regents of the University of California. 341098Smckusick * All rights reserved. 441098Smckusick * 541098Smckusick * Redistribution and use in source and binary forms are permitted 641098Smckusick * provided that the above copyright notice and this paragraph are 741098Smckusick * duplicated in all such forms and that any documentation, 841098Smckusick * advertising materials, and other materials related to such 941098Smckusick * distribution and use acknowledge that the software was developed 1041098Smckusick * by the University of California, Berkeley. The name of the 1141098Smckusick * University may not be used to endorse or promote products derived 1241098Smckusick * from this software without specific prior written permission. 1341098Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1441098Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1541098Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1641098Smckusick */ 1741098Smckusick 1841098Smckusick #ifndef lint 19*42041Sbostic static char sccsid[] = "@(#)preen.c 5.3 (Berkeley) 05/15/90"; 2041098Smckusick #endif /* not lint */ 2141098Smckusick 2241098Smckusick #include <sys/param.h> 2341098Smckusick #include <sys/stat.h> 2441098Smckusick #include <sys/wait.h> 2541098Smckusick #include <fstab.h> 26*42041Sbostic #include <string.h> 2741098Smckusick #include <stdio.h> 2841098Smckusick #include <ctype.h> 2941098Smckusick 3041098Smckusick char *rawname(), *unrawname(), *blockcheck(), *malloc(); 3141098Smckusick 3241098Smckusick struct part { 3341098Smckusick struct part *next; /* forward link of partitions on disk */ 3441098Smckusick char *name; /* device name */ 3541098Smckusick char *fsname; /* mounted filesystem name */ 3641098Smckusick long auxdata; /* auxillary data for application */ 3741098Smckusick } *badlist, **badnext = &badlist; 3841098Smckusick 3941098Smckusick struct disk { 4041098Smckusick char *name; /* disk base name */ 4141098Smckusick struct disk *next; /* forward link for list of disks */ 4241098Smckusick struct part *part; /* head of list of partitions on disk */ 4341098Smckusick int pid; /* If != 0, pid of proc working on */ 4441098Smckusick } *disks; 4541098Smckusick 4641416Smckusick int nrun, ndisks; 4741416Smckusick char hotroot; 4841098Smckusick 4941098Smckusick checkfstab(preen, maxrun, docheck, chkit) 5041098Smckusick int preen, maxrun; 5141098Smckusick int (*docheck)(), (*chkit)(); 5241098Smckusick { 5341098Smckusick register struct fstab *fsp; 5441098Smckusick register struct disk *dk, *nextdisk; 5541098Smckusick register struct part *pt; 5641098Smckusick int ret, pid, retcode, passno, sumstatus, status; 5741098Smckusick long auxdata; 5841098Smckusick char *name; 5941098Smckusick 6041098Smckusick sumstatus = 0; 6141098Smckusick for (passno = 1; passno <= 2; passno++) { 6241098Smckusick if (setfsent() == 0) { 6341098Smckusick fprintf(stderr, "Can't open checklist file: %s\n", 6441098Smckusick _PATH_FSTAB); 6541098Smckusick return (8); 6641098Smckusick } 6741098Smckusick while ((fsp = getfsent()) != 0) { 6841098Smckusick if ((auxdata = (*docheck)(fsp)) == 0) 6941098Smckusick continue; 7041098Smckusick if (preen == 0 || passno == 1 && fsp->fs_passno == 1) { 7141098Smckusick if (name = blockcheck(fsp->fs_spec)) { 7241098Smckusick if (sumstatus = (*chkit)(name, 7341098Smckusick fsp->fs_file, auxdata)) 7441098Smckusick return (sumstatus); 7541098Smckusick } else if (preen) 7641098Smckusick return (8); 7741098Smckusick } else if (passno == 2 && fsp->fs_passno > 1) { 7841098Smckusick if ((name = blockcheck(fsp->fs_spec)) == NULL) { 7941098Smckusick fprintf(stderr, "BAD DISK NAME %s\n", 8041098Smckusick fsp->fs_spec); 8141098Smckusick sumstatus |= 8; 8241098Smckusick continue; 8341098Smckusick } 8441098Smckusick addpart(name, fsp->fs_file, auxdata); 8541098Smckusick } 8641098Smckusick } 8741098Smckusick if (preen == 0) 8841098Smckusick return (0); 8941098Smckusick } 9041098Smckusick if (preen) { 9141098Smckusick if (maxrun == 0) 9241098Smckusick maxrun = ndisks; 9341098Smckusick if (maxrun > ndisks) 9441098Smckusick maxrun = ndisks; 9541098Smckusick nextdisk = disks; 9641098Smckusick for (passno = 0; passno < maxrun; ++passno) { 9741098Smckusick while (ret = startdisk(nextdisk, chkit) && nrun > 0) 9841098Smckusick sleep(10); 9941098Smckusick if (ret) 10041098Smckusick return (ret); 10141098Smckusick nextdisk = nextdisk->next; 10241098Smckusick } 10341098Smckusick while ((pid = wait(&status)) != -1) { 10441098Smckusick for (dk = disks; dk; dk = dk->next) 10541098Smckusick if (dk->pid == pid) 10641098Smckusick break; 10741098Smckusick if (dk == 0) { 10841098Smckusick printf("Unknown pid %d\n", pid); 10941098Smckusick continue; 11041098Smckusick } 11141098Smckusick if (WIFEXITED(status)) 11241098Smckusick retcode = WEXITSTATUS(status); 11341098Smckusick else 11441098Smckusick retcode = 0; 11541098Smckusick if (WIFSIGNALED(status)) { 11641098Smckusick printf("%s (%s): EXITED WITH SIGNAL %d\n", 11741098Smckusick dk->part->name, dk->part->fsname, 11841098Smckusick WTERMSIG(status)); 11941098Smckusick retcode = 8; 12041098Smckusick } 12141098Smckusick if (retcode != 0) { 12241098Smckusick sumstatus |= retcode; 12341098Smckusick *badnext = dk->part; 12441098Smckusick badnext = &dk->part->next; 12541098Smckusick dk->part = dk->part->next; 12641098Smckusick *badnext = NULL; 12741098Smckusick } else 12841098Smckusick dk->part = dk->part->next; 12941098Smckusick dk->pid = 0; 13041098Smckusick nrun--; 13141098Smckusick if (dk->part == NULL) 13241098Smckusick ndisks--; 13341098Smckusick 13441098Smckusick if (nextdisk == NULL) { 13541098Smckusick if (dk->part) { 13641098Smckusick while (ret = startdisk(dk, chkit) && 13741098Smckusick nrun > 0) 13841098Smckusick sleep(10); 13941098Smckusick if (ret) 14041098Smckusick return (ret); 14141098Smckusick } 14241098Smckusick } else if (nrun < maxrun && nrun < ndisks) { 14341098Smckusick for ( ;; ) { 14441098Smckusick if ((nextdisk = nextdisk->next) == NULL) 14541098Smckusick nextdisk = disks; 14641098Smckusick if (nextdisk->part != NULL && 14741098Smckusick nextdisk->pid == 0) 14841098Smckusick break; 14941098Smckusick } 15041098Smckusick while (ret = startdisk(nextdisk, chkit) && 15141098Smckusick nrun > 0) 15241098Smckusick sleep(10); 15341098Smckusick if (ret) 15441098Smckusick return (ret); 15541098Smckusick } 15641098Smckusick } 15741098Smckusick } 15841098Smckusick if (sumstatus) { 15941098Smckusick if (badlist == 0) 16041098Smckusick return (sumstatus); 16141098Smckusick fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 16241098Smckusick badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); 16341098Smckusick for (pt = badlist; pt; pt = pt->next) 16441098Smckusick fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname, 16541098Smckusick pt->next ? ", " : "\n"); 16641098Smckusick return (sumstatus); 16741098Smckusick } 16841098Smckusick (void)endfsent(); 16941098Smckusick return (0); 17041098Smckusick } 17141098Smckusick 17241098Smckusick struct disk * 17341098Smckusick finddisk(name) 17441098Smckusick char *name; 17541098Smckusick { 17641098Smckusick register struct disk *dk, **dkp; 17741098Smckusick register char *p; 17841098Smckusick int len; 17941098Smckusick 18041098Smckusick for (p = name + strlen(name) - 1; p >= name; --p) 18141098Smckusick if (isdigit(*p)) { 18241098Smckusick len = p - name + 1; 18341098Smckusick break; 18441098Smckusick } 18541098Smckusick if (p < name) 18641098Smckusick len = strlen(name); 18741098Smckusick 18841098Smckusick for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) { 18941098Smckusick if (strncmp(dk->name, name, len) == 0 && 19041098Smckusick dk->name[len] == 0) 19141098Smckusick return (dk); 19241098Smckusick } 19341098Smckusick if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) { 19441098Smckusick fprintf(stderr, "out of memory"); 19541098Smckusick exit (8); 19641098Smckusick } 19741098Smckusick dk = *dkp; 19841098Smckusick if ((dk->name = malloc((unsigned int)len + 1)) == NULL) { 19941098Smckusick fprintf(stderr, "out of memory"); 20041098Smckusick exit (8); 20141098Smckusick } 20241098Smckusick strncpy(dk->name, name, len); 20341098Smckusick dk->name[len] = '\0'; 20441098Smckusick dk->part = NULL; 20541098Smckusick dk->next = NULL; 20641098Smckusick dk->pid = 0; 20741098Smckusick ndisks++; 20841098Smckusick return (dk); 20941098Smckusick } 21041098Smckusick 21141098Smckusick addpart(name, fsname, auxdata) 21241098Smckusick char *name, *fsname; 21341098Smckusick long auxdata; 21441098Smckusick { 21541098Smckusick struct disk *dk = finddisk(name); 21641098Smckusick register struct part *pt, **ppt = &dk->part; 21741098Smckusick 21841098Smckusick for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next) 21941098Smckusick if (strcmp(pt->name, name) == 0) { 22041098Smckusick printf("%s in fstab more than once!\n", name); 22141098Smckusick return; 22241098Smckusick } 22341098Smckusick if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) { 22441098Smckusick fprintf(stderr, "out of memory"); 22541098Smckusick exit (8); 22641098Smckusick } 22741098Smckusick pt = *ppt; 22841098Smckusick if ((pt->name = malloc((unsigned int)strlen(name) + 1)) == NULL) { 22941098Smckusick fprintf(stderr, "out of memory"); 23041098Smckusick exit (8); 23141098Smckusick } 23241098Smckusick strcpy(pt->name, name); 23341098Smckusick if ((pt->fsname = malloc((unsigned int)strlen(fsname) + 1)) == NULL) { 23441098Smckusick fprintf(stderr, "out of memory"); 23541098Smckusick exit (8); 23641098Smckusick } 23741098Smckusick strcpy(pt->fsname, fsname); 23841098Smckusick pt->next = NULL; 23941098Smckusick pt->auxdata = auxdata; 24041098Smckusick } 24141098Smckusick 24241098Smckusick startdisk(dk, checkit) 24341098Smckusick register struct disk *dk; 24441098Smckusick int (*checkit)(); 24541098Smckusick { 24641098Smckusick register struct part *pt = dk->part; 24741098Smckusick 24841098Smckusick dk->pid = fork(); 24941098Smckusick if (dk->pid < 0) { 25041098Smckusick perror("fork"); 25141098Smckusick return (8); 25241098Smckusick } 25341098Smckusick if (dk->pid == 0) 25441098Smckusick exit((*checkit)(pt->name, pt->fsname, pt->auxdata)); 25541098Smckusick nrun++; 25641098Smckusick return (0); 25741098Smckusick } 25841098Smckusick 25941098Smckusick char * 26041098Smckusick blockcheck(name) 26141098Smckusick char *name; 26241098Smckusick { 26341098Smckusick struct stat stslash, stblock, stchar; 26441098Smckusick char *raw; 26541098Smckusick int retried = 0; 26641098Smckusick 26741098Smckusick hotroot = 0; 26841098Smckusick if (stat("/", &stslash) < 0) { 26941098Smckusick perror("/"); 27041098Smckusick printf("Can't stat root\n"); 27141098Smckusick return (0); 27241098Smckusick } 27341098Smckusick retry: 27441098Smckusick if (stat(name, &stblock) < 0) { 27541098Smckusick perror(name); 27641098Smckusick printf("Can't stat %s\n", name); 27741098Smckusick return (0); 27841098Smckusick } 27941098Smckusick if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 28041098Smckusick if (stslash.st_dev == stblock.st_rdev) 28141098Smckusick hotroot++; 28241098Smckusick raw = rawname(name); 28341098Smckusick if (stat(raw, &stchar) < 0) { 28441098Smckusick perror(raw); 28541098Smckusick printf("Can't stat %s\n", raw); 28641098Smckusick return (name); 28741098Smckusick } 28841098Smckusick if ((stchar.st_mode & S_IFMT) == S_IFCHR) { 28941098Smckusick return (raw); 29041098Smckusick } else { 29141098Smckusick printf("%s is not a character device\n", raw); 29241098Smckusick return (name); 29341098Smckusick } 29441098Smckusick } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { 29541098Smckusick name = unrawname(name); 29641098Smckusick retried++; 29741098Smckusick goto retry; 29841098Smckusick } 29941098Smckusick printf("Can't make sense out of name %s\n", name); 30041098Smckusick return (0); 30141098Smckusick } 30241098Smckusick 30341098Smckusick char * 30441098Smckusick unrawname(name) 30541098Smckusick char *name; 30641098Smckusick { 30741098Smckusick char *dp; 30841098Smckusick struct stat stb; 30941098Smckusick 31041098Smckusick if ((dp = rindex(name, '/')) == 0) 31141098Smckusick return (name); 31241098Smckusick if (stat(name, &stb) < 0) 31341098Smckusick return (name); 31441098Smckusick if ((stb.st_mode & S_IFMT) != S_IFCHR) 31541098Smckusick return (name); 31641098Smckusick if (*(dp + 1) != 'r') 31741098Smckusick return (name); 31841098Smckusick (void)strcpy(dp + 1, dp + 2); 31941098Smckusick return (name); 32041098Smckusick } 32141098Smckusick 32241098Smckusick char * 32341098Smckusick rawname(name) 32441098Smckusick char *name; 32541098Smckusick { 32641098Smckusick static char rawbuf[32]; 32741098Smckusick char *dp; 32841098Smckusick 32941098Smckusick if ((dp = rindex(name, '/')) == 0) 33041098Smckusick return (0); 33141098Smckusick *dp = 0; 33241098Smckusick (void)strcpy(rawbuf, name); 33341098Smckusick *dp = '/'; 33441098Smckusick (void)strcat(rawbuf, "/r"); 33541098Smckusick (void)strcat(rawbuf, dp + 1); 33641098Smckusick return (rawbuf); 33741098Smckusick } 338