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