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) 04/26/90"; 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 } 337