1 /* $NetBSD: preen.c,v 1.27 2005/01/13 22:56:09 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. 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.27 2005/01/13 22:56:09 christos 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 int error = 0; 94 95 TAILQ_INIT(&badh); 96 TAILQ_INIT(&diskh); 97 98 sumstatus = 0; 99 100 for (passno = 1; passno <= 2; passno++) { 101 if (setfsent() == 0) { 102 warnx("Can't open checklist file: %s", _PATH_FSTAB); 103 return (8); 104 } 105 while ((fs = getfsent()) != 0) { 106 if ((auxarg = (*docheck)(fs)) == NULL) 107 continue; 108 109 name = blockcheck(fs->fs_spec); 110 if (flags & CHECK_DEBUG) 111 printf("pass %d, name %s\n", passno, name); 112 113 if ((flags & CHECK_PREEN) == 0 || 114 (passno == 1 && fs->fs_passno == 1)) { 115 if (name == NULL) { 116 if (flags & CHECK_PREEN) 117 return 8; 118 else 119 continue; 120 } 121 sumstatus = (*checkit)(fs->fs_vfstype, 122 name, fs->fs_file, auxarg, NULL); 123 124 if (sumstatus) { 125 if ((flags & CHECK_NOFIX) == 0) 126 return (sumstatus); 127 else 128 error |= sumstatus; 129 } 130 } else if (passno == 2 && fs->fs_passno > 1) { 131 if (name == NULL) { 132 (void) fprintf(stderr, 133 "BAD DISK NAME %s\n", fs->fs_spec); 134 sumstatus |= 8; 135 continue; 136 } 137 addpart(fs->fs_vfstype, name, fs->fs_file, 138 auxarg); 139 } 140 } 141 if ((flags & CHECK_PREEN) == 0) 142 return error; 143 } 144 145 if (flags & CHECK_DEBUG) 146 printpart(); 147 148 if (flags & CHECK_PREEN) { 149 if (maxrun == 0) 150 maxrun = ndisks; 151 if (maxrun > ndisks) 152 maxrun = ndisks; 153 nextdisk = TAILQ_FIRST(&diskh); 154 for (passno = 0; passno < maxrun; ++passno) { 155 if ((ret = startdisk(nextdisk, checkit)) != 0) { 156 if ((flags & CHECK_NOFIX) == 0) 157 return ret; 158 else 159 error |= ret; 160 } 161 nextdisk = TAILQ_NEXT(nextdisk, d_entries); 162 } 163 164 while ((pid = wait(&status)) != -1) { 165 TAILQ_FOREACH(d, &diskh, d_entries) 166 if (d->d_pid == pid) 167 break; 168 169 if (d == NULL) { 170 warnx("Unknown pid %d", pid); 171 continue; 172 } 173 174 175 if (WIFEXITED(status)) 176 retcode = WEXITSTATUS(status); 177 else 178 retcode = 0; 179 180 p = TAILQ_FIRST(&d->d_part); 181 182 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) 183 (void) printf("done %s: %s (%s) = 0x%x\n", 184 p->p_type, p->p_devname, p->p_mntpt, 185 status); 186 187 if (WIFSIGNALED(status)) { 188 (void) fprintf(stderr, 189 "%s: %s (%s): EXITED WITH SIGNAL %d\n", 190 p->p_type, p->p_devname, p->p_mntpt, 191 WTERMSIG(status)); 192 retcode = 8; 193 } 194 195 TAILQ_REMOVE(&d->d_part, p, p_entries); 196 197 if (retcode != 0) { 198 TAILQ_INSERT_TAIL(&badh, p, p_entries); 199 sumstatus |= retcode; 200 } else { 201 free(p->p_type); 202 free(p->p_devname); 203 free(p); 204 } 205 d->d_pid = 0; 206 nrun--; 207 208 if (TAILQ_FIRST(&d->d_part) == NULL) 209 ndisks--; 210 211 if (nextdisk == NULL) { 212 if (TAILQ_FIRST(&d->d_part) != NULL) { 213 if ((ret = startdisk(d, checkit)) != 0) 214 { 215 if ((flags & CHECK_NOFIX) == 0) 216 return ret; 217 else 218 error |= ret; 219 } 220 } 221 } else if (nrun < maxrun && nrun < ndisks) { 222 for ( ;; ) { 223 nextdisk = TAILQ_NEXT(nextdisk, 224 d_entries); 225 if (nextdisk == NULL) 226 nextdisk = TAILQ_FIRST(&diskh); 227 if (TAILQ_FIRST(&nextdisk->d_part) 228 != NULL && nextdisk->d_pid == 0) 229 break; 230 } 231 if ((ret = startdisk(nextdisk, checkit)) != 0) 232 { 233 if ((flags & CHECK_NOFIX) == 0) 234 return ret; 235 else 236 error |= ret; 237 } 238 } 239 } 240 } 241 if (sumstatus) { 242 p = TAILQ_FIRST(&badh); 243 if (p == NULL) 244 return (sumstatus); 245 246 (void) fprintf(stderr, 247 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 248 TAILQ_NEXT(p, p_entries) ? "S" : "", 249 "UNEXPECTED INCONSISTENCY:"); 250 251 TAILQ_FOREACH(p, &badh, p_entries) 252 (void) fprintf(stderr, 253 "%s: %s (%s)%s", p->p_type, p->p_devname, 254 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 255 256 return sumstatus; 257 } 258 (void) endfsent(); 259 return error; 260 } 261 262 263 static struct diskentry * 264 finddisk(const char *name) 265 { 266 const char *p; 267 size_t len = 0; 268 struct diskentry *d; 269 270 for (len = strlen(name), p = name + len - 1; p >= name; --p) 271 if (isdigit((unsigned char)*p)) { 272 len = p - name + 1; 273 break; 274 } 275 if (p < name) 276 len = strlen(name); 277 278 TAILQ_FOREACH(d, &diskh, d_entries) 279 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 280 return d; 281 282 d = emalloc(sizeof(*d)); 283 d->d_name = estrdup(name); 284 d->d_name[len] = '\0'; 285 TAILQ_INIT(&d->d_part); 286 d->d_pid = 0; 287 288 TAILQ_INSERT_TAIL(&diskh, d, d_entries); 289 ndisks++; 290 291 return d; 292 } 293 294 295 static void 296 printpart(void) 297 { 298 struct diskentry *d; 299 struct partentry *p; 300 301 TAILQ_FOREACH(d, &diskh, d_entries) { 302 (void) printf("disk %s: ", d->d_name); 303 TAILQ_FOREACH(p, &d->d_part, p_entries) 304 (void) printf("%s ", p->p_devname); 305 (void) printf("\n"); 306 } 307 } 308 309 310 static void 311 addpart(const char *type, const char *dev, const char *mntpt, void *auxarg) 312 { 313 struct diskentry *d = finddisk(dev); 314 struct partentry *p; 315 316 TAILQ_FOREACH(p, &d->d_part, p_entries) 317 if (strcmp(p->p_devname, dev) == 0) { 318 warnx("%s in fstab more than once!", dev); 319 return; 320 } 321 322 p = emalloc(sizeof(*p)); 323 p->p_devname = estrdup(dev); 324 p->p_mntpt = estrdup(mntpt); 325 p->p_type = estrdup(type); 326 p->p_auxarg = auxarg; 327 328 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 329 } 330 331 332 static int 333 startdisk(struct diskentry *d, 334 int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 335 { 336 struct partentry *p = TAILQ_FIRST(&d->d_part); 337 int rv; 338 339 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt, 340 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0) 341 sleep(10); 342 343 if (rv == 0) 344 nrun++; 345 346 return rv; 347 } 348