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