1 /* $OpenBSD: main.c,v 1.30 2023/03/08 04:43:06 guenther Exp $ */
2 /* $NetBSD: main.c,v 1.1 1997/06/11 11:21:50 bouyer Exp $ */
3
4 /*
5 * Copyright (c) 1997 Manuel Bouyer.
6 * Copyright (c) 1980, 1986, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/types.h>
35 #include <sys/signal.h>
36 #include <sys/time.h>
37 #include <sys/mount.h>
38 #include <ufs/ext2fs/ext2fs_dinode.h>
39 #include <ufs/ext2fs/ext2fs.h>
40 #include <fstab.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <err.h>
48
49 #include "fsck.h"
50 #include "extern.h"
51 #include "fsutil.h"
52
53 volatile sig_atomic_t returntosingle;
54
55 int main(int, char *[]);
56
57 static int argtoi(int, char *, char *, int);
58 static int checkfilesys(char *, char *, long, int);
59 static void usage(void);
60
61 struct bufarea bufhead; /* head of list of other blks in filesys */
62 struct bufarea sblk; /* file system superblock */
63 struct bufarea asblk; /* first alternate superblock */
64 struct bufarea *pdirbp; /* current directory contents */
65 struct bufarea *pbp; /* current inode block */
66 struct bufarea *getdatablk(daddr32_t, long);
67 struct m_ext2fs sblock;
68
69 struct dups *duplist; /* head of dup list */
70 struct dups *muldup; /* end of unique duplicate dup block numbers */
71
72 struct zlncnt *zlnhead; /* head of zero link count list */
73
74 struct inoinfo **inphead, **inpsort;
75 long numdirs, listmax, inplast;
76
77 long secsize; /* actual disk sector size */
78 char nflag; /* assume a no response */
79 char yflag; /* assume a yes response */
80 int bflag; /* location of alternate super block */
81 int debug; /* output debugging info */
82 int preen; /* just fix normal inconsistencies */
83 char havesb; /* superblock has been read */
84 char skipclean; /* skip clean file systems if preening */
85 int fsmodified; /* 1 => write done to file system */
86 int fsreadfd; /* file descriptor for reading file system */
87 int fswritefd; /* file descriptor for writing file system */
88 int rerun; /* rerun fsck. Only used in non-preen mode */
89
90 daddr32_t maxfsblock; /* number of blocks in the file system */
91 char *blockmap; /* ptr to primary blk allocation map */
92 ino_t maxino; /* number of inodes in file system */
93 ino_t lastino; /* last inode in use */
94 char *statemap; /* ptr to inode state table */
95 u_char *typemap; /* ptr to inode type table */
96 int16_t *lncntp; /* ptr to link count table */
97
98 ino_t lfdir; /* lost & found directory inode number */
99
100 daddr32_t n_blks; /* number of blocks in use */
101 daddr32_t n_files; /* number of files in use */
102
103 struct ext2fs_dinode zino;
104
105 int
main(int argc,char * argv[])106 main(int argc, char *argv[])
107 {
108 int ch;
109 int ret = 0;
110
111 checkroot();
112
113 sync();
114 skipclean = 1;
115 while ((ch = getopt(argc, argv, "b:dfm:npy")) != -1) {
116 switch (ch) {
117 case 'b':
118 skipclean = 0;
119 bflag = argtoi('b', "number", optarg, 10);
120 printf("Alternate super block location: %d\n", bflag);
121 break;
122
123 case 'd':
124 debug = 1;
125 break;
126
127 case 'f':
128 skipclean = 0;
129 break;
130
131 case 'm':
132 lfmode = argtoi('m', "mode", optarg, 8);
133 if (lfmode &~ 07777)
134 errexit("bad mode to -m: %o\n", lfmode);
135 printf("** lost+found creation mode %o\n", lfmode);
136 break;
137
138 case 'n':
139 nflag = 1;
140 yflag = 0;
141 break;
142
143 case 'p':
144 preen = 1;
145 break;
146
147 case 'y':
148 yflag = 1;
149 nflag = 0;
150 break;
151
152 default:
153 usage();
154 }
155 }
156
157 argc -= optind;
158 argv += optind;
159
160 if (argc != 1)
161 usage();
162
163 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
164 (void)signal(SIGINT, catch);
165 if (preen)
166 (void)signal(SIGQUIT, catchquit);
167
168 (void)checkfilesys(blockcheck(*argv), 0, 0L, 0);
169
170 if (returntosingle)
171 ret = 2;
172
173 exit(ret);
174 }
175
176 static int
argtoi(int flag,char * req,char * str,int base)177 argtoi(int flag, char *req, char *str, int base)
178 {
179 char *cp;
180 int ret;
181
182 ret = (int)strtol(str, &cp, base);
183 if (cp == str || *cp)
184 errexit("-%c flag requires a %s\n", flag, req);
185 return (ret);
186 }
187
188 /*
189 * Check the specified filesystem.
190 */
191 static int
checkfilesys(char * filesys,char * mntpt,long auxdata,int child)192 checkfilesys(char *filesys, char *mntpt, long auxdata, int child)
193 {
194 daddr32_t n_bfree;
195 struct dups *dp;
196 struct zlncnt *zlnp;
197 int i;
198
199 if (preen && child)
200 (void)signal(SIGQUIT, voidquit);
201 setcdevname(filesys, NULL, preen);
202 if (debug && preen)
203 pwarn("starting\n");
204
205 switch (setup(filesys)) {
206 case 0:
207 if (preen)
208 pfatal("CAN'T CHECK FILE SYSTEM.");
209 case -1:
210 return (0);
211 }
212 /*
213 * 1: scan inodes tallying blocks used
214 */
215 if (preen == 0) {
216 if (sblock.e2fs.e2fs_rev > E2FS_REV0) {
217 printf("** Last Mounted on %s\n",
218 sblock.e2fs.e2fs_fsmnt);
219 }
220 if (hotroot())
221 printf("** Root file system\n");
222 printf("** Phase 1 - Check Blocks and Sizes\n");
223 }
224 pass1();
225
226 /*
227 * 1b: locate first references to duplicates, if any
228 */
229 if (duplist) {
230 if (preen)
231 pfatal("INTERNAL ERROR: dups with -p");
232 printf("** Phase 1b - Rescan For More DUPS\n");
233 pass1b();
234 }
235
236 /*
237 * 2: traverse directories from root to mark all connected directories
238 */
239 if (preen == 0)
240 printf("** Phase 2 - Check Pathnames\n");
241 pass2();
242
243 /*
244 * 3: scan inodes looking for disconnected directories
245 */
246 if (preen == 0)
247 printf("** Phase 3 - Check Connectivity\n");
248 pass3();
249
250 /*
251 * 4: scan inodes looking for disconnected files; check reference counts
252 */
253 if (preen == 0)
254 printf("** Phase 4 - Check Reference Counts\n");
255 pass4();
256
257 /*
258 * 5: check and repair resource counts in cylinder groups
259 */
260 if (preen == 0)
261 printf("** Phase 5 - Check Cyl groups\n");
262 pass5();
263
264 /*
265 * print out summary statistics
266 */
267 n_bfree = sblock.e2fs.e2fs_fbcount;
268
269 pwarn("%d files, %d used, %d free\n",
270 n_files, n_blks, n_bfree);
271 if (debug &&
272 /* 9 reserved and unused inodes in FS */
273 (n_files -= maxino - 9 - sblock.e2fs.e2fs_ficount))
274 printf("%d files missing\n", n_files);
275 if (debug) {
276 for (i = 0; i < sblock.e2fs_ncg; i++)
277 n_blks += cgoverhead(i);
278 n_blks += sblock.e2fs.e2fs_first_dblock;
279 if (n_blks -= maxfsblock - n_bfree)
280 printf("%d blocks missing\n", n_blks);
281 if (duplist != NULL) {
282 printf("The following duplicate blocks remain:");
283 for (dp = duplist; dp; dp = dp->next)
284 printf(" %d,", dp->dup);
285 printf("\n");
286 }
287 if (zlnhead != NULL) {
288 printf("The following zero link count inodes remain:");
289 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
290 printf(" %llu,",
291 (unsigned long long)zlnp->zlncnt);
292 printf("\n");
293 }
294 }
295 zlnhead = NULL;
296 duplist = NULL;
297 muldup = NULL;
298 inocleanup();
299 if (fsmodified) {
300 time_t t;
301 (void)time(&t);
302 sblock.e2fs.e2fs_wtime = t;
303 sblock.e2fs.e2fs_lastfsck = t;
304 sbdirty();
305 }
306 ckfini(1);
307 free(blockmap);
308 free(statemap);
309 free((char *)lncntp);
310 if (!fsmodified)
311 return (0);
312 if (!preen)
313 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
314 if (rerun)
315 printf("\n***** PLEASE RERUN FSCK *****\n");
316 if (hotroot()) {
317 struct statfs stfs_buf;
318 /*
319 * We modified the root. Do a mount update on
320 * it, unless it is read-write, so we can continue.
321 */
322 if (statfs("/", &stfs_buf) == 0) {
323 long flags = stfs_buf.f_flags;
324 struct ufs_args args;
325 int ret;
326
327 if (flags & MNT_RDONLY) {
328 args.fspec = 0;
329 args.export_info.ex_flags = 0;
330 args.export_info.ex_root = 0;
331 flags |= MNT_UPDATE | MNT_RELOAD;
332 ret = mount(MOUNT_EXT2FS, "/", flags, &args);
333 if (ret == 0)
334 return(0);
335 }
336 }
337 if (!preen)
338 printf("\n***** REBOOT NOW *****\n");
339 sync();
340 return (4);
341 }
342 return (0);
343 }
344
345 static void
usage(void)346 usage(void)
347 {
348 extern char *__progname;
349
350 (void) fprintf(stderr,
351 "usage: %s [-dfnpy] [-b block#] [-m mode] filesystem\n",
352 __progname);
353 exit(1);
354 }
355