fsck.c revision 1.3 1 /* $NetBSD: fsck.c,v 1.3 1996/09/27 21:51:03 cgd 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.3 1996/09/27 21:51:03 cgd 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 #include "extern.h"
59 #include "util.h"
60
61 static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
62
63 TAILQ_HEAD(fstypelist, entry) opthead, selhead;
64
65 struct entry {
66 char *type;
67 char *options;
68 TAILQ_ENTRY(entry) entries;
69 };
70
71 static int preen = 0, maxrun = 0;
72 int debug = 0, verbose = 0;
73 static char *options = NULL;
74
75 int main __P((int, char *[]));
76
77 static int checkfs __P((const char *, const char *, pid_t *));
78 static int selected __P((const char *));
79 static void addoption __P((char *));
80 static const char *getoptions __P((const char *));
81 static void addentry __P((struct fstypelist *, const char *, const char *));
82 static void maketypelist __P((char *));
83 static char *catopt __P((char *, const char *, int));
84 static void mangle __P((char *, int *, const char **));
85 static void usage __P((void));
86 static int isok __P((struct fstab *));
87
88
89 int
90 main(argc, argv)
91 int argc;
92 char *argv[];
93 {
94 struct fstab *fs;
95 int i, rval = 0;
96 char *vfstype = NULL;
97
98 TAILQ_INIT(&selhead);
99 TAILQ_INIT(&opthead);
100
101 while ((i = getopt(argc, argv, "dvpnyl:t:T:")) != -1)
102 switch (i) {
103 #ifdef DEBUG
104 # define DEBUGOPT "d"
105 case 'd':
106 debug++;
107 break;
108 #else
109 # define DEBUGOPT ""
110 #endif
111
112 case 'v':
113 verbose++;
114 break;
115
116 case 'y':
117 options = catopt(options, "-y", 1);
118 break;
119
120 case 'l':
121 maxrun = atoi(optarg);
122 break;
123
124 case 'n':
125 options = catopt(options, "-n", 1);
126 break;
127
128 case 'T':
129 if (*optarg)
130 addoption(optarg);
131 break;
132
133 case 't':
134 if (selhead.tqh_first != NULL)
135 errx(1, "only one -t option may be specified.");
136
137 maketypelist(optarg);
138 vfstype = optarg;
139 break;
140
141 case 'p':
142 options = catopt(options, "-p", 1);
143 preen++;
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(preen, 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 errx(1,
170 "%s: unknown special file or file system.",
171 *argv);
172 spec = *argv;
173 type = vfstype;
174 }
175 else {
176 spec = fs->fs_spec;
177 type = fs->fs_vfstype;
178 if (BADTYPE(fs->fs_type))
179 errx(1, "%s has unknown file system type.",
180 *argv);
181 }
182
183 rval |= checkfs(type, blockcheck(spec), NULL);
184 }
185
186 return rval;
187 }
188
189
190 static int
191 isok(fs)
192 struct fstab *fs;
193 {
194 if (fs->fs_passno == 0)
195 return 0;
196
197 if (BADTYPE(fs->fs_type))
198 return 0;
199
200 if (!selected(fs->fs_vfstype))
201 return 0;
202
203 return 1;
204 }
205
206
207 static int
208 checkfs(vfstype, spec, pidp)
209 const char *vfstype, *spec;
210 pid_t *pidp;
211 {
212 /* List of directories containing fsck_xxx subcommands. */
213 static const char *edirs[] = {
214 _PATH_SBIN,
215 _PATH_USRSBIN,
216 NULL
217 };
218 const char *argv[100], **edir;
219 pid_t pid;
220 int argc, i, status;
221 char *optbuf = NULL, execname[MAXPATHLEN + 1];
222 const char *extra = getoptions(vfstype);
223
224 #ifdef __GNUC__
225 /* Avoid vfork clobbering */
226 (void) &optbuf;
227 #endif
228
229 if (strcmp(vfstype, "ufs") == 0)
230 vfstype = MOUNT_UFS;
231
232 argc = 0;
233 argv[argc++] = vfstype;
234
235 if (options) {
236 if (extra != NULL)
237 optbuf = catopt(options, extra, 0);
238 else
239 optbuf = estrdup(options);
240 }
241 else if (extra)
242 optbuf = estrdup(extra);
243
244 if (optbuf)
245 mangle(optbuf, &argc, argv);
246
247 argv[argc++] = spec;
248
249 if (debug || verbose) {
250 (void)printf("start %swait fsck_%s", pidp ? "no" : "",
251 vfstype);
252 for (i = 1; i < argc; i++)
253 (void)printf(" %s", argv[i]);
254 (void)printf("\n");
255 }
256
257 switch (pid = vfork()) {
258 case -1: /* Error. */
259 warn("vfork");
260 if (optbuf)
261 free(optbuf);
262 return (1);
263
264 case 0: /* Child. */
265 #ifdef DEBUG
266 if (debug)
267 _exit(0);
268 #endif
269
270 /* Go find an executable. */
271 edir = edirs;
272 do {
273 (void)snprintf(execname,
274 sizeof(execname), "%s/fsck_%s", *edir, vfstype);
275 execv(execname, (char * const *)argv);
276 if (errno != ENOENT)
277 if (spec)
278 warn("exec %s for %s", execname, spec);
279 else
280 warn("exec %s", execname);
281 } while (*++edir != NULL);
282
283 if (errno == ENOENT)
284 if (spec)
285 warn("exec %s for %s", execname, spec);
286 else
287 warn("exec %s", execname);
288 exit(1);
289 /* NOTREACHED */
290
291 default: /* Parent. */
292 if (optbuf)
293 free(optbuf);
294
295 if (pidp) {
296 *pidp = pid;
297 return 0;
298 }
299
300 if (waitpid(pid, &status, 0) < 0) {
301 warn("waitpid");
302 return (1);
303 }
304
305 if (WIFEXITED(status)) {
306 if (WEXITSTATUS(status) != 0)
307 return (WEXITSTATUS(status));
308 }
309 else if (WIFSIGNALED(status)) {
310 warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
311 return (1);
312 }
313 break;
314 }
315
316 return (0);
317 }
318
319
320 static int
321 selected(type)
322 const char *type;
323 {
324 struct entry *e;
325
326 /* If no type specified, it's always selected. */
327 for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next)
328 if (!strncmp(e->type, type, MFSNAMELEN))
329 return which == IN_LIST ? 1 : 0;
330
331 return which == IN_LIST ? 0 : 1;
332 }
333
334
335 static const char *
336 getoptions(type)
337 const char *type;
338 {
339 struct entry *e;
340
341 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
342 if (!strncmp(e->type, type, MFSNAMELEN))
343 return e->options;
344 return "";
345 }
346
347
348 static void
349 addoption(optstr)
350 char *optstr;
351 {
352 char *newoptions;
353 struct entry *e;
354
355 if ((newoptions = strchr(optstr, ':')) == NULL)
356 errx(1, "Invalid option string");
357
358 *newoptions++ = '\0';
359
360 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
361 if (!strncmp(e->type, optstr, MFSNAMELEN)) {
362 e->options = catopt(e->options, newoptions, 1);
363 return;
364 }
365 addentry(&opthead, optstr, newoptions);
366 }
367
368
369 static void
370 addentry(list, type, opts)
371 struct fstypelist *list;
372 const char *type;
373 const char *opts;
374 {
375 struct entry *e;
376
377 e = emalloc(sizeof(struct entry));
378 e->type = estrdup(type);
379 e->options = estrdup(opts);
380 TAILQ_INSERT_TAIL(list, e, entries);
381 }
382
383
384 static void
385 maketypelist(fslist)
386 char *fslist;
387 {
388 char *ptr;
389
390 if ((fslist == NULL) || (fslist[0] == '\0'))
391 errx(1, "empty type list");
392
393 if (fslist[0] == 'n' && fslist[1] == 'o') {
394 fslist += 2;
395 which = NOT_IN_LIST;
396 }
397 else
398 which = IN_LIST;
399
400 while ((ptr = strsep(&fslist, ",")) != NULL)
401 addentry(&selhead, ptr, "");
402
403 }
404
405
406 static char *
407 catopt(s0, s1, fr)
408 char *s0;
409 const char *s1;
410 int fr;
411 {
412 size_t i;
413 char *cp;
414
415 if (s0 && *s0) {
416 i = strlen(s0) + strlen(s1) + 1 + 1;
417 cp = emalloc(i);
418 (void)snprintf(cp, i, "%s,%s", s0, s1);
419 }
420 else
421 cp = estrdup(s1);
422
423 if (s0 && fr)
424 free(s0);
425 return (cp);
426 }
427
428
429 static void
430 mangle(opts, argcp, argv)
431 char *opts;
432 int *argcp;
433 const char **argv;
434 {
435 char *p, *s;
436 int argc;
437
438 argc = *argcp;
439 for (s = opts; (p = strsep(&s, ",")) != NULL;)
440 if (*p != '\0')
441 if (*p == '-') {
442 argv[argc++] = p;
443 p = strchr(p, '=');
444 if (p) {
445 *p = '\0';
446 argv[argc++] = p+1;
447 }
448 }
449 else {
450 argv[argc++] = "-o";
451 argv[argc++] = p;
452 }
453
454 *argcp = argc;
455 }
456
457
458 static void
459 usage()
460 {
461 extern char *__progname;
462 static const char common[] =
463 "pvlyn] [-T fstype:fsoptions] [-t fstype]";
464
465 (void)fprintf(stderr, "Usage: %s [-%s%s [special|node]...\n",
466 __progname, DEBUGOPT, common);
467 exit(1);
468 }
469