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