1 /* $NetBSD: main.c,v 1.55 2020/04/03 19:36:33 joerg Exp $    */
2 
3 /*
4  * Copyright (c) 1980, 1986, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/mount.h>
35 
36 #include <ufs/lfs/lfs.h>
37 #include <ufs/lfs/lfs_accessors.h>
38 
39 #include <fstab.h>
40 #include <stdbool.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <err.h>
48 #include <util.h>
49 #include <signal.h>
50 
51 #include "fsck.h"
52 #include "extern.h"
53 #include "fsutil.h"
54 #include "exitvalues.h"
55 
56 int       Uflag;
57 
58 static int argtoi(int, const char *, const char *, int);
59 static int checkfilesys(const char *, char *, long, int);
60 static void usage(void);
61 static void efun(int, const char *, ...);
62 
63 static void
efun(int eval,const char * fmt,...)64 efun(int eval, const char *fmt, ...)
65 {
66           va_list ap;
67           va_start(ap, fmt);
68           verr(EEXIT, fmt, ap);
69           va_end(ap);
70 }
71 
72 int
main(int argc,char ** argv)73 main(int argc, char **argv)
74 {
75           int ch;
76           int ret = FSCK_EXIT_OK;
77           const char *optstring = "b:dfi:m:npPqUy";
78           bool reallypreen;
79 
80           reallypreen = false;
81           ckfinish = ckfini;
82           skipclean = 1;
83           exitonfail = 0;
84           idaddr = 0x0;
85           panic_func = vmsg;
86           esetfunc(efun);
87           while ((ch = getopt(argc, argv, optstring)) != -1) {
88                     switch (ch) {
89                     case 'b':
90                               skipclean = 0;
91                               bflag = argtoi('b', "number", optarg, 0);
92                               printf("Alternate super block location: %d\n", bflag);
93                               break;
94                     case 'd':
95                               debug++;
96                               break;
97                     case 'e':
98                               exitonfail++;
99                               break;
100                     case 'f':
101                               skipclean = 0;
102                               reallypreen = true;
103                               break;
104                     case 'i':
105                               idaddr = strtol(optarg, NULL, 0);
106                               break;
107                     case 'm':
108                               lfmode = argtoi('m', "mode", optarg, 8);
109                               if (lfmode & ~07777)
110                                         err(1, "bad mode to -m: %o", lfmode);
111                               printf("** lost+found creation mode %o\n", lfmode);
112                               break;
113 
114                     case 'n':
115                               nflag++;
116                               yflag = 0;
117                               break;
118 
119                     case 'p':
120                               preen++;
121                               break;
122 
123                     case 'P':           /* Progress meter not implemented. */
124                               break;
125 
126                     case 'q':
127                               quiet++;
128                               break;
129 #ifndef SMALL
130                     case 'U':
131                               Uflag++;
132                               break;
133 #endif
134                     case 'y':
135                               yflag++;
136                               nflag = 0;
137                               break;
138 
139                     default:
140                               usage();
141                     }
142           }
143 
144           argc -= optind;
145           argv += optind;
146 
147           if (!argc)
148                     usage();
149 
150           /*
151            * Don't do anything in preen mode. This is a replacement for
152            * version 1.111 of src/distrib/utils/sysinst/disks.c, which
153            * disabled fsck on installer-generated lfs partitions. That
154            * isn't the right way to do it; better to run fsck but have
155            * it not do anything, so that when the issues in fsck get
156            * resolved it can be turned back on.
157            *
158            * If you really want to run fsck in preen mode you can do:
159            *    fsck_lfs -p -f image
160            *
161            * This was prompted by
162            * http://mail-index.netbsd.org/tech-kern/2010/02/09/msg007306.html.
163            *
164            * It would be nice if someone prepared a more detailed report
165            * of the problems.
166            *
167            * XXX.
168            */
169           if (preen && !reallypreen) {
170                     return ret;
171           }
172 
173           if (signal(SIGINT, SIG_IGN) != SIG_IGN)
174                     (void) signal(SIGINT, catch);
175           if (preen)
176                     (void) signal(SIGQUIT, catchquit);
177 
178           while (argc-- > 0) {
179                     int nret = checkfilesys(blockcheck(*argv++), 0, 0L, 0);
180                     if (ret < nret)
181                               ret = nret;
182           }
183 
184           return returntosingle ? FSCK_EXIT_UNRESOLVED : ret;
185 }
186 
187 static int
argtoi(int flag,const char * req,const char * str,int base)188 argtoi(int flag, const char *req, const char *str, int base)
189 {
190           char *cp;
191           int ret;
192 
193           ret = (int) strtol(str, &cp, base);
194           if (cp == str || *cp)
195                     err(FSCK_EXIT_USAGE, "-%c flag requires a %s", flag, req);
196           return (ret);
197 }
198 
199 /*
200  * Check the specified filesystem.
201  */
202 
203 /* ARGSUSED */
204 static int
checkfilesys(const char * filesys,char * mntpt,long auxdata,int child)205 checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
206 {
207           struct dups *dp;
208           struct zlncnt *zlnp;
209 
210           if (preen && child)
211                     (void) signal(SIGQUIT, voidquit);
212           setcdevname(filesys, preen);
213           if (debug && preen)
214                     pwarn("starting\n");
215           switch (setup(filesys)) {
216           case 0:
217                     if (preen)
218                               pfatal("CAN'T CHECK FILE SYSTEM.");
219                     /* FALLTHROUGH */
220           case -1:
221                     return FSCK_EXIT_OK;
222           }
223 
224           /*
225            * For LFS, "preen" means "roll forward".  We don't check anything
226            * else.
227            */
228           if (preen == 0) {
229                     printf("** Last Mounted on %s\n", lfs_sb_getfsmnt(fs));
230                     if (hotroot())
231                               printf("** Root file system\n");
232                     /*
233                      * 0: check segment checksums, inode ranges
234                      */
235                     printf("** Phase 0 - Check Inode Free List\n");
236           }
237 
238           /*
239            * Check inode free list - we do this even if idaddr is set,
240            * since if we're writing we don't want to write a bad list.
241            */
242           pass0();
243 
244           if (preen == 0) {
245                     /*
246                      * 1: scan inodes tallying blocks used
247                      */
248                     printf("** Phase 1 - Check Blocks and Sizes\n");
249                     pass1();
250 
251                     /*
252                      * 2: traverse directories from root to mark all connected directories
253                      */
254                     printf("** Phase 2 - Check Pathnames\n");
255                     pass2();
256 
257                     /*
258                      * 3: scan inodes looking for disconnected directories
259                      */
260                     printf("** Phase 3 - Check Connectivity\n");
261                     pass3();
262 
263                     /*
264                      * 4: scan inodes looking for disconnected files; check reference counts
265                      */
266                     printf("** Phase 4 - Check Reference Counts\n");
267                     pass4();
268           }
269 
270           /*
271            * 5: check segment byte totals and dirty flags, and cleanerinfo
272            */
273           if (!preen)
274                     printf("** Phase 5 - Check Segment Block Accounting\n");
275           pass5();
276 
277           if (debug && !preen) {
278                     if (duplist != NULL) {
279                               printf("The following duplicate blocks remain:");
280                               for (dp = duplist; dp; dp = dp->next)
281                                         printf(" %lld,", (long long) dp->dup);
282                               printf("\n");
283                     }
284                     if (zlnhead != NULL) {
285                               printf("The following zero link count inodes remain:");
286                               for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
287                                         printf(" %llu,",
288                                             (unsigned long long)zlnp->zlncnt);
289                               printf("\n");
290                     }
291           }
292 
293           if (!rerun) {
294                     if (!preen) {
295                               if (reply("ROLL FILESYSTEM FORWARD") == 1) {
296                                         printf("** Phase 6 - Roll Forward\n");
297                                         pass6();
298                               }
299                     }
300                     else {
301                               pass6();
302                     }
303           }
304           zlnhead = (struct zlncnt *) 0;
305           orphead = (struct zlncnt *) 0;
306           duplist = (struct dups *) 0;
307           muldup = (struct dups *) 0;
308           inocleanup();
309 
310           /*
311            * print out summary statistics
312            */
313           pwarn("%ju files, %jd used, %jd free\n",
314               (uintmax_t) n_files, (intmax_t) n_blks,
315               (intmax_t) lfs_sb_getbfree(fs));
316 
317           ckfini(1);
318 
319           free(blockmap);
320           free(statemap);
321           free((char *)lncntp);
322           if (!fsmodified) {
323                     return FSCK_EXIT_OK;
324           }
325           if (!preen)
326                     printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
327           if (rerun)
328                     printf("\n***** PLEASE RERUN FSCK *****\n");
329           if (hotroot()) {
330                     struct statvfs stfs_buf;
331                     /*
332                      * We modified the root.  Do a mount update on
333                      * it, unless it is read-write, so we can continue.
334                      */
335                     if (statvfs("/", &stfs_buf) == 0) {
336                               long flags = stfs_buf.f_flag;
337                               struct ulfs_args args;
338 
339                               if (flags & MNT_RDONLY) {
340                                         args.fspec = 0;
341                                         flags |= MNT_UPDATE | MNT_RELOAD;
342                                         if (mount(MOUNT_LFS, "/", flags,
343                                             &args, sizeof args) == 0)
344                                                   return FSCK_EXIT_OK;
345                               }
346                     }
347                     if (!preen)
348                               printf("\n***** REBOOT NOW *****\n");
349                     sync();
350                     return FSCK_EXIT_ROOT_CHANGED;
351           }
352           return FSCK_EXIT_OK;
353 }
354 
355 static void
usage(void)356 usage(void)
357 {
358 
359           (void) fprintf(stderr,
360               "Usage: %s [-dfpqU] [-b block] [-m mode] [-y | -n] filesystem ...\n",
361               getprogname());
362           exit(FSCK_EXIT_USAGE);
363 }
364