]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/fsck/fsck.c
This commit was generated by cvs2svn to compensate for changes in r91041,
[FreeBSD/FreeBSD.git] / sbin / fsck / fsck.c
1 /*      $NetBSD: fsck.c,v 1.21 1999/04/22 04:20:53 abs 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  * $NetBSD: fsck.c,v 1.21 1999/04/22 04:20:53 abs Exp $
39  */
40
41 #include <sys/cdefs.h>
42 #ifndef lint
43 __RCSID("$FreeBSD$");
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/mount.h>
48 #include <sys/queue.h>
49 #include <sys/wait.h>
50 #define FSTYPENAMES
51 #define DKTYPENAMES
52 #include <sys/disklabel.h>
53 #include <sys/ioctl.h>
54
55 #include <err.h>
56 #include <errno.h>
57 #include <fstab.h>
58 #include <fcntl.h>
59 #include <paths.h>
60 #include <signal.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65
66 #include "pathnames.h"
67 #include "fsutil.h"
68
69 static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
70
71 TAILQ_HEAD(fstypelist, entry) opthead, selhead;
72
73 struct entry {
74         char *type;
75         char *options;
76         TAILQ_ENTRY(entry) entries;
77 };
78
79 static char *options = NULL;
80 static int flags = 0;
81 static int forceflag = 0;
82
83 int main __P((int, char *[]));
84
85 static int checkfs __P((const char *, const char *, const char *, char *,
86     pid_t *));
87 static int selected __P((const char *));
88 static void addoption __P((char *));
89 static const char *getoptions __P((const char *));
90 static void addentry __P((struct fstypelist *, const char *, const char *));
91 static void maketypelist __P((char *));
92 static void catopt __P((char **, const char *));
93 static void mangle __P((char *, int *, const char ***, int *));
94 static const char *getfslab __P((const char *));
95 static void usage __P((void));
96 static int isok __P((struct fstab *));
97
98 int
99 main(argc, argv)
100         int argc;
101         char *argv[];
102 {
103         struct fstab *fs;
104         int i, rval = 0;
105         const char *vfstype = NULL;
106         char globopt[3];
107
108         globopt[0] = '-';
109         globopt[2] = '\0';
110
111         TAILQ_INIT(&selhead);
112         TAILQ_INIT(&opthead);
113
114         while ((i = getopt(argc, argv, "BdvpfFnyl:t:T:")) != -1)
115                 switch (i) {
116                 case 'B':
117                         if (flags & CHECK_BACKGRD)
118                                 errx(1, "Cannot specify -B and -F.");
119                         flags |= DO_BACKGRD;
120                         break;
121
122                 case 'd':
123                         flags |= CHECK_DEBUG;
124                         break;
125
126                 case 'v':
127                         flags |= CHECK_VERBOSE;
128                         break;
129
130                 case 'F':
131                         if (flags & DO_BACKGRD)
132                                 errx(1, "Cannot specify -B and -F.");
133                         flags |= CHECK_BACKGRD;
134                         break;
135
136                 case 'p':
137                         flags |= CHECK_PREEN;
138                         /*FALLTHROUGH*/
139                 case 'n':
140                 case 'y':
141                         globopt[1] = i;
142                         catopt(&options, globopt);
143                         break;
144
145                 case 'f':
146                         forceflag = 1;
147                         globopt[1] = i;
148                         catopt(&options, globopt);
149                         break;
150
151                 case 'l':
152                         warnx("Ignoring obsolete -l option\n");
153                         break;
154
155                 case 'T':
156                         if (*optarg)
157                                 addoption(optarg);
158                         break;
159
160                 case 't':
161                         if (!TAILQ_EMPTY(&selhead))
162                                 errx(1, "only one -t option may be specified.");
163
164                         maketypelist(optarg);
165                         vfstype = optarg;
166                         break;
167
168                 case '?':
169                 default:
170                         usage();
171                         /* NOTREACHED */
172                 }
173
174         argc -= optind;
175         argv += optind;
176
177         if (argc == 0)
178                 return checkfstab(flags, isok, checkfs);
179
180 #define BADTYPE(type)                                                   \
181         (strcmp(type, FSTAB_RO) &&                                      \
182             strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
183
184
185         for (; argc--; argv++) {
186                 const char *spec, *mntpt, *type, *cp;
187                 char device[MAXPATHLEN];
188                 struct statfs *mntp;
189
190                 spec = *argv;
191                 cp = strrchr(spec, '/');
192                 if (cp == 0) {
193                         (void)snprintf(device, sizeof(device), "%s%s",
194                                 _PATH_DEV, spec);
195                         spec = device;
196                 }
197                 mntp = getmntpt(spec);
198                 if (mntp != NULL) {
199                         spec = mntp->f_mntfromname;
200                         mntpt = mntp->f_mntonname;
201                 }
202                 if ((fs = getfsfile(spec)) == NULL &&
203                     (fs = getfsspec(spec)) == NULL) {
204                         if (vfstype == NULL)
205                                 vfstype = getfslab(spec);
206                         type = vfstype;
207                         devcheck(spec);
208                 } else {
209                         spec = fs->fs_spec;
210                         type = fs->fs_vfstype;
211                         mntpt = fs->fs_file;
212                         if (BADTYPE(fs->fs_type))
213                                 errx(1, "%s has unknown file system type.",
214                                     spec);
215                 }
216                 if ((flags & CHECK_BACKGRD) &&
217                     checkfs(type, spec, mntpt, "-F", NULL) == 0) {
218                         printf("%s: DEFER FOR BACKGROUND CHECKING\n", *argv);
219                         continue;
220                 }
221                 if ((flags & DO_BACKGRD) && forceflag == 0 &&
222                     checkfs(type, spec, mntpt, "-F", NULL) != 0)
223                         continue;
224
225                 rval |= checkfs(type, spec, mntpt, NULL, NULL);
226         }
227
228         return rval;
229 }
230
231
232 static int
233 isok(fs)
234         struct fstab *fs;
235 {
236         int i;
237
238         if (fs->fs_passno == 0)
239                 return (0);
240         if (BADTYPE(fs->fs_type))
241                 return (0);
242         if (!selected(fs->fs_vfstype))
243                 return (0);
244         /*
245          * If the -B flag has been given, then process the needed
246          * background checks. Background checks cannot be run on
247          * filesystems that will be mounted read-only or that were
248          * not mounted at boot time (typically those marked `noauto').
249          * If these basic tests are passed, check with the filesystem
250          * itself to see if it is willing to do background checking
251          * by invoking its check program with the -F flag.
252          */
253         if (flags & DO_BACKGRD) {
254                 if (!strcmp(fs->fs_type, FSTAB_RO))
255                         return (0);
256                 if (getmntpt(fs->fs_spec) == NULL)
257                         return (0);
258                 if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", 0))
259                         return (0);
260                 return (1);
261         }
262         /*
263          * If the -F flag has been given, then consider deferring the
264          * check to background. Background checks cannot be run on
265          * filesystems that will be mounted read-only or that will
266          * not be mounted at boot time (e.g., marked `noauto'). If
267          * these basic tests are passed, check with the filesystem
268          * itself to see if it is willing to defer to background
269          * checking by invoking its check program with the -F flag.
270          */
271         if ((flags & CHECK_BACKGRD) == 0 || !strcmp(fs->fs_type, FSTAB_RO))
272                 return (1);
273         for (i = strlen(fs->fs_mntops) - 6; i >= 0; i--)
274                 if (!strncmp(&fs->fs_mntops[i], "noauto", 6))
275                         break;
276         if (i >= 0)
277                 return (1);
278         if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", NULL) != 0)
279                 return (1);
280         printf("%s: DEFER FOR BACKGROUND CHECKING\n", fs->fs_spec);
281         return (0);
282 }
283
284
285 static int
286 checkfs(pvfstype, spec, mntpt, auxopt, pidp)
287         const char *pvfstype, *spec, *mntpt;
288         char *auxopt;
289         pid_t *pidp;
290 {
291         /* List of directories containing fsck_xxx subcommands. */
292         static const char *edirs[] = {
293                 _PATH_SBIN,
294                 _PATH_USRSBIN,
295                 NULL
296         };
297         const char **argv, **edir;
298         pid_t pid;
299         int argc, i, status, maxargc;
300         char *optbuf, execname[MAXPATHLEN + 1], execbase[MAXPATHLEN];
301         char *vfstype = NULL;
302         const char *extra = NULL;
303
304 #ifdef __GNUC__
305         /* Avoid vfork clobbering */
306         (void) &optbuf;
307         (void) &vfstype;
308 #endif
309         /*
310          * We convert the vfstype to lowercase and any spaces to underscores
311          * to not confuse the issue
312          */
313         vfstype = strdup(pvfstype);
314         if (vfstype == NULL)
315                 perror("strdup(pvfstype)"); 
316         for (i = 0; i < strlen(vfstype); i++) {
317                 vfstype[i] = tolower(vfstype[i]);
318                 if (vfstype[i] == ' ')
319                         vfstype[i] = '_';
320         }
321
322         extra = getoptions(vfstype);
323         optbuf = NULL;
324         if (options)
325                 catopt(&optbuf, options);
326         if (extra)
327                 catopt(&optbuf, extra);
328         if (auxopt)
329                 catopt(&optbuf, auxopt);
330         else if (flags & DO_BACKGRD)
331                 catopt(&optbuf, "-B");
332
333         maxargc = 64;
334         argv = emalloc(sizeof(char *) * maxargc);
335
336         (void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype);
337         argc = 0;
338         argv[argc++] = execbase;
339         if (optbuf)
340                 mangle(optbuf, &argc, &argv, &maxargc);
341         argv[argc++] = spec;
342         argv[argc] = NULL;
343
344         if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
345                 (void)printf("start %s %swait", mntpt, 
346                         pidp ? "no" : "");
347                 for (i = 0; i < argc; i++)
348                         (void)printf(" %s", argv[i]);
349                 (void)printf("\n");
350         }
351
352         switch (pid = vfork()) {
353         case -1:                                /* Error. */
354                 warn("vfork");
355                 if (optbuf)
356                         free(optbuf);
357                 free(vfstype);
358                 return (1);
359
360         case 0:                                 /* Child. */
361                 if ((flags & CHECK_DEBUG) && auxopt == NULL)
362                         _exit(0);
363
364                 /* Go find an executable. */
365                 edir = edirs;
366                 do {
367                         (void)snprintf(execname,
368                             sizeof(execname), "%s/%s", *edir, execbase);
369                         execv(execname, (char * const *)argv);
370                         if (errno != ENOENT) {
371                                 if (spec)
372                                         warn("exec %s for %s", execname, spec);
373                                 else
374                                         warn("exec %s", execname);
375                         }
376                 } while (*++edir != NULL);
377
378                 if (errno == ENOENT) {
379                         if (spec)
380                                 warn("exec %s for %s", execname, spec);
381                         else
382                                 warn("exec %s", execname);
383                 }
384                 _exit(1);
385                 /* NOTREACHED */
386
387         default:                                /* Parent. */
388                 if (optbuf)
389                         free(optbuf);
390
391                 free(vfstype);
392
393                 if (pidp) {
394                         *pidp = pid;
395                         return 0;
396                 }
397
398                 if (waitpid(pid, &status, 0) < 0) {
399                         warn("waitpid");
400                         return (1);
401                 }
402
403                 if (WIFEXITED(status)) {
404                         if (WEXITSTATUS(status) != 0)
405                                 return (WEXITSTATUS(status));
406                 }
407                 else if (WIFSIGNALED(status)) {
408                         warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
409                         return (1);
410                 }
411                 break;
412         }
413
414         return (0);
415 }
416
417
418 static int
419 selected(type)
420         const char *type;
421 {
422         struct entry *e;
423
424         /* If no type specified, it's always selected. */
425         TAILQ_FOREACH(e, &selhead, entries)
426                 if (!strncmp(e->type, type, MFSNAMELEN))
427                         return which == IN_LIST ? 1 : 0;
428
429         return which == IN_LIST ? 0 : 1;
430 }
431
432
433 static const char *
434 getoptions(type)
435         const char *type;
436 {
437         struct entry *e;
438
439         TAILQ_FOREACH(e, &opthead, entries)
440                 if (!strncmp(e->type, type, MFSNAMELEN))
441                         return e->options;
442         return "";
443 }
444
445
446 static void
447 addoption(optstr)
448         char *optstr;
449 {
450         char *newoptions;
451         struct entry *e;
452
453         if ((newoptions = strchr(optstr, ':')) == NULL)
454                 errx(1, "Invalid option string");
455
456         *newoptions++ = '\0';
457
458         TAILQ_FOREACH(e, &opthead, entries)
459                 if (!strncmp(e->type, optstr, MFSNAMELEN)) {
460                         catopt(&e->options, newoptions);
461                         return;
462                 }
463         addentry(&opthead, optstr, newoptions);
464 }
465
466
467 static void
468 addentry(list, type, opts)
469         struct fstypelist *list;
470         const char *type;
471         const char *opts;
472 {
473         struct entry *e;
474
475         e = emalloc(sizeof(struct entry));
476         e->type = estrdup(type);
477         e->options = estrdup(opts);
478         TAILQ_INSERT_TAIL(list, e, entries);
479 }
480
481
482 static void
483 maketypelist(fslist)
484         char *fslist;
485 {
486         char *ptr;
487
488         if ((fslist == NULL) || (fslist[0] == '\0'))
489                 errx(1, "empty type list");
490
491         if (fslist[0] == 'n' && fslist[1] == 'o') {
492                 fslist += 2;
493                 which = NOT_IN_LIST;
494         }
495         else
496                 which = IN_LIST;
497
498         while ((ptr = strsep(&fslist, ",")) != NULL)
499                 addentry(&selhead, ptr, "");
500
501 }
502
503
504 static void
505 catopt(sp, o)
506         char **sp;
507         const char *o;
508 {
509         char *s;
510         size_t i, j;
511
512         s = *sp;
513         if (s) {
514                 i = strlen(s);
515                 j = i + 1 + strlen(o) + 1;
516                 s = erealloc(s, j);
517                 (void)snprintf(s + i, j, ",%s", o);
518         } else
519                 s = estrdup(o);
520         *sp = s;
521 }
522
523
524 static void
525 mangle(options, argcp, argvp, maxargcp)
526         char *options;
527         int *argcp, *maxargcp;
528         const char ***argvp;
529 {
530         char *p, *s;
531         int argc, maxargc;
532         const char **argv;
533
534         argc = *argcp;
535         argv = *argvp;
536         maxargc = *maxargcp;
537
538         for (s = options; (p = strsep(&s, ",")) != NULL;) {
539                 /* Always leave space for one more argument and the NULL. */
540                 if (argc >= maxargc - 3) {
541                         maxargc <<= 1;
542                         argv = erealloc(argv, maxargc * sizeof(char *));
543                 }
544                 if (*p != '\0')  {
545                         if (*p == '-') {
546                                 argv[argc++] = p;
547                                 p = strchr(p, '=');
548                                 if (p) {
549                                         *p = '\0';
550                                         argv[argc++] = p+1;
551                                 }
552                         } else {
553                                 argv[argc++] = "-o";
554                                 argv[argc++] = p;
555                         }
556                 }
557         }
558
559         *argcp = argc;
560         *argvp = argv;
561         *maxargcp = maxargc;
562 }
563
564
565 const static char *
566 getfslab(str)
567         const char *str;
568 {
569         struct disklabel dl;
570         int fd;
571         char p;
572         const char *vfstype;
573         u_char t;
574
575         /* deduce the filesystem type from the disk label */
576         if ((fd = open(str, O_RDONLY)) == -1)
577                 err(1, "cannot open `%s'", str);
578
579         if (ioctl(fd, DIOCGDINFO, &dl) == -1)
580                 err(1, "cannot get disklabel for `%s'", str);
581
582         (void) close(fd);
583
584         p = str[strlen(str) - 1];
585
586         if ((p - 'a') >= dl.d_npartitions)
587                 errx(1, "partition `%s' is not defined on disk", str);
588
589         if ((t = dl.d_partitions[p - 'a'].p_fstype) >= FSMAXTYPES) 
590                 errx(1, "partition `%s' is not of a legal vfstype",
591                     str);
592
593         if ((vfstype = fstypenames[t]) == NULL)
594                 errx(1, "vfstype `%s' on partition `%s' is not supported",
595                     fstypenames[t], str);
596
597         return vfstype;
598 }
599
600
601 static void
602 usage()
603 {
604         extern char *__progname;
605         static const char common[] =
606             "[-BFdpvlyn] [-T fstype:fsoptions] [-t fstype]";
607
608         (void)fprintf(stderr, "Usage: %s %s [special|node]...\n",
609             __progname, common);
610         exit(1);
611 }