preen.c revision 1.28 1 /* $NetBSD: preen.c,v 1.28 2006/08/26 18:14:28 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. 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
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95";
36 #else
37 __RCSID("$NetBSD: preen.c,v 1.28 2006/08/26 18:14:28 christos Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <sys/queue.h>
45
46 #include <err.h>
47 #include <ctype.h>
48 #include <fstab.h>
49 #include <string.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <util.h>
54
55 #include "fsutil.h"
56
57 struct partentry {
58 TAILQ_ENTRY(partentry) p_entries;
59 char *p_devname; /* device name */
60 char *p_mntpt; /* mount point */
61 char *p_type; /* file system type */
62 void *p_auxarg; /* auxiliary argument */
63 };
64
65 TAILQ_HEAD(part, partentry) badh;
66
67 struct diskentry {
68 TAILQ_ENTRY(diskentry) d_entries;
69 char *d_name; /* disk base name */
70 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */
71 int d_pid; /* 0 or pid of fsck proc */
72 };
73
74 TAILQ_HEAD(disk, diskentry) diskh;
75
76 static int nrun = 0, ndisks = 0;
77
78 static struct diskentry *finddisk(const char *);
79 static void addpart(const char *, const char *, const char *, void *);
80 static int startdisk(struct diskentry *,
81 int (*)(const char *, const char *, const char *, void *, pid_t *));
82 static void printpart(void);
83
84 int
85 checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *),
86 int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
87 {
88 struct fstab *fs;
89 struct diskentry *d, *nextdisk;
90 struct partentry *p;
91 int ret, pid, retcode, passno, sumstatus, status;
92 void *auxarg;
93 const char *name;
94 int error = 0;
95
96 TAILQ_INIT(&badh);
97 TAILQ_INIT(&diskh);
98
99 sumstatus = 0;
100
101 for (passno = 1; passno <= 2; passno++) {
102 if (setfsent() == 0) {
103 warnx("Can't open checklist file: %s", _PATH_FSTAB);
104 return (8);
105 }
106 while ((fs = getfsent()) != 0) {
107 if ((auxarg = (*docheck)(fs)) == NULL)
108 continue;
109
110 name = blockcheck(fs->fs_spec);
111 if (flags & CHECK_DEBUG)
112 printf("pass %d, name %s\n", passno, name);
113
114 if ((flags & CHECK_PREEN) == 0 ||
115 (passno == 1 && fs->fs_passno == 1)) {
116 if (name == NULL) {
117 if (flags & CHECK_PREEN)
118 return 8;
119 else
120 continue;
121 }
122 sumstatus = (*checkit)(fs->fs_vfstype,
123 name, fs->fs_file, auxarg, NULL);
124
125 if (sumstatus) {
126 if ((flags & CHECK_NOFIX) == 0)
127 return (sumstatus);
128 else
129 error |= sumstatus;
130 }
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 error;
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 = TAILQ_FIRST(&diskh);
155 for (passno = 0; passno < maxrun; ++passno) {
156 if ((ret = startdisk(nextdisk, checkit)) != 0) {
157 if ((flags & CHECK_NOFIX) == 0)
158 return ret;
159 else
160 error |= ret;
161 }
162 nextdisk = TAILQ_NEXT(nextdisk, d_entries);
163 }
164
165 while ((pid = wait(&status)) != -1) {
166 TAILQ_FOREACH(d, &diskh, d_entries)
167 if (d->d_pid == pid)
168 break;
169
170 if (d == NULL) {
171 warnx("Unknown pid %d", pid);
172 continue;
173 }
174
175
176 if (WIFEXITED(status))
177 retcode = WEXITSTATUS(status);
178 else
179 retcode = 0;
180
181 p = TAILQ_FIRST(&d->d_part);
182
183 if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
184 (void) printf("done %s: %s (%s) = 0x%x\n",
185 p->p_type, p->p_devname, p->p_mntpt,
186 status);
187
188 if (WIFSIGNALED(status)) {
189 (void) fprintf(stderr,
190 "%s: %s (%s): EXITED WITH SIGNAL %d\n",
191 p->p_type, p->p_devname, p->p_mntpt,
192 WTERMSIG(status));
193 retcode = 8;
194 }
195
196 TAILQ_REMOVE(&d->d_part, p, p_entries);
197
198 if (retcode != 0) {
199 TAILQ_INSERT_TAIL(&badh, p, p_entries);
200 sumstatus |= retcode;
201 } else {
202 free(p->p_type);
203 free(p->p_devname);
204 free(p);
205 }
206 d->d_pid = 0;
207 nrun--;
208
209 if (TAILQ_FIRST(&d->d_part) == NULL)
210 ndisks--;
211
212 if (nextdisk == NULL) {
213 if (TAILQ_FIRST(&d->d_part) != NULL) {
214 if ((ret = startdisk(d, checkit)) != 0)
215 {
216 if ((flags & CHECK_NOFIX) == 0)
217 return ret;
218 else
219 error |= ret;
220 }
221 }
222 } else if (nrun < maxrun && nrun < ndisks) {
223 for ( ;; ) {
224 nextdisk = TAILQ_NEXT(nextdisk,
225 d_entries);
226 if (nextdisk == NULL)
227 nextdisk = TAILQ_FIRST(&diskh);
228 if (TAILQ_FIRST(&nextdisk->d_part)
229 != NULL && nextdisk->d_pid == 0)
230 break;
231 }
232 if ((ret = startdisk(nextdisk, checkit)) != 0)
233 {
234 if ((flags & CHECK_NOFIX) == 0)
235 return ret;
236 else
237 error |= ret;
238 }
239 }
240 }
241 }
242 if (sumstatus) {
243 p = TAILQ_FIRST(&badh);
244 if (p == NULL)
245 return (sumstatus);
246
247 (void) fprintf(stderr,
248 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
249 TAILQ_NEXT(p, p_entries) ? "S" : "",
250 "UNEXPECTED INCONSISTENCY:");
251
252 TAILQ_FOREACH(p, &badh, p_entries)
253 (void) fprintf(stderr,
254 "%s: %s (%s)%s", p->p_type, p->p_devname,
255 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
256
257 return sumstatus;
258 }
259 (void) endfsent();
260 return error;
261 }
262
263
264 static struct diskentry *
265 finddisk(const char *name)
266 {
267 const char *p;
268 size_t len = 0;
269 struct diskentry *d;
270
271 for (len = strlen(name), p = name + len - 1; p >= name; --p)
272 if (isdigit((unsigned char)*p)) {
273 len = p - name + 1;
274 break;
275 }
276 if (p < name)
277 len = strlen(name);
278
279 TAILQ_FOREACH(d, &diskh, d_entries)
280 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
281 return d;
282
283 d = emalloc(sizeof(*d));
284 d->d_name = estrdup(name);
285 d->d_name[len] = '\0';
286 TAILQ_INIT(&d->d_part);
287 d->d_pid = 0;
288
289 TAILQ_INSERT_TAIL(&diskh, d, d_entries);
290 ndisks++;
291
292 return d;
293 }
294
295
296 static void
297 printpart(void)
298 {
299 struct diskentry *d;
300 struct partentry *p;
301
302 TAILQ_FOREACH(d, &diskh, d_entries) {
303 (void) printf("disk %s: ", d->d_name);
304 TAILQ_FOREACH(p, &d->d_part, p_entries)
305 (void) printf("%s ", p->p_devname);
306 (void) printf("\n");
307 }
308 }
309
310
311 static void
312 addpart(const char *type, const char *dev, const char *mntpt, void *auxarg)
313 {
314 struct diskentry *d = finddisk(dev);
315 struct partentry *p;
316
317 TAILQ_FOREACH(p, &d->d_part, p_entries)
318 if (strcmp(p->p_devname, dev) == 0) {
319 warnx("%s in fstab more than once!", dev);
320 return;
321 }
322
323 p = emalloc(sizeof(*p));
324 p->p_devname = estrdup(dev);
325 p->p_mntpt = estrdup(mntpt);
326 p->p_type = estrdup(type);
327 p->p_auxarg = auxarg;
328
329 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
330 }
331
332
333 static int
334 startdisk(struct diskentry *d,
335 int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
336 {
337 struct partentry *p = TAILQ_FIRST(&d->d_part);
338 int rv;
339
340 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
341 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
342 sleep(10);
343
344 if (rv == 0)
345 nrun++;
346
347 return rv;
348 }
349