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