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