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