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