166869Sadrian/*	$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $	*/
266869Sadrian
3331722Seadler/*
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 * 4. Neither the name of the University nor the names of its contributors
1666869Sadrian *    may be used to endorse or promote products derived from this software
1766869Sadrian *    without specific prior written permission.
1866869Sadrian *
1966869Sadrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2066869Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2166869Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2266869Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2366869Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2466869Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2566869Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2666869Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2766869Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2866869Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2966869Sadrian * SUCH DAMAGE.
3066869Sadrian *
3166869Sadrian * $FreeBSD$
3266869Sadrian */
3366869Sadrian
3466869Sadrian#include <sys/cdefs.h>
3566869Sadrian#ifndef lint
3666869Sadrian#if 0
3766869Sadrianstatic char sccsid[] = "@(#)preen.c	8.5 (Berkeley) 4/28/95";
3866869Sadrian#else
3966869Sadrian__RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
4066869Sadrian#endif
4166869Sadrian#endif /* not lint */
4266869Sadrian
4366869Sadrian#include <sys/param.h>
4466869Sadrian#include <sys/stat.h>
4566869Sadrian#include <sys/wait.h>
4666869Sadrian#include <sys/queue.h>
4766869Sadrian
4866869Sadrian#include <err.h>
4966869Sadrian#include <ctype.h>
5066869Sadrian#include <fstab.h>
5166869Sadrian#include <string.h>
5266869Sadrian#include <stdio.h>
5366869Sadrian#include <stdlib.h>
5466869Sadrian#include <unistd.h>
5566869Sadrian
5666869Sadrian#include "fsutil.h"
5766869Sadrian
5866869Sadrianstruct partentry {
5966869Sadrian	TAILQ_ENTRY(partentry)	 p_entries;
6066869Sadrian	char		  	*p_devname;	/* device name */
6166869Sadrian	char			*p_mntpt;	/* mount point */
62102231Strhodes	char		  	*p_type;	/* file system type */
6366869Sadrian};
6466869Sadrian
65227081Sedstatic TAILQ_HEAD(part, partentry) badh;
6666869Sadrian
6766869Sadrianstruct diskentry {
6866869Sadrian	TAILQ_ENTRY(diskentry) 	    d_entries;
6966869Sadrian	char		       	   *d_name;	/* disk base name */
7066869Sadrian	TAILQ_HEAD(prt, partentry)  d_part;	/* list of partitions on disk */
7166869Sadrian	int			    d_pid;	/* 0 or pid of fsck proc */
7266869Sadrian};
7366869Sadrian
74227081Sedstatic TAILQ_HEAD(disk, diskentry) diskh;
7566869Sadrian
7666869Sadrianstatic int nrun = 0, ndisks = 0;
7766869Sadrian
7892839Simpstatic struct diskentry *finddisk(const char *);
7992839Simpstatic void addpart(const char *, const char *, const char *);
8092839Simpstatic int startdisk(struct diskentry *,
81241807Suqs    int (*)(const char *, const char *, const char *, const char *, pid_t *));
8292839Simpstatic void printpart(void);
8366869Sadrian
8466869Sadrianint
8592839Simpcheckfstab(int flags, int (*docheck)(struct fstab *),
86241807Suqs    int (*checkit)(const char *, const char *, const char *, const char *, pid_t *))
8766869Sadrian{
8866869Sadrian	struct fstab *fs;
8966869Sadrian	struct diskentry *d, *nextdisk;
9066869Sadrian	struct partentry *p;
9175015Sphk	int ret, pid, retcode, passno, sumstatus, status, nextpass;
9266869Sadrian	const char *name;
9366869Sadrian
9466869Sadrian	TAILQ_INIT(&badh);
9566869Sadrian	TAILQ_INIT(&diskh);
9666869Sadrian
9766869Sadrian	sumstatus = 0;
9866869Sadrian
9975015Sphk	nextpass = 0;
10075015Sphk	for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
10175015Sphk		if (flags & CHECK_DEBUG)
10275015Sphk			printf("pass %d\n", passno);
10375015Sphk
10475015Sphk		nextpass = INT_MAX;
10566869Sadrian		if (setfsent() == 0) {
10666869Sadrian			warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
10766869Sadrian			return (8);
10866869Sadrian		}
109298194Saraujo		while ((fs = getfsent()) != NULL) {
11066869Sadrian			name = fs->fs_spec;
11175015Sphk			if (fs->fs_passno > passno && fs->fs_passno < nextpass)
11275015Sphk				nextpass = fs->fs_passno;
11375015Sphk
114107987Sphk			if (passno != fs->fs_passno)
11575015Sphk				continue;
11675015Sphk
117107987Sphk			if ((*docheck)(fs) == 0)
118107987Sphk				continue;
119107987Sphk
12066869Sadrian			if (flags & CHECK_DEBUG)
12166869Sadrian				printf("pass %d, name %s\n", passno, name);
12266869Sadrian
12375936Smckusick			if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
12475936Smckusick			    (flags & DO_BACKGRD) != 0) {
12566869Sadrian				if (name == NULL) {
12666869Sadrian					if (flags & CHECK_PREEN)
12766869Sadrian						return 8;
12866869Sadrian					else
12966869Sadrian						continue;
13066869Sadrian				}
13166869Sadrian				sumstatus = (*checkit)(fs->fs_vfstype,
13275936Smckusick				    name, fs->fs_file, NULL, NULL);
13366869Sadrian
13466869Sadrian				if (sumstatus)
13566869Sadrian					return (sumstatus);
13675015Sphk				continue;
13775015Sphk			}
13875015Sphk			if (name == NULL) {
13975015Sphk				(void) fprintf(stderr,
14075015Sphk				    "BAD DISK NAME %s\n", fs->fs_spec);
14175015Sphk				sumstatus |= 8;
14275015Sphk				continue;
14366869Sadrian			}
14475936Smckusick			addpart(fs->fs_vfstype, name, fs->fs_file);
14566869Sadrian		}
14666869Sadrian
14775936Smckusick		if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
14875936Smckusick		    (flags & DO_BACKGRD) != 0)
14975015Sphk			continue;
15066869Sadrian
15175015Sphk		if (flags & CHECK_DEBUG) {
15275015Sphk			printf("Parallel start\n");
15375015Sphk			printpart();
15475015Sphk		}
15575015Sphk
15675015Sphk		TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
15766869Sadrian			if ((ret = startdisk(nextdisk, checkit)) != 0)
15866869Sadrian				return ret;
15966869Sadrian		}
16066869Sadrian
16175015Sphk		if (flags & CHECK_DEBUG)
16275015Sphk			printf("Parallel wait\n");
16366869Sadrian		while ((pid = wait(&status)) != -1) {
16470413Sphk			TAILQ_FOREACH(d, &diskh, d_entries)
16566869Sadrian				if (d->d_pid == pid)
16666869Sadrian					break;
16766869Sadrian
16866869Sadrian			if (d == NULL) {
16966869Sadrian				warnx("Unknown pid %d\n", pid);
17066869Sadrian				continue;
17166869Sadrian			}
17266869Sadrian
17366869Sadrian			if (WIFEXITED(status))
17466869Sadrian				retcode = WEXITSTATUS(status);
17566869Sadrian			else
17666869Sadrian				retcode = 0;
17766869Sadrian
17870413Sphk			p = TAILQ_FIRST(&d->d_part);
17966869Sadrian
18066869Sadrian			if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
18166869Sadrian				(void) printf("done %s: %s (%s) = 0x%x\n",
18266869Sadrian				    p->p_type, p->p_devname, p->p_mntpt,
18366869Sadrian				    status);
18466869Sadrian
18566869Sadrian			if (WIFSIGNALED(status)) {
18666869Sadrian				(void) fprintf(stderr,
18766869Sadrian				    "%s: %s (%s): EXITED WITH SIGNAL %d\n",
18866869Sadrian				    p->p_type, p->p_devname, p->p_mntpt,
18966869Sadrian				    WTERMSIG(status));
19066869Sadrian				retcode = 8;
19166869Sadrian			}
19266869Sadrian
19366869Sadrian			TAILQ_REMOVE(&d->d_part, p, p_entries);
19466869Sadrian
19566869Sadrian			if (retcode != 0) {
19666869Sadrian				TAILQ_INSERT_TAIL(&badh, p, p_entries);
19766869Sadrian				sumstatus |= retcode;
19866869Sadrian			} else {
19966869Sadrian				free(p->p_type);
20066869Sadrian				free(p->p_devname);
20166869Sadrian				free(p);
20266869Sadrian			}
20366869Sadrian			d->d_pid = 0;
20466869Sadrian			nrun--;
20566869Sadrian
20675015Sphk			if (TAILQ_EMPTY(&d->d_part)) {
20775015Sphk				TAILQ_REMOVE(&diskh, d, d_entries);
20866869Sadrian				ndisks--;
20975289Sphk			} else {
21075289Sphk				if ((ret = startdisk(d, checkit)) != 0)
21175289Sphk					return ret;
21266869Sadrian			}
21366869Sadrian		}
21475015Sphk		if (flags & CHECK_DEBUG) {
21575015Sphk			printf("Parallel end\n");
21675015Sphk			printpart();
21775015Sphk		}
21866869Sadrian	}
21975015Sphk
22075015Sphk	if (!(flags & CHECK_PREEN))
22175015Sphk			return 0;
22275015Sphk
22366869Sadrian	if (sumstatus) {
22470522Sphk		p = TAILQ_FIRST(&badh);
22566869Sadrian		if (p == NULL)
22666869Sadrian			return (sumstatus);
22766869Sadrian
22866869Sadrian		(void) fprintf(stderr,
22966869Sadrian			"THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
23070413Sphk			TAILQ_NEXT(p, p_entries) ? "S" : "",
23166869Sadrian			"UNEXPECTED INCONSISTENCY:");
23266869Sadrian
23370413Sphk		for (; p; p = TAILQ_NEXT(p, p_entries))
23466869Sadrian			(void) fprintf(stderr,
23566869Sadrian			    "%s: %s (%s)%s", p->p_type, p->p_devname,
23670413Sphk			    p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
23766869Sadrian
23866869Sadrian		return sumstatus;
23966869Sadrian	}
24066869Sadrian	(void) endfsent();
24166869Sadrian	return (0);
24266869Sadrian}
24366869Sadrian
24466869Sadrian
24566869Sadrianstatic struct diskentry *
24692839Simpfinddisk(const char *name)
24766869Sadrian{
24866869Sadrian	const char *p;
24966869Sadrian	size_t len = 0;
25066869Sadrian	struct diskentry *d;
25166869Sadrian
25270415Sphk	p = strrchr(name, '/');
25370415Sphk	if (p == NULL)
25470415Sphk		p = name;
25570415Sphk	else
25670415Sphk		p++;
25770415Sphk	for (; *p && !isdigit(*p); p++)
25870415Sphk		continue;
25970415Sphk	for (; *p && isdigit(*p); p++)
26070415Sphk		continue;
26170415Sphk	len = p - name;
26270415Sphk	if (len == 0)
26366869Sadrian		len = strlen(name);
26466869Sadrian
26570413Sphk	TAILQ_FOREACH(d, &diskh, d_entries)
26666869Sadrian		if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
26766869Sadrian			return d;
26866869Sadrian
26966869Sadrian	d = emalloc(sizeof(*d));
27066869Sadrian	d->d_name = estrdup(name);
27166869Sadrian	d->d_name[len] = '\0';
27266869Sadrian	TAILQ_INIT(&d->d_part);
27366869Sadrian	d->d_pid = 0;
27466869Sadrian
27566869Sadrian	TAILQ_INSERT_TAIL(&diskh, d, d_entries);
27666869Sadrian	ndisks++;
27766869Sadrian
27866869Sadrian	return d;
27966869Sadrian}
28066869Sadrian
28166869Sadrian
28266869Sadrianstatic void
28392839Simpprintpart(void)
28466869Sadrian{
28566869Sadrian	struct diskentry *d;
28666869Sadrian	struct partentry *p;
28766869Sadrian
28870413Sphk	TAILQ_FOREACH(d, &diskh, d_entries) {
28966869Sadrian		(void) printf("disk %s: ", d->d_name);
29070413Sphk		TAILQ_FOREACH(p, &d->d_part, p_entries)
29166869Sadrian			(void) printf("%s ", p->p_devname);
29266869Sadrian		(void) printf("\n");
29366869Sadrian	}
29466869Sadrian}
29566869Sadrian
29666869Sadrian
29766869Sadrianstatic void
298241806Suqsaddpart(const char *type, const char *dev, const char *mntpt)
29966869Sadrian{
300241806Suqs	struct diskentry *d = finddisk(dev);
30166869Sadrian	struct partentry *p;
30266869Sadrian
30370413Sphk	TAILQ_FOREACH(p, &d->d_part, p_entries)
304241806Suqs		if (strcmp(p->p_devname, dev) == 0) {
305241806Suqs			warnx("%s in fstab more than once!\n", dev);
30666869Sadrian			return;
30766869Sadrian		}
30866869Sadrian
30966869Sadrian	p = emalloc(sizeof(*p));
310241806Suqs	p->p_devname = estrdup(dev);
31166869Sadrian	p->p_mntpt = estrdup(mntpt);
31266869Sadrian	p->p_type = estrdup(type);
31366869Sadrian
31466869Sadrian	TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
31566869Sadrian}
31666869Sadrian
31766869Sadrian
31866869Sadrianstatic int
31992839Simpstartdisk(struct diskentry *d, int (*checkit)(const char *, const char *,
320241807Suqs    const char *, const char *, pid_t *))
32166869Sadrian{
32270522Sphk	struct partentry *p = TAILQ_FIRST(&d->d_part);
32366869Sadrian	int rv;
32466869Sadrian
32566869Sadrian	while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
32675936Smckusick	    NULL, &d->d_pid)) != 0 && nrun > 0)
32766869Sadrian		sleep(10);
32866869Sadrian
32966869Sadrian	if (rv == 0)
33066869Sadrian		nrun++;
33166869Sadrian
33266869Sadrian	return rv;
33366869Sadrian}
334