1 1.32 dholland /* $NetBSD: preen.c,v 1.32 2015/06/21 04:01:40 dholland Exp $ */ 2 1.11 cgd 3 1.1 cgd /* 4 1.6 mycroft * Copyright (c) 1990, 1993 5 1.6 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.25 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.16 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.11 cgd #if 0 35 1.17 lukem static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95"; 36 1.11 cgd #else 37 1.32 dholland __RCSID("$NetBSD: preen.c,v 1.32 2015/06/21 04:01:40 dholland Exp $"); 38 1.11 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.32 dholland /* 42 1.32 dholland * used by sbin/fsck 43 1.32 dholland * used by usr.sbin/quotacheck 44 1.32 dholland */ 45 1.32 dholland 46 1.1 cgd #include <sys/param.h> 47 1.1 cgd #include <sys/stat.h> 48 1.1 cgd #include <sys/wait.h> 49 1.13 christos #include <sys/queue.h> 50 1.29 christos #include <sys/disk.h> 51 1.29 christos #include <sys/ioctl.h> 52 1.13 christos 53 1.17 lukem #include <err.h> 54 1.17 lukem #include <ctype.h> 55 1.1 cgd #include <fstab.h> 56 1.29 christos #include <fcntl.h> 57 1.1 cgd #include <string.h> 58 1.1 cgd #include <stdio.h> 59 1.1 cgd #include <stdlib.h> 60 1.9 cgd #include <unistd.h> 61 1.28 christos #include <util.h> 62 1.13 christos 63 1.14 christos #include "fsutil.h" 64 1.30 christos #include "exitvalues.h" 65 1.1 cgd 66 1.13 christos struct partentry { 67 1.13 christos TAILQ_ENTRY(partentry) p_entries; 68 1.14 christos char *p_devname; /* device name */ 69 1.14 christos char *p_mntpt; /* mount point */ 70 1.22 lukem char *p_type; /* file system type */ 71 1.15 christos void *p_auxarg; /* auxiliary argument */ 72 1.13 christos }; 73 1.13 christos 74 1.13 christos TAILQ_HEAD(part, partentry) badh; 75 1.13 christos 76 1.13 christos struct diskentry { 77 1.13 christos TAILQ_ENTRY(diskentry) d_entries; 78 1.20 lukem char *d_name; /* disk base name */ 79 1.13 christos TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 80 1.13 christos int d_pid; /* 0 or pid of fsck proc */ 81 1.13 christos }; 82 1.13 christos 83 1.29 christos TAILQ_HEAD(diskinfo, diskentry) diskh; 84 1.13 christos 85 1.13 christos static int nrun = 0, ndisks = 0; 86 1.13 christos 87 1.20 lukem static struct diskentry *finddisk(const char *); 88 1.20 lukem static void addpart(const char *, const char *, const char *, void *); 89 1.20 lukem static int startdisk(struct diskentry *, 90 1.20 lukem int (*)(const char *, const char *, const char *, void *, pid_t *)); 91 1.20 lukem static void printpart(void); 92 1.9 cgd 93 1.9 cgd int 94 1.20 lukem checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *), 95 1.20 lukem int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 96 1.1 cgd { 97 1.13 christos struct fstab *fs; 98 1.13 christos struct diskentry *d, *nextdisk; 99 1.13 christos struct partentry *p; 100 1.1 cgd int ret, pid, retcode, passno, sumstatus, status; 101 1.15 christos void *auxarg; 102 1.18 mycroft const char *name; 103 1.30 christos int error = FSCK_EXIT_OK; 104 1.1 cgd 105 1.13 christos TAILQ_INIT(&badh); 106 1.13 christos TAILQ_INIT(&diskh); 107 1.13 christos 108 1.30 christos sumstatus = FSCK_EXIT_OK; 109 1.13 christos 110 1.1 cgd for (passno = 1; passno <= 2; passno++) { 111 1.1 cgd if (setfsent() == 0) { 112 1.24 grant warnx("Can't open checklist file: %s", _PATH_FSTAB); 113 1.30 christos return FSCK_EXIT_CHECK_FAILED; 114 1.1 cgd } 115 1.13 christos while ((fs = getfsent()) != 0) { 116 1.31 christos char buf[MAXPATHLEN]; 117 1.31 christos const char *fsspec; 118 1.15 christos if ((auxarg = (*docheck)(fs)) == NULL) 119 1.1 cgd continue; 120 1.31 christos fsspec = getfsspecname(buf, sizeof(buf), fs->fs_spec); 121 1.31 christos if (fsspec == NULL) { 122 1.31 christos warn("%s", buf); 123 1.31 christos return FSCK_EXIT_CHECK_FAILED; 124 1.31 christos } 125 1.31 christos name = blockcheck(fsspec); 126 1.14 christos if (flags & CHECK_DEBUG) 127 1.13 christos printf("pass %d, name %s\n", passno, name); 128 1.13 christos 129 1.14 christos if ((flags & CHECK_PREEN) == 0 || 130 1.14 christos (passno == 1 && fs->fs_passno == 1)) { 131 1.13 christos if (name == NULL) { 132 1.14 christos if (flags & CHECK_PREEN) 133 1.30 christos return FSCK_EXIT_CHECK_FAILED; 134 1.13 christos else 135 1.13 christos continue; 136 1.13 christos } 137 1.15 christos sumstatus = (*checkit)(fs->fs_vfstype, 138 1.15 christos name, fs->fs_file, auxarg, NULL); 139 1.13 christos 140 1.27 christos if (sumstatus) { 141 1.27 christos if ((flags & CHECK_NOFIX) == 0) 142 1.30 christos return sumstatus; 143 1.30 christos else if (error < sumstatus) 144 1.30 christos error = sumstatus; 145 1.27 christos } 146 1.13 christos } else if (passno == 2 && fs->fs_passno > 1) { 147 1.13 christos if (name == NULL) { 148 1.13 christos (void) fprintf(stderr, 149 1.31 christos "BAD DISK NAME %s\n", fsspec); 150 1.30 christos sumstatus = FSCK_EXIT_CHECK_FAILED; 151 1.1 cgd continue; 152 1.1 cgd } 153 1.15 christos addpart(fs->fs_vfstype, name, fs->fs_file, 154 1.15 christos auxarg); 155 1.1 cgd } 156 1.1 cgd } 157 1.14 christos if ((flags & CHECK_PREEN) == 0) 158 1.27 christos return error; 159 1.1 cgd } 160 1.13 christos 161 1.14 christos if (flags & CHECK_DEBUG) 162 1.13 christos printpart(); 163 1.13 christos 164 1.14 christos if (flags & CHECK_PREEN) { 165 1.1 cgd if (maxrun == 0) 166 1.1 cgd maxrun = ndisks; 167 1.1 cgd if (maxrun > ndisks) 168 1.1 cgd maxrun = ndisks; 169 1.19 lukem nextdisk = TAILQ_FIRST(&diskh); 170 1.1 cgd for (passno = 0; passno < maxrun; ++passno) { 171 1.27 christos if ((ret = startdisk(nextdisk, checkit)) != 0) { 172 1.27 christos if ((flags & CHECK_NOFIX) == 0) 173 1.27 christos return ret; 174 1.30 christos else if (error < ret) 175 1.30 christos error = ret; 176 1.27 christos } 177 1.21 lukem nextdisk = TAILQ_NEXT(nextdisk, d_entries); 178 1.1 cgd } 179 1.13 christos 180 1.1 cgd while ((pid = wait(&status)) != -1) { 181 1.19 lukem TAILQ_FOREACH(d, &diskh, d_entries) 182 1.13 christos if (d->d_pid == pid) 183 1.1 cgd break; 184 1.13 christos 185 1.13 christos if (d == NULL) { 186 1.24 grant warnx("Unknown pid %d", pid); 187 1.1 cgd continue; 188 1.1 cgd } 189 1.13 christos 190 1.13 christos 191 1.1 cgd if (WIFEXITED(status)) 192 1.1 cgd retcode = WEXITSTATUS(status); 193 1.1 cgd else 194 1.1 cgd retcode = 0; 195 1.13 christos 196 1.19 lukem p = TAILQ_FIRST(&d->d_part); 197 1.13 christos 198 1.14 christos if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) 199 1.16 lukem (void) printf("done %s: %s (%s) = 0x%x\n", 200 1.14 christos p->p_type, p->p_devname, p->p_mntpt, 201 1.14 christos status); 202 1.13 christos 203 1.1 cgd if (WIFSIGNALED(status)) { 204 1.13 christos (void) fprintf(stderr, 205 1.14 christos "%s: %s (%s): EXITED WITH SIGNAL %d\n", 206 1.14 christos p->p_type, p->p_devname, p->p_mntpt, 207 1.14 christos WTERMSIG(status)); 208 1.30 christos retcode = FSCK_EXIT_SIGNALLED; 209 1.1 cgd } 210 1.13 christos 211 1.13 christos TAILQ_REMOVE(&d->d_part, p, p_entries); 212 1.13 christos 213 1.1 cgd if (retcode != 0) { 214 1.13 christos TAILQ_INSERT_TAIL(&badh, p, p_entries); 215 1.1 cgd sumstatus |= retcode; 216 1.13 christos } else { 217 1.13 christos free(p->p_type); 218 1.14 christos free(p->p_devname); 219 1.13 christos free(p); 220 1.13 christos } 221 1.13 christos d->d_pid = 0; 222 1.1 cgd nrun--; 223 1.13 christos 224 1.19 lukem if (TAILQ_FIRST(&d->d_part) == NULL) 225 1.1 cgd ndisks--; 226 1.1 cgd 227 1.1 cgd if (nextdisk == NULL) { 228 1.19 lukem if (TAILQ_FIRST(&d->d_part) != NULL) { 229 1.15 christos if ((ret = startdisk(d, checkit)) != 0) 230 1.27 christos { 231 1.27 christos if ((flags & CHECK_NOFIX) == 0) 232 1.27 christos return ret; 233 1.30 christos else if (error < ret) 234 1.30 christos error = ret; 235 1.27 christos } 236 1.1 cgd } 237 1.1 cgd } else if (nrun < maxrun && nrun < ndisks) { 238 1.1 cgd for ( ;; ) { 239 1.19 lukem nextdisk = TAILQ_NEXT(nextdisk, 240 1.19 lukem d_entries); 241 1.13 christos if (nextdisk == NULL) 242 1.19 lukem nextdisk = TAILQ_FIRST(&diskh); 243 1.19 lukem if (TAILQ_FIRST(&nextdisk->d_part) 244 1.19 lukem != NULL && nextdisk->d_pid == 0) 245 1.1 cgd break; 246 1.1 cgd } 247 1.15 christos if ((ret = startdisk(nextdisk, checkit)) != 0) 248 1.27 christos { 249 1.27 christos if ((flags & CHECK_NOFIX) == 0) 250 1.27 christos return ret; 251 1.30 christos else if (error < ret) 252 1.30 christos error = ret; 253 1.27 christos } 254 1.1 cgd } 255 1.1 cgd } 256 1.1 cgd } 257 1.1 cgd if (sumstatus) { 258 1.19 lukem p = TAILQ_FIRST(&badh); 259 1.13 christos if (p == NULL) 260 1.30 christos return sumstatus; 261 1.13 christos 262 1.13 christos (void) fprintf(stderr, 263 1.13 christos "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 264 1.21 lukem TAILQ_NEXT(p, p_entries) ? "S" : "", 265 1.13 christos "UNEXPECTED INCONSISTENCY:"); 266 1.13 christos 267 1.21 lukem TAILQ_FOREACH(p, &badh, p_entries) 268 1.13 christos (void) fprintf(stderr, 269 1.14 christos "%s: %s (%s)%s", p->p_type, p->p_devname, 270 1.21 lukem p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 271 1.13 christos 272 1.13 christos return sumstatus; 273 1.1 cgd } 274 1.13 christos (void) endfsent(); 275 1.27 christos return error; 276 1.1 cgd } 277 1.1 cgd 278 1.13 christos 279 1.13 christos static struct diskentry * 280 1.20 lukem finddisk(const char *name) 281 1.1 cgd { 282 1.13 christos const char *p; 283 1.29 christos size_t len, dlen; 284 1.13 christos struct diskentry *d; 285 1.29 christos char buf[MAXPATHLEN]; 286 1.29 christos struct dkwedge_info dkw; 287 1.29 christos int fd; 288 1.29 christos 289 1.29 christos if ((fd = opendisk(name, O_RDONLY, buf, sizeof(buf), 0)) != -1) { 290 1.29 christos if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) 291 1.29 christos name = dkw.dkw_parent; 292 1.29 christos (void)close(fd); 293 1.29 christos } 294 1.1 cgd 295 1.29 christos for (dlen = len = strlen(name), p = name + len - 1; p >= name; --p) 296 1.26 dsl if (isdigit((unsigned char)*p)) { 297 1.1 cgd len = p - name + 1; 298 1.1 cgd break; 299 1.1 cgd } 300 1.1 cgd if (p < name) 301 1.29 christos len = dlen; 302 1.1 cgd 303 1.19 lukem TAILQ_FOREACH(d, &diskh, d_entries) 304 1.13 christos if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 305 1.13 christos return d; 306 1.13 christos 307 1.13 christos d = emalloc(sizeof(*d)); 308 1.13 christos d->d_name = estrdup(name); 309 1.13 christos d->d_name[len] = '\0'; 310 1.13 christos TAILQ_INIT(&d->d_part); 311 1.13 christos d->d_pid = 0; 312 1.13 christos 313 1.13 christos TAILQ_INSERT_TAIL(&diskh, d, d_entries); 314 1.1 cgd ndisks++; 315 1.13 christos 316 1.13 christos return d; 317 1.1 cgd } 318 1.1 cgd 319 1.13 christos 320 1.13 christos static void 321 1.20 lukem printpart(void) 322 1.1 cgd { 323 1.13 christos struct diskentry *d; 324 1.13 christos struct partentry *p; 325 1.1 cgd 326 1.19 lukem TAILQ_FOREACH(d, &diskh, d_entries) { 327 1.29 christos (void) printf("disk %s:", d->d_name); 328 1.19 lukem TAILQ_FOREACH(p, &d->d_part, p_entries) 329 1.29 christos (void) printf(" %s", p->p_devname); 330 1.13 christos (void) printf("\n"); 331 1.1 cgd } 332 1.1 cgd } 333 1.1 cgd 334 1.13 christos 335 1.13 christos static void 336 1.23 lukem addpart(const char *type, const char *dev, const char *mntpt, void *auxarg) 337 1.1 cgd { 338 1.23 lukem struct diskentry *d = finddisk(dev); 339 1.13 christos struct partentry *p; 340 1.13 christos 341 1.19 lukem TAILQ_FOREACH(p, &d->d_part, p_entries) 342 1.23 lukem if (strcmp(p->p_devname, dev) == 0) { 343 1.24 grant warnx("%s in fstab more than once!", dev); 344 1.13 christos return; 345 1.13 christos } 346 1.1 cgd 347 1.13 christos p = emalloc(sizeof(*p)); 348 1.23 lukem p->p_devname = estrdup(dev); 349 1.14 christos p->p_mntpt = estrdup(mntpt); 350 1.13 christos p->p_type = estrdup(type); 351 1.15 christos p->p_auxarg = auxarg; 352 1.13 christos 353 1.13 christos TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 354 1.1 cgd } 355 1.1 cgd 356 1.1 cgd 357 1.13 christos static int 358 1.20 lukem startdisk(struct diskentry *d, 359 1.20 lukem int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 360 1.1 cgd { 361 1.19 lukem struct partentry *p = TAILQ_FIRST(&d->d_part); 362 1.13 christos int rv; 363 1.1 cgd 364 1.14 christos while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt, 365 1.15 christos p->p_auxarg, &d->d_pid)) != 0 && nrun > 0) 366 1.13 christos sleep(10); 367 1.1 cgd 368 1.13 christos if (rv == 0) 369 1.13 christos nrun++; 370 1.1 cgd 371 1.13 christos return rv; 372 1.1 cgd } 373