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