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