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