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