fsck.c revision 1.8 1 1.8 christos /* $NetBSD: fsck.c,v 1.8 1996/12/05 18:30:23 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.8 christos static char rcsid[] = "$NetBSD: fsck.c,v 1.8 1996/12/05 18:30:23 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.8 christos (void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype);
235 1.8 christos
236 1.7 christos maxargc = 100;
237 1.7 christos argv = emalloc(sizeof(char *) * maxargc);
238 1.7 christos
239 1.8 christos /* construct basename of executable and argv[0] simultaneously */
240 1.8 christos (void)strncat(execbase,
241 1.8 christos (const char *)vfstype,
242 1.8 christos sizeof(execbase) - 6); /* strlen("fsck_") + \0 */
243 1.8 christos argv[0] = vfstype;
244 1.2 christos
245 1.2 christos if (options) {
246 1.2 christos if (extra != NULL)
247 1.2 christos optbuf = catopt(options, extra, 0);
248 1.2 christos else
249 1.2 christos optbuf = estrdup(options);
250 1.2 christos }
251 1.2 christos else if (extra)
252 1.2 christos optbuf = estrdup(extra);
253 1.2 christos
254 1.2 christos if (optbuf)
255 1.7 christos mangle(optbuf, &argc, &argv, &maxargc);
256 1.2 christos
257 1.2 christos argv[argc++] = spec;
258 1.7 christos argv[argc] = NULL;
259 1.1 christos
260 1.4 christos if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
261 1.8 christos (void)printf("start %s %swait", mntpt,
262 1.8 christos pidp ? "no" : "");
263 1.8 christos for (i = 0; i < argc; i++)
264 1.1 christos (void)printf(" %s", argv[i]);
265 1.1 christos (void)printf("\n");
266 1.1 christos }
267 1.1 christos
268 1.1 christos switch (pid = vfork()) {
269 1.1 christos case -1: /* Error. */
270 1.1 christos warn("vfork");
271 1.1 christos if (optbuf)
272 1.1 christos free(optbuf);
273 1.1 christos return (1);
274 1.1 christos
275 1.1 christos case 0: /* Child. */
276 1.4 christos if (flags & CHECK_DEBUG)
277 1.2 christos _exit(0);
278 1.2 christos
279 1.1 christos /* Go find an executable. */
280 1.1 christos edir = edirs;
281 1.1 christos do {
282 1.1 christos (void)snprintf(execname,
283 1.8 christos sizeof(execname), "%s/%s", *edir, execbase);
284 1.1 christos execv(execname, (char * const *)argv);
285 1.1 christos if (errno != ENOENT)
286 1.1 christos if (spec)
287 1.1 christos warn("exec %s for %s", execname, spec);
288 1.1 christos else
289 1.1 christos warn("exec %s", execname);
290 1.1 christos } while (*++edir != NULL);
291 1.1 christos
292 1.1 christos if (errno == ENOENT)
293 1.1 christos if (spec)
294 1.1 christos warn("exec %s for %s", execname, spec);
295 1.1 christos else
296 1.1 christos warn("exec %s", execname);
297 1.8 christos _exit(1);
298 1.1 christos /* NOTREACHED */
299 1.1 christos
300 1.1 christos default: /* Parent. */
301 1.1 christos if (optbuf)
302 1.1 christos free(optbuf);
303 1.1 christos
304 1.2 christos if (pidp) {
305 1.2 christos *pidp = pid;
306 1.2 christos return 0;
307 1.2 christos }
308 1.2 christos
309 1.1 christos if (waitpid(pid, &status, 0) < 0) {
310 1.1 christos warn("waitpid");
311 1.1 christos return (1);
312 1.1 christos }
313 1.1 christos
314 1.1 christos if (WIFEXITED(status)) {
315 1.1 christos if (WEXITSTATUS(status) != 0)
316 1.1 christos return (WEXITSTATUS(status));
317 1.1 christos }
318 1.1 christos else if (WIFSIGNALED(status)) {
319 1.1 christos warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
320 1.1 christos return (1);
321 1.1 christos }
322 1.1 christos break;
323 1.1 christos }
324 1.1 christos
325 1.1 christos return (0);
326 1.1 christos }
327 1.1 christos
328 1.1 christos
329 1.1 christos static int
330 1.1 christos selected(type)
331 1.1 christos const char *type;
332 1.1 christos {
333 1.1 christos struct entry *e;
334 1.1 christos
335 1.1 christos /* If no type specified, it's always selected. */
336 1.2 christos for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next)
337 1.1 christos if (!strncmp(e->type, type, MFSNAMELEN))
338 1.1 christos return which == IN_LIST ? 1 : 0;
339 1.1 christos
340 1.1 christos return which == IN_LIST ? 0 : 1;
341 1.1 christos }
342 1.1 christos
343 1.1 christos
344 1.2 christos static const char *
345 1.2 christos getoptions(type)
346 1.1 christos const char *type;
347 1.1 christos {
348 1.1 christos struct entry *e;
349 1.1 christos
350 1.2 christos for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
351 1.2 christos if (!strncmp(e->type, type, MFSNAMELEN))
352 1.2 christos return e->options;
353 1.2 christos return "";
354 1.1 christos }
355 1.1 christos
356 1.1 christos
357 1.1 christos static void
358 1.2 christos addoption(optstr)
359 1.2 christos char *optstr;
360 1.1 christos {
361 1.2 christos char *newoptions;
362 1.1 christos struct entry *e;
363 1.1 christos
364 1.2 christos if ((newoptions = strchr(optstr, ':')) == NULL)
365 1.2 christos errx(1, "Invalid option string");
366 1.2 christos
367 1.2 christos *newoptions++ = '\0';
368 1.2 christos
369 1.2 christos for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
370 1.2 christos if (!strncmp(e->type, optstr, MFSNAMELEN)) {
371 1.2 christos e->options = catopt(e->options, newoptions, 1);
372 1.1 christos return;
373 1.1 christos }
374 1.2 christos addentry(&opthead, optstr, newoptions);
375 1.1 christos }
376 1.1 christos
377 1.1 christos
378 1.1 christos static void
379 1.2 christos addentry(list, type, opts)
380 1.2 christos struct fstypelist *list;
381 1.1 christos const char *type;
382 1.2 christos const char *opts;
383 1.1 christos {
384 1.2 christos struct entry *e;
385 1.2 christos
386 1.2 christos e = emalloc(sizeof(struct entry));
387 1.2 christos e->type = estrdup(type);
388 1.2 christos e->options = estrdup(opts);
389 1.2 christos TAILQ_INSERT_TAIL(list, e, entries);
390 1.1 christos }
391 1.1 christos
392 1.1 christos
393 1.1 christos static void
394 1.1 christos maketypelist(fslist)
395 1.1 christos char *fslist;
396 1.1 christos {
397 1.1 christos char *ptr;
398 1.1 christos
399 1.1 christos if ((fslist == NULL) || (fslist[0] == '\0'))
400 1.1 christos errx(1, "empty type list");
401 1.1 christos
402 1.1 christos if (fslist[0] == 'n' && fslist[1] == 'o') {
403 1.1 christos fslist += 2;
404 1.1 christos which = NOT_IN_LIST;
405 1.1 christos }
406 1.1 christos else
407 1.1 christos which = IN_LIST;
408 1.1 christos
409 1.1 christos while ((ptr = strsep(&fslist, ",")) != NULL)
410 1.2 christos addentry(&selhead, ptr, "");
411 1.1 christos
412 1.1 christos }
413 1.1 christos
414 1.1 christos
415 1.1 christos static char *
416 1.2 christos catopt(s0, s1, fr)
417 1.1 christos char *s0;
418 1.1 christos const char *s1;
419 1.2 christos int fr;
420 1.1 christos {
421 1.1 christos size_t i;
422 1.1 christos char *cp;
423 1.1 christos
424 1.1 christos if (s0 && *s0) {
425 1.1 christos i = strlen(s0) + strlen(s1) + 1 + 1;
426 1.1 christos cp = emalloc(i);
427 1.1 christos (void)snprintf(cp, i, "%s,%s", s0, s1);
428 1.1 christos }
429 1.1 christos else
430 1.1 christos cp = estrdup(s1);
431 1.1 christos
432 1.2 christos if (s0 && fr)
433 1.1 christos free(s0);
434 1.1 christos return (cp);
435 1.1 christos }
436 1.1 christos
437 1.1 christos
438 1.1 christos static void
439 1.7 christos mangle(opts, argcp, argvp, maxargcp)
440 1.2 christos char *opts;
441 1.1 christos int *argcp;
442 1.7 christos const char ***argvp;
443 1.7 christos int *maxargcp;
444 1.1 christos {
445 1.1 christos char *p, *s;
446 1.7 christos int argc = *argcp, maxargc = *maxargcp;
447 1.7 christos const char **argv = *argvp;
448 1.1 christos
449 1.1 christos argc = *argcp;
450 1.7 christos maxargc = *maxargcp;
451 1.7 christos
452 1.7 christos for (s = opts; (p = strsep(&s, ",")) != NULL;) {
453 1.7 christos /* always leave space for one more argument and the NULL */
454 1.7 christos if (argc >= maxargc - 3) {
455 1.7 christos maxargc += 50;
456 1.7 christos argv = erealloc(argv, maxargc * sizeof(char *));
457 1.7 christos }
458 1.1 christos if (*p != '\0')
459 1.1 christos if (*p == '-') {
460 1.1 christos argv[argc++] = p;
461 1.1 christos p = strchr(p, '=');
462 1.1 christos if (p) {
463 1.1 christos *p = '\0';
464 1.1 christos argv[argc++] = p+1;
465 1.1 christos }
466 1.1 christos }
467 1.1 christos else {
468 1.1 christos argv[argc++] = "-o";
469 1.1 christos argv[argc++] = p;
470 1.1 christos }
471 1.7 christos }
472 1.1 christos
473 1.1 christos *argcp = argc;
474 1.7 christos *argvp = argv;
475 1.7 christos *maxargcp = maxargc;
476 1.1 christos }
477 1.8 christos
478 1.8 christos
479 1.8 christos /* Maybe this belongs to <sys/disklabel.h> */
480 1.8 christos static char *fscknames[] = {
481 1.8 christos NULL,
482 1.8 christos NULL,
483 1.8 christos NULL,
484 1.8 christos NULL,
485 1.8 christos NULL,
486 1.8 christos NULL,
487 1.8 christos NULL,
488 1.8 christos "ffs",
489 1.8 christos "msdos",
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 NULL,
496 1.8 christos NULL,
497 1.8 christos NULL,
498 1.8 christos NULL
499 1.8 christos };
500 1.8 christos
501 1.8 christos
502 1.8 christos static char *
503 1.8 christos getfslab(str)
504 1.8 christos const char *str;
505 1.8 christos {
506 1.8 christos struct disklabel dl;
507 1.8 christos int fd;
508 1.8 christos char p, *vfstype;
509 1.8 christos u_char t;
510 1.8 christos
511 1.8 christos /* deduce the filesystem type from the disk label */
512 1.8 christos if ((fd = open(str, O_RDONLY)) == -1)
513 1.8 christos err(1, "cannot open `%s'", str);
514 1.8 christos
515 1.8 christos if (ioctl(fd, DIOCGDINFO, &dl) == -1)
516 1.8 christos err(1, "cannot get disklabel for `%s'", str);
517 1.8 christos
518 1.8 christos (void) close(fd);
519 1.8 christos
520 1.8 christos p = str[strlen(str) - 1];
521 1.8 christos
522 1.8 christos if ((p - 'a') >= dl.d_npartitions)
523 1.8 christos errx(1, "partition `%s' is not defined on disk", str);
524 1.8 christos
525 1.8 christos if ((t = dl.d_partitions[p - 'a'].p_fstype) >= DKMAXTYPES)
526 1.8 christos errx(1, "partition `%s' is not of a legal vfstype",
527 1.8 christos p, str);
528 1.8 christos
529 1.8 christos if ((vfstype = fscknames[t]) == NULL)
530 1.8 christos errx(1, "vfstype `%s' on partition `%s' is not supported",
531 1.8 christos fstypenames[t], str);
532 1.8 christos
533 1.8 christos return vfstype;
534 1.8 christos }
535 1.8 christos
536 1.1 christos
537 1.1 christos
538 1.1 christos static void
539 1.1 christos usage()
540 1.1 christos {
541 1.1 christos extern char *__progname;
542 1.2 christos static const char common[] =
543 1.4 christos "[-dpvlyn] [-T fstype:fsoptions] [-t fstype]";
544 1.1 christos
545 1.4 christos (void)fprintf(stderr, "Usage: %s %s [special|node]...\n",
546 1.4 christos __progname, common);
547 1.1 christos exit(1);
548 1.1 christos }
549