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