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