]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sbin/quotacheck/preen.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 <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 }