1 /* $NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 1990, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. 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 #include <sys/cdefs.h> 35 #ifndef lint 36 #if 0 37 static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95"; 38 #else 39 __RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $"); 40 #endif 41 #endif /* not lint */ 42 43 #include <sys/param.h> 44 #include <sys/stat.h> 45 #include <sys/wait.h> 46 #include <sys/queue.h> 47 48 #include <err.h> 49 #include <ctype.h> 50 #include <fstab.h> 51 #include <string.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <unistd.h> 55 56 #include "fsutil.h" 57 58 struct partentry { 59 TAILQ_ENTRY(partentry) p_entries; 60 char *p_devname; /* device name */ 61 char *p_mntpt; /* mount point */ 62 char *p_type; /* file system type */ 63 int p_failok; /* failok option set */ 64 }; 65 66 static TAILQ_HEAD(part, partentry) badh; 67 68 struct diskentry { 69 TAILQ_ENTRY(diskentry) d_entries; 70 char *d_name; /* disk base name */ 71 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 72 int d_pid; /* 0 or pid of fsck proc */ 73 }; 74 75 static TAILQ_HEAD(disk, diskentry) diskh; 76 77 static int nrun = 0, ndisks = 0; 78 79 static struct diskentry *finddisk(const char *); 80 static void addpart(const char *, const char *, const char *, const int); 81 static int startdisk(struct diskentry *, 82 int (*)(const char *, const char *, const char *, const char *, pid_t *)); 83 static void printpart(void); 84 85 int 86 checkfstab(int flags, int (*docheck)(struct fstab *), 87 int (*checkit)(const char *, const char *, const char *, const char *, pid_t *)) 88 { 89 struct fstab *fs; 90 struct diskentry *d, *nextdisk; 91 struct partentry *p; 92 int ret, pid, retcode, passno, sumstatus, status, nextpass; 93 const char *name; 94 95 TAILQ_INIT(&badh); 96 TAILQ_INIT(&diskh); 97 98 sumstatus = 0; 99 100 nextpass = 0; 101 for (passno = 1; nextpass != INT_MAX; passno = nextpass) { 102 if (flags & CHECK_DEBUG) 103 printf("pass %d\n", passno); 104 105 nextpass = INT_MAX; 106 if (setfsent() == 0) { 107 warnx("Can't open checklist file: %s\n", _PATH_FSTAB); 108 return (8); 109 } 110 while ((fs = getfsent()) != NULL) { 111 name = fs->fs_spec; 112 if (fs->fs_passno > passno && fs->fs_passno < nextpass) 113 nextpass = fs->fs_passno; 114 115 if (passno != fs->fs_passno) 116 continue; 117 118 if ((*docheck)(fs) == 0) 119 continue; 120 121 if (flags & CHECK_DEBUG) 122 printf("pass %d, name %s\n", passno, name); 123 124 if ((flags & CHECK_PREEN) == 0 || passno == 1 || 125 (flags & DO_BACKGRD) != 0) { 126 if (name == NULL) { 127 if (flags & CHECK_PREEN) 128 return 8; 129 else 130 continue; 131 } 132 sumstatus = (*checkit)(fs->fs_vfstype, 133 name, fs->fs_file, NULL, NULL); 134 if (sumstatus) 135 return (sumstatus); 136 continue; 137 } 138 if (name == NULL) { 139 (void) fprintf(stderr, 140 "BAD DISK NAME %s\n", fs->fs_spec); 141 sumstatus |= 8; 142 continue; 143 } 144 addpart(fs->fs_vfstype, name, fs->fs_file, 145 getfsopt(fs, "failok")); 146 } 147 148 if ((flags & CHECK_PREEN) == 0 || passno == 1 || 149 (flags & DO_BACKGRD) != 0) 150 continue; 151 152 if (flags & CHECK_DEBUG) { 153 printf("Parallel start\n"); 154 printpart(); 155 } 156 157 TAILQ_FOREACH(nextdisk, &diskh, d_entries) { 158 if ((ret = startdisk(nextdisk, checkit)) != 0) 159 return ret; 160 } 161 162 if (flags & CHECK_DEBUG) 163 printf("Parallel wait\n"); 164 while ((pid = wait(&status)) != -1) { 165 TAILQ_FOREACH(d, &diskh, d_entries) 166 if (d->d_pid == pid) 167 break; 168 169 if (d == NULL) { 170 warnx("Unknown pid %d\n", pid); 171 continue; 172 } 173 174 p = TAILQ_FIRST(&d->d_part); 175 176 if (WIFEXITED(status) == 0) { 177 retcode = 0; 178 } else if (p->p_failok == 0) { 179 retcode = WEXITSTATUS(status); 180 } else { 181 retcode = 0; 182 fprintf(stderr, "%s: failok SPECIFIED, FSCK " 183 "ERROR(S) IGNORED\n", p->p_devname); 184 } 185 186 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) 187 (void) printf("done %s: %s (%s) = 0x%x\n", 188 p->p_type, p->p_devname, p->p_mntpt, 189 status); 190 191 if (WIFSIGNALED(status)) { 192 (void) fprintf(stderr, 193 "%s: %s (%s): EXITED WITH SIGNAL %d\n", 194 p->p_type, p->p_devname, p->p_mntpt, 195 WTERMSIG(status)); 196 retcode = 8; 197 } 198 199 TAILQ_REMOVE(&d->d_part, p, p_entries); 200 201 if (retcode != 0) { 202 TAILQ_INSERT_TAIL(&badh, p, p_entries); 203 sumstatus |= retcode; 204 } else { 205 free(p->p_type); 206 free(p->p_devname); 207 free(p); 208 } 209 d->d_pid = 0; 210 nrun--; 211 212 if (TAILQ_EMPTY(&d->d_part)) { 213 TAILQ_REMOVE(&diskh, d, d_entries); 214 ndisks--; 215 } else { 216 if ((ret = startdisk(d, checkit)) != 0) 217 return ret; 218 } 219 } 220 if (flags & CHECK_DEBUG) { 221 printf("Parallel end\n"); 222 printpart(); 223 } 224 } 225 226 if (!(flags & CHECK_PREEN)) 227 return 0; 228 229 if (sumstatus) { 230 p = TAILQ_FIRST(&badh); 231 if (p == NULL) 232 return (sumstatus); 233 234 (void) fprintf(stderr, 235 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 236 TAILQ_NEXT(p, p_entries) ? "S" : "", 237 "UNEXPECTED INCONSISTENCY:"); 238 239 for (; p; p = TAILQ_NEXT(p, p_entries)) 240 (void) fprintf(stderr, 241 "%s: %s (%s)%s", p->p_type, p->p_devname, 242 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 243 244 return sumstatus; 245 } 246 (void) endfsent(); 247 return (0); 248 } 249 250 static struct diskentry * 251 finddisk(const char *name) 252 { 253 const char *p; 254 size_t len = 0; 255 struct diskentry *d; 256 257 p = strrchr(name, '/'); 258 if (p == NULL) 259 p = name; 260 else 261 p++; 262 for (; *p && !isdigit(*p); p++) 263 continue; 264 for (; *p && isdigit(*p); p++) 265 continue; 266 len = p - name; 267 if (len == 0) 268 len = strlen(name); 269 270 TAILQ_FOREACH(d, &diskh, d_entries) 271 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 272 return d; 273 274 d = emalloc(sizeof(*d)); 275 d->d_name = estrdup(name); 276 d->d_name[len] = '\0'; 277 TAILQ_INIT(&d->d_part); 278 d->d_pid = 0; 279 280 TAILQ_INSERT_TAIL(&diskh, d, d_entries); 281 ndisks++; 282 283 return d; 284 } 285 286 287 static void 288 printpart(void) 289 { 290 struct diskentry *d; 291 struct partentry *p; 292 293 TAILQ_FOREACH(d, &diskh, d_entries) { 294 (void) printf("disk %s: ", d->d_name); 295 TAILQ_FOREACH(p, &d->d_part, p_entries) 296 (void) printf("%s ", p->p_devname); 297 (void) printf("\n"); 298 } 299 } 300 301 302 static void 303 addpart(const char *type, const char *dev, const char *mntpt, const int failok) 304 { 305 struct diskentry *d = finddisk(dev); 306 struct partentry *p; 307 308 TAILQ_FOREACH(p, &d->d_part, p_entries) 309 if (strcmp(p->p_devname, dev) == 0) { 310 warnx("%s in fstab more than once!\n", dev); 311 return; 312 } 313 314 p = emalloc(sizeof(*p)); 315 p->p_devname = estrdup(dev); 316 p->p_mntpt = estrdup(mntpt); 317 p->p_type = estrdup(type); 318 p->p_failok = failok; 319 320 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 321 } 322 323 324 static int 325 startdisk(struct diskentry *d, int (*checkit)(const char *, const char *, 326 const char *, const char *, pid_t *)) 327 { 328 struct partentry *p = TAILQ_FIRST(&d->d_part); 329 int rv; 330 331 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt, 332 NULL, &d->d_pid)) != 0 && nrun > 0) 333 sleep(10); 334 335 if (rv == 0) 336 nrun++; 337 338 return rv; 339 } 340