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