fsck.c revision 1.2 1 /* $NetBSD: fsck.c,v 1.2 1996/09/23 16:11:34 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.2 1996/09/23 16:11:34 christos 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 argc = 0;
230 argv[argc++] = vfstype;
231
232 if (options) {
233 if (extra != NULL)
234 optbuf = catopt(options, extra, 0);
235 else
236 optbuf = estrdup(options);
237 }
238 else if (extra)
239 optbuf = estrdup(extra);
240
241 if (optbuf)
242 mangle(optbuf, &argc, argv);
243
244 argv[argc++] = spec;
245
246 if (debug || verbose) {
247 (void)printf("start %swait fsck_%s", vfstype,
248 pidp ? "no" : "");
249 for (i = 1; i < argc; i++)
250 (void)printf(" %s", argv[i]);
251 (void)printf("\n");
252 }
253
254 switch (pid = vfork()) {
255 case -1: /* Error. */
256 warn("vfork");
257 if (optbuf)
258 free(optbuf);
259 return (1);
260
261 case 0: /* Child. */
262 #ifdef DEBUG
263 if (debug)
264 _exit(0);
265 #endif
266
267 /* Go find an executable. */
268 edir = edirs;
269 do {
270 (void)snprintf(execname,
271 sizeof(execname), "%s/fsck_%s", *edir, vfstype);
272 execv(execname, (char * const *)argv);
273 if (errno != ENOENT)
274 if (spec)
275 warn("exec %s for %s", execname, spec);
276 else
277 warn("exec %s", execname);
278 } while (*++edir != NULL);
279
280 if (errno == ENOENT)
281 if (spec)
282 warn("exec %s for %s", execname, spec);
283 else
284 warn("exec %s", execname);
285 exit(1);
286 /* NOTREACHED */
287
288 default: /* Parent. */
289 if (optbuf)
290 free(optbuf);
291
292 if (pidp) {
293 *pidp = pid;
294 return 0;
295 }
296
297 if (waitpid(pid, &status, 0) < 0) {
298 warn("waitpid");
299 return (1);
300 }
301
302 if (WIFEXITED(status)) {
303 if (WEXITSTATUS(status) != 0)
304 return (WEXITSTATUS(status));
305 }
306 else if (WIFSIGNALED(status)) {
307 warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
308 return (1);
309 }
310 break;
311 }
312
313 return (0);
314 }
315
316
317 static int
318 selected(type)
319 const char *type;
320 {
321 struct entry *e;
322
323 /* If no type specified, it's always selected. */
324 for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next)
325 if (!strncmp(e->type, type, MFSNAMELEN))
326 return which == IN_LIST ? 1 : 0;
327
328 return which == IN_LIST ? 0 : 1;
329 }
330
331
332 static const char *
333 getoptions(type)
334 const char *type;
335 {
336 struct entry *e;
337
338 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
339 if (!strncmp(e->type, type, MFSNAMELEN))
340 return e->options;
341 return "";
342 }
343
344
345 static void
346 addoption(optstr)
347 char *optstr;
348 {
349 char *newoptions;
350 struct entry *e;
351
352 if ((newoptions = strchr(optstr, ':')) == NULL)
353 errx(1, "Invalid option string");
354
355 *newoptions++ = '\0';
356
357 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
358 if (!strncmp(e->type, optstr, MFSNAMELEN)) {
359 e->options = catopt(e->options, newoptions, 1);
360 return;
361 }
362 addentry(&opthead, optstr, newoptions);
363 }
364
365
366 static void
367 addentry(list, type, opts)
368 struct fstypelist *list;
369 const char *type;
370 const char *opts;
371 {
372 struct entry *e;
373
374 e = emalloc(sizeof(struct entry));
375 e->type = estrdup(type);
376 e->options = estrdup(opts);
377 TAILQ_INSERT_TAIL(list, e, entries);
378 }
379
380
381 static void
382 maketypelist(fslist)
383 char *fslist;
384 {
385 char *ptr;
386
387 if ((fslist == NULL) || (fslist[0] == '\0'))
388 errx(1, "empty type list");
389
390 if (fslist[0] == 'n' && fslist[1] == 'o') {
391 fslist += 2;
392 which = NOT_IN_LIST;
393 }
394 else
395 which = IN_LIST;
396
397 while ((ptr = strsep(&fslist, ",")) != NULL)
398 addentry(&selhead, ptr, "");
399
400 }
401
402
403 static char *
404 catopt(s0, s1, fr)
405 char *s0;
406 const char *s1;
407 int fr;
408 {
409 size_t i;
410 char *cp;
411
412 if (s0 && *s0) {
413 i = strlen(s0) + strlen(s1) + 1 + 1;
414 cp = emalloc(i);
415 (void)snprintf(cp, i, "%s,%s", s0, s1);
416 }
417 else
418 cp = estrdup(s1);
419
420 if (s0 && fr)
421 free(s0);
422 return (cp);
423 }
424
425
426 static void
427 mangle(opts, argcp, argv)
428 char *opts;
429 int *argcp;
430 const char **argv;
431 {
432 char *p, *s;
433 int argc;
434
435 argc = *argcp;
436 for (s = opts; (p = strsep(&s, ",")) != NULL;)
437 if (*p != '\0')
438 if (*p == '-') {
439 argv[argc++] = p;
440 p = strchr(p, '=');
441 if (p) {
442 *p = '\0';
443 argv[argc++] = p+1;
444 }
445 }
446 else {
447 argv[argc++] = "-o";
448 argv[argc++] = p;
449 }
450
451 *argcp = argc;
452 }
453
454
455 static void
456 usage()
457 {
458 extern char *__progname;
459 static const char common[] =
460 "pvlyn] [-T fstype:fsoptions] [-t fstype]";
461
462 (void)fprintf(stderr, "Usage: %s [-%s%s [special|node]...\n",
463 __progname, DEBUGOPT, common);
464 exit(1);
465 }
466