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