fsck.c revision 1.1 1 /* $NetBSD: fsck.c,v 1.1 1996/09/11 20:27:14 christos Exp $ */
2
3 /*
4 * Copyright (c) 1996 Christos Zoulas. All rights reserved.
5 * Copyright (c) 1980, 1989, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * From: @(#)mount.c 8.19 (Berkeley) 4/19/94
37 * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
38 *
39 */
40
41 static char rcsid[] = "$NetBSD: fsck.c,v 1.1 1996/09/11 20:27:14 christos Exp $";
42
43 #include <sys/param.h>
44 #include <sys/mount.h>
45 #include <sys/queue.h>
46 #include <sys/wait.h>
47
48 #include <err.h>
49 #include <errno.h>
50 #include <fstab.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #include "pathnames.h"
58
59 static enum { IN_LIST, NOT_IN_LIST } which;
60
61 TAILQ_HEAD(fstypelist, entry) head;
62
63 struct entry {
64 char *type;
65 TAILQ_ENTRY(entry) entries;
66 };
67
68 static int preen = 0, verbose = 0, debug = 0;
69 static struct fstypelist *typelist;
70
71 static int checkfs __P((const char *, const char *, const char *));
72 static int selected __P((const char *));
73 static void addentry __P((const char *));
74 static void rementry __P((const char *));
75 static void unselect __P((const char *));
76 static void maketypelist __P((char *));
77 static char *catopt __P((char *, const char *));
78 static void mangle __P((char *, int *, const char **));
79 static void *emalloc __P((size_t));
80 static char *estrdup __P((const char *));
81 static void usage __P((void));
82
83
84 int
85 main(argc, argv)
86 int argc;
87 char * const argv[];
88 {
89 struct fstab *fs;
90 int i, rval = 0;
91 char *options = NULL;
92 char *vfstype = NULL;
93
94 while ((i = getopt(argc, argv, "dvpnyt:o:")) != -1)
95 switch (i) {
96 case 'd':
97 debug++;
98 break;
99
100 case 'v':
101 verbose++;
102 break;
103
104 case 'y':
105 options = catopt(options, "-y");
106 break;
107
108 case 'n':
109 options = catopt(options, "-n");
110 break;
111
112 case 'o':
113 if (*optarg)
114 options = catopt(options, optarg);
115 break;
116
117 case 't':
118 if (typelist != NULL)
119 errx(1, "only one -t option may be specified.");
120 maketypelist(optarg);
121 vfstype = optarg;
122 break;
123
124 case 'p':
125 options = catopt(options, "-p");
126 preen++;
127 break;
128
129 case '?':
130 default:
131 usage();
132 /* NOTREACHED */
133 }
134
135 argc -= optind;
136 argv += optind;
137
138 #define BADTYPE(type) \
139 (strcmp(type, FSTAB_RO) && \
140 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
141
142 if (argc == 0) {
143 while ((fs = getfsent()) != NULL) {
144
145 if (fs->fs_passno == 0)
146 continue;
147
148 if (BADTYPE(fs->fs_type))
149 continue;
150
151 if (!selected(fs->fs_vfstype))
152 continue;
153
154 if (preen) {
155 rval |= checkfs(fs->fs_vfstype, NULL, options);
156 unselect(fs->fs_vfstype);
157 }
158 else
159 rval |= checkfs(fs->fs_vfstype, fs->fs_spec,
160 options);
161 }
162 return rval;
163 }
164
165 /*
166 * When we select specific filesystems, we cannot preen
167 */
168 if (preen)
169 usage();
170
171 for (; argc--; argv++) {
172 char *spec, *type;
173
174 if ((fs = getfsfile(*argv)) == NULL &&
175 (fs = getfsspec(*argv)) == NULL) {
176 if (vfstype == NULL)
177 errx(1,
178 "%s: unknown special file or file system.",
179 *argv);
180 spec = *argv;
181 type = vfstype;
182 }
183 else {
184 spec = fs->fs_spec;
185 type = fs->fs_vfstype;
186 if (BADTYPE(fs->fs_type))
187 errx(1, "%s has unknown file system type.",
188 *argv);
189 }
190
191 rval |= checkfs(type, spec, options);
192 }
193
194 return rval;
195 }
196
197 static int
198 checkfs(vfstype, spec, options)
199 const char *vfstype, *spec, *options;
200 {
201 /* List of directories containing fsck_xxx subcommands. */
202 static const char *edirs[] = {
203 _PATH_SBIN,
204 _PATH_USRSBIN,
205 NULL
206 };
207 const char *argv[100], **edir;
208 pid_t pid;
209 int argc, i, status;
210 char *optbuf = NULL, execname[MAXPATHLEN + 1];
211
212 #ifdef __GNUC__
213 /* Avoid vfork clobbering */
214 (void) &optbuf;
215 #endif
216
217 argc = 0;
218 argv[argc++] = vfstype;
219 if (options)
220 mangle(optbuf = estrdup(options), &argc, argv);
221 if (spec)
222 argv[argc++] = spec;
223 argv[argc] = NULL;
224
225 if (debug || verbose) {
226 (void)printf("fsck_%s", vfstype);
227 for (i = 1; i < argc; i++)
228 (void)printf(" %s", argv[i]);
229 (void)printf("\n");
230 if (debug)
231 return (0);
232 }
233
234 switch (pid = vfork()) {
235 case -1: /* Error. */
236 warn("vfork");
237 if (optbuf)
238 free(optbuf);
239 return (1);
240
241 case 0: /* Child. */
242 /* Go find an executable. */
243 edir = edirs;
244 do {
245 (void)snprintf(execname,
246 sizeof(execname), "%s/fsck_%s", *edir, vfstype);
247 execv(execname, (char * const *)argv);
248 if (errno != ENOENT)
249 if (spec)
250 warn("exec %s for %s", execname, spec);
251 else
252 warn("exec %s", execname);
253 } while (*++edir != NULL);
254
255 if (errno == ENOENT)
256 if (spec)
257 warn("exec %s for %s", execname, spec);
258 else
259 warn("exec %s", execname);
260 exit(1);
261 /* NOTREACHED */
262
263 default: /* Parent. */
264 if (optbuf)
265 free(optbuf);
266
267 if (waitpid(pid, &status, 0) < 0) {
268 warn("waitpid");
269 return (1);
270 }
271
272 if (WIFEXITED(status)) {
273 if (WEXITSTATUS(status) != 0)
274 return (WEXITSTATUS(status));
275 }
276 else if (WIFSIGNALED(status)) {
277 warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
278 return (1);
279 }
280 break;
281 }
282
283 return (0);
284 }
285
286
287 static int
288 selected(type)
289 const char *type;
290 {
291 struct entry *e;
292
293 /* If no type specified, it's always selected. */
294 if (typelist == NULL)
295 return (1);
296
297 for (e = typelist->tqh_first; e != NULL; e = e->entries.tqe_next)
298 if (!strncmp(e->type, type, MFSNAMELEN))
299 return which == IN_LIST ? 1 : 0;
300
301 return which == IN_LIST ? 0 : 1;
302 }
303
304
305 static void
306 addentry(type)
307 const char *type;
308 {
309 struct entry *e;
310
311 e = emalloc(sizeof(struct entry));
312 e->type = estrdup(type);
313
314 TAILQ_INSERT_TAIL(typelist, e, entries);
315 }
316
317
318 static void
319 rementry(type)
320 const char *type;
321 {
322 struct entry *e;
323
324 for (e = typelist->tqh_first; e != NULL; e = e->entries.tqe_next)
325 if (!strncmp(e->type, type, MFSNAMELEN)) {
326 TAILQ_REMOVE(typelist, e, entries);
327 free(e->type);
328 free(e);
329 return;
330 }
331 }
332
333
334 static void
335 unselect(type)
336 const char *type;
337 {
338 if (typelist == NULL) {
339 TAILQ_INIT(&head);
340 typelist = &head;
341 which = NOT_IN_LIST;
342 addentry(type);
343 return;
344 }
345 if (which == IN_LIST)
346 rementry(type);
347 else
348 addentry(type);
349 }
350
351
352 static void
353 maketypelist(fslist)
354 char *fslist;
355 {
356 char *ptr;
357
358 if (typelist == NULL) {
359 TAILQ_INIT(&head);
360 typelist = &head;
361 }
362
363 if ((fslist == NULL) || (fslist[0] == '\0'))
364 errx(1, "empty type list");
365
366 if (fslist[0] == 'n' && fslist[1] == 'o') {
367 fslist += 2;
368 which = NOT_IN_LIST;
369 }
370 else
371 which = IN_LIST;
372
373 while ((ptr = strsep(&fslist, ",")) != NULL)
374 addentry(ptr);
375
376 }
377
378
379 static char *
380 catopt(s0, s1)
381 char *s0;
382 const char *s1;
383 {
384 size_t i;
385 char *cp;
386
387 if (s0 && *s0) {
388 i = strlen(s0) + strlen(s1) + 1 + 1;
389 cp = emalloc(i);
390 (void)snprintf(cp, i, "%s,%s", s0, s1);
391 }
392 else
393 cp = estrdup(s1);
394
395 if (s0)
396 free(s0);
397 return (cp);
398 }
399
400
401 static void
402 mangle(options, argcp, argv)
403 char *options;
404 int *argcp;
405 const char **argv;
406 {
407 char *p, *s;
408 int argc;
409
410 argc = *argcp;
411 for (s = options; (p = strsep(&s, ",")) != NULL;)
412 if (*p != '\0')
413 if (*p == '-') {
414 argv[argc++] = p;
415 p = strchr(p, '=');
416 if (p) {
417 *p = '\0';
418 argv[argc++] = p+1;
419 }
420 }
421 else {
422 argv[argc++] = "-o";
423 argv[argc++] = p;
424 }
425
426 *argcp = argc;
427 }
428
429
430 static void *
431 emalloc(s)
432 size_t s;
433 {
434 void *p = malloc(s);
435 if (p == NULL)
436 err(1, "malloc failed");
437 return p;
438 }
439
440
441 static char *
442 estrdup(s)
443 const char *s;
444 {
445 char *p = strdup(s);
446 if (p == NULL)
447 err(1, "strdup failed");
448 return p;
449 }
450
451
452 static void
453 usage()
454 {
455 extern char *__progname;
456 static const char common[] = "dvYyNn] [-o fsoptions] [-t fstype]";
457
458 (void)fprintf(stderr, "Usage: %s [-p%s\n\t%s [-%s [special|node]...\n",
459 __progname, common, __progname, common);
460 exit(1);
461 }
462