fsck.c revision 1.11 1 /* $NetBSD: fsck.c,v 1.11 1997/06/23 01:03:35 mikel 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.11 1997/06/23 01:03:35 mikel 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 static char *
476 getfslab(str)
477 const char *str;
478 {
479 struct disklabel dl;
480 int fd;
481 char p, *vfstype;
482 u_char t;
483
484 /* deduce the filesystem type from the disk label */
485 if ((fd = open(str, O_RDONLY)) == -1)
486 err(1, "cannot open `%s'", str);
487
488 if (ioctl(fd, DIOCGDINFO, &dl) == -1)
489 err(1, "cannot get disklabel for `%s'", str);
490
491 (void) close(fd);
492
493 p = str[strlen(str) - 1];
494
495 if ((p - 'a') >= dl.d_npartitions)
496 errx(1, "partition `%s' is not defined on disk", str);
497
498 if ((t = dl.d_partitions[p - 'a'].p_fstype) >= DKMAXTYPES)
499 errx(1, "partition `%s' is not of a legal vfstype",
500 str);
501
502 if ((vfstype = fscknames[t]) == NULL)
503 errx(1, "vfstype `%s' on partition `%s' is not supported",
504 fstypenames[t], str);
505
506 return vfstype;
507 }
508
509
510 static void
511 usage()
512 {
513 extern char *__progname;
514 static const char common[] =
515 "[-dpvlyn] [-T fstype:fsoptions] [-t fstype]";
516
517 (void)fprintf(stderr, "Usage: %s %s [special|node]...\n",
518 __progname, common);
519 exit(1);
520 }
521