preen.c revision 92839
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 * 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 * $FreeBSD: head/sbin/fsck/preen.c 92839 2002-03-20 22:57:10Z imp $
36 */
37
38#include <sys/cdefs.h>
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)preen.c	8.5 (Berkeley) 4/28/95";
42#else
43__RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
44#endif
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/stat.h>
49#include <sys/wait.h>
50#include <sys/queue.h>
51
52#include <err.h>
53#include <ctype.h>
54#include <fstab.h>
55#include <string.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <unistd.h>
59
60#include "fsutil.h"
61
62struct partentry {
63	TAILQ_ENTRY(partentry)	 p_entries;
64	char		  	*p_devname;	/* device name */
65	char			*p_mntpt;	/* mount point */
66	char		  	*p_type;	/* filesystem type */
67};
68
69TAILQ_HEAD(part, partentry) badh;
70
71struct 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 */
76};
77
78TAILQ_HEAD(disk, diskentry) diskh;
79
80static int nrun = 0, ndisks = 0;
81
82static struct diskentry *finddisk(const char *);
83static void addpart(const char *, const char *, const char *);
84static int startdisk(struct diskentry *,
85    int (*)(const char *, const char *, const char *, char *, pid_t *));
86static void printpart(void);
87
88int
89checkfstab(int flags, int (*docheck)(struct fstab *),
90    int (*checkit)(const char *, const char *, const char *, char *, pid_t *))
91{
92	struct fstab *fs;
93	struct diskentry *d, *nextdisk;
94	struct partentry *p;
95	int ret, pid, retcode, passno, sumstatus, status, nextpass;
96	const char *name;
97
98	TAILQ_INIT(&badh);
99	TAILQ_INIT(&diskh);
100
101	sumstatus = 0;
102
103	nextpass = 0;
104	for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
105		if (flags & CHECK_DEBUG)
106			printf("pass %d\n", passno);
107
108		nextpass = INT_MAX;
109		if (setfsent() == 0) {
110			warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
111			return (8);
112		}
113		while ((fs = getfsent()) != 0) {
114			name = fs->fs_spec;
115			if (fs->fs_passno > passno && fs->fs_passno < nextpass)
116				nextpass = fs->fs_passno;
117
118			if (passno != fs->fs_passno || (*docheck)(fs) == 0)
119				continue;
120
121			if (flags & CHECK_DEBUG)
122				printf("pass %d, name %s\n", passno, name);
123
124			if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
125			    (flags & DO_BACKGRD) != 0) {
126				if (name == NULL) {
127					if (flags & CHECK_PREEN)
128						return 8;
129					else
130						continue;
131				}
132				sumstatus = (*checkit)(fs->fs_vfstype,
133				    name, fs->fs_file, NULL, NULL);
134
135				if (sumstatus)
136					return (sumstatus);
137				continue;
138			}
139			if (name == NULL) {
140				(void) fprintf(stderr,
141				    "BAD DISK NAME %s\n", fs->fs_spec);
142				sumstatus |= 8;
143				continue;
144			}
145			addpart(fs->fs_vfstype, name, fs->fs_file);
146		}
147
148		if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
149		    (flags & DO_BACKGRD) != 0)
150			continue;
151
152		if (flags & CHECK_DEBUG) {
153			printf("Parallel start\n");
154			printpart();
155		}
156
157		TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
158			if ((ret = startdisk(nextdisk, checkit)) != 0)
159				return ret;
160		}
161
162		if (flags & CHECK_DEBUG)
163			printf("Parallel wait\n");
164		while ((pid = wait(&status)) != -1) {
165			TAILQ_FOREACH(d, &diskh, d_entries)
166				if (d->d_pid == pid)
167					break;
168
169			if (d == NULL) {
170				warnx("Unknown pid %d\n", pid);
171				continue;
172			}
173
174			if (WIFEXITED(status))
175				retcode = WEXITSTATUS(status);
176			else
177				retcode = 0;
178
179			p = TAILQ_FIRST(&d->d_part);
180
181			if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
182				(void) printf("done %s: %s (%s) = 0x%x\n",
183				    p->p_type, p->p_devname, p->p_mntpt,
184				    status);
185
186			if (WIFSIGNALED(status)) {
187				(void) fprintf(stderr,
188				    "%s: %s (%s): EXITED WITH SIGNAL %d\n",
189				    p->p_type, p->p_devname, p->p_mntpt,
190				    WTERMSIG(status));
191				retcode = 8;
192			}
193
194			TAILQ_REMOVE(&d->d_part, p, p_entries);
195
196			if (retcode != 0) {
197				TAILQ_INSERT_TAIL(&badh, p, p_entries);
198				sumstatus |= retcode;
199			} else {
200				free(p->p_type);
201				free(p->p_devname);
202				free(p);
203			}
204			d->d_pid = 0;
205			nrun--;
206
207			if (TAILQ_EMPTY(&d->d_part)) {
208				TAILQ_REMOVE(&diskh, d, d_entries);
209				ndisks--;
210			} else {
211				if ((ret = startdisk(d, checkit)) != 0)
212					return ret;
213			}
214		}
215		if (flags & CHECK_DEBUG) {
216			printf("Parallel end\n");
217			printpart();
218		}
219	}
220
221	if (!(flags & CHECK_PREEN))
222			return 0;
223
224	if (sumstatus) {
225		p = TAILQ_FIRST(&badh);
226		if (p == NULL)
227			return (sumstatus);
228
229		(void) fprintf(stderr,
230			"THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
231			TAILQ_NEXT(p, p_entries) ? "S" : "",
232			"UNEXPECTED INCONSISTENCY:");
233
234		for (; p; p = TAILQ_NEXT(p, p_entries))
235			(void) fprintf(stderr,
236			    "%s: %s (%s)%s", p->p_type, p->p_devname,
237			    p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
238
239		return sumstatus;
240	}
241	(void) endfsent();
242	return (0);
243}
244
245
246static struct diskentry *
247finddisk(const char *name)
248{
249	const char *p;
250	size_t len = 0;
251	struct diskentry *d;
252
253	p = strrchr(name, '/');
254	if (p == NULL)
255		p = name;
256	else
257		p++;
258	for (; *p && !isdigit(*p); p++)
259		continue;
260	for (; *p && isdigit(*p); p++)
261		continue;
262	len = p - name;
263	if (len == 0)
264		len = strlen(name);
265
266	TAILQ_FOREACH(d, &diskh, d_entries)
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
283static void
284printpart(void)
285{
286	struct diskentry *d;
287	struct partentry *p;
288
289	TAILQ_FOREACH(d, &diskh, d_entries) {
290		(void) printf("disk %s: ", d->d_name);
291		TAILQ_FOREACH(p, &d->d_part, p_entries)
292			(void) printf("%s ", p->p_devname);
293		(void) printf("\n");
294	}
295}
296
297
298static void
299addpart(const char *type, const char *devname, const char *mntpt)
300{
301	struct diskentry *d = finddisk(devname);
302	struct partentry *p;
303
304	TAILQ_FOREACH(p, &d->d_part, p_entries)
305		if (strcmp(p->p_devname, devname) == 0) {
306			warnx("%s in fstab more than once!\n", devname);
307			return;
308		}
309
310	p = emalloc(sizeof(*p));
311	p->p_devname = estrdup(devname);
312	p->p_mntpt = estrdup(mntpt);
313	p->p_type = estrdup(type);
314
315	TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
316}
317
318
319static int
320startdisk(struct diskentry *d, int (*checkit)(const char *, const char *,
321    const char *, char *, pid_t *))
322{
323	struct partentry *p = TAILQ_FIRST(&d->d_part);
324	int rv;
325
326	while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
327	    NULL, &d->d_pid)) != 0 && nrun > 0)
328		sleep(10);
329
330	if (rv == 0)
331		nrun++;
332
333	return rv;
334}
335