1 /* $NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft 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 * 4. 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 * $FreeBSD$ 32 */ 33 34 #include <sys/cdefs.h> 35 #ifndef lint 36 #if 0 37 static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95"; 38 #else 39 __RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $"); 40 #endif 41 #endif /* not lint */ 42 43 #include <sys/param.h> 44 #include <sys/stat.h> 45 #include <sys/wait.h> 46 #include <sys/queue.h> 47 48 #include <err.h> 49 #include <ctype.h> 50 #include <fstab.h> 51 #include <string.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <unistd.h> 55 56 #include "quotacheck.h" 57 58 struct partentry { 59 TAILQ_ENTRY(partentry) p_entries; 60 char *p_devname; /* device name */ 61 char *p_mntpt; /* mount point */ 62 char *p_type; /* file system type */ 63 struct quotaname *p_quota; /* quota file info ptr */ 64 }; 65 66 TAILQ_HEAD(part, partentry) badh; 67 68 struct diskentry { 69 TAILQ_ENTRY(diskentry) d_entries; 70 char *d_name; /* disk base name */ 71 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 72 int d_pid; /* 0 or pid of fsck proc */ 73 }; 74 75 TAILQ_HEAD(disk, diskentry) diskh; 76 77 static struct diskentry *finddisk(const char *); 78 static void addpart(const char *, const char *, const char *, 79 struct quotaname *); 80 static int startdisk(struct diskentry *); 81 extern void *emalloc(size_t); 82 extern char *estrdup(const char *); 83 84 int 85 checkfstab(void) 86 { 87 struct fstab *fs; 88 struct diskentry *d, *nextdisk; 89 struct partentry *p; 90 int ret, pid, retcode, passno, sumstatus, status, nextpass; 91 char *name; 92 struct quotaname *qnp; 93 94 TAILQ_INIT(&badh); 95 TAILQ_INIT(&diskh); 96 97 sumstatus = 0; 98 99 nextpass = 0; 100 for (passno = 1; nextpass != INT_MAX; passno = nextpass) { 101 nextpass = INT_MAX; 102 if (setfsent() == 0) { 103 warnx("Can't open checklist file: %s\n", _PATH_FSTAB); 104 return (8); 105 } 106 while ((fs = getfsent()) != 0) { 107 name = fs->fs_spec; 108 if (fs->fs_passno > passno && fs->fs_passno < nextpass) 109 nextpass = fs->fs_passno; 110 111 if (passno != fs->fs_passno) 112 continue; 113 114 if ((qnp = needchk(fs)) == NULL) 115 continue; 116 117 if (passno == 1) { 118 sumstatus = chkquota(name, fs->fs_file, qnp); 119 120 if (sumstatus) 121 return (sumstatus); 122 continue; 123 } 124 if (name == NULL) { 125 (void) fprintf(stderr, 126 "BAD DISK NAME %s\n", fs->fs_spec); 127 sumstatus |= 8; 128 continue; 129 } 130 addpart(fs->fs_vfstype, name, fs->fs_file, qnp); 131 } 132 133 if (passno == 1) 134 continue; 135 136 TAILQ_FOREACH(nextdisk, &diskh, d_entries) { 137 if ((ret = startdisk(nextdisk)) != 0) 138 return ret; 139 } 140 141 while ((pid = wait(&status)) != -1) { 142 TAILQ_FOREACH(d, &diskh, d_entries) 143 if (d->d_pid == pid) 144 break; 145 146 if (d == NULL) { 147 warnx("Unknown pid %d\n", pid); 148 continue; 149 } 150 151 if (WIFEXITED(status)) 152 retcode = WEXITSTATUS(status); 153 else 154 retcode = 0; 155 156 p = TAILQ_FIRST(&d->d_part); 157 158 if (WIFSIGNALED(status)) { 159 (void) fprintf(stderr, 160 "%s: %s (%s): EXITED WITH SIGNAL %d\n", 161 p->p_type, p->p_devname, p->p_mntpt, 162 WTERMSIG(status)); 163 retcode = 8; 164 } 165 166 TAILQ_REMOVE(&d->d_part, p, p_entries); 167 168 if (retcode != 0) { 169 TAILQ_INSERT_TAIL(&badh, p, p_entries); 170 sumstatus |= retcode; 171 } else { 172 free(p->p_type); 173 free(p->p_devname); 174 free(p); 175 } 176 d->d_pid = 0; 177 178 if (TAILQ_EMPTY(&d->d_part)) { 179 TAILQ_REMOVE(&diskh, d, d_entries); 180 } else { 181 if ((ret = startdisk(d)) != 0) 182 return ret; 183 } 184 } 185 } 186 187 if (sumstatus) { 188 p = TAILQ_FIRST(&badh); 189 if (p == NULL) 190 return (sumstatus); 191 192 (void) fprintf(stderr, 193 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 194 TAILQ_NEXT(p, p_entries) ? "S" : "", 195 "UNEXPECTED INCONSISTENCY:"); 196 197 for (; p; p = TAILQ_NEXT(p, p_entries)) 198 (void) fprintf(stderr, 199 "%s: %s (%s)%s", p->p_type, p->p_devname, 200 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 201 202 return sumstatus; 203 } 204 (void) endfsent(); 205 return (0); 206 } 207 208 209 static struct diskentry * 210 finddisk(const char *name) 211 { 212 const char *p; 213 size_t len = 0; 214 struct diskentry *d; 215 216 p = strrchr(name, '/'); 217 if (p == NULL) 218 p = name; 219 else 220 p++; 221 for (; *p && !isdigit(*p); p++) 222 continue; 223 for (; *p && isdigit(*p); p++) 224 continue; 225 len = p - name; 226 if (len == 0) 227 len = strlen(name); 228 229 TAILQ_FOREACH(d, &diskh, d_entries) 230 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 231 return d; 232 233 d = emalloc(sizeof(*d)); 234 d->d_name = estrdup(name); 235 d->d_name[len] = '\0'; 236 TAILQ_INIT(&d->d_part); 237 d->d_pid = 0; 238 239 TAILQ_INSERT_TAIL(&diskh, d, d_entries); 240 241 return d; 242 } 243 244 static void 245 addpart(const char *type, const char *devname, const char *mntpt, 246 struct quotaname *qnp) 247 { 248 struct diskentry *d = finddisk(devname); 249 struct partentry *p; 250 251 TAILQ_FOREACH(p, &d->d_part, p_entries) 252 if (strcmp(p->p_devname, devname) == 0) { 253 warnx("%s in fstab more than once!\n", devname); 254 return; 255 } 256 257 p = emalloc(sizeof(*p)); 258 p->p_devname = estrdup(devname); 259 p->p_mntpt = estrdup(mntpt); 260 p->p_type = estrdup(type); 261 p->p_quota = qnp; 262 263 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 264 } 265 266 267 static int 268 startdisk(struct diskentry *d) 269 { 270 struct partentry *p = TAILQ_FIRST(&d->d_part); 271 272 d->d_pid = fork(); 273 if (d->d_pid < 0) { 274 perror("fork"); 275 return (8); 276 } 277 if (d->d_pid == 0) 278 exit(chkquota(p->p_devname, p->p_mntpt, p->p_quota)); 279 return (0); 280 } 281