ast@cs.vu.nl (Andy Tanenbaum) (10/17/88)
/* fsck - file system checker Author: Robbert van Renesse */ #include "../h/const.h" #include "../h/type.h" #include "../fs/const.h" #include "../fs/type.h" #ifndef STANDALONE #include <stdio.h> #endif /* Fsck may be compiled to run in any of two situations. * * - standalone, as part of the boot diskette used to bring MINIX up * - as a running MINIX program. * * When used for standalone operation, -DSTANDALONE must be used. * The following commands can be used to build a standalone version: * * cc -c -Di8088 -DSTANDALONE fsck.c * asld -o fsck fsck1.s fsck.s /usr/lib/libc.a /usr/lib/end.s * * Fsck1.s contains calls to the BIOS routines used by the standalone * version. The production version makes ordinary MINIX reads and writes. */ #define HEADS 4 /* # heads per cylinder */ #define TRACKSIZE 17 /* # sectors per track */ #define CYLSIZE (HEADS*TRACKSIZE) /* # sectors per cylinder */ #define BITSHIFT 4 /* = 2log(#bits(int)) */ #define BITMAPSHIFT 13 /* = 2log(#bits(block)); 13 means 1K blocks */ #define MAXPRINT 8 /* max. number of error lines in chkmap */ #define MAXWIDTH 32 /* max. width of an ``integer string'' */ #define MAXDIRSIZE 5000 /* max. size of a reasonable directory */ #define CINDIR 128 /* number of indirect zno's read at a time */ #define CDIRECT 16 /* number of dir entries read at a time */ #define SECT_SHIFT 9 /* sectors are 512 bytes */ #define SECTOR_SIZE (1<<SECT_SHIFT) /* bytes in a sector */ #define BITMASK ((1 << BITSHIFT) - 1) #define PARB 6 #define between(c,l,u) ((unsigned short) ((c) - (l)) <= ((u) - (l))) #define isprint(c) between(c, ' ', '~') #define isdigit(c) between(c, '0', '9') #define islower(c) between(c, 'a', 'z') #define isupper(c) between(c, 'A', 'Z') #define toupper(c) ( (c) + 'A' - 'a' ) #define quote(x) x #define nextarg(t) (*argp.quote(u_)t++) #define prn(t,b,s) { printnum((long)nextarg(t),b,s,width,pad); width = 0; } #define prc(c) { width -= printchar(c, mode); } #define setbit(w, b) (w[(b) >> BITSHIFT] |= 1 << ((b) & BITMASK)) #define clrbit(w, b) (w[(b) >> BITSHIFT] &= ~(1 << ((b) & BITMASK))) #define bitset(w, b) (w[(b) >> BITSHIFT] & (1 << ((b) & BITMASK))) int drive, partition, cylsiz, tracksiz; int virgin = 1; /* MUST be initialized to put it in data seg */ int floptrk = 9; /* MUST be initialized to put it in data seg */ int zone_ct = 360; int inode_ct = 95; struct dsb { inode_nr s_ninodes; /* # inodes on the minor device */ zone_nr s_nzones; /* total dev size, incl. bit maps etc */ unsigned short s_imap_blocks; /* # of blocks used by inode bit map */ unsigned short s_zmap_blocks; /* # of blocks used by zone bit map */ zone_nr s_firstdatazone; /* number of first data zone */ short s_log_zone_size; /* log2 of blocks/zone */ file_pos s_maxsize; /* maximum file size on this device */ int s_magic; /* magic number for super blocks */ } sb; #define STICKY_BIT 01000 /* not defined anywhere else */ /* ztob gives the block address of a zone * btoa gives the byte address of a block */ #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size) #define btoa(b) ((long) (b) * BLOCK_SIZE) #define SCALE ((int) ztob(1)) /* # blocks in a zone */ #define FIRST sb.s_firstdatazone /* as the name says */ /* # blocks of each type */ #define N_SUPER 1 #define N_IMAP (sb.s_imap_blocks) #define N_ZMAP (sb.s_zmap_blocks) #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK) #define N_DATA (sb.s_nzones - FIRST + 1) /* block address of each type */ #define BLK_SUPER (SUPER_BLOCK) #define BLK_IMAP (BLK_SUPER + N_SUPER) #define BLK_ZMAP (BLK_IMAP + N_IMAP) #define BLK_ILIST (BLK_ZMAP + N_ZMAP) #define BLK_FIRST ztob(FIRST) #define ZONE_SIZE ((int) ztob(BLOCK_SIZE)) #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1) /* byte address of a zone/of an inode */ #define zaddr(z) btoa(ztob(z)) #define inoaddr(i) ((long) (i - 1) * INODE_SIZE + btoa(BLK_ILIST)) #define INDCHUNK (CINDIR * ZONE_NUM_SIZE) #define DIRCHUNK (CDIRECT * DIR_ENTRY_SIZE) char *prog, *device; /* program name (fsck), device name */ int firstcnterr; /* is this the first inode ref cnt error? */ unsigned *imap, *spec_imap; /* inode bit maps */ unsigned *zmap, *spec_zmap; /* zone bit maps */ unsigned *dirmap; /* directory (inode) bit map */ char *rwbuf; /* one block buffer cache */ char rwbuf1[BLOCK_SIZE]; /* in case of a DMA-overrun under DOS .. */ char rwbuf2[BLOCK_SIZE]; /* .. an other buffer can be used */ char nullbuf[BLOCK_SIZE]; /* null buffer */ links *count; /* inode count */ dir_struct nulldir; /* empty directory entry */ block_nr thisblk; /* block that is now in the buffer */ int changed; /* has the diskette been written to? */ struct stack { dir_struct *st_dir; struct stack *st_next; char st_presence; } *ftop; extern long lseek(); #ifdef DOS #define atol(s) atoi(s) /* kludge for C86 (no atol(s) in library) */ #else long atol(); #endif #ifdef STANDALONE extern end; /* last variable */ int *brk; /* the ``break'' (end of data space) */ #else int dev; /* file descriptor of the device */ #endif #define DOT 1 #define DOTDOT 2 /* counters for each type of inode/zone */ int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode; int nfreezone, ztype[NLEVEL]; int repair, automatic, listing, listsuper, makefs; /* flags */ int firstlist; /* has the listing header been printed? */ unsigned part_offset; /* sector offset for this partition */ char answer[] = {"Answer questions with y or n. Then hit RETURN"}; union types { int *u_char; /* %c */ int *u_int; /* %d */ unsigned *u_unsigned; /* %u */ long *u_long; /* %D */ char **u_charp; /* %s */ }; #ifndef STANDALONE # ifdef DOS # include "/lib/c86/stdio.h" # endif #else /*STANDALONE*/ /* Print the given character. */ putchar(c){ if (c == '\n') putc('\r'); putc(c); } /* Get a character from the user and echo it. */ getchar(){ register c; if ((c = getc() & 0xFF) == '\r') c = '\n'; putchar(c); return(c); } #endif /*STANDALONE*/ /* Print the number n. */ printnum(n, base, sign, width, pad) long n; int base, sign; int width, pad; { register short i, mod; char a[MAXWIDTH]; register char *p = a; if (sign) if (n < 0) { n = -n; width--; } else sign = 0; do { /* mod = n % base; n /= base */ mod = 0; for (i = 0; i < 32; i++) { mod <<= 1; if (n < 0) mod++; n <<= 1; if (mod >= base) { mod -= base; n++; } } *p++ = "0123456789ABCDEF"[mod]; width--; } while (n); while (width-- > 0) putchar(pad); if (sign) *p++ = '-'; while (p > a) putchar(*--p); } /* Print the character c. */ printchar(c, mode){ if (mode == 0 || (isprint(c) && c != '\\')) { putchar(c); return(1); } else { putchar('\\'); switch (c) { case '\0': putchar('0'); break; case '\b': putchar('b'); break; case '\n': putchar('n'); break; case '\r': putchar('r'); break; case '\t': putchar('t'); break; case '\f': putchar('f'); break; case '\\': putchar('\\'); break; default: printnum((long) (c & 0xFF), 8, 0, 3, '0'); return(4); } return(2); } } /* Print the arguments pointer to by `arg' according to format. */ doprnt(format, argp) char *format; union types argp; { register char *fmt, *s; register short width, pad, mode; for (fmt = format; *fmt != 0; fmt++) switch(*fmt) { case '\n': putchar('\r'); default: putchar(*fmt); break; case '%': if (*++fmt == '-') fmt++; pad = *fmt == '0' ? '0' : ' '; width = 0; while (isdigit(*fmt)) { width *= 10; width += *fmt++ - '0'; } if (*fmt == 'l' && islower(*++fmt)) *fmt = toupper(*fmt); mode = isupper(*fmt); switch (*fmt) { case 'c': case 'C': prc(nextarg(char)); break; case 'b': prn(unsigned, 2, 0); break; case 'B': prn(long, 2, 0); break; case 'o': prn(unsigned, 8, 0); break; case 'O': prn(long, 8, 0); break; case 'd': prn(int, 10, 1); break; case 'D': prn(long, 10, 1); break; case 'u': prn(unsigned, 10, 0); break; case 'U': prn(long, 10, 0); break; case 'x': prn(unsigned, 16, 0); break; case 'X': prn(long, 16, 0); break; case 's': case 'S': s = nextarg(charp); while (*s) prc(*s++); break; case '\0': break; default: putchar(*fmt); } while (width-- > 0) putchar(pad); } #ifndef STANDALONE fflush(stdout); #endif /*STANDALONE*/ } /* Print the arguments according to fmt. */ printf(fmt, args) char *fmt; { doprnt(fmt, &args); } /* Initialize the variables used by this program. */ initvars(){ register level; #ifdef STANDALONE brk = &end; #endif nregular = ndirectory = nblkspec = ncharspec = nbadinode = 0; for (level = 0; level < NLEVEL; level++) ztype[level] = 0; changed = 0; firstlist = 1; firstcnterr = 1; thisblk = NO_BLOCK; } /* Copy n bytes. */ copy(p, q, n) register char *p, *q; register int n; { do *q++ = *p++; while (--n); } /* Print the string `s' and exit. */ fatal(s) char *s; { printf("%s\n", s); printf("fatal\n"); exit(-1); } /* Test for end of line. */ eoln(c) { return(c < 0 || c == '\n' || c == '\r'); } /* Ask a question and get the answer unless automatic is set. */ yes(question) char *question; { register c, answer; if (!repair) { printf("\n"); return(0); } printf("%s? ", question); if (automatic) { printf("yes\n"); return(1); } if ((c = answer = getchar()) == 'q' || c == 'Q') exit(1); while (!eoln(c)) c = getchar(); return !(answer == 'n' || answer == 'N'); } /* Convert string to integer. Representation is octal. */ atoo(s) char *s; { register n = 0; while ('0' <= *s && *s < '8') { n *= 8; n += *s++ - '0'; } return(n); } /* If repairing the file system, print a prompt and get a string from the user. */ input(buf, size) char *buf; { register char *p = buf; printf("\n"); if (repair) { printf("--> "); while (--size) { *p = getchar(); if (eoln(*p)) { *p = 0; return(p > buf); } p++; } *p = 0; while (!eoln(getchar())) ; return(1); } return(0); } /* Allocate some memory and zero it. */ char *alloc(nelem, elsize) unsigned nelem, elsize; { char *p; #ifdef STANDALONE register *r; p = (char *) brk; brk += nelem * ((elsize + sizeof(int) - 1) / sizeof(int)); for (r = (int *) p; r < brk; r++) *r = 0; return(p); #else extern char *Calloc(); if ((p = Calloc(nelem, elsize)) == 0) fatal("out of memory"); return(p); #endif } #ifndef STANDALONE /* Deallocate previously allocated memory. */ dealloc(p) char *p; { free(p); } /* Allocate and zero memory */ char *Calloc(nelem, elsize) unsigned nelem, elsize; { register int i; register char *mem; extern char *malloc(); if ((mem = malloc(nelem * elsize)) != NULL) { for (i = 0; i < nelem*elsize; ++i) mem[i] = '\0'; } return mem; } #endif /*STANDALONE*/ /* Print the name in a directory entry. */ printname(s) char *s; { register n = NAME_SIZE; do { if (*s == 0) break; printf("%c", isprint(*s) ? *s : '?'); s++; } while (--n); } /* Print the pathname given by a linked list pointed to by `sp'. The * names are in reverse order. */ printrec(sp) struct stack *sp; { if (sp->st_next != 0) { printrec(sp->st_next); printf("/"); printname(sp->st_dir->d_name); } } /* Print the current pathname. */ printpath(mode, nlcr){ if (ftop->st_next == 0) printf("/"); else printrec(ftop); switch (mode) { case 1: printf(" (ino = %u, ", ftop->st_dir->d_inum); break; case 2: printf(" (ino = %u)", ftop->st_dir->d_inum); break; } if (nlcr) printf("\n"); } #ifndef STANDALONE # ifndef DOS /* don't need to open devices under DOS */ /* Open the device. */ devopen(){ if ((dev = open(device, repair ? 2 : 0)) < 0) { perror(device); fatal(""); } } /* Close the device. */ devclose(){ if (close(dev) != 0) { perror("close"); fatal(""); } } # else /*DOS*/ devopen(){} /* dummies */ devclose(){} sync(){} # endif #endif #ifdef DOS # ifndef STANDALONE # define STANDALONE /* DOS will need the diskio routine */ # define TMP /* remember standalone wasn't defined */ # endif #endif #ifdef STANDALONE disktype() { register retry = 3, error, dir=READING; /* test whether at or pc diskette. Note logical sectors * count from 0 and bios counts from 1. */ tracksiz=15; cylsiz=30; reset_diskette(); do error = diskio(dir, 14, rwbuf, 1); while ( ((error & 0xFF00) != 0) && (retry--)); if ((error & 0xFF00)!=0) { /* not an AT-diskette */ tracksiz=9; cylsiz=18; retry=3; reset_diskette(); do error = diskio(dir, 8, rwbuf, 1); while ( ((error & 0xFF00) != 0) && (retry--)); if ((error & 0xFF00)!=0) fatal ("can't determine diskette-type"); } } # ifdef TMP # undef TMP # undef STANDALONE # endif #endif /* Read or write a block. * Note that under STANDALONE or DOS only the * A-drive (drive 0) can be used */ devio(bno, dir) block_nr bno; { long lastone; long offset = btoa(bno); register error; if (dir == READING && bno == thisblk) return; thisblk = bno; #ifdef DOS # ifndef STANDALONE # define STANDALONE /* DOS will need the diskio routine */ # define TMP /* remember standalone wasn't defined */ # endif #endif #ifdef STANDALONE { register sector = offset >> SECT_SHIFT, retry = 3; lastone = sector + part_offset + (BLOCK_SIZE>>SECT_SHIFT); if (lastone > 65535) { printf("Fsck cannot read beyond sector 65535\n"); exit(1); } error = diskio(dir, sector+part_offset, rwbuf, BLOCK_SIZE>>SECT_SHIFT); if ((error & 0xFF00) == 0) return; reset_diskette(); do { printf("error 0x%x %s block %D, retry\n", error, dir == READING ? "reading" : "writing", (long) bno); error = diskio(dir, sector+part_offset, rwbuf, BLOCK_SIZE >> SECT_SHIFT); if ((error & 0xFF00) == 0) return; } while (--retry != 0); } # ifdef TMP # undef TMP # undef STANDALONE # endif #else /*STANDALONE*/ { extern read(), write(), errno; lseek(dev, offset, 0); if (dir == READING) if (read(dev,rwbuf,BLOCK_SIZE) == BLOCK_SIZE) return; else error = errno; else if (write(dev,rwbuf,BLOCK_SIZE) == BLOCK_SIZE) return; else error = errno; } #endif /*STANDALONE*/ printf("%s: can't %s block %D (error = 0x%x)\n", prog, dir == READING ? "read" : "write", (long) bno, error); fatal(""); } /* Read `size' bytes from the disk starting at byte `offset'. */ devread(offset, buf, size) long offset; char *buf; { devio((block_nr) (offset / BLOCK_SIZE), READING); copy(&rwbuf[(int)(offset % BLOCK_SIZE)], buf, size); } /* Write `size' bytes to the disk starting at byte `offset'. */ devwrite(offset, buf, size) long offset; char *buf; { if (!repair) fatal("internal error (devwrite)"); if (size != BLOCK_SIZE) devio((block_nr) (offset / BLOCK_SIZE), READING); copy(buf, &rwbuf[(int)(offset % BLOCK_SIZE)], size); devio((block_nr) (offset / BLOCK_SIZE), WRITING); changed = 1; } /* Print a string with either a singular or a plural pronoun. */ pr(fmt, cnt, s, p) char *fmt, *s, *p; { printf(fmt, cnt, cnt == 1 ? s : p); } #ifndef STANDALONE /* Convert string to number. */ bit_nr getnumber(s) char *s; { register bit_nr n = 0; if (s == 0) return(NO_BIT); while (*s != 0) { if (!isdigit(*s)) return(NO_BIT); n *= 10; n += *s++ - '0'; } return(n); } /* See if the list pointed to by `argv' contains numbers. */ char **getlist(argv, type) char ***argv, *type; { register char **list = *argv; register empty = 1; while (getnumber(**argv) != NO_BIT) { (*argv)++; empty = 0; } if (empty) { printf("warning: no %s numbers given\n", type); return(0); } return(list); } #endif /*STANDALONE*/ /* Make a listing of the super block. If `repair' is set, ask the user * for changes. */ lsuper(){ char buf[80]; long atol(); do { printf("ninodes = %u", sb.s_ninodes); if (input(buf, 80)) sb.s_ninodes = atol(buf); printf("nzones = %u", sb.s_nzones); if (input(buf, 80)) sb.s_nzones = atol(buf); printf("imap_blocks = %u", sb.s_imap_blocks); if (input(buf, 80)) sb.s_imap_blocks = atol(buf); printf("zmap_blocks = %u", sb.s_zmap_blocks); if (input(buf, 80)) sb.s_zmap_blocks = atol(buf); printf("firstdatazone = %u", sb.s_firstdatazone); if (input(buf, 80)) sb.s_firstdatazone = atol(buf); printf("log_zone_size = %u", sb.s_log_zone_size); if (input(buf, 80)) sb.s_log_zone_size = atol(buf); printf("maxsize = %U", sb.s_maxsize); if (input(buf, 80)) sb.s_maxsize = atol(buf); if (yes("ok now")) { devwrite(btoa(BLK_SUPER), (char *) &sb, sizeof(sb)); return; } } while (yes("Do you want to try again")); if (repair) exit(0); } /* Add an empty root directory to the file system. */ makedev(){ register long position = BLK_IMAP * BLOCK_SIZE; register int n = N_IMAP + N_ZMAP + N_ILIST; static dir_struct rootdir[] = { { 1, "." }, { 1, ".." } }; static d_inode inode = { I_DIRECTORY | 0755, 0, sizeof(rootdir), 0, 0, 2 }; devio((block_nr) sb.s_nzones - 1, WRITING); nullbuf[0] = 1 << (ROOT_INODE - 1); /* corrupt nullbuf */ do { devwrite(position, nullbuf, BLOCK_SIZE); nullbuf[0] = 0; /* nullbuf restored */ position += BLOCK_SIZE; } while (--n); #ifndef STANDALONE time(&inode.i_modtime); #endif inode.i_zone[0] = FIRST; devwrite(inoaddr(ROOT_INODE), (char *) &inode, INODE_SIZE); devwrite(zaddr(FIRST), nullbuf, BLOCK_SIZE); devwrite(zaddr(FIRST), (char *) rootdir, sizeof(rootdir)); } /* Get the contents for the super block from the user. Make him some * suggestions. */ mkfs(){ char buf[80]; long atol(); printf("Hit RETURN key to select default values\n\n"); sb.s_nzones = zone_ct; printf("# zones (default: %d) ", zone_ct); if (input(buf, 80)) sb.s_nzones = atol(buf); sb.s_log_zone_size = 0; printf("log zonesize (default: %d) ", sb.s_log_zone_size); if (input(buf, 80)) sb.s_log_zone_size = atol(buf); sb.s_ninodes = inode_ct; printf("#inodes (default: %u) ", sb.s_ninodes); if (input(buf, 80)) sb.s_ninodes = atol(buf); sb.s_imap_blocks = (sb.s_ninodes + (1<<BITMAPSHIFT)-1) >> BITMAPSHIFT; sb.s_zmap_blocks = (sb.s_nzones + (1<<BITMAPSHIFT)-1) >> BITMAPSHIFT; sb.s_firstdatazone = (BLK_ILIST+N_ILIST+SCALE-1) >> sb.s_log_zone_size; sb.s_maxsize = MAX_FILE_POS; if (((sb.s_maxsize-1) >> sb.s_log_zone_size) / BLOCK_SIZE >= MAX_ZONES) sb.s_maxsize =((long)MAX_ZONES*BLOCK_SIZE)<<sb.s_log_zone_size; sb.s_magic = SUPER_MAGIC; printf("\n"); repair = 0; lsuper(); repair = 1; if (!yes("is this ok")) lsuper(); else devwrite(btoa(BLK_SUPER), (char *) &sb, sizeof(sb)); makedev(); } /* Get the super block from either disk or user. Do some initial checks. */ getsuper(){ if (makefs) mkfs(); else { devread(btoa(BLK_SUPER), (char *) &sb, sizeof(sb)); if (listsuper) lsuper(); } if (sb.s_magic != SUPER_MAGIC) fatal("bad magic number in super block"); if ((short) sb.s_ninodes <= 0) fatal("no inodes"); if (sb.s_nzones <= 2) fatal("no zones"); if ((short) sb.s_imap_blocks <= 0) fatal("no imap"); if ((short) sb.s_zmap_blocks <= 0) fatal("no zmap"); if ((short) sb.s_firstdatazone <= 1) fatal("first data zone too small"); if ((short) sb.s_log_zone_size < 0) fatal("zone size < block size"); if (sb.s_maxsize <= 0) fatal("max. file size <= 0"); } /* Check the super block for reasonable contents. */ chksuper(){ register n; register file_pos maxsize; n = (sb.s_ninodes + (1 << BITMAPSHIFT)) >> BITMAPSHIFT; if (sb.s_magic != SUPER_MAGIC) fatal("bad magic number in super block"); if ((short) sb.s_imap_blocks < n) fatal("too few imap blocks"); if (sb.s_imap_blocks != n) { pr("warning: expected %d imap_block%s", n, "", "s"); printf(" instead of %d\n", sb.s_imap_blocks); } n = (sb.s_nzones + (1 << BITMAPSHIFT) - 1) >> BITMAPSHIFT; if ((short) sb.s_zmap_blocks < n) fatal("too few zmap blocks"); if (sb.s_zmap_blocks != n) { pr("warning: expected %d zmap_block%s", n, "", "s"); printf(" instead of %d\n", sb.s_zmap_blocks); } if ((short) sb.s_firstdatazone >= sb.s_nzones) fatal("first data zone too large"); if ((unsigned short) sb.s_log_zone_size >= 8 * sizeof(block_nr)) fatal("log_zone_size too large"); if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n", sb.s_log_zone_size); n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size; if ((short) sb.s_firstdatazone < n) fatal("first data zone too small"); if (sb.s_firstdatazone != n) { printf("warning: expected first data zone to be %d ", n); printf("instead of %u\n", sb.s_firstdatazone); } maxsize = MAX_FILE_POS; if (((maxsize - 1) >> sb.s_log_zone_size) / BLOCK_SIZE >= MAX_ZONES) maxsize = ((long) MAX_ZONES*BLOCK_SIZE) << sb.s_log_zone_size; if (sb.s_maxsize != maxsize) { printf("warning: expected max size to be %D ", maxsize); printf("instead of %D\n", sb.s_maxsize); } } #ifndef STANDALONE /* Make a listing of the inodes given by `clist'. If `repair' is set, ask * the user for changes. */ lsi(clist) char **clist; { register bit_nr bit; register inode_nr ino; d_inode inode, *ip = &inode; char buf[80]; long atol(); if (clist == 0) return; while ((bit = getnumber(*clist++)) != NO_BIT) { setbit(spec_imap, bit); ino = bit; do { devread(inoaddr(ino), (char *) ip, INODE_SIZE); printf("inode %u:\n", ino); printf(" mode = %06o", ip->i_mode); if (input(buf, 80)) ip->i_mode = atoo(buf); printf(" nlinks = %6u", ip->i_nlinks); if (input(buf, 80)) ip->i_nlinks = atol(buf); printf(" size = %6D", ip->i_size); if (input(buf, 80)) ip->i_size = atol(buf); if (yes("Write this back")) { devwrite(inoaddr(ino), (char*) ip, INODE_SIZE); break; } } while (yes("Do you want to change it again")); } } #endif /*STANDALONE*/ /* Allocate `nblk' blocks worth of bitmap. */ unsigned *allocbitmap(nblk){ register unsigned *bitmap; bitmap = (unsigned *) alloc(nblk, BLOCK_SIZE); *bitmap |= 1; return(bitmap); } /* Load the bitmap starting at block `bno' from disk. */ loadbitmap(bitmap, bno, nblk) unsigned *bitmap; block_nr bno; { register i; register unsigned *p; p = bitmap; for (i = 0; i < nblk; i++, bno++, p += INTS_PER_BLOCK) devread(btoa(bno), (char *) p, BLOCK_SIZE); *bitmap |= 1; } /* Write the bitmap starting at block `bno' to disk. */ dumpbitmap(bitmap, bno, nblk) unsigned *bitmap; block_nr bno; { register i; register unsigned *p = bitmap; for (i = 0; i < nblk; i++, bno++, p += INTS_PER_BLOCK) devwrite(btoa(bno), (char *) p, BLOCK_SIZE); } /* Initialize the given bitmap by setting all the bits starting at `bit'. */ initbitmap(bitmap, bit, nblk) unsigned *bitmap; bit_nr bit; { register unsigned *first, *last; while (bit & BITMASK) { setbit(bitmap, bit); bit++; } first = &bitmap[bit >> BITSHIFT]; last = &bitmap[nblk * INTS_PER_BLOCK]; while (first < last) *first++ = ~(unsigned)0; } #ifndef STANDALONE /* Set the bits given by `list' in the bitmap. */ fillbitmap(bitmap, lwb, upb, list) unsigned *bitmap; bit_nr lwb, upb; char **list; { register bit_nr bit; if (list == 0) return; while ((bit = getnumber(*list++)) != NO_BIT) if (bit < lwb || bit >= upb) { if (bitmap == spec_imap) printf("inode number %u ", bit); else printf("zone number %u ", bit); printf("out of range (ignored)\n"); } else setbit(bitmap, bit - lwb + 1); } /* Deallocate the bitmap `p'. */ freebitmap(p) unsigned *p; { dealloc((char *) p); } #endif /*STANDALONE*/ /* Get all the bitmaps used by this program. */ getbitmaps(){ imap = allocbitmap(N_IMAP); zmap = allocbitmap(N_ZMAP); spec_imap = allocbitmap(N_IMAP); spec_zmap = allocbitmap(N_ZMAP); dirmap = allocbitmap(N_IMAP); } #ifndef STANDALONE /* Release all the space taken by the bitmaps. */ putbitmaps(){ freebitmap(imap); freebitmap(zmap); freebitmap(spec_imap); freebitmap(spec_zmap); freebitmap(dirmap); } #endif /* `w1' and `w2' are differing words from two bitmaps that should be * identical. Print what's the matter with them. */ chkword(w1, w2, bit, nbit, type, n, report) unsigned w1, w2; char *type; bit_nr bit, nbit; int *n, *report; { for (; (w1 | w2) && bit < nbit; w1 >>= 1, w2 >>= 1, bit++) if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report && (!repair || automatic || yes("stop this listing"))) *report = 0; else if (*report) if ((w1 & 1) && !(w2 & 1)) printf("%s %u is missing\n", type, bit); else if (!(w1 & 1) && (w2 & 1)) printf("%s %u is not free\n", type, bit); } /* Check if the given (correct) bitmap is identical with the one that is * on the disk. If not, ask if the disk should be repaired. */ chkmap(cmap, dmap, bit, blkno, nblk, nbit, type) unsigned *cmap, *dmap; bit_nr bit, nbit; block_nr blkno; char *type; { register unsigned *p = dmap, *q = cmap; int report = 1, nerr = 0; if (makefs) { dumpbitmap(cmap, blkno, nblk); return; } printf("Checking %s map\n", type); loadbitmap(dmap, blkno, nblk); do { if (*p != *q) chkword(*p, *q, bit, nbit, type, &nerr, &report); p++; q++; } while ((bit += 8 * sizeof(unsigned)) < nbit); if ((!repair || automatic) && !report) printf("etc. "); if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr); if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk); if (nerr > 0) printf("\n"); } /* See if the inodes that aren't allocated are cleared. */ chkilist(){ register inode_nr ino = 1; mask_bits mode; if (makefs) return; printf("Checking inode list\n"); do if (!bitset(imap, (bit_nr) ino)) { devread(inoaddr(ino), (char *) &mode, sizeof(mode)); if (mode != I_NOT_ALLOC) { printf("mode inode %u not cleared", ino); if (yes(". clear")) devwrite(inoaddr(ino), nullbuf, INODE_SIZE); } } while (++ino <= sb.s_ninodes); printf("\n"); } /* Allocate an array to maintain the inode reference counts in. */ getcount(){ count = (links *) alloc(sb.s_ninodes + 1, sizeof(links)); } /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */ counterror(ino) inode_nr ino; { d_inode inode; if (firstcnterr) { printf("INODE NLINK COUNT\n"); firstcnterr = 0; } devread(inoaddr(ino), (char *) &inode, INODE_SIZE); count[ino] += inode.i_nlinks; printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]); if (yes(" adjust")) { if ((inode.i_nlinks = count[ino]) == 0) { fatal("internal error (counterror)"); /* This would be a patch inode.i_mode = I_NOT_ALLOC; clrbit(imap, (bit_nr) ino); */ } devwrite(inoaddr(ino), (char *) &inode, INODE_SIZE); } } /* Check if the reference count of the inodes are correct. The array `count' * is maintained as follows: an entry indexed by the inode number is * incremented each time a link is found; when the inode is read the link * count in there is substracted from the corresponding entry in `count'. * Thus, when the whole file system has been traversed, all the entries * should be zero. */ chkcount(){ register inode_nr ino; for (ino = 1; ino <= sb.s_ninodes; ino++) if (count[ino] != 0) counterror(ino); if (!firstcnterr) printf("\n"); } #ifndef STANDALONE /* Deallocate the `count' array. */ freecount(){ dealloc((char *) count); } #endif /* Print the inode permission bits given by mode and shift. */ printperm(mode, shift, special, overlay) mask_bits mode; { printf(mode >> shift & R_BIT ? "r" : "-"); printf(mode >> shift & W_BIT ? "w" : "-"); if (mode & special) printf("%c", overlay); else printf(mode >> shift & X_BIT ? "x" : "-"); } /* List the given inode. */ list(ino, ip) inode_nr ino; d_inode *ip; { if (firstlist) { firstlist = 0; printf(" inode permission link size name\n"); } printf("%6u ", ino); switch (ip->i_mode & I_TYPE) { case I_REGULAR: printf("-"); break; case I_DIRECTORY: printf("d"); break; case I_CHAR_SPECIAL: printf("c"); break; case I_BLOCK_SPECIAL: printf("b"); break; default: printf("?"); } printperm(ip->i_mode, 6, I_SET_UID_BIT, 's'); printperm(ip->i_mode, 3, I_SET_GID_BIT, 's'); printperm(ip->i_mode, 0, STICKY_BIT, 't'); printf(" %3u ", ip->i_nlinks); switch (ip->i_mode & I_TYPE) { case I_CHAR_SPECIAL: case I_BLOCK_SPECIAL: printf(" %2x,%2x ", (dev_nr) ip->i_zone[0] >> MAJOR & 0xFF, (dev_nr) ip->i_zone[0] >> MINOR & 0xFF); break; default: printf("%7D ", ip->i_size); } printpath(0, 1); } /* Remove an entry from a directory if ok with the user. */ remove(dp) dir_struct *dp; { int i; char *cp1, *cp2; setbit(spec_imap, (bit_nr) dp->d_inum); if (yes(". remove entry")) { count[dp->d_inum]--; cp1 = (char *) &nulldir; cp2 = (char *) dp; i = sizeof(dir_struct); while (i--) *cp2++ = *cp1++; return(1); } return(0); } /* See if the `.' or `..' entry is as expected. */ chkdots(ino, pos, dp, exp) inode_nr ino, exp; file_pos pos; dir_struct *dp; { if (dp->d_inum != exp) { printf("bad %s in ", dp->d_name); printpath(1, 0); printf("%s is linked to %u ", dp->d_name, dp->d_inum); printf("instead of %u)", exp); setbit(spec_imap, (bit_nr) ino); setbit(spec_imap, (bit_nr) dp->d_inum); setbit(spec_imap, (bit_nr) exp); if (yes(". repair")) { count[dp->d_inum]--; dp->d_inum = exp; count[exp]++; return(0); } } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) { printf("warning: %s has offset %D in ", dp->d_name, pos); printpath(1, 0); printf("%s is linked to %u)\n", dp->d_name, dp->d_inum); setbit(spec_imap, (bit_nr) ino); setbit(spec_imap, (bit_nr) dp->d_inum); setbit(spec_imap, (bit_nr) exp); } return(1); } /* Check the name in a directory entry. */ chkname(ino, dp) inode_nr ino; dir_struct *dp; { register n = NAME_SIZE + 1; register char *p = dp->d_name; if (*p == 0) { printf("null name found in "); printpath(0, 0); setbit(spec_imap, (bit_nr) ino); if (remove(dp)) return(0); } while (--n != 0 && *p != 0) if (*p++ == '/') { printf("found a '/' in entry of directory "); printpath(1, 0); setbit(spec_imap, (bit_nr) ino); printf("entry = '"); printname(dp->d_name); printf("')"); if (remove(dp)) return(0); break; } return(1); } /* Check a directory entry. Here the routine `descendtree' is called * recursively to check the file or directory pointed to by the entry. */ chkentry(ino, pos, dp) inode_nr ino; file_pos pos; dir_struct *dp; { char *cp1, *cp2; int i; if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) { printf("bad inode found in directory "); printpath(1, 0); printf("ino found = %u, ", dp->d_inum); printf("name = '"); printname(dp->d_name); printf("')"); if (yes(". remove entry")) { cp1 = (char *) &nulldir; cp2 = (char *) dp; i = sizeof(dir_struct); while (i--) *cp2++ = *cp1++; return(0); } return(1); } if ((unsigned) count[dp->d_inum] == MAX_LINKS) { printf("too many links to ino %u\n", dp->d_inum); printf("discovered at entry '"); printname(dp->d_name); printf("' in directory "); printpath(0, 1); if (remove(dp)) return(0); } count[dp->d_inum]++; if (strcmp(dp->d_name, ".") == 0) { ftop->st_presence |= DOT; return(chkdots(ino, pos, dp, ino)); } if (strcmp(dp->d_name, "..") == 0) { ftop->st_presence |= DOTDOT; return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino : ftop->st_next->st_dir->d_inum)); } if (!chkname(ino, dp)) return(0); if (bitset(dirmap, (bit_nr) dp->d_inum)) { printf("link to directory discovered in "); printpath(1, 0); printf("name = '"); printname(dp->d_name); printf("', dir ino = %u)", dp->d_inum); return !remove(dp); } return(descendtree(dp)); } /* Check a zone of a directory by checking all the entries in the zone. * The zone is split up into chunks to not allocate too much stack. */ chkdirzone(ino, ip, pos, zno) inode_nr ino; d_inode *ip; file_pos pos; zone_nr zno; { dir_struct dirblk[CDIRECT]; register dir_struct *dp; register n = SCALE * (NR_DIR_ENTRIES / CDIRECT), dirty; register long offset = zaddr(zno); do { devread(offset, (char *) dirblk, DIRCHUNK); dirty = 0; for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) { if (ip->i_size - pos < DIR_ENTRY_SIZE) { printf("bad format in directory "); printpath(2, 0); if (yes(". truncate")) { setbit(spec_imap, (bit_nr) ino); ip->i_size = pos; dirty = 1; } else return(0); } if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp)) dirty = 1; if ((pos += DIR_ENTRY_SIZE) >= ip->i_size) break; } if (dirty) devwrite(offset, (char *) dirblk, DIRCHUNK); offset += DIRCHUNK; } while (--n && pos < ip->i_size); return(1); } /* There is something wrong with the given zone. Print some details. */ errzone(mess, zno, level, pos) char *mess; zone_nr zno; file_pos pos; { printf("%s zone in ", mess); printpath(1, 0); printf("zno = %u, type = ", zno); switch (level) { case 0: printf("DATA"); break; case 1: printf("SINGLE INDIRECT"); break; case 2: printf("DOUBLE INDIRECT"); break; default: printf("VERY INDIRECT"); } printf(", pos = %D)\n", pos); } /* Found the given zone in the given inode. Check it, and if ok, mark it * in the zone bitmap. */ markzone(ino, zno, level, pos) inode_nr ino; zone_nr zno; file_pos pos; { register bit_nr bit = (bit_nr) zno - FIRST + 1; ztype[level]++; if (zno < FIRST || zno >= sb.s_nzones) { errzone("out-of-range", zno, level, pos); return(0); } if (bitset(zmap, bit)) { setbit(spec_zmap, bit); errzone("duplicate", zno, level, pos); return(0); } nfreezone--; if (bitset(spec_zmap, bit)) errzone("found", ino, zno, level, pos, bit); setbit(zmap, bit); return(1); } /* Check an indirect zone by checking all of its entries. * The zone is split up into chunks to not allocate too much stack. */ chkindzone(ino, ip, pos, zno, level) inode_nr ino; d_inode *ip; file_pos *pos; zone_nr zno; { zone_nr indirect[CINDIR]; register n = NR_INDIRECTS / CINDIR; register long offset = zaddr(zno); do { devread(offset, (char *) indirect, INDCHUNK); if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0); offset += INDCHUNK; } while (--n && *pos < ip->i_size); return(1); } /* Return the size of a gap in the file, represented by a null zone number * at some level of indirection. */ file_pos jump(level){ file_pos power = ZONE_SIZE; if (level != 0) do power *= NR_INDIRECTS; while (--level); return(power); } /* Check a zone, which may be either a normal data zone, a directory zone, * or an indirect zone. */ zonechk(ino, ip, pos, zno, level) inode_nr ino; d_inode *ip; file_pos *pos; zone_nr zno; { if (level == 0) { if ((ip->i_mode & I_TYPE) == I_DIRECTORY && !chkdirzone(ino, ip, *pos, zno)) return(0); *pos += ZONE_SIZE; return(1); } else return chkindzone(ino, ip, pos, zno, level); } /* Check a list of zones given by `zlist'. */ chkzones(ino, ip, pos, zlist, len, level) inode_nr ino; d_inode *ip; file_pos *pos; zone_nr *zlist; { register ok = 1, i; for (i = 0; i < len && *pos < ip->i_size; i++) if (zlist[i] == NO_ZONE) *pos += jump(level); else if (!markzone(ino, zlist[i], level, *pos)) { *pos += jump(level); ok = 0; } else if (!zonechk(ino, ip, pos, zlist[i], level)) ok = 0; return(ok); } /* Check a file or a directory. */ chkfile(ino, ip) inode_nr ino; d_inode *ip; { register ok, i, level; file_pos pos = 0; ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0); for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++) if (!chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level)) ok = 0; return(ok); } /* Check a directory by checking the contents. Check if . and .. are present. */ chkdirectory(ino, ip) inode_nr ino; d_inode *ip; { register ok; setbit(dirmap, (bit_nr) ino); if (ip->i_size > MAXDIRSIZE) { printf("warning: huge directory: "); printpath(2, 1); } ok = chkfile(ino, ip); if (!(ftop->st_presence & DOT)) { printf(". missing in "); printpath(2, 1); ok = 0; } if (!(ftop->st_presence & DOTDOT)) { printf(".. missing in "); printpath(2, 1); ok = 0; } return(ok); } /* Check the mode of an inode, and if it is a file or a directory, check * the contents. */ chkmode(ino, ip) inode_nr ino; d_inode *ip; { switch (ip->i_mode & I_TYPE) { case I_REGULAR: nregular++; return chkfile(ino, ip); break; case I_DIRECTORY: ndirectory++; return chkdirectory(ino, ip); case I_BLOCK_SPECIAL: nblkspec++; return(1); case I_CHAR_SPECIAL: ncharspec++; return(1); default: nbadinode++; printf("bad mode of "); printpath(1, 0); printf("mode = %o)", ip->i_mode); return(0); } } /* Check an inode. */ chkinode(ino, ip) inode_nr ino; d_inode *ip; { if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) { printf("root inode is not a directory "); printf("(ino = %u, mode = %o)\n", ino, ip->i_mode); fatal(""); } if (ip->i_nlinks == 0) { printf("link count zero of "); printpath(2, 0); return(0); } nfreeinode--; setbit(imap, (bit_nr) ino); if ((unsigned) ip->i_nlinks > MAX_LINKS) { printf("link count too big in "); printpath(1, 0); printf("cnt = %u)\n", (unsigned) ip->i_nlinks); count[ino] -= MAX_LINKS; setbit(spec_imap, (bit_nr) ino); } else count[ino] -= (unsigned) ip->i_nlinks; return chkmode(ino, ip); } /* Check the directory entry pointed to by dp, by checking the inode. */ descendtree(dp) dir_struct *dp; { d_inode inode; register inode_nr ino = dp->d_inum; register visited; struct stack stk; char *cp1, *cp2; int i; stk.st_dir = dp; stk.st_next = ftop; ftop = &stk; if (bitset(spec_imap, (bit_nr) ino)) { printf("found inode %u: ", ino); printpath(0, 1); } visited = bitset(imap, (bit_nr) ino); if (!visited || listing) { devread(inoaddr(ino), (char *) &inode, INODE_SIZE); if (listing) list(ino, &inode); if (!visited && !chkinode(ino, &inode)) { setbit(spec_imap, (bit_nr) ino); if (yes("remove")) { count[ino] += inode.i_nlinks - 1; clrbit(imap, (bit_nr) ino); devwrite(inoaddr(ino), nullbuf, INODE_SIZE); cp1 = (char *) &nulldir; cp2 = (char *) dp; i = sizeof(dir_struct); while (i--) *cp2++ = *cp1++; ftop = ftop->st_next; return(0); } } } ftop = ftop->st_next; return(1); } /* Check the file system tree. */ chktree(){ dir_struct dir; if (!makefs) nfreeinode = sb.s_ninodes; nfreezone = N_DATA; dir.d_inum = ROOT_INODE; dir.d_name[0] = 0; if (!descendtree(&dir)) fatal("bad root inode"); printf("\n"); } /* Print the totals of all the objects found. */ printtotal(){ printf("blocksize = %5d ", BLOCK_SIZE); printf("zonesize = %5d\n", ZONE_SIZE); printf("\n"); pr("%6u Regular file%s\n", nregular, "", "s"); pr("%6u Director%s\n", ndirectory, "y", "ies"); pr("%6u Block special file%s\n", nblkspec, "", "s"); pr("%6u Character special file%s\n", ncharspec, "", "s"); if (nbadinode != 0) pr("%6u Bad inode%s\n", nbadinode, "", "s"); pr("%6u Free inode%s\n", nfreeinode, "", "s"); /* Don't print some fields. printf("\n"); pr("%6u Data zone%s\n", ztype[0], "", "s"); pr("%6u Single indirect zone%s\n", ztype[1], "", "s"); pr("%6u Double indirect zone%s\n", ztype[2], "", "s"); */ pr("%6u Free zone%s\n", nfreezone, "", "s"); } /* Check the device which name is given by `f'. The inodes listed by `clist' * should be listed separately, and the inodes listed by `ilist' and the zones * listed by `zlist' should be watched for while checking the file system. */ chkdev(f, clist, ilist, zlist) char *f, **clist, **ilist, **zlist; { if (automatic || makefs) repair = 1; device = f; initvars(); #ifndef STANDALONE devopen(); #endif getsuper(); chksuper(); #ifndef STANDALONE lsi(clist); #endif getbitmaps(); initbitmap(imap, (bit_nr) sb.s_ninodes + 1, N_IMAP); initbitmap(zmap, (bit_nr) sb.s_nzones - FIRST + 1, N_ZMAP); #ifndef STANDALONE fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist); fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_nzones, zlist); #endif getcount(); chktree(); chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, (bit_nr) sb.s_nzones, "zone"); chkcount(); chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, (bit_nr) sb.s_ninodes + 1, "inode"); chkilist(); printtotal(); #ifndef STANDALONE putbitmaps(); freecount(); devclose(); #endif if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n"); } main(argc, argv) char **argv; { register char **clist = 0, **ilist = 0, **zlist = 0; #ifdef STANDALONE register c, command; if (virgin) floptrk = tracksiz; /* save 9 or 15 in floptrk */ virgin = 0; /* only on first pass thru */ if (tracksiz < 9 || cylsiz < 18) printf("Bootblok gave bad tracksiz\n"); rwbuf = rwbuf1; prog = "fsck"; printf("\n\n\n\n"); for (;;) { printf("\nHit key as follows:\n\n"); printf(" = start MINIX (root file system in drive 0)\n"); printf(" u start MINIX on PS/2 Model 30, U.S. keyboard (root file sys in drive 0)\n"); printf(" d start MINIX on PS/2 Model 30, Dutch keyboard (root file sys in drive 0)\n"); printf(" f check the file system (first insert any file system diskette)\n"); printf(" l check and list file system (first insert any file system diskette)\n"); printf(" m make an (empty) file system (first insert blank, formatted diskette)\n"); printf(" h check hard disk file system\n"); printf("\n# "); c = getc(); command = c & 0xFF; printf("%c\n", command); part_offset = 0; partition = 0; drive = 0; switch (command) { case 'h': get_partition(); drive = (partition < PARB ? 0x80 : 0x81); cylsiz = CYLSIZE; /* sectors per cylinder */ tracksiz = TRACKSIZE; printf("Checking hard disk. %s\n", answer); if (read_partition() < 0) continue; repair = 1; break; case 'f': printf("Checking diskette. %s\n", answer); disktype(); /* init tracksiz & cylsiz */ repair = 1; break; case 'l': printf("Checking diskette. %s\n", answer); listing = listsuper = 1; disktype(); /* init tracksiz & cylsiz */ break; case 'm': printf("Making empty file system\n"); disktype(); /* init tracksiz & cylsiz */ makefs = 1; if (tracksiz == 15) { /* 1.2M diskette. */ zone_ct = 1200; inode_ct = 255; } break; case '=': return((c >> 8) & 0xFF); case 'u': return((c >> 8) & 0xFF); case 'd': return((c >> 8) & 0xFF); default: printf("Illegal command\n"); continue; } chkdev("disk(ette)", clist, ilist, zlist); repair = listing = listsuper = makefs = 0; } #else /* STANDALONE */ register devgiven = 0; register char *arg; rwbuf = rwbuf1; #ifdef DOS if (DMAoverrun(rwbuf1)) rwbuf = rwbuf2; disktype() /* init tracksiz & cylsize for disk in A: */ #endif sync(); prog = *argv++; while ((arg = *argv++) != 0) if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) { case 'a': automatic ^= 1; break; case 'c': clist = getlist(&argv, "inode"); break; case 'i': ilist = getlist(&argv, "inode"); break; case 'z': zlist = getlist(&argv, "zone" ); break; case 'r': repair ^= 1; break; case 'l': listing ^= 1; break; case 's': listsuper ^= 1; break; case 'm': makefs ^= 1; break; default: printf("%s: unknown flag '%s'\n", prog, arg); } else { chkdev(arg, clist, ilist, zlist); clist = 0; ilist = 0; zlist = 0; devgiven = 1; } if (!devgiven) { printf("Usage: fsck [-acilmrsz] file\n"); exit(1); } return(0); #endif /*STANDALONE*/ } #ifdef STANDALONE get_partition() { /* Ask for a partition number and wait for it. */ char chr; while (1) { printf("\n\nPlease enter partition number. Drive 0: 1-4, drive 1: 6-9, then hit RETURN: "); while (1) { chr = getc(); printf("%c", chr); if (chr == '\r') { printf("\n"); if (partition > 0) return; else break; } else { if (partition > 0) break; } if (chr < '1' || chr > '9' || chr == '5') break; partition = chr - '0'; } partition = 0; } } /* This define tells where to find things in partition table. */ #define P1 0x1C6 int read_partition() { /* Read the partition table to find out where the requested partition * begins. Put the sector offset in 'part_offset'. */ int error, p, retries = 0; long val[4]; long b0, b1, b2, b3; while (1) { retries++; if (retries > 5) { printf("Disk errors. Can't read partition table\n"); return(-1); } error = diskio(READING, 0, rwbuf, 1); if ( (error&0xFF00) == 0) break; } /* Find start of the requested partition and set 'part_offset'. */ for (p=0; p<4; p++) { b0 = rwbuf[P1+16*p+0] & 0xFF; b1 = rwbuf[P1+16*p+1] & 0xFF; b2 = rwbuf[P1+16*p+2] & 0xFF; b3 = rwbuf[P1+16*p+3] & 0xFF; val[p] = (b3<<24) | (b2<<16) | (b1<<8) | b0; if (val[p] > 65535) { printf("Fsck can't handle partitions above sector 65535\n"); exit(1); } } p = (partition >= PARB ? partition - PARB + 1 : partition); sort(val); part_offset = (unsigned) val[p-1]; if ((part_offset % (BLOCK_SIZE/SECTOR_SIZE)) != 0) part_offset = (part_offset/(BLOCK_SIZE/SECTOR_SIZE)+1)*(BLOCK_SIZE/SECTOR_SIZE); return(0); } sort(val) register long *val; { register int i,j; for (i=0; i<4; i++) for (j=0; j<3; j++) if ((val[j] == 0) && (val[j+1] != 0)) swap(&val[j], &val[j+1]); else if (val[j] > val[j+1] && val[j+1] != 0) swap(&val[j], &val[j+1]); } swap(first, second) register long *first, *second; { register long tmp; tmp = *first; *first = *second; *second = tmp; } #endif /*STANDALONE*/
fozzy@edvvie.at (Fozzy C. Dressel) (09/07/89)
I`m working on my new MINIX-AT 1.3 and try to tell fsck, that I have a ST4096 with 9 (nine) heads and not with 4. When I compile and link the fsck*.[cs] the runfile is 2k smaller than the original fsck. After starting the news fsck I got the message: trap .... illegal systemcall Do anybody know whats happend ? thanks ! -- Fozzy C. Dressel LOCAL: fozzy@eliza EDV Ges.m.b.H Vienna USENET: fozzy@edvvie.at Hofmuehlgasse 3 - 5 A-1060 Vienna, Austria/Europe Tel: (0043) (222) 59907 (8-19 CET)