fsck.c

Go to the documentation of this file.
00001 /* Hacks for version 1.6 */                                     
00002 
00003 #define INODES_PER_BLOCK V2_INODES_PER_BLOCK(block_size)
00004 #define INODE_SIZE ((int) V2_INODE_SIZE)
00005 #define WORDS_PER_BLOCK (block_size / (int) sizeof(bitchunk_t))
00006 #define MAX_ZONES (V2_NR_DZONES+V2_INDIRECTS(block_size)+(long)V2_INDIRECTS(block_size)*V2_INDIRECTS(block_size))
00007 #define NR_DZONE_NUM V2_NR_DZONES
00008 #define NR_INDIRECTS V2_INDIRECTS(block_size)
00009 #define NR_ZONE_NUMS V2_NR_TZONES
00010 #define ZONE_NUM_SIZE V2_ZONE_NUM_SIZE
00011 #define bit_nr bit_t
00012 #define block_nr block_t
00013 #define d_inode d2_inode
00014 #define d_inum d_ino
00015 #define dir_struct struct direct
00016 #define i_mode d2_mode
00017 #define i_nlinks d2_nlinks
00018 #define i_size d2_size
00019 #define i_zone d2_zone
00020 #define zone_nr zone_t
00021 
00022 /* fsck - file system checker           Author: Robbert van Renesse */
00023 
00024 /* Modified by Norbert Schlenker
00025 *   Removed vestiges of standalone/DOS versions:
00026 *     - various unused variables and buffers removed
00027 *     - now uses library functions rather than private internal routines
00028 *     - bytewise structure copies replaced by structure assignment
00029 *     - fixed one bug with 14 character file names
00030 *     - other small tweaks for speed
00031 *
00032 * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
00033 *   Removed -m option, by which fsck could be told to make a file
00034 *   system on a 360K floppy.  The code had limited utility, was buggy,
00035 *   and failed due to a bug in the ACK C compiler.  Use mkfs instead!
00036 */
00037 
00038 #include <sys/types.h>
00039 #include <sys/dir.h>
00040 #include <ctype.h>
00041 #include <errno.h>
00042 #include <fcntl.h>
00043 #include <limits.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #include <minix/config.h>
00048 #include <minix/const.h>
00049 #include <minix/type.h>
00050 #include "../../servers/fs/const.h"
00051 #include "../../servers/fs/inode.h"
00052 #include "../../servers/fs/type.h"
00053 #include <minix/fslib.h>
00054 #include <stdio.h>
00055 #include <sys/stat.h>
00056 #include <a.out.h>
00057 #include <tools.h>
00058 #include <dirent.h>
00059 
00060 #undef N_DATA
00061 
00062 unsigned int fs_version = 2, block_size = 0;
00063 
00064 #define BITSHIFT          4     /* = log2(#bits(int)) */
00065 
00066 #define MAXPRINT          80    /* max. number of error lines in chkmap */
00067 #define CINDIR          128     /* number of indirect zno's read at a time */
00068 #define CDIRECT           1     /* number of dir entries read at a time */
00069 
00070 /* Macros for handling bitmaps.  Now bit_t is long, these are bulky and the
00071  * type demotions produce a lot of lint.  The explicit demotion in POWEROFBIT
00072  * is for efficiency and assumes 2's complement ints.  Lint should be clever
00073  * enough not to warn about it since BITMASK is small, but isn't.  (It would
00074  * be easier to get right if bit_t was was unsigned (long) since then there
00075  * would be no danger from wierd sign representations.  Lint doesn't know
00076  * we only use non-negative bit numbers.) There will usually be an implicit
00077  * demotion when WORDOFBIT is used as an array index.  This should be safe
00078  * since memory for bitmaps will run out first.
00079  */
00080 #define BITMASK         ((1 << BITSHIFT) - 1)
00081 #define WORDOFBIT(b)    ((b) >> BITSHIFT)
00082 #define POWEROFBIT(b)   (1 << ((int) (b) & BITMASK))
00083 #define setbit(w, b)    (w[WORDOFBIT(b)] |= POWEROFBIT(b))
00084 #define clrbit(w, b)    (w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
00085 #define bitset(w, b)    (w[WORDOFBIT(b)] & POWEROFBIT(b))
00086 
00087 #define ZONE_CT         360     /* default zones  (when making file system) */
00088 #define INODE_CT         95     /* default inodes (when making file system) */
00089 
00090 #include "../../servers/fs/super.h"
00091 static struct super_block sb;
00092 
00093 #define STICKY_BIT      01000   /* not defined anywhere else */
00094 
00095 /* Ztob gives the block address of a zone
00096  * btoa gives the byte address of a block
00097  */
00098 #define ztob(z)         ((block_nr) (z) << sb.s_log_zone_size)
00099 #define btoa(b)         ((long) (b) * block_size)
00100 #define SCALE           ((int) ztob(1)) /* # blocks in a zone */
00101 #define FIRST           ((zone_nr) sb.s_firstdatazone)  /* as the name says */
00102 
00103 /* # blocks of each type */
00104 #define N_IMAP          (sb.s_imap_blocks)
00105 #define N_ZMAP          (sb.s_zmap_blocks)
00106 #define N_ILIST         ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
00107 #define N_DATA          (sb.s_zones - FIRST)
00108 
00109 /* Block address of each type */
00110 #define OFFSET_SUPER_BLOCK      SUPER_BLOCK_BYTES
00111 #define BLK_IMAP        2
00112 #define BLK_ZMAP        (BLK_IMAP  + N_IMAP)
00113 #define BLK_ILIST       (BLK_ZMAP  + N_ZMAP)
00114 #define BLK_FIRST       ztob(FIRST)
00115 #define ZONE_SIZE       ((int) ztob(block_size))
00116 #define NLEVEL          (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
00117 
00118 /* Byte address of a zone/of an inode */
00119 #define zaddr(z)        btoa(ztob(z))
00120 #define cinoaddr(i)     ((long) (i - 1) * INODE_SIZE + (long) btoa(BLK_ILIST))
00121 #define INDCHUNK        ((int) (CINDIR * ZONE_NUM_SIZE))
00122 #define DIRCHUNK        ((int) (CDIRECT * DIR_ENTRY_SIZE))
00123 
00124 char *prog, *fsck_device;               /* program name (fsck), device name */
00125 int firstcnterr;                /* is this the first inode ref cnt error? */
00126 bitchunk_t *imap, *spec_imap;   /* inode bit maps */
00127 bitchunk_t *zmap, *spec_zmap;   /* zone bit maps */
00128 bitchunk_t *dirmap;             /* directory (inode) bit map */
00129 char *rwbuf;                    /* one block buffer cache */
00130 block_nr thisblk;               /* block in buffer cache */
00131 char *nullbuf;  /* null buffer */
00132 nlink_t *count;                 /* inode count */
00133 int changed;                    /* has the diskette been written to? */
00134 struct stack {
00135   dir_struct *st_dir;
00136   struct stack *st_next;
00137   char st_presence;
00138 } *ftop;
00139 
00140 int dev;                        /* file descriptor of the device */
00141 
00142 #define DOT     1
00143 #define DOTDOT  2
00144 
00145 /* Counters for each type of inode/zone. */
00146 int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
00147 int npipe, nsyml, ztype[NLEVEL];
00148 long nfreezone;
00149 
00150 int repair, automatic, listing, listsuper;      /* flags */
00151 int firstlist;                  /* has the listing header been printed? */
00152 unsigned part_offset;           /* sector offset for this partition */
00153 char answer[] = "Answer questions with y or n.  Then hit RETURN";
00154 
00155 _PROTOTYPE(int main, (int argc, char **argv));
00156 _PROTOTYPE(void initvars, (void));
00157 _PROTOTYPE(void fatal, (char *s));
00158 _PROTOTYPE(int eoln, (int c));
00159 _PROTOTYPE(int yes, (char *question));
00160 _PROTOTYPE(int atoo, (char *s));
00161 _PROTOTYPE(int input, (char *buf, int size));
00162 _PROTOTYPE(char *alloc, (unsigned nelem, unsigned elsize));
00163 _PROTOTYPE(void printname, (char *s));
00164 _PROTOTYPE(void printrec, (struct stack *sp));
00165 _PROTOTYPE(void printpath, (int mode, int nlcr));
00166 _PROTOTYPE(void devopen, (void));
00167 _PROTOTYPE(void devclose, (void));
00168 _PROTOTYPE(void devio, (block_nr bno, int dir));
00169 _PROTOTYPE(void devread, (long offset, char *buf, int size));
00170 _PROTOTYPE(void devwrite, (long offset, char *buf, int size));
00171 _PROTOTYPE(void pr, (char *fmt, int cnt, char *s, char *p));
00172 _PROTOTYPE(void lpr, (char *fmt, long cnt, char *s, char *p));
00173 _PROTOTYPE(bit_nr getnumber, (char *s));
00174 _PROTOTYPE(char **getlist, (char ***argv, char *type));
00175 _PROTOTYPE(void lsuper, (void));
00176 _PROTOTYPE(void getsuper, (void));
00177 _PROTOTYPE(void chksuper, (void));
00178 _PROTOTYPE(void lsi, (char **clist));
00179 _PROTOTYPE(bitchunk_t *allocbitmap, (int nblk));
00180 _PROTOTYPE(void loadbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
00181 _PROTOTYPE(void dumpbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
00182 _PROTOTYPE(void fillbitmap, (bitchunk_t *bitmap, bit_nr lwb, bit_nr upb, char **list));
00183 _PROTOTYPE(void freebitmap, (bitchunk_t *p));
00184 _PROTOTYPE(void getbitmaps, (void));
00185 _PROTOTYPE(void putbitmaps, (void));
00186 _PROTOTYPE(void chkword, (unsigned w1, unsigned w2, bit_nr bit, char *type, int *n, int *report, bit_t));
00187 _PROTOTYPE(void chkmap, (bitchunk_t *cmap, bitchunk_t *dmap, bit_nr bit, block_nr blkno, int nblk, char *type));
00188 _PROTOTYPE(void chkilist, (void));
00189 _PROTOTYPE(void getcount, (void));
00190 _PROTOTYPE(void counterror, (Ino_t ino));
00191 _PROTOTYPE(void chkcount, (void));
00192 _PROTOTYPE(void freecount, (void));
00193 _PROTOTYPE(void printperm, (mode_t mode, int shift, int special, int overlay));
00194 _PROTOTYPE(void list, (Ino_t ino, d_inode *ip));
00195 _PROTOTYPE(int Remove, (dir_struct *dp));
00196 _PROTOTYPE(void make_printable_name, (char *dst, char *src, int n));
00197 _PROTOTYPE(int chkdots, (Ino_t ino, off_t pos, dir_struct *dp, Ino_t exp));
00198 _PROTOTYPE(int chkname, (Ino_t ino, dir_struct *dp));
00199 _PROTOTYPE(int chkentry, (Ino_t ino, off_t pos, dir_struct *dp));
00200 _PROTOTYPE(int chkdirzone, (Ino_t ino, d_inode *ip, off_t pos, zone_nr zno));
00201 _PROTOTYPE(int chksymlinkzone, (Ino_t ino, d_inode *ip, off_t pos,
00202                                                                 zone_nr zno));
00203 _PROTOTYPE(void errzone, (char *mess, zone_nr zno, int level, off_t pos));
00204 _PROTOTYPE(int markzone, (zone_nr zno, int level, off_t pos));
00205 _PROTOTYPE(int chkindzone, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
00206 _PROTOTYPE(off_t jump, (int level));
00207 _PROTOTYPE(int zonechk, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
00208 _PROTOTYPE(int chkzones, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int len, int level));
00209 _PROTOTYPE(int chkfile, (Ino_t ino, d_inode *ip));
00210 _PROTOTYPE(int chkdirectory, (Ino_t ino, d_inode *ip));
00211 _PROTOTYPE(int chklink, (Ino_t ino, d_inode *ip));
00212 _PROTOTYPE(int chkspecial, (Ino_t ino, d_inode *ip));
00213 _PROTOTYPE(int chkmode, (Ino_t ino, d_inode *ip));
00214 _PROTOTYPE(int chkinode, (Ino_t ino, d_inode *ip));
00215 _PROTOTYPE(int descendtree, (dir_struct *dp));
00216 _PROTOTYPE(void chktree, (void));
00217 _PROTOTYPE(void printtotal, (void));
00218 _PROTOTYPE(void chkdev, (char *f, char **clist, char **ilist, char **zlist));
00219 
00220 /* Initialize the variables used by this program. */
00221 void initvars()
00222 {
00223   register level;
00224 
00225   nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = nsyml = 0;
00226   for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
00227   changed = 0;
00228   thisblk = NO_BLOCK;
00229   firstlist = 1;
00230   firstcnterr = 1;
00231 }
00232 
00233 /* Print the string `s' and exit. */
00234 void fatal(s)
00235 char *s;
00236 {
00237   printf("%s\nfatal\n", s);
00238   exit(-1);
00239 }
00240 
00241 /* Test for end of line. */
00242 int eoln(c)
00243 int c;
00244 {
00245   return(c == EOF || c == '\n' || c == '\r');
00246 }
00247 
00248 /* Ask a question and get the answer unless automatic is set. */
00249 int yes(question)
00250 char *question;
00251 {
00252   register int c, answerchar;
00253   static int note = 0;
00254 
00255   if (!repair) {
00256         printf("\n");
00257         return(0);
00258   }
00259   printf("%s? ", question);
00260   if(!note) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note = 1; }
00261   if (automatic) {
00262         printf("yes\n");
00263         return(1);
00264   }
00265   fflush(stdout);
00266   if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(1);
00267   if(c == 'A') { automatic = 1; c = 'y'; }
00268   while (!eoln(c)) c = getchar();
00269   return !(answerchar == 'n' || answerchar == 'N');
00270 }
00271 
00272 /* Convert string to integer.  Representation is octal. */
00273 int atoo(s)
00274 register char *s;
00275 {
00276   register int n = 0;
00277 
00278   while ('0' <= *s && *s < '8') {
00279         n <<= 3;
00280         n += *s++ - '0';
00281   }
00282   return n;
00283 }
00284 
00285 /* If repairing the file system, print a prompt and get a string from user. */
00286 int input(buf, size)
00287 char *buf;
00288 int size;
00289 {
00290   register char *p = buf;
00291 
00292   printf("\n");
00293   if (repair) {
00294         printf("--> ");
00295         fflush(stdout);
00296         while (--size) {
00297                 *p = getchar();
00298                 if (eoln(*p)) {
00299                         *p = 0;
00300                         return(p > buf);
00301                 }
00302                 p++;
00303         }
00304         *p = 0;
00305         while (!eoln(getchar()));
00306         return(1);
00307   }
00308   return(0);
00309 }
00310 
00311 /* Allocate some memory and zero it. */
00312 char *alloc(nelem, elsize)
00313 unsigned nelem, elsize;
00314 {
00315   char *p;
00316 
00317   if ((p = (char *)malloc((size_t)nelem * elsize)) == 0) {
00318         fprintf(stderr, "Tried to allocate %dkB\n",
00319                 nelem*elsize/1024);
00320         fatal("out of memory");
00321   }
00322   memset((void *) p, 0, (size_t)nelem * elsize);
00323   return(p);
00324 }
00325 
00326 /* Print the name in a directory entry. */
00327 void printname(s)
00328 char *s;
00329 {
00330   register n = NAME_MAX;
00331   int c;
00332 
00333   do {
00334         if ((c = *s) == 0) break;
00335         if (!isprint(c)) c = '?';
00336         putchar(c);
00337         s++;
00338   } while (--n);
00339 }
00340 
00341 /* Print the pathname given by a linked list pointed to by `sp'.  The
00342  * names are in reverse order.
00343  */
00344 void printrec(sp)
00345 struct stack *sp;
00346 {
00347   if (sp->st_next != 0) {
00348         printrec(sp->st_next);
00349         putchar('/');
00350         printname(sp->st_dir->d_name);
00351   }
00352 }
00353 
00354 /* Print the current pathname.  */
00355 void printpath(mode, nlcr)
00356 int mode;
00357 int nlcr;
00358 {
00359   if (ftop->st_next == 0)
00360         putchar('/');
00361   else
00362         printrec(ftop);
00363   switch (mode) {
00364       case 1:
00365         printf(" (ino = %u, ", ftop->st_dir->d_inum);
00366         break;
00367       case 2:
00368         printf(" (ino = %u)", ftop->st_dir->d_inum);
00369         break;
00370   }
00371   if (nlcr) printf("\n");
00372 }
00373 
00374 /* Open the device.  */
00375 void devopen()
00376 {
00377   if ((dev = open(fsck_device, repair ? O_RDWR : O_RDONLY)) < 0) {
00378         perror(fsck_device);
00379         fatal("couldn't open device to fsck");
00380   }
00381 }
00382 
00383 /* Close the device. */
00384 void devclose()
00385 {
00386   if (close(dev) != 0) {
00387         perror("close");
00388         fatal("");
00389   }
00390 }
00391 
00392 /* Read or write a block. */
00393 void devio(bno, dir)
00394 block_nr bno;
00395 int dir;
00396 {
00397   if(!block_size) fatal("devio() with unknown block size");
00398   if (dir == READING && bno == thisblk) return;
00399   thisblk = bno;
00400 
00401 #if 0
00402 printf("%s at block %5d\n", dir == READING ? "reading " : "writing", bno);
00403 #endif
00404   lseek(dev, (off_t) btoa(bno), SEEK_SET);
00405   if (dir == READING) {
00406         if (read(dev, rwbuf, block_size) == block_size)
00407                 return;
00408   } else {
00409         if (write(dev, rwbuf, block_size) == block_size)
00410                 return;
00411   }
00412 
00413   printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
00414          dir == READING ? "read" : "write", (long) bno, errno);
00415   if (dir == READING) {
00416         printf("Continuing with a zero-filled block.\n");
00417         memset(rwbuf, 0, block_size);
00418         return;
00419   }
00420   fatal("");
00421 }
00422 
00423 /* Read `size' bytes from the disk starting at byte `offset'. */
00424 void devread(offset, buf, size)
00425 long offset;
00426 char *buf;
00427 int size;
00428 {
00429   if(!block_size) fatal("devread() with unknown block size");
00430   devio((block_nr) (offset / block_size), READING);
00431   memmove(buf, &rwbuf[(int) (offset % block_size)], (size_t)size);  /* lint but OK */
00432 }
00433 
00434 /* Write `size' bytes to the disk starting at byte `offset'. */
00435 void devwrite(offset, buf, size)
00436 long offset;
00437 char *buf;
00438 int size;
00439 {
00440   if(!block_size) fatal("devwrite() with unknown block size");
00441   if (!repair) fatal("internal error (devwrite)");
00442   if (size != block_size) devio((block_nr) (offset / block_size), READING);
00443   memmove(&rwbuf[(int) (offset % block_size)], buf, (size_t)size);  /* lint but OK */
00444   devio((block_nr) (offset / block_size), WRITING);
00445   changed = 1;
00446 }
00447 
00448 /* Print a string with either a singular or a plural pronoun. */
00449 void pr(fmt, cnt, s, p)
00450 char *fmt, *s, *p;
00451 int cnt;
00452 {
00453   printf(fmt, cnt, cnt == 1 ? s : p);
00454 }
00455 
00456 /* Same as above, but with a long argument */
00457 void lpr(fmt, cnt, s, p)
00458 char *fmt, *s, *p;
00459 long cnt;
00460 {
00461   printf(fmt, cnt, cnt == 1 ? s : p);
00462 }
00463 
00464 /* Convert string to number. */
00465 bit_nr getnumber(s)
00466 register char *s;
00467 {
00468   register bit_nr n = 0;
00469 
00470   if (s == NULL)
00471         return NO_BIT;
00472   while (isdigit(*s))
00473         n = (n << 1) + (n << 3) + *s++ - '0';
00474   return (*s == '\0') ? n : NO_BIT;
00475 }
00476 
00477 /* See if the list pointed to by `argv' contains numbers. */
00478 char **getlist(argv, type)
00479 char ***argv, *type;
00480 {
00481   register char **list = *argv;
00482   register empty = 1;
00483 
00484   while (getnumber(**argv) != NO_BIT) {
00485         (*argv)++;
00486         empty = 0;
00487   }
00488   if (empty) {
00489         printf("warning: no %s numbers given\n", type);
00490         return(NULL);
00491   }
00492   return(list);
00493 }
00494 
00495 /* Make a listing of the super block.  If `repair' is set, ask the user
00496  * for changes.
00497  */
00498 void lsuper()
00499 {
00500   char buf[80];
00501 
00502   do {
00503         /* Most of the following atol's enrage lint, for good reason. */  
00504         printf("ninodes       = %u", sb.s_ninodes);
00505         if (input(buf, 80)) sb.s_ninodes = atol(buf);
00506         printf("nzones        = %ld", sb.s_zones);
00507         if (input(buf, 80)) sb.s_zones = atol(buf);
00508         printf("imap_blocks   = %u", sb.s_imap_blocks);
00509         if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
00510         printf("zmap_blocks   = %u", sb.s_zmap_blocks);
00511         if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
00512         printf("firstdatazone = %u", sb.s_firstdatazone);
00513         if (input(buf, 80)) sb.s_firstdatazone = atol(buf);
00514         printf("log_zone_size = %u", sb.s_log_zone_size);
00515         if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
00516         printf("maxsize       = %ld", sb.s_max_size);
00517         if (input(buf, 80)) sb.s_max_size = atol(buf);
00518         printf("block size    = %ld", sb.s_block_size);
00519         if (input(buf, 80)) sb.s_block_size = atol(buf);
00520         if (yes("ok now")) {
00521                 devwrite(OFFSET_SUPER_BLOCK, (char *) &sb, sizeof(sb));
00522                 return;
00523         }
00524   } while (yes("Do you want to try again"));
00525   if (repair) exit(0);
00526 }
00527 
00528 /* Get the super block from either disk or user.  Do some initial checks. */
00529 void getsuper()
00530 {
00531   if(lseek(dev, OFFSET_SUPER_BLOCK, SEEK_SET) < 0) {
00532         perror("lseek");
00533         fatal("couldn't seek to super block.");
00534   }
00535   if(read(dev, &sb, sizeof(sb)) != sizeof(sb)) {
00536         fatal("couldn't read super block.");
00537   }
00538   if (listsuper) lsuper();
00539   if (sb.s_magic == SUPER_MAGIC) fatal("Cannot handle V1 file systems");
00540   if (sb.s_magic == SUPER_V2) {
00541         fs_version = 2;
00542         block_size = /* STATIC_BLOCK_SIZE */ 8192;
00543   } else if(sb.s_magic == SUPER_V3) {
00544         fs_version = 3;
00545         block_size = sb.s_block_size;
00546   } else {
00547         fatal("bad magic number in super block");
00548   }
00549   if (sb.s_ninodes <= 0) fatal("no inodes");
00550   if (sb.s_zones <= 0) fatal("no zones");
00551   if (sb.s_imap_blocks <= 0) fatal("no imap");
00552   if (sb.s_zmap_blocks <= 0) fatal("no zmap");
00553   if (sb.s_firstdatazone <= 4) fatal("first data zone too small");
00554   if (sb.s_log_zone_size < 0) fatal("zone size < block size");
00555   if (sb.s_max_size <= 0) fatal("max. file size <= 0");
00556 
00557 }
00558 
00559 /* Check the super block for reasonable contents. */
00560 void chksuper()
00561 {
00562   register n;
00563   register off_t maxsize;
00564 
00565   n = bitmapsize((bit_t) sb.s_ninodes + 1, block_size);
00566   if (sb.s_magic != SUPER_V2 && sb.s_magic != SUPER_V3)
00567         fatal("bad magic number in super block");
00568   if (sb.s_imap_blocks < n) {
00569         printf("need %d bocks for inode bitmap; only have %d\n",
00570                 n, sb.s_imap_blocks);
00571         fatal("too few imap blocks");
00572   }
00573   if (sb.s_imap_blocks != n) {
00574         pr("warning: expected %d imap_block%s", n, "", "s");
00575         printf(" instead of %d\n", sb.s_imap_blocks);
00576   }
00577   n = bitmapsize((bit_t) sb.s_zones, block_size);
00578   if (sb.s_zmap_blocks < n) fatal("too few zmap blocks");
00579   if (sb.s_zmap_blocks != n) {
00580         pr("warning: expected %d zmap_block%s", n, "", "s");
00581         printf(" instead of %d\n", sb.s_zmap_blocks);
00582   }
00583   if (sb.s_firstdatazone >= sb.s_zones)
00584         fatal("first data zone too large");
00585   if (sb.s_log_zone_size >= 8 * sizeof(block_nr))
00586         fatal("log_zone_size too large");
00587   if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
00588                sb.s_log_zone_size);
00589   n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
00590   if (sb.s_firstdatazone < n) fatal("first data zone too small");
00591   if (sb.s_firstdatazone != n) {
00592         printf("warning: expected first data zone to be %d ", n);
00593         printf("instead of %u\n", sb.s_firstdatazone);
00594   }
00595   maxsize = MAX_FILE_POS;
00596   if (((maxsize - 1) >> sb.s_log_zone_size) / block_size >= MAX_ZONES)
00597         maxsize = ((long) MAX_ZONES * block_size) << sb.s_log_zone_size;
00598   if (sb.s_max_size != maxsize) {
00599         printf("warning: expected max size to be %ld ", maxsize);
00600         printf("instead of %ld\n", sb.s_max_size);
00601   }
00602 }
00603 
00604 int inoaddr(int inn)
00605 {
00606         int a;
00607         a = cinoaddr(inn);
00608         return a;
00609 }
00610 
00611 /* Make a listing of the inodes given by `clist'.  If `repair' is set, ask
00612  * the user for changes.
00613  */
00614 void lsi(clist)
00615 char **clist;
00616 {
00617   register bit_nr bit;
00618   register ino_t ino;
00619   d_inode inode, *ip = &inode;
00620   char buf[80];
00621 
00622   if (clist == 0) return;
00623   while ((bit = getnumber(*clist++)) != NO_BIT) {
00624         setbit(spec_imap, bit);
00625         ino = bit;
00626         do {
00627                 devread(inoaddr(ino), (char *) ip, INODE_SIZE);
00628                 printf("inode %u:\n", ino);
00629                 printf("    mode   = %6o", ip->i_mode);
00630                 if (input(buf, 80)) ip->i_mode = atoo(buf);
00631                 printf("    nlinks = %6u", ip->i_nlinks);
00632                 if (input(buf, 80)) ip->i_nlinks = atol(buf);
00633                 printf("    size   = %6ld", ip->i_size);
00634                 if (input(buf, 80)) ip->i_size = atol(buf);
00635                 if (yes("Write this back")) {
00636                         devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
00637                         break;
00638                 }
00639         } while (yes("Do you want to change it again"));
00640   }
00641 }
00642 
00643 /* Allocate `nblk' blocks worth of bitmap. */
00644 bitchunk_t *allocbitmap(nblk)
00645 int nblk;
00646 {
00647   register bitchunk_t *bitmap;
00648 
00649   bitmap = (bitchunk_t *) alloc((unsigned) nblk, block_size);
00650   *bitmap |= 1;
00651   return(bitmap);
00652 }
00653 
00654 /* Load the bitmap starting at block `bno' from disk. */
00655 void loadbitmap(bitmap, bno, nblk)
00656 bitchunk_t *bitmap;
00657 block_nr bno;
00658 int nblk;
00659 {
00660   register i;
00661   register bitchunk_t *p;
00662 
00663   p = bitmap;
00664   for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
00665         devread(btoa(bno), (char *) p, block_size);
00666   *bitmap |= 1;
00667 }
00668 
00669 /* Write the bitmap starting at block `bno' to disk. */
00670 void dumpbitmap(bitmap, bno, nblk)
00671 bitchunk_t *bitmap;
00672 block_nr bno;
00673 int nblk;
00674 {
00675   register i;
00676   register bitchunk_t *p = bitmap;
00677 
00678   for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
00679         devwrite(btoa(bno), (char *) p, block_size);
00680 }
00681 
00682 /* Set the bits given by `list' in the bitmap. */
00683 void fillbitmap(bitmap, lwb, upb, list)
00684 bitchunk_t *bitmap;
00685 bit_nr lwb, upb;
00686 char **list;
00687 {
00688   register bit_nr bit;
00689 
00690   if (list == 0) return;
00691   while ((bit = getnumber(*list++)) != NO_BIT)
00692         if (bit < lwb || bit >= upb) {
00693                 if (bitmap == spec_imap)
00694                         printf("inode number %ld ", bit);
00695                 else
00696                         printf("zone number %ld ", bit);
00697                 printf("out of range (ignored)\n");
00698         } else
00699                 setbit(bitmap, bit - lwb + 1);
00700 }
00701 
00702 /* Deallocate the bitmap `p'. */
00703 void freebitmap(p)
00704 bitchunk_t *p;
00705 {
00706   free((char *) p);
00707 }
00708 
00709 /* Get all the bitmaps used by this program. */
00710 void getbitmaps()
00711 {
00712   imap = allocbitmap(N_IMAP);
00713   zmap = allocbitmap(N_ZMAP);
00714   spec_imap = allocbitmap(N_IMAP);
00715   spec_zmap = allocbitmap(N_ZMAP);
00716   dirmap = allocbitmap(N_IMAP);
00717 }
00718 
00719 /* Release all the space taken by the bitmaps. */
00720 void putbitmaps()
00721 {
00722   freebitmap(imap);
00723   freebitmap(zmap);
00724   freebitmap(spec_imap);
00725   freebitmap(spec_zmap);
00726   freebitmap(dirmap);
00727 }
00728 
00729 /* `w1' and `w2' are differing words from two bitmaps that should be
00730  * identical.  Print what's the matter with them.
00731  */
00732 void chkword(w1, w2, bit, type, n, report, phys)
00733 unsigned w1, w2;
00734 char *type;
00735 bit_nr bit;
00736 int *n, *report;
00737 bit_nr phys;
00738 {
00739   for (; (w1 | w2); w1 >>= 1, w2 >>= 1, bit++, phys++)
00740         if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
00741             (!repair || automatic || yes("stop this listing")))
00742                 *report = 0;
00743         else if (*report)
00744                 if ((w1 & 1) && !(w2 & 1))
00745                         printf("%s %ld (%ld) is missing\n", type, bit, phys);
00746                 else if (!(w1 & 1) && (w2 & 1))
00747                         printf("%s %ld (%ld) is not free\n", type, bit, phys);
00748 }
00749 
00750 /* Check if the given (correct) bitmap is identical with the one that is
00751  * on the disk.  If not, ask if the disk should be repaired.
00752  */
00753 void chkmap(cmap, dmap, bit, blkno, nblk, type)
00754 bitchunk_t *cmap, *dmap;
00755 bit_nr bit;
00756 block_nr blkno;
00757 int nblk;
00758 char *type;
00759 {
00760   register bitchunk_t *p = dmap, *q = cmap;
00761   int report = 1, nerr = 0;
00762   int w = nblk * WORDS_PER_BLOCK;
00763   bit_nr phys = 0;
00764 
00765   printf("Checking %s map\n", type);
00766   loadbitmap(dmap, blkno, nblk);
00767   do {
00768         if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
00769         p++;
00770         q++;
00771         bit += 8 * sizeof(bitchunk_t);
00772         phys += 8 * sizeof(bitchunk_t);
00773   } while (--w > 0);
00774 
00775   if ((!repair || automatic) && !report) printf("etc. ");
00776   if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
00777   if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
00778   if (nerr > 0) printf("\n");
00779 }
00780 
00781 /* See if the inodes that aren't allocated are cleared. */
00782 void chkilist()
00783 {
00784   register ino_t ino = 1;
00785   mode_t mode;
00786 
00787   printf("Checking inode list\n");
00788   do
00789         if (!bitset(imap, (bit_nr) ino)) {
00790                 devread(inoaddr(ino), (char *) &mode, sizeof(mode));
00791                 if (mode != I_NOT_ALLOC) {
00792                         printf("mode inode %u not cleared", ino);
00793                         if (yes(". clear")) devwrite(inoaddr(ino), nullbuf,
00794                                          INODE_SIZE);
00795                 }
00796         }
00797   while (++ino <= sb.s_ninodes && ino != 0);
00798   printf("\n");
00799 }
00800 
00801 /* Allocate an array to maintain the inode reference counts in. */
00802 void getcount()
00803 {
00804   count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
00805 }
00806 
00807 /* The reference count for inode `ino' is wrong.  Ask if it should be adjusted. */
00808 void counterror(ino)
00809 ino_t ino;
00810 {
00811   d_inode inode;
00812 
00813   if (firstcnterr) {
00814         printf("INODE NLINK COUNT\n");
00815         firstcnterr = 0;
00816   }
00817   devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
00818   count[ino] += inode.i_nlinks; /* it was already subtracted; add it back */
00819   printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
00820   if (yes(" adjust")) {
00821         if ((inode.i_nlinks = count[ino]) == 0) {
00822                 fatal("internal error (counterror)");
00823                 inode.i_mode = I_NOT_ALLOC;
00824                 clrbit(imap, (bit_nr) ino);
00825         }
00826         devwrite(inoaddr(ino), (char *) &inode, INODE_SIZE);
00827   }
00828 }
00829 
00830 /* Check if the reference count of the inodes are correct.  The array `count'
00831  * is maintained as follows:  an entry indexed by the inode number is
00832  * incremented each time a link is found; when the inode is read the link
00833  * count in there is substracted from the corresponding entry in `count'.
00834  * Thus, when the whole file system has been traversed, all the entries
00835  * should be zero.
00836  */
00837 void chkcount()
00838 {
00839   register ino_t ino;
00840 
00841   for (ino = 1; ino <= sb.s_ninodes && ino != 0; ino++)
00842         if (count[ino] != 0) counterror(ino);
00843   if (!firstcnterr) printf("\n");
00844 }
00845 
00846 /* Deallocate the `count' array. */
00847 void freecount()
00848 {
00849   free((char *) count);
00850 }
00851 
00852 /* Print the inode permission bits given by mode and shift. */
00853 void printperm(mode_t mode, int shift, int special, int overlay)
00854 {
00855   if (mode >> shift & R_BIT)
00856         putchar('r');
00857   else
00858         putchar('-');
00859   if (mode >> shift & W_BIT)
00860         putchar('w');
00861   else
00862         putchar('-');
00863   if (mode & special)
00864         putchar(overlay);
00865   else
00866         if (mode >> shift & X_BIT)
00867                 putchar('x');
00868         else
00869                 putchar('-');
00870 }
00871 
00872 /* List the given inode. */
00873 void list(ino, ip)
00874 ino_t ino;
00875 d_inode *ip;
00876 {
00877   if (firstlist) {
00878         firstlist = 0;
00879         printf(" inode permission link   size name\n");
00880   }
00881   printf("%6u ", ino);
00882   switch (ip->i_mode & I_TYPE) {
00883       case I_REGULAR:           putchar('-');   break;
00884       case I_DIRECTORY:         putchar('d');   break;
00885       case I_CHAR_SPECIAL:      putchar('c');   break;
00886       case I_BLOCK_SPECIAL:     putchar('b');   break;
00887       case I_NAMED_PIPE:        putchar('p');   break;
00888 #ifdef I_SYMBOLIC_LINK
00889       case I_SYMBOLIC_LINK:     putchar('l');   break;
00890 #endif
00891       default:                  putchar('?');
00892 }
00893   printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
00894   printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
00895   printperm(ip->i_mode, 0, STICKY_BIT, 't');
00896   printf(" %3u ", ip->i_nlinks);
00897   switch (ip->i_mode & I_TYPE) {
00898       case I_CHAR_SPECIAL:
00899       case I_BLOCK_SPECIAL:
00900         printf("  %2x,%2x ", (dev_t) ip->i_zone[0] >> MAJOR & 0xFF,
00901                (dev_t) ip->i_zone[0] >> MINOR & 0xFF);
00902         break;
00903       default:  printf("%7ld ", ip->i_size);
00904   }
00905   printpath(0, 1);
00906 }
00907 
00908 /* Remove an entry from a directory if ok with the user.
00909  * Don't name the function remove() - that is owned by ANSI, and chaos results
00910  * when it is a macro.
00911  */
00912 int Remove(dp)
00913 dir_struct *dp;
00914 {
00915   setbit(spec_imap, (bit_nr) dp->d_inum);
00916   if (yes(". remove entry")) {
00917         count[dp->d_inum]--;
00918         memset((void *) dp, 0, sizeof(dir_struct));
00919         return(1);
00920   }
00921   return(0);
00922 }
00923 
00924 /* Convert string so that embedded control characters are printable. */
00925 void make_printable_name(dst, src, n)
00926 register char *dst;
00927 register char *src;
00928 register int n;
00929 {
00930   register int c;
00931 
00932   while (--n >= 0 && (c = *src++) != '\0') {
00933         if (isprint(c) && c != '\\')
00934                 *dst++ = c;
00935         else {
00936                 *dst++ = '\\';
00937                 switch (c) {
00938                       case '\\':
00939                         *dst++ = '\\'; break;
00940                       case '\b':
00941                         *dst++ = 'b'; break;
00942                       case '\f':
00943                         *dst++ = 'f'; break;
00944                       case '\n':
00945                         *dst++ = 'n'; break;
00946                       case '\r':
00947                         *dst++ = 'r'; break;
00948                       case '\t':
00949                         *dst++ = 't'; break;
00950                       default:
00951                         *dst++ = '0' + ((c >> 6) & 03);
00952                         *dst++ = '0' + ((c >> 3) & 07);
00953                         *dst++ = '0' + (c & 07);
00954                 }
00955         }
00956   }
00957   *dst = '\0';
00958 }
00959 
00960 /* See if the `.' or `..' entry is as expected. */
00961 int chkdots(ino, pos, dp, exp)
00962 ino_t ino, exp;
00963 off_t pos;
00964 dir_struct *dp;
00965 {
00966   char printable_name[4 * NAME_MAX + 1];
00967 
00968   if (dp->d_inum != exp) {
00969         make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
00970         printf("bad %s in ", printable_name);
00971         printpath(1, 0);
00972         printf("%s is linked to %u ", printable_name, dp->d_inum);
00973         printf("instead of %u)", exp);
00974         setbit(spec_imap, (bit_nr) ino);
00975         setbit(spec_imap, (bit_nr) dp->d_inum);
00976         setbit(spec_imap, (bit_nr) exp);
00977         if (yes(". repair")) {
00978                 count[dp->d_inum]--;
00979                 dp->d_inum = exp;
00980                 count[exp]++;
00981                 return(0);
00982         }
00983   } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) {
00984         make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
00985         printf("warning: %s has offset %ld in ", printable_name, pos);
00986         printpath(1, 0);
00987         printf("%s is linked to %u)\n", printable_name, dp->d_inum);
00988         setbit(spec_imap, (bit_nr) ino);
00989         setbit(spec_imap, (bit_nr) dp->d_inum);
00990         setbit(spec_imap, (bit_nr) exp);
00991   }
00992   return(1);
00993 }
00994 
00995 /* Check the name in a directory entry. */
00996 int chkname(ino, dp)
00997 ino_t ino;
00998 dir_struct *dp;
00999 {
01000   register n = NAME_MAX + 1;
01001   register char *p = dp->d_name;
01002 
01003   if (*p == '\0') {
01004         printf("null name found in ");
01005         printpath(0, 0);
01006         setbit(spec_imap, (bit_nr) ino);
01007         if (Remove(dp)) return(0);
01008   }
01009   while (*p != '\0' && --n != 0)
01010         if (*p++ == '/') {
01011                 printf("found a '/' in entry of directory ");
01012                 printpath(1, 0);
01013                 setbit(spec_imap, (bit_nr) ino);
01014                 printf("entry = '");
01015                 printname(dp->d_name);
01016                 printf("')");
01017                 if (Remove(dp)) return(0);
01018                 break;
01019         }
01020   return(1);
01021 }
01022 
01023 /* Check a directory entry.  Here the routine `descendtree' is called
01024  * recursively to check the file or directory pointed to by the entry.
01025  */
01026 int chkentry(ino, pos, dp)
01027 ino_t ino;
01028 off_t pos;
01029 dir_struct *dp;
01030 {
01031   if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
01032         printf("bad inode found in directory ");
01033         printpath(1, 0);
01034         printf("ino found = %u, ", dp->d_inum);
01035         printf("name = '");
01036         printname(dp->d_name);
01037         printf("')");
01038         if (yes(". remove entry")) {
01039                 memset((void *) dp, 0, sizeof(dir_struct));
01040                 return(0);
01041         }
01042         return(1);
01043   }
01044   if ((unsigned) count[dp->d_inum] == SHRT_MAX) {
01045         printf("too many links to ino %u\n", dp->d_inum);
01046         printf("discovered at entry '");
01047         printname(dp->d_name);
01048         printf("' in directory ");
01049         printpath(0, 1);
01050         if (Remove(dp)) return(0);
01051   }
01052   count[dp->d_inum]++;
01053   if (strcmp(dp->d_name, ".") == 0) {
01054         ftop->st_presence |= DOT;
01055         return(chkdots(ino, pos, dp, ino));
01056   }
01057   if (strcmp(dp->d_name, "..") == 0) {
01058         ftop->st_presence |= DOTDOT;
01059         return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
01060                         ftop->st_next->st_dir->d_inum));
01061   }
01062   if (!chkname(ino, dp)) return(0);
01063   if (bitset(dirmap, (bit_nr) dp->d_inum)) {
01064         printf("link to directory discovered in ");
01065         printpath(1, 0);
01066         printf("name = '");
01067         printname(dp->d_name);
01068         printf("', dir ino = %u)", dp->d_inum);
01069         return !Remove(dp);
01070   }
01071   return(descendtree(dp));
01072 }
01073 
01074 /* Check a zone of a directory by checking all the entries in the zone.
01075  * The zone is split up into chunks to not allocate too much stack.
01076  */
01077 int chkdirzone(ino, ip, pos, zno)
01078 ino_t ino;
01079 d_inode *ip;
01080 off_t pos;
01081 zone_nr zno;
01082 {
01083   dir_struct dirblk[CDIRECT];
01084   register dir_struct *dp;
01085   register n, dirty;
01086   register long offset = zaddr(zno);
01087   register off_t size = 0;
01088   n = SCALE * (NR_DIR_ENTRIES(block_size) / CDIRECT);
01089 
01090   do {
01091         devread(offset, (char *) dirblk, DIRCHUNK);
01092         dirty = 0;
01093         for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
01094                 if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
01095                         dirty = 1;
01096                 pos += DIR_ENTRY_SIZE;
01097                 if (dp->d_inum != NO_ENTRY) size = pos;
01098         }
01099         if (dirty) devwrite(offset, (char *) dirblk, DIRCHUNK);
01100         offset += DIRCHUNK;
01101         n--;
01102   } while (n > 0);
01103 
01104   if (size > ip->i_size) {
01105         printf("size not updated of directory ");
01106         printpath(2, 0);
01107         if (yes(". extend")) {
01108                 setbit(spec_imap, (bit_nr) ino);
01109                 ip->i_size = size;
01110                 devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
01111         }
01112   }
01113   return(1);
01114 }
01115 
01116 
01117 int chksymlinkzone(ino, ip, pos, zno)
01118 ino_t ino;
01119 d_inode *ip;
01120 off_t pos;
01121 zone_nr zno;
01122 {
01123         long offset;
01124         size_t len;
01125         char target[PATH_MAX+1];
01126 
01127         if (ip->i_size > PATH_MAX)
01128                 fatal("chksymlinkzone: fsck program inconsistency\n");
01129         offset = zaddr(zno);
01130         devread(offset, target, ip->i_size);
01131         target[ip->i_size]= '\0';
01132         len= strlen(target);
01133         if (len != ip->i_size)
01134         {
01135                 printf("bad size in symbolic link (%d instead of %d) ",
01136                         ip->i_size, len);
01137                 printpath(2, 0);
01138                 if (yes(". update")) {
01139                         setbit(spec_imap, (bit_nr) ino);
01140                         ip->i_size = len;
01141                         devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
01142                 }
01143         }
01144         return 1;
01145 }
01146 
01147 /* There is something wrong with the given zone.  Print some details. */
01148 void errzone(mess, zno, level, pos)
01149 char *mess;
01150 zone_nr zno;
01151 int level;
01152 off_t pos;
01153 {
01154   printf("%s zone in ", mess);
01155   printpath(1, 0);
01156   printf("zno = %ld, type = ", zno);
01157   switch (level) {
01158       case 0:   printf("DATA"); break;
01159       case 1:   printf("SINGLE INDIRECT");      break;
01160       case 2:   printf("DOUBLE INDIRECT");      break;
01161       default:  printf("VERY INDIRECT");
01162   }
01163   printf(", pos = %ld)\n", pos);
01164 }
01165 
01166 /* Found the given zone in the given inode.  Check it, and if ok, mark it
01167  * in the zone bitmap.
01168  */
01169 int markzone(zno, level, pos)
01170 zone_nr zno;
01171 int level;
01172 off_t pos;
01173 {
01174   register bit_nr bit = (bit_nr) zno - FIRST + 1;
01175 
01176   ztype[level]++;
01177   if (zno < FIRST || zno >= sb.s_zones) {
01178         errzone("out-of-range", zno, level, pos);
01179         return(0);
01180   }
01181   if (bitset(zmap, bit)) {
01182         setbit(spec_zmap, bit);
01183         errzone("duplicate", zno, level, pos);
01184         return(0);
01185   }
01186   nfreezone--;
01187   if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
01188   setbit(zmap, bit);
01189   return(1);
01190 }
01191 
01192 /* Check an indirect zone by checking all of its entries.
01193  * The zone is split up into chunks to not allocate too much stack.
01194  */
01195 int chkindzone(ino, ip, pos, zno, level)
01196 ino_t ino;
01197 d_inode *ip;
01198 off_t *pos;
01199 zone_nr zno;
01200 int level;
01201 {
01202   zone_nr indirect[CINDIR];
01203   register n = NR_INDIRECTS / CINDIR;
01204   register long offset = zaddr(zno);
01205 
01206   do {
01207         devread(offset, (char *) indirect, INDCHUNK);
01208         if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
01209         offset += INDCHUNK;
01210   } while (--n && *pos < ip->i_size);
01211   return(1);
01212 }
01213 
01214 /* Return the size of a gap in the file, represented by a null zone number
01215  * at some level of indirection.
01216  */
01217 off_t jump(level)
01218 int level;
01219 {
01220   off_t power = ZONE_SIZE;
01221 
01222   if (level != 0) do
01223                 power *= NR_INDIRECTS;
01224         while (--level);
01225   return(power);
01226 }
01227 
01228 /* Check a zone, which may be either a normal data zone, a directory zone,
01229  * or an indirect zone.
01230  */
01231 int zonechk(ino, ip, pos, zno, level)
01232 ino_t ino;
01233 d_inode *ip;
01234 off_t *pos;
01235 zone_nr zno;
01236 int level;
01237 {
01238   if (level == 0) {
01239         if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
01240             !chkdirzone(ino, ip, *pos, zno))
01241                 return(0);
01242         if ((ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK &&
01243             !chksymlinkzone(ino, ip, *pos, zno))
01244                 return(0);
01245         *pos += ZONE_SIZE;
01246         return(1);
01247   } else
01248         return chkindzone(ino, ip, pos, zno, level);
01249 }
01250 
01251 /* Check a list of zones given by `zlist'. */
01252 int chkzones(ino, ip, pos, zlist, len, level)
01253 ino_t ino;
01254 d_inode *ip;
01255 off_t *pos;
01256 zone_nr *zlist;
01257 int len;
01258 int level;
01259 {
01260   register ok = 1, i;
01261 
01262   /* The check on the position in the next loop is commented out, since FS
01263    * now requires valid zone numbers in each level that is necessary and FS
01264    * always deleted all the zones in the double indirect block.
01265    */
01266   for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
01267         if (zlist[i] == NO_ZONE)
01268                 *pos += jump(level);
01269         else if (!markzone(zlist[i], level, *pos)) {
01270                 *pos += jump(level);
01271                 ok = 0;
01272         } else if (!zonechk(ino, ip, pos, zlist[i], level))
01273                 ok = 0;
01274   return(ok);
01275 }
01276 
01277 /* Check a file or a directory. */
01278 int chkfile(ino, ip)
01279 ino_t ino;
01280 d_inode *ip;
01281 {
01282   register ok, i, level;
01283   off_t pos = 0;
01284 
01285   ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
01286   for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
01287         ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
01288   return(ok);
01289 }
01290 
01291 /* Check a directory by checking the contents.  Check if . and .. are present. */
01292 int chkdirectory(ino, ip)
01293 ino_t ino;
01294 d_inode *ip;
01295 {
01296   register ok;
01297 
01298   setbit(dirmap, (bit_nr) ino);
01299   ok = chkfile(ino, ip);
01300   if (!(ftop->st_presence & DOT)) {
01301         printf(". missing in ");
01302         printpath(2, 1);
01303         ok = 0;
01304   }
01305   if (!(ftop->st_presence & DOTDOT)) {
01306         printf(".. missing in ");
01307         printpath(2, 1);
01308         ok = 0;
01309   }
01310   return(ok);
01311 }
01312 
01313 #ifdef I_SYMBOLIC_LINK
01314 
01315 /* Check the validity of a symbolic link. */
01316 int chklink(ino, ip)
01317 ino_t ino;
01318 d_inode *ip;
01319 {
01320   int ok;
01321 
01322   ok = chkfile(ino, ip);
01323   if (ip->i_size <= 0 || ip->i_size > block_size) {
01324         if (ip->i_size == 0)
01325                 printf("empty symbolic link ");
01326         else
01327                 printf("symbolic link too large (size %ld) ", ip->i_size);
01328         printpath(2, 1);
01329         ok = 0;
01330   }
01331   return(ok);
01332 }
01333 
01334 #endif
01335 
01336 /* Check the validity of a special file. */
01337 int chkspecial(ino, ip)
01338 ino_t ino;
01339 d_inode *ip;
01340 {
01341   int i, ok;
01342 
01343   ok = 1;
01344   if ((dev_t) ip->i_zone[0] == NO_DEV) {
01345         printf("illegal device number %ld for special file ", ip->i_zone[0]);
01346         printpath(2, 1);
01347         ok = 0;
01348   }
01349 
01350   /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
01351    * they are nonzero, since this should not happen.
01352    */
01353   for (i = 1; i < NR_ZONE_NUMS; i++)
01354         if (ip->i_zone[i] != NO_ZONE) {
01355                 printf("nonzero zone number %ld for special file ",
01356                        ip->i_zone[i]);
01357                 printpath(2, 1);
01358                 ok = 0;
01359         }
01360   return(ok);
01361 }
01362 
01363 /* Check the mode and contents of an inode. */
01364 int chkmode(ino, ip)
01365 ino_t ino;
01366 d_inode *ip;
01367 {
01368   switch (ip->i_mode & I_TYPE) {
01369       case I_REGULAR:
01370         nregular++;
01371         return chkfile(ino, ip);
01372       case I_DIRECTORY:
01373         ndirectory++;
01374         return chkdirectory(ino, ip);
01375       case I_BLOCK_SPECIAL:
01376         nblkspec++;
01377         return chkspecial(ino, ip);
01378       case I_CHAR_SPECIAL:
01379         ncharspec++;
01380         return chkspecial(ino, ip);
01381       case I_NAMED_PIPE:
01382         npipe++;
01383         return chkfile(ino, ip);
01384 #ifdef I_SYMBOLIC_LINK
01385       case I_SYMBOLIC_LINK:
01386         nsyml++;
01387         return chklink(ino, ip);
01388 #endif
01389       default:
01390         nbadinode++;
01391         printf("bad mode of ");
01392         printpath(1, 0);
01393         printf("mode = %o)", ip->i_mode);
01394         return(0);
01395   }
01396 }
01397 
01398 /* Check an inode. */
01399 int chkinode(ino, ip)
01400 ino_t ino;
01401 d_inode *ip;
01402 {
01403   if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
01404         printf("root inode is not a directory ");
01405         printf("(ino = %u, mode = %o)\n", ino, ip->i_mode);
01406         fatal("");
01407   }
01408   if (ip->i_nlinks == 0) {
01409         printf("link count zero of ");
01410         printpath(2, 0);
01411         return(0);
01412   }
01413   nfreeinode--;
01414   setbit(imap, (bit_nr) ino);
01415   if ((unsigned) ip->i_nlinks > SHRT_MAX) {
01416         printf("link count too big in ");
01417         printpath(1, 0);
01418         printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
01419         count[ino] -= SHRT_MAX;
01420         setbit(spec_imap, (bit_nr) ino);
01421   } else {
01422         count[ino] -= (unsigned) ip->i_nlinks;
01423   }
01424   return chkmode(ino, ip);
01425 }
01426 
01427 /* Check the directory entry pointed to by dp, by checking the inode. */
01428 int descendtree(dp)
01429 dir_struct *dp;
01430 {
01431   d_inode inode;
01432   register ino_t ino = dp->d_inum;
01433   register visited;
01434   struct stack stk;
01435 
01436   stk.st_dir = dp;
01437   stk.st_next = ftop;
01438   ftop = &stk;
01439   if (bitset(spec_imap, (bit_nr) ino)) {
01440         printf("found inode %u: ", ino);
01441         printpath(0, 1);
01442   }
01443   visited = bitset(imap, (bit_nr) ino);
01444   if (!visited || listing) {
01445         devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
01446         if (listing) list(ino, &inode);
01447         if (!visited && !chkinode(ino, &inode)) {
01448                 setbit(spec_imap, (bit_nr) ino);
01449                 if (yes("remove")) {
01450                         count[ino] += inode.i_nlinks - 1;
01451                         clrbit(imap, (bit_nr) ino);
01452                         devwrite(inoaddr(ino), nullbuf, INODE_SIZE);
01453                         memset((void *) dp, 0, sizeof(dir_struct));
01454                         ftop = ftop->st_next;
01455                         return(0);
01456                 }
01457         }
01458   }
01459   ftop = ftop->st_next;
01460   return(1);
01461 }
01462 
01463 /* Check the file system tree. */
01464 void chktree()
01465 {
01466   dir_struct dir;
01467 
01468   nfreeinode = sb.s_ninodes;
01469   nfreezone = N_DATA;
01470   dir.d_inum = ROOT_INODE;
01471   dir.d_name[0] = 0;
01472   if (!descendtree(&dir)) fatal("bad root inode");
01473   putchar('\n');
01474 }
01475 
01476 /* Print the totals of all the objects found. */
01477 void printtotal()
01478 {
01479   printf("blocksize = %5d        ", block_size);
01480   printf("zonesize  = %5d\n", ZONE_SIZE);
01481   printf("\n");
01482   pr("%8u    Regular file%s\n", nregular, "", "s");
01483   pr("%8u    Director%s\n", ndirectory, "y", "ies");
01484   pr("%8u    Block special file%s\n", nblkspec, "", "s");
01485   pr("%8u    Character special file%s\n", ncharspec, "", "s");
01486   if (nbadinode != 0) pr("%6u    Bad inode%s\n", nbadinode, "", "s");
01487   pr("%8u    Free inode%s\n", nfreeinode, "", "s");
01488   pr("%8u    Named pipe%s\n", npipe, "", "s");
01489   pr("%8u    Symbolic link%s\n", nsyml, "", "s");
01490 /* Don't print some fields.
01491   printf("\n");
01492   pr("%8u    Data zone%s\n",              ztype[0],      "",   "s");
01493   pr("%8u    Single indirect zone%s\n",   ztype[1],      "",   "s");
01494   pr("%8u    Double indirect zone%s\n",   ztype[2],      "",   "s");
01495 */
01496   lpr("%8ld    Free zone%s\n", nfreezone, "", "s");
01497 }
01498 
01499 /* Check the device which name is given by `f'.  The inodes listed by `clist'
01500  * should be listed separately, and the inodes listed by `ilist' and the zones
01501  * listed by `zlist' should be watched for while checking the file system.
01502  */
01503 
01504 void chkdev(f, clist, ilist, zlist)
01505 char *f, **clist, **ilist, **zlist;
01506 {
01507   if (automatic) repair = 1;
01508   fsck_device = f;
01509   initvars();
01510 
01511   devopen();
01512 
01513   getsuper();
01514 
01515   if(block_size < _MIN_BLOCK_SIZE || block_size > _MAX_BLOCK_SIZE)
01516         fatal("funny block size");
01517 
01518   if(!(rwbuf = malloc(block_size))) fatal("couldn't allocate fs buf (1)");
01519   if(!(nullbuf = malloc(block_size))) fatal("couldn't allocate fs buf (2)");
01520   memset(nullbuf, 0, block_size);
01521 
01522   chksuper();
01523 
01524   lsi(clist);
01525 
01526   getbitmaps();
01527 
01528   fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
01529   fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
01530 
01531   getcount();
01532   chktree();
01533   chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
01534   chkcount();
01535   chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
01536   chkilist();
01537   printtotal();
01538 
01539   putbitmaps();
01540   freecount();
01541   devclose();
01542 
01543   if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
01544 }
01545 
01546 int main(argc, argv)
01547 int argc;
01548 char **argv;
01549 {
01550   register char **clist = 0, **ilist = 0, **zlist = 0;
01551 
01552   register devgiven = 0;
01553   register char *arg;
01554 
01555   if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
01556         printf("Fsck was compiled with the wrong BITSHIFT!\n");
01557         exit(1);
01558   }
01559 
01560   sync();
01561   prog = *argv++;
01562   while ((arg = *argv++) != 0)
01563         if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
01564                     case 'a':   automatic ^= 1; break;
01565                     case 'c':
01566                         clist = getlist(&argv, "inode");
01567                         break;
01568                     case 'i':
01569                         ilist = getlist(&argv, "inode");
01570                         break;
01571                     case 'z':
01572                         zlist = getlist(&argv, "zone");
01573                         break;
01574                     case 'r':   repair ^= 1;    break;
01575                     case 'l':   listing ^= 1;   break;
01576                     case 's':   listsuper ^= 1; break;
01577                     default:
01578                         printf("%s: unknown flag '%s'\n", prog, arg);
01579                 }
01580         else {
01581                 chkdev(arg, clist, ilist, zlist);
01582                 clist = 0;
01583                 ilist = 0;
01584                 zlist = 0;
01585                 devgiven = 1;
01586         }
01587   if (!devgiven) {
01588         printf("Usage: fsck [-acilrsz] file\n");
01589         exit(1);
01590   }
01591   return(0);
01592 }

Generated on Fri Apr 14 22:57:06 2006 for minix by  doxygen 1.4.6