preen.c revision 75936
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 75936 2001-04-25 07:18:22Z mckusick $
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 __P((const char *));
83static void addpart __P((const char *, const char *, const char *));
84static int startdisk __P((struct diskentry *,
85    int (*)(const char *, const char *, const char *, char *, pid_t *)));
86static void printpart __P((void));
87
88int
89checkfstab(flags, docheck, checkit)
90	int flags;
91	int (*docheck) __P((struct fstab *));
92	int (*checkit) __P((const char *, const char *, const char *, char *,
93	    pid_t *));
94{
95	struct fstab *fs;
96	struct diskentry *d, *nextdisk;
97	struct partentry *p;
98	int ret, pid, retcode, passno, sumstatus, status, nextpass;
99	const char *name;
100
101	TAILQ_INIT(&badh);
102	TAILQ_INIT(&diskh);
103
104	sumstatus = 0;
105
106	nextpass = 0;
107	for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
108		if (flags & CHECK_DEBUG)
109			printf("pass %d\n", passno);
110
111		nextpass = INT_MAX;
112		if (setfsent() == 0) {
113			warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
114			return (8);
115		}
116		while ((fs = getfsent()) != 0) {
117			name = fs->fs_spec;
118			if (fs->fs_passno > passno && fs->fs_passno < nextpass)
119				nextpass = fs->fs_passno;
120
121			if (passno != fs->fs_passno || (*docheck)(fs) == 0)
122				continue;
123
124			if (flags & CHECK_DEBUG)
125				printf("pass %d, name %s\n", passno, name);
126
127			if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
128			    (flags & DO_BACKGRD) != 0) {
129				if (name == NULL) {
130					if (flags & CHECK_PREEN)
131						return 8;
132					else
133						continue;
134				}
135				sumstatus = (*checkit)(fs->fs_vfstype,
136				    name, fs->fs_file, NULL, NULL);
137
138				if (sumstatus)
139					return (sumstatus);
140				continue;
141			}
142			if (name == NULL) {
143				(void) fprintf(stderr,
144				    "BAD DISK NAME %s\n", fs->fs_spec);
145				sumstatus |= 8;
146				continue;
147			}
148			addpart(fs->fs_vfstype, name, fs->fs_file);
149		}
150
151		if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
152		    (flags & DO_BACKGRD) != 0)
153			continue;
154
155		if (flags & CHECK_DEBUG) {
156			printf("Parallel start\n");
157			printpart();
158		}
159
160		TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
161			if ((ret = startdisk(nextdisk, checkit)) != 0)
162				return ret;
163		}
164
165		if (flags & CHECK_DEBUG)
166			printf("Parallel wait\n");
167		while ((pid = wait(&status)) != -1) {
168			TAILQ_FOREACH(d, &diskh, d_entries)
169				if (d->d_pid == pid)
170					break;
171
172			if (d == NULL) {
173				warnx("Unknown pid %d\n", pid);
174				continue;
175			}
176
177			if (WIFEXITED(status))
178				retcode = WEXITSTATUS(status);
179			else
180				retcode = 0;
181
182			p = TAILQ_FIRST(&d->d_part);
183
184			if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
185				(void) printf("done %s: %s (%s) = 0x%x\n",
186				    p->p_type, p->p_devname, p->p_mntpt,
187				    status);
188
189			if (WIFSIGNALED(status)) {
190				(void) fprintf(stderr,
191				    "%s: %s (%s): EXITED WITH SIGNAL %d\n",
192				    p->p_type, p->p_devname, p->p_mntpt,
193				    WTERMSIG(status));
194				retcode = 8;
195			}
196
197			TAILQ_REMOVE(&d->d_part, p, p_entries);
198
199			if (retcode != 0) {
200				TAILQ_INSERT_TAIL(&badh, p, p_entries);
201				sumstatus |= retcode;
202			} else {
203				free(p->p_type);
204				free(p->p_devname);
205				free(p);
206			}
207			d->d_pid = 0;
208			nrun--;
209
210			if (TAILQ_EMPTY(&d->d_part)) {
211				TAILQ_REMOVE(&diskh, d, d_entries);
212				ndisks--;
213			} else {
214				if ((ret = startdisk(d, checkit)) != 0)
215					return ret;
216			}
217		}
218		if (flags & CHECK_DEBUG) {
219			printf("Parallel end\n");
220			printpart();
221		}
222	}
223
224	if (!(flags & CHECK_PREEN))
225			return 0;
226
227	if (sumstatus) {
228		p = TAILQ_FIRST(&badh);
229		if (p == NULL)
230			return (sumstatus);
231
232		(void) fprintf(stderr,
233			"THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
234			TAILQ_NEXT(p, p_entries) ? "S" : "",
235			"UNEXPECTED INCONSISTENCY:");
236
237		for (; p; p = TAILQ_NEXT(p, p_entries))
238			(void) fprintf(stderr,
239			    "%s: %s (%s)%s", p->p_type, p->p_devname,
240			    p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
241
242		return sumstatus;
243	}
244	(void) endfsent();
245	return (0);
246}
247
248
249static struct diskentry *
250finddisk(name)
251	const char *name;
252{
253	const char *p;
254	size_t len = 0;
255	struct diskentry *d;
256
257	p = strrchr(name, '/');
258	if (p == NULL)
259		p = name;
260	else
261		p++;
262	for (; *p && !isdigit(*p); p++)
263		continue;
264	for (; *p && isdigit(*p); p++)
265		continue;
266	len = p - name;
267	if (len == 0)
268		len = strlen(name);
269
270	TAILQ_FOREACH(d, &diskh, d_entries)
271		if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
272			return d;
273
274	d = emalloc(sizeof(*d));
275	d->d_name = estrdup(name);
276	d->d_name[len] = '\0';
277	TAILQ_INIT(&d->d_part);
278	d->d_pid = 0;
279
280	TAILQ_INSERT_TAIL(&diskh, d, d_entries);
281	ndisks++;
282
283	return d;
284}
285
286
287static void
288printpart()
289{
290	struct diskentry *d;
291	struct partentry *p;
292
293	TAILQ_FOREACH(d, &diskh, d_entries) {
294		(void) printf("disk %s: ", d->d_name);
295		TAILQ_FOREACH(p, &d->d_part, p_entries)
296			(void) printf("%s ", p->p_devname);
297		(void) printf("\n");
298	}
299}
300
301
302static void
303addpart(type, devname, mntpt)
304	const char *type, *devname, *mntpt;
305{
306	struct diskentry *d = finddisk(devname);
307	struct partentry *p;
308
309	TAILQ_FOREACH(p, &d->d_part, p_entries)
310		if (strcmp(p->p_devname, devname) == 0) {
311			warnx("%s in fstab more than once!\n", devname);
312			return;
313		}
314
315	p = emalloc(sizeof(*p));
316	p->p_devname = estrdup(devname);
317	p->p_mntpt = estrdup(mntpt);
318	p->p_type = estrdup(type);
319
320	TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
321}
322
323
324static int
325startdisk(d, checkit)
326	struct diskentry *d;
327	int (*checkit) __P((const char *, const char *, const char *, char *,
328	    pid_t *));
329{
330	struct partentry *p = TAILQ_FIRST(&d->d_part);
331	int rv;
332
333	while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
334	    NULL, &d->d_pid)) != 0 && nrun > 0)
335		sleep(10);
336
337	if (rv == 0)
338		nrun++;
339
340	return rv;
341}
342