preen.c revision 1.15 1 /* $NetBSD: preen.c,v 1.15 1996/09/28 19:21:42 christos 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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)preen.c 8.3 (Berkeley) 12/6/94";
39 #else
40 static char rcsid[] = "$NetBSD: preen.c,v 1.15 1996/09/28 19:21:42 christos Exp $";
41 #endif
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
47 #include <sys/queue.h>
48
49 #include <fstab.h>
50 #include <string.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <ctype.h>
54 #include <unistd.h>
55 #include <err.h>
56
57 #include "fsutil.h"
58
59 struct partentry {
60 TAILQ_ENTRY(partentry) p_entries;
61 char *p_devname; /* device name */
62 char *p_mntpt; /* mount point */
63 char *p_type; /* filesystem type */
64 void *p_auxarg; /* auxiliary argument */
65 };
66
67 TAILQ_HEAD(part, partentry) badh;
68
69 struct diskentry {
70 TAILQ_ENTRY(diskentry) d_entries;
71 char *d_name; /* disk base name */
72 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */
73 int d_pid; /* 0 or pid of fsck proc */
74 };
75
76 TAILQ_HEAD(disk, diskentry) diskh;
77
78 static int nrun = 0, ndisks = 0;
79
80 static struct diskentry *finddisk __P((const char *));
81 static void addpart __P((const char *, const char *, const char *, void *));
82 static int startdisk __P((struct diskentry *,
83 int (*)(const char *, const char *, const char *, void *, pid_t *)));
84 static void printpart __P((void));
85
86 int
87 checkfstab(flags, maxrun, docheck, checkit)
88 int flags, maxrun;
89 void *(*docheck) __P((struct fstab *));
90 int (*checkit) __P((const char *, const char *, const char *, void *,
91 pid_t *));
92 {
93 struct fstab *fs;
94 struct diskentry *d, *nextdisk;
95 struct partentry *p;
96 int ret, pid, retcode, passno, sumstatus, status;
97 void *auxarg;
98 char *name;
99
100 TAILQ_INIT(&badh);
101 TAILQ_INIT(&diskh);
102
103 sumstatus = 0;
104
105 for (passno = 1; passno <= 2; passno++) {
106 if (setfsent() == 0) {
107 warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
108 return (8);
109 }
110 while ((fs = getfsent()) != 0) {
111 if ((auxarg = (*docheck)(fs)) == NULL)
112 continue;
113
114 name = blockcheck(fs->fs_spec);
115 if (flags & CHECK_DEBUG)
116 printf("pass %d, name %s\n", passno, name);
117
118 if ((flags & CHECK_PREEN) == 0 ||
119 (passno == 1 && fs->fs_passno == 1)) {
120 if (name == NULL) {
121 if (flags & CHECK_PREEN)
122 return 8;
123 else
124 continue;
125 }
126 sumstatus = (*checkit)(fs->fs_vfstype,
127 name, fs->fs_file, auxarg, NULL);
128
129 if (sumstatus)
130 return (sumstatus);
131 } else if (passno == 2 && fs->fs_passno > 1) {
132 if (name == NULL) {
133 (void) fprintf(stderr,
134 "BAD DISK NAME %s\n", fs->fs_spec);
135 sumstatus |= 8;
136 continue;
137 }
138 addpart(fs->fs_vfstype, name, fs->fs_file,
139 auxarg);
140 }
141 }
142 if ((flags & CHECK_PREEN) == 0)
143 return 0;
144 }
145
146 if (flags & CHECK_DEBUG)
147 printpart();
148
149 if (flags & CHECK_PREEN) {
150 if (maxrun == 0)
151 maxrun = ndisks;
152 if (maxrun > ndisks)
153 maxrun = ndisks;
154 nextdisk = diskh.tqh_first;
155 for (passno = 0; passno < maxrun; ++passno) {
156 if ((ret = startdisk(nextdisk, checkit)) != 0)
157 return ret;
158 nextdisk = nextdisk->d_entries.tqe_next;
159 }
160
161 while ((pid = wait(&status)) != -1) {
162 for (d = diskh.tqh_first; d; d = d->d_entries.tqe_next)
163 if (d->d_pid == pid)
164 break;
165
166 if (d == NULL) {
167 warnx("Unknown pid %d\n", pid);
168 continue;
169 }
170
171
172 if (WIFEXITED(status))
173 retcode = WEXITSTATUS(status);
174 else
175 retcode = 0;
176
177 p = d->d_part.tqh_first;
178
179 if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
180 (void) printf("done %s: %s (%s) = %x\n",
181 p->p_type, p->p_devname, p->p_mntpt,
182 status);
183
184 if (WIFSIGNALED(status)) {
185 (void) fprintf(stderr,
186 "%s: %s (%s): EXITED WITH SIGNAL %d\n",
187 p->p_type, p->p_devname, p->p_mntpt,
188 WTERMSIG(status));
189 retcode = 8;
190 }
191
192 TAILQ_REMOVE(&d->d_part, p, p_entries);
193
194 if (retcode != 0) {
195 TAILQ_INSERT_TAIL(&badh, p, p_entries);
196 sumstatus |= retcode;
197 } else {
198 free(p->p_type);
199 free(p->p_devname);
200 free(p);
201 }
202 d->d_pid = 0;
203 nrun--;
204
205 if (d->d_part.tqh_first == NULL)
206 ndisks--;
207
208 if (nextdisk == NULL) {
209 if (d->d_part.tqh_first) {
210 if ((ret = startdisk(d, checkit)) != 0)
211 return ret;
212 }
213 } else if (nrun < maxrun && nrun < ndisks) {
214 for ( ;; ) {
215 nextdisk = nextdisk->d_entries.tqe_next;
216 if (nextdisk == NULL)
217 nextdisk = diskh.tqh_first;
218 if (nextdisk->d_part.tqh_first != NULL
219 && nextdisk->d_pid == 0)
220 break;
221 }
222 if ((ret = startdisk(nextdisk, checkit)) != 0)
223 return ret;
224 }
225 }
226 }
227 if (sumstatus) {
228 p = badh.tqh_first;
229 if (p == NULL)
230 return (sumstatus);
231
232 (void) fprintf(stderr,
233 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
234 p->p_entries.tqe_next ? "S" : "",
235 "UNEXPECTED INCONSISTENCY:");
236
237 for (; p; p = p->p_entries.tqe_next)
238 (void) fprintf(stderr,
239 "%s: %s (%s)%s", p->p_type, p->p_devname,
240 p->p_mntpt, p->p_entries.tqe_next ? ", " : "\n");
241
242 return sumstatus;
243 }
244 (void) endfsent();
245 return (0);
246 }
247
248
249 static struct diskentry *
250 finddisk(name)
251 const char *name;
252 {
253 const char *p;
254 size_t len;
255 struct diskentry *d;
256
257 for (p = name + strlen(name) - 1; p >= name; --p)
258 if (isdigit(*p)) {
259 len = p - name + 1;
260 break;
261 }
262
263 if (p < name)
264 len = strlen(name);
265
266 for (d = diskh.tqh_first; d != NULL; d = d->d_entries.tqe_next)
267 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
268 return d;
269
270 d = emalloc(sizeof(*d));
271 d->d_name = estrdup(name);
272 d->d_name[len] = '\0';
273 TAILQ_INIT(&d->d_part);
274 d->d_pid = 0;
275
276 TAILQ_INSERT_TAIL(&diskh, d, d_entries);
277 ndisks++;
278
279 return d;
280 }
281
282
283 static void
284 printpart()
285 {
286 struct diskentry *d;
287 struct partentry *p;
288
289 for (d = diskh.tqh_first; d != NULL; d = d->d_entries.tqe_next) {
290 (void) printf("disk %s: ", d->d_name);
291 for (p = d->d_part.tqh_first; p != NULL;
292 p = p->p_entries.tqe_next)
293 (void) printf("%s ", p->p_devname);
294 (void) printf("\n");
295 }
296 }
297
298
299 static void
300 addpart(type, devname, mntpt, auxarg)
301 const char *type, *devname, *mntpt;
302 void *auxarg;
303 {
304 struct diskentry *d = finddisk(devname);
305 struct partentry *p;
306
307 for (p = d->d_part.tqh_first; p != NULL; p = p->p_entries.tqe_next)
308 if (strcmp(p->p_devname, devname) == 0) {
309 warnx("%s in fstab more than once!\n", devname);
310 return;
311 }
312
313 p = emalloc(sizeof(*p));
314 p->p_devname = estrdup(devname);
315 p->p_mntpt = estrdup(mntpt);
316 p->p_type = estrdup(type);
317 p->p_auxarg = auxarg;
318
319 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
320 }
321
322
323 static int
324 startdisk(d, checkit)
325 register struct diskentry *d;
326 int (*checkit) __P((const char *, const char *, const char *, void *,
327 pid_t *));
328 {
329 register struct partentry *p = d->d_part.tqh_first;
330 int rv;
331
332 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
333 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
334 sleep(10);
335
336 if (rv == 0)
337 nrun++;
338
339 return rv;
340 }
341