1 /* $NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 1990, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95"; 40 #else 41 __RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/wait.h> 48 #include <sys/queue.h> 49 50 #include <ufs/ufs/quota.h> 51 52 #include <err.h> 53 #include <ctype.h> 54 #include <fcntl.h> 55 #include <fstab.h> 56 #include <libutil.h> 57 #include <string.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <unistd.h> 61 62 #include "quotacheck.h" 63 64 struct partentry { 65 TAILQ_ENTRY(partentry) p_entries; 66 char *p_devname; /* device name */ 67 const char *p_mntpt; /* mount point */ 68 struct quotafile *p_qfu; /* user quota file info ptr */ 69 struct quotafile *p_qfg; /* group quota file info */ 70 }; 71 72 TAILQ_HEAD(part, partentry) badh; 73 74 struct diskentry { 75 TAILQ_ENTRY(diskentry) d_entries; 76 char *d_name; /* disk base name */ 77 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 78 int d_pid; /* 0 or pid of fsck proc */ 79 }; 80 81 TAILQ_HEAD(disk, diskentry) diskh; 82 83 static struct diskentry *finddisk(const char *); 84 static void addpart(struct fstab *, struct quotafile *, struct quotafile *); 85 static int startdisk(struct diskentry *); 86 extern void *emalloc(size_t); 87 extern char *estrdup(const char *); 88 89 int 90 checkfstab(int uflag, int gflag) 91 { 92 struct fstab *fs; 93 struct diskentry *d, *nextdisk; 94 struct partentry *p; 95 int ret, pid, retcode, passno, sumstatus, status, nextpass; 96 struct quotafile *qfu, *qfg; 97 98 TAILQ_INIT(&badh); 99 TAILQ_INIT(&diskh); 100 101 sumstatus = 0; 102 103 nextpass = 0; 104 for (passno = 1; nextpass != INT_MAX; passno = nextpass) { 105 nextpass = INT_MAX; 106 if (setfsent() == 0) { 107 warnx("Can't open checklist file: %s\n", _PATH_FSTAB); 108 return (8); 109 } 110 while ((fs = getfsent()) != NULL) { 111 if (fs->fs_passno > passno && fs->fs_passno < nextpass) 112 nextpass = fs->fs_passno; 113 114 if (passno != fs->fs_passno) 115 continue; 116 117 qfu = NULL; 118 if (uflag) 119 qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR); 120 qfg = NULL; 121 if (gflag) 122 qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR); 123 if (qfu == NULL && qfg == NULL) 124 continue; 125 126 if (passno == 1) { 127 sumstatus = chkquota(fs->fs_spec, qfu, qfg); 128 if (qfu) 129 quota_close(qfu); 130 if (qfg) 131 quota_close(qfg); 132 if (sumstatus) 133 return (sumstatus); 134 continue; 135 } 136 addpart(fs, qfu, qfg); 137 } 138 139 if (passno == 1) 140 continue; 141 142 TAILQ_FOREACH(nextdisk, &diskh, d_entries) { 143 if ((ret = startdisk(nextdisk)) != 0) 144 return ret; 145 } 146 147 while ((pid = wait(&status)) != -1) { 148 TAILQ_FOREACH(d, &diskh, d_entries) 149 if (d->d_pid == pid) 150 break; 151 152 if (d == NULL) { 153 warnx("Unknown pid %d\n", pid); 154 continue; 155 } 156 157 if (WIFEXITED(status)) 158 retcode = WEXITSTATUS(status); 159 else 160 retcode = 0; 161 162 p = TAILQ_FIRST(&d->d_part); 163 164 if (WIFSIGNALED(status)) { 165 (void) fprintf(stderr, 166 "%s: (%s): EXITED WITH SIGNAL %d\n", 167 p->p_devname, p->p_mntpt, 168 WTERMSIG(status)); 169 retcode = 8; 170 } 171 172 TAILQ_REMOVE(&d->d_part, p, p_entries); 173 174 if (retcode != 0) { 175 TAILQ_INSERT_TAIL(&badh, p, p_entries); 176 sumstatus |= retcode; 177 } else { 178 free(p->p_devname); 179 if (p->p_qfu) 180 quota_close(p->p_qfu); 181 if (p->p_qfg) 182 quota_close(p->p_qfg); 183 free(p); 184 } 185 d->d_pid = 0; 186 187 if (TAILQ_EMPTY(&d->d_part)) { 188 TAILQ_REMOVE(&diskh, d, d_entries); 189 } else { 190 if ((ret = startdisk(d)) != 0) 191 return ret; 192 } 193 } 194 } 195 196 if (sumstatus) { 197 p = TAILQ_FIRST(&badh); 198 if (p == NULL) 199 return (sumstatus); 200 201 (void) fprintf(stderr, 202 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 203 TAILQ_NEXT(p, p_entries) ? "S" : "", 204 "UNEXPECTED INCONSISTENCY:"); 205 206 for (; p; p = TAILQ_NEXT(p, p_entries)) 207 (void) fprintf(stderr, 208 "%s: (%s)%s", p->p_devname, p->p_mntpt, 209 TAILQ_NEXT(p, p_entries) ? ", " : "\n"); 210 211 return sumstatus; 212 } 213 (void) endfsent(); 214 return (0); 215 } 216 217 218 static struct diskentry * 219 finddisk(const char *name) 220 { 221 const char *p; 222 size_t len = 0; 223 struct diskentry *d; 224 225 p = strrchr(name, '/'); 226 if (p == NULL) 227 p = name; 228 else 229 p++; 230 for (; *p && !isdigit(*p); p++) 231 continue; 232 for (; *p && isdigit(*p); p++) 233 continue; 234 len = p - name; 235 if (len == 0) 236 len = strlen(name); 237 238 TAILQ_FOREACH(d, &diskh, d_entries) 239 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0) 240 return d; 241 242 d = emalloc(sizeof(*d)); 243 d->d_name = estrdup(name); 244 d->d_name[len] = '\0'; 245 TAILQ_INIT(&d->d_part); 246 d->d_pid = 0; 247 248 TAILQ_INSERT_TAIL(&diskh, d, d_entries); 249 250 return d; 251 } 252 253 static void 254 addpart(struct fstab *fs, struct quotafile *qfu, struct quotafile *qfg) 255 { 256 struct diskentry *d = finddisk(fs->fs_spec); 257 struct partentry *p; 258 259 TAILQ_FOREACH(p, &d->d_part, p_entries) 260 if (strcmp(p->p_devname, fs->fs_spec) == 0) { 261 warnx("%s in fstab more than once!\n", fs->fs_spec); 262 return; 263 } 264 265 p = emalloc(sizeof(*p)); 266 p->p_devname = estrdup(blockcheck(fs->fs_spec)); 267 if (qfu != NULL) 268 p->p_mntpt = quota_fsname(qfu); 269 else 270 p->p_mntpt = quota_fsname(qfg); 271 p->p_qfu = qfu; 272 p->p_qfg = qfg; 273 274 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 275 } 276 277 278 static int 279 startdisk(struct diskentry *d) 280 { 281 struct partentry *p = TAILQ_FIRST(&d->d_part); 282 283 d->d_pid = fork(); 284 if (d->d_pid < 0) { 285 perror("fork"); 286 return (8); 287 } 288 if (d->d_pid == 0) 289 exit(chkquota(p->p_devname, p->p_qfu, p->p_qfg)); 290 return (0); 291 } 292