fsck.c revision 1.9 1 /* $NetBSD: fsck.c,v 1.9 1996/12/07 19:09:11 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.9 1996/12/07 19:09:11 christos Exp $";
42
43 #include <sys/param.h>
44 #include <sys/mount.h>
45 #include <sys/queue.h>
46 #include <sys/wait.h>
47 #define DKTYPENAMES
48 #include <sys/disklabel.h>
49 #include <sys/ioctl.h>
50
51 #include <err.h>
52 #include <errno.h>
53 #include <fstab.h>
54 #include <fcntl.h>
55 #include <signal.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60
61 #include "pathnames.h"
62 #include "fsutil.h"
63
64 static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
65
66 TAILQ_HEAD(fstypelist, entry) opthead, selhead;
67
68 struct entry {
69 char *type;
70 char *options;
71 TAILQ_ENTRY(entry) entries;
72 };
73
74 static int maxrun = 0;
75 static char *options = NULL;
76 static int flags = 0;
77
78 int main __P((int, char *[]));
79
80 static int checkfs __P((const char *, const char *, const char *, void *,
81 pid_t *));
82 static int selected __P((const char *));
83 static void addoption __P((char *));
84 static const char *getoptions __P((const char *));
85 static void addentry __P((struct fstypelist *, const char *, const char *));
86 static void maketypelist __P((char *));
87 static char *catopt __P((char *, const char *, int));
88 static void mangle __P((char *, int *, const char ***, int *));
89 static char *getfslab __P((const char *));
90 static void usage __P((void));
91 static void *isok __P((struct fstab *));
92
93 int
94 main(argc, argv)
95 int argc;
96 char *argv[];
97 {
98 struct fstab *fs;
99 int i, rval = 0;
100 char *vfstype = NULL;
101 char globopt[3];
102
103 globopt[0] = '-';
104 globopt[2] = '\0';
105
106 TAILQ_INIT(&selhead);
107 TAILQ_INIT(&opthead);
108
109 while ((i = getopt(argc, argv, "dvpfnyl:t:T:")) != -1)
110 switch (i) {
111 case 'd':
112 flags |= CHECK_DEBUG;
113 break;
114
115 case 'v':
116 flags |= CHECK_VERBOSE;
117 break;
118
119 case 'p':
120 flags |= CHECK_PREEN;
121 /*FALLTHROUGH*/
122 case 'n':
123 case 'f':
124 case 'y':
125 globopt[1] = i;
126 options = catopt(options, globopt, 1);
127 break;
128
129 case 'l':
130 maxrun = atoi(optarg);
131 break;
132
133 case 'T':
134 if (*optarg)
135 addoption(optarg);
136 break;
137
138 case 't':
139 if (selhead.tqh_first != NULL)
140 errx(1, "only one -t option may be specified.");
141
142 maketypelist(optarg);
143 vfstype = optarg;
144 break;
145
146 case '?':
147 default:
148 usage();
149 /* NOTREACHED */
150 }
151
152 argc -= optind;
153 argv += optind;
154
155 if (argc == 0)
156 return checkfstab(flags, maxrun, isok, checkfs);
157
158 #define BADTYPE(type) \
159 (strcmp(type, FSTAB_RO) && \
160 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
161
162
163 for (; argc--; argv++) {
164 char *spec, *type;
165
166 if ((fs = getfsfile(*argv)) == NULL &&
167 (fs = getfsspec(*argv)) == NULL) {
168 if (vfstype == NULL)
169 vfstype = getfslab(*argv);
170 spec = *argv;
171 type = vfstype;
172 }
173 else {
174 spec = fs->fs_spec;
175 type = fs->fs_vfstype;
176 if (BADTYPE(fs->fs_type))
177 errx(1, "%s has unknown file system type.",
178 *argv);
179 }
180
181 rval |= checkfs(type, blockcheck(spec), *argv, NULL, NULL);
182 }
183
184 return rval;
185 }
186
187
188 static void *
189 isok(fs)
190 struct fstab *fs;
191 {
192 if (fs->fs_passno == 0)
193 return NULL;
194
195 if (BADTYPE(fs->fs_type))
196 return NULL;
197
198 if (!selected(fs->fs_vfstype))
199 return NULL;
200
201 return fs;
202 }
203
204
205 static int
206 checkfs(vfstype, spec, mntpt, auxarg, pidp)
207 const char *vfstype, *spec, *mntpt;
208 void *auxarg;
209 pid_t *pidp;
210 {
211 /* List of directories containing fsck_xxx subcommands. */
212 static const char *edirs[] = {
213 _PATH_SBIN,
214 _PATH_USRSBIN,
215 NULL
216 };
217 char execbase[MAXPATHLEN];
218 const char **argv, **edir;
219 pid_t pid;
220 int argc = 1, i, status, maxargc;
221 char *optbuf = NULL, execname[MAXPATHLEN + 1];
222 const char *extra = getoptions(vfstype);
223
224
225 #ifdef __GNUC__
226 /* Avoid vfork clobbering */
227 (void) &optbuf;
228 (void) &vfstype;
229 #endif
230
231 if (strcmp(vfstype, "ufs") == 0)
232 vfstype = MOUNT_UFS;
233
234 maxargc = 100;
235 argv = emalloc(sizeof(char *) * maxargc);
236
237 /* construct basename of executable and argv[0] simultaneously */
238 (void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype);
239 argv[0] = vfstype;
240
241 if (options) {
242 if (extra != NULL)
243 optbuf = catopt(options, extra, 0);
244 else
245 optbuf = estrdup(options);
246 }
247 else if (extra)
248 optbuf = estrdup(extra);
249
250 if (optbuf)
251 mangle(optbuf, &argc, &argv, &maxargc);
252
253 argv[argc++] = spec;
254 argv[argc] = NULL;
255
256 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
257 (void)printf("start %s %swait", mntpt,
258 pidp ? "no" : "");
259 for (i = 0; i < argc; i++)
260 (void)printf(" %s", argv[i]);
261 (void)printf("\n");
262 }
263
264 switch (pid = vfork()) {
265 case -1: /* Error. */
266 warn("vfork");
267 if (optbuf)
268 free(optbuf);
269 return (1);
270
271 case 0: /* Child. */
272 if (flags & CHECK_DEBUG)
273 _exit(0);
274
275 /* Go find an executable. */
276 edir = edirs;
277 do {
278 (void)snprintf(execname,
279 sizeof(execname), "%s/%s", *edir, execbase);
280 execv(execname, (char * const *)argv);
281 if (errno != ENOENT)
282 if (spec)
283 warn("exec %s for %s", execname, spec);
284 else
285 warn("exec %s", execname);
286 } while (*++edir != NULL);
287
288 if (errno == ENOENT)
289 if (spec)
290 warn("exec %s for %s", execname, spec);
291 else
292 warn("exec %s", execname);
293 _exit(1);
294 /* NOTREACHED */
295
296 default: /* Parent. */
297 if (optbuf)
298 free(optbuf);
299
300 if (pidp) {
301 *pidp = pid;
302 return 0;
303 }
304
305 if (waitpid(pid, &status, 0) < 0) {
306 warn("waitpid");
307 return (1);
308 }
309
310 if (WIFEXITED(status)) {
311 if (WEXITSTATUS(status) != 0)
312 return (WEXITSTATUS(status));
313 }
314 else if (WIFSIGNALED(status)) {
315 warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
316 return (1);
317 }
318 break;
319 }
320
321 return (0);
322 }
323
324
325 static int
326 selected(type)
327 const char *type;
328 {
329 struct entry *e;
330
331 /* If no type specified, it's always selected. */
332 for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next)
333 if (!strncmp(e->type, type, MFSNAMELEN))
334 return which == IN_LIST ? 1 : 0;
335
336 return which == IN_LIST ? 0 : 1;
337 }
338
339
340 static const char *
341 getoptions(type)
342 const char *type;
343 {
344 struct entry *e;
345
346 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
347 if (!strncmp(e->type, type, MFSNAMELEN))
348 return e->options;
349 return "";
350 }
351
352
353 static void
354 addoption(optstr)
355 char *optstr;
356 {
357 char *newoptions;
358 struct entry *e;
359
360 if ((newoptions = strchr(optstr, ':')) == NULL)
361 errx(1, "Invalid option string");
362
363 *newoptions++ = '\0';
364
365 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
366 if (!strncmp(e->type, optstr, MFSNAMELEN)) {
367 e->options = catopt(e->options, newoptions, 1);
368 return;
369 }
370 addentry(&opthead, optstr, newoptions);
371 }
372
373
374 static void
375 addentry(list, type, opts)
376 struct fstypelist *list;
377 const char *type;
378 const char *opts;
379 {
380 struct entry *e;
381
382 e = emalloc(sizeof(struct entry));
383 e->type = estrdup(type);
384 e->options = estrdup(opts);
385 TAILQ_INSERT_TAIL(list, e, entries);
386 }
387
388
389 static void
390 maketypelist(fslist)
391 char *fslist;
392 {
393 char *ptr;
394
395 if ((fslist == NULL) || (fslist[0] == '\0'))
396 errx(1, "empty type list");
397
398 if (fslist[0] == 'n' && fslist[1] == 'o') {
399 fslist += 2;
400 which = NOT_IN_LIST;
401 }
402 else
403 which = IN_LIST;
404
405 while ((ptr = strsep(&fslist, ",")) != NULL)
406 addentry(&selhead, ptr, "");
407
408 }
409
410
411 static char *
412 catopt(s0, s1, fr)
413 char *s0;
414 const char *s1;
415 int fr;
416 {
417 size_t i;
418 char *cp;
419
420 if (s0 && *s0) {
421 i = strlen(s0) + strlen(s1) + 1 + 1;
422 cp = emalloc(i);
423 (void)snprintf(cp, i, "%s,%s", s0, s1);
424 }
425 else
426 cp = estrdup(s1);
427
428 if (s0 && fr)
429 free(s0);
430 return (cp);
431 }
432
433
434 static void
435 mangle(opts, argcp, argvp, maxargcp)
436 char *opts;
437 int *argcp;
438 const char ***argvp;
439 int *maxargcp;
440 {
441 char *p, *s;
442 int argc = *argcp, maxargc = *maxargcp;
443 const char **argv = *argvp;
444
445 argc = *argcp;
446 maxargc = *maxargcp;
447
448 for (s = opts; (p = strsep(&s, ",")) != NULL;) {
449 /* always leave space for one more argument and the NULL */
450 if (argc >= maxargc - 3) {
451 maxargc += 50;
452 argv = erealloc(argv, maxargc * sizeof(char *));
453 }
454 if (*p != '\0')
455 if (*p == '-') {
456 argv[argc++] = p;
457 p = strchr(p, '=');
458 if (p) {
459 *p = '\0';
460 argv[argc++] = p+1;
461 }
462 }
463 else {
464 argv[argc++] = "-o";
465 argv[argc++] = p;
466 }
467 }
468
469 *argcp = argc;
470 *argvp = argv;
471 *maxargcp = maxargc;
472 }
473
474
475 /* Maybe this belongs to <sys/disklabel.h> */
476 static char *fscknames[] = {
477 NULL,
478 NULL,
479 NULL,
480 NULL,
481 NULL,
482 NULL,
483 NULL,
484 "ffs",
485 "msdos",
486 NULL,
487 NULL,
488 NULL,
489 NULL,
490 NULL,
491 NULL,
492 NULL,
493 NULL,
494 NULL
495 };
496
497
498 static char *
499 getfslab(str)
500 const char *str;
501 {
502 struct disklabel dl;
503 int fd;
504 char p, *vfstype;
505 u_char t;
506
507 /* deduce the filesystem type from the disk label */
508 if ((fd = open(str, O_RDONLY)) == -1)
509 err(1, "cannot open `%s'", str);
510
511 if (ioctl(fd, DIOCGDINFO, &dl) == -1)
512 err(1, "cannot get disklabel for `%s'", str);
513
514 (void) close(fd);
515
516 p = str[strlen(str) - 1];
517
518 if ((p - 'a') >= dl.d_npartitions)
519 errx(1, "partition `%s' is not defined on disk", str);
520
521 if ((t = dl.d_partitions[p - 'a'].p_fstype) >= DKMAXTYPES)
522 errx(1, "partition `%s' is not of a legal vfstype",
523 p, str);
524
525 if ((vfstype = fscknames[t]) == NULL)
526 errx(1, "vfstype `%s' on partition `%s' is not supported",
527 fstypenames[t], str);
528
529 return vfstype;
530 }
531
532
533
534 static void
535 usage()
536 {
537 extern char *__progname;
538 static const char common[] =
539 "[-dpvlyn] [-T fstype:fsoptions] [-t fstype]";
540
541 (void)fprintf(stderr, "Usage: %s %s [special|node]...\n",
542 __progname, common);
543 exit(1);
544 }
545