]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/quotacheck/preen.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sbin / quotacheck / preen.c
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()) != 0) {
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 }