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