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