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