]>
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__)) |
6e1eda6f RM |
180 | usage(void) { |
181 | FILE *out = stdout; | |
158b8d69 SK |
182 | fputs(USAGE_HEADER, out); |
183 | fprintf(out, _(" %s [options] <device>\n"), program_invocation_short_name); | |
184 | fputs(USAGE_SEPARATOR, out); | |
185 | fputs(_("Check the consistency of a Minix filesystem.\n"), out); | |
186 | fputs(USAGE_OPTIONS, out); | |
187 | fputs(_(" -l, --list list all filenames\n"), out); | |
188 | fputs(_(" -a, --auto automatic repair\n"), out); | |
189 | fputs(_(" -r, --repair interactive repair\n"), out); | |
190 | fputs(_(" -v, --verbose be verbose\n"), out); | |
191 | fputs(_(" -s, --super output super-block information\n"), out); | |
192 | fputs(_(" -m, --uncleared activate mode not cleared warnings\n"), out); | |
193 | fputs(_(" -f, --force force check\n"), out); | |
194 | fputs(USAGE_SEPARATOR, out); | |
f45f3ec3 RM |
195 | printf(USAGE_HELP_OPTIONS(18)); |
196 | printf(USAGE_MAN_TAIL("fsck.minix(8)")); | |
6e1eda6f | 197 | exit(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 | 295 | } |
6dbe3af9 KZ |
296 | } |
297 | ||
65c74885 KZ |
298 | |
299 | static int is_valid_zone_nr(unsigned short nr) | |
300 | { | |
301 | if (nr < get_first_zone()) | |
302 | return 0; | |
042f62df | 303 | if (nr >= get_nzones()) |
65c74885 KZ |
304 | return 0; |
305 | return 1; | |
306 | } | |
307 | ||
a2bfda30 SK |
308 | /* check_zone_nr checks to see that *nr is a valid zone nr. If it isn't, it |
309 | * will possibly be repaired. Check_zone_nr sets *corrected if an error was | |
310 | * corrected, and returns the zone (0 for no zone or a bad zone-number). */ | |
22853e4a | 311 | static int |
a2bfda30 | 312 | check_zone_nr(unsigned short *nr, int *corrected) { |
6dbe3af9 KZ |
313 | if (!*nr) |
314 | return 0; | |
612721db | 315 | |
971b7341 | 316 | if (*nr < get_first_zone()) { |
612721db | 317 | get_current_name(); |
a2bfda30 | 318 | printf(_("Zone nr < FIRSTZONE in file `%s'."), current_name); |
971b7341 | 319 | } else if (*nr >= get_nzones()) { |
612721db | 320 | get_current_name(); |
a2bfda30 | 321 | printf(_("Zone nr >= ZONES in file `%s'."), current_name); |
612721db | 322 | } else |
6dbe3af9 | 323 | return *nr; |
612721db | 324 | |
a2bfda30 | 325 | if (ask(_("Remove block"), 1)) { |
6dbe3af9 KZ |
326 | *nr = 0; |
327 | *corrected = 1; | |
328 | } | |
329 | return 0; | |
330 | } | |
331 | ||
22853e4a | 332 | static int |
a2bfda30 | 333 | check_zone_nr2(unsigned int *nr, int *corrected) { |
fd6b7a7f KZ |
334 | if (!*nr) |
335 | return 0; | |
612721db | 336 | |
971b7341 | 337 | if (*nr < get_first_zone()) { |
612721db | 338 | get_current_name(); |
a2bfda30 | 339 | printf(_("Zone nr < FIRSTZONE in file `%s'."), current_name); |
971b7341 | 340 | } else if (*nr >= get_nzones()) { |
612721db | 341 | get_current_name(); |
a2bfda30 | 342 | printf(_("Zone nr >= ZONES in file `%s'."), current_name); |
612721db | 343 | } else |
fd6b7a7f | 344 | return *nr; |
612721db | 345 | |
a2bfda30 | 346 | if (ask(_("Remove block"), 1)) { |
fd6b7a7f KZ |
347 | *nr = 0; |
348 | *corrected = 1; | |
349 | } | |
350 | return 0; | |
351 | } | |
352 | ||
a2bfda30 | 353 | /* read-block reads block nr into the buffer at addr. */ |
22853e4a | 354 | static void |
a2bfda30 | 355 | read_block(unsigned int nr, char *addr) { |
6dbe3af9 | 356 | if (!nr) { |
a2bfda30 | 357 | memset(addr, 0, MINIX_BLOCK_SIZE); |
6dbe3af9 KZ |
358 | return; |
359 | } | |
e1df9d4c | 360 | if (MINIX_BLOCK_SIZE * nr != lseek(device_fd, MINIX_BLOCK_SIZE * nr, SEEK_SET)) { |
612721db KZ |
361 | get_current_name(); |
362 | printf(_("Read error: unable to seek to block in file '%s'\n"), | |
363 | current_name); | |
a2bfda30 | 364 | memset(addr, 0, MINIX_BLOCK_SIZE); |
6dbe3af9 | 365 | errors_uncorrected = 1; |
e1df9d4c | 366 | } else if (MINIX_BLOCK_SIZE != read(device_fd, addr, MINIX_BLOCK_SIZE)) { |
612721db | 367 | get_current_name(); |
a2bfda30 SK |
368 | printf(_("Read error: bad block in file '%s'\n"), current_name); |
369 | memset(addr, 0, MINIX_BLOCK_SIZE); | |
6dbe3af9 KZ |
370 | errors_uncorrected = 1; |
371 | } | |
372 | } | |
373 | ||
a2bfda30 | 374 | /* write_block writes block nr to disk. */ |
22853e4a | 375 | static void |
a2bfda30 | 376 | write_block(unsigned int nr, char *addr) { |
6dbe3af9 KZ |
377 | if (!nr) |
378 | return; | |
971b7341 | 379 | if (nr < get_first_zone() || nr >= get_nzones()) { |
7eda085c | 380 | printf(_("Internal error: trying to write bad block\n" |
a2bfda30 | 381 | "Write request ignored\n")); |
6dbe3af9 KZ |
382 | errors_uncorrected = 1; |
383 | return; | |
384 | } | |
e1df9d4c | 385 | if (MINIX_BLOCK_SIZE * nr != lseek(device_fd, MINIX_BLOCK_SIZE * nr, SEEK_SET)) |
eb63b9b8 | 386 | die(_("seek failed in write_block")); |
e1df9d4c | 387 | if (MINIX_BLOCK_SIZE != write(device_fd, addr, MINIX_BLOCK_SIZE)) { |
612721db KZ |
388 | get_current_name(); |
389 | printf(_("Write error: bad block in file '%s'\n"), | |
390 | current_name); | |
6dbe3af9 KZ |
391 | errors_uncorrected = 1; |
392 | } | |
393 | } | |
394 | ||
a2bfda30 SK |
395 | /* map-block calculates the absolute block nr of a block in a file. It sets |
396 | * 'changed' if the inode has needed changing, and re-writes any indirect | |
397 | * blocks with errors. */ | |
22853e4a | 398 | static int |
a2bfda30 SK |
399 | map_block(struct minix_inode *inode, unsigned int blknr) { |
400 | unsigned short ind[MINIX_BLOCK_SIZE >> 1]; | |
401 | unsigned short dind[MINIX_BLOCK_SIZE >> 1]; | |
6dbe3af9 | 402 | int blk_chg, block, result; |
51b4b398 | 403 | size_t range; |
6dbe3af9 | 404 | |
a2bfda30 | 405 | if (blknr < 7) |
6dbe3af9 KZ |
406 | return check_zone_nr(inode->i_zone + blknr, &changed); |
407 | blknr -= 7; | |
a2bfda30 | 408 | if (blknr < 512) { |
6dbe3af9 | 409 | block = check_zone_nr(inode->i_zone + 7, &changed); |
a2bfda30 | 410 | read_block(block, (char *)ind); |
6dbe3af9 KZ |
411 | blk_chg = 0; |
412 | result = check_zone_nr(blknr + ind, &blk_chg); | |
413 | if (blk_chg) | |
a2bfda30 | 414 | write_block(block, (char *)ind); |
6dbe3af9 KZ |
415 | return result; |
416 | } | |
417 | blknr -= 512; | |
418 | block = check_zone_nr(inode->i_zone + 8, &changed); | |
a2bfda30 | 419 | read_block(block, (char *)dind); |
6dbe3af9 | 420 | blk_chg = 0; |
51b4b398 SK |
421 | range = blknr / 512; |
422 | if (ARRAY_SIZE(dind) <= range) { | |
423 | printf(_("Warning: block out of range\n")); | |
424 | return 1; | |
425 | } | |
426 | result = check_zone_nr(dind + range, &blk_chg); | |
6dbe3af9 | 427 | if (blk_chg) |
a2bfda30 | 428 | write_block(block, (char *)dind); |
6dbe3af9 | 429 | block = result; |
a2bfda30 | 430 | read_block(block, (char *)ind); |
6dbe3af9 | 431 | blk_chg = 0; |
a2bfda30 | 432 | result = check_zone_nr(ind + (blknr % 512), &blk_chg); |
6dbe3af9 | 433 | if (blk_chg) |
a2bfda30 | 434 | write_block(block, (char *)ind); |
6dbe3af9 KZ |
435 | return result; |
436 | } | |
437 | ||
22853e4a | 438 | static int |
a2bfda30 | 439 | map_block2(struct minix2_inode *inode, unsigned int blknr) { |
63883af7 SK |
440 | unsigned int ind[MINIX_BLOCK_SIZE >> 2]; |
441 | unsigned int dind[MINIX_BLOCK_SIZE >> 2]; | |
442 | unsigned int tind[MINIX_BLOCK_SIZE >> 2]; | |
fd6b7a7f KZ |
443 | int blk_chg, block, result; |
444 | ||
445 | if (blknr < 7) | |
a2bfda30 | 446 | return check_zone_nr2(inode->i_zone + blknr, &changed); |
fd6b7a7f KZ |
447 | blknr -= 7; |
448 | if (blknr < 256) { | |
a2bfda30 SK |
449 | block = check_zone_nr2(inode->i_zone + 7, &changed); |
450 | read_block(block, (char *)ind); | |
fd6b7a7f | 451 | blk_chg = 0; |
a2bfda30 | 452 | result = check_zone_nr2(blknr + ind, &blk_chg); |
fd6b7a7f | 453 | if (blk_chg) |
a2bfda30 | 454 | write_block(block, (char *)ind); |
fd6b7a7f KZ |
455 | return result; |
456 | } | |
457 | blknr -= 256; | |
06c0375c | 458 | if (blknr < 256 * 256) { |
a2bfda30 SK |
459 | block = check_zone_nr2(inode->i_zone + 8, &changed); |
460 | read_block(block, (char *)dind); | |
fd6b7a7f | 461 | blk_chg = 0; |
a2bfda30 | 462 | result = check_zone_nr2(dind + blknr / 256, &blk_chg); |
fd6b7a7f | 463 | if (blk_chg) |
a2bfda30 | 464 | write_block(block, (char *)dind); |
fd6b7a7f | 465 | block = result; |
a2bfda30 | 466 | read_block(block, (char *)ind); |
fd6b7a7f | 467 | blk_chg = 0; |
a2bfda30 | 468 | result = check_zone_nr2(ind + blknr % 256, &blk_chg); |
fd6b7a7f | 469 | if (blk_chg) |
a2bfda30 | 470 | write_block(block, (char *)ind); |
fd6b7a7f KZ |
471 | return result; |
472 | } | |
473 | blknr -= 256 * 256; | |
a2bfda30 SK |
474 | block = check_zone_nr2(inode->i_zone + 9, &changed); |
475 | read_block(block, (char *)tind); | |
fd6b7a7f | 476 | blk_chg = 0; |
a2bfda30 | 477 | result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg); |
fd6b7a7f | 478 | if (blk_chg) |
a2bfda30 | 479 | write_block(block, (char *)tind); |
fd6b7a7f | 480 | block = result; |
a2bfda30 | 481 | read_block(block, (char *)dind); |
fd6b7a7f | 482 | blk_chg = 0; |
a2bfda30 | 483 | result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg); |
fd6b7a7f | 484 | if (blk_chg) |
a2bfda30 | 485 | write_block(block, (char *)dind); |
fd6b7a7f | 486 | block = result; |
a2bfda30 | 487 | read_block(block, (char *)ind); |
fd6b7a7f | 488 | blk_chg = 0; |
a2bfda30 | 489 | result = check_zone_nr2(ind + blknr % 256, &blk_chg); |
fd6b7a7f | 490 | if (blk_chg) |
a2bfda30 | 491 | write_block(block, (char *)ind); |
fd6b7a7f KZ |
492 | return result; |
493 | } | |
fd6b7a7f | 494 | |
22853e4a KZ |
495 | static void |
496 | write_super_block(void) { | |
86a9f3da SK |
497 | /* v3 super block does not track state */ |
498 | if (fs_version == 3) | |
499 | return; | |
a2bfda30 SK |
500 | /* Set the state of the filesystem based on whether or not there are |
501 | * uncorrected errors. The filesystem valid flag is unconditionally | |
502 | * set if we get this far. */ | |
6dbe3af9 | 503 | Super.s_state |= MINIX_VALID_FS; |
a2bfda30 | 504 | if (errors_uncorrected) |
6dbe3af9 KZ |
505 | Super.s_state |= MINIX_ERROR_FS; |
506 | else | |
507 | Super.s_state &= ~MINIX_ERROR_FS; | |
c1d26b19 | 508 | |
e1df9d4c | 509 | if (MINIX_BLOCK_SIZE != lseek(device_fd, MINIX_BLOCK_SIZE, SEEK_SET)) |
eb63b9b8 | 510 | die(_("seek failed in write_super_block")); |
e1df9d4c | 511 | if (MINIX_BLOCK_SIZE != write(device_fd, super_block_buffer, MINIX_BLOCK_SIZE)) |
eb63b9b8 | 512 | die(_("unable to write super-block")); |
6dbe3af9 KZ |
513 | } |
514 | ||
22853e4a KZ |
515 | static void |
516 | write_tables(void) { | |
971b7341 DB |
517 | unsigned long buffsz = get_inode_buffer_size(); |
518 | unsigned long imaps = get_nimaps(); | |
519 | unsigned long zmaps = get_nzmaps(); | |
6dbe3af9 | 520 | |
3acc206d SK |
521 | write_super_block(); |
522 | ||
e1df9d4c | 523 | if (write_all(device_fd, inode_map, imaps * MINIX_BLOCK_SIZE)) |
eb63b9b8 | 524 | die(_("Unable to write inode map")); |
ab1c86fc | 525 | |
e1df9d4c | 526 | if (write_all(device_fd, zone_map, zmaps * MINIX_BLOCK_SIZE)) |
eb63b9b8 | 527 | die(_("Unable to write zone map")); |
ab1c86fc | 528 | |
e1df9d4c | 529 | if (write_all(device_fd, inode_buffer, buffsz)) |
eb63b9b8 | 530 | die(_("Unable to write inodes")); |
6dbe3af9 KZ |
531 | } |
532 | ||
22853e4a | 533 | static void |
a2bfda30 | 534 | get_dirsize(void) { |
fd6b7a7f | 535 | int block; |
63883af7 | 536 | char blk[MINIX_BLOCK_SIZE]; |
ab1c86fc | 537 | size_t size; |
fd6b7a7f | 538 | |
86a9f3da | 539 | if (fs_version == 2 || fs_version == 3) |
fd6b7a7f KZ |
540 | block = Inode2[ROOT_INO].i_zone[0]; |
541 | else | |
fd6b7a7f | 542 | block = Inode[ROOT_INO].i_zone[0]; |
a2bfda30 | 543 | read_block(block, blk); |
ab1c86fc | 544 | |
63883af7 | 545 | for (size = 16; size < MINIX_BLOCK_SIZE; size <<= 1) { |
ab1c86fc | 546 | if (strcmp(blk + size + 2, "..") == 0) { |
fd6b7a7f KZ |
547 | dirsize = size; |
548 | namelen = size - 2; | |
549 | return; | |
550 | } | |
551 | } | |
552 | /* use defaults */ | |
553 | } | |
554 | ||
22853e4a KZ |
555 | static void |
556 | read_superblock(void) { | |
e1df9d4c | 557 | if (MINIX_BLOCK_SIZE != lseek(device_fd, MINIX_BLOCK_SIZE, SEEK_SET)) |
eb63b9b8 | 558 | die(_("seek failed")); |
c326060c | 559 | |
63883af7 | 560 | super_block_buffer = calloc(1, MINIX_BLOCK_SIZE); |
c326060c KZ |
561 | if (!super_block_buffer) |
562 | die(_("unable to alloc buffer for superblock")); | |
563 | ||
e1df9d4c | 564 | if (MINIX_BLOCK_SIZE != read(device_fd, super_block_buffer, MINIX_BLOCK_SIZE)) |
eb63b9b8 | 565 | die(_("unable to read super block")); |
86a9f3da | 566 | if (Super.s_magic == MINIX_SUPER_MAGIC) { |
6dbe3af9 KZ |
567 | namelen = 14; |
568 | dirsize = 16; | |
971b7341 | 569 | fs_version = 1; |
86a9f3da | 570 | } else if (Super.s_magic == MINIX_SUPER_MAGIC2) { |
6dbe3af9 KZ |
571 | namelen = 30; |
572 | dirsize = 32; | |
971b7341 | 573 | fs_version = 1; |
86a9f3da | 574 | } else if (Super.s_magic == MINIX2_SUPER_MAGIC) { |
fd6b7a7f KZ |
575 | namelen = 14; |
576 | dirsize = 16; | |
971b7341 | 577 | fs_version = 2; |
86a9f3da | 578 | } else if (Super.s_magic == MINIX2_SUPER_MAGIC2) { |
fd6b7a7f KZ |
579 | namelen = 30; |
580 | dirsize = 32; | |
971b7341 | 581 | fs_version = 2; |
86a9f3da SK |
582 | } else if (Super3.s_magic == MINIX3_SUPER_MAGIC) { |
583 | namelen = 60; | |
584 | dirsize = 64; | |
585 | fs_version = 3; | |
6dbe3af9 | 586 | } else |
eb63b9b8 | 587 | die(_("bad magic number in super-block")); |
63883af7 | 588 | if (get_zone_size() != 0 || MINIX_BLOCK_SIZE != 1024) |
eb63b9b8 | 589 | die(_("Only 1k blocks/zones supported")); |
8f35b3a9 TS |
590 | if (get_ninodes() == 0 || get_ninodes() == UINT32_MAX) |
591 | die(_("bad s_ninodes field in super-block")); | |
63883af7 | 592 | if (get_nimaps() * MINIX_BLOCK_SIZE * 8 < get_ninodes() + 1) |
eb63b9b8 | 593 | die(_("bad s_imap_blocks field in super-block")); |
8f35b3a9 TS |
594 | if (get_first_zone() > (off_t) get_nzones()) |
595 | die(_("bad s_firstdatazone field in super-block")); | |
a2bfda30 SK |
596 | if (get_nzmaps() * MINIX_BLOCK_SIZE * 8 < |
597 | get_nzones() - get_first_zone() + 1) | |
eb63b9b8 | 598 | die(_("bad s_zmap_blocks field in super-block")); |
fd6b7a7f KZ |
599 | } |
600 | ||
22853e4a KZ |
601 | static void |
602 | read_tables(void) { | |
971b7341 | 603 | unsigned long inodes = get_ninodes(); |
a180dc6c SK |
604 | size_t buffsz = get_inode_buffer_size(); |
605 | off_t norm_first_zone = first_zone_data(); | |
606 | off_t first_zone = get_first_zone(); | |
971b7341 DB |
607 | unsigned long zones = get_nzones(); |
608 | unsigned long imaps = get_nimaps(); | |
609 | unsigned long zmaps = get_nzmaps(); | |
ab1c86fc | 610 | ssize_t rc; |
971b7341 | 611 | |
63883af7 | 612 | inode_map = malloc(imaps * MINIX_BLOCK_SIZE); |
2b6fc908 | 613 | if (!inode_map) |
eb63b9b8 | 614 | die(_("Unable to allocate buffer for inode map")); |
63883af7 | 615 | zone_map = malloc(zmaps * MINIX_BLOCK_SIZE); |
f8209a0f | 616 | if (!zone_map) |
65b27d36 | 617 | die(_("Unable to allocate buffer for zone map")); |
971b7341 | 618 | inode_buffer = malloc(buffsz); |
6dbe3af9 | 619 | if (!inode_buffer) |
eb63b9b8 | 620 | die(_("Unable to allocate buffer for inodes")); |
d73af2ac | 621 | inode_count = calloc(1, inodes + 1); |
6dbe3af9 | 622 | if (!inode_count) |
eb63b9b8 | 623 | die(_("Unable to allocate buffer for inode count")); |
d73af2ac | 624 | zone_count = calloc(1, zones); |
6dbe3af9 | 625 | if (!zone_count) |
eb63b9b8 | 626 | die(_("Unable to allocate buffer for zone count")); |
ab1c86fc | 627 | |
e1df9d4c | 628 | rc = read(device_fd, inode_map, imaps * MINIX_BLOCK_SIZE); |
ab1c86fc | 629 | if (rc < 0 || imaps * MINIX_BLOCK_SIZE != (size_t) rc) |
eb63b9b8 | 630 | die(_("Unable to read inode map")); |
ab1c86fc | 631 | |
e1df9d4c | 632 | rc = read(device_fd, zone_map, zmaps * MINIX_BLOCK_SIZE); |
ab1c86fc | 633 | if (rc < 0 || zmaps * MINIX_BLOCK_SIZE != (size_t) rc) |
eb63b9b8 | 634 | die(_("Unable to read zone map")); |
ab1c86fc | 635 | |
e1df9d4c | 636 | rc = read(device_fd, inode_buffer, buffsz); |
ab1c86fc | 637 | if (rc < 0 || buffsz != (size_t) rc) |
eb63b9b8 | 638 | die(_("Unable to read inodes")); |
971b7341 | 639 | if (norm_first_zone != first_zone) { |
7eda085c | 640 | printf(_("Warning: Firstzone != Norm_firstzone\n")); |
6dbe3af9 KZ |
641 | errors_uncorrected = 1; |
642 | } | |
a2bfda30 | 643 | get_dirsize(); |
6dbe3af9 | 644 | if (show) { |
971b7341 DB |
645 | printf(_("%ld inodes\n"), inodes); |
646 | printf(_("%ld blocks\n"), zones); | |
fdbd7bb9 RM |
647 | printf(_("Firstdatazone=%jd (%jd)\n"), |
648 | (intmax_t)first_zone, (intmax_t)norm_first_zone); | |
a2bfda30 | 649 | printf(_("Zonesize=%d\n"), MINIX_BLOCK_SIZE << get_zone_size()); |
248b8101 | 650 | printf(_("Maxsize=%zu\n"), get_max_size()); |
86a9f3da SK |
651 | if (fs_version < 3) |
652 | printf(_("Filesystem state=%d\n"), Super.s_state); | |
a2bfda30 | 653 | printf(_("namelen=%zd\n\n"), namelen); |
6dbe3af9 KZ |
654 | } |
655 | } | |
656 | ||
22853e4a KZ |
657 | static struct minix_inode * |
658 | get_inode(unsigned int nr) { | |
a2bfda30 | 659 | struct minix_inode *inode; |
6dbe3af9 | 660 | |
971b7341 | 661 | if (!nr || nr > get_ninodes()) |
6dbe3af9 KZ |
662 | return NULL; |
663 | total++; | |
664 | inode = Inode + nr; | |
665 | if (!inode_count[nr]) { | |
666 | if (!inode_in_use(nr)) { | |
612721db KZ |
667 | get_current_name(); |
668 | printf(_("Inode %d marked unused, " | |
a2bfda30 | 669 | "but used for file '%s'\n"), nr, current_name); |
5c36a0eb | 670 | if (repair) { |
a2bfda30 | 671 | if (ask(_("Mark in use"), 1)) |
6dbe3af9 | 672 | mark_inode(nr); |
5c36a0eb | 673 | } else { |
a2bfda30 | 674 | errors_uncorrected = 1; |
5c36a0eb | 675 | } |
6dbe3af9 KZ |
676 | } |
677 | if (S_ISDIR(inode->i_mode)) | |
678 | directory++; | |
679 | else if (S_ISREG(inode->i_mode)) | |
680 | regular++; | |
681 | else if (S_ISCHR(inode->i_mode)) | |
682 | chardev++; | |
683 | else if (S_ISBLK(inode->i_mode)) | |
684 | blockdev++; | |
685 | else if (S_ISLNK(inode->i_mode)) | |
686 | symlinks++; | |
687 | else if (S_ISSOCK(inode->i_mode)) | |
688 | ; | |
689 | else if (S_ISFIFO(inode->i_mode)) | |
690 | ; | |
691 | else { | |
a2bfda30 SK |
692 | get_current_name(); |
693 | printf(_("The file `%s' has mode %05o\n"), | |
612721db | 694 | current_name, inode->i_mode); |
a2bfda30 | 695 | } |
6dbe3af9 KZ |
696 | |
697 | } else | |
698 | links++; | |
699 | if (!++inode_count[nr]) { | |
7eda085c | 700 | printf(_("Warning: inode count too big.\n")); |
6dbe3af9 KZ |
701 | inode_count[nr]--; |
702 | errors_uncorrected = 1; | |
703 | } | |
704 | return inode; | |
705 | } | |
706 | ||
22853e4a | 707 | static struct minix2_inode * |
a2bfda30 | 708 | get_inode2(unsigned int nr) { |
fd6b7a7f KZ |
709 | struct minix2_inode *inode; |
710 | ||
971b7341 | 711 | if (!nr || nr > get_ninodes()) |
fd6b7a7f KZ |
712 | return NULL; |
713 | total++; | |
714 | inode = Inode2 + nr; | |
715 | if (!inode_count[nr]) { | |
a2bfda30 | 716 | if (!inode_in_use(nr)) { |
612721db | 717 | get_current_name(); |
a2bfda30 SK |
718 | printf(_("Inode %d marked unused, " |
719 | "but used for file '%s'\n"), nr, current_name); | |
fd6b7a7f | 720 | if (repair) { |
a2bfda30 SK |
721 | if (ask(_("Mark in use"), 1)) |
722 | mark_inode(nr); | |
fd6b7a7f KZ |
723 | else |
724 | errors_uncorrected = 1; | |
725 | } | |
726 | } | |
a2bfda30 | 727 | if (S_ISDIR(inode->i_mode)) |
fd6b7a7f | 728 | directory++; |
a2bfda30 | 729 | else if (S_ISREG(inode->i_mode)) |
fd6b7a7f | 730 | regular++; |
a2bfda30 | 731 | else if (S_ISCHR(inode->i_mode)) |
fd6b7a7f | 732 | chardev++; |
a2bfda30 | 733 | else if (S_ISBLK(inode->i_mode)) |
fd6b7a7f | 734 | blockdev++; |
a2bfda30 | 735 | else if (S_ISLNK(inode->i_mode)) |
fd6b7a7f | 736 | symlinks++; |
a2bfda30 SK |
737 | else if (S_ISSOCK(inode->i_mode)) ; |
738 | else if (S_ISFIFO(inode->i_mode)) ; | |
fd6b7a7f | 739 | else { |
a2bfda30 SK |
740 | get_current_name(); |
741 | printf(_("The file `%s' has mode %05o\n"), | |
742 | current_name, inode->i_mode); | |
fd6b7a7f KZ |
743 | } |
744 | } else | |
745 | links++; | |
746 | if (!++inode_count[nr]) { | |
a2bfda30 | 747 | printf(_("Warning: inode count too big.\n")); |
fd6b7a7f KZ |
748 | inode_count[nr]--; |
749 | errors_uncorrected = 1; | |
750 | } | |
751 | return inode; | |
752 | } | |
fd6b7a7f | 753 | |
22853e4a KZ |
754 | static void |
755 | check_root(void) { | |
a2bfda30 | 756 | struct minix_inode *inode = Inode + ROOT_INO; |
6dbe3af9 KZ |
757 | |
758 | if (!inode || !S_ISDIR(inode->i_mode)) | |
eb63b9b8 | 759 | die(_("root inode isn't a directory")); |
6dbe3af9 KZ |
760 | } |
761 | ||
22853e4a | 762 | static void |
a2bfda30 | 763 | check_root2(void) { |
fd6b7a7f KZ |
764 | struct minix2_inode *inode = Inode2 + ROOT_INO; |
765 | ||
a2bfda30 | 766 | if (!inode || !S_ISDIR(inode->i_mode)) |
65b27d36 | 767 | die(_("root inode isn't a directory")); |
fd6b7a7f | 768 | } |
fd6b7a7f | 769 | |
22853e4a | 770 | static int |
a2bfda30 | 771 | add_zone(unsigned short *znr, int *corrected) { |
6dbe3af9 KZ |
772 | int block; |
773 | ||
6dbe3af9 KZ |
774 | block = check_zone_nr(znr, corrected); |
775 | if (!block) | |
776 | return 0; | |
777 | if (zone_count[block]) { | |
612721db KZ |
778 | get_current_name(); |
779 | printf(_("Block has been used before. Now in file `%s'."), | |
780 | current_name); | |
a2bfda30 | 781 | if (ask(_("Clear"), 1)) { |
6dbe3af9 KZ |
782 | *znr = 0; |
783 | block = 0; | |
784 | *corrected = 1; | |
785 | } | |
786 | } | |
787 | if (!block) | |
788 | return 0; | |
789 | if (!zone_in_use(block)) { | |
612721db KZ |
790 | get_current_name(); |
791 | printf(_("Block %d in file `%s' is marked not in use."), | |
792 | block, current_name); | |
a2bfda30 | 793 | if (ask(_("Correct"), 1)) |
6dbe3af9 KZ |
794 | mark_zone(block); |
795 | } | |
796 | if (!++zone_count[block]) | |
797 | zone_count[block]--; | |
798 | return block; | |
799 | } | |
800 | ||
22853e4a | 801 | static int |
a2bfda30 | 802 | add_zone2(unsigned int *znr, int *corrected) { |
fd6b7a7f KZ |
803 | int block; |
804 | ||
a2bfda30 | 805 | block = check_zone_nr2(znr, corrected); |
fd6b7a7f KZ |
806 | if (!block) |
807 | return 0; | |
808 | if (zone_count[block]) { | |
612721db | 809 | get_current_name(); |
a2bfda30 SK |
810 | printf(_("Block has been used before. Now in file `%s'."), |
811 | current_name); | |
812 | if (ask(_("Clear"), 1)) { | |
fd6b7a7f KZ |
813 | *znr = 0; |
814 | block = 0; | |
815 | *corrected = 1; | |
816 | } | |
817 | } | |
818 | if (!block) | |
819 | return 0; | |
a2bfda30 | 820 | if (!zone_in_use(block)) { |
612721db | 821 | get_current_name(); |
a2bfda30 SK |
822 | printf(_("Block %d in file `%s' is marked not in use."), |
823 | block, current_name); | |
824 | if (ask(_("Correct"), 1)) | |
825 | mark_zone(block); | |
fd6b7a7f KZ |
826 | } |
827 | if (!++zone_count[block]) | |
828 | zone_count[block]--; | |
829 | return block; | |
830 | } | |
831 | ||
22853e4a | 832 | static void |
a2bfda30 | 833 | add_zone_ind(unsigned short *znr, int *corrected) { |
63883af7 | 834 | static char blk[MINIX_BLOCK_SIZE]; |
a2bfda30 | 835 | int i, chg_blk = 0; |
6dbe3af9 KZ |
836 | int block; |
837 | ||
838 | block = add_zone(znr, corrected); | |
839 | if (!block) | |
840 | return; | |
841 | read_block(block, blk); | |
a2bfda30 SK |
842 | for (i = 0; i < (MINIX_BLOCK_SIZE >> 1); i++) |
843 | add_zone(i + (unsigned short *)blk, &chg_blk); | |
6dbe3af9 KZ |
844 | if (chg_blk) |
845 | write_block(block, blk); | |
846 | } | |
847 | ||
5c36a0eb | 848 | static void |
a2bfda30 | 849 | add_zone_ind2(unsigned int *znr, int *corrected) { |
63883af7 | 850 | static char blk[MINIX_BLOCK_SIZE]; |
fd6b7a7f KZ |
851 | int i, chg_blk = 0; |
852 | int block; | |
853 | ||
a2bfda30 | 854 | block = add_zone2(znr, corrected); |
fd6b7a7f KZ |
855 | if (!block) |
856 | return; | |
a2bfda30 | 857 | read_block(block, blk); |
63883af7 | 858 | for (i = 0; i < MINIX_BLOCK_SIZE >> 2; i++) |
a2bfda30 | 859 | add_zone2(i + (unsigned int *)blk, &chg_blk); |
fd6b7a7f | 860 | if (chg_blk) |
a2bfda30 | 861 | write_block(block, blk); |
fd6b7a7f KZ |
862 | } |
863 | ||
22853e4a | 864 | static void |
a2bfda30 | 865 | add_zone_dind(unsigned short *znr, int *corrected) { |
63883af7 | 866 | static char blk[MINIX_BLOCK_SIZE]; |
a2bfda30 | 867 | int i, blk_chg = 0; |
6dbe3af9 KZ |
868 | int block; |
869 | ||
870 | block = add_zone(znr, corrected); | |
871 | if (!block) | |
872 | return; | |
873 | read_block(block, blk); | |
a2bfda30 SK |
874 | for (i = 0; i < (MINIX_BLOCK_SIZE >> 1); i++) |
875 | add_zone_ind(i + (unsigned short *)blk, &blk_chg); | |
6dbe3af9 KZ |
876 | if (blk_chg) |
877 | write_block(block, blk); | |
878 | } | |
879 | ||
fd6b7a7f | 880 | static void |
a2bfda30 | 881 | add_zone_dind2(unsigned int *znr, int *corrected) { |
63883af7 | 882 | static char blk[MINIX_BLOCK_SIZE]; |
fd6b7a7f KZ |
883 | int i, blk_chg = 0; |
884 | int block; | |
885 | ||
a2bfda30 | 886 | block = add_zone2(znr, corrected); |
fd6b7a7f KZ |
887 | if (!block) |
888 | return; | |
a2bfda30 | 889 | read_block(block, blk); |
63883af7 | 890 | for (i = 0; i < MINIX_BLOCK_SIZE >> 2; i++) |
a2bfda30 | 891 | add_zone_ind2(i + (unsigned int *)blk, &blk_chg); |
fd6b7a7f | 892 | if (blk_chg) |
a2bfda30 | 893 | write_block(block, blk); |
fd6b7a7f KZ |
894 | } |
895 | ||
896 | static void | |
a2bfda30 | 897 | add_zone_tind2(unsigned int *znr, int *corrected) { |
63883af7 | 898 | static char blk[MINIX_BLOCK_SIZE]; |
fd6b7a7f KZ |
899 | int i, blk_chg = 0; |
900 | int block; | |
901 | ||
a2bfda30 | 902 | block = add_zone2(znr, corrected); |
fd6b7a7f KZ |
903 | if (!block) |
904 | return; | |
a2bfda30 | 905 | read_block(block, blk); |
63883af7 | 906 | for (i = 0; i < MINIX_BLOCK_SIZE >> 2; i++) |
a2bfda30 | 907 | add_zone_dind2(i + (unsigned int *)blk, &blk_chg); |
fd6b7a7f | 908 | if (blk_chg) |
a2bfda30 | 909 | write_block(block, blk); |
fd6b7a7f KZ |
910 | } |
911 | ||
22853e4a KZ |
912 | static void |
913 | check_zones(unsigned int i) { | |
971b7341 | 914 | struct minix_inode *inode; |
6dbe3af9 | 915 | |
971b7341 | 916 | if (!i || i > get_ninodes()) |
6dbe3af9 KZ |
917 | return; |
918 | if (inode_count[i] > 1) /* have we counted this file already? */ | |
919 | return; | |
920 | inode = Inode + i; | |
921 | if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && | |
922 | !S_ISLNK(inode->i_mode)) | |
923 | return; | |
a2bfda30 | 924 | for (i = 0; i < 7; i++) |
6dbe3af9 KZ |
925 | add_zone(i + inode->i_zone, &changed); |
926 | add_zone_ind(7 + inode->i_zone, &changed); | |
927 | add_zone_dind(8 + inode->i_zone, &changed); | |
928 | } | |
929 | ||
22853e4a | 930 | static void |
a2bfda30 | 931 | check_zones2(unsigned int i) { |
fd6b7a7f KZ |
932 | struct minix2_inode *inode; |
933 | ||
971b7341 | 934 | if (!i || i > get_ninodes()) |
fd6b7a7f KZ |
935 | return; |
936 | if (inode_count[i] > 1) /* have we counted this file already? */ | |
937 | return; | |
938 | inode = Inode2 + i; | |
a2bfda30 SK |
939 | if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) |
940 | && !S_ISLNK(inode->i_mode)) | |
fd6b7a7f KZ |
941 | return; |
942 | for (i = 0; i < 7; i++) | |
a2bfda30 SK |
943 | add_zone2(i + inode->i_zone, &changed); |
944 | add_zone_ind2(7 + inode->i_zone, &changed); | |
945 | add_zone_dind2(8 + inode->i_zone, &changed); | |
946 | add_zone_tind2(9 + inode->i_zone, &changed); | |
fd6b7a7f | 947 | } |
fd6b7a7f | 948 | |
22853e4a | 949 | static void |
a2bfda30 | 950 | check_file(struct minix_inode *dir, unsigned int offset) { |
1e9d849b | 951 | static char blk[MINIX_BLOCK_SIZE + 2]; |
a2bfda30 | 952 | struct minix_inode *inode; |
ab1c86fc | 953 | unsigned int ino; |
a2bfda30 | 954 | char *name; |
6dbe3af9 KZ |
955 | int block; |
956 | ||
a2bfda30 | 957 | block = map_block(dir, offset / MINIX_BLOCK_SIZE); |
6dbe3af9 | 958 | read_block(block, blk); |
63883af7 | 959 | name = blk + (offset % MINIX_BLOCK_SIZE) + 2; |
a2bfda30 | 960 | ino = *(unsigned short *)(name - 2); |
971b7341 | 961 | if (ino > get_ninodes()) { |
612721db KZ |
962 | get_current_name(); |
963 | printf(_("The directory '%s' contains a bad inode number " | |
a2bfda30 SK |
964 | "for file '%.*s'."), current_name, (int)namelen, name); |
965 | if (ask(_(" Remove"), 1)) { | |
966 | *(unsigned short *)(name - 2) = 0; | |
6dbe3af9 KZ |
967 | write_block(block, blk); |
968 | } | |
969 | ino = 0; | |
a2bfda30 | 970 | } |
fd6b7a7f | 971 | if (name_depth < MAX_DEPTH) |
730ae9c8 SK |
972 | xstrncpy(name_list[name_depth], name, namelen); |
973 | else | |
974 | return; | |
fd6b7a7f | 975 | name_depth++; |
6dbe3af9 | 976 | inode = get_inode(ino); |
fd6b7a7f | 977 | name_depth--; |
5c36a0eb | 978 | if (!offset) { |
ad296391 | 979 | if (!inode || strcmp(".", name) != 0) { |
612721db | 980 | get_current_name(); |
65b27d36 | 981 | printf(_("%s: bad directory: '.' isn't first\n"), |
612721db | 982 | current_name); |
6dbe3af9 | 983 | errors_uncorrected = 1; |
a2bfda30 SK |
984 | } else |
985 | return; | |
5c36a0eb KZ |
986 | } |
987 | if (offset == dirsize) { | |
ad296391 | 988 | if (!inode || strcmp("..", name) != 0) { |
612721db | 989 | get_current_name(); |
65b27d36 | 990 | printf(_("%s: bad directory: '..' isn't second\n"), |
612721db | 991 | current_name); |
6dbe3af9 | 992 | errors_uncorrected = 1; |
a2bfda30 SK |
993 | } else |
994 | return; | |
5c36a0eb | 995 | } |
6dbe3af9 KZ |
996 | if (!inode) |
997 | return; | |
998 | if (name_depth < MAX_DEPTH) | |
730ae9c8 SK |
999 | xstrncpy(name_list[name_depth], name, namelen); |
1000 | else | |
1001 | return; | |
a2bfda30 | 1002 | name_depth++; |
6dbe3af9 KZ |
1003 | if (list) { |
1004 | if (verbose) | |
364cda48 KZ |
1005 | printf("%6d %07o %3d ", ino, |
1006 | inode->i_mode, inode->i_nlinks); | |
612721db KZ |
1007 | get_current_name(); |
1008 | printf("%s", current_name); | |
6dbe3af9 KZ |
1009 | if (S_ISDIR(inode->i_mode)) |
1010 | printf(":\n"); | |
1011 | else | |
1012 | printf("\n"); | |
1013 | } | |
1014 | check_zones(ino); | |
1015 | if (inode && S_ISDIR(inode->i_mode)) | |
1016 | recursive_check(ino); | |
1017 | name_depth--; | |
6dbe3af9 KZ |
1018 | } |
1019 | ||
22853e4a | 1020 | static void |
a2bfda30 | 1021 | check_file2(struct minix2_inode *dir, unsigned int offset) { |
1e9d849b | 1022 | static char blk[MINIX_BLOCK_SIZE + 4]; |
fd6b7a7f | 1023 | struct minix2_inode *inode; |
a180dc6c | 1024 | ino_t ino; |
fd6b7a7f KZ |
1025 | char *name; |
1026 | int block; | |
86a9f3da | 1027 | const int version_offset = fs_version == 3 ? 4 : 2; |
fd6b7a7f | 1028 | |
a2bfda30 SK |
1029 | block = map_block2(dir, offset / MINIX_BLOCK_SIZE); |
1030 | read_block(block, blk); | |
86a9f3da | 1031 | name = blk + (offset % MINIX_BLOCK_SIZE) + version_offset; |
fcb12426 RM |
1032 | ino = version_offset == 4 ? *(uint32_t *)(name - version_offset) |
1033 | : *(uint16_t *)(name - version_offset); | |
971b7341 | 1034 | if (ino > get_ninodes()) { |
612721db KZ |
1035 | get_current_name(); |
1036 | printf(_("The directory '%s' contains a bad inode number " | |
a2bfda30 SK |
1037 | "for file '%.*s'."), current_name, (int)namelen, name); |
1038 | if (ask(_(" Remove"), 1)) { | |
fcb12426 | 1039 | memset(name - version_offset, 0, version_offset); |
a2bfda30 | 1040 | write_block(block, blk); |
fd6b7a7f KZ |
1041 | } |
1042 | ino = 0; | |
1043 | } | |
1044 | if (name_depth < MAX_DEPTH) | |
730ae9c8 SK |
1045 | xstrncpy(name_list[name_depth], name, namelen); |
1046 | else | |
1047 | return; | |
fd6b7a7f | 1048 | name_depth++; |
a2bfda30 | 1049 | inode = get_inode2(ino); |
fd6b7a7f KZ |
1050 | name_depth--; |
1051 | if (!offset) { | |
ad296391 | 1052 | if (!inode || strcmp(".", name) != 0) { |
a2bfda30 SK |
1053 | get_current_name(); |
1054 | printf(_("%s: bad directory: '.' isn't first\n"), | |
1055 | current_name); | |
fd6b7a7f KZ |
1056 | errors_uncorrected = 1; |
1057 | } else | |
1058 | return; | |
1059 | } | |
1060 | if (offset == dirsize) { | |
ad296391 | 1061 | if (!inode || strcmp("..", name) != 0) { |
a2bfda30 SK |
1062 | get_current_name(); |
1063 | printf(_("%s: bad directory: '..' isn't second\n"), | |
1064 | current_name); | |
fd6b7a7f KZ |
1065 | errors_uncorrected = 1; |
1066 | } else | |
1067 | return; | |
1068 | } | |
1069 | if (!inode) | |
1070 | return; | |
1071 | name_depth++; | |
1072 | if (list) { | |
1073 | if (verbose) | |
fdbd7bb9 | 1074 | printf("%6ju %07o %3d ", (uintmax_t)ino, inode->i_mode, |
a2bfda30 SK |
1075 | inode->i_nlinks); |
1076 | get_current_name(); | |
612721db | 1077 | printf("%s", current_name); |
a2bfda30 SK |
1078 | if (S_ISDIR(inode->i_mode)) |
1079 | printf(":\n"); | |
fd6b7a7f | 1080 | else |
a2bfda30 | 1081 | printf("\n"); |
fd6b7a7f | 1082 | } |
a2bfda30 SK |
1083 | check_zones2(ino); |
1084 | if (inode && S_ISDIR(inode->i_mode)) | |
1085 | recursive_check2(ino); | |
fd6b7a7f | 1086 | name_depth--; |
fd6b7a7f | 1087 | } |
fd6b7a7f | 1088 | |
22853e4a KZ |
1089 | static void |
1090 | recursive_check(unsigned int ino) { | |
a2bfda30 | 1091 | struct minix_inode *dir; |
a180dc6c | 1092 | off_t offset; |
6dbe3af9 KZ |
1093 | |
1094 | dir = Inode + ino; | |
1095 | if (!S_ISDIR(dir->i_mode)) | |
eb63b9b8 | 1096 | die(_("internal error")); |
fd6b7a7f | 1097 | if (dir->i_size < 2 * dirsize) { |
612721db | 1098 | get_current_name(); |
a2bfda30 | 1099 | printf(_("%s: bad directory: size < 32"), current_name); |
6dbe3af9 KZ |
1100 | errors_uncorrected = 1; |
1101 | } | |
65c74885 KZ |
1102 | |
1103 | if ((!repair || automatic) && !is_valid_zone_nr(*dir->i_zone)) { | |
1104 | get_current_name(); | |
1105 | printf(_("%s: bad directory: invalid i_zone, use --repair to fix\n"), current_name); | |
1106 | return; | |
1107 | } | |
a2bfda30 SK |
1108 | for (offset = 0; offset < dir->i_size; offset += dirsize) |
1109 | check_file(dir, offset); | |
6dbe3af9 KZ |
1110 | } |
1111 | ||
22853e4a | 1112 | static void |
a2bfda30 | 1113 | recursive_check2(unsigned int ino) { |
fd6b7a7f | 1114 | struct minix2_inode *dir; |
a180dc6c | 1115 | off_t offset; |
fd6b7a7f KZ |
1116 | |
1117 | dir = Inode2 + ino; | |
a2bfda30 | 1118 | if (!S_ISDIR(dir->i_mode)) |
65b27d36 | 1119 | die(_("internal error")); |
fd6b7a7f | 1120 | if (dir->i_size < 2 * dirsize) { |
a2bfda30 SK |
1121 | get_current_name(); |
1122 | printf(_("%s: bad directory: size < 32"), current_name); | |
fd6b7a7f KZ |
1123 | errors_uncorrected = 1; |
1124 | } | |
1125 | for (offset = 0; offset < dir->i_size; offset += dirsize) | |
a2bfda30 | 1126 | check_file2(dir, offset); |
fd6b7a7f | 1127 | } |
fd6b7a7f | 1128 | |
22853e4a KZ |
1129 | static int |
1130 | bad_zone(int i) { | |
6dbe3af9 KZ |
1131 | char buffer[1024]; |
1132 | ||
e1df9d4c | 1133 | if (MINIX_BLOCK_SIZE * i != lseek(device_fd, MINIX_BLOCK_SIZE * i, SEEK_SET)) |
eb63b9b8 | 1134 | die(_("seek failed in bad_zone")); |
e1df9d4c | 1135 | return (MINIX_BLOCK_SIZE != read(device_fd, buffer, MINIX_BLOCK_SIZE)); |
6dbe3af9 KZ |
1136 | } |
1137 | ||
22853e4a KZ |
1138 | static void |
1139 | check_counts(void) { | |
ab1c86fc | 1140 | unsigned long i; |
6dbe3af9 | 1141 | |
a2bfda30 | 1142 | for (i = 1; i <= get_ninodes(); i++) { |
6dbe3af9 | 1143 | if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { |
ab1c86fc | 1144 | printf(_("Inode %lu mode not cleared."), i); |
a2bfda30 | 1145 | if (ask(_("Clear"), 1)) { |
6dbe3af9 KZ |
1146 | Inode[i].i_mode = 0; |
1147 | changed = 1; | |
1148 | } | |
1149 | } | |
1150 | if (!inode_count[i]) { | |
1151 | if (!inode_in_use(i)) | |
1152 | continue; | |
a2bfda30 SK |
1153 | printf(_("Inode %lu not used, marked used in the bitmap."), i); |
1154 | if (ask(_("Clear"), 1)) | |
6dbe3af9 KZ |
1155 | unmark_inode(i); |
1156 | continue; | |
1157 | } | |
1158 | if (!inode_in_use(i)) { | |
a2bfda30 SK |
1159 | printf(_("Inode %lu used, marked unused in the bitmap."), i); |
1160 | if (ask(_("Set"), 1)) | |
6dbe3af9 KZ |
1161 | mark_inode(i); |
1162 | } | |
1163 | if (Inode[i].i_nlinks != inode_count[i]) { | |
ab1c86fc | 1164 | printf(_("Inode %lu (mode = %07o), i_nlinks=%d, counted=%d."), |
a2bfda30 SK |
1165 | i, Inode[i].i_mode, Inode[i].i_nlinks, |
1166 | inode_count[i]); | |
1167 | if (ask(_("Set i_nlinks to count"), 1)) { | |
1168 | Inode[i].i_nlinks = inode_count[i]; | |
1169 | changed = 1; | |
6dbe3af9 KZ |
1170 | } |
1171 | } | |
1172 | } | |
a2bfda30 | 1173 | for (i = get_first_zone(); i < get_nzones(); i++) { |
6dbe3af9 KZ |
1174 | if (zone_in_use(i) == zone_count[i]) |
1175 | continue; | |
1176 | if (!zone_count[i]) { | |
1177 | if (bad_zone(i)) | |
1178 | continue; | |
a2bfda30 SK |
1179 | printf(_("Zone %lu: marked in use, no file uses it."), |
1180 | i); | |
1181 | if (ask(_("Unmark"), 1)) | |
6dbe3af9 KZ |
1182 | unmark_zone(i); |
1183 | continue; | |
1184 | } | |
e8f26419 | 1185 | if (zone_in_use(i)) |
ab1c86fc | 1186 | printf(_("Zone %lu: in use, counted=%d\n"), |
e8f26419 KZ |
1187 | i, zone_count[i]); |
1188 | else | |
ab1c86fc | 1189 | printf(_("Zone %lu: not in use, counted=%d\n"), |
e8f26419 | 1190 | i, zone_count[i]); |
6dbe3af9 KZ |
1191 | } |
1192 | } | |
1193 | ||
22853e4a | 1194 | static void |
a2bfda30 | 1195 | check_counts2(void) { |
ab1c86fc | 1196 | unsigned long i; |
fd6b7a7f | 1197 | |
971b7341 | 1198 | for (i = 1; i <= get_ninodes(); i++) { |
a2bfda30 SK |
1199 | if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) { |
1200 | printf(_("Inode %lu mode not cleared."), i); | |
1201 | if (ask(_("Clear"), 1)) { | |
fd6b7a7f KZ |
1202 | Inode2[i].i_mode = 0; |
1203 | changed = 1; | |
1204 | } | |
1205 | } | |
1206 | if (!inode_count[i]) { | |
a2bfda30 | 1207 | if (!inode_in_use(i)) |
fd6b7a7f | 1208 | continue; |
a2bfda30 SK |
1209 | printf(_("Inode %lu not used, marked used in the bitmap."), i); |
1210 | if (ask(_("Clear"), 1)) | |
1211 | unmark_inode(i); | |
fd6b7a7f KZ |
1212 | continue; |
1213 | } | |
a2bfda30 SK |
1214 | if (!inode_in_use(i)) { |
1215 | printf(_("Inode %lu used, marked unused in the bitmap."), i); | |
1216 | if (ask(_("Set"), 1)) | |
1217 | mark_inode(i); | |
fd6b7a7f KZ |
1218 | } |
1219 | if (Inode2[i].i_nlinks != inode_count[i]) { | |
a2bfda30 SK |
1220 | printf(_("Inode %lu (mode = %07o), i_nlinks=%d, counted=%d."), |
1221 | i, Inode2[i].i_mode, Inode2[i].i_nlinks, | |
1222 | inode_count[i]); | |
1223 | if (ask(_("Set i_nlinks to count"), 1)) { | |
fd6b7a7f KZ |
1224 | Inode2[i].i_nlinks = inode_count[i]; |
1225 | changed = 1; | |
1226 | } | |
1227 | } | |
1228 | } | |
971b7341 | 1229 | for (i = get_first_zone(); i < get_nzones(); i++) { |
a2bfda30 | 1230 | if (zone_in_use(i) == zone_count[i]) |
fd6b7a7f KZ |
1231 | continue; |
1232 | if (!zone_count[i]) { | |
a2bfda30 | 1233 | if (bad_zone(i)) |
fd6b7a7f | 1234 | continue; |
a2bfda30 SK |
1235 | printf(_("Zone %lu: marked in use, no file uses it."), |
1236 | i); | |
1237 | if (ask(_("Unmark"), 1)) | |
1238 | unmark_zone(i); | |
fd6b7a7f KZ |
1239 | continue; |
1240 | } | |
a2bfda30 SK |
1241 | if (zone_in_use(i)) |
1242 | printf(_("Zone %lu: in use, counted=%d\n"), | |
1243 | i, zone_count[i]); | |
e8f26419 | 1244 | else |
a2bfda30 SK |
1245 | printf(_("Zone %lu: not in use, counted=%d\n"), |
1246 | i, zone_count[i]); | |
fd6b7a7f KZ |
1247 | } |
1248 | } | |
fd6b7a7f | 1249 | |
22853e4a KZ |
1250 | static void |
1251 | check(void) { | |
a2bfda30 SK |
1252 | memset(inode_count, 0, (get_ninodes() + 1) * sizeof(*inode_count)); |
1253 | memset(zone_count, 0, get_nzones() * sizeof(*zone_count)); | |
6dbe3af9 KZ |
1254 | check_zones(ROOT_INO); |
1255 | recursive_check(ROOT_INO); | |
1256 | check_counts(); | |
1257 | } | |
1258 | ||
22853e4a | 1259 | static void |
a2bfda30 SK |
1260 | check2(void) { |
1261 | memset(inode_count, 0, (get_ninodes() + 1) * sizeof(*inode_count)); | |
1262 | memset(zone_count, 0, get_nzones() * sizeof(*zone_count)); | |
1263 | check_zones2(ROOT_INO); | |
1264 | recursive_check2(ROOT_INO); | |
1265 | check_counts2(); | |
fd6b7a7f | 1266 | } |
fd6b7a7f | 1267 | |
22853e4a | 1268 | int |
a2bfda30 | 1269 | main(int argc, char **argv) { |
fd6b7a7f | 1270 | struct termios tmp; |
6dbe3af9 | 1271 | int count; |
65ca6f83 | 1272 | int retcode = FSCK_EX_OK; |
158b8d69 SK |
1273 | int i; |
1274 | static const struct option longopts[] = { | |
1275 | {"list", no_argument, NULL, 'l'}, | |
1276 | {"auto", no_argument, NULL, 'a'}, | |
1277 | {"repair", no_argument, NULL, 'r'}, | |
1278 | {"verbose", no_argument, NULL, 'v'}, | |
1279 | {"super", no_argument, NULL, 's'}, | |
1280 | {"uncleared", no_argument, NULL, 'm'}, | |
1281 | {"force", no_argument, NULL, 'f'}, | |
1282 | {"version", no_argument, NULL, 'V'}, | |
1283 | {"help", no_argument, NULL, 'h'}, | |
1284 | {NULL, 0, NULL, 0} | |
1285 | }; | |
6dbe3af9 | 1286 | |
7eda085c KZ |
1287 | setlocale(LC_ALL, ""); |
1288 | bindtextdomain(PACKAGE, LOCALEDIR); | |
1289 | textdomain(PACKAGE); | |
2c308875 | 1290 | close_stdout_atexit(); |
7eda085c | 1291 | |
0b2b32e8 RM |
1292 | strutils_set_exitcode(FSCK_EX_USAGE); |
1293 | ||
63883af7 | 1294 | if (INODE_SIZE * MINIX_INODES_PER_BLOCK != MINIX_BLOCK_SIZE) |
eb63b9b8 | 1295 | die(_("bad inode size")); |
63883af7 | 1296 | if (INODE2_SIZE * MINIX2_INODES_PER_BLOCK != MINIX_BLOCK_SIZE) |
eb63b9b8 | 1297 | die(_("bad v2 inode size")); |
c129767e | 1298 | |
158b8d69 SK |
1299 | while ((i = getopt_long(argc, argv, "larvsmfVh", longopts, NULL)) != -1) |
1300 | switch (i) { | |
1301 | case 'l': | |
1302 | list = 1; | |
1303 | break; | |
1304 | case 'a': | |
1305 | automatic = 1; | |
1306 | repair = 1; | |
1307 | break; | |
1308 | case 'r': | |
1309 | automatic = 0; | |
1310 | repair = 1; | |
1311 | break; | |
1312 | case 'v': | |
1313 | verbose = 1; | |
1314 | break; | |
1315 | case 's': | |
1316 | show = 1; | |
1317 | break; | |
1318 | case 'm': | |
1319 | warn_mode = 1; | |
1320 | break; | |
1321 | case 'f': | |
1322 | force = 1; | |
1323 | break; | |
1324 | case 'V': | |
2c308875 | 1325 | print_version(FSCK_EX_OK); |
158b8d69 | 1326 | case 'h': |
6e1eda6f | 1327 | usage(); |
158b8d69 | 1328 | default: |
677ec86c | 1329 | errtryhelp(FSCK_EX_USAGE); |
158b8d69 SK |
1330 | } |
1331 | argc -= optind; | |
1332 | argv += optind; | |
1333 | if (0 < argc) { | |
1334 | device_name = argv[0]; | |
6e1eda6f RM |
1335 | } else { |
1336 | warnx(_("no device specified")); | |
1337 | errtryhelp(FSCK_EX_USAGE); | |
1338 | } | |
6dbe3af9 | 1339 | check_mount(); /* trying to check a mounted filesystem? */ |
74ce680a SK |
1340 | if (repair && !automatic && (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))) |
1341 | die(_("need terminal for interactive repairs")); | |
1342 | ||
e1df9d4c SK |
1343 | device_fd = open(device_name, repair ? O_RDWR : O_RDONLY); |
1344 | if (device_fd < 0) | |
289dcc90 | 1345 | die(_("cannot open %s: %s"), device_name, strerror(errno)); |
a2bfda30 | 1346 | for (count = 0; count < 3; count++) |
6dbe3af9 | 1347 | sync(); |
fd6b7a7f | 1348 | read_superblock(); |
6dbe3af9 | 1349 | |
a2bfda30 SK |
1350 | /* Determine whether or not we should continue with the checking. This |
1351 | * is based on the status of the filesystem valid and error flags and | |
1352 | * whether or not the -f switch was specified on the command line. */ | |
86a9f3da | 1353 | if (fs_version < 3 && !(Super.s_state & MINIX_ERROR_FS) && |
a2bfda30 | 1354 | (Super.s_state & MINIX_VALID_FS) && !force) { |
6dbe3af9 | 1355 | if (repair) |
7eda085c | 1356 | printf(_("%s is clean, no check.\n"), device_name); |
6dbe3af9 | 1357 | return retcode; |
042f62df RP |
1358 | } |
1359 | ||
1360 | 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 | } |