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