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
checkfstab(preen,maxrun,docheck,chkit)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 *
finddisk(name)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
addpart(name,fsname,auxdata)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
startdisk(dk,checkit)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 *
blockcheck(origname)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 *
unrawname(name)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 *
rawname(name)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