]>
Commit | Line | Data |
---|---|---|
6dbe3af9 | 1 | /* |
727b3c2f | 2 | * fsck.minix.c - a file system consistency checker for Linux. |
6dbe3af9 KZ |
3 | * |
4 | * (C) 1991, 1992 Linus Torvalds. This file may be redistributed | |
5 | * as per the GNU copyleft. | |
6 | */ | |
7 | ||
8 | /* | |
9e930041 | 9 | * 09.11.91 - made the first rudimentary functions |
6dbe3af9 KZ |
10 | * |
11 | * 10.11.91 - updated, does checking, no repairs yet. | |
12 | * Sent out to the mailing-list for testing. | |
13 | * | |
14 | * 14.11.91 - Testing seems to have gone well. Added some | |
15 | * correction-code, and changed some functions. | |
16 | * | |
17 | * 15.11.91 - More correction code. Hopefully it notices most | |
18 | * cases now, and tries to do something about them. | |
19 | * | |
20 | * 16.11.91 - More corrections (thanks to Mika Jalava). Most | |
21 | * things seem to work now. Yeah, sure. | |
22 | * | |
23 | * | |
24 | * 19.04.92 - Had to start over again from this old version, as a | |
9e930041 | 25 | * kernel bug ate my enhanced fsck in February. |
6dbe3af9 KZ |
26 | * |
27 | * 28.02.93 - added support for different directory entry sizes.. | |
28 | * | |
29 | * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with | |
30 | * super-block information | |
31 | * | |
32 | * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform | |
33 | * to that required by fsutil | |
34 | * | |
35 | * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) | |
36 | * Added support for file system valid flag. Also | |
37 | * added program_version variable and output of | |
38 | * program name and version number when program | |
39 | * is executed. | |
fd6b7a7f KZ |
40 | * |
41 | * 30.10.94 - added support for v2 filesystem | |
42 | * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) | |
43 | * | |
6dbe3af9 KZ |
44 | * 10.12.94 - added test to prevent checking of mounted fs adapted |
45 | * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck | |
46 | * program. (Daniel Quinlan, quinlan@yggdrasil.com) | |
47 | * | |
fd6b7a7f KZ |
48 | * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such |
49 | * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) | |
50 | * | |
c1d26b19 | 51 | * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk |
fd6b7a7f | 52 | * (Russell King). He made them for ARM. It would seem |
2b6fc908 | 53 | * that the ARM is powerful enough to do this in C whereas |
fd6b7a7f KZ |
54 | * i386 and m64k must use assembly to get it fast >:-) |
55 | * This should make minix fsck systemindependent. | |
56 | * (janl@math.uio.no, Nicolai Langfeldt) | |
57 | * | |
58 | * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler | |
c1d26b19 | 59 | * warnings. Added mc68k bitops from |
fd6b7a7f KZ |
60 | * Joerg Dorchain <dorchain@mpi-sb.mpg.de>. |
61 | * | |
62 | * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by | |
63 | * Andreas Schwab. | |
64 | * | |
b50945d4 | 65 | * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> |
7eda085c KZ |
66 | * - added Native Language Support |
67 | * | |
54a78201 JY |
68 | * 2008-04-06 James Youngman <jay@gnu.org> |
69 | * - Issue better error message if we fail to open the device. | |
70 | * - Restore terminal state if we get a fatal signal. | |
71 | * | |
7eda085c | 72 | * |
6dbe3af9 KZ |
73 | * I've had no time to add comments - hopefully the function names |
74 | * are comments enough. As with all file system checkers, this assumes | |
75 | * the file system is quiescent - don't use it on a mounted device | |
76 | * unless you can be sure nobody is writing to it (and remember that the | |
77 | * kernel can write to it when it searches for files). | |
78 | * | |
6dbe3af9 KZ |
79 | */ |
80 | ||
81 | #include <stdio.h> | |
bb983885 | 82 | #include <stdarg.h> |
fd6b7a7f | 83 | #include <errno.h> |
6dbe3af9 KZ |
84 | #include <unistd.h> |
85 | #include <string.h> | |
86 | #include <fcntl.h> | |
87 | #include <ctype.h> | |
88 | #include <stdlib.h> | |
89 | #include <termios.h> | |
6dbe3af9 | 90 | #include <sys/stat.h> |
54a78201 | 91 | #include <signal.h> |
158b8d69 | 92 | #include <getopt.h> |
6dbe3af9 | 93 | |
78ecf61b | 94 | #include "c.h" |
891327c0 | 95 | #include "exitcodes.h" |
7cc112d9 | 96 | #include "minix_programs.h" |
7eda085c | 97 | #include "nls.h" |
fc68cd49 | 98 | #include "pathnames.h" |
e98754d6 | 99 | #include "bitops.h" |
c0f6d6d0 | 100 | #include "ismounted.h" |
e12c9866 | 101 | #include "all-io.h" |
45ca68ec | 102 | #include "closestream.h" |
51924a4e | 103 | #include "rpmatch.h" |
730ae9c8 | 104 | #include "strutils.h" |
6dbe3af9 | 105 | |
6dbe3af9 | 106 | #define ROOT_INO 1 |
d4a573bc | 107 | #define YESNO_LENGTH 64 |
6dbe3af9 | 108 | |
9e930041 | 109 | /* Global variables used in minix_programs.h inline functions */ |
058cda4c KZ |
110 | int fs_version = 1; |
111 | char *super_block_buffer; | |
112 | ||
0dca7bd5 | 113 | static char *inode_buffer; |
058cda4c KZ |
114 | |
115 | #define Inode (((struct minix_inode *) inode_buffer) - 1) | |
116 | #define Inode2 (((struct minix2_inode *) inode_buffer) - 1) | |
117 | ||
0dca7bd5 | 118 | static char *device_name; |
e1df9d4c | 119 | static int device_fd; |
0dca7bd5 KZ |
120 | static int repair, automatic, verbose, list, show, warn_mode, force; |
121 | static int directory, regular, blockdev, chardev, links, symlinks, total; | |
6dbe3af9 | 122 | |
a2bfda30 SK |
123 | static int changed; /* flags if the filesystem has been changed */ |
124 | static int errors_uncorrected; /* flag if some error was not corrected */ | |
ab1c86fc KZ |
125 | static size_t dirsize = 16; |
126 | static size_t namelen = 14; | |
fd6b7a7f | 127 | static struct termios termios; |
0dca7bd5 | 128 | static volatile sig_atomic_t termios_set; |
6dbe3af9 KZ |
129 | |
130 | /* File-name data */ | |
131 | #define MAX_DEPTH 50 | |
0dca7bd5 KZ |
132 | static int name_depth; |
133 | static char name_list[MAX_DEPTH][MINIX_NAME_MAX + 1]; | |
134 | ||
a2bfda30 SK |
135 | /* Copy of the previous, just for error reporting - see get_current_name. This |
136 | * is a waste of 12kB or so. */ | |
0dca7bd5 | 137 | static char current_name[MAX_DEPTH * (MINIX_NAME_MAX + 1) + 1]; |
6dbe3af9 | 138 | |
0dca7bd5 KZ |
139 | static unsigned char *inode_count = NULL; |
140 | static unsigned char *zone_count = NULL; | |
6dbe3af9 | 141 | |
22853e4a | 142 | static void recursive_check(unsigned int ino); |
22853e4a | 143 | static void recursive_check2(unsigned int ino); |
6dbe3af9 | 144 | |
0dca7bd5 KZ |
145 | static char *inode_map; |
146 | static char *zone_map; | |
147 | ||
e98754d6 | 148 | #define inode_in_use(x) (isset(inode_map,(x)) != 0) |
971b7341 | 149 | #define zone_in_use(x) (isset(zone_map,(x)-get_first_zone()+1) != 0) |
6dbe3af9 KZ |
150 | |
151 | #define mark_inode(x) (setbit(inode_map,(x)),changed=1) | |
152 | #define unmark_inode(x) (clrbit(inode_map,(x)),changed=1) | |
153 | ||
971b7341 DB |
154 | #define mark_zone(x) (setbit(zone_map,(x)-get_first_zone()+1),changed=1) |
155 | #define unmark_zone(x) (clrbit(zone_map,(x)-get_first_zone()+1),changed=1) | |
6dbe3af9 | 156 | |
22853e4a | 157 | static void |
54a78201 | 158 | reset(void) { |
fd6b7a7f | 159 | if (termios_set) |
65ca6f83 | 160 | tcsetattr(STDIN_FILENO, TCSANOW, &termios); |
54a78201 JY |
161 | } |
162 | ||
54a78201 JY |
163 | static void |
164 | fatalsig(int sig) { | |
a2bfda30 SK |
165 | /* We received a fatal signal. Reset the terminal. Also reset the |
166 | * signal handler and re-send the signal, so that the parent process | |
167 | * knows which signal actually caused our death. */ | |
54a78201 JY |
168 | signal(sig, SIG_DFL); |
169 | reset(); | |
170 | raise(sig); | |
171 | } | |
172 | ||
158b8d69 | 173 | static void __attribute__((__noreturn__)) |
54a78201 | 174 | leave(int status) { |
a2bfda30 | 175 | reset(); |
6dbe3af9 KZ |
176 | exit(status); |
177 | } | |
178 | ||
82c7ab9c | 179 | static void __attribute__((__noreturn__)) |
158b8d69 SK |
180 | usage(FILE *out) { |
181 | fputs(USAGE_HEADER, out); | |
182 | fprintf(out, _(" %s [options] <device>\n"), program_invocation_short_name); | |
183 | fputs(USAGE_SEPARATOR, out); | |
184 | fputs(_("Check the consistency of a Minix filesystem.\n"), out); | |
185 | fputs(USAGE_OPTIONS, out); | |
186 | fputs(_(" -l, --list list all filenames\n"), out); | |
187 | fputs(_(" -a, --auto automatic repair\n"), out); | |
188 | fputs(_(" -r, --repair interactive repair\n"), out); | |
189 | fputs(_(" -v, --verbose be verbose\n"), out); | |
190 | fputs(_(" -s, --super output super-block information\n"), out); | |
191 | fputs(_(" -m, --uncleared activate mode not cleared warnings\n"), out); | |
192 | fputs(_(" -f, --force force check\n"), out); | |
193 | fputs(USAGE_SEPARATOR, out); | |
194 | fputs(USAGE_HELP, out); | |
195 | fputs(USAGE_VERSION, out); | |
196 | fprintf(out, USAGE_MAN_TAIL("fsck.minix(8)")); | |
197 | leave(out == stderr ? FSCK_EX_USAGE : FSCK_EX_OK); | |
eb63b9b8 KZ |
198 | } |
199 | ||
bb983885 | 200 | static void die(const char *fmt, ...) |
a2bfda30 | 201 | __attribute__ ((__format__(__printf__, 1, 2))); |
bb983885 | 202 | |
22853e4a | 203 | static void |
bb983885 JY |
204 | die(const char *fmt, ...) { |
205 | va_list ap; | |
206 | ||
0c6625a1 | 207 | fprintf(stderr, UTIL_LINUX_VERSION); |
bb983885 JY |
208 | va_start(ap, fmt); |
209 | vfprintf(stderr, fmt, ap); | |
a2bfda30 | 210 | va_end(ap); |
bb983885 | 211 | fputc('\n', stderr); |
891327c0 | 212 | leave(FSCK_EX_ERROR); |
eb63b9b8 | 213 | } |
6dbe3af9 | 214 | |
a2bfda30 | 215 | /* This simply goes through the file-name data and prints out the current file. */ |
22853e4a | 216 | static void |
612721db KZ |
217 | get_current_name(void) { |
218 | int i = 0, ct; | |
219 | char *p, *q; | |
220 | ||
221 | q = current_name; | |
222 | while (i < name_depth) { | |
223 | p = name_list[i++]; | |
224 | ct = namelen; | |
225 | *q++ = '/'; | |
226 | while (ct-- && *p) | |
227 | *q++ = *p++; | |
228 | } | |
fd6b7a7f | 229 | if (i == 0) |
612721db KZ |
230 | *q++ = '/'; |
231 | *q = 0; | |
6dbe3af9 KZ |
232 | } |
233 | ||
22853e4a | 234 | static int |
a2bfda30 | 235 | ask(const char *string, int def) { |
d4a573bc SK |
236 | int resp; |
237 | char input[YESNO_LENGTH]; | |
6dbe3af9 KZ |
238 | |
239 | if (!repair) { | |
240 | printf("\n"); | |
241 | errors_uncorrected = 1; | |
242 | return 0; | |
243 | } | |
244 | if (automatic) { | |
245 | printf("\n"); | |
246 | if (!def) | |
a2bfda30 | 247 | errors_uncorrected = 1; |
6dbe3af9 KZ |
248 | return def; |
249 | } | |
d4a573bc SK |
250 | /* TRANSLATORS: these yes no questions uses rpmatch(), and should be |
251 | * translated. */ | |
252 | printf(def ? _("%s (y/n)? ") : _("%s (n/y)? "), string); | |
253 | fflush(stdout); | |
28d4cdcb | 254 | ignore_result( fgets(input, YESNO_LENGTH, stdin) ); |
d4a573bc SK |
255 | resp = rpmatch(input); |
256 | switch (resp) { | |
cd2a6f1c | 257 | case RPMATCH_INVALID: |
d4a573bc SK |
258 | /* def = def */ |
259 | break; | |
cd2a6f1c SK |
260 | case RPMATCH_NO: |
261 | case RPMATCH_YES: | |
d4a573bc SK |
262 | def = resp; |
263 | break; | |
264 | default: | |
265 | /* rpmatch bug? */ | |
266 | abort(); | |
6dbe3af9 KZ |
267 | } |
268 | if (def) | |
d4a573bc | 269 | printf(_("y\n")); |
6dbe3af9 | 270 | else { |
d4a573bc | 271 | printf(_("n\n")); |
6dbe3af9 | 272 | errors_uncorrected = 1; |
d4a573bc | 273 | } |
6dbe3af9 KZ |
274 | return def; |
275 | } | |
276 | ||
a2bfda30 SK |
277 | /* Make certain that we aren't checking a filesystem that is on a mounted |
278 | * partition. Code adapted from e2fsck, Copyright (C) 1993, 1994 Theodore | |
279 | * Ts'o. Also licensed under GPL. */ | |
22853e4a | 280 | static void |
a2bfda30 | 281 | check_mount(void) { |
6dbe3af9 | 282 | int cont; |
6dbe3af9 | 283 | |
c0f6d6d0 | 284 | if (!is_mounted(device_name)) |
6dbe3af9 KZ |
285 | return; |
286 | ||
a2bfda30 | 287 | printf(_("%s is mounted. "), device_name); |
65ca6f83 | 288 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) |
7eda085c | 289 | cont = ask(_("Do you really want to continue"), 0); |
6dbe3af9 KZ |
290 | else |
291 | cont = 0; | |
292 | if (!cont) { | |
a2bfda30 SK |
293 | printf(_("check aborted.\n")); |
294 | exit(FSCK_EX_OK); | |
6dbe3af9 KZ |
295 | } |
296 | return; | |
297 | } | |
298 | ||
65c74885 KZ |
299 | |
300 | static int is_valid_zone_nr(unsigned short nr) | |
301 | { | |
302 | if (nr < get_first_zone()) | |
303 | return 0; | |
304 | else if (nr >= get_nzones()) | |
305 | return 0; | |
306 | return 1; | |
307 | } | |
308 | ||
a2bfda30 SK |
309 | /* check_zone_nr checks to see that *nr is a valid zone nr. If it isn't, it |
310 | * will possibly be repaired. Check_zone_nr sets *corrected if an error was | |
311 | * corrected, and returns the zone (0 for no zone or a bad zone-number). */ | |
22853e4a | 312 | static int |
a2bfda30 | 313 | check_zone_nr(unsigned short *nr, int *corrected) { |
6dbe3af9 KZ |
314 | if (!*nr) |
315 | return 0; | |
612721db | 316 | |
971b7341 | 317 | if (*nr < get_first_zone()) { |
612721db | 318 | get_current_name(); |
a2bfda30 | 319 | printf(_("Zone nr < FIRSTZONE in file `%s'."), current_name); |
971b7341 | 320 | } else if (*nr >= get_nzones()) { |
612721db | 321 | get_current_name(); |
a2bfda30 | 322 | printf(_("Zone nr >= ZONES in file `%s'."), current_name); |
612721db | 323 | } else |
6dbe3af9 | 324 | return *nr; |
612721db | 325 | |
a2bfda30 | 326 | if (ask(_("Remove block"), 1)) { |
6dbe3af9 KZ |
327 | *nr = 0; |
328 | *corrected = 1; | |
329 | } | |
330 | return 0; | |
331 | } | |
332 | ||
22853e4a | 333 | static int |
a2bfda30 | 334 | check_zone_nr2(unsigned int *nr, int *corrected) { |
fd6b7a7f KZ |
335 | if (!*nr) |
336 | return 0; | |
612721db | 337 | |
971b7341 | 338 | if (*nr < get_first_zone()) { |
612721db | 339 | get_current_name(); |
a2bfda30 | 340 | printf(_("Zone nr < FIRSTZONE in file `%s'."), current_name); |
971b7341 | 341 | } else if (*nr >= get_nzones()) { |
612721db | 342 | get_current_name(); |
a2bfda30 | 343 | printf(_("Zone nr >= ZONES in file `%s'."), current_name); |
612721db | 344 | } else |
fd6b7a7f | 345 | return *nr; |
612721db | 346 | |
a2bfda30 | 347 | if (ask(_("Remove block"), 1)) { |
fd6b7a7f KZ |
348 | *nr = 0; |
349 | *corrected = 1; | |
350 | } | |
351 | return 0; | |
352 | } | |
353 | ||
a2bfda30 | 354 | /* read-block reads block nr into the buffer at addr. */ |
22853e4a | 355 | static void |
a2bfda30 | 356 | read_block(unsigned int nr, char *addr) { |
6dbe3af9 | 357 | if (!nr) { |
a2bfda30 | 358 | memset(addr, 0, MINIX_BLOCK_SIZE); |
6dbe3af9 KZ |
359 | return; |
360 | } | |
e1df9d4c | 361 | if (MINIX_BLOCK_SIZE * nr != lseek(device_fd, MINIX_BLOCK_SIZE * nr, SEEK_SET)) { |
612721db KZ |
362 | get_current_name(); |
363 | printf(_("Read error: unable to seek to block in file '%s'\n"), | |
364 | current_name); | |
a2bfda30 | 365 | memset(addr, 0, MINIX_BLOCK_SIZE); |
6dbe3af9 | 366 | errors_uncorrected = 1; |
e1df9d4c | 367 | } else if (MINIX_BLOCK_SIZE != read(device_fd, addr, MINIX_BLOCK_SIZE)) { |
612721db | 368 | get_current_name(); |
a2bfda30 SK |
369 | printf(_("Read error: bad block in file '%s'\n"), current_name); |
370 | memset(addr, 0, MINIX_BLOCK_SIZE); | |
6dbe3af9 KZ |
371 | errors_uncorrected = 1; |
372 | } | |
373 | } | |
374 | ||
a2bfda30 | 375 | /* write_block writes block nr to disk. */ |
22853e4a | 376 | static void |
a2bfda30 | 377 | write_block(unsigned int nr, char *addr) { |
6dbe3af9 KZ |
378 | if (!nr) |
379 | return; | |
971b7341 | 380 | if (nr < get_first_zone() || nr >= get_nzones()) { |
7eda085c | 381 | printf(_("Internal error: trying to write bad block\n" |
a2bfda30 | 382 | "Write request ignored\n")); |
6dbe3af9 KZ |
383 | errors_uncorrected = 1; |
384 | return; | |
385 | } | |
e1df9d4c | 386 | if (MINIX_BLOCK_SIZE * nr != lseek(device_fd, MINIX_BLOCK_SIZE * nr, SEEK_SET)) |
eb63b9b8 | 387 | die(_("seek failed in write_block")); |
e1df9d4c | 388 | if (MINIX_BLOCK_SIZE != write(device_fd, addr, MINIX_BLOCK_SIZE)) { |
612721db KZ |
389 | get_current_name(); |
390 | printf(_("Write error: bad block in file '%s'\n"), | |
391 | current_name); | |
6dbe3af9 KZ |
392 | errors_uncorrected = 1; |
393 | } | |
394 | } | |
395 | ||
a2bfda30 SK |
396 | /* map-block calculates the absolute block nr of a block in a file. It sets |
397 | * 'changed' if the inode has needed changing, and re-writes any indirect | |
398 | * blocks with errors. */ | |
22853e4a | 399 | static int |
a2bfda30 SK |
400 | map_block(struct minix_inode *inode, unsigned int blknr) { |
401 | unsigned short ind[MINIX_BLOCK_SIZE >> 1]; | |
402 | unsigned short dind[MINIX_BLOCK_SIZE >> 1]; | |
6dbe3af9 | 403 | int blk_chg, block, result; |
51b4b398 | 404 | size_t range; |
6dbe3af9 | 405 | |
a2bfda30 | 406 | if (blknr < 7) |
6dbe3af9 KZ |
407 | return check_zone_nr(inode->i_zone + blknr, &changed); |
408 | blknr -= 7; | |
a2bfda30 | 409 | if (blknr < 512) { |
6dbe3af9 | 410 | block = check_zone_nr(inode->i_zone + 7, &changed); |
a2bfda30 | 411 | read_block(block, (char *)ind); |
6dbe3af9 KZ |
412 | blk_chg = 0; |
413 | result = check_zone_nr(blknr + ind, &blk_chg); | |
414 | if (blk_chg) | |
a2bfda30 | 415 | write_block(block, (char *)ind); |
6dbe3af9 KZ |
416 | return result; |
417 | } | |
418 | blknr -= 512; | |
419 | block = check_zone_nr(inode->i_zone + 8, &changed); | |
a2bfda30 | 420 | read_block(block, (char *)dind); |
6dbe3af9 | 421 | blk_chg = 0; |
51b4b398 SK |
422 | range = blknr / 512; |
423 | if (ARRAY_SIZE(dind) <= range) { | |
424 | printf(_("Warning: block out of range\n")); | |
425 | return 1; | |
426 | } | |
427 | result = check_zone_nr(dind + range, &blk_chg); | |
6dbe3af9 | 428 | if (blk_chg) |
a2bfda30 | 429 | write_block(block, (char *)dind); |
6dbe3af9 | 430 | block = result; |
a2bfda30 | 431 | read_block(block, (char *)ind); |
6dbe3af9 | 432 | blk_chg = 0; |
a2bfda30 | 433 | result = check_zone_nr(ind + (blknr % 512), &blk_chg); |
6dbe3af9 | 434 | if (blk_chg) |
a2bfda30 | 435 | write_block(block, (char *)ind); |
6dbe3af9 KZ |
436 | return result; |
437 | } | |
438 | ||
22853e4a | 439 | static int |
a2bfda30 | 440 | map_block2(struct minix2_inode *inode, unsigned int blknr) { |
63883af7 SK |
441 | unsigned int ind[MINIX_BLOCK_SIZE >> 2]; |
442 | unsigned int dind[MINIX_BLOCK_SIZE >> 2]; | |
443 | unsigned int tind[MINIX_BLOCK_SIZE >> 2]; | |
fd6b7a7f KZ |
444 | int blk_chg, block, result; |
445 | ||
446 | if (blknr < 7) | |
a2bfda30 | 447 | return check_zone_nr2(inode->i_zone + blknr, &changed); |
fd6b7a7f KZ |
448 | blknr -= 7; |
449 | if (blknr < 256) { | |
a2bfda30 SK |
450 | block = check_zone_nr2(inode->i_zone + 7, &changed); |
451 | read_block(block, (char *)ind); | |
fd6b7a7f | 452 | blk_chg = 0; |
a2bfda30 | 453 | result = check_zone_nr2(blknr + ind, &blk_chg); |
fd6b7a7f | 454 | if (blk_chg) |
a2bfda30 | 455 | write_block(block, (char *)ind); |
fd6b7a7f KZ |
456 | return result; |
457 | } | |
458 | blknr -= 256; | |
06c0375c | 459 | if (blknr < 256 * 256) { |
a2bfda30 SK |
460 | block = check_zone_nr2(inode->i_zone + 8, &changed); |
461 | read_block(block, (char *)dind); | |
fd6b7a7f | 462 | blk_chg = 0; |
a2bfda30 | 463 | result = check_zone_nr2(dind + blknr / 256, &blk_chg); |
fd6b7a7f | 464 | if (blk_chg) |
a2bfda30 | 465 | write_block(block, (char *)dind); |
fd6b7a7f | 466 | block = result; |
a2bfda30 | 467 | read_block(block, (char *)ind); |
fd6b7a7f | 468 | blk_chg = 0; |
a2bfda30 | 469 | result = check_zone_nr2(ind + blknr % 256, &blk_chg); |
fd6b7a7f | 470 | if (blk_chg) |
a2bfda30 | 471 | write_block(block, (char *)ind); |
fd6b7a7f KZ |
472 | return result; |
473 | } | |
474 | blknr -= 256 * 256; | |
a2bfda30 SK |
475 | block = check_zone_nr2(inode->i_zone + 9, &changed); |
476 | read_block(block, (char *)tind); | |
fd6b7a7f | 477 | blk_chg = 0; |
a2bfda30 | 478 | result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg); |
fd6b7a7f | 479 | if (blk_chg) |
a2bfda30 | 480 | write_block(block, (char *)tind); |
fd6b7a7f | 481 | block = result; |
a2bfda30 | 482 | read_block(block, (char *)dind); |
fd6b7a7f | 483 | blk_chg = 0; |
a2bfda30 | 484 | result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg); |
fd6b7a7f | 485 | if (blk_chg) |
a2bfda30 | 486 | write_block(block, (char *)dind); |
fd6b7a7f | 487 | block = result; |
a2bfda30 | 488 | read_block(block, (char *)ind); |
fd6b7a7f | 489 | blk_chg = 0; |
a2bfda30 | 490 | result = check_zone_nr2(ind + blknr % 256, &blk_chg); |
fd6b7a7f | 491 | if (blk_chg) |
a2bfda30 | 492 | write_block(block, (char *)ind); |
fd6b7a7f KZ |
493 | return result; |
494 | } | |
fd6b7a7f | 495 | |
22853e4a KZ |
496 | static void |
497 | write_super_block(void) { | |
86a9f3da SK |
498 | /* v3 super block does not track state */ |
499 | if (fs_version == 3) | |
500 | return; | |
a2bfda30 SK |
501 | /* Set the state of the filesystem based on whether or not there are |
502 | * uncorrected errors. The filesystem valid flag is unconditionally | |
503 | * set if we get this far. */ | |
6dbe3af9 | 504 | Super.s_state |= MINIX_VALID_FS; |
a2bfda30 | 505 | if (errors_uncorrected) |
6dbe3af9 KZ |
506 | Super.s_state |= MINIX_ERROR_FS; |
507 | else | |
508 | Super.s_state &= ~MINIX_ERROR_FS; | |
c1d26b19 | 509 | |
e1df9d4c | 510 | if (MINIX_BLOCK_SIZE != lseek(device_fd, MINIX_BLOCK_SIZE, SEEK_SET)) |
eb63b9b8 | 511 | die(_("seek failed in write_super_block")); |
e1df9d4c | 512 | if (MINIX_BLOCK_SIZE != write(device_fd, super_block_buffer, MINIX_BLOCK_SIZE)) |
eb63b9b8 | 513 | die(_("unable to write super-block")); |
6dbe3af9 KZ |
514 | return; |
515 | } | |
516 | ||
22853e4a KZ |
517 | static void |
518 | write_tables(void) { | |
971b7341 DB |
519 | unsigned long buffsz = get_inode_buffer_size(); |
520 | unsigned long imaps = get_nimaps(); | |
521 | unsigned long zmaps = get_nzmaps(); | |
6dbe3af9 | 522 | |
3acc206d SK |
523 | write_super_block(); |
524 | ||
e1df9d4c | 525 | if (write_all(device_fd, inode_map, imaps * MINIX_BLOCK_SIZE)) |
eb63b9b8 | 526 | die(_("Unable to write inode map")); |
ab1c86fc | 527 | |
e1df9d4c | 528 | if (write_all(device_fd, zone_map, zmaps * MINIX_BLOCK_SIZE)) |
eb63b9b8 | 529 | die(_("Unable to write zone map")); |
ab1c86fc | 530 | |
e1df9d4c | 531 | if (write_all(device_fd, inode_buffer, buffsz)) |
eb63b9b8 | 532 | die(_("Unable to write inodes")); |
6dbe3af9 KZ |
533 | } |
534 | ||
22853e4a | 535 | static void |
a2bfda30 | 536 | get_dirsize(void) { |
fd6b7a7f | 537 | int block; |
63883af7 | 538 | char blk[MINIX_BLOCK_SIZE]; |
ab1c86fc | 539 | size_t size; |
fd6b7a7f | 540 | |
86a9f3da | 541 | if (fs_version == 2 || fs_version == 3) |
fd6b7a7f KZ |
542 | block = Inode2[ROOT_INO].i_zone[0]; |
543 | else | |
fd6b7a7f | 544 | block = Inode[ROOT_INO].i_zone[0]; |
a2bfda30 | 545 | read_block(block, blk); |
ab1c86fc | 546 | |
63883af7 | 547 | for (size = 16; size < MINIX_BLOCK_SIZE; size <<= 1) { |
ab1c86fc | 548 | if (strcmp(blk + size + 2, "..") == 0) { |
fd6b7a7f KZ |
549 | dirsize = size; |
550 | namelen = size - 2; | |
551 | return; | |
552 | } | |
553 | } | |
554 | /* use defaults */ | |
555 | } | |
556 | ||
22853e4a KZ |
557 | static void |
558 | read_superblock(void) { | |
e1df9d4c | 559 | if (MINIX_BLOCK_SIZE != lseek(device_fd, MINIX_BLOCK_SIZE, SEEK_SET)) |
eb63b9b8 | 560 | die(_("seek failed")); |
c326060c | 561 | |
63883af7 | 562 | super_block_buffer = calloc(1, MINIX_BLOCK_SIZE); |
c326060c KZ |
563 | if (!super_block_buffer) |
564 | die(_("unable to alloc buffer for superblock")); | |
565 | ||
e1df9d4c | 566 | if (MINIX_BLOCK_SIZE != read(device_fd, super_block_buffer, MINIX_BLOCK_SIZE)) |
eb63b9b8 | 567 | die(_("unable to read super block")); |
86a9f3da | 568 | if (Super.s_magic == MINIX_SUPER_MAGIC) { |
6dbe3af9 KZ |
569 | namelen = 14; |
570 | dirsize = 16; | |
971b7341 | 571 | fs_version = 1; |
86a9f3da | 572 | } else if (Super.s_magic == MINIX_SUPER_MAGIC2) { |
6dbe3af9 KZ |
573 | namelen = 30; |
574 | dirsize = 32; | |
971b7341 | 575 | fs_version = 1; |
86a9f3da | 576 | } else if (Super.s_magic == MINIX2_SUPER_MAGIC) { |
fd6b7a7f KZ |
577 | namelen = 14; |
578 | dirsize = 16; | |
971b7341 | 579 | fs_version = 2; |
86a9f3da | 580 | } else if (Super.s_magic == MINIX2_SUPER_MAGIC2) { |
fd6b7a7f KZ |
581 | namelen = 30; |
582 | dirsize = 32; | |
971b7341 | 583 | fs_version = 2; |
86a9f3da SK |
584 | } else if (Super3.s_magic == MINIX3_SUPER_MAGIC) { |
585 | namelen = 60; | |
586 | dirsize = 64; | |
587 | fs_version = 3; | |
6dbe3af9 | 588 | } else |
eb63b9b8 | 589 | die(_("bad magic number in super-block")); |
63883af7 | 590 | if (get_zone_size() != 0 || MINIX_BLOCK_SIZE != 1024) |
eb63b9b8 | 591 | die(_("Only 1k blocks/zones supported")); |
8f35b3a9 TS |
592 | if (get_ninodes() == 0 || get_ninodes() == UINT32_MAX) |
593 | die(_("bad s_ninodes field in super-block")); | |
63883af7 | 594 | if (get_nimaps() * MINIX_BLOCK_SIZE * 8 < get_ninodes() + 1) |
eb63b9b8 | 595 | die(_("bad s_imap_blocks field in super-block")); |
8f35b3a9 TS |
596 | if (get_first_zone() > (off_t) get_nzones()) |
597 | die(_("bad s_firstdatazone field in super-block")); | |
a2bfda30 SK |
598 | if (get_nzmaps() * MINIX_BLOCK_SIZE * 8 < |
599 | get_nzones() - get_first_zone() + 1) | |
eb63b9b8 | 600 | die(_("bad s_zmap_blocks field in super-block")); |
fd6b7a7f KZ |
601 | } |
602 | ||
22853e4a KZ |
603 | static void |
604 | read_tables(void) { | |
971b7341 | 605 | unsigned long inodes = get_ninodes(); |
a180dc6c SK |
606 | size_t buffsz = get_inode_buffer_size(); |
607 | off_t norm_first_zone = first_zone_data(); | |
608 | off_t first_zone = get_first_zone(); | |
971b7341 DB |
609 | unsigned long zones = get_nzones(); |
610 | unsigned long imaps = get_nimaps(); | |
611 | unsigned long zmaps = get_nzmaps(); | |
ab1c86fc | 612 | ssize_t rc; |
971b7341 | 613 | |
63883af7 | 614 | inode_map = malloc(imaps * MINIX_BLOCK_SIZE); |
2b6fc908 | 615 | if (!inode_map) |
eb63b9b8 | 616 | die(_("Unable to allocate buffer for inode map")); |
63883af7 | 617 | zone_map = malloc(zmaps * MINIX_BLOCK_SIZE); |
f8209a0f | 618 | if (!zone_map) |
65b27d36 | 619 | die(_("Unable to allocate buffer for zone map")); |
971b7341 | 620 | inode_buffer = malloc(buffsz); |
6dbe3af9 | 621 | if (!inode_buffer) |
eb63b9b8 | 622 | die(_("Unable to allocate buffer for inodes")); |
d73af2ac | 623 | inode_count = calloc(1, inodes + 1); |
6dbe3af9 | 624 | if (!inode_count) |
eb63b9b8 | 625 | die(_("Unable to allocate buffer for inode count")); |
d73af2ac | 626 | zone_count = calloc(1, zones); |
6dbe3af9 | 627 | if (!zone_count) |
eb63b9b8 | 628 | die(_("Unable to allocate buffer for zone count")); |
ab1c86fc | 629 | |
e1df9d4c | 630 | rc = read(device_fd, inode_map, imaps * MINIX_BLOCK_SIZE); |
ab1c86fc | 631 | if (rc < 0 || imaps * MINIX_BLOCK_SIZE != (size_t) rc) |
eb63b9b8 | 632 | die(_("Unable to read inode map")); |
ab1c86fc | 633 | |
e1df9d4c | 634 | rc = read(device_fd, zone_map, zmaps * MINIX_BLOCK_SIZE); |
ab1c86fc | 635 | if (rc < 0 || zmaps * MINIX_BLOCK_SIZE != (size_t) rc) |
eb63b9b8 | 636 | die(_("Unable to read zone map")); |
ab1c86fc | 637 | |
e1df9d4c | 638 | rc = read(device_fd, inode_buffer, buffsz); |
ab1c86fc | 639 | if (rc < 0 || buffsz != (size_t) rc) |
eb63b9b8 | 640 | die(_("Unable to read inodes")); |
971b7341 | 641 | if (norm_first_zone != first_zone) { |
7eda085c | 642 | printf(_("Warning: Firstzone != Norm_firstzone\n")); |
6dbe3af9 KZ |
643 | errors_uncorrected = 1; |
644 | } | |
a2bfda30 | 645 | get_dirsize(); |
6dbe3af9 | 646 | if (show) { |
971b7341 DB |
647 | printf(_("%ld inodes\n"), inodes); |
648 | printf(_("%ld blocks\n"), zones); | |
fdbd7bb9 RM |
649 | printf(_("Firstdatazone=%jd (%jd)\n"), |
650 | (intmax_t)first_zone, (intmax_t)norm_first_zone); | |
a2bfda30 | 651 | printf(_("Zonesize=%d\n"), MINIX_BLOCK_SIZE << get_zone_size()); |
248b8101 | 652 | printf(_("Maxsize=%zu\n"), get_max_size()); |
86a9f3da SK |
653 | if (fs_version < 3) |
654 | printf(_("Filesystem state=%d\n"), Super.s_state); | |
a2bfda30 | 655 | printf(_("namelen=%zd\n\n"), namelen); |
6dbe3af9 KZ |
656 | } |
657 | } | |
658 | ||
22853e4a KZ |
659 | static struct minix_inode * |
660 | get_inode(unsigned int nr) { | |
a2bfda30 | 661 | struct minix_inode *inode; |
6dbe3af9 | 662 | |
971b7341 | 663 | if (!nr || nr > get_ninodes()) |
6dbe3af9 KZ |
664 | return NULL; |
665 | total++; | |
666 | inode = Inode + nr; | |
667 | if (!inode_count[nr]) { | |
668 | if (!inode_in_use(nr)) { | |
612721db KZ |
669 | get_current_name(); |
670 | printf(_("Inode %d marked unused, " | |
a2bfda30 | 671 | "but used for file '%s'\n"), nr, current_name); |
5c36a0eb | 672 | if (repair) { |
a2bfda30 | 673 | if (ask(_("Mark in use"), 1)) |
6dbe3af9 | 674 | mark_inode(nr); |
5c36a0eb | 675 | } else { |
a2bfda30 | 676 | errors_uncorrected = 1; |
5c36a0eb | 677 | } |
6dbe3af9 KZ |
678 | } |
679 | if (S_ISDIR(inode->i_mode)) | |
680 | directory++; | |
681 | else if (S_ISREG(inode->i_mode)) | |
682 | regular++; | |
683 | else if (S_ISCHR(inode->i_mode)) | |
684 | chardev++; | |
685 | else if (S_ISBLK(inode->i_mode)) | |
686 | blockdev++; | |
687 | else if (S_ISLNK(inode->i_mode)) | |
688 | symlinks++; | |
689 | else if (S_ISSOCK(inode->i_mode)) | |
690 | ; | |
691 | else if (S_ISFIFO(inode->i_mode)) | |
692 | ; | |
693 | else { | |
a2bfda30 SK |
694 | get_current_name(); |
695 | printf(_("The file `%s' has mode %05o\n"), | |
612721db | 696 | current_name, inode->i_mode); |
a2bfda30 | 697 | } |
6dbe3af9 KZ |
698 | |
699 | } else | |
700 | links++; | |
701 | if (!++inode_count[nr]) { | |
7eda085c | 702 | printf(_("Warning: inode count too big.\n")); |
6dbe3af9 KZ |
703 | inode_count[nr]--; |
704 | errors_uncorrected = 1; | |
705 | } | |
706 | return inode; | |
707 | } | |
708 | ||
22853e4a | 709 | static struct minix2_inode * |
a2bfda30 | 710 | get_inode2(unsigned int nr) { |
fd6b7a7f KZ |
711 | struct minix2_inode *inode; |
712 | ||
971b7341 | 713 | if (!nr || nr > get_ninodes()) |
fd6b7a7f KZ |
714 | return NULL; |
715 | total++; | |
716 | inode = Inode2 + nr; | |
717 | if (!inode_count[nr]) { | |
a2bfda30 | 718 | if (!inode_in_use(nr)) { |
612721db | 719 | get_current_name(); |
a2bfda30 SK |
720 | printf(_("Inode %d marked unused, " |
721 | "but used for file '%s'\n"), nr, current_name); | |
fd6b7a7f | 722 | if (repair) { |
a2bfda30 SK |
723 | if (ask(_("Mark in use"), 1)) |
724 | mark_inode(nr); | |
fd6b7a7f KZ |
725 | else |
726 | errors_uncorrected = 1; | |
727 | } | |
728 | } | |
a2bfda30 | 729 | if (S_ISDIR(inode->i_mode)) |
fd6b7a7f | 730 | directory++; |
a2bfda30 | 731 | else if (S_ISREG(inode->i_mode)) |
fd6b7a7f | 732 | regular++; |
a2bfda30 | 733 | else if (S_ISCHR(inode->i_mode)) |
fd6b7a7f | 734 | chardev++; |
a2bfda30 | 735 | else if (S_ISBLK(inode->i_mode)) |
fd6b7a7f | 736 | blockdev++; |
a2bfda30 | 737 | else if (S_ISLNK(inode->i_mode)) |
fd6b7a7f | 738 | symlinks++; |
a2bfda30 SK |
739 | else if (S_ISSOCK(inode->i_mode)) ; |
740 | else if (S_ISFIFO(inode->i_mode)) ; | |
fd6b7a7f | 741 | else { |
a2bfda30 SK |
742 | get_current_name(); |
743 | printf(_("The file `%s' has mode %05o\n"), | |
744 | current_name, inode->i_mode); | |
fd6b7a7f KZ |
745 | } |
746 | } else | |
747 | links++; | |
748 | if (!++inode_count[nr]) { | |
a2bfda30 | 749 | printf(_("Warning: inode count too big.\n")); |
fd6b7a7f KZ |
750 | inode_count[nr]--; |
751 | errors_uncorrected = 1; | |
752 | } | |
753 | return inode; | |
754 | } | |
fd6b7a7f | 755 | |
22853e4a KZ |
756 | static void |
757 | check_root(void) { | |
a2bfda30 | 758 | struct minix_inode *inode = Inode + ROOT_INO; |
6dbe3af9 KZ |
759 | |
760 | if (!inode || !S_ISDIR(inode->i_mode)) | |
eb63b9b8 | 761 | die(_("root inode isn't a directory")); |
6dbe3af9 KZ |
762 | } |
763 | ||
22853e4a | 764 | static void |
a2bfda30 | 765 | check_root2(void) { |
fd6b7a7f KZ |
766 | struct minix2_inode *inode = Inode2 + ROOT_INO; |
767 | ||
a2bfda30 | 768 | if (!inode || !S_ISDIR(inode->i_mode)) |
65b27d36 | 769 | die(_("root inode isn't a directory")); |
fd6b7a7f | 770 | } |
fd6b7a7f | 771 | |
22853e4a | 772 | static int |
a2bfda30 | 773 | add_zone(unsigned short *znr, int *corrected) { |
6dbe3af9 KZ |
774 | int block; |
775 | ||
6dbe3af9 KZ |
776 | block = check_zone_nr(znr, corrected); |
777 | if (!block) | |
778 | return 0; | |
779 | if (zone_count[block]) { | |
612721db KZ |
780 | get_current_name(); |
781 | printf(_("Block has been used before. Now in file `%s'."), | |
782 | current_name); | |
a2bfda30 | 783 | if (ask(_("Clear"), 1)) { |
6dbe3af9 KZ |
784 | *znr = 0; |
785 | block = 0; | |
786 | *corrected = 1; | |
787 | } | |
788 | } | |
789 | if (!block) | |
790 | return 0; | |
791 | if (!zone_in_use(block)) { | |
612721db KZ |
792 | get_current_name(); |
793 | printf(_("Block %d in file `%s' is marked not in use."), | |
794 | block, current_name); | |
a2bfda30 | 795 | if (ask(_("Correct"), 1)) |
6dbe3af9 KZ |
796 | mark_zone(block); |
797 | } | |
798 | if (!++zone_count[block]) | |
799 | zone_count[block]--; | |
800 | return block; | |
801 | } | |
802 | ||
22853e4a | 803 | static int |
a2bfda30 | 804 | add_zone2(unsigned int *znr, int *corrected) { |
fd6b7a7f KZ |
805 | int block; |
806 | ||
a2bfda30 | 807 | block = check_zone_nr2(znr, corrected); |
fd6b7a7f KZ |
808 | if (!block) |
809 | return 0; | |
810 | if (zone_count[block]) { | |
612721db | 811 | get_current_name(); |
a2bfda30 SK |
812 | printf(_("Block has been used before. Now in file `%s'."), |
813 | current_name); | |
814 | if (ask(_("Clear"), 1)) { | |
fd6b7a7f KZ |
815 | *znr = 0; |
816 | block = 0; | |
817 | *corrected = 1; | |
818 | } | |
819 | } | |
820 | if (!block) | |
821 | return 0; | |
a2bfda30 | 822 | if (!zone_in_use(block)) { |
612721db | 823 | get_current_name(); |
a2bfda30 SK |
824 | printf(_("Block %d in file `%s' is marked not in use."), |
825 | block, current_name); | |
826 | if (ask(_("Correct"), 1)) | |
827 | mark_zone(block); | |
fd6b7a7f KZ |
828 | } |
829 | if (!++zone_count[block]) | |
830 | zone_count[block]--; | |
831 | return block; | |
832 | } | |
833 | ||
22853e4a | 834 | static void |
a2bfda30 | 835 | add_zone_ind(unsigned short *znr, int *corrected) { |
63883af7 | 836 | static char blk[MINIX_BLOCK_SIZE]; |
a2bfda30 | 837 | int i, chg_blk = 0; |
6dbe3af9 KZ |
838 | int block; |
839 | ||
840 | block = add_zone(znr, corrected); | |
841 | if (!block) | |
842 | return; | |
843 | read_block(block, blk); | |
a2bfda30 SK |
844 | for (i = 0; i < (MINIX_BLOCK_SIZE >> 1); i++) |
845 | add_zone(i + (unsigned short *)blk, &chg_blk); | |
6dbe3af9 KZ |
846 | if (chg_blk) |
847 | write_block(block, blk); | |
848 | } | |
849 | ||
5c36a0eb | 850 | static void |
a2bfda30 | 851 | add_zone_ind2(unsigned int *znr, int *corrected) { |
63883af7 | 852 | static char blk[MINIX_BLOCK_SIZE]; |
fd6b7a7f KZ |
853 | int i, chg_blk = 0; |
854 | int block; | |
855 | ||
a2bfda30 | 856 | block = add_zone2(znr, corrected); |
fd6b7a7f KZ |
857 | if (!block) |
858 | return; | |
a2bfda30 | 859 | read_block(block, blk); |
63883af7 | 860 | for (i = 0; i < MINIX_BLOCK_SIZE >> 2; i++) |
a2bfda30 | 861 | add_zone2(i + (unsigned int *)blk, &chg_blk); |
fd6b7a7f | 862 | if (chg_blk) |
a2bfda30 | 863 | write_block(block, blk); |
fd6b7a7f KZ |
864 | } |
865 | ||
22853e4a | 866 | static void |
a2bfda30 | 867 | add_zone_dind(unsigned short *znr, int *corrected) { |
63883af7 | 868 | static char blk[MINIX_BLOCK_SIZE]; |
a2bfda30 | 869 | int i, blk_chg = 0; |
6dbe3af9 KZ |
870 | int block; |
871 | ||
872 | block = add_zone(znr, corrected); | |
873 | if (!block) | |
874 | return; | |
875 | read_block(block, blk); | |
a2bfda30 SK |
876 | for (i = 0; i < (MINIX_BLOCK_SIZE >> 1); i++) |
877 | add_zone_ind(i + (unsigned short *)blk, &blk_chg); | |
6dbe3af9 KZ |
878 | if (blk_chg) |
879 | write_block(block, blk); | |
880 | } | |
881 | ||
fd6b7a7f | 882 | static void |
a2bfda30 | 883 | add_zone_dind2(unsigned int *znr, int *corrected) { |
63883af7 | 884 | static char blk[MINIX_BLOCK_SIZE]; |
fd6b7a7f KZ |
885 | int i, blk_chg = 0; |
886 | int block; | |
887 | ||
a2bfda30 | 888 | block = add_zone2(znr, corrected); |
fd6b7a7f KZ |
889 | if (!block) |
890 | return; | |
a2bfda30 | 891 | read_block(block, blk); |
63883af7 | 892 | for (i = 0; i < MINIX_BLOCK_SIZE >> 2; i++) |
a2bfda30 | 893 | add_zone_ind2(i + (unsigned int *)blk, &blk_chg); |
fd6b7a7f | 894 | if (blk_chg) |
a2bfda30 | 895 | write_block(block, blk); |
fd6b7a7f KZ |
896 | } |
897 | ||
898 | static void | |
a2bfda30 | 899 | add_zone_tind2(unsigned int *znr, int *corrected) { |
63883af7 | 900 | static char blk[MINIX_BLOCK_SIZE]; |
fd6b7a7f KZ |
901 | int i, blk_chg = 0; |
902 | int block; | |
903 | ||
a2bfda30 | 904 | block = add_zone2(znr, corrected); |
fd6b7a7f KZ |
905 | if (!block) |
906 | return; | |
a2bfda30 | 907 | read_block(block, blk); |
63883af7 | 908 | for (i = 0; i < MINIX_BLOCK_SIZE >> 2; i++) |
a2bfda30 | 909 | add_zone_dind2(i + (unsigned int *)blk, &blk_chg); |
fd6b7a7f | 910 | if (blk_chg) |
a2bfda30 | 911 | write_block(block, blk); |
fd6b7a7f KZ |
912 | } |
913 | ||
22853e4a KZ |
914 | static void |
915 | check_zones(unsigned int i) { | |
971b7341 | 916 | struct minix_inode *inode; |
6dbe3af9 | 917 | |
971b7341 | 918 | if (!i || i > get_ninodes()) |
6dbe3af9 KZ |
919 | return; |
920 | if (inode_count[i] > 1) /* have we counted this file already? */ | |
921 | return; | |
922 | inode = Inode + i; | |
923 | if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && | |
924 | !S_ISLNK(inode->i_mode)) | |
925 | return; | |
a2bfda30 | 926 | for (i = 0; i < 7; i++) |
6dbe3af9 KZ |
927 | add_zone(i + inode->i_zone, &changed); |
928 | add_zone_ind(7 + inode->i_zone, &changed); | |
929 | add_zone_dind(8 + inode->i_zone, &changed); | |
930 | } | |
931 | ||
22853e4a | 932 | static void |
a2bfda30 | 933 | check_zones2(unsigned int i) { |
fd6b7a7f KZ |
934 | struct minix2_inode *inode; |
935 | ||
971b7341 | 936 | if (!i || i > get_ninodes()) |
fd6b7a7f KZ |
937 | return; |
938 | if (inode_count[i] > 1) /* have we counted this file already? */ | |
939 | return; | |
940 | inode = Inode2 + i; | |
a2bfda30 SK |
941 | if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) |
942 | && !S_ISLNK(inode->i_mode)) | |
fd6b7a7f KZ |
943 | return; |
944 | for (i = 0; i < 7; i++) | |
a2bfda30 SK |
945 | add_zone2(i + inode->i_zone, &changed); |
946 | add_zone_ind2(7 + inode->i_zone, &changed); | |
947 | add_zone_dind2(8 + inode->i_zone, &changed); | |
948 | add_zone_tind2(9 + inode->i_zone, &changed); | |
fd6b7a7f | 949 | } |
fd6b7a7f | 950 | |
22853e4a | 951 | static void |
a2bfda30 | 952 | check_file(struct minix_inode *dir, unsigned int offset) { |
1e9d849b | 953 | static char blk[MINIX_BLOCK_SIZE + 2]; |
a2bfda30 | 954 | struct minix_inode *inode; |
ab1c86fc | 955 | unsigned int ino; |
a2bfda30 | 956 | char *name; |
6dbe3af9 KZ |
957 | int block; |
958 | ||
a2bfda30 | 959 | block = map_block(dir, offset / MINIX_BLOCK_SIZE); |
6dbe3af9 | 960 | read_block(block, blk); |
63883af7 | 961 | name = blk + (offset % MINIX_BLOCK_SIZE) + 2; |
a2bfda30 | 962 | ino = *(unsigned short *)(name - 2); |
971b7341 | 963 | if (ino > get_ninodes()) { |
612721db KZ |
964 | get_current_name(); |
965 | printf(_("The directory '%s' contains a bad inode number " | |
a2bfda30 SK |
966 | "for file '%.*s'."), current_name, (int)namelen, name); |
967 | if (ask(_(" Remove"), 1)) { | |
968 | *(unsigned short *)(name - 2) = 0; | |
6dbe3af9 KZ |
969 | write_block(block, blk); |
970 | } | |
971 | ino = 0; | |
a2bfda30 | 972 | } |
fd6b7a7f | 973 | if (name_depth < MAX_DEPTH) |
730ae9c8 SK |
974 | xstrncpy(name_list[name_depth], name, namelen); |
975 | else | |
976 | return; | |
fd6b7a7f | 977 | name_depth++; |
6dbe3af9 | 978 | inode = get_inode(ino); |
fd6b7a7f | 979 | name_depth--; |
5c36a0eb | 980 | if (!offset) { |
a2bfda30 | 981 | if (!inode || strcmp(".", name)) { |
612721db | 982 | get_current_name(); |
65b27d36 | 983 | printf(_("%s: bad directory: '.' isn't first\n"), |
612721db | 984 | current_name); |
6dbe3af9 | 985 | errors_uncorrected = 1; |
a2bfda30 SK |
986 | } else |
987 | return; | |
5c36a0eb KZ |
988 | } |
989 | if (offset == dirsize) { | |
a2bfda30 | 990 | if (!inode || strcmp("..", name)) { |
612721db | 991 | get_current_name(); |
65b27d36 | 992 | printf(_("%s: bad directory: '..' isn't second\n"), |
612721db | 993 | current_name); |
6dbe3af9 | 994 | errors_uncorrected = 1; |
a2bfda30 SK |
995 | } else |
996 | return; | |
5c36a0eb | 997 | } |
6dbe3af9 KZ |
998 | if (!inode) |
999 | return; | |
1000 | if (name_depth < MAX_DEPTH) | |
730ae9c8 SK |
1001 | xstrncpy(name_list[name_depth], name, namelen); |
1002 | else | |
1003 | return; | |
a2bfda30 | 1004 | name_depth++; |
6dbe3af9 KZ |
1005 | if (list) { |
1006 | if (verbose) | |
364cda48 KZ |
1007 | printf("%6d %07o %3d ", ino, |
1008 | inode->i_mode, inode->i_nlinks); | |
612721db KZ |
1009 | get_current_name(); |
1010 | printf("%s", current_name); | |
6dbe3af9 KZ |
1011 | if (S_ISDIR(inode->i_mode)) |
1012 | printf(":\n"); | |
1013 | else | |
1014 | printf("\n"); | |
1015 | } | |
1016 | check_zones(ino); | |
1017 | if (inode && S_ISDIR(inode->i_mode)) | |
1018 | recursive_check(ino); | |
1019 | name_depth--; | |
1020 | return; | |
1021 | } | |
1022 | ||
22853e4a | 1023 | static void |
a2bfda30 | 1024 | check_file2(struct minix2_inode *dir, unsigned int offset) { |
1e9d849b | 1025 | static char blk[MINIX_BLOCK_SIZE + 4]; |
fd6b7a7f | 1026 | struct minix2_inode *inode; |
a180dc6c | 1027 | ino_t ino; |
fd6b7a7f KZ |
1028 | char *name; |
1029 | int block; | |
86a9f3da | 1030 | const int version_offset = fs_version == 3 ? 4 : 2; |
fd6b7a7f | 1031 | |
a2bfda30 SK |
1032 | block = map_block2(dir, offset / MINIX_BLOCK_SIZE); |
1033 | read_block(block, blk); | |
86a9f3da | 1034 | name = blk + (offset % MINIX_BLOCK_SIZE) + version_offset; |
fcb12426 RM |
1035 | ino = version_offset == 4 ? *(uint32_t *)(name - version_offset) |
1036 | : *(uint16_t *)(name - version_offset); | |
971b7341 | 1037 | if (ino > get_ninodes()) { |
612721db KZ |
1038 | get_current_name(); |
1039 | printf(_("The directory '%s' contains a bad inode number " | |
a2bfda30 SK |
1040 | "for file '%.*s'."), current_name, (int)namelen, name); |
1041 | if (ask(_(" Remove"), 1)) { | |
fcb12426 | 1042 | memset(name - version_offset, 0, version_offset); |
a2bfda30 | 1043 | write_block(block, blk); |
fd6b7a7f KZ |
1044 | } |
1045 | ino = 0; | |
1046 | } | |
1047 | if (name_depth < MAX_DEPTH) | |
730ae9c8 SK |
1048 | xstrncpy(name_list[name_depth], name, namelen); |
1049 | else | |
1050 | return; | |
fd6b7a7f | 1051 | name_depth++; |
a2bfda30 | 1052 | inode = get_inode2(ino); |
fd6b7a7f KZ |
1053 | name_depth--; |
1054 | if (!offset) { | |
a2bfda30 SK |
1055 | if (!inode || strcmp(".", name)) { |
1056 | get_current_name(); | |
1057 | printf(_("%s: bad directory: '.' isn't first\n"), | |
1058 | current_name); | |
fd6b7a7f KZ |
1059 | errors_uncorrected = 1; |
1060 | } else | |
1061 | return; | |
1062 | } | |
1063 | if (offset == dirsize) { | |
a2bfda30 SK |
1064 | if (!inode || strcmp("..", name)) { |
1065 | get_current_name(); | |
1066 | printf(_("%s: bad directory: '..' isn't second\n"), | |
1067 | current_name); | |
fd6b7a7f KZ |
1068 | errors_uncorrected = 1; |
1069 | } else | |
1070 | return; | |
1071 | } | |
1072 | if (!inode) | |
1073 | return; | |
1074 | name_depth++; | |
1075 | if (list) { | |
1076 | if (verbose) | |
fdbd7bb9 | 1077 | printf("%6ju %07o %3d ", (uintmax_t)ino, inode->i_mode, |
a2bfda30 SK |
1078 | inode->i_nlinks); |
1079 | get_current_name(); | |
612721db | 1080 | printf("%s", current_name); |
a2bfda30 SK |
1081 | if (S_ISDIR(inode->i_mode)) |
1082 | printf(":\n"); | |
fd6b7a7f | 1083 | else |
a2bfda30 | 1084 | printf("\n"); |
fd6b7a7f | 1085 | } |
a2bfda30 SK |
1086 | check_zones2(ino); |
1087 | if (inode && S_ISDIR(inode->i_mode)) | |
1088 | recursive_check2(ino); | |
fd6b7a7f KZ |
1089 | name_depth--; |
1090 | return; | |
1091 | } | |
fd6b7a7f | 1092 | |
22853e4a KZ |
1093 | static void |
1094 | recursive_check(unsigned int ino) { | |
a2bfda30 | 1095 | struct minix_inode *dir; |
a180dc6c | 1096 | off_t offset; |
6dbe3af9 KZ |
1097 | |
1098 | dir = Inode + ino; | |
1099 | if (!S_ISDIR(dir->i_mode)) | |
eb63b9b8 | 1100 | die(_("internal error")); |
fd6b7a7f | 1101 | if (dir->i_size < 2 * dirsize) { |
612721db | 1102 | get_current_name(); |
a2bfda30 | 1103 | printf(_("%s: bad directory: size < 32"), current_name); |
6dbe3af9 KZ |
1104 | errors_uncorrected = 1; |
1105 | } | |
65c74885 KZ |
1106 | |
1107 | if ((!repair || automatic) && !is_valid_zone_nr(*dir->i_zone)) { | |
1108 | get_current_name(); | |
1109 | printf(_("%s: bad directory: invalid i_zone, use --repair to fix\n"), current_name); | |
1110 | return; | |
1111 | } | |
a2bfda30 SK |
1112 | for (offset = 0; offset < dir->i_size; offset += dirsize) |
1113 | check_file(dir, offset); | |
6dbe3af9 KZ |
1114 | } |
1115 | ||
22853e4a | 1116 | static void |
a2bfda30 | 1117 | recursive_check2(unsigned int ino) { |
fd6b7a7f | 1118 | struct minix2_inode *dir; |
a180dc6c | 1119 | off_t offset; |
fd6b7a7f KZ |
1120 | |
1121 | dir = Inode2 + ino; | |
a2bfda30 | 1122 | if (!S_ISDIR(dir->i_mode)) |
65b27d36 | 1123 | die(_("internal error")); |
fd6b7a7f | 1124 | if (dir->i_size < 2 * dirsize) { |
a2bfda30 SK |
1125 | get_current_name(); |
1126 | printf(_("%s: bad directory: size < 32"), current_name); | |
fd6b7a7f KZ |
1127 | errors_uncorrected = 1; |
1128 | } | |
1129 | for (offset = 0; offset < dir->i_size; offset += dirsize) | |
a2bfda30 | 1130 | check_file2(dir, offset); |
fd6b7a7f | 1131 | } |
fd6b7a7f | 1132 | |
22853e4a KZ |
1133 | static int |
1134 | bad_zone(int i) { | |
6dbe3af9 KZ |
1135 | char buffer[1024]; |
1136 | ||
e1df9d4c | 1137 | if (MINIX_BLOCK_SIZE * i != lseek(device_fd, MINIX_BLOCK_SIZE * i, SEEK_SET)) |
eb63b9b8 | 1138 | die(_("seek failed in bad_zone")); |
e1df9d4c | 1139 | return (MINIX_BLOCK_SIZE != read(device_fd, buffer, MINIX_BLOCK_SIZE)); |
6dbe3af9 KZ |
1140 | } |
1141 | ||
22853e4a KZ |
1142 | static void |
1143 | check_counts(void) { | |
ab1c86fc | 1144 | unsigned long i; |
6dbe3af9 | 1145 | |
a2bfda30 | 1146 | for (i = 1; i <= get_ninodes(); i++) { |
6dbe3af9 | 1147 | if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { |
ab1c86fc | 1148 | printf(_("Inode %lu mode not cleared."), i); |
a2bfda30 | 1149 | if (ask(_("Clear"), 1)) { |
6dbe3af9 KZ |
1150 | Inode[i].i_mode = 0; |
1151 | changed = 1; | |
1152 | } | |
1153 | } | |
1154 | if (!inode_count[i]) { | |
1155 | if (!inode_in_use(i)) | |
1156 | continue; | |
a2bfda30 SK |
1157 | printf(_("Inode %lu not used, marked used in the bitmap."), i); |
1158 | if (ask(_("Clear"), 1)) | |
6dbe3af9 KZ |
1159 | unmark_inode(i); |
1160 | continue; | |
1161 | } | |
1162 | if (!inode_in_use(i)) { | |
a2bfda30 SK |
1163 | printf(_("Inode %lu used, marked unused in the bitmap."), i); |
1164 | if (ask(_("Set"), 1)) | |
6dbe3af9 KZ |
1165 | mark_inode(i); |
1166 | } | |
1167 | if (Inode[i].i_nlinks != inode_count[i]) { | |
ab1c86fc | 1168 | printf(_("Inode %lu (mode = %07o), i_nlinks=%d, counted=%d."), |
a2bfda30 SK |
1169 | i, Inode[i].i_mode, Inode[i].i_nlinks, |
1170 | inode_count[i]); | |
1171 | if (ask(_("Set i_nlinks to count"), 1)) { | |
1172 | Inode[i].i_nlinks = inode_count[i]; | |
1173 | changed = 1; | |
6dbe3af9 KZ |
1174 | } |
1175 | } | |
1176 | } | |
a2bfda30 | 1177 | for (i = get_first_zone(); i < get_nzones(); i++) { |
6dbe3af9 KZ |
1178 | if (zone_in_use(i) == zone_count[i]) |
1179 | continue; | |
1180 | if (!zone_count[i]) { | |
1181 | if (bad_zone(i)) | |
1182 | continue; | |
a2bfda30 SK |
1183 | printf(_("Zone %lu: marked in use, no file uses it."), |
1184 | i); | |
1185 | if (ask(_("Unmark"), 1)) | |
6dbe3af9 KZ |
1186 | unmark_zone(i); |
1187 | continue; | |
1188 | } | |
e8f26419 | 1189 | if (zone_in_use(i)) |
ab1c86fc | 1190 | printf(_("Zone %lu: in use, counted=%d\n"), |
e8f26419 KZ |
1191 | i, zone_count[i]); |
1192 | else | |
ab1c86fc | 1193 | printf(_("Zone %lu: not in use, counted=%d\n"), |
e8f26419 | 1194 | i, zone_count[i]); |
6dbe3af9 KZ |
1195 | } |
1196 | } | |
1197 | ||
22853e4a | 1198 | static void |
a2bfda30 | 1199 | check_counts2(void) { |
ab1c86fc | 1200 | unsigned long i; |
fd6b7a7f | 1201 | |
971b7341 | 1202 | for (i = 1; i <= get_ninodes(); i++) { |
a2bfda30 SK |
1203 | if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) { |
1204 | printf(_("Inode %lu mode not cleared."), i); | |
1205 | if (ask(_("Clear"), 1)) { | |
fd6b7a7f KZ |
1206 | Inode2[i].i_mode = 0; |
1207 | changed = 1; | |
1208 | } | |
1209 | } | |
1210 | if (!inode_count[i]) { | |
a2bfda30 | 1211 | if (!inode_in_use(i)) |
fd6b7a7f | 1212 | continue; |
a2bfda30 SK |
1213 | printf(_("Inode %lu not used, marked used in the bitmap."), i); |
1214 | if (ask(_("Clear"), 1)) | |
1215 | unmark_inode(i); | |
fd6b7a7f KZ |
1216 | continue; |
1217 | } | |
a2bfda30 SK |
1218 | if (!inode_in_use(i)) { |
1219 | printf(_("Inode %lu used, marked unused in the bitmap."), i); | |
1220 | if (ask(_("Set"), 1)) | |
1221 | mark_inode(i); | |
fd6b7a7f KZ |
1222 | } |
1223 | if (Inode2[i].i_nlinks != inode_count[i]) { | |
a2bfda30 SK |
1224 | printf(_("Inode %lu (mode = %07o), i_nlinks=%d, counted=%d."), |
1225 | i, Inode2[i].i_mode, Inode2[i].i_nlinks, | |
1226 | inode_count[i]); | |
1227 | if (ask(_("Set i_nlinks to count"), 1)) { | |
fd6b7a7f KZ |
1228 | Inode2[i].i_nlinks = inode_count[i]; |
1229 | changed = 1; | |
1230 | } | |
1231 | } | |
1232 | } | |
971b7341 | 1233 | for (i = get_first_zone(); i < get_nzones(); i++) { |
a2bfda30 | 1234 | if (zone_in_use(i) == zone_count[i]) |
fd6b7a7f KZ |
1235 | continue; |
1236 | if (!zone_count[i]) { | |
a2bfda30 | 1237 | if (bad_zone(i)) |
fd6b7a7f | 1238 | continue; |
a2bfda30 SK |
1239 | printf(_("Zone %lu: marked in use, no file uses it."), |
1240 | i); | |
1241 | if (ask(_("Unmark"), 1)) | |
1242 | unmark_zone(i); | |
fd6b7a7f KZ |
1243 | continue; |
1244 | } | |
a2bfda30 SK |
1245 | if (zone_in_use(i)) |
1246 | printf(_("Zone %lu: in use, counted=%d\n"), | |
1247 | i, zone_count[i]); | |
e8f26419 | 1248 | else |
a2bfda30 SK |
1249 | printf(_("Zone %lu: not in use, counted=%d\n"), |
1250 | i, zone_count[i]); | |
fd6b7a7f KZ |
1251 | } |
1252 | } | |
fd6b7a7f | 1253 | |
22853e4a KZ |
1254 | static void |
1255 | check(void) { | |
a2bfda30 SK |
1256 | memset(inode_count, 0, (get_ninodes() + 1) * sizeof(*inode_count)); |
1257 | memset(zone_count, 0, get_nzones() * sizeof(*zone_count)); | |
6dbe3af9 KZ |
1258 | check_zones(ROOT_INO); |
1259 | recursive_check(ROOT_INO); | |
1260 | check_counts(); | |
1261 | } | |
1262 | ||
22853e4a | 1263 | static void |
a2bfda30 SK |
1264 | check2(void) { |
1265 | memset(inode_count, 0, (get_ninodes() + 1) * sizeof(*inode_count)); | |
1266 | memset(zone_count, 0, get_nzones() * sizeof(*zone_count)); | |
1267 | check_zones2(ROOT_INO); | |
1268 | recursive_check2(ROOT_INO); | |
1269 | check_counts2(); | |
fd6b7a7f | 1270 | } |
fd6b7a7f | 1271 | |
22853e4a | 1272 | int |
a2bfda30 | 1273 | main(int argc, char **argv) { |
fd6b7a7f | 1274 | struct termios tmp; |
6dbe3af9 | 1275 | int count; |
65ca6f83 | 1276 | int retcode = FSCK_EX_OK; |
158b8d69 SK |
1277 | int i; |
1278 | static const struct option longopts[] = { | |
1279 | {"list", no_argument, NULL, 'l'}, | |
1280 | {"auto", no_argument, NULL, 'a'}, | |
1281 | {"repair", no_argument, NULL, 'r'}, | |
1282 | {"verbose", no_argument, NULL, 'v'}, | |
1283 | {"super", no_argument, NULL, 's'}, | |
1284 | {"uncleared", no_argument, NULL, 'm'}, | |
1285 | {"force", no_argument, NULL, 'f'}, | |
1286 | {"version", no_argument, NULL, 'V'}, | |
1287 | {"help", no_argument, NULL, 'h'}, | |
1288 | {NULL, 0, NULL, 0} | |
1289 | }; | |
6dbe3af9 | 1290 | |
7eda085c KZ |
1291 | setlocale(LC_ALL, ""); |
1292 | bindtextdomain(PACKAGE, LOCALEDIR); | |
1293 | textdomain(PACKAGE); | |
45ca68ec | 1294 | atexit(close_stdout); |
7eda085c | 1295 | |
63883af7 | 1296 | if (INODE_SIZE * MINIX_INODES_PER_BLOCK != MINIX_BLOCK_SIZE) |
eb63b9b8 | 1297 | die(_("bad inode size")); |
63883af7 | 1298 | if (INODE2_SIZE * MINIX2_INODES_PER_BLOCK != MINIX_BLOCK_SIZE) |
eb63b9b8 | 1299 | die(_("bad v2 inode size")); |
c129767e | 1300 | |
158b8d69 SK |
1301 | while ((i = getopt_long(argc, argv, "larvsmfVh", longopts, NULL)) != -1) |
1302 | switch (i) { | |
1303 | case 'l': | |
1304 | list = 1; | |
1305 | break; | |
1306 | case 'a': | |
1307 | automatic = 1; | |
1308 | repair = 1; | |
1309 | break; | |
1310 | case 'r': | |
1311 | automatic = 0; | |
1312 | repair = 1; | |
1313 | break; | |
1314 | case 'v': | |
1315 | verbose = 1; | |
1316 | break; | |
1317 | case 's': | |
1318 | show = 1; | |
1319 | break; | |
1320 | case 'm': | |
1321 | warn_mode = 1; | |
1322 | break; | |
1323 | case 'f': | |
1324 | force = 1; | |
1325 | break; | |
1326 | case 'V': | |
1327 | printf(UTIL_LINUX_VERSION); | |
1328 | return FSCK_EX_OK; | |
1329 | case 'h': | |
1330 | usage(stdout); | |
1331 | default: | |
677ec86c | 1332 | errtryhelp(FSCK_EX_USAGE); |
158b8d69 SK |
1333 | } |
1334 | argc -= optind; | |
1335 | argv += optind; | |
1336 | if (0 < argc) { | |
1337 | device_name = argv[0]; | |
1338 | } else | |
1339 | usage(stderr); | |
1340 | ||
6dbe3af9 | 1341 | check_mount(); /* trying to check a mounted filesystem? */ |
74ce680a SK |
1342 | if (repair && !automatic && (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))) |
1343 | die(_("need terminal for interactive repairs")); | |
1344 | ||
e1df9d4c SK |
1345 | device_fd = open(device_name, repair ? O_RDWR : O_RDONLY); |
1346 | if (device_fd < 0) | |
289dcc90 | 1347 | die(_("cannot open %s: %s"), device_name, strerror(errno)); |
a2bfda30 | 1348 | for (count = 0; count < 3; count++) |
6dbe3af9 | 1349 | sync(); |
fd6b7a7f | 1350 | read_superblock(); |
6dbe3af9 | 1351 | |
a2bfda30 SK |
1352 | /* Determine whether or not we should continue with the checking. This |
1353 | * is based on the status of the filesystem valid and error flags and | |
1354 | * whether or not the -f switch was specified on the command line. */ | |
86a9f3da | 1355 | if (fs_version < 3 && !(Super.s_state & MINIX_ERROR_FS) && |
a2bfda30 | 1356 | (Super.s_state & MINIX_VALID_FS) && !force) { |
6dbe3af9 | 1357 | if (repair) |
7eda085c | 1358 | printf(_("%s is clean, no check.\n"), device_name); |
6dbe3af9 | 1359 | return retcode; |
a2bfda30 | 1360 | } else if (force) |
7eda085c | 1361 | printf(_("Forcing filesystem check on %s.\n"), device_name); |
6dbe3af9 | 1362 | else if (repair) |
a2bfda30 SK |
1363 | printf(_("Filesystem on %s is dirty, needs checking.\n"), |
1364 | device_name); | |
6dbe3af9 | 1365 | |
fd6b7a7f KZ |
1366 | read_tables(); |
1367 | ||
a2bfda30 SK |
1368 | /* Restore the terminal state on fatal signals. We don't do this for |
1369 | * SIGALRM, SIGUSR1 or SIGUSR2. */ | |
54a78201 JY |
1370 | signal(SIGINT, fatalsig); |
1371 | signal(SIGQUIT, fatalsig); | |
1372 | signal(SIGTERM, fatalsig); | |
1373 | ||
fd6b7a7f | 1374 | if (repair && !automatic) { |
65ca6f83 | 1375 | tcgetattr(STDIN_FILENO, &termios); |
fd6b7a7f | 1376 | tmp = termios; |
a2bfda30 | 1377 | tmp.c_lflag &= ~(ICANON | ECHO); |
65ca6f83 | 1378 | tcsetattr(STDIN_FILENO, TCSANOW, &tmp); |
fd6b7a7f KZ |
1379 | termios_set = 1; |
1380 | } | |
1381 | ||
86a9f3da | 1382 | if (fs_version == 2 || fs_version == 3) { |
a2bfda30 SK |
1383 | check_root2(); |
1384 | check2(); | |
c129767e | 1385 | } else { |
fd6b7a7f KZ |
1386 | check_root(); |
1387 | check(); | |
1388 | } | |
6dbe3af9 | 1389 | if (verbose) { |
624e147b | 1390 | unsigned long inode, free; |
6dbe3af9 | 1391 | |
624e147b SK |
1392 | for (inode = 1, free = 0; inode <= get_ninodes(); inode++) |
1393 | if (!inode_in_use(inode)) | |
6dbe3af9 | 1394 | free++; |
a2bfda30 SK |
1395 | printf(_("\n%6ld inodes used (%ld%%)\n"), |
1396 | (get_ninodes() - free), | |
1397 | 100 * (get_ninodes() - free) / get_ninodes()); | |
624e147b SK |
1398 | for (inode = get_first_zone(), free = 0; inode < get_nzones(); inode++) |
1399 | if (!zone_in_use(inode)) | |
6dbe3af9 | 1400 | free++; |
a2bfda30 SK |
1401 | printf(_("%6ld zones used (%ld%%)\n"), (get_nzones() - free), |
1402 | 100 * (get_nzones() - free) / get_nzones()); | |
7eda085c | 1403 | printf(_("\n%6d regular files\n" |
a2bfda30 SK |
1404 | "%6d directories\n" |
1405 | "%6d character device files\n" | |
1406 | "%6d block device files\n" | |
1407 | "%6d links\n" | |
1408 | "%6d symbolic links\n" | |
1409 | "------\n" | |
1410 | "%6d files\n"), | |
1411 | regular, directory, chardev, blockdev, | |
1412 | links - 2 * directory + 1, symlinks, | |
1413 | total - 2 * directory + 1); | |
6dbe3af9 KZ |
1414 | } |
1415 | if (changed) { | |
1416 | write_tables(); | |
a2bfda30 SK |
1417 | printf(_("----------------------------\n" |
1418 | "FILE SYSTEM HAS BEEN CHANGED\n" | |
1419 | "----------------------------\n")); | |
1420 | for (count = 0; count < 3; count++) | |
6dbe3af9 | 1421 | sync(); |
a2bfda30 | 1422 | } else if (repair) |
6dbe3af9 | 1423 | write_super_block(); |
a2bfda30 | 1424 | |
6dbe3af9 | 1425 | if (repair && !automatic) |
65ca6f83 | 1426 | tcsetattr(STDIN_FILENO, TCSANOW, &termios); |
6dbe3af9 | 1427 | |
e1df9d4c | 1428 | if (close_fd(device_fd) != 0) |
564dd4af | 1429 | err(FSCK_EX_ERROR, _("write failed")); |
6dbe3af9 | 1430 | if (changed) |
a2bfda30 | 1431 | retcode += 3; |
6dbe3af9 | 1432 | if (errors_uncorrected) |
a2bfda30 | 1433 | retcode += 4; |
6dbe3af9 KZ |
1434 | return retcode; |
1435 | } |