preen.c revision 128073
1184610Salfred/*
2184610Salfred * Copyright (c) 1990, 1993
3184610Salfred *	The Regents of the University of California.  All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred * 4. Neither the name of the University nor the names of its contributors
14184610Salfred *    may be used to endorse or promote products derived from this software
15184610Salfred *    without specific prior written permission.
16184610Salfred *
17184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27184610Salfred * SUCH DAMAGE.
28184610Salfred */
29184610Salfred
30184610Salfred#if 0
31184610Salfred#ifndef lint
32184610Salfredstatic const char sccsid[] = "@(#)preen.c	8.5 (Berkeley) 4/28/95";
33184610Salfred#endif /* not lint */
34184610Salfred#endif
35190185Sthompsa#include <sys/cdefs.h>
36190185Sthompsa__FBSDID("$FreeBSD: head/sbin/quotacheck/preen.c 128073 2004-04-09 19:58:40Z markm $");
37190180Sthompsa
38190180Sthompsa#include <sys/param.h>
39190180Sthompsa#include <sys/stat.h>
40190180Sthompsa#include <sys/wait.h>
41190180Sthompsa
42184610Salfred#include <ufs/ufs/dinode.h>
43184610Salfred#include <ufs/ffs/fs.h>
44190180Sthompsa
45190180Sthompsa#include <ctype.h>
46190180Sthompsa#include <errno.h>
47190180Sthompsa#include <fstab.h>
48190180Sthompsa#include <string.h>
49190180Sthompsa#include <stdio.h>
50184610Salfred#include <stdlib.h>
51184610Salfred#include <unistd.h>
52190180Sthompsa
53190180Sthompsachar *blockcheck(char *origname);
54190180Sthompsa
55190180Sthompsa
56189599Sthompsastruct part {
57189599Sthompsa	struct	part *next;		/* forward link of partitions on disk */
58189599Sthompsa	char	*name;			/* device name */
59189599Sthompsa	char	*fsname;		/* mounted file system name */
60190180Sthompsa	long	auxdata;		/* auxiliary data for application */
61190180Sthompsa} *badlist, **badnext = &badlist;
62190180Sthompsa
63190180Sthompsastruct disk {
64190180Sthompsa	char	*name;			/* disk base name */
65190180Sthompsa	struct	disk *next;		/* forward link for list of disks */
66190180Sthompsa	struct	part *part;		/* head of list of partitions on disk */
67190180Sthompsa	int	pid;			/* If != 0, pid of proc working on */
68190180Sthompsa} *disks;
69190180Sthompsa
70190180Sthompsaint	nrun, ndisks;
71190180Sthompsa
72190180Sthompsastatic void addpart(char *name, char *fsname, long auxdata);
73190180Sthompsastatic struct disk *finddisk(char *name);
74190180Sthompsastatic int startdisk(struct disk *dk,int (*checkit)(char *, char *, long, int));
75190180Sthompsa
76190180Sthompsaint
77190180Sthompsacheckfstab(int preen, int maxrun, int (*docheck)(struct fstab *),
78190180Sthompsa    int (*chkit)(char *, char *, long, int))
79190180Sthompsa{
80190180Sthompsa	struct fstab *fsp;
81190180Sthompsa	struct disk *dk, *nextdisk;
82190180Sthompsa	struct part *pt;
83190180Sthompsa	int ret, pid, retcode, passno, sumstatus, status;
84190180Sthompsa	long auxdata;
85190180Sthompsa	char *name;
86190180Sthompsa
87190180Sthompsa	sumstatus = 0;
88190180Sthompsa	for (passno = 1; passno <= 2; passno++) {
89190180Sthompsa		if (setfsent() == 0) {
90190180Sthompsa			fprintf(stderr, "Can't open checklist file: %s\n",
91190180Sthompsa			    _PATH_FSTAB);
92190180Sthompsa			return (8);
93190180Sthompsa		}
94190180Sthompsa		while ((fsp = getfsent()) != 0) {
95190180Sthompsa			if ((auxdata = (*docheck)(fsp)) == 0)
96190180Sthompsa				continue;
97190180Sthompsa			if (preen == 0 ||
98190180Sthompsa			    (passno == 1 && fsp->fs_passno == 1)) {
99190180Sthompsa				if ((name = blockcheck(fsp->fs_spec)) != 0) {
100190180Sthompsa					if ((sumstatus = (*chkit)(name,
101190180Sthompsa					    fsp->fs_file, auxdata, 0)) != 0)
102190180Sthompsa						return (sumstatus);
103190180Sthompsa				} else if (preen)
104190180Sthompsa					return (8);
105190180Sthompsa			} else if (passno == 2 && fsp->fs_passno > 1) {
106190180Sthompsa				if ((name = blockcheck(fsp->fs_spec)) == NULL) {
107190180Sthompsa					fprintf(stderr, "BAD DISK NAME %s\n",
108190180Sthompsa						fsp->fs_spec);
109190180Sthompsa					sumstatus |= 8;
110190180Sthompsa					continue;
111190180Sthompsa				}
112190180Sthompsa				addpart(name, fsp->fs_file, auxdata);
113190180Sthompsa			}
114190180Sthompsa		}
115190734Sthompsa		if (preen == 0)
116190734Sthompsa			return (0);
117190734Sthompsa	}
118190734Sthompsa	if (preen) {
119190734Sthompsa		if (maxrun == 0)
120190734Sthompsa			maxrun = ndisks;
121190734Sthompsa		if (maxrun > ndisks)
122190734Sthompsa			maxrun = ndisks;
123190734Sthompsa		nextdisk = disks;
124190734Sthompsa		for (passno = 0; passno < maxrun; ++passno) {
125190734Sthompsa			while ((ret = startdisk(nextdisk, chkit)) && nrun > 0)
126190734Sthompsa				sleep(10);
127190734Sthompsa			if (ret)
128190734Sthompsa				return (ret);
129190734Sthompsa			nextdisk = nextdisk->next;
130190734Sthompsa		}
131184610Salfred		while ((pid = wait(&status)) != -1) {
132184610Salfred			for (dk = disks; dk; dk = dk->next)
133184610Salfred				if (dk->pid == pid)
134184610Salfred					break;
135184610Salfred			if (dk == 0) {
136184610Salfred				printf("Unknown pid %d\n", pid);
137184610Salfred				continue;
138184610Salfred			}
139184610Salfred			if (WIFEXITED(status))
140184610Salfred				retcode = WEXITSTATUS(status);
141184610Salfred			else
142184610Salfred				retcode = 0;
143184610Salfred			if (WIFSIGNALED(status)) {
144184610Salfred				printf("%s (%s): EXITED WITH SIGNAL %d\n",
145184610Salfred					dk->part->name, dk->part->fsname,
146184610Salfred					WTERMSIG(status));
147184610Salfred				retcode = 8;
148184610Salfred			}
149184610Salfred			if (retcode != 0) {
150184610Salfred				sumstatus |= retcode;
151184610Salfred				*badnext = dk->part;
152184610Salfred				badnext = &dk->part->next;
153184610Salfred				dk->part = dk->part->next;
154184610Salfred				*badnext = NULL;
155184610Salfred			} else
156184610Salfred				dk->part = dk->part->next;
157184610Salfred			dk->pid = 0;
158184610Salfred			nrun--;
159184610Salfred			if (dk->part == NULL)
160184610Salfred				ndisks--;
161190185Sthompsa
162188942Sthompsa			if (nextdisk == NULL) {
163184610Salfred				if (dk->part) {
164188942Sthompsa					while ((ret = startdisk(dk, chkit)) &&
165184610Salfred					    nrun > 0)
166190185Sthompsa						sleep(10);
167184610Salfred					if (ret)
168190185Sthompsa						return (ret);
169184610Salfred				}
170190185Sthompsa			} else if (nrun < maxrun && nrun < ndisks) {
171184610Salfred				for ( ;; ) {
172190185Sthompsa					if ((nextdisk = nextdisk->next) == NULL)
173184610Salfred						nextdisk = disks;
174184610Salfred					if (nextdisk->part != NULL &&
175184610Salfred					    nextdisk->pid == 0)
176184610Salfred						break;
177184610Salfred				}
178190185Sthompsa				while ((ret = startdisk(nextdisk, chkit)) &&
179190185Sthompsa				    nrun > 0)
180190185Sthompsa					sleep(10);
181190185Sthompsa				if (ret)
182190185Sthompsa					return (ret);
183190185Sthompsa			}
184190185Sthompsa		}
185190185Sthompsa	}
186190185Sthompsa	if (sumstatus) {
187190185Sthompsa		if (badlist == 0)
188190185Sthompsa			return (sumstatus);
189190185Sthompsa		fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
190190185Sthompsa			badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
191190185Sthompsa		for (pt = badlist; pt; pt = pt->next)
192190185Sthompsa			fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
193190185Sthompsa			    pt->next ? ", " : "\n");
194190185Sthompsa		return (sumstatus);
195190185Sthompsa	}
196190185Sthompsa	(void)endfsent();
197190185Sthompsa	return (0);
198190185Sthompsa}
199190185Sthompsa
200190185Sthompsastatic struct disk *
201190185Sthompsafinddisk(char *name)
202184610Salfred{
203184610Salfred	struct disk *dk, **dkp;
204184610Salfred	char *p;
205190185Sthompsa	size_t len;
206190185Sthompsa
207190185Sthompsa	p = strrchr(name, '/');
208184610Salfred	p = p == NULL ? name : p + 1;
209190181Sthompsa	while (*p != '\0' && !isdigit((u_char)*p))
210190181Sthompsa		p++;
211190181Sthompsa	while (isdigit((u_char)*p))
212190181Sthompsa		p++;
213184610Salfred	len = (size_t)(p - name);
214184610Salfred	for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
215184610Salfred		if (strncmp(dk->name, name, len) == 0 &&
216184610Salfred		    dk->name[len] == 0)
217184610Salfred			return (dk);
218184610Salfred	}
219184610Salfred	if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
220184610Salfred		fprintf(stderr, "out of memory");
221184610Salfred		exit (8);
222184610Salfred	}
223184610Salfred	dk = *dkp;
224184610Salfred	if ((dk->name = malloc(len + 1)) == NULL) {
225184610Salfred		fprintf(stderr, "out of memory");
226184610Salfred		exit (8);
227184610Salfred	}
228184610Salfred	(void)strncpy(dk->name, name, len);
229184610Salfred	dk->name[len] = '\0';
230184610Salfred	dk->part = NULL;
231184610Salfred	dk->next = NULL;
232184610Salfred	dk->pid = 0;
233184610Salfred	ndisks++;
234184610Salfred	return (dk);
235184610Salfred}
236184610Salfred
237184610Salfredstatic void
238184610Salfredaddpart(char *name, char *fsname, long auxdata)
239184610Salfred{
240184610Salfred	struct disk *dk = finddisk(name);
241184610Salfred	struct part *pt, **ppt = &dk->part;
242184610Salfred
243184610Salfred	for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
244184610Salfred		if (strcmp(pt->name, name) == 0) {
245184610Salfred			printf("%s in fstab more than once!\n", name);
246184610Salfred			return;
247184610Salfred		}
248184610Salfred	if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
249184610Salfred		fprintf(stderr, "out of memory");
250184610Salfred		exit (8);
251185087Salfred	}
252185087Salfred	pt = *ppt;
253185087Salfred	if ((pt->name = malloc(strlen(name) + 1)) == NULL) {
254187173Sthompsa		fprintf(stderr, "out of memory");
255187173Sthompsa		exit (8);
256187173Sthompsa	}
257184610Salfred	(void)strcpy(pt->name, name);
258184610Salfred	if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) {
259184610Salfred		fprintf(stderr, "out of memory");
260184610Salfred		exit (8);
261184610Salfred	}
262184610Salfred	(void)strcpy(pt->fsname, fsname);
263184610Salfred	pt->next = NULL;
264184610Salfred	pt->auxdata = auxdata;
265184610Salfred}
266184610Salfred
267184610Salfredstatic int
268184610Salfredstartdisk(struct disk *dk, int (*checkit)(char *, char *, long, int))
269184610Salfred{
270184610Salfred	struct part *pt = dk->part;
271190174Sthompsa
272190174Sthompsa	dk->pid = fork();
273190174Sthompsa	if (dk->pid < 0) {
274190174Sthompsa		perror("fork");
275190174Sthompsa		return (8);
276190174Sthompsa	}
277190174Sthompsa	if (dk->pid == 0)
278190174Sthompsa		exit((*checkit)(pt->name, pt->fsname, pt->auxdata, 1));
279190181Sthompsa	nrun++;
280190181Sthompsa	return (0);
281190174Sthompsa}
282190174Sthompsa
283190181Sthompsa