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