preen.c revision 92839
166869Sadrian/*	$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $	*/
266869Sadrian
366869Sadrian/*
466869Sadrian * Copyright (c) 1990, 1993
566869Sadrian *	The Regents of the University of California.  All rights reserved.
666869Sadrian *
766869Sadrian * Redistribution and use in source and binary forms, with or without
866869Sadrian * modification, are permitted provided that the following conditions
966869Sadrian * are met:
1066869Sadrian * 1. Redistributions of source code must retain the above copyright
1166869Sadrian *    notice, this list of conditions and the following disclaimer.
1266869Sadrian * 2. Redistributions in binary form must reproduce the above copyright
1366869Sadrian *    notice, this list of conditions and the following disclaimer in the
1466869Sadrian *    documentation and/or other materials provided with the distribution.
1566869Sadrian * 3. All advertising materials mentioning features or use of this software
1666869Sadrian *    must display the following acknowledgement:
1766869Sadrian *	This product includes software developed by the University of
1866869Sadrian *	California, Berkeley and its contributors.
1966869Sadrian * 4. Neither the name of the University nor the names of its contributors
2066869Sadrian *    may be used to endorse or promote products derived from this software
2166869Sadrian *    without specific prior written permission.
2266869Sadrian *
2366869Sadrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2466869Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2566869Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2666869Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2766869Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2866869Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2966869Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3066869Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3166869Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3266869Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3366869Sadrian * SUCH DAMAGE.
3466869Sadrian *
3566869Sadrian * $FreeBSD: head/sbin/fsck/preen.c 92839 2002-03-20 22:57:10Z imp $
3666869Sadrian */
3766869Sadrian
3866869Sadrian#include <sys/cdefs.h>
3966869Sadrian#ifndef lint
4066869Sadrian#if 0
4166869Sadrianstatic char sccsid[] = "@(#)preen.c	8.5 (Berkeley) 4/28/95";
4266869Sadrian#else
4366869Sadrian__RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
4466869Sadrian#endif
4566869Sadrian#endif /* not lint */
4666869Sadrian
4766869Sadrian#include <sys/param.h>
4866869Sadrian#include <sys/stat.h>
4966869Sadrian#include <sys/wait.h>
5066869Sadrian#include <sys/queue.h>
5166869Sadrian
5266869Sadrian#include <err.h>
5366869Sadrian#include <ctype.h>
5466869Sadrian#include <fstab.h>
5566869Sadrian#include <string.h>
5666869Sadrian#include <stdio.h>
5766869Sadrian#include <stdlib.h>
5866869Sadrian#include <unistd.h>
5966869Sadrian
6066869Sadrian#include "fsutil.h"
6166869Sadrian
6266869Sadrianstruct partentry {
6366869Sadrian	TAILQ_ENTRY(partentry)	 p_entries;
6466869Sadrian	char		  	*p_devname;	/* device name */
6566869Sadrian	char			*p_mntpt;	/* mount point */
6666869Sadrian	char		  	*p_type;	/* filesystem type */
6766869Sadrian};
6866869Sadrian
6966869SadrianTAILQ_HEAD(part, partentry) badh;
7066869Sadrian
7166869Sadrianstruct diskentry {
7266869Sadrian	TAILQ_ENTRY(diskentry) 	    d_entries;
7366869Sadrian	char		       	   *d_name;	/* disk base name */
7466869Sadrian	TAILQ_HEAD(prt, partentry)  d_part;	/* list of partitions on disk */
7566869Sadrian	int			    d_pid;	/* 0 or pid of fsck proc */
7666869Sadrian};
7766869Sadrian
7866869SadrianTAILQ_HEAD(disk, diskentry) diskh;
7966869Sadrian
8066869Sadrianstatic int nrun = 0, ndisks = 0;
8166869Sadrian
8292839Simpstatic struct diskentry *finddisk(const char *);
8392839Simpstatic void addpart(const char *, const char *, const char *);
8492839Simpstatic int startdisk(struct diskentry *,
8592839Simp    int (*)(const char *, const char *, const char *, char *, pid_t *));
8692839Simpstatic void printpart(void);
8766869Sadrian
8866869Sadrianint
8992839Simpcheckfstab(int flags, int (*docheck)(struct fstab *),
9092839Simp    int (*checkit)(const char *, const char *, const char *, char *, pid_t *))
9166869Sadrian{
9266869Sadrian	struct fstab *fs;
9366869Sadrian	struct diskentry *d, *nextdisk;
9466869Sadrian	struct partentry *p;
9575015Sphk	int ret, pid, retcode, passno, sumstatus, status, nextpass;
9666869Sadrian	const char *name;
9766869Sadrian
9866869Sadrian	TAILQ_INIT(&badh);
9966869Sadrian	TAILQ_INIT(&diskh);
10066869Sadrian
10166869Sadrian	sumstatus = 0;
10266869Sadrian
10375015Sphk	nextpass = 0;
10475015Sphk	for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
10575015Sphk		if (flags & CHECK_DEBUG)
10675015Sphk			printf("pass %d\n", passno);
10775015Sphk
10875015Sphk		nextpass = INT_MAX;
10966869Sadrian		if (setfsent() == 0) {
11066869Sadrian			warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
11166869Sadrian			return (8);
11266869Sadrian		}
11366869Sadrian		while ((fs = getfsent()) != 0) {
11466869Sadrian			name = fs->fs_spec;
11575015Sphk			if (fs->fs_passno > passno && fs->fs_passno < nextpass)
11675015Sphk				nextpass = fs->fs_passno;
11775015Sphk
11875936Smckusick			if (passno != fs->fs_passno || (*docheck)(fs) == 0)
11975015Sphk				continue;
12075015Sphk
12166869Sadrian			if (flags & CHECK_DEBUG)
12266869Sadrian				printf("pass %d, name %s\n", passno, name);
12366869Sadrian
12475936Smckusick			if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
12575936Smckusick			    (flags & DO_BACKGRD) != 0) {
12666869Sadrian				if (name == NULL) {
12766869Sadrian					if (flags & CHECK_PREEN)
12866869Sadrian						return 8;
12966869Sadrian					else
13066869Sadrian						continue;
13166869Sadrian				}
13266869Sadrian				sumstatus = (*checkit)(fs->fs_vfstype,
13375936Smckusick				    name, fs->fs_file, NULL, NULL);
13466869Sadrian
13566869Sadrian				if (sumstatus)
13666869Sadrian					return (sumstatus);
13775015Sphk				continue;
13875015Sphk			}
13975015Sphk			if (name == NULL) {
14075015Sphk				(void) fprintf(stderr,
14175015Sphk				    "BAD DISK NAME %s\n", fs->fs_spec);
14275015Sphk				sumstatus |= 8;
14375015Sphk				continue;
14466869Sadrian			}
14575936Smckusick			addpart(fs->fs_vfstype, name, fs->fs_file);
14666869Sadrian		}
14766869Sadrian
14875936Smckusick		if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
14975936Smckusick		    (flags & DO_BACKGRD) != 0)
15075015Sphk			continue;
15166869Sadrian
15275015Sphk		if (flags & CHECK_DEBUG) {
15375015Sphk			printf("Parallel start\n");
15475015Sphk			printpart();
15575015Sphk		}
15675015Sphk
15775015Sphk		TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
15866869Sadrian			if ((ret = startdisk(nextdisk, checkit)) != 0)
15966869Sadrian				return ret;
16066869Sadrian		}
16166869Sadrian
16275015Sphk		if (flags & CHECK_DEBUG)
16375015Sphk			printf("Parallel wait\n");
16466869Sadrian		while ((pid = wait(&status)) != -1) {
16570413Sphk			TAILQ_FOREACH(d, &diskh, d_entries)
16666869Sadrian				if (d->d_pid == pid)
16766869Sadrian					break;
16866869Sadrian
16966869Sadrian			if (d == NULL) {
17066869Sadrian				warnx("Unknown pid %d\n", pid);
17166869Sadrian				continue;
17266869Sadrian			}
17366869Sadrian
17466869Sadrian			if (WIFEXITED(status))
17566869Sadrian				retcode = WEXITSTATUS(status);
17666869Sadrian			else
17766869Sadrian				retcode = 0;
17866869Sadrian
17970413Sphk			p = TAILQ_FIRST(&d->d_part);
18066869Sadrian
18166869Sadrian			if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
18266869Sadrian				(void) printf("done %s: %s (%s) = 0x%x\n",
18366869Sadrian				    p->p_type, p->p_devname, p->p_mntpt,
18466869Sadrian				    status);
18566869Sadrian
18666869Sadrian			if (WIFSIGNALED(status)) {
18766869Sadrian				(void) fprintf(stderr,
18866869Sadrian				    "%s: %s (%s): EXITED WITH SIGNAL %d\n",
18966869Sadrian				    p->p_type, p->p_devname, p->p_mntpt,
19066869Sadrian				    WTERMSIG(status));
19166869Sadrian				retcode = 8;
19266869Sadrian			}
19366869Sadrian
19466869Sadrian			TAILQ_REMOVE(&d->d_part, p, p_entries);
19566869Sadrian
19666869Sadrian			if (retcode != 0) {
19766869Sadrian				TAILQ_INSERT_TAIL(&badh, p, p_entries);
19866869Sadrian				sumstatus |= retcode;
19966869Sadrian			} else {
20066869Sadrian				free(p->p_type);
20166869Sadrian				free(p->p_devname);
20266869Sadrian				free(p);
20366869Sadrian			}
20466869Sadrian			d->d_pid = 0;
20566869Sadrian			nrun--;
20666869Sadrian
20775015Sphk			if (TAILQ_EMPTY(&d->d_part)) {
20875015Sphk				TAILQ_REMOVE(&diskh, d, d_entries);
20966869Sadrian				ndisks--;
21075289Sphk			} else {
21175289Sphk				if ((ret = startdisk(d, checkit)) != 0)
21275289Sphk					return ret;
21366869Sadrian			}
21466869Sadrian		}
21575015Sphk		if (flags & CHECK_DEBUG) {
21675015Sphk			printf("Parallel end\n");
21775015Sphk			printpart();
21875015Sphk		}
21966869Sadrian	}
22075015Sphk
22175015Sphk	if (!(flags & CHECK_PREEN))
22275015Sphk			return 0;
22375015Sphk
22466869Sadrian	if (sumstatus) {
22570522Sphk		p = TAILQ_FIRST(&badh);
22666869Sadrian		if (p == NULL)
22766869Sadrian			return (sumstatus);
22866869Sadrian
22966869Sadrian		(void) fprintf(stderr,
23066869Sadrian			"THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
23170413Sphk			TAILQ_NEXT(p, p_entries) ? "S" : "",
23266869Sadrian			"UNEXPECTED INCONSISTENCY:");
23366869Sadrian
23470413Sphk		for (; p; p = TAILQ_NEXT(p, p_entries))
23566869Sadrian			(void) fprintf(stderr,
23666869Sadrian			    "%s: %s (%s)%s", p->p_type, p->p_devname,
23770413Sphk			    p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
23866869Sadrian
23966869Sadrian		return sumstatus;
24066869Sadrian	}
24166869Sadrian	(void) endfsent();
24266869Sadrian	return (0);
24366869Sadrian}
24466869Sadrian
24566869Sadrian
24666869Sadrianstatic struct diskentry *
24792839Simpfinddisk(const char *name)
24866869Sadrian{
24966869Sadrian	const char *p;
25066869Sadrian	size_t len = 0;
25166869Sadrian	struct diskentry *d;
25266869Sadrian
25370415Sphk	p = strrchr(name, '/');
25470415Sphk	if (p == NULL)
25570415Sphk		p = name;
25670415Sphk	else
25770415Sphk		p++;
25870415Sphk	for (; *p && !isdigit(*p); p++)
25970415Sphk		continue;
26070415Sphk	for (; *p && isdigit(*p); p++)
26170415Sphk		continue;
26270415Sphk	len = p - name;
26370415Sphk	if (len == 0)
26466869Sadrian		len = strlen(name);
26566869Sadrian
26670413Sphk	TAILQ_FOREACH(d, &diskh, d_entries)
26766869Sadrian		if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
26866869Sadrian			return d;
26966869Sadrian
27066869Sadrian	d = emalloc(sizeof(*d));
27166869Sadrian	d->d_name = estrdup(name);
27266869Sadrian	d->d_name[len] = '\0';
27366869Sadrian	TAILQ_INIT(&d->d_part);
27466869Sadrian	d->d_pid = 0;
27566869Sadrian
27666869Sadrian	TAILQ_INSERT_TAIL(&diskh, d, d_entries);
27766869Sadrian	ndisks++;
27866869Sadrian
27966869Sadrian	return d;
28066869Sadrian}
28166869Sadrian
28266869Sadrian
28366869Sadrianstatic void
28492839Simpprintpart(void)
28566869Sadrian{
28666869Sadrian	struct diskentry *d;
28766869Sadrian	struct partentry *p;
28866869Sadrian
28970413Sphk	TAILQ_FOREACH(d, &diskh, d_entries) {
29066869Sadrian		(void) printf("disk %s: ", d->d_name);
29170413Sphk		TAILQ_FOREACH(p, &d->d_part, p_entries)
29266869Sadrian			(void) printf("%s ", p->p_devname);
29366869Sadrian		(void) printf("\n");
29466869Sadrian	}
29566869Sadrian}
29666869Sadrian
29766869Sadrian
29866869Sadrianstatic void
29992839Simpaddpart(const char *type, const char *devname, const char *mntpt)
30066869Sadrian{
30166869Sadrian	struct diskentry *d = finddisk(devname);
30266869Sadrian	struct partentry *p;
30366869Sadrian
30470413Sphk	TAILQ_FOREACH(p, &d->d_part, p_entries)
30566869Sadrian		if (strcmp(p->p_devname, devname) == 0) {
30666869Sadrian			warnx("%s in fstab more than once!\n", devname);
30766869Sadrian			return;
30866869Sadrian		}
30966869Sadrian
31066869Sadrian	p = emalloc(sizeof(*p));
31166869Sadrian	p->p_devname = estrdup(devname);
31266869Sadrian	p->p_mntpt = estrdup(mntpt);
31366869Sadrian	p->p_type = estrdup(type);
31466869Sadrian
31566869Sadrian	TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
31666869Sadrian}
31766869Sadrian
31866869Sadrian
31966869Sadrianstatic int
32092839Simpstartdisk(struct diskentry *d, int (*checkit)(const char *, const char *,
32192839Simp    const char *, char *, pid_t *))
32266869Sadrian{
32370522Sphk	struct partentry *p = TAILQ_FIRST(&d->d_part);
32466869Sadrian	int rv;
32566869Sadrian
32666869Sadrian	while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
32775936Smckusick	    NULL, &d->d_pid)) != 0 && nrun > 0)
32866869Sadrian		sleep(10);
32966869Sadrian
33066869Sadrian	if (rv == 0)
33166869Sadrian		nrun++;
33266869Sadrian
33366869Sadrian	return rv;
33466869Sadrian}
335