xref: /csrg-svn/sbin/fsck/preen.c (revision 41098)
1*41098Smckusick /*
2*41098Smckusick  * Copyright (c) 1990 The Regents of the University of California.
3*41098Smckusick  * All rights reserved.
4*41098Smckusick  *
5*41098Smckusick  * Redistribution and use in source and binary forms are permitted
6*41098Smckusick  * provided that the above copyright notice and this paragraph are
7*41098Smckusick  * duplicated in all such forms and that any documentation,
8*41098Smckusick  * advertising materials, and other materials related to such
9*41098Smckusick  * distribution and use acknowledge that the software was developed
10*41098Smckusick  * by the University of California, Berkeley.  The name of the
11*41098Smckusick  * University may not be used to endorse or promote products derived
12*41098Smckusick  * from this software without specific prior written permission.
13*41098Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*41098Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*41098Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*41098Smckusick  */
17*41098Smckusick 
18*41098Smckusick #ifndef lint
19*41098Smckusick static char sccsid[] = "@(#)preen.c	5.1 (Berkeley) 04/26/90";
20*41098Smckusick #endif /* not lint */
21*41098Smckusick 
22*41098Smckusick #include <sys/param.h>
23*41098Smckusick #include <sys/stat.h>
24*41098Smckusick #include <sys/wait.h>
25*41098Smckusick #include <fstab.h>
26*41098Smckusick #include <strings.h>
27*41098Smckusick #include <stdio.h>
28*41098Smckusick #include <ctype.h>
29*41098Smckusick 
30*41098Smckusick char	*rawname(), *unrawname(), *blockcheck(), *malloc();
31*41098Smckusick 
32*41098Smckusick struct part {
33*41098Smckusick 	struct	part *next;		/* forward link of partitions on disk */
34*41098Smckusick 	char	*name;			/* device name */
35*41098Smckusick 	char	*fsname;		/* mounted filesystem name */
36*41098Smckusick 	long	auxdata;		/* auxillary data for application */
37*41098Smckusick } *badlist, **badnext = &badlist;
38*41098Smckusick 
39*41098Smckusick struct disk {
40*41098Smckusick 	char	*name;			/* disk base name */
41*41098Smckusick 	struct	disk *next;		/* forward link for list of disks */
42*41098Smckusick 	struct	part *part;		/* head of list of partitions on disk */
43*41098Smckusick 	int	pid;			/* If != 0, pid of proc working on */
44*41098Smckusick } *disks;
45*41098Smckusick 
46*41098Smckusick int	nrun, ndisks, hotroot;
47*41098Smckusick 
48*41098Smckusick checkfstab(preen, maxrun, docheck, chkit)
49*41098Smckusick 	int preen, maxrun;
50*41098Smckusick 	int (*docheck)(), (*chkit)();
51*41098Smckusick {
52*41098Smckusick 	register struct fstab *fsp;
53*41098Smckusick 	register struct disk *dk, *nextdisk;
54*41098Smckusick 	register struct part *pt;
55*41098Smckusick 	int ret, pid, retcode, passno, sumstatus, status;
56*41098Smckusick 	long auxdata;
57*41098Smckusick 	char *name;
58*41098Smckusick 
59*41098Smckusick 	sumstatus = 0;
60*41098Smckusick 	for (passno = 1; passno <= 2; passno++) {
61*41098Smckusick 		if (setfsent() == 0) {
62*41098Smckusick 			fprintf(stderr, "Can't open checklist file: %s\n",
63*41098Smckusick 			    _PATH_FSTAB);
64*41098Smckusick 			return (8);
65*41098Smckusick 		}
66*41098Smckusick 		while ((fsp = getfsent()) != 0) {
67*41098Smckusick 			if ((auxdata = (*docheck)(fsp)) == 0)
68*41098Smckusick 				continue;
69*41098Smckusick 			if (preen == 0 || passno == 1 && fsp->fs_passno == 1) {
70*41098Smckusick 				if (name = blockcheck(fsp->fs_spec)) {
71*41098Smckusick 					if (sumstatus = (*chkit)(name,
72*41098Smckusick 					    fsp->fs_file, auxdata))
73*41098Smckusick 						return (sumstatus);
74*41098Smckusick 				} else if (preen)
75*41098Smckusick 					return (8);
76*41098Smckusick 			} else if (passno == 2 && fsp->fs_passno > 1) {
77*41098Smckusick 				if ((name = blockcheck(fsp->fs_spec)) == NULL) {
78*41098Smckusick 					fprintf(stderr, "BAD DISK NAME %s\n",
79*41098Smckusick 						fsp->fs_spec);
80*41098Smckusick 					sumstatus |= 8;
81*41098Smckusick 					continue;
82*41098Smckusick 				}
83*41098Smckusick 				addpart(name, fsp->fs_file, auxdata);
84*41098Smckusick 			}
85*41098Smckusick 		}
86*41098Smckusick 		if (preen == 0)
87*41098Smckusick 			return (0);
88*41098Smckusick 	}
89*41098Smckusick 	if (preen) {
90*41098Smckusick 		if (maxrun == 0)
91*41098Smckusick 			maxrun = ndisks;
92*41098Smckusick 		if (maxrun > ndisks)
93*41098Smckusick 			maxrun = ndisks;
94*41098Smckusick 		nextdisk = disks;
95*41098Smckusick 		for (passno = 0; passno < maxrun; ++passno) {
96*41098Smckusick 			while (ret = startdisk(nextdisk, chkit) && nrun > 0)
97*41098Smckusick 				sleep(10);
98*41098Smckusick 			if (ret)
99*41098Smckusick 				return (ret);
100*41098Smckusick 			nextdisk = nextdisk->next;
101*41098Smckusick 		}
102*41098Smckusick 		while ((pid = wait(&status)) != -1) {
103*41098Smckusick 			for (dk = disks; dk; dk = dk->next)
104*41098Smckusick 				if (dk->pid == pid)
105*41098Smckusick 					break;
106*41098Smckusick 			if (dk == 0) {
107*41098Smckusick 				printf("Unknown pid %d\n", pid);
108*41098Smckusick 				continue;
109*41098Smckusick 			}
110*41098Smckusick 			if (WIFEXITED(status))
111*41098Smckusick 				retcode = WEXITSTATUS(status);
112*41098Smckusick 			else
113*41098Smckusick 				retcode = 0;
114*41098Smckusick 			if (WIFSIGNALED(status)) {
115*41098Smckusick 				printf("%s (%s): EXITED WITH SIGNAL %d\n",
116*41098Smckusick 					dk->part->name, dk->part->fsname,
117*41098Smckusick 					WTERMSIG(status));
118*41098Smckusick 				retcode = 8;
119*41098Smckusick 			}
120*41098Smckusick 			if (retcode != 0) {
121*41098Smckusick 				sumstatus |= retcode;
122*41098Smckusick 				*badnext = dk->part;
123*41098Smckusick 				badnext = &dk->part->next;
124*41098Smckusick 				dk->part = dk->part->next;
125*41098Smckusick 				*badnext = NULL;
126*41098Smckusick 			} else
127*41098Smckusick 				dk->part = dk->part->next;
128*41098Smckusick 			dk->pid = 0;
129*41098Smckusick 			nrun--;
130*41098Smckusick 			if (dk->part == NULL)
131*41098Smckusick 				ndisks--;
132*41098Smckusick 
133*41098Smckusick 			if (nextdisk == NULL) {
134*41098Smckusick 				if (dk->part) {
135*41098Smckusick 					while (ret = startdisk(dk, chkit) &&
136*41098Smckusick 					    nrun > 0)
137*41098Smckusick 						sleep(10);
138*41098Smckusick 					if (ret)
139*41098Smckusick 						return (ret);
140*41098Smckusick 				}
141*41098Smckusick 			} else if (nrun < maxrun && nrun < ndisks) {
142*41098Smckusick 				for ( ;; ) {
143*41098Smckusick 					if ((nextdisk = nextdisk->next) == NULL)
144*41098Smckusick 						nextdisk = disks;
145*41098Smckusick 					if (nextdisk->part != NULL &&
146*41098Smckusick 					    nextdisk->pid == 0)
147*41098Smckusick 						break;
148*41098Smckusick 				}
149*41098Smckusick 				while (ret = startdisk(nextdisk, chkit) &&
150*41098Smckusick 				    nrun > 0)
151*41098Smckusick 					sleep(10);
152*41098Smckusick 				if (ret)
153*41098Smckusick 					return (ret);
154*41098Smckusick 			}
155*41098Smckusick 		}
156*41098Smckusick 	}
157*41098Smckusick 	if (sumstatus) {
158*41098Smckusick 		if (badlist == 0)
159*41098Smckusick 			return (sumstatus);
160*41098Smckusick 		fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
161*41098Smckusick 			badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
162*41098Smckusick 		for (pt = badlist; pt; pt = pt->next)
163*41098Smckusick 			fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
164*41098Smckusick 			    pt->next ? ", " : "\n");
165*41098Smckusick 		return (sumstatus);
166*41098Smckusick 	}
167*41098Smckusick 	(void)endfsent();
168*41098Smckusick 	return (0);
169*41098Smckusick }
170*41098Smckusick 
171*41098Smckusick struct disk *
172*41098Smckusick finddisk(name)
173*41098Smckusick 	char *name;
174*41098Smckusick {
175*41098Smckusick 	register struct disk *dk, **dkp;
176*41098Smckusick 	register char *p;
177*41098Smckusick 	int len;
178*41098Smckusick 
179*41098Smckusick 	for (p = name + strlen(name) - 1; p >= name; --p)
180*41098Smckusick 		if (isdigit(*p)) {
181*41098Smckusick 			len = p - name + 1;
182*41098Smckusick 			break;
183*41098Smckusick 		}
184*41098Smckusick 	if (p < name)
185*41098Smckusick 		len = strlen(name);
186*41098Smckusick 
187*41098Smckusick 	for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
188*41098Smckusick 		if (strncmp(dk->name, name, len) == 0 &&
189*41098Smckusick 		    dk->name[len] == 0)
190*41098Smckusick 			return (dk);
191*41098Smckusick 	}
192*41098Smckusick 	if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
193*41098Smckusick 		fprintf(stderr, "out of memory");
194*41098Smckusick 		exit (8);
195*41098Smckusick 	}
196*41098Smckusick 	dk = *dkp;
197*41098Smckusick 	if ((dk->name = malloc((unsigned int)len + 1)) == NULL) {
198*41098Smckusick 		fprintf(stderr, "out of memory");
199*41098Smckusick 		exit (8);
200*41098Smckusick 	}
201*41098Smckusick 	strncpy(dk->name, name, len);
202*41098Smckusick 	dk->name[len] = '\0';
203*41098Smckusick 	dk->part = NULL;
204*41098Smckusick 	dk->next = NULL;
205*41098Smckusick 	dk->pid = 0;
206*41098Smckusick 	ndisks++;
207*41098Smckusick 	return (dk);
208*41098Smckusick }
209*41098Smckusick 
210*41098Smckusick addpart(name, fsname, auxdata)
211*41098Smckusick 	char *name, *fsname;
212*41098Smckusick 	long auxdata;
213*41098Smckusick {
214*41098Smckusick 	struct disk *dk = finddisk(name);
215*41098Smckusick 	register struct part *pt, **ppt = &dk->part;
216*41098Smckusick 
217*41098Smckusick 	for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
218*41098Smckusick 		if (strcmp(pt->name, name) == 0) {
219*41098Smckusick 			printf("%s in fstab more than once!\n", name);
220*41098Smckusick 			return;
221*41098Smckusick 		}
222*41098Smckusick 	if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
223*41098Smckusick 		fprintf(stderr, "out of memory");
224*41098Smckusick 		exit (8);
225*41098Smckusick 	}
226*41098Smckusick 	pt = *ppt;
227*41098Smckusick 	if ((pt->name = malloc((unsigned int)strlen(name) + 1)) == NULL) {
228*41098Smckusick 		fprintf(stderr, "out of memory");
229*41098Smckusick 		exit (8);
230*41098Smckusick 	}
231*41098Smckusick 	strcpy(pt->name, name);
232*41098Smckusick 	if ((pt->fsname = malloc((unsigned int)strlen(fsname) + 1)) == NULL) {
233*41098Smckusick 		fprintf(stderr, "out of memory");
234*41098Smckusick 		exit (8);
235*41098Smckusick 	}
236*41098Smckusick 	strcpy(pt->fsname, fsname);
237*41098Smckusick 	pt->next = NULL;
238*41098Smckusick 	pt->auxdata = auxdata;
239*41098Smckusick }
240*41098Smckusick 
241*41098Smckusick startdisk(dk, checkit)
242*41098Smckusick 	register struct disk *dk;
243*41098Smckusick 	int (*checkit)();
244*41098Smckusick {
245*41098Smckusick 	register struct part *pt = dk->part;
246*41098Smckusick 
247*41098Smckusick 	dk->pid = fork();
248*41098Smckusick 	if (dk->pid < 0) {
249*41098Smckusick 		perror("fork");
250*41098Smckusick 		return (8);
251*41098Smckusick 	}
252*41098Smckusick 	if (dk->pid == 0)
253*41098Smckusick 		exit((*checkit)(pt->name, pt->fsname, pt->auxdata));
254*41098Smckusick 	nrun++;
255*41098Smckusick 	return (0);
256*41098Smckusick }
257*41098Smckusick 
258*41098Smckusick char *
259*41098Smckusick blockcheck(name)
260*41098Smckusick 	char *name;
261*41098Smckusick {
262*41098Smckusick 	struct stat stslash, stblock, stchar;
263*41098Smckusick 	char *raw;
264*41098Smckusick 	int retried = 0;
265*41098Smckusick 
266*41098Smckusick 	hotroot = 0;
267*41098Smckusick 	if (stat("/", &stslash) < 0) {
268*41098Smckusick 		perror("/");
269*41098Smckusick 		printf("Can't stat root\n");
270*41098Smckusick 		return (0);
271*41098Smckusick 	}
272*41098Smckusick retry:
273*41098Smckusick 	if (stat(name, &stblock) < 0) {
274*41098Smckusick 		perror(name);
275*41098Smckusick 		printf("Can't stat %s\n", name);
276*41098Smckusick 		return (0);
277*41098Smckusick 	}
278*41098Smckusick 	if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
279*41098Smckusick 		if (stslash.st_dev == stblock.st_rdev)
280*41098Smckusick 			hotroot++;
281*41098Smckusick 		raw = rawname(name);
282*41098Smckusick 		if (stat(raw, &stchar) < 0) {
283*41098Smckusick 			perror(raw);
284*41098Smckusick 			printf("Can't stat %s\n", raw);
285*41098Smckusick 			return (name);
286*41098Smckusick 		}
287*41098Smckusick 		if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
288*41098Smckusick 			return (raw);
289*41098Smckusick 		} else {
290*41098Smckusick 			printf("%s is not a character device\n", raw);
291*41098Smckusick 			return (name);
292*41098Smckusick 		}
293*41098Smckusick 	} else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
294*41098Smckusick 		name = unrawname(name);
295*41098Smckusick 		retried++;
296*41098Smckusick 		goto retry;
297*41098Smckusick 	}
298*41098Smckusick 	printf("Can't make sense out of name %s\n", name);
299*41098Smckusick 	return (0);
300*41098Smckusick }
301*41098Smckusick 
302*41098Smckusick char *
303*41098Smckusick unrawname(name)
304*41098Smckusick 	char *name;
305*41098Smckusick {
306*41098Smckusick 	char *dp;
307*41098Smckusick 	struct stat stb;
308*41098Smckusick 
309*41098Smckusick 	if ((dp = rindex(name, '/')) == 0)
310*41098Smckusick 		return (name);
311*41098Smckusick 	if (stat(name, &stb) < 0)
312*41098Smckusick 		return (name);
313*41098Smckusick 	if ((stb.st_mode & S_IFMT) != S_IFCHR)
314*41098Smckusick 		return (name);
315*41098Smckusick 	if (*(dp + 1) != 'r')
316*41098Smckusick 		return (name);
317*41098Smckusick 	(void)strcpy(dp + 1, dp + 2);
318*41098Smckusick 	return (name);
319*41098Smckusick }
320*41098Smckusick 
321*41098Smckusick char *
322*41098Smckusick rawname(name)
323*41098Smckusick 	char *name;
324*41098Smckusick {
325*41098Smckusick 	static char rawbuf[32];
326*41098Smckusick 	char *dp;
327*41098Smckusick 
328*41098Smckusick 	if ((dp = rindex(name, '/')) == 0)
329*41098Smckusick 		return (0);
330*41098Smckusick 	*dp = 0;
331*41098Smckusick 	(void)strcpy(rawbuf, name);
332*41098Smckusick 	*dp = '/';
333*41098Smckusick 	(void)strcat(rawbuf, "/r");
334*41098Smckusick 	(void)strcat(rawbuf, dp + 1);
335*41098Smckusick 	return (rawbuf);
336*41098Smckusick }
337