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