snj doesn't like my accent, so use proper English month names.
[netbsd-mini2440.git] / sbin / fsck / preen.c
blob6eb3a6975db0e42d7840694cbd17aa3f6f97c9b7
1 /* $NetBSD: preen.c,v 1.29 2006/08/26 21:54:05 christos Exp $ */
3 /*
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
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 */
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>
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>
58 #include "fsutil.h"
59 #include "exitvalues.h"
61 struct partentry {
62 TAILQ_ENTRY(partentry) p_entries;
63 char *p_devname; /* device name */
64 char *p_mntpt; /* mount point */
65 char *p_type; /* file system type */
66 void *p_auxarg; /* auxiliary argument */
69 TAILQ_HEAD(part, partentry) badh;
71 struct diskentry {
72 TAILQ_ENTRY(diskentry) d_entries;
73 char *d_name; /* disk base name */
74 TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */
75 int d_pid; /* 0 or pid of fsck proc */
78 TAILQ_HEAD(diskinfo, diskentry) diskh;
80 static int nrun = 0, ndisks = 0;
82 static struct diskentry *finddisk(const char *);
83 static void addpart(const char *, const char *, const char *, void *);
84 static int startdisk(struct diskentry *,
85 int (*)(const char *, const char *, const char *, void *, pid_t *));
86 static void printpart(void);
88 int
89 checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *),
90 int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
92 struct fstab *fs;
93 struct diskentry *d, *nextdisk;
94 struct partentry *p;
95 int ret, pid, retcode, passno, sumstatus, status;
96 void *auxarg;
97 const char *name;
98 int error = FSCK_EXIT_OK;
100 TAILQ_INIT(&badh);
101 TAILQ_INIT(&diskh);
103 sumstatus = FSCK_EXIT_OK;
105 for (passno = 1; passno <= 2; passno++) {
106 if (setfsent() == 0) {
107 warnx("Can't open checklist file: %s", _PATH_FSTAB);
108 return FSCK_EXIT_CHECK_FAILED;
110 while ((fs = getfsent()) != 0) {
111 if ((auxarg = (*docheck)(fs)) == NULL)
112 continue;
114 name = blockcheck(fs->fs_spec);
115 if (flags & CHECK_DEBUG)
116 printf("pass %d, name %s\n", passno, name);
118 if ((flags & CHECK_PREEN) == 0 ||
119 (passno == 1 && fs->fs_passno == 1)) {
120 if (name == NULL) {
121 if (flags & CHECK_PREEN)
122 return FSCK_EXIT_CHECK_FAILED;
123 else
124 continue;
126 sumstatus = (*checkit)(fs->fs_vfstype,
127 name, fs->fs_file, auxarg, NULL);
129 if (sumstatus) {
130 if ((flags & CHECK_NOFIX) == 0)
131 return sumstatus;
132 else if (error < sumstatus)
133 error = sumstatus;
135 } else if (passno == 2 && fs->fs_passno > 1) {
136 if (name == NULL) {
137 (void) fprintf(stderr,
138 "BAD DISK NAME %s\n", fs->fs_spec);
139 sumstatus = FSCK_EXIT_CHECK_FAILED;
140 continue;
142 addpart(fs->fs_vfstype, name, fs->fs_file,
143 auxarg);
146 if ((flags & CHECK_PREEN) == 0)
147 return error;
150 if (flags & CHECK_DEBUG)
151 printpart();
153 if (flags & CHECK_PREEN) {
154 if (maxrun == 0)
155 maxrun = ndisks;
156 if (maxrun > ndisks)
157 maxrun = ndisks;
158 nextdisk = TAILQ_FIRST(&diskh);
159 for (passno = 0; passno < maxrun; ++passno) {
160 if ((ret = startdisk(nextdisk, checkit)) != 0) {
161 if ((flags & CHECK_NOFIX) == 0)
162 return ret;
163 else if (error < ret)
164 error = ret;
166 nextdisk = TAILQ_NEXT(nextdisk, d_entries);
169 while ((pid = wait(&status)) != -1) {
170 TAILQ_FOREACH(d, &diskh, d_entries)
171 if (d->d_pid == pid)
172 break;
174 if (d == NULL) {
175 warnx("Unknown pid %d", pid);
176 continue;
180 if (WIFEXITED(status))
181 retcode = WEXITSTATUS(status);
182 else
183 retcode = 0;
185 p = TAILQ_FIRST(&d->d_part);
187 if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
188 (void) printf("done %s: %s (%s) = 0x%x\n",
189 p->p_type, p->p_devname, p->p_mntpt,
190 status);
192 if (WIFSIGNALED(status)) {
193 (void) fprintf(stderr,
194 "%s: %s (%s): EXITED WITH SIGNAL %d\n",
195 p->p_type, p->p_devname, p->p_mntpt,
196 WTERMSIG(status));
197 retcode = FSCK_EXIT_SIGNALLED;
200 TAILQ_REMOVE(&d->d_part, p, p_entries);
202 if (retcode != 0) {
203 TAILQ_INSERT_TAIL(&badh, p, p_entries);
204 sumstatus |= retcode;
205 } else {
206 free(p->p_type);
207 free(p->p_devname);
208 free(p);
210 d->d_pid = 0;
211 nrun--;
213 if (TAILQ_FIRST(&d->d_part) == NULL)
214 ndisks--;
216 if (nextdisk == NULL) {
217 if (TAILQ_FIRST(&d->d_part) != NULL) {
218 if ((ret = startdisk(d, checkit)) != 0)
220 if ((flags & CHECK_NOFIX) == 0)
221 return ret;
222 else if (error < ret)
223 error = ret;
226 } else if (nrun < maxrun && nrun < ndisks) {
227 for ( ;; ) {
228 nextdisk = TAILQ_NEXT(nextdisk,
229 d_entries);
230 if (nextdisk == NULL)
231 nextdisk = TAILQ_FIRST(&diskh);
232 if (TAILQ_FIRST(&nextdisk->d_part)
233 != NULL && nextdisk->d_pid == 0)
234 break;
236 if ((ret = startdisk(nextdisk, checkit)) != 0)
238 if ((flags & CHECK_NOFIX) == 0)
239 return ret;
240 else if (error < ret)
241 error = ret;
246 if (sumstatus) {
247 p = TAILQ_FIRST(&badh);
248 if (p == NULL)
249 return sumstatus;
251 (void) fprintf(stderr,
252 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
253 TAILQ_NEXT(p, p_entries) ? "S" : "",
254 "UNEXPECTED INCONSISTENCY:");
256 TAILQ_FOREACH(p, &badh, p_entries)
257 (void) fprintf(stderr,
258 "%s: %s (%s)%s", p->p_type, p->p_devname,
259 p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
261 return sumstatus;
263 (void) endfsent();
264 return error;
268 static struct diskentry *
269 finddisk(const char *name)
271 const char *p;
272 size_t len, dlen;
273 struct diskentry *d;
274 char buf[MAXPATHLEN];
275 struct dkwedge_info dkw;
276 int fd;
278 if ((fd = opendisk(name, O_RDONLY, buf, sizeof(buf), 0)) != -1) {
279 if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1)
280 name = dkw.dkw_parent;
281 (void)close(fd);
284 for (dlen = len = strlen(name), p = name + len - 1; p >= name; --p)
285 if (isdigit((unsigned char)*p)) {
286 len = p - name + 1;
287 break;
289 if (p < name)
290 len = dlen;
292 TAILQ_FOREACH(d, &diskh, d_entries)
293 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
294 return d;
296 d = emalloc(sizeof(*d));
297 d->d_name = estrdup(name);
298 d->d_name[len] = '\0';
299 TAILQ_INIT(&d->d_part);
300 d->d_pid = 0;
302 TAILQ_INSERT_TAIL(&diskh, d, d_entries);
303 ndisks++;
305 return d;
309 static void
310 printpart(void)
312 struct diskentry *d;
313 struct partentry *p;
315 TAILQ_FOREACH(d, &diskh, d_entries) {
316 (void) printf("disk %s:", d->d_name);
317 TAILQ_FOREACH(p, &d->d_part, p_entries)
318 (void) printf(" %s", p->p_devname);
319 (void) printf("\n");
324 static void
325 addpart(const char *type, const char *dev, const char *mntpt, void *auxarg)
327 struct diskentry *d = finddisk(dev);
328 struct partentry *p;
330 TAILQ_FOREACH(p, &d->d_part, p_entries)
331 if (strcmp(p->p_devname, dev) == 0) {
332 warnx("%s in fstab more than once!", dev);
333 return;
336 p = emalloc(sizeof(*p));
337 p->p_devname = estrdup(dev);
338 p->p_mntpt = estrdup(mntpt);
339 p->p_type = estrdup(type);
340 p->p_auxarg = auxarg;
342 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
346 static int
347 startdisk(struct diskentry *d,
348 int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
350 struct partentry *p = TAILQ_FIRST(&d->d_part);
351 int rv;
353 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
354 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
355 sleep(10);
357 if (rv == 0)
358 nrun++;
360 return rv;