1 | /* Hacks for version 1.6 */
|
---|
2 |
|
---|
3 | #define INODES_PER_BLOCK V1_INODES_PER_BLOCK
|
---|
4 | #define INODE_SIZE V1_INODE_SIZE
|
---|
5 | #define WORDS_PER_BLOCK (BLOCK_SIZE / (int) sizeof(bitchunk_t))
|
---|
6 | #define MAX_ZONES (V1_NR_DZONES+V1_INDIRECTS+(long)V1_INDIRECTS*V1_INDIRECTS)
|
---|
7 | #define NR_DZONE_NUM V1_NR_DZONES
|
---|
8 | #define NR_INDIRECTS V1_INDIRECTS
|
---|
9 | #define NR_ZONE_NUMS V1_NR_TZONES
|
---|
10 | #define ZONE_NUM_SIZE V1_ZONE_NUM_SIZE
|
---|
11 | #define bit_nr u16_t /* perhaps bit_t should be used, although slower */
|
---|
12 | #define Bit_nr U16_t
|
---|
13 | #define block_nr block_t
|
---|
14 | #define d_inode d1_inode
|
---|
15 | #define d_inum d_ino
|
---|
16 | #define dir_struct struct direct
|
---|
17 | #define i_mode d1_mode
|
---|
18 | #define i_nlinks d1_nlinks
|
---|
19 | #define i_size d1_size
|
---|
20 | #define i_zone d1_zone
|
---|
21 | #define zone_nr zone1_t
|
---|
22 | #define Zone_nr Zone1_t
|
---|
23 |
|
---|
24 | /* fsck - file system checker Author: Robbert van Renesse */
|
---|
25 |
|
---|
26 | /* Modified by Norbert Schlenker
|
---|
27 | * Removed vestiges of standalone/DOS versions:
|
---|
28 | * - various unused variables and buffers removed
|
---|
29 | * - now uses library functions rather than private internal routines
|
---|
30 | * - bytewise structure copies replaced by structure assignment
|
---|
31 | * - fixed one bug with 14 character file names
|
---|
32 | * - other small tweaks for speed
|
---|
33 | *
|
---|
34 | * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
|
---|
35 | * Removed -m option, by which fsck could be told to make a file
|
---|
36 | * system on a 360K floppy. The code had limited utility, was buggy,
|
---|
37 | * and failed due to a bug in the ACK C compiler. Use mkfs instead!
|
---|
38 | */
|
---|
39 |
|
---|
40 | #include <sys/types.h>
|
---|
41 | #include <sys/dir.h>
|
---|
42 | #include <ctype.h>
|
---|
43 | #include <errno.h>
|
---|
44 | #include <fcntl.h>
|
---|
45 | #include <limits.h>
|
---|
46 | #include <stdlib.h>
|
---|
47 | #include <string.h>
|
---|
48 | #include <unistd.h>
|
---|
49 | #include <minix/config.h>
|
---|
50 | #include <minix/const.h>
|
---|
51 | #include <minix/type.h>
|
---|
52 | #include "../../servers/fs/const.h"
|
---|
53 | #include "../../servers/fs/inode.h"
|
---|
54 | #include "../../servers/fs/type.h"
|
---|
55 | #include <minix/fslib.h>
|
---|
56 | #include <stdio.h>
|
---|
57 | #include <dirent.h>
|
---|
58 |
|
---|
59 | #define BLOCK_SIZE _STATIC_BLOCK_SIZE
|
---|
60 |
|
---|
61 | #define BITSHIFT 4 /* = log2(#bits(int)) */
|
---|
62 |
|
---|
63 | #define MAXPRINT 8 /* max. number of error lines in chkmap */
|
---|
64 | #define CINDIR 128 /* number of indirect zno's read at a time */
|
---|
65 | #define CDIRECT 16 /* number of dir entries read at a time */
|
---|
66 | #define BITMASK ((1 << BITSHIFT) - 1)
|
---|
67 | #define setbit(w, b) (w[(b) >> BITSHIFT] |= 1 << ((b) & BITMASK))
|
---|
68 | #define clrbit(w, b) (w[(b) >> BITSHIFT] &= ~(1 << ((b) & BITMASK)))
|
---|
69 | #define bitset(w, b) (w[(b) >> BITSHIFT] & (1 << ((b) & BITMASK)))
|
---|
70 |
|
---|
71 | #define ZONE_CT 360 /* default zones (when making file system) */
|
---|
72 | #define INODE_CT 95 /* default inodes (when making file system) */
|
---|
73 |
|
---|
74 | #include "../../servers/fs/super.h"
|
---|
75 | struct super_block sb;
|
---|
76 |
|
---|
77 | #define STICKY_BIT 01000 /* not defined anywhere else */
|
---|
78 |
|
---|
79 | /* Ztob gives the block address of a zone
|
---|
80 | * btoa gives the byte address of a block
|
---|
81 | */
|
---|
82 | #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
|
---|
83 | #define btoa(b) ((long) (b) * BLOCK_SIZE)
|
---|
84 | #define SCALE ((int) ztob(1)) /* # blocks in a zone */
|
---|
85 | #define FIRST ((zone_nr) sb.s_firstdatazone) /* as the name says */
|
---|
86 |
|
---|
87 | /* # blocks of each type */
|
---|
88 | #define N_SUPER 1
|
---|
89 | #define N_IMAP (sb.s_imap_blocks)
|
---|
90 | #define N_ZMAP (sb.s_zmap_blocks)
|
---|
91 | #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
|
---|
92 | #define N_DATA (sb.s_nzones - FIRST)
|
---|
93 |
|
---|
94 | /* Block address of each type */
|
---|
95 | #define BLK_SUPER (1)
|
---|
96 | #define BLK_IMAP (BLK_SUPER + N_SUPER)
|
---|
97 | #define BLK_ZMAP (BLK_IMAP + N_IMAP)
|
---|
98 | #define BLK_ILIST (BLK_ZMAP + N_ZMAP)
|
---|
99 | #define BLK_FIRST ztob(FIRST)
|
---|
100 | #define ZONE_SIZE ((int) ztob(BLOCK_SIZE))
|
---|
101 | #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
|
---|
102 |
|
---|
103 | /* Byte address of a zone/of an inode */
|
---|
104 | #define zaddr(z) btoa(ztob(z))
|
---|
105 | #define inoaddr(i) ((long) (i - 1) * INODE_SIZE + btoa(BLK_ILIST))
|
---|
106 | #define INDCHUNK (CINDIR * ZONE_NUM_SIZE)
|
---|
107 | #define DIRCHUNK (CDIRECT * DIR_ENTRY_SIZE)
|
---|
108 |
|
---|
109 | char *prog, *device; /* program name (fsck), device name */
|
---|
110 | int firstcnterr; /* is this the first inode ref cnt error? */
|
---|
111 | bitchunk_t *imap, *spec_imap; /* inode bit maps */
|
---|
112 | bitchunk_t *zmap, *spec_zmap; /* zone bit maps */
|
---|
113 | bitchunk_t *dirmap; /* directory (inode) bit map */
|
---|
114 | char rwbuf[BLOCK_SIZE]; /* one block buffer cache */
|
---|
115 | block_nr thisblk; /* block in buffer cache */
|
---|
116 | char nullbuf[BLOCK_SIZE]; /* null buffer */
|
---|
117 | nlink_t *count; /* inode count */
|
---|
118 | int changed; /* has the diskette been written to? */
|
---|
119 | struct stack {
|
---|
120 | dir_struct *st_dir;
|
---|
121 | struct stack *st_next;
|
---|
122 | char st_presence;
|
---|
123 | } *ftop;
|
---|
124 |
|
---|
125 | int dev; /* file descriptor of the device */
|
---|
126 |
|
---|
127 | #define DOT 1
|
---|
128 | #define DOTDOT 2
|
---|
129 |
|
---|
130 | /* Counters for each type of inode/zone. */
|
---|
131 | int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
|
---|
132 | int npipe, nsyml, nfreezone, ztype[NLEVEL];
|
---|
133 |
|
---|
134 | int repair, automatic, listing, listsuper; /* flags */
|
---|
135 | int firstlist; /* has the listing header been printed? */
|
---|
136 | unsigned part_offset; /* sector offset for this partition */
|
---|
137 | char answer[] = "Answer questions with y or n. Then hit RETURN";
|
---|
138 |
|
---|
139 | _PROTOTYPE(int main, (int argc, char **argv));
|
---|
140 | _PROTOTYPE(void initvars, (void));
|
---|
141 | _PROTOTYPE(void fatal, (char *s));
|
---|
142 | _PROTOTYPE(int eoln, (int c));
|
---|
143 | _PROTOTYPE(int yes, (char *question));
|
---|
144 | _PROTOTYPE(int atoo, (char *s));
|
---|
145 | _PROTOTYPE(int input, (char *buf, int size));
|
---|
146 | _PROTOTYPE(char *alloc, (unsigned nelem, unsigned elsize));
|
---|
147 | _PROTOTYPE(void printname, (char *s));
|
---|
148 | _PROTOTYPE(void printrec, (struct stack *sp));
|
---|
149 | _PROTOTYPE(void printpath, (int mode, int nlcr));
|
---|
150 | _PROTOTYPE(void devopen, (void));
|
---|
151 | _PROTOTYPE(void devclose, (void));
|
---|
152 | _PROTOTYPE(void devio, (block_nr bno, int dir));
|
---|
153 | _PROTOTYPE(void devread, (long offset, char *buf, int size));
|
---|
154 | _PROTOTYPE(void devwrite, (long offset, char *buf, int size));
|
---|
155 | _PROTOTYPE(void pr, (char *fmt, int cnt, char *s, char *p));
|
---|
156 | _PROTOTYPE(bit_nr getnumber, (char *s));
|
---|
157 | _PROTOTYPE(char **getlist, (char ***argv, char *type));
|
---|
158 | _PROTOTYPE(void lsuper, (void));
|
---|
159 | _PROTOTYPE(void getsuper, (void));
|
---|
160 | _PROTOTYPE(void chksuper, (void));
|
---|
161 | _PROTOTYPE(void lsi, (char **clist));
|
---|
162 | _PROTOTYPE(bitchunk_t *allocbitmap, (int nblk));
|
---|
163 | _PROTOTYPE(void loadbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
|
---|
164 | _PROTOTYPE(void dumpbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
|
---|
165 | _PROTOTYPE(void fillbitmap, (bitchunk_t *bitmap, Bit_nr lwb, Bit_nr upb, char **list));
|
---|
166 | _PROTOTYPE(void freebitmap, (bitchunk_t *p));
|
---|
167 | _PROTOTYPE(void getbitmaps, (void));
|
---|
168 | _PROTOTYPE(void putbitmaps, (void));
|
---|
169 | _PROTOTYPE(void chkword, (unsigned w1, unsigned w2, Bit_nr bit, char *type, int *n, int *report));
|
---|
170 | _PROTOTYPE(void chkmap, (bitchunk_t *cmap, bitchunk_t *dmap, Bit_nr bit, block_nr blkno, int nblk, char *type));
|
---|
171 | _PROTOTYPE(void chkilist, (void));
|
---|
172 | _PROTOTYPE(void getcount, (void));
|
---|
173 | _PROTOTYPE(void counterror, (Ino_t ino));
|
---|
174 | _PROTOTYPE(void chkcount, (void));
|
---|
175 | _PROTOTYPE(void freecount, (void));
|
---|
176 | _PROTOTYPE(void printperm, (mode_t mode, int shift, int special, int overlay));
|
---|
177 | _PROTOTYPE(void list, (Ino_t ino, d_inode *ip));
|
---|
178 | _PROTOTYPE(int Remove, (dir_struct *dp));
|
---|
179 | _PROTOTYPE(void make_printable_name, (char *dst, char *src, int n));
|
---|
180 | _PROTOTYPE(int chkdots, (Ino_t ino, off_t pos, dir_struct *dp, Ino_t exp));
|
---|
181 | _PROTOTYPE(int chkname, (Ino_t ino, dir_struct *dp));
|
---|
182 | _PROTOTYPE(int chkentry, (Ino_t ino, off_t pos, dir_struct *dp));
|
---|
183 | _PROTOTYPE(int chkdirzone, (Ino_t ino, d_inode *ip, off_t pos, Zone_nr zno));
|
---|
184 | _PROTOTYPE(void errzone, (char *mess, Zone_nr zno, int level, off_t pos));
|
---|
185 | _PROTOTYPE(int markzone, (Ino_t ino, Zone_nr zno, int level, off_t pos));
|
---|
186 | _PROTOTYPE(int chkindzone, (Ino_t ino, d_inode *ip, off_t *pos, Zone_nr zno, int level));
|
---|
187 | _PROTOTYPE(off_t jump, (int level));
|
---|
188 | _PROTOTYPE(int zonechk, (Ino_t ino, d_inode *ip, off_t *pos, Zone_nr zno, int level));
|
---|
189 | _PROTOTYPE(int chkzones, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int len, int level));
|
---|
190 | _PROTOTYPE(int chkfile, (Ino_t ino, d_inode *ip));
|
---|
191 | _PROTOTYPE(int chkdirectory, (Ino_t ino, d_inode *ip));
|
---|
192 | _PROTOTYPE(int chklink, (Ino_t ino, d_inode *ip));
|
---|
193 | _PROTOTYPE(int chkmode, (Ino_t ino, d_inode *ip));
|
---|
194 | _PROTOTYPE(int chkinode, (Ino_t ino, d_inode *ip));
|
---|
195 | _PROTOTYPE(int chkspecial, (Ino_t ino, d_inode *ip) );
|
---|
196 | _PROTOTYPE(int descendtree, (dir_struct *dp));
|
---|
197 | _PROTOTYPE(void chktree, (void));
|
---|
198 | _PROTOTYPE(void printtotal, (void));
|
---|
199 | _PROTOTYPE(void chkdev, (char *f, char **clist, char **ilist, char **zlist));
|
---|
200 |
|
---|
201 | /* Initialize the variables used by this program. */
|
---|
202 | void initvars()
|
---|
203 | {
|
---|
204 | register level;
|
---|
205 |
|
---|
206 | nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = nsyml = 0;
|
---|
207 | for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
|
---|
208 | changed = 0;
|
---|
209 | thisblk = NO_BLOCK;
|
---|
210 | firstlist = 1;
|
---|
211 | firstcnterr = 1;
|
---|
212 | }
|
---|
213 |
|
---|
214 | /* Print the string `s' and exit. */
|
---|
215 | void fatal(s)
|
---|
216 | char *s;
|
---|
217 | {
|
---|
218 | printf("%s\nfatal\n", s);
|
---|
219 | exit(-1);
|
---|
220 | }
|
---|
221 |
|
---|
222 | /* Test for end of line. */
|
---|
223 | int eoln(c)
|
---|
224 | int c;
|
---|
225 | {
|
---|
226 | return(c == EOF || c == '\n' || c == '\r');
|
---|
227 | }
|
---|
228 |
|
---|
229 | /* Ask a question and get the answer unless automatic is set. */
|
---|
230 | int yes(question)
|
---|
231 | char *question;
|
---|
232 | {
|
---|
233 | register c, answer;
|
---|
234 |
|
---|
235 | if (!repair) {
|
---|
236 | printf("\n");
|
---|
237 | return(0);
|
---|
238 | }
|
---|
239 | printf("%s? ", question);
|
---|
240 | if (automatic) {
|
---|
241 | printf("yes\n");
|
---|
242 | return(1);
|
---|
243 | }
|
---|
244 | fflush(stdout);
|
---|
245 | if ((c = answer = getchar()) == 'q' || c == 'Q') exit(1);
|
---|
246 | while (!eoln(c)) c = getchar();
|
---|
247 | return !(answer == 'n' || answer == 'N');
|
---|
248 | }
|
---|
249 |
|
---|
250 | /* Convert string to integer. Representation is octal. */
|
---|
251 | int atoo(s)
|
---|
252 | register char *s;
|
---|
253 | {
|
---|
254 | register int n = 0;
|
---|
255 |
|
---|
256 | while ('0' <= *s && *s < '8') {
|
---|
257 | n <<= 3;
|
---|
258 | n += *s++ - '0';
|
---|
259 | }
|
---|
260 | return n;
|
---|
261 | }
|
---|
262 |
|
---|
263 | /* If repairing the file system, print a prompt and get a string from user. */
|
---|
264 | int input(buf, size)
|
---|
265 | char *buf;
|
---|
266 | int size;
|
---|
267 | {
|
---|
268 | register char *p = buf;
|
---|
269 |
|
---|
270 | printf("\n");
|
---|
271 | if (repair) {
|
---|
272 | printf("--> ");
|
---|
273 | fflush(stdout);
|
---|
274 | while (--size) {
|
---|
275 | *p = getchar();
|
---|
276 | if (eoln(*p)) {
|
---|
277 | *p = 0;
|
---|
278 | return(p > buf);
|
---|
279 | }
|
---|
280 | p++;
|
---|
281 | }
|
---|
282 | *p = 0;
|
---|
283 | while (!eoln(getchar()));
|
---|
284 | return(1);
|
---|
285 | }
|
---|
286 | return(0);
|
---|
287 | }
|
---|
288 |
|
---|
289 | /* Allocate some memory and zero it. */
|
---|
290 | char *alloc(nelem, elsize)
|
---|
291 | unsigned nelem, elsize;
|
---|
292 | {
|
---|
293 | char *p;
|
---|
294 |
|
---|
295 | if ((p = (char *) malloc((size_t)nelem * elsize)) == 0) fatal("out of memory");
|
---|
296 | memset(p, 0, (size_t)nelem * elsize);
|
---|
297 | return(p);
|
---|
298 | }
|
---|
299 |
|
---|
300 | /* Print the name in a directory entry. */
|
---|
301 | void printname(s)
|
---|
302 | char *s;
|
---|
303 | {
|
---|
304 | register n = NAME_MAX;
|
---|
305 | int c;
|
---|
306 |
|
---|
307 | do {
|
---|
308 | if ((c = *s) == 0) break;
|
---|
309 | if (!isprint(c)) c = '?';
|
---|
310 | putchar(c);
|
---|
311 | s++;
|
---|
312 | } while (--n);
|
---|
313 | }
|
---|
314 |
|
---|
315 | /* Print the pathname given by a linked list pointed to by `sp'. The
|
---|
316 | * names are in reverse order.
|
---|
317 | */
|
---|
318 | void printrec(sp)
|
---|
319 | struct stack *sp;
|
---|
320 | {
|
---|
321 | if (sp->st_next != 0) {
|
---|
322 | printrec(sp->st_next);
|
---|
323 | putchar('/');
|
---|
324 | printname(sp->st_dir->d_name);
|
---|
325 | }
|
---|
326 | }
|
---|
327 |
|
---|
328 | /* Print the current pathname. */
|
---|
329 | void printpath(mode, nlcr)
|
---|
330 | int mode;
|
---|
331 | int nlcr;
|
---|
332 | {
|
---|
333 | if (ftop->st_next == 0)
|
---|
334 | putchar('/');
|
---|
335 | else
|
---|
336 | printrec(ftop);
|
---|
337 | switch (mode) {
|
---|
338 | case 1:
|
---|
339 | printf(" (ino = %u, ", ftop->st_dir->d_inum);
|
---|
340 | break;
|
---|
341 | case 2:
|
---|
342 | printf(" (ino = %u)", ftop->st_dir->d_inum);
|
---|
343 | break;
|
---|
344 | }
|
---|
345 | if (nlcr) printf("\n");
|
---|
346 | }
|
---|
347 |
|
---|
348 | /* Open the device. */
|
---|
349 | void devopen()
|
---|
350 | {
|
---|
351 | if ((dev = open(device, repair ? O_RDWR : O_RDONLY)) < 0) {
|
---|
352 | perror(device);
|
---|
353 | fatal("");
|
---|
354 | }
|
---|
355 | }
|
---|
356 |
|
---|
357 | /* Close the device. */
|
---|
358 | void devclose()
|
---|
359 | {
|
---|
360 | if (close(dev) != 0) {
|
---|
361 | perror("close");
|
---|
362 | fatal("");
|
---|
363 | }
|
---|
364 | }
|
---|
365 |
|
---|
366 | /* Read or write a block. */
|
---|
367 | void devio(bno, dir)
|
---|
368 | block_nr bno;
|
---|
369 | int dir;
|
---|
370 | {
|
---|
371 | if (dir == READING && bno == thisblk) return;
|
---|
372 | thisblk = bno;
|
---|
373 |
|
---|
374 | lseek(dev, (off_t) btoa(bno), SEEK_SET);
|
---|
375 | if (dir == READING) {
|
---|
376 | if (read(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
|
---|
377 | return;
|
---|
378 | } else {
|
---|
379 | if (write(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
|
---|
380 | return;
|
---|
381 | }
|
---|
382 |
|
---|
383 | printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
|
---|
384 | dir == READING ? "read" : "write", (long) bno, errno);
|
---|
385 | if (dir == READING) {
|
---|
386 | printf("Continuing with a zero-filled block.\n");
|
---|
387 | memset(rwbuf, 0, BLOCK_SIZE);
|
---|
388 | return;
|
---|
389 | }
|
---|
390 | fatal("");
|
---|
391 | }
|
---|
392 |
|
---|
393 | /* Read `size' bytes from the disk starting at byte `offset'. */
|
---|
394 | void devread(offset, buf, size)
|
---|
395 | long offset;
|
---|
396 | char *buf;
|
---|
397 | int size;
|
---|
398 | {
|
---|
399 | devio((block_nr) (offset / BLOCK_SIZE), READING);
|
---|
400 | memmove(buf, &rwbuf[(int) (offset % BLOCK_SIZE)], (size_t)size);
|
---|
401 | }
|
---|
402 |
|
---|
403 | /* Write `size' bytes to the disk starting at byte `offset'. */
|
---|
404 | void devwrite(offset, buf, size)
|
---|
405 | long offset;
|
---|
406 | char *buf;
|
---|
407 | int size;
|
---|
408 | {
|
---|
409 | if (!repair) fatal("internal error (devwrite)");
|
---|
410 | if (size != BLOCK_SIZE) devio((block_nr) (offset / BLOCK_SIZE), READING);
|
---|
411 | memmove(&rwbuf[(int) (offset % BLOCK_SIZE)], buf, (size_t)size);
|
---|
412 | devio((block_nr) (offset / BLOCK_SIZE), WRITING);
|
---|
413 | changed = 1;
|
---|
414 | }
|
---|
415 |
|
---|
416 | /* Print a string with either a singular or a plural pronoun. */
|
---|
417 | void pr(fmt, cnt, s, p)
|
---|
418 | char *fmt, *s, *p;
|
---|
419 | int cnt;
|
---|
420 | {
|
---|
421 | printf(fmt, cnt, cnt == 1 ? s : p);
|
---|
422 | }
|
---|
423 |
|
---|
424 | /* Convert string to number. */
|
---|
425 | bit_nr getnumber(s)
|
---|
426 | register char *s;
|
---|
427 | {
|
---|
428 | register bit_nr n = 0;
|
---|
429 |
|
---|
430 | if (s == NULL)
|
---|
431 | return NO_BIT;
|
---|
432 | while (isdigit(*s))
|
---|
433 | n = (n << 1) + (n << 3) + *s++ - '0';
|
---|
434 | return (*s == '\0') ? n : NO_BIT;
|
---|
435 | }
|
---|
436 |
|
---|
437 | /* See if the list pointed to by `argv' contains numbers. */
|
---|
438 | char **getlist(argv, type)
|
---|
439 | char ***argv, *type;
|
---|
440 | {
|
---|
441 | register char **list = *argv;
|
---|
442 | register empty = 1;
|
---|
443 |
|
---|
444 | while (getnumber(**argv) != NO_BIT) {
|
---|
445 | (*argv)++;
|
---|
446 | empty = 0;
|
---|
447 | }
|
---|
448 | if (empty) {
|
---|
449 | printf("warning: no %s numbers given\n", type);
|
---|
450 | return(NULL);
|
---|
451 | }
|
---|
452 | return(list);
|
---|
453 | }
|
---|
454 |
|
---|
455 | /* Make a listing of the super block. If `repair' is set, ask the user
|
---|
456 | * for changes.
|
---|
457 | */
|
---|
458 | void lsuper()
|
---|
459 | {
|
---|
460 | char buf[80];
|
---|
461 |
|
---|
462 | do {
|
---|
463 | printf("ninodes = %u", sb.s_ninodes);
|
---|
464 | if (input(buf, 80)) sb.s_ninodes = atol(buf);
|
---|
465 | printf("nzones = %u", sb.s_nzones);
|
---|
466 | if (input(buf, 80)) sb.s_nzones = atol(buf);
|
---|
467 | printf("imap_blocks = %u", sb.s_imap_blocks);
|
---|
468 | if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
|
---|
469 | printf("zmap_blocks = %u", sb.s_zmap_blocks);
|
---|
470 | if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
|
---|
471 | printf("firstdatazone = %u", sb.s_firstdatazone);
|
---|
472 | if (input(buf, 80)) sb.s_firstdatazone = atol(buf);
|
---|
473 | printf("log_zone_size = %u", sb.s_log_zone_size);
|
---|
474 | if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
|
---|
475 | printf("maxsize = %lu", sb.s_max_size);
|
---|
476 | if (input(buf, 80)) sb.s_max_size = atol(buf);
|
---|
477 | if (yes("ok now")) {
|
---|
478 | devwrite(btoa(BLK_SUPER), (char *) &sb, sizeof(sb));
|
---|
479 | return;
|
---|
480 | }
|
---|
481 | } while (yes("Do you want to try again"));
|
---|
482 | if (repair) exit(0);
|
---|
483 | }
|
---|
484 |
|
---|
485 | /* Get the super block from either disk or user. Do some initial checks. */
|
---|
486 | void getsuper()
|
---|
487 | {
|
---|
488 | devread(btoa(BLK_SUPER), (char *) &sb, sizeof(sb));
|
---|
489 | if (listsuper) lsuper();
|
---|
490 | if (sb.s_magic == SUPER_V2) fatal("Cannot handle V2 file systems");
|
---|
491 | if (sb.s_magic != SUPER_MAGIC) fatal("bad magic number in super block");
|
---|
492 | if ((short) sb.s_ninodes <= 0) fatal("no inodes");
|
---|
493 | if (sb.s_nzones <= 2) fatal("no zones");
|
---|
494 | if ((short) sb.s_imap_blocks <= 0) fatal("no imap");
|
---|
495 | if ((short) sb.s_zmap_blocks <= 0) fatal("no zmap");
|
---|
496 | if ((short) sb.s_firstdatazone <= 1) fatal("first data zone too small");
|
---|
497 | if ((short) sb.s_log_zone_size < 0) fatal("zone size < block size");
|
---|
498 | if (sb.s_max_size <= 0) fatal("max. file size <= 0");
|
---|
499 | }
|
---|
500 |
|
---|
501 | /* Check the super block for reasonable contents. */
|
---|
502 | void chksuper()
|
---|
503 | {
|
---|
504 | register n;
|
---|
505 | register off_t maxsize;
|
---|
506 |
|
---|
507 | n = bitmapsize((bit_t) sb.s_ninodes + 1, BLOCK_SIZE);
|
---|
508 | if (sb.s_magic != SUPER_MAGIC) fatal("bad magic number in super block");
|
---|
509 | if ((short) sb.s_imap_blocks < n) fatal("too few imap blocks");
|
---|
510 | if (sb.s_imap_blocks != n) {
|
---|
511 | pr("warning: expected %d imap_block%s", n, "", "s");
|
---|
512 | printf(" instead of %d\n", sb.s_imap_blocks);
|
---|
513 | }
|
---|
514 | n = bitmapsize((bit_t) sb.s_nzones, BLOCK_SIZE);
|
---|
515 | if ((short) sb.s_zmap_blocks < n) fatal("too few zmap blocks");
|
---|
516 | if (sb.s_zmap_blocks != n) {
|
---|
517 | pr("warning: expected %d zmap_block%s", n, "", "s");
|
---|
518 | printf(" instead of %d\n", sb.s_zmap_blocks);
|
---|
519 | }
|
---|
520 | if (sb.s_firstdatazone >= sb.s_nzones)
|
---|
521 | fatal("first data zone too large");
|
---|
522 | if ((unsigned short) sb.s_log_zone_size >= 8 * sizeof(block_nr))
|
---|
523 | fatal("log_zone_size too large");
|
---|
524 | if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
|
---|
525 | sb.s_log_zone_size);
|
---|
526 | n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
|
---|
527 | if ((short) sb.s_firstdatazone < n) fatal("first data zone too small");
|
---|
528 | if (sb.s_firstdatazone != n) {
|
---|
529 | printf("warning: expected first data zone to be %d ", n);
|
---|
530 | printf("instead of %u\n", sb.s_firstdatazone);
|
---|
531 | }
|
---|
532 | maxsize = MAX_FILE_POS;
|
---|
533 | if (((maxsize - 1) >> sb.s_log_zone_size) / BLOCK_SIZE >= MAX_ZONES)
|
---|
534 | maxsize = ((long) MAX_ZONES * BLOCK_SIZE) << sb.s_log_zone_size;
|
---|
535 | if (sb.s_max_size != maxsize) {
|
---|
536 | printf("warning: expected max size to be %ld ", maxsize);
|
---|
537 | printf("instead of %ld\n", sb.s_max_size);
|
---|
538 | }
|
---|
539 | }
|
---|
540 |
|
---|
541 | /* Make a listing of the inodes given by `clist'. If `repair' is set, ask
|
---|
542 | * the user for changes.
|
---|
543 | */
|
---|
544 | void lsi(clist)
|
---|
545 | char **clist;
|
---|
546 | {
|
---|
547 | register bit_nr bit;
|
---|
548 | register ino_t ino;
|
---|
549 | d_inode inode, *ip = &inode;
|
---|
550 | char buf[80];
|
---|
551 |
|
---|
552 | if (clist == 0) return;
|
---|
553 | while ((bit = getnumber(*clist++)) != NO_BIT) {
|
---|
554 | setbit(spec_imap, bit);
|
---|
555 | ino = bit;
|
---|
556 | do {
|
---|
557 | devread(inoaddr(ino), (char *) ip, INODE_SIZE);
|
---|
558 | printf("inode %u:\n", ino);
|
---|
559 | printf(" mode = %06o", ip->i_mode);
|
---|
560 | if (input(buf, 80)) ip->i_mode = atoo(buf);
|
---|
561 | printf(" nlinks = %6u", ip->i_nlinks);
|
---|
562 | if (input(buf, 80)) ip->i_nlinks = atol(buf);
|
---|
563 | printf(" size = %6ld", ip->i_size);
|
---|
564 | if (input(buf, 80)) ip->i_size = atol(buf);
|
---|
565 | if (yes("Write this back")) {
|
---|
566 | devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
|
---|
567 | break;
|
---|
568 | }
|
---|
569 | } while (yes("Do you want to change it again"));
|
---|
570 | }
|
---|
571 | }
|
---|
572 |
|
---|
573 | /* Allocate `nblk' blocks worth of bitmap. */
|
---|
574 | bitchunk_t *allocbitmap(nblk)
|
---|
575 | int nblk;
|
---|
576 | {
|
---|
577 | register bitchunk_t *bitmap;
|
---|
578 |
|
---|
579 | bitmap = (bitchunk_t *) alloc(nblk, BLOCK_SIZE);
|
---|
580 | *bitmap |= 1;
|
---|
581 | return(bitmap);
|
---|
582 | }
|
---|
583 |
|
---|
584 | /* Load the bitmap starting at block `bno' from disk. */
|
---|
585 | void loadbitmap(bitmap, bno, nblk)
|
---|
586 | bitchunk_t *bitmap;
|
---|
587 | block_nr bno;
|
---|
588 | int nblk;
|
---|
589 | {
|
---|
590 | register i;
|
---|
591 | register bitchunk_t *p;
|
---|
592 |
|
---|
593 | p = bitmap;
|
---|
594 | for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
|
---|
595 | devread(btoa(bno), (char *) p, BLOCK_SIZE);
|
---|
596 | *bitmap |= 1;
|
---|
597 | }
|
---|
598 |
|
---|
599 | /* Write the bitmap starting at block `bno' to disk. */
|
---|
600 | void dumpbitmap(bitmap, bno, nblk)
|
---|
601 | bitchunk_t *bitmap;
|
---|
602 | block_nr bno;
|
---|
603 | int nblk;
|
---|
604 | {
|
---|
605 | register i;
|
---|
606 | register bitchunk_t *p = bitmap;
|
---|
607 |
|
---|
608 | for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
|
---|
609 | devwrite(btoa(bno), (char *) p, BLOCK_SIZE);
|
---|
610 | }
|
---|
611 |
|
---|
612 | /* Set the bits given by `list' in the bitmap. */
|
---|
613 | void fillbitmap(bitmap, lwb, upb, list)
|
---|
614 | bitchunk_t *bitmap;
|
---|
615 | bit_nr lwb, upb;
|
---|
616 | char **list;
|
---|
617 | {
|
---|
618 | register bit_nr bit;
|
---|
619 |
|
---|
620 | if (list == 0) return;
|
---|
621 | while ((bit = getnumber(*list++)) != NO_BIT)
|
---|
622 | if (bit < lwb || bit >= upb) {
|
---|
623 | if (bitmap == spec_imap)
|
---|
624 | printf("inode number %u ", bit);
|
---|
625 | else
|
---|
626 | printf("zone number %u ", bit);
|
---|
627 | printf("out of range (ignored)\n");
|
---|
628 | } else
|
---|
629 | setbit(bitmap, bit - lwb + 1);
|
---|
630 | }
|
---|
631 |
|
---|
632 | /* Deallocate the bitmap `p'. */
|
---|
633 | void freebitmap(p)
|
---|
634 | bitchunk_t *p;
|
---|
635 | {
|
---|
636 | free((char *) p);
|
---|
637 | }
|
---|
638 |
|
---|
639 | /* Get all the bitmaps used by this program. */
|
---|
640 | void getbitmaps()
|
---|
641 | {
|
---|
642 | imap = allocbitmap(N_IMAP);
|
---|
643 | zmap = allocbitmap(N_ZMAP);
|
---|
644 | spec_imap = allocbitmap(N_IMAP);
|
---|
645 | spec_zmap = allocbitmap(N_ZMAP);
|
---|
646 | dirmap = allocbitmap(N_IMAP);
|
---|
647 | }
|
---|
648 |
|
---|
649 | /* Release all the space taken by the bitmaps. */
|
---|
650 | void putbitmaps()
|
---|
651 | {
|
---|
652 | freebitmap(imap);
|
---|
653 | freebitmap(zmap);
|
---|
654 | freebitmap(spec_imap);
|
---|
655 | freebitmap(spec_zmap);
|
---|
656 | freebitmap(dirmap);
|
---|
657 | }
|
---|
658 |
|
---|
659 | /* `w1' and `w2' are differing words from two bitmaps that should be
|
---|
660 | * identical. Print what's the matter with them.
|
---|
661 | */
|
---|
662 | void chkword(w1, w2, bit, type, n, report)
|
---|
663 | unsigned w1, w2;
|
---|
664 | char *type;
|
---|
665 | bit_nr bit;
|
---|
666 | int *n, *report;
|
---|
667 | {
|
---|
668 | for (; (w1 | w2); w1 >>= 1, w2 >>= 1, bit++)
|
---|
669 | if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
|
---|
670 | (!repair || automatic || yes("stop this listing")))
|
---|
671 | *report = 0;
|
---|
672 | else if (*report)
|
---|
673 | if ((w1 & 1) && !(w2 & 1))
|
---|
674 | printf("%s %u is missing\n", type, bit);
|
---|
675 | else if (!(w1 & 1) && (w2 & 1))
|
---|
676 | printf("%s %u is not free\n", type, bit);
|
---|
677 | }
|
---|
678 |
|
---|
679 | /* Check if the given (correct) bitmap is identical with the one that is
|
---|
680 | * on the disk. If not, ask if the disk should be repaired.
|
---|
681 | */
|
---|
682 | void chkmap(cmap, dmap, bit, blkno, nblk, type)
|
---|
683 | bitchunk_t *cmap, *dmap;
|
---|
684 | bit_nr bit;
|
---|
685 | block_nr blkno;
|
---|
686 | int nblk;
|
---|
687 | char *type;
|
---|
688 | {
|
---|
689 | register bitchunk_t *p = dmap, *q = cmap;
|
---|
690 | int report = 1, nerr = 0;
|
---|
691 | int w = nblk * WORDS_PER_BLOCK;
|
---|
692 |
|
---|
693 | printf("Checking %s map\n", type);
|
---|
694 | loadbitmap(dmap, blkno, nblk);
|
---|
695 | do {
|
---|
696 | if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report);
|
---|
697 | p++;
|
---|
698 | q++;
|
---|
699 | bit += 8 * sizeof(bitchunk_t);
|
---|
700 | } while (--w > 0);
|
---|
701 |
|
---|
702 | if ((!repair || automatic) && !report) printf("etc. ");
|
---|
703 | if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
|
---|
704 | if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
|
---|
705 | if (nerr > 0) printf("\n");
|
---|
706 | }
|
---|
707 |
|
---|
708 | /* See if the inodes that aren't allocated are cleared. */
|
---|
709 | void chkilist()
|
---|
710 | {
|
---|
711 | register ino_t ino = 1;
|
---|
712 | mode_t mode;
|
---|
713 |
|
---|
714 | printf("Checking inode list\n");
|
---|
715 | do
|
---|
716 | if (!bitset(imap, (bit_nr) ino)) {
|
---|
717 | devread(inoaddr(ino), (char *) &mode, sizeof(mode));
|
---|
718 | if (mode != I_NOT_ALLOC) {
|
---|
719 | printf("mode inode %u not cleared", ino);
|
---|
720 | if (yes(". clear")) devwrite(inoaddr(ino), nullbuf,
|
---|
721 | INODE_SIZE);
|
---|
722 | }
|
---|
723 | }
|
---|
724 | while (++ino <= sb.s_ninodes);
|
---|
725 | printf("\n");
|
---|
726 | }
|
---|
727 |
|
---|
728 | /* Allocate an array to maintain the inode reference counts in. */
|
---|
729 | void getcount()
|
---|
730 | {
|
---|
731 | count = (nlink_t *) alloc(sb.s_ninodes + 1, sizeof(nlink_t));
|
---|
732 | }
|
---|
733 |
|
---|
734 | /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */
|
---|
735 | void counterror(ino)
|
---|
736 | ino_t ino;
|
---|
737 | {
|
---|
738 | d_inode inode;
|
---|
739 |
|
---|
740 | if (firstcnterr) {
|
---|
741 | printf("INODE NLINK COUNT\n");
|
---|
742 | firstcnterr = 0;
|
---|
743 | }
|
---|
744 | devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
|
---|
745 | count[ino] += inode.i_nlinks;
|
---|
746 | printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
|
---|
747 | if (yes(" adjust")) {
|
---|
748 | if ((inode.i_nlinks = count[ino]) == 0) {
|
---|
749 | fatal("internal error (counterror)");
|
---|
750 | /* This would be a patch
|
---|
751 | inode.i_mode = I_NOT_ALLOC;
|
---|
752 | clrbit(imap, (bit_nr) ino);
|
---|
753 | */
|
---|
754 | }
|
---|
755 | devwrite(inoaddr(ino), (char *) &inode, INODE_SIZE);
|
---|
756 | }
|
---|
757 | }
|
---|
758 |
|
---|
759 | /* Check if the reference count of the inodes are correct. The array `count'
|
---|
760 | * is maintained as follows: an entry indexed by the inode number is
|
---|
761 | * incremented each time a link is found; when the inode is read the link
|
---|
762 | * count in there is substracted from the corresponding entry in `count'.
|
---|
763 | * Thus, when the whole file system has been traversed, all the entries
|
---|
764 | * should be zero.
|
---|
765 | */
|
---|
766 | void chkcount()
|
---|
767 | {
|
---|
768 | register ino_t ino;
|
---|
769 |
|
---|
770 | for (ino = 1; ino <= sb.s_ninodes; ino++)
|
---|
771 | if (count[ino] != 0) counterror(ino);
|
---|
772 | if (!firstcnterr) printf("\n");
|
---|
773 | }
|
---|
774 |
|
---|
775 | /* Deallocate the `count' array. */
|
---|
776 | void freecount()
|
---|
777 | {
|
---|
778 | free((char *) count);
|
---|
779 | }
|
---|
780 |
|
---|
781 | /* Print the inode permission bits given by mode and shift. */
|
---|
782 | void printperm(mode_t mode, int shift, int special, int overlay)
|
---|
783 | {
|
---|
784 | if (mode >> shift & R_BIT)
|
---|
785 | putchar('r');
|
---|
786 | else
|
---|
787 | putchar('-');
|
---|
788 | if (mode >> shift & W_BIT)
|
---|
789 | putchar('w');
|
---|
790 | else
|
---|
791 | putchar('-');
|
---|
792 | if (mode & special)
|
---|
793 | putchar(overlay);
|
---|
794 | else
|
---|
795 | if (mode >> shift & X_BIT)
|
---|
796 | putchar('x');
|
---|
797 | else
|
---|
798 | putchar('-');
|
---|
799 | }
|
---|
800 |
|
---|
801 | /* List the given inode. */
|
---|
802 | void list(ino, ip)
|
---|
803 | ino_t ino;
|
---|
804 | d_inode *ip;
|
---|
805 | {
|
---|
806 | if (firstlist) {
|
---|
807 | firstlist = 0;
|
---|
808 | printf(" inode permission link size name\n");
|
---|
809 | }
|
---|
810 | printf("%6u ", ino);
|
---|
811 | switch (ip->i_mode & I_TYPE) {
|
---|
812 | case I_REGULAR: putchar('-'); break;
|
---|
813 | case I_DIRECTORY: putchar('d'); break;
|
---|
814 | case I_CHAR_SPECIAL: putchar('c'); break;
|
---|
815 | case I_BLOCK_SPECIAL: putchar('b'); break;
|
---|
816 | case I_NAMED_PIPE: putchar('p'); break;
|
---|
817 | #ifdef I_SYMBOLIC_LINK
|
---|
818 | case I_SYMBOLIC_LINK: putchar('l'); break;
|
---|
819 | #endif
|
---|
820 | default: putchar('?');
|
---|
821 | }
|
---|
822 | printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
|
---|
823 | printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
|
---|
824 | printperm(ip->i_mode, 0, STICKY_BIT, 't');
|
---|
825 | printf(" %3u ", ip->i_nlinks);
|
---|
826 | switch (ip->i_mode & I_TYPE) {
|
---|
827 | case I_CHAR_SPECIAL:
|
---|
828 | case I_BLOCK_SPECIAL:
|
---|
829 | printf(" %2x,%2x ", (dev_t) ip->i_zone[0] >> MAJOR & 0xFF,
|
---|
830 | (dev_t) ip->i_zone[0] >> MINOR & 0xFF);
|
---|
831 | break;
|
---|
832 | default: printf("%7ld ", ip->i_size);
|
---|
833 | }
|
---|
834 | printpath(0, 1);
|
---|
835 | }
|
---|
836 |
|
---|
837 | /* Remove an entry from a directory if ok with the user.
|
---|
838 | * Don't name the function remove() - that is owned by ANSI, and chaos results
|
---|
839 | * when it is a macro.
|
---|
840 | */
|
---|
841 | int Remove(dp)
|
---|
842 | dir_struct *dp;
|
---|
843 | {
|
---|
844 | setbit(spec_imap, (bit_nr) dp->d_inum);
|
---|
845 | if (yes(". remove entry")) {
|
---|
846 | count[dp->d_inum]--;
|
---|
847 | memset((void *) dp, 0, sizeof(dir_struct));
|
---|
848 | return(1);
|
---|
849 | }
|
---|
850 | return(0);
|
---|
851 | }
|
---|
852 |
|
---|
853 | /* Convert string so that embedded control characters are printable. */
|
---|
854 | void make_printable_name(dst, src, n)
|
---|
855 | register char *dst;
|
---|
856 | register char *src;
|
---|
857 | register int n;
|
---|
858 | {
|
---|
859 | register int c;
|
---|
860 |
|
---|
861 | while (--n >= 0 && (c = *src++) != '\0') {
|
---|
862 | if (isprint(c) && c != '\\')
|
---|
863 | *dst++ = c;
|
---|
864 | else {
|
---|
865 | *dst++ = '\\';
|
---|
866 | switch (c) {
|
---|
867 | case '\\':
|
---|
868 | *dst++ = '\\'; break;
|
---|
869 | case '\b':
|
---|
870 | *dst++ = 'b'; break;
|
---|
871 | case '\f':
|
---|
872 | *dst++ = 'f'; break;
|
---|
873 | case '\n':
|
---|
874 | *dst++ = 'n'; break;
|
---|
875 | case '\r':
|
---|
876 | *dst++ = 'r'; break;
|
---|
877 | case '\t':
|
---|
878 | *dst++ = 't'; break;
|
---|
879 | default:
|
---|
880 | *dst++ = '0' + ((c >> 6) & 03);
|
---|
881 | *dst++ = '0' + ((c >> 3) & 07);
|
---|
882 | *dst++ = '0' + (c & 07);
|
---|
883 | }
|
---|
884 | }
|
---|
885 | }
|
---|
886 | *dst = '\0';
|
---|
887 | }
|
---|
888 |
|
---|
889 | /* See if the `.' or `..' entry is as expected. */
|
---|
890 | int chkdots(ino, pos, dp, exp)
|
---|
891 | ino_t ino, exp;
|
---|
892 | off_t pos;
|
---|
893 | dir_struct *dp;
|
---|
894 | {
|
---|
895 | char printable_name[4 * NAME_MAX + 1];
|
---|
896 |
|
---|
897 | if (dp->d_inum != exp) {
|
---|
898 | make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
|
---|
899 | printf("bad %s in ", printable_name);
|
---|
900 | printpath(1, 0);
|
---|
901 | printf("%s is linked to %u ", printable_name, dp->d_inum);
|
---|
902 | printf("instead of %u)", exp);
|
---|
903 | setbit(spec_imap, (bit_nr) ino);
|
---|
904 | setbit(spec_imap, (bit_nr) dp->d_inum);
|
---|
905 | setbit(spec_imap, (bit_nr) exp);
|
---|
906 | if (yes(". repair")) {
|
---|
907 | count[dp->d_inum]--;
|
---|
908 | dp->d_inum = exp;
|
---|
909 | count[exp]++;
|
---|
910 | return(0);
|
---|
911 | }
|
---|
912 | } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) {
|
---|
913 | make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
|
---|
914 | printf("warning: %s has offset %ld in ", printable_name, pos);
|
---|
915 | printpath(1, 0);
|
---|
916 | printf("%s is linked to %u)\n", printable_name, dp->d_inum);
|
---|
917 | setbit(spec_imap, (bit_nr) ino);
|
---|
918 | setbit(spec_imap, (bit_nr) dp->d_inum);
|
---|
919 | setbit(spec_imap, (bit_nr) exp);
|
---|
920 | }
|
---|
921 | return(1);
|
---|
922 | }
|
---|
923 |
|
---|
924 | /* Check the name in a directory entry. */
|
---|
925 | int chkname(ino, dp)
|
---|
926 | ino_t ino;
|
---|
927 | dir_struct *dp;
|
---|
928 | {
|
---|
929 | register n = NAME_MAX + 1;
|
---|
930 | register char *p = dp->d_name;
|
---|
931 |
|
---|
932 | if (*p == '\0') {
|
---|
933 | printf("null name found in ");
|
---|
934 | printpath(0, 0);
|
---|
935 | setbit(spec_imap, (bit_nr) ino);
|
---|
936 | if (Remove(dp)) return(0);
|
---|
937 | }
|
---|
938 | while (*p != '\0' && --n != 0)
|
---|
939 | if (*p++ == '/') {
|
---|
940 | printf("found a '/' in entry of directory ");
|
---|
941 | printpath(1, 0);
|
---|
942 | setbit(spec_imap, (bit_nr) ino);
|
---|
943 | printf("entry = '");
|
---|
944 | printname(dp->d_name);
|
---|
945 | printf("')");
|
---|
946 | if (Remove(dp)) return(0);
|
---|
947 | break;
|
---|
948 | }
|
---|
949 | return(1);
|
---|
950 | }
|
---|
951 |
|
---|
952 | /* Check a directory entry. Here the routine `descendtree' is called
|
---|
953 | * recursively to check the file or directory pointed to by the entry.
|
---|
954 | */
|
---|
955 | int chkentry(ino, pos, dp)
|
---|
956 | ino_t ino;
|
---|
957 | off_t pos;
|
---|
958 | dir_struct *dp;
|
---|
959 | {
|
---|
960 | if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
|
---|
961 | printf("bad inode found in directory ");
|
---|
962 | printpath(1, 0);
|
---|
963 | printf("ino found = %u, ", dp->d_inum);
|
---|
964 | printf("name = '");
|
---|
965 | printname(dp->d_name);
|
---|
966 | printf("')");
|
---|
967 | if (yes(". remove entry")) {
|
---|
968 | memset((void *) dp, 0, sizeof(dir_struct));
|
---|
969 | return(0);
|
---|
970 | }
|
---|
971 | return(1);
|
---|
972 | }
|
---|
973 | if ((unsigned) count[dp->d_inum] == CHAR_MAX) {
|
---|
974 | printf("too many links to ino %u\n", dp->d_inum);
|
---|
975 | printf("discovered at entry '");
|
---|
976 | printname(dp->d_name);
|
---|
977 | printf("' in directory ");
|
---|
978 | printpath(0, 1);
|
---|
979 | if (Remove(dp)) return(0);
|
---|
980 | }
|
---|
981 | count[dp->d_inum]++;
|
---|
982 | if (strcmp(dp->d_name, ".") == 0) {
|
---|
983 | ftop->st_presence |= DOT;
|
---|
984 | return(chkdots(ino, pos, dp, ino));
|
---|
985 | }
|
---|
986 | if (strcmp(dp->d_name, "..") == 0) {
|
---|
987 | ftop->st_presence |= DOTDOT;
|
---|
988 | return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
|
---|
989 | ftop->st_next->st_dir->d_inum));
|
---|
990 | }
|
---|
991 | if (!chkname(ino, dp)) return(0);
|
---|
992 | if (bitset(dirmap, (bit_nr) dp->d_inum)) {
|
---|
993 | printf("link to directory discovered in ");
|
---|
994 | printpath(1, 0);
|
---|
995 | printf("name = '");
|
---|
996 | printname(dp->d_name);
|
---|
997 | printf("', dir ino = %u)", dp->d_inum);
|
---|
998 | return !Remove(dp);
|
---|
999 | }
|
---|
1000 | return(descendtree(dp));
|
---|
1001 | }
|
---|
1002 |
|
---|
1003 | /* Check a zone of a directory by checking all the entries in the zone.
|
---|
1004 | * The zone is split up into chunks to not allocate too much stack.
|
---|
1005 | */
|
---|
1006 | int chkdirzone(ino, ip, pos, zno)
|
---|
1007 | ino_t ino;
|
---|
1008 | d_inode *ip;
|
---|
1009 | off_t pos;
|
---|
1010 | zone_nr zno;
|
---|
1011 | {
|
---|
1012 | dir_struct dirblk[CDIRECT];
|
---|
1013 | register dir_struct *dp;
|
---|
1014 | register n = SCALE * (NR_DIR_ENTRIES(BLOCK_SIZE) / CDIRECT), dirty;
|
---|
1015 | register long offset = zaddr(zno);
|
---|
1016 | register off_t size = 0;
|
---|
1017 |
|
---|
1018 | do {
|
---|
1019 | devread(offset, (char *) dirblk, DIRCHUNK);
|
---|
1020 | dirty = 0;
|
---|
1021 | for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
|
---|
1022 | if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
|
---|
1023 | dirty = 1;
|
---|
1024 | pos += DIR_ENTRY_SIZE;
|
---|
1025 | if (dp->d_inum != NO_ENTRY) size = pos;
|
---|
1026 | }
|
---|
1027 | if (dirty) devwrite(offset, (char *) dirblk, DIRCHUNK);
|
---|
1028 | offset += DIRCHUNK;
|
---|
1029 | } while (--n);
|
---|
1030 |
|
---|
1031 | if (size > ip->i_size) {
|
---|
1032 | printf("size not updated of directory ");
|
---|
1033 | printpath(2, 0);
|
---|
1034 | if (yes(". extend")) {
|
---|
1035 | setbit(spec_imap, (bit_nr) ino);
|
---|
1036 | ip->i_size = size;
|
---|
1037 | devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
|
---|
1038 | }
|
---|
1039 | }
|
---|
1040 | return(1);
|
---|
1041 | }
|
---|
1042 |
|
---|
1043 | /* There is something wrong with the given zone. Print some details. */
|
---|
1044 | void errzone(mess, zno, level, pos)
|
---|
1045 | char *mess;
|
---|
1046 | zone_nr zno;
|
---|
1047 | int level;
|
---|
1048 | off_t pos;
|
---|
1049 | {
|
---|
1050 | printf("%s zone in ", mess);
|
---|
1051 | printpath(1, 0);
|
---|
1052 | printf("zno = %u, type = ", zno);
|
---|
1053 | switch (level) {
|
---|
1054 | case 0: printf("DATA"); break;
|
---|
1055 | case 1: printf("SINGLE INDIRECT"); break;
|
---|
1056 | case 2: printf("DOUBLE INDIRECT"); break;
|
---|
1057 | default: printf("VERY INDIRECT");
|
---|
1058 | }
|
---|
1059 | printf(", pos = %ld)\n", pos);
|
---|
1060 | }
|
---|
1061 |
|
---|
1062 | /* Found the given zone in the given inode. Check it, and if ok, mark it
|
---|
1063 | * in the zone bitmap.
|
---|
1064 | */
|
---|
1065 | int markzone(ino, zno, level, pos)
|
---|
1066 | ino_t ino;
|
---|
1067 | zone_nr zno;
|
---|
1068 | int level;
|
---|
1069 | off_t pos;
|
---|
1070 | {
|
---|
1071 | register bit_nr bit = (bit_nr) zno - FIRST + 1;
|
---|
1072 |
|
---|
1073 | ztype[level]++;
|
---|
1074 | if (zno < FIRST || zno >= sb.s_nzones) {
|
---|
1075 | errzone("out-of-range", zno, level, pos);
|
---|
1076 | return(0);
|
---|
1077 | }
|
---|
1078 | if (bitset(zmap, bit)) {
|
---|
1079 | setbit(spec_zmap, bit);
|
---|
1080 | errzone("duplicate", zno, level, pos);
|
---|
1081 | return(0);
|
---|
1082 | }
|
---|
1083 | nfreezone--;
|
---|
1084 | if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
|
---|
1085 | setbit(zmap, bit);
|
---|
1086 | return(1);
|
---|
1087 | }
|
---|
1088 |
|
---|
1089 | /* Check an indirect zone by checking all of its entries.
|
---|
1090 | * The zone is split up into chunks to not allocate too much stack.
|
---|
1091 | */
|
---|
1092 | int chkindzone(ino, ip, pos, zno, level)
|
---|
1093 | ino_t ino;
|
---|
1094 | d_inode *ip;
|
---|
1095 | off_t *pos;
|
---|
1096 | zone_nr zno;
|
---|
1097 | int level;
|
---|
1098 | {
|
---|
1099 | zone_nr indirect[CINDIR];
|
---|
1100 | register n = NR_INDIRECTS / CINDIR;
|
---|
1101 | register long offset = zaddr(zno);
|
---|
1102 |
|
---|
1103 | do {
|
---|
1104 | devread(offset, (char *) indirect, INDCHUNK);
|
---|
1105 | if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
|
---|
1106 | offset += INDCHUNK;
|
---|
1107 | } while (--n && *pos < ip->i_size);
|
---|
1108 | return(1);
|
---|
1109 | }
|
---|
1110 |
|
---|
1111 | /* Return the size of a gap in the file, represented by a null zone number
|
---|
1112 | * at some level of indirection.
|
---|
1113 | */
|
---|
1114 | off_t jump(level)
|
---|
1115 | int level;
|
---|
1116 | {
|
---|
1117 | off_t power = ZONE_SIZE;
|
---|
1118 |
|
---|
1119 | if (level != 0) do
|
---|
1120 | power *= NR_INDIRECTS;
|
---|
1121 | while (--level);
|
---|
1122 | return(power);
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 | /* Check a zone, which may be either a normal data zone, a directory zone,
|
---|
1126 | * or an indirect zone.
|
---|
1127 | */
|
---|
1128 | int zonechk(ino, ip, pos, zno, level)
|
---|
1129 | ino_t ino;
|
---|
1130 | d_inode *ip;
|
---|
1131 | off_t *pos;
|
---|
1132 | zone_nr zno;
|
---|
1133 | int level;
|
---|
1134 | {
|
---|
1135 | if (level == 0) {
|
---|
1136 | if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
|
---|
1137 | !chkdirzone(ino, ip, *pos, zno))
|
---|
1138 | return(0);
|
---|
1139 | *pos += ZONE_SIZE;
|
---|
1140 | return(1);
|
---|
1141 | } else
|
---|
1142 | return chkindzone(ino, ip, pos, zno, level);
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | /* Check a list of zones given by `zlist'. */
|
---|
1146 | int chkzones(ino, ip, pos, zlist, len, level)
|
---|
1147 | ino_t ino;
|
---|
1148 | d_inode *ip;
|
---|
1149 | off_t *pos;
|
---|
1150 | zone_nr *zlist;
|
---|
1151 | int len;
|
---|
1152 | int level;
|
---|
1153 | {
|
---|
1154 | register ok = 1, i;
|
---|
1155 |
|
---|
1156 | /* The check on the position in the next loop is commented out, since FS
|
---|
1157 | * now requires valid zone numbers in each level that is necessary and FS
|
---|
1158 | * always deleted all the zones in the double indirect block.
|
---|
1159 | */
|
---|
1160 | for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
|
---|
1161 | if (zlist[i] == NO_ZONE)
|
---|
1162 | *pos += jump(level);
|
---|
1163 | else if (!markzone(ino, zlist[i], level, *pos)) {
|
---|
1164 | *pos += jump(level);
|
---|
1165 | ok = 0;
|
---|
1166 | } else if (!zonechk(ino, ip, pos, zlist[i], level))
|
---|
1167 | ok = 0;
|
---|
1168 | return(ok);
|
---|
1169 | }
|
---|
1170 |
|
---|
1171 | /* Check a file or a directory. */
|
---|
1172 | int chkfile(ino, ip)
|
---|
1173 | ino_t ino;
|
---|
1174 | d_inode *ip;
|
---|
1175 | {
|
---|
1176 | register ok, i, level;
|
---|
1177 | off_t pos = 0;
|
---|
1178 |
|
---|
1179 | ok = chkzones(ino, ip, &pos, (zone_nr *)&ip->i_zone[0], NR_DZONE_NUM, 0);
|
---|
1180 | for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
|
---|
1181 | ok &= chkzones(ino, ip, &pos, (zone_nr *)&ip->i_zone[i], 1, level);
|
---|
1182 | return(ok);
|
---|
1183 | }
|
---|
1184 |
|
---|
1185 | /* Check a directory by checking the contents. Check if . and .. are present. */
|
---|
1186 | int chkdirectory(ino, ip)
|
---|
1187 | ino_t ino;
|
---|
1188 | d_inode *ip;
|
---|
1189 | {
|
---|
1190 | register ok;
|
---|
1191 |
|
---|
1192 | setbit(dirmap, (bit_nr) ino);
|
---|
1193 | ok = chkfile(ino, ip);
|
---|
1194 | if (!(ftop->st_presence & DOT)) {
|
---|
1195 | printf(". missing in ");
|
---|
1196 | printpath(2, 1);
|
---|
1197 | ok = 0;
|
---|
1198 | }
|
---|
1199 | if (!(ftop->st_presence & DOTDOT)) {
|
---|
1200 | printf(".. missing in ");
|
---|
1201 | printpath(2, 1);
|
---|
1202 | ok = 0;
|
---|
1203 | }
|
---|
1204 | return(ok);
|
---|
1205 | }
|
---|
1206 |
|
---|
1207 | #ifdef I_SYMBOLIC_LINK
|
---|
1208 |
|
---|
1209 | /* Check the validity of a symbolic link. */
|
---|
1210 | int chklink(ino, ip)
|
---|
1211 | ino_t ino;
|
---|
1212 | d_inode *ip;
|
---|
1213 | {
|
---|
1214 | int ok;
|
---|
1215 |
|
---|
1216 | ok = chkfile(ino, ip);
|
---|
1217 | if (ip->i_size <= 0 || ip->i_size > BLOCK_SIZE) {
|
---|
1218 | if (ip->i_size == 0)
|
---|
1219 | printf("empty symbolic link ");
|
---|
1220 | else
|
---|
1221 | printf("symbolic link too large (size %ld) ", ip->i_size);
|
---|
1222 | printpath(2, 1);
|
---|
1223 | ok = 0;
|
---|
1224 | }
|
---|
1225 | return(ok);
|
---|
1226 | }
|
---|
1227 |
|
---|
1228 | #endif
|
---|
1229 |
|
---|
1230 | /* Check the validity of a special file. */
|
---|
1231 | int chkspecial(ino, ip)
|
---|
1232 | ino_t ino;
|
---|
1233 | d_inode *ip;
|
---|
1234 | {
|
---|
1235 | int i, ok;
|
---|
1236 |
|
---|
1237 | ok = 1;
|
---|
1238 | if ((dev_t) ip->i_zone[0] == NO_DEV) {
|
---|
1239 | printf("illegal device number %u for special file ", ip->i_zone[0]);
|
---|
1240 | printpath(2, 1);
|
---|
1241 | ok = 0;
|
---|
1242 | }
|
---|
1243 |
|
---|
1244 | /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
|
---|
1245 | * they are nonzero, since this should not happen.
|
---|
1246 | */
|
---|
1247 | for (i = 1; i < NR_ZONE_NUMS; i++)
|
---|
1248 | if (ip->i_zone[i] != NO_ZONE) {
|
---|
1249 | printf("nonzero zone number %u for special file ",
|
---|
1250 | ip->i_zone[i]);
|
---|
1251 | printpath(2, 1);
|
---|
1252 | ok = 0;
|
---|
1253 | }
|
---|
1254 | return(ok);
|
---|
1255 | }
|
---|
1256 |
|
---|
1257 | /* Check the mode and contents of an inode. */
|
---|
1258 | int chkmode(ino, ip)
|
---|
1259 | ino_t ino;
|
---|
1260 | d_inode *ip;
|
---|
1261 | {
|
---|
1262 | switch (ip->i_mode & I_TYPE) {
|
---|
1263 | case I_REGULAR:
|
---|
1264 | nregular++;
|
---|
1265 | return chkfile(ino, ip);
|
---|
1266 | case I_DIRECTORY:
|
---|
1267 | ndirectory++;
|
---|
1268 | return chkdirectory(ino, ip);
|
---|
1269 | case I_BLOCK_SPECIAL:
|
---|
1270 | nblkspec++;
|
---|
1271 | return chkspecial(ino, ip);
|
---|
1272 | case I_CHAR_SPECIAL:
|
---|
1273 | ncharspec++;
|
---|
1274 | return chkspecial(ino, ip);
|
---|
1275 | case I_NAMED_PIPE:
|
---|
1276 | npipe++;
|
---|
1277 | return chkfile(ino, ip);
|
---|
1278 | #ifdef I_SYMBOLIC_LINK
|
---|
1279 | case I_SYMBOLIC_LINK:
|
---|
1280 | nsyml++;
|
---|
1281 | return chklink(ino, ip);
|
---|
1282 | #endif
|
---|
1283 | default:
|
---|
1284 | nbadinode++;
|
---|
1285 | printf("bad mode of ");
|
---|
1286 | printpath(1, 0);
|
---|
1287 | printf("mode = %o)", ip->i_mode);
|
---|
1288 | return(0);
|
---|
1289 | }
|
---|
1290 | }
|
---|
1291 |
|
---|
1292 | /* Check an inode. */
|
---|
1293 | int chkinode(ino, ip)
|
---|
1294 | ino_t ino;
|
---|
1295 | d_inode *ip;
|
---|
1296 | {
|
---|
1297 | if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
|
---|
1298 | printf("root inode is not a directory ");
|
---|
1299 | printf("(ino = %u, mode = %o)\n", ino, ip->i_mode);
|
---|
1300 | fatal("");
|
---|
1301 | }
|
---|
1302 | if (ip->i_nlinks == 0) {
|
---|
1303 | printf("link count zero of ");
|
---|
1304 | printpath(2, 0);
|
---|
1305 | return(0);
|
---|
1306 | }
|
---|
1307 | nfreeinode--;
|
---|
1308 | setbit(imap, (bit_nr) ino);
|
---|
1309 | if ((unsigned) ip->i_nlinks > CHAR_MAX) {
|
---|
1310 | printf("link count too big in ");
|
---|
1311 | printpath(1, 0);
|
---|
1312 | printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
|
---|
1313 | count[ino] -= CHAR_MAX;
|
---|
1314 | setbit(spec_imap, (bit_nr) ino);
|
---|
1315 | } else
|
---|
1316 | count[ino] -= (unsigned) ip->i_nlinks;
|
---|
1317 | return chkmode(ino, ip);
|
---|
1318 | }
|
---|
1319 |
|
---|
1320 | /* Check the directory entry pointed to by dp, by checking the inode. */
|
---|
1321 | int descendtree(dp)
|
---|
1322 | dir_struct *dp;
|
---|
1323 | {
|
---|
1324 | d_inode inode;
|
---|
1325 | register ino_t ino = dp->d_inum;
|
---|
1326 | register visited;
|
---|
1327 | struct stack stk;
|
---|
1328 |
|
---|
1329 | stk.st_dir = dp;
|
---|
1330 | stk.st_next = ftop;
|
---|
1331 | ftop = &stk;
|
---|
1332 | if (bitset(spec_imap, (bit_nr) ino)) {
|
---|
1333 | printf("found inode %u: ", ino);
|
---|
1334 | printpath(0, 1);
|
---|
1335 | }
|
---|
1336 | visited = bitset(imap, (bit_nr) ino);
|
---|
1337 | if (!visited || listing) {
|
---|
1338 | devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
|
---|
1339 | if (listing) list(ino, &inode);
|
---|
1340 | if (!visited && !chkinode(ino, &inode)) {
|
---|
1341 | setbit(spec_imap, (bit_nr) ino);
|
---|
1342 | if (yes("remove")) {
|
---|
1343 | count[ino] += inode.i_nlinks - 1;
|
---|
1344 | clrbit(imap, (bit_nr) ino);
|
---|
1345 | devwrite(inoaddr(ino), nullbuf, INODE_SIZE);
|
---|
1346 | memset((void *) dp, 0, sizeof(dir_struct));
|
---|
1347 | ftop = ftop->st_next;
|
---|
1348 | return(0);
|
---|
1349 | }
|
---|
1350 | }
|
---|
1351 | }
|
---|
1352 | ftop = ftop->st_next;
|
---|
1353 | return(1);
|
---|
1354 | }
|
---|
1355 |
|
---|
1356 | /* Check the file system tree. */
|
---|
1357 | void chktree()
|
---|
1358 | {
|
---|
1359 | dir_struct dir;
|
---|
1360 |
|
---|
1361 | nfreeinode = sb.s_ninodes;
|
---|
1362 | nfreezone = N_DATA;
|
---|
1363 | dir.d_inum = ROOT_INODE;
|
---|
1364 | dir.d_name[0] = 0;
|
---|
1365 | if (!descendtree(&dir)) fatal("bad root inode");
|
---|
1366 | putchar('\n');
|
---|
1367 | }
|
---|
1368 |
|
---|
1369 | /* Print the totals of all the objects found. */
|
---|
1370 | void printtotal()
|
---|
1371 | {
|
---|
1372 | printf("blocksize = %5d ", BLOCK_SIZE);
|
---|
1373 | printf("zonesize = %5d\n", ZONE_SIZE);
|
---|
1374 | printf("\n");
|
---|
1375 | pr("%6u Regular file%s\n", nregular, "", "s");
|
---|
1376 | pr("%6u Director%s\n", ndirectory, "y", "ies");
|
---|
1377 | pr("%6u Block special file%s\n", nblkspec, "", "s");
|
---|
1378 | pr("%6u Character special file%s\n", ncharspec, "", "s");
|
---|
1379 | if (nbadinode != 0) pr("%6u Bad inode%s\n", nbadinode, "", "s");
|
---|
1380 | pr("%6u Free inode%s\n", nfreeinode, "", "s");
|
---|
1381 | pr("%6u Named pipe%s\n", npipe, "", "s");
|
---|
1382 | pr("%6u Symbolic link%s\n", nsyml, "", "s");
|
---|
1383 | /* Don't print some fields.
|
---|
1384 | printf("\n");
|
---|
1385 | pr("%6u Data zone%s\n", ztype[0], "", "s");
|
---|
1386 | pr("%6u Single indirect zone%s\n", ztype[1], "", "s");
|
---|
1387 | pr("%6u Double indirect zone%s\n", ztype[2], "", "s");
|
---|
1388 | */
|
---|
1389 | pr("%6u Free zone%s\n", nfreezone, "", "s");
|
---|
1390 | }
|
---|
1391 |
|
---|
1392 | /* Check the device which name is given by `f'. The inodes listed by `clist'
|
---|
1393 | * should be listed separately, and the inodes listed by `ilist' and the zones
|
---|
1394 | * listed by `zlist' should be watched for while checking the file system.
|
---|
1395 | */
|
---|
1396 |
|
---|
1397 | void chkdev(f, clist, ilist, zlist)
|
---|
1398 | char *f, **clist, **ilist, **zlist;
|
---|
1399 | {
|
---|
1400 | if (automatic) repair = 1;
|
---|
1401 | device = f;
|
---|
1402 | initvars();
|
---|
1403 |
|
---|
1404 | devopen();
|
---|
1405 |
|
---|
1406 | getsuper();
|
---|
1407 | chksuper();
|
---|
1408 |
|
---|
1409 | lsi(clist);
|
---|
1410 |
|
---|
1411 | getbitmaps();
|
---|
1412 |
|
---|
1413 | fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
|
---|
1414 | fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_nzones, zlist);
|
---|
1415 |
|
---|
1416 | getcount();
|
---|
1417 | chktree();
|
---|
1418 | chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
|
---|
1419 | chkcount();
|
---|
1420 | chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
|
---|
1421 | chkilist();
|
---|
1422 | printtotal();
|
---|
1423 |
|
---|
1424 | putbitmaps();
|
---|
1425 | freecount();
|
---|
1426 | devclose();
|
---|
1427 |
|
---|
1428 | if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
|
---|
1429 | }
|
---|
1430 |
|
---|
1431 | int main(argc, argv)
|
---|
1432 | int argc;
|
---|
1433 | char **argv;
|
---|
1434 | {
|
---|
1435 | register char **clist = 0, **ilist = 0, **zlist = 0;
|
---|
1436 |
|
---|
1437 | register devgiven = 0;
|
---|
1438 | register char *arg;
|
---|
1439 |
|
---|
1440 | if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
|
---|
1441 | printf("Fsck was compiled with the wrong BITSHIFT!\n");
|
---|
1442 | exit(1);
|
---|
1443 | }
|
---|
1444 |
|
---|
1445 | sync();
|
---|
1446 | prog = *argv++;
|
---|
1447 | while ((arg = *argv++) != 0)
|
---|
1448 | if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
|
---|
1449 | case 'a': automatic ^= 1; break;
|
---|
1450 | case 'c':
|
---|
1451 | clist = getlist(&argv, "inode");
|
---|
1452 | break;
|
---|
1453 | case 'i':
|
---|
1454 | ilist = getlist(&argv, "inode");
|
---|
1455 | break;
|
---|
1456 | case 'z':
|
---|
1457 | zlist = getlist(&argv, "zone");
|
---|
1458 | break;
|
---|
1459 | case 'r': repair ^= 1; break;
|
---|
1460 | case 'l': listing ^= 1; break;
|
---|
1461 | case 's': listsuper ^= 1; break;
|
---|
1462 | default:
|
---|
1463 | printf("%s: unknown flag '%s'\n", prog, arg);
|
---|
1464 | }
|
---|
1465 | else {
|
---|
1466 | chkdev(arg, clist, ilist, zlist);
|
---|
1467 | clist = 0;
|
---|
1468 | ilist = 0;
|
---|
1469 | zlist = 0;
|
---|
1470 | devgiven = 1;
|
---|
1471 | }
|
---|
1472 | if (!devgiven) {
|
---|
1473 | printf("Usage: fsck1 [-acilrsz] file\n");
|
---|
1474 | exit(1);
|
---|
1475 | }
|
---|
1476 | return(0);
|
---|
1477 | }
|
---|