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 34 /* $NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $ */ 35 36 #include <sys/param.h> 37 #include <sys/stat.h> 38 #include <sys/wait.h> 39 #include <sys/queue.h> 40 41 #include <ufs/ufs/quota.h> 42 43 #include <err.h> 44 #include <ctype.h> 45 #include <fcntl.h> 46 #include <fstab.h> 47 #include <libutil.h> 48 #include <string.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <unistd.h> 52 53 #include "quotacheck.h" 54 55 struct partentry { 56 TAILQ_ENTRY(partentry) p_entries; 57 char *p_devname; /* device name */ 58 const char *p_mntpt; /* mount point */ 59 struct quotafile *p_qfu; /* user quota file info ptr */ 60 struct quotafile *p_qfg; /* group quota file info */ 61 }; 62 63 TAILQ_HEAD(part, partentry) badh; 64 65 struct diskentry { 66 TAILQ_ENTRY(diskentry) d_entries; 67 char *d_name; /* disk base name */ 68 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */ 69 int d_pid; /* 0 or pid of fsck proc */ 70 }; 71 72 TAILQ_HEAD(disk, diskentry) diskh; 73 74 static struct diskentry *finddisk(const char *); 75 static void addpart(struct fstab *, struct quotafile *, struct quotafile *); 76 static int startdisk(struct diskentry *); 77 extern void *emalloc(size_t); 78 extern char *estrdup(const char *); 79 80 int 81 checkfstab(int uflag, int gflag) 82 { 83 struct fstab *fs; 84 struct diskentry *d, *nextdisk; 85 struct partentry *p; 86 int ret, pid, retcode, passno, sumstatus, status, nextpass; 87 struct quotafile *qfu, *qfg; 88 89 TAILQ_INIT(&badh); 90 TAILQ_INIT(&diskh); 91 92 sumstatus = 0; 93 94 nextpass = 0; 95 for (passno = 1; nextpass != INT_MAX; passno = nextpass) { 96 nextpass = INT_MAX; 97 if (setfsent() == 0) { 98 warnx("Can't open checklist file: %s\n", _PATH_FSTAB); 99 return (8); 100 } 101 while ((fs = getfsent()) != NULL) { 102 if (fs->fs_passno > passno && fs->fs_passno < nextpass) 103 nextpass = fs->fs_passno; 104 105 if (passno != fs->fs_passno) 106 continue; 107 108 qfu = NULL; 109 if (uflag) 110 qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR); 111 qfg = NULL; 112 if (gflag) 113 qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR); 114 if (qfu == NULL && qfg == NULL) 115 continue; 116 117 if (passno == 1) { 118 sumstatus = chkquota(fs->fs_spec, qfu, qfg); 119 if (qfu) 120 quota_close(qfu); 121 if (qfg) 122 quota_close(qfg); 123 if (sumstatus) 124 return (sumstatus); 125 continue; 126 } 127 addpart(fs, qfu, qfg); 128 } 129 130 if (passno == 1) 131 continue; 132 133 TAILQ_FOREACH(nextdisk, &diskh, d_entries) { 134 if ((ret = startdisk(nextdisk)) != 0) 135 return ret; 136 } 137 138 while ((pid = wait(&status)) != -1) { 139 TAILQ_FOREACH(d, &diskh, d_entries) 140 if (d->d_pid == pid) 141 break; 142 143 if (d == NULL) { 144 warnx("Unknown pid %d\n", pid); 145 continue; 146 } 147 148 if (WIFEXITED(status)) 149 retcode = WEXITSTATUS(status); 150 else 151 retcode = 0; 152 153 p = TAILQ_FIRST(&d->d_part); 154 155 if (WIFSIGNALED(status)) { 156 (void) fprintf(stderr, 157 "%s: (%s): EXITED WITH SIGNAL %d\n", 158 p->p_devname, p->p_mntpt, 159 WTERMSIG(status)); 160 retcode = 8; 161 } 162 163 TAILQ_REMOVE(&d->d_part, p, p_entries); 164 165 if (retcode != 0) { 166 TAILQ_INSERT_TAIL(&badh, p, p_entries); 167 sumstatus |= retcode; 168 } else { 169 free(p->p_devname); 170 if (p->p_qfu) 171 quota_close(p->p_qfu); 172 if (p->p_qfg) 173 quota_close(p->p_qfg); 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", p->p_devname, p->p_mntpt, 200 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(struct fstab *fs, struct quotafile *qfu, struct quotafile *qfg) 246 { 247 struct diskentry *d = finddisk(fs->fs_spec); 248 struct partentry *p; 249 250 TAILQ_FOREACH(p, &d->d_part, p_entries) 251 if (strcmp(p->p_devname, fs->fs_spec) == 0) { 252 warnx("%s in fstab more than once!\n", fs->fs_spec); 253 return; 254 } 255 256 p = emalloc(sizeof(*p)); 257 p->p_devname = estrdup(blockcheck(fs->fs_spec)); 258 if (qfu != NULL) 259 p->p_mntpt = quota_fsname(qfu); 260 else 261 p->p_mntpt = quota_fsname(qfg); 262 p->p_qfu = qfu; 263 p->p_qfg = qfg; 264 265 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); 266 } 267 268 269 static int 270 startdisk(struct diskentry *d) 271 { 272 struct partentry *p = TAILQ_FIRST(&d->d_part); 273 274 d->d_pid = fork(); 275 if (d->d_pid < 0) { 276 perror("fork"); 277 return (8); 278 } 279 if (d->d_pid == 0) 280 exit(chkquota(p->p_devname, p->p_qfu, p->p_qfg)); 281 return (0); 282 } 283