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