1 /* $OpenBSD: preen.c,v 1.16 2005/10/28 07:30:35 otto Exp $ */ 2 /* $NetBSD: preen.c,v 1.15 1996/09/28 19:21:42 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)preen.c 8.3 (Berkeley) 12/6/94"; 36 #else 37 static const char rcsid[] = "$OpenBSD: preen.c,v 1.16 2005/10/28 07:30:35 otto Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #include <sys/wait.h> 44 #include <sys/queue.h> 45 46 #include <fstab.h> 47 #include <string.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <ctype.h> 51 #include <unistd.h> 52 #include <err.h> 53 54 #include "fsutil.h" 55 56 struct partentry { 57 TAILQ_ENTRY(partentry) p_entries; 58 char *p_devname; /* device name */ 59 char *p_mntpt; /* mount point */ 60 char *p_type; /* filesystem type */ 61 void *p_auxarg; /* auxiliary argument */ 62 }; 63 64 TAILQ_HEAD(part, partentry) badh; 65 66 struct diskentry { 67 TAILQ_ENTRY(diskentry) d_entries; 68 char *d_name; /* disk base name */ 69 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 70 pid_t d_pid; /* 0 or pid of fsck proc */ 71 }; 72 73 TAILQ_HEAD(disk, diskentry) diskh; 74 75 static int nrun = 0, ndisks = 0; 76 77 static struct diskentry *finddisk(const char *); 78 static void addpart(const char *, const char *, const char *, void *); 79 static int startdisk(struct diskentry *, 80 int (*)(const char *, const char *, const char *, void *, pid_t *)); 81 static void printpart(void); 82 83 int 84 checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *), 85 int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 86 { 87 struct fstab *fs; 88 struct diskentry *d, *nextdisk; 89 struct partentry *p; 90 int ret, retcode, passno, sumstatus, status; 91 void *auxarg; 92 char *name; 93 pid_t pid; 94 95 TAILQ_INIT(&badh); 96 TAILQ_INIT(&diskh); 97 98 sumstatus = 0; 99 100 for (passno = 1; passno <= 2; passno++) { 101 if (setfsent() == 0) { 102 warnx("Can't open checklist file: %s", _PATH_FSTAB); 103 return (8); 104 } 105 while ((fs = getfsent()) != 0) { 106 if ((auxarg = (*docheck)(fs)) == NULL) 107 continue; 108 109 name = blockcheck(fs->fs_spec); 110 if (flags & CHECK_DEBUG) 111 printf("pass %d, name %s\n", passno, name); 112 113 if ((flags & CHECK_PREEN) == 0 || 114 (passno == 1 && fs->fs_passno == 1)) { 115 if (name == NULL) { 116 if (flags & CHECK_PREEN) 117 return 8; 118 else 119 continue; 120 } 121 sumstatus = (*checkit)(fs->fs_vfstype, 122 name, fs->fs_file, auxarg, NULL); 123 124 if (sumstatus) 125 return (sumstatus); 126 } else if (passno == 2 && fs->fs_passno > 1) { 127 if (name == NULL) { 128 (void) fprintf(stderr, 129 "BAD DISK NAME %s\n", fs->fs_spec); 130 sumstatus |= 8; 131 continue; 132 } 133 addpart(fs->fs_vfstype, name, fs->fs_file, 134 auxarg); 135 } 136 } 137 if ((flags & CHECK_PREEN) == 0) 138 return 0; 139 } 140 141 if (flags & CHECK_DEBUG) 142 printpart(); 143 144 if (flags & CHECK_PREEN) { 145 if (maxrun == 0) 146 maxrun = ndisks; 147 if (maxrun > ndisks) 148 maxrun = ndisks; 149 nextdisk = TAILQ_FIRST(&diskh); 150 for (passno = 0; passno < maxrun; ++passno) { 151 if ((ret = startdisk(nextdisk, checkit)) != 0) 152 return ret; 153 nextdisk = TAILQ_NEXT(nextdisk, d_entries); 154 } 155 156 while ((pid = wait(&status)) != -1) { 157 TAILQ_FOREACH(d, &diskh, d_entries) 158 if (d->d_pid == pid) 159 break; 160 161 if (d == NULL) { 162 warnx("Unknown pid %ld", (long)pid); 163 continue; 164 } 165 166 167 if (WIFEXITED(status)) 168 retcode = WEXITSTATUS(status); 169 else 170 retcode = 0; 171 172 p = TAILQ_FIRST(&d->d_part); 173 174 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) 175 (void) printf("done %s: %s (%s) = %x\n", 176 p->p_type, p->p_devname, p->p_mntpt, 177 status); 178 179 if (WIFSIGNALED(status)) { 180 (void) fprintf(stderr, 181 "%s: %s (%s): EXITED WITH SIGNAL %d\n", 182 p->p_type, p->p_devname, p->p_mntpt, 183 WTERMSIG(status)); 184 retcode = 8; 185 } 186 187 TAILQ_REMOVE(&d->d_part, p, p_entries); 188 189 if (retcode != 0) { 190 TAILQ_INSERT_TAIL(&badh, p, p_entries); 191 sumstatus |= retcode; 192 } else { 193 free(p->p_type); 194 free(p->p_devname); 195 free(p); 196 } 197 d->d_pid = 0; 198 nrun--; 199 200 if (TAILQ_EMPTY(&d->d_part)) 201 ndisks--; 202 203 if (nextdisk == NULL) { 204 if (!TAILQ_EMPTY(&d->d_part)) { 205 if ((ret = startdisk(d, checkit)) != 0) 206 return ret; 207 } 208 } else if (nrun < maxrun && nrun < ndisks) { 209 for ( ;; ) { 210 nextdisk = TAILQ_NEXT(nextdisk, 211 d_entries); 212 if (nextdisk == NULL) 213 nextdisk = TAILQ_FIRST(&diskh); 214 if (!TAILQ_EMPTY(&nextdisk->d_part) && 215 nextdisk->d_pid == 0) 216 break; 217 } 218 if ((ret = startdisk(nextdisk, checkit)) != 0) 219 return ret; 220 } 221 } 222 } 223 if (sumstatus) { 224 p = TAILQ_FIRST(&badh); 225 if (p == NULL) 226 return (sumstatus); 227 228 (void) fprintf(stderr, 229 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 230 TAILQ_NEXT(p, p_entries) ? "S" : "", 231 "UNEXPECTED INCONSISTENCY:"); 232 233 for (; p; p = TAILQ_NEXT(p, p_entries)) 234 (void) fprintf(stderr, 235 "%s: %s (%s)%s", p->p_type, p->p_devname, 236 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 237 238 return sumstatus; 239 } 240 (void) endfsent(); 241 return (0); 242 } 243 244 245 static struct diskentry * 246 finddisk(const char *name) 247 { 248 const char *p; 249 size_t len = 0; 250 struct diskentry *d; 251 252 for (p = name + strlen(name) - 1; p >= name; --p) 253 if (isdigit(*p)) { 254 len = p - name + 1; 255 break; 256 } 257 258 if (p < name) 259 len = strlen(name); 260 261 TAILQ_FOREACH(d, &diskh, d_entries) 262 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 263 return d; 264 265 d = emalloc(sizeof(*d)); 266 d->d_name = estrdup(name); 267 d->d_name[len] = '\0'; 268 TAILQ_INIT(&d->d_part); 269 d->d_pid = 0; 270 271 TAILQ_INSERT_TAIL(&diskh, d, d_entries); 272 ndisks++; 273 274 return d; 275 } 276 277 278 static void 279 printpart(void) 280 { 281 struct diskentry *d; 282 struct partentry *p; 283 284 TAILQ_FOREACH(d, &diskh, d_entries) { 285 (void) printf("disk %s: ", d->d_name); 286 TAILQ_FOREACH(p, &d->d_part, p_entries) 287 (void) printf("%s ", p->p_devname); 288 (void) printf("\n"); 289 } 290 } 291 292 293 static void 294 addpart(const char *type, const char *devname, const char *mntpt, void *auxarg) 295 { 296 struct diskentry *d = finddisk(devname); 297 struct partentry *p; 298 299 TAILQ_FOREACH(p, &d->d_part, p_entries) 300 if (strcmp(p->p_devname, devname) == 0) { 301 warnx("%s in fstab more than once!", devname); 302 return; 303 } 304 305 p = emalloc(sizeof(*p)); 306 p->p_devname = estrdup(devname); 307 p->p_mntpt = estrdup(mntpt); 308 p->p_type = estrdup(type); 309 p->p_auxarg = auxarg; 310 311 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 312 } 313 314 315 static int 316 startdisk(struct diskentry *d, 317 int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 318 { 319 struct partentry *p = TAILQ_FIRST(&d->d_part); 320 int rv; 321 322 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt, 323 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0) 324 sleep(10); 325 326 if (rv == 0) 327 nrun++; 328 329 return rv; 330 } 331