1 /* $NetBSD: preen.c,v 1.23 2001/11/01 07:31:23 lukem 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95"; 40 #else 41 __RCSID("$NetBSD: preen.c,v 1.23 2001/11/01 07:31:23 lukem Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/wait.h> 48 #include <sys/queue.h> 49 50 #include <err.h> 51 #include <ctype.h> 52 #include <fstab.h> 53 #include <string.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <unistd.h> 57 58 #include "fsutil.h" 59 60 struct partentry { 61 TAILQ_ENTRY(partentry) p_entries; 62 char *p_devname; /* device name */ 63 char *p_mntpt; /* mount point */ 64 char *p_type; /* file system type */ 65 void *p_auxarg; /* auxiliary argument */ 66 }; 67 68 TAILQ_HEAD(part, partentry) badh; 69 70 struct diskentry { 71 TAILQ_ENTRY(diskentry) d_entries; 72 char *d_name; /* disk base name */ 73 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 74 int d_pid; /* 0 or pid of fsck proc */ 75 }; 76 77 TAILQ_HEAD(disk, diskentry) diskh; 78 79 static int nrun = 0, ndisks = 0; 80 81 static struct diskentry *finddisk(const char *); 82 static void addpart(const char *, const char *, const char *, void *); 83 static int startdisk(struct diskentry *, 84 int (*)(const char *, const char *, const char *, void *, pid_t *)); 85 static void printpart(void); 86 87 int 88 checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *), 89 int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 90 { 91 struct fstab *fs; 92 struct diskentry *d, *nextdisk; 93 struct partentry *p; 94 int ret, pid, retcode, passno, sumstatus, status; 95 void *auxarg; 96 const char *name; 97 98 TAILQ_INIT(&badh); 99 TAILQ_INIT(&diskh); 100 101 sumstatus = 0; 102 103 for (passno = 1; passno <= 2; passno++) { 104 if (setfsent() == 0) { 105 warnx("Can't open checklist file: %s\n", _PATH_FSTAB); 106 return (8); 107 } 108 while ((fs = getfsent()) != 0) { 109 if ((auxarg = (*docheck)(fs)) == NULL) 110 continue; 111 112 name = blockcheck(fs->fs_spec); 113 if (flags & CHECK_DEBUG) 114 printf("pass %d, name %s\n", passno, name); 115 116 if ((flags & CHECK_PREEN) == 0 || 117 (passno == 1 && fs->fs_passno == 1)) { 118 if (name == NULL) { 119 if (flags & CHECK_PREEN) 120 return 8; 121 else 122 continue; 123 } 124 sumstatus = (*checkit)(fs->fs_vfstype, 125 name, fs->fs_file, auxarg, NULL); 126 127 if (sumstatus) 128 return (sumstatus); 129 } else if (passno == 2 && fs->fs_passno > 1) { 130 if (name == NULL) { 131 (void) fprintf(stderr, 132 "BAD DISK NAME %s\n", fs->fs_spec); 133 sumstatus |= 8; 134 continue; 135 } 136 addpart(fs->fs_vfstype, name, fs->fs_file, 137 auxarg); 138 } 139 } 140 if ((flags & CHECK_PREEN) == 0) 141 return 0; 142 } 143 144 if (flags & CHECK_DEBUG) 145 printpart(); 146 147 if (flags & CHECK_PREEN) { 148 if (maxrun == 0) 149 maxrun = ndisks; 150 if (maxrun > ndisks) 151 maxrun = ndisks; 152 nextdisk = TAILQ_FIRST(&diskh); 153 for (passno = 0; passno < maxrun; ++passno) { 154 if ((ret = startdisk(nextdisk, checkit)) != 0) 155 return ret; 156 nextdisk = TAILQ_NEXT(nextdisk, d_entries); 157 } 158 159 while ((pid = wait(&status)) != -1) { 160 TAILQ_FOREACH(d, &diskh, d_entries) 161 if (d->d_pid == pid) 162 break; 163 164 if (d == NULL) { 165 warnx("Unknown pid %d\n", pid); 166 continue; 167 } 168 169 170 if (WIFEXITED(status)) 171 retcode = WEXITSTATUS(status); 172 else 173 retcode = 0; 174 175 p = TAILQ_FIRST(&d->d_part); 176 177 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) 178 (void) printf("done %s: %s (%s) = 0x%x\n", 179 p->p_type, p->p_devname, p->p_mntpt, 180 status); 181 182 if (WIFSIGNALED(status)) { 183 (void) fprintf(stderr, 184 "%s: %s (%s): EXITED WITH SIGNAL %d\n", 185 p->p_type, p->p_devname, p->p_mntpt, 186 WTERMSIG(status)); 187 retcode = 8; 188 } 189 190 TAILQ_REMOVE(&d->d_part, p, p_entries); 191 192 if (retcode != 0) { 193 TAILQ_INSERT_TAIL(&badh, p, p_entries); 194 sumstatus |= retcode; 195 } else { 196 free(p->p_type); 197 free(p->p_devname); 198 free(p); 199 } 200 d->d_pid = 0; 201 nrun--; 202 203 if (TAILQ_FIRST(&d->d_part) == NULL) 204 ndisks--; 205 206 if (nextdisk == NULL) { 207 if (TAILQ_FIRST(&d->d_part) != NULL) { 208 if ((ret = startdisk(d, checkit)) != 0) 209 return ret; 210 } 211 } else if (nrun < maxrun && nrun < ndisks) { 212 for ( ;; ) { 213 nextdisk = TAILQ_NEXT(nextdisk, 214 d_entries); 215 if (nextdisk == NULL) 216 nextdisk = TAILQ_FIRST(&diskh); 217 if (TAILQ_FIRST(&nextdisk->d_part) 218 != NULL && nextdisk->d_pid == 0) 219 break; 220 } 221 if ((ret = startdisk(nextdisk, checkit)) != 0) 222 return ret; 223 } 224 } 225 } 226 if (sumstatus) { 227 p = TAILQ_FIRST(&badh); 228 if (p == NULL) 229 return (sumstatus); 230 231 (void) fprintf(stderr, 232 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 233 TAILQ_NEXT(p, p_entries) ? "S" : "", 234 "UNEXPECTED INCONSISTENCY:"); 235 236 TAILQ_FOREACH(p, &badh, p_entries) 237 (void) fprintf(stderr, 238 "%s: %s (%s)%s", p->p_type, p->p_devname, 239 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 240 241 return sumstatus; 242 } 243 (void) endfsent(); 244 return (0); 245 } 246 247 248 static struct diskentry * 249 finddisk(const char *name) 250 { 251 const char *p; 252 size_t len = 0; 253 struct diskentry *d; 254 255 for (len = strlen(name), p = name + len - 1; p >= name; --p) 256 if (isdigit(*p)) { 257 len = p - name + 1; 258 break; 259 } 260 if (p < name) 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, void *auxarg) 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_auxarg = auxarg; 312 313 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 314 } 315 316 317 static int 318 startdisk(struct diskentry *d, 319 int (*checkit)(const char *, const char *, const char *, void *, 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 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0) 326 sleep(10); 327 328 if (rv == 0) 329 nrun++; 330 331 return rv; 332 } 333