1254721Semaste/* $NetBSD: preen.c,v 1.31 2012/04/07 04:52:20 christos Exp $ */ 2254721Semaste 3254721Semaste/* 4254721Semaste * Copyright (c) 1990, 1993 5254721Semaste * The Regents of the University of California. All rights reserved. 6254721Semaste * 7254721Semaste * Redistribution and use in source and binary forms, with or without 8254721Semaste * modification, are permitted provided that the following conditions 9254721Semaste * are met: 10254721Semaste * 1. Redistributions of source code must retain the above copyright 11254721Semaste * notice, this list of conditions and the following disclaimer. 12254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 13254721Semaste * notice, this list of conditions and the following disclaimer in the 14254721Semaste * documentation and/or other materials provided with the distribution. 15254721Semaste * 3. Neither the name of the University nor the names of its contributors 16254721Semaste * may be used to endorse or promote products derived from this software 17254721Semaste * without specific prior written permission. 18254721Semaste * 19254721Semaste * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22254721Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29254721Semaste * SUCH DAMAGE. 30254721Semaste */ 31254721Semaste 32254721Semaste#include <sys/cdefs.h> 33254721Semaste#ifndef lint 34254721Semaste#if 0 35254721Semastestatic char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95"; 36254721Semaste#else 37254721Semaste__RCSID("$NetBSD: preen.c,v 1.31 2012/04/07 04:52:20 christos Exp $"); 38254721Semaste#endif 39254721Semaste#endif /* not lint */ 40254721Semaste 41254721Semaste/* 42254721Semaste * used by sbin/fsck 43254721Semaste * used by usr.sbin/quotacheck 44254721Semaste */ 45254721Semaste 46254721Semaste#include <sys/param.h> 47254721Semaste#include <sys/stat.h> 48254721Semaste#include <sys/wait.h> 49254721Semaste#include <sys/queue.h> 50254721Semaste#include <sys/disk.h> 51254721Semaste#include <sys/ioctl.h> 52254721Semaste 53254721Semaste#include <err.h> 54254721Semaste#include <ctype.h> 55254721Semaste#include <fstab.h> 56254721Semaste#include <fcntl.h> 57254721Semaste#include <string.h> 58254721Semaste#include <stdio.h> 59254721Semaste#include <stdlib.h> 60254721Semaste#include <unistd.h> 61254721Semaste#include <util.h> 62254721Semaste 63254721Semaste#include "fsutil.h" 64254721Semaste#include "exitvalues.h" 65254721Semaste 66254721Semastestruct partentry { 67254721Semaste TAILQ_ENTRY(partentry) p_entries; 68254721Semaste char *p_devname; /* device name */ 69254721Semaste char *p_mntpt; /* mount point */ 70254721Semaste char *p_type; /* file system type */ 71254721Semaste void *p_auxarg; /* auxiliary argument */ 72254721Semaste}; 73254721Semaste 74254721SemasteTAILQ_HEAD(part, partentry) badh; 75254721Semaste 76254721Semastestruct diskentry { 77254721Semaste TAILQ_ENTRY(diskentry) d_entries; 78254721Semaste char *d_name; /* disk base name */ 79254721Semaste TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 80254721Semaste int d_pid; /* 0 or pid of fsck proc */ 81254721Semaste}; 82254721Semaste 83254721SemasteTAILQ_HEAD(diskinfo, diskentry) diskh; 84254721Semaste 85254721Semastestatic int nrun = 0, ndisks = 0; 86254721Semaste 87254721Semastestatic struct diskentry *finddisk(const char *); 88254721Semastestatic void addpart(const char *, const char *, const char *, void *); 89254721Semastestatic int startdisk(struct diskentry *, 90254721Semaste int (*)(const char *, const char *, const char *, void *, pid_t *)); 91254721Semastestatic void printpart(void); 92254721Semaste 93254721Semasteint 94254721Semastecheckfstab(int flags, int maxrun, void *(*docheck)(struct fstab *), 95254721Semaste int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 96254721Semaste{ 97254721Semaste struct fstab *fs; 98254721Semaste struct diskentry *d, *nextdisk; 99254721Semaste struct partentry *p; 100254721Semaste int ret, pid, retcode, passno, sumstatus, status; 101254721Semaste void *auxarg; 102254721Semaste const char *name; 103254721Semaste int error = FSCK_EXIT_OK; 104254721Semaste 105254721Semaste TAILQ_INIT(&badh); 106254721Semaste TAILQ_INIT(&diskh); 107254721Semaste 108254721Semaste sumstatus = FSCK_EXIT_OK; 109254721Semaste 110254721Semaste for (passno = 1; passno <= 2; passno++) { 111254721Semaste if (setfsent() == 0) { 112254721Semaste warnx("Can't open checklist file: %s", _PATH_FSTAB); 113254721Semaste return FSCK_EXIT_CHECK_FAILED; 114254721Semaste } 115254721Semaste while ((fs = getfsent()) != 0) { 116254721Semaste char buf[MAXPATHLEN]; 117254721Semaste const char *fsspec; 118254721Semaste if ((auxarg = (*docheck)(fs)) == NULL) 119254721Semaste continue; 120254721Semaste fsspec = getfsspecname(buf, sizeof(buf), fs->fs_spec); 121254721Semaste if (fsspec == NULL) { 122254721Semaste warn("%s", buf); 123254721Semaste return FSCK_EXIT_CHECK_FAILED; 124254721Semaste } 125254721Semaste name = blockcheck(fsspec); 126254721Semaste if (flags & CHECK_DEBUG) 127254721Semaste printf("pass %d, name %s\n", passno, name); 128254721Semaste 129254721Semaste if ((flags & CHECK_PREEN) == 0 || 130254721Semaste (passno == 1 && fs->fs_passno == 1)) { 131254721Semaste if (name == NULL) { 132254721Semaste if (flags & CHECK_PREEN) 133254721Semaste return FSCK_EXIT_CHECK_FAILED; 134254721Semaste else 135254721Semaste continue; 136254721Semaste } 137254721Semaste sumstatus = (*checkit)(fs->fs_vfstype, 138254721Semaste name, fs->fs_file, auxarg, NULL); 139254721Semaste 140254721Semaste if (sumstatus) { 141254721Semaste if ((flags & CHECK_NOFIX) == 0) 142254721Semaste return sumstatus; 143254721Semaste else if (error < sumstatus) 144254721Semaste error = sumstatus; 145254721Semaste } 146254721Semaste } else if (passno == 2 && fs->fs_passno > 1) { 147254721Semaste if (name == NULL) { 148254721Semaste (void) fprintf(stderr, 149254721Semaste "BAD DISK NAME %s\n", fsspec); 150254721Semaste sumstatus = FSCK_EXIT_CHECK_FAILED; 151254721Semaste continue; 152254721Semaste } 153254721Semaste addpart(fs->fs_vfstype, name, fs->fs_file, 154254721Semaste auxarg); 155254721Semaste } 156254721Semaste } 157254721Semaste if ((flags & CHECK_PREEN) == 0) 158254721Semaste return error; 159254721Semaste } 160254721Semaste 161254721Semaste if (flags & CHECK_DEBUG) 162254721Semaste printpart(); 163254721Semaste 164254721Semaste if (flags & CHECK_PREEN) { 165254721Semaste if (maxrun == 0) 166254721Semaste maxrun = ndisks; 167254721Semaste if (maxrun > ndisks) 168254721Semaste maxrun = ndisks; 169254721Semaste nextdisk = TAILQ_FIRST(&diskh); 170254721Semaste for (passno = 0; passno < maxrun; ++passno) { 171254721Semaste if ((ret = startdisk(nextdisk, checkit)) != 0) { 172254721Semaste if ((flags & CHECK_NOFIX) == 0) 173254721Semaste return ret; 174254721Semaste else if (error < ret) 175254721Semaste error = ret; 176254721Semaste } 177254721Semaste nextdisk = TAILQ_NEXT(nextdisk, d_entries); 178254721Semaste } 179254721Semaste 180254721Semaste while ((pid = wait(&status)) != -1) { 181254721Semaste TAILQ_FOREACH(d, &diskh, d_entries) 182254721Semaste if (d->d_pid == pid) 183254721Semaste break; 184254721Semaste 185254721Semaste if (d == NULL) { 186254721Semaste warnx("Unknown pid %d", pid); 187254721Semaste continue; 188254721Semaste } 189254721Semaste 190254721Semaste 191254721Semaste if (WIFEXITED(status)) 192254721Semaste retcode = WEXITSTATUS(status); 193254721Semaste else 194254721Semaste retcode = 0; 195254721Semaste 196254721Semaste p = TAILQ_FIRST(&d->d_part); 197254721Semaste 198254721Semaste if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) 199254721Semaste (void) printf("done %s: %s (%s) = 0x%x\n", 200254721Semaste p->p_type, p->p_devname, p->p_mntpt, 201254721Semaste status); 202254721Semaste 203254721Semaste if (WIFSIGNALED(status)) { 204254721Semaste (void) fprintf(stderr, 205254721Semaste "%s: %s (%s): EXITED WITH SIGNAL %d\n", 206254721Semaste p->p_type, p->p_devname, p->p_mntpt, 207254721Semaste WTERMSIG(status)); 208254721Semaste retcode = FSCK_EXIT_SIGNALLED; 209254721Semaste } 210254721Semaste 211254721Semaste TAILQ_REMOVE(&d->d_part, p, p_entries); 212254721Semaste 213254721Semaste if (retcode != 0) { 214254721Semaste TAILQ_INSERT_TAIL(&badh, p, p_entries); 215254721Semaste sumstatus |= retcode; 216254721Semaste } else { 217254721Semaste free(p->p_type); 218254721Semaste free(p->p_devname); 219254721Semaste free(p); 220254721Semaste } 221254721Semaste d->d_pid = 0; 222254721Semaste nrun--; 223254721Semaste 224254721Semaste if (TAILQ_FIRST(&d->d_part) == NULL) 225254721Semaste ndisks--; 226254721Semaste 227254721Semaste if (nextdisk == NULL) { 228254721Semaste if (TAILQ_FIRST(&d->d_part) != NULL) { 229254721Semaste if ((ret = startdisk(d, checkit)) != 0) 230254721Semaste { 231254721Semaste if ((flags & CHECK_NOFIX) == 0) 232254721Semaste return ret; 233254721Semaste else if (error < ret) 234254721Semaste error = ret; 235254721Semaste } 236254721Semaste } 237254721Semaste } else if (nrun < maxrun && nrun < ndisks) { 238254721Semaste for ( ;; ) { 239254721Semaste nextdisk = TAILQ_NEXT(nextdisk, 240254721Semaste d_entries); 241254721Semaste if (nextdisk == NULL) 242254721Semaste nextdisk = TAILQ_FIRST(&diskh); 243254721Semaste if (TAILQ_FIRST(&nextdisk->d_part) 244254721Semaste != NULL && nextdisk->d_pid == 0) 245254721Semaste break; 246254721Semaste } 247254721Semaste if ((ret = startdisk(nextdisk, checkit)) != 0) 248254721Semaste { 249254721Semaste if ((flags & CHECK_NOFIX) == 0) 250254721Semaste return ret; 251254721Semaste else if (error < ret) 252254721Semaste error = ret; 253254721Semaste } 254254721Semaste } 255254721Semaste } 256254721Semaste } 257254721Semaste if (sumstatus) { 258254721Semaste p = TAILQ_FIRST(&badh); 259254721Semaste if (p == NULL) 260254721Semaste return sumstatus; 261254721Semaste 262254721Semaste (void) fprintf(stderr, 263254721Semaste "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 264254721Semaste TAILQ_NEXT(p, p_entries) ? "S" : "", 265254721Semaste "UNEXPECTED INCONSISTENCY:"); 266254721Semaste 267254721Semaste TAILQ_FOREACH(p, &badh, p_entries) 268254721Semaste (void) fprintf(stderr, 269254721Semaste "%s: %s (%s)%s", p->p_type, p->p_devname, 270254721Semaste p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 271254721Semaste 272254721Semaste return sumstatus; 273254721Semaste } 274254721Semaste (void) endfsent(); 275254721Semaste return error; 276254721Semaste} 277254721Semaste 278254721Semaste 279254721Semastestatic struct diskentry * 280254721Semastefinddisk(const char *name) 281254721Semaste{ 282254721Semaste const char *p; 283254721Semaste size_t len, dlen; 284254721Semaste struct diskentry *d; 285254721Semaste char buf[MAXPATHLEN]; 286254721Semaste struct dkwedge_info dkw; 287254721Semaste int fd; 288254721Semaste 289254721Semaste if ((fd = opendisk(name, O_RDONLY, buf, sizeof(buf), 0)) != -1) { 290254721Semaste if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) 291254721Semaste name = dkw.dkw_parent; 292254721Semaste (void)close(fd); 293254721Semaste } 294254721Semaste 295254721Semaste for (dlen = len = strlen(name), p = name + len - 1; p >= name; --p) 296254721Semaste if (isdigit((unsigned char)*p)) { 297254721Semaste len = p - name + 1; 298254721Semaste break; 299254721Semaste } 300254721Semaste if (p < name) 301254721Semaste len = dlen; 302254721Semaste 303254721Semaste TAILQ_FOREACH(d, &diskh, d_entries) 304254721Semaste if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 305254721Semaste return d; 306254721Semaste 307254721Semaste d = emalloc(sizeof(*d)); 308254721Semaste d->d_name = estrdup(name); 309254721Semaste d->d_name[len] = '\0'; 310254721Semaste TAILQ_INIT(&d->d_part); 311254721Semaste d->d_pid = 0; 312254721Semaste 313254721Semaste TAILQ_INSERT_TAIL(&diskh, d, d_entries); 314254721Semaste ndisks++; 315254721Semaste 316254721Semaste return d; 317254721Semaste} 318254721Semaste 319254721Semaste 320254721Semastestatic void 321254721Semasteprintpart(void) 322254721Semaste{ 323254721Semaste struct diskentry *d; 324254721Semaste struct partentry *p; 325254721Semaste 326254721Semaste TAILQ_FOREACH(d, &diskh, d_entries) { 327254721Semaste (void) printf("disk %s:", d->d_name); 328254721Semaste TAILQ_FOREACH(p, &d->d_part, p_entries) 329254721Semaste (void) printf(" %s", p->p_devname); 330254721Semaste (void) printf("\n"); 331254721Semaste } 332254721Semaste} 333254721Semaste 334254721Semaste 335254721Semastestatic void 336254721Semasteaddpart(const char *type, const char *dev, const char *mntpt, void *auxarg) 337254721Semaste{ 338254721Semaste struct diskentry *d = finddisk(dev); 339254721Semaste struct partentry *p; 340254721Semaste 341254721Semaste TAILQ_FOREACH(p, &d->d_part, p_entries) 342254721Semaste if (strcmp(p->p_devname, dev) == 0) { 343254721Semaste warnx("%s in fstab more than once!", dev); 344254721Semaste return; 345254721Semaste } 346254721Semaste 347254721Semaste p = emalloc(sizeof(*p)); 348254721Semaste p->p_devname = estrdup(dev); 349254721Semaste p->p_mntpt = estrdup(mntpt); 350254721Semaste p->p_type = estrdup(type); 351254721Semaste p->p_auxarg = auxarg; 352254721Semaste 353254721Semaste TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 354254721Semaste} 355254721Semaste 356254721Semaste 357254721Semastestatic int 358254721Semastestartdisk(struct diskentry *d, 359254721Semaste int (*checkit)(const char *, const char *, const char *, void *, pid_t *)) 360254721Semaste{ 361254721Semaste struct partentry *p = TAILQ_FIRST(&d->d_part); 362254721Semaste int rv; 363254721Semaste 364254721Semaste while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt, 365254721Semaste p->p_auxarg, &d->d_pid)) != 0 && nrun > 0) 366254721Semaste sleep(10); 367254721Semaste 368254721Semaste if (rv == 0) 369254721Semaste nrun++; 370254721Semaste 371254721Semaste return rv; 372254721Semaste} 373254721Semaste