]> Zhao Yanbai Git Server - minix.git/commitdiff
mkfs reloaded 32/532/2
authorAntoine Leca <antoine.leca.1@gmail.com>
Fri, 26 Apr 2013 18:54:22 +0000 (20:54 +0200)
committerGerrit Code Review <gerrit@gerrit>
Mon, 13 May 2013 09:17:34 +0000 (11:17 +0200)
* restored the zone>block stuff
* generalized the support for more-than-1-block bitmaps to also deal
  with big inodes maps in small blocks
* improved pexit() to printf-like syntax; also replaced pexit() with
  err() or errx() where there are no reference to proto lines
* unified the allocation of blocks to all use alloc_block() instead
  of raw malloc half of the time
* removed the V2_ d2_ etc. prefixes which are obscure and obsolete

While here, also
* used new-form definitions, and closer to KNF style in general
* used often-built-ins such as mem* or strncpy where relevant
* pruned a fair amount of constants which are irrelevant

Thanks to Thomas V. and Lionel who did a good amount of work with the
cross-compilation stuff and made that change to be much smoother.

usr.sbin/mkfs.mfs/const.h
usr.sbin/mkfs.mfs/mfsdir.h
usr.sbin/mkfs.mfs/mkfs.c
usr.sbin/mkfs.mfs/super.h
usr.sbin/mkfs.mfs/type.h

index b4c1cd008285e36f8bbe6d042cb2d9e85d77acc7..fecb9e80433df4694dc0e963ea99c73ff5f1bfc1 100644 (file)
@@ -1,23 +1,12 @@
-#ifndef __MFS_CONST_H__
-#define __MFS_CONST_H__
+#ifndef _MKFS_MFS_CONST_H__
+#define _MKFS_MFS_CONST_H__
 
 /* Tables sizes */
-#define V2_NR_DZONES       7   /* # direct zone numbers in a V2 inode */
-#define V2_NR_TZONES      10   /* total # zone numbers in a V2 inode */
-
-#define NR_INODES        512   /* # slots in "in core" inode table,
-                                * should be more or less the same as
-                                * NR_VNODES in vfs
-                                */
-#define GETDENTS_BUFSIZ  257
-
-#define INODE_HASH_LOG2   7     /* 2 based logarithm of the inode hash size */
-#define INODE_HASH_SIZE   ((unsigned long)1<<INODE_HASH_LOG2)
-#define INODE_HASH_MASK   (((unsigned long)1<<INODE_HASH_LOG2)-1)
-
-/* Max. filename length */
-#define MFS_NAME_MAX    MFS_DIRSIZ
+#define NR_DZONES       7      /* # direct zone numbers in a V2 inode */
+#define NR_TZONES      10      /* total # zone numbers in a V2 inode */
 
+#define MIN_BLOCK_SIZE         1024
+#define DEFAULT_BLOCK_SIZE     4096
 
 /* The type of sizeof may be (unsigned) long.  Use the following macro for
  * taking the sizes of small objects so that there are no surprises like
  */
 #define usizeof(t) ((unsigned) sizeof(t))
 
-/* File system types. */
-#define SUPER_MAGIC   0x137F   /* magic number contained in super-block */
-#define SUPER_REV     0x7F13   /* magic # when 68000 disk read on PC or vv */
-#define SUPER_V2      0x2468   /* magic # for V2 file systems */
-#define SUPER_V2_REV  0x6824   /* V2 magic written on PC, read on 68K or vv */
+/* File system types: magic number contained in super-block. */
 #define SUPER_V3      0x4d5a   /* magic # for V3 file systems */
-
-#define V1                1    /* version number of V1 file systems */ 
-#define V2                2    /* version number of V2 file systems */ 
-#define V3                3    /* version number of V3 file systems */ 
+#define SUPER_MAGIC    SUPER_V3
 
 /* Miscellaneous constants */
-#define SU_UID          ((uid_t) 0)    /* super_user's uid_t */
-#define NORMAL            0    /* forces get_block to do disk read */
-#define NO_READ            1   /* prevents get_block from doing disk read */
-#define PREFETCH           2   /* tells get_block not to read or mark dev */
-
-#define NO_BIT   ((uint32_t) 0)        /* returned by alloc_bit() to signal failure */
-
-#define LOOK_UP            0 /* tells search_dir to lookup string */
-#define ENTER              1 /* tells search_dir to make dir entry */
-#define DELETE             2 /* tells search_dir to delete entry */
-#define IS_EMPTY           3 /* tells search_dir to ret. OK or ENOTEMPTY */  
-
-/* write_map() args */
-#define WMAP_FREE      (1 << 0)
+#define SU_UID          ((uid_t) 0)    /* super_user's uid_t */
+#define SECTOR_SIZE    512
 
-#define IGN_PERM       0
-#define CHK_PERM       1
+#define ROOT_INODE     ((ino_t) 1)     /* inode number for root directory */
 
-#define BP_CLEAN        0      /* on-disk block and memory copies identical */
-#define BP_DIRTY        1      /* on-disk block and memory copies differ */
-#define IN_CLEAN        0      /* in-block inode and memory copies identical */
-#define IN_DIRTY        1      /* in-block inode and memory copies differ */
-#define ATIME            002   /* set if atime field needs updating */
-#define CTIME            004   /* set if ctime field needs updating */
-#define MTIME            010   /* set if mtime field needs updating */
-
-#define BYTE_SWAP          0   /* tells conv2/conv4 to swap bytes */
-
-#define END_OF_FILE   (-104)   /* eof detected */
-
-#define ROOT_INODE    ((ino_t) 1)      /* inode number for root directory */
-#define BOOT_BLOCK  ((blkcnt_t) 0)     /* block number of boot block */
+#define BOOT_BLOCK     ((blkcnt_t) 0)  /* block number of boot block */
 #define SUPER_BLOCK_BYTES  (1024)      /* bytes offset */
-#define START_BLOCK ((blkcnt_t) 2)     /* first block of FS (not counting SB) */
+#define START_BLOCK    ((blkcnt_t) 2)  /* first block of FS (not counting SB) */
 
-#define DIR_ENTRY_SIZE       usizeof (struct direct)  /* # bytes/dir entry   */
-#define NR_DIR_ENTRIES(b)   ((b)/DIR_ENTRY_SIZE)  /* # dir entries/blk   */
-#define SUPER_SIZE      usizeof (struct super_block)  /* super_block size    */
-
-#define FS_BITMAP_CHUNKS(b) ((b)/usizeof (uint32_t))/* # map chunks/blk   */
-#define FS_BITCHUNK_BITS               (usizeof(uint32_t) * CHAR_BIT)
+#define FS_BITMAP_CHUNKS(b)    ((b)/usizeof(bitchunk_t)) /*# map chunks/blk*/
+#define FS_BITCHUNK_BITS       (usizeof(bitchunk_t) * CHAR_BIT)
 #define FS_BITS_PER_BLOCK(b)   (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS)
 
-/* Derived sizes pertaining to the V2 file system. */
-#define V2_ZONE_NUM_SIZE            usizeof (uint32_t)  /* # bytes in V2 zone  */
-#define V2_INODE_SIZE             usizeof (d2_inode)  /* bytes in V2 dsk ino */
-#define V2_INDIRECTS(b)   ((b)/V2_ZONE_NUM_SIZE)  /* # zones/indir block */
-#define V2_INODES_PER_BLOCK(b) ((b)/V2_INODE_SIZE)/* # V2 dsk inodes/blk */
-
-#define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m))
+/* Derived sizes pertaining to the file system. */
+#define ZONE_NUM_SIZE          usizeof (zone_t)  /* # bytes in zone */
+#define INODE_SIZE             usizeof (struct inode)  /* bytes in dsk ino */
+#define INDIRECTS(b)           ((b)/ZONE_NUM_SIZE)  /* # zones/indir block */
+#define INODES_PER_BLOCK(b)    ((b)/INODE_SIZE)  /* # V2 dsk inodes/blk */
 
-#define _STATIC_BLOCK_SIZE      1024
-#define _MIN_BLOCK_SIZE          1024
-#define _MAX_BLOCK_SIZE          4096
+#define DIR_ENTRY_SIZE         usizeof(struct direct) /* # bytes/dir entry */
+#define NR_DIR_ENTRIES(b)      ((b)/DIR_ENTRY_SIZE)  /* # dir entries/blk  */
 #endif
-
index 3610c1ab1a0151513e961947b29501210e2796e1..46f62b7602c6ee8d95be421be8becca8ecce074f 100644 (file)
@@ -1,17 +1,16 @@
-#ifndef _MFSDIR_H
-#define _MFSDIR_H
+#ifndef _MKFS_MFSDIR_H
+#define _MKFS_MFSDIR_H
 
 /* Maximum Minix MFS on-disk directory filename.
  * MFS uses 'struct direct' to write and parse 
  * directory entries, so this can't be changed
  * without breaking filesystems.
  */
-
 #define MFS_DIRSIZ     60
 
 struct direct {
-  uint32_t mfs_d_ino;
-  char mfs_d_name[MFS_DIRSIZ];
+  uint32_t d_ino;
+  char d_name[MFS_DIRSIZ];
 } __packed;
 
-#endif /* _MFSDIR_H */
+#endif /* _MKFS_MFSDIR_H */
index f0e8e99249932811095c1a046175d554a13fcc85..414938dd9d82df1c5ba61f5a40d44289386ad90a 100644 (file)
@@ -1,14 +1,6 @@
 /* mkfs  -  make the MINIX filesystem  Authors: Tanenbaum et al. */
 
-/*     Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
- *
- * This program can make version 1, 2 and 3 file systems, as follows:
- *     mkfs /dev/fd0 1200      # Version 3 (default)
- *     mkfs -1 /dev/fd0 360    # Version 1
- *
- * Note that the version 1 and 2 file systems produced by this program are not
- * compatible with the original version 1 and 2 file system layout.
- */
+/*     Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans */
 
 #if HAVE_NBTOOL_CONFIG_H
 #include "nbtool_config.h"
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <stdio.h>
+
+#if defined(__minix)
+#include <minix/minlib.h>
+#include <minix/partition.h>
+#include <minix/u64.h>
+#include <sys/ioctl.h>
+#elif defined(__linux__)
+#include <mntent.h>
+#endif
+
 #include <assert.h>
+#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <stdint.h>
+
+/* Definition of the file system layout: */
 #include "const.h"
 #include "type.h"
 #include "mfsdir.h"
-#if defined(__minix)
-#include <minix/partition.h>
-#include <minix/u64.h>
-#include <minix/minlib.h>
-#include <sys/ioctl.h>
-#include <strings.h>
-#endif
-#include <dirent.h>
-
-
-
-#undef EXTERN
-#define EXTERN                 /* get rid of EXTERN by making it null */
 #include "super.h"
 
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
+#define INODE_MAP      START_BLOCK
+/* inode zone indexes pointing to single and double indirect zones */
+#define S_INDIRECT_IDX (NR_DZONES)
+#define D_INDIRECT_IDX (NR_DZONES+1)
+
 
-#define INODE_MAP            2
 #define MAX_TOKENS          10
 #define LINE_LEN           200
+/* XXX why do we not use 0 / SU_ID ? */
 #define BIN                  2
 #define BINGRP               2
-#define BIT_MAP_SHIFT       13
-#define INODE_MAX       ((unsigned) 65535)
-#define SECTOR_SIZE       512
-
-/* inode block indexes pointing to single and double indirect block */
-#define S_INDIRECT_IDX (V2_NR_DZONES)
-#define D_INDIRECT_IDX (V2_NR_DZONES+1)
 
 #if !defined(__minix)
-#define mul64u(a,b)    ((a) * (b))
+#define mul64u(a,b)    ((uint64_t)(a) * (b))
 #define lseek64(a,b,c,d) lseek(a,b,c)
-#ifdef __linux__
-#include <mntent.h>
 #endif
+
+/* some Minix specific types that do not conflict with Posix */
+#ifndef block_t
+typedef uint32_t block_t;      /* block number */
+#endif
+#ifndef zone_t
+typedef uint32_t zone_t;       /* zone number */
+#endif
+#ifndef bit_t
+typedef uint32_t bit_t;                /* bit number in a bit map */
+#endif
+#ifndef bitchunk_t
+typedef uint32_t bitchunk_t;   /* collection of bits in a bitmap */
 #endif
 
-typedef uint32_t block_t;
-typedef uint32_t zone_t;
-typedef uint32_t bitchunk_t;
+struct fs_size {
+  ino_t inocount; /* amount of inodes */
+  zone_t zonecount; /* amount of zones */
+  block_t blockcount; /* amount of bloks */
+};
 
 extern char *optarg;
 extern int optind;
 
-int next_zone, next_inode, zoff;
 block_t nrblocks;
-int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
-unsigned int nrinodes;
-int override = 0, simple = 0, dflag;
+int zone_per_block, zone_shift = 0;
+zone_t next_zone, zoff, nr_indirzones;
+int inodes_per_block, indir_per_block, indir_per_zone;
+unsigned int zone_size;
+ino_t nrinodes, inode_offset, next_inode;
+int lct = 0, fd, print = 0;
+int simple = 0, dflag = 0, verbose = 0;
 int donttest;                  /* skip test if it fits on medium */
 char *progname;
 
-uint32_t current_time, bin_time;
-char *zero, *lastp;
-char *umap_array;      /* bit map tells if block read yet */
-int umap_array_elements = 0;
+time_t current_time;
+char *zero;
+unsigned char *umap_array;     /* bit map tells if block read yet */
+size_t umap_array_elements;
 block_t zone_map;              /* where is zone map? (depends on # inodes) */
-int inodes_per_block;
+#ifndef MFS_STATIC_BLOCK_SIZE
 size_t block_size;
-int extra_space_percent;
+#else
+#define block_size     MFS_STATIC_BLOCK_SIZE
+#endif
 
 FILE *proto;
 
-#define getline _mkfs_getline
-
 int main(int argc, char **argv);
+void detect_fs_size(struct fs_size * fssize);
+void sizeup_dir(struct fs_size * fssize);
 block_t sizeup(char *device);
+static int bitmapsize(bit_t nr_bits, size_t blk_size);
 void super(zone_t zones, ino_t inodes);
 void rootdir(ino_t inode);
-int dir_try_enter(zone_t z, ino_t child, char *name);
+void enter_symlink(ino_t inode, char *link);
+int dir_try_enter(zone_t z, ino_t child, char const *name);
 void eat_dir(ino_t parent);
 void eat_file(ino_t inode, int f);
 void enter_dir(ino_t parent, char const *name, ino_t child);
-void enter_symlink(ino_t inode, char *link);
-d2_inode *get_inoblock(ino_t i, block_t *blockno, d2_inode **ino);
+void add_zone(ino_t n, zone_t z, size_t bytes, time_t cur_time);
+void incr_link(ino_t n);
 void incr_size(ino_t n, size_t count);
 static ino_t alloc_inode(int mode, int usrid, int grpid);
 static zone_t alloc_zone(void);
-void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
-void add_z_1(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
-void add_z_2(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
-void incr_link(ino_t n);
-void insert_bit(block_t block, int bit);
+void insert_bit(block_t block, bit_t bit);
 int mode_con(char *p);
-void getline(char line[LINE_LEN], char *parse[MAX_TOKENS]);
-void check_mtab(char *devname);
-uint32_t file_time(int f);
-__dead void pexit(char const *s);
-void copy(char *from, char *to, size_t count);
+void get_line(char line[LINE_LEN], char *parse[MAX_TOKENS]);
+void check_mtab(const char *devname);
+time_t file_time(int f);
+__dead void pexit(char const *s, ...) __printflike(1,2);
+void *alloc_block(void);
 void print_fs(void);
 int read_and_set(block_t n);
 void special(char *string);
-void get_block(block_t n, char *buf);
-void get_super_block(char *buf);
-void put_block(block_t n, char *buf);
-void mx_read(int blocknr, char *buf);
-void mx_write(int blocknr, char *buf);
-void dexit(char *s, int sectnum, int err);
 __dead void usage(void);
-void *alloc_block(void);
-
-struct fs_size {
-  ino_t inocount; /* amount of inodes */
-  zone_t zonecount; /* amount of zones */
-  block_t blockcount; /* amount of bloks */
-};
-
-void detect_fs_size(struct fs_size * fssize);
-void sizeup_dir(struct fs_size * fssize);
-void detect_size(void);
-void size_dir(void);
-static int bitmapsize(uint32_t nr_bits, size_t block_size);
+void get_block(block_t n, void *buf);
+void get_super_block(void *buf);
+void put_block(block_t n, void *buf);
 
 /*================================================================
  *                    mkfs  -  make filesystem
  *===============================================================*/
-int main(argc, argv)
-int argc;
-char *argv[];
+int
+main(int argc, char *argv[])
 {
-  int nread, mode, usrid, grpid, ch;
+  int nread, mode, usrid, grpid, ch, extra_space_percent;
   block_t blocks, maxblocks;
-  size_t i;
-  ino_t root_inum;
-  ino_t inodes;
-  zone_t zones;
-  char *token[MAX_TOKENS], line[LINE_LEN];
+  ino_t inodes, root_inum;
+  time_t bin_time;
+  char *token[MAX_TOKENS], line[LINE_LEN], *sfx;
   struct stat statbuf;
   struct fs_size fssize;
 
+  progname = argv[0];
+
   /* Get two times, the current time and the mod time of the binary of
    * mkfs itself.  When the -d flag is used, the later time is put into
    * the i_mtimes of all the files.  This feature is useful when
@@ -171,18 +158,42 @@ char *argv[];
    * want, then go.
    */
   current_time = time((time_t *) 0);   /* time mkfs is being run */
-  stat(argv[0], &statbuf);
-  bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
+  if (stat(progname, &statbuf)) {
+       perror("stat of itself");
+       bin_time = current_time;        /* provide some default value */
+  } else
+       bin_time = statbuf.st_mtime;    /* time when mkfs binary was last modified */
 
   /* Process switches. */
-  progname = argv[0];
   blocks = 0;
-  i = 0;
-  inodes_per_block = 0;
+  inodes = 0;
+#ifndef MFS_STATIC_BLOCK_SIZE
   block_size = 0;
+#endif
+  zone_shift = 0;
   extra_space_percent = 0;
-  while ((ch = getopt(argc, argv, "b:di:lotB:x:")) != EOF)
+  while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:")) != EOF)
        switch (ch) {
+#ifndef MFS_STATIC_BLOCK_SIZE
+           case 'B':
+               block_size = strtoul(optarg, &sfx, 0);
+               switch(*sfx) {
+               case 'b': case 'B': /* bytes; NetBSD-compatible */
+               case '\0':      break;
+               case 'K':
+               case 'k':       block_size*=1024; break;
+               case 's':       block_size*=SECTOR_SIZE; break;
+               default:        usage();
+               }
+               break;
+#else
+           case 'B':
+               if (block_size != strtoul(optarg, (char **) NULL, 0))
+                       errx(4, "block size must be exactly %d bytes",
+                           MFS_STATIC_BLOCK_SIZE);
+               break;
+               (void)sfx;      /* shut up warnings about unused variable...*/
+#endif
            case 'b':
                blocks = strtoul(optarg, (char **) NULL, 0);
                break;
@@ -191,13 +202,13 @@ char *argv[];
                current_time = bin_time;
                break;
            case 'i':
-               i = strtoul(optarg, (char **) NULL, 0);
+               inodes = strtoul(optarg, (char **) NULL, 0);
                break;
            case 'l':   print = 1;      break;
-           case 'o':   override = 1;   break;
            case 't':   donttest = 1;   break;
-           case 'B':   block_size = atoi(optarg);      break;
+           case 'v':   ++verbose;      break;
            case 'x':   extra_space_percent = atoi(optarg); break;
+           case 'z':   zone_shift = atoi(optarg);      break;
            default:    usage();
        }
 
@@ -208,29 +219,40 @@ char *argv[];
    */
   if(extra_space_percent < 0 || extra_space_percent > 2000) usage();
 
-  {
-       if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
-       if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
-               fprintf(stderr, "block size must be multiple of sector (%d) "
-                       "and at least %d bytes\n",
-                       SECTOR_SIZE, _MIN_BLOCK_SIZE);
-               pexit("specified block size illegal");
-       }
-       if(block_size%V2_INODE_SIZE) {
-               fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
-                       V2_INODE_SIZE);
-               pexit("specified block size illegal");
-       }
-  }
-
-  if(!inodes_per_block)
-       inodes_per_block = V2_INODES_PER_BLOCK(block_size);
+#ifdef DEFAULT_BLOCK_SIZE
+  if(!block_size) block_size = DEFAULT_BLOCK_SIZE;
+#endif
+  if (block_size % SECTOR_SIZE)
+       errx(4, "block size must be multiple of sector (%d bytes)", SECTOR_SIZE);
+#ifdef MIN_BLOCK_SIZE
+  if (block_size < MIN_BLOCK_SIZE)
+       errx(4, "block size must be at least %d bytes", MIN_BLOCK_SIZE);
+#endif
+#ifdef MAX_BLOCK_SIZE
+  if (block_size > MAX_BLOCK_SIZE)
+       errx(4, "block size must be at most %d bytes", MAX_BLOCK_SIZE);
+#endif
+  if(block_size%INODE_SIZE)
+       errx(4, "block size must be a multiple of inode size (%d bytes)", INODE_SIZE);
+
+  if(zone_shift < 0 || zone_shift > 14)
+       errx(4, "zone_shift must be a small non-negative integer");
+  zone_per_block = 1 << zone_shift;    /* nr of blocks per zone */
+
+  inodes_per_block = INODES_PER_BLOCK(block_size);
+  indir_per_block = INDIRECTS(block_size);
+  indir_per_zone = INDIRECTS(block_size) << zone_shift;
+  /* number of file zones we can address directly and with a single indirect*/
+  nr_indirzones = NR_DZONES + indir_per_zone;
+  zone_size = block_size << zone_shift;
+  /* Checks for an overflow: only with very big block size */
+  if (zone_size <= 0)
+       errx(4, "Zones are too big for this program; smaller -B or -z, please!");
 
   /* now that the block size is known, do buffer allocations where
    * possible.
    */
   zero = alloc_block();
-  bzero(zero, block_size);
 
   /* Determine the size of the device if not specified as -b or proto. */
   maxblocks = sizeup(argv[optind]);
@@ -240,9 +262,8 @@ char *argv[];
         * reporting a 0-sized device (displays usage).
         */
        if(blocks < 1) {
-               fprintf(stderr, "%s: zero size device.\n", progname);
-               return 1;
-       }
+               errx(1, "zero size device.");
+       }
   }
 
   /* The remaining args must be 'special proto', or just 'special' if the
@@ -250,10 +271,8 @@ char *argv[];
    */
   if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
 
-  if (blocks > maxblocks) {
-       fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
-               progname, argv[optind]);
-       return 1;
+  if (maxblocks && blocks > maxblocks) {
+       errx(1, "%s: number of blocks too large for device.", argv[optind]);
   }
 
   /* Check special. */
@@ -264,15 +283,15 @@ char *argv[];
   if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
        /* Prototype file is readable. */
        lct = 1;
-       getline(line, token);   /* skip boot block info */
+       get_line(line, token);  /* skip boot block info */
 
        /* Read the line with the block and inode counts. */
-       getline(line, token);
-       blocks = atol(token[0]);
-       inodes = atoi(token[1]);
+       get_line(line, token);
+       blocks = strtol(token[0], (char **) NULL, 10);
+       inodes = strtol(token[1], (char **) NULL, 10);
 
        /* Process mode line for root directory. */
-       getline(line, token);
+       get_line(line, token);
        mode = mode_con(token[0]);
        usrid = atoi(token[1]);
        grpid = atoi(token[2]);
@@ -283,28 +302,35 @@ char *argv[];
                inodes = fssize.inocount;
                blocks += blocks*extra_space_percent/100;
                inodes += inodes*extra_space_percent/100;
-               printf("dynamically sized filesystem: %d blocks, %d inodes\n", blocks, 
-                       (unsigned int) inodes);
+/* XXX is it OK to write on stdout? Use warn() instead? Also consider using verbose */
+               printf("dynamically sized filesystem: %u blocks, %u inodes\n",
+                   (unsigned int) blocks, (unsigned int) inodes);
        }               
   } else {
        lct = 0;
        if (optind < argc) {
                /* Maybe the prototype file is just a size.  Check. */
                blocks = strtoul(optarg, (char **) NULL, 0);
-               if (blocks == 0) pexit("Can't open prototype file");
+               if (blocks == 0) errx(2, "Can't open prototype file");
        }
-       if (i == 0) {
-               uint32_t kb = ((unsigned long long) blocks * block_size) / 1024;
-               i = kb / 2;
-               if (kb >= 100000) i = kb / 4;
+       if (inodes == 0) {
+               long long kb = ((unsigned long long)blocks*block_size) / 1024;
+
+               inodes = kb / 2;
+               if (kb >= 100000) inodes = kb / 4;
+               if (kb >= 1000000) inodes = kb / 6;
+               if (kb >= 10000000) inodes = kb / 8;
+               if (kb >= 100000000) inodes = kb / 10;
+               if (kb >= 1000000000) inodes = kb / 12;
+/* XXX check overflow: with very large number of blocks, this results in insanely large number of inodes */
+/* XXX check underflow (if/when ino_t is signed), else the message below will look strange */
 
                /* round up to fill inode block */
-               i += inodes_per_block - 1;
-               i = i / inodes_per_block * inodes_per_block;
+               inodes += inodes_per_block - 1;
+               inodes = inodes / inodes_per_block * inodes_per_block;
        }
-       if (blocks < 5) pexit("Block count too small");
-       if (i < 1) pexit("Inode count too small");
-       inodes = (ino_t) i;
+       if (blocks < 5) errx(1, "Block count too small");
+       if (inodes < 1) errx(1, "Inode count too small");
 
        /* Make simple file system of the given size, using defaults. */
        mode = 040777;
@@ -316,74 +342,76 @@ char *argv[];
   nrblocks = blocks;
   nrinodes = inodes;
 
-{
-  size_t bytes;
-  bytes = 1 + blocks/8;
-  if(!(umap_array = malloc(bytes))) {
-       fprintf(stderr, "mkfs: can't allocate block bitmap (%u bytes).\n",
-               bytes);
-       exit(1);
-  }
-  umap_array_elements = bytes;
-}
+  umap_array_elements = 1 + blocks/8;
+  if(!(umap_array = malloc(umap_array_elements)))
+       err(1, "can't allocate block bitmap (%u bytes).",
+               (unsigned)umap_array_elements);
 
   /* Open special. */
   special(argv[--optind]);
 
   if (!donttest) {
-       short *testb;
+       uint16_t *testb;
        ssize_t w;
 
-       testb = (short *) alloc_block();
+       testb = alloc_block();
 
        /* Try writing the last block of partition or diskette. */
        if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
-               pexit("couldn't seek to last block to test size (1)");
+               err(1, "couldn't seek to last block to test size (1)");
        }
        testb[0] = 0x3245;
        testb[1] = 0x11FF;
        testb[block_size/2-1] = 0x1F2F;
-       if ((w=write(fd, (char *) testb, block_size)) != block_size) {
-               if(w < 0) perror("write");
-               printf("%d/%u\n", w, block_size);
-               pexit("File system is too big for minor device (write)");
-       }
+       if ((w=write(fd, testb, block_size)) != block_size)
+               err(1, "File system is too big for minor device (write1 %d/%u)",
+                   w, block_size);
        sync();                 /* flush write, so if error next read fails */
        if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
-               pexit("couldn't seek to last block to test size (2)");
+               err(1, "couldn't seek to last block to test size (2)");
        }
        testb[0] = 0;
        testb[1] = 0;
-       nread = read(fd, (char *) testb, block_size);
+       testb[block_size/2-1] = 0;
+       nread = read(fd, testb, block_size);
        if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
-               testb[block_size/2-1] != 0x1F2F) {
-               if(nread < 0) perror("read");
-printf("nread = %d\n", nread);
-printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]);
-               pexit("File system is too big for minor device (read)");
+           testb[block_size/2-1] != 0x1F2F) {
+               warn("nread = %d\n", nread);
+               warnx("testb = 0x%x 0x%x 0x%x\n",
+                   testb[0], testb[1], testb[block_size-1]);
+               errx(1, "File system is too big for minor device (read)");
        }
        lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL);
        testb[0] = 0;
        testb[1] = 0;
-       if (write(fd, (char *) testb, block_size) != block_size)
-               pexit("File system is too big for minor device (write2)");
+       testb[block_size/2-1] = 0;
+       if (write(fd, testb, block_size) != block_size)
+               err(1, "File system is too big for minor device (write2)");
        lseek(fd, 0L, SEEK_SET);
        free(testb);
   }
 
   /* Make the file-system */
 
-       put_block((block_t) 0, zero);   /* Write a null boot block. */
-
-  zones = nrblocks;
+  put_block(BOOT_BLOCK, zero);         /* Write a null boot block. */
+  put_block(BOOT_BLOCK+1, zero);       /* Write another null block. */
 
-  super(zones, inodes);
+  super(nrblocks >> zone_shift, inodes);
 
   root_inum = alloc_inode(mode, usrid, grpid);
   rootdir(root_inum);
   if (simple == 0) eat_dir(root_inum);
 
   if (print) print_fs();
+  else if (verbose > 1) {
+         if (zone_shift)
+               fprintf(stderr, "%d inodes used.     %u zones (%u blocks) used.\n",
+                   (int)next_inode-1, next_zone, next_zone*zone_per_block);
+         else
+               fprintf(stderr, "%d inodes used.     %u zones used.\n",
+                   (int)next_inode-1, next_zone);
+  }
+
   return(0);
 
   /* NOTREACHED */
@@ -392,56 +420,49 @@ printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]);
 /*================================================================
  *        detect_fs_size  -  determine image size dynamically
  *===============================================================*/
-void detect_fs_size(struct fs_size * fssize)
+void
+detect_fs_size(struct fs_size * fssize)
 {
   int prev_lct = lct;
-  uint32_t point = ftell(proto);
-  
+  off_t point = ftell(proto);
+  block_t initb;
+  zone_t initz;
+
   fssize->inocount = 1;        /* root directory node */
   fssize->zonecount = 0;
   fssize->blockcount = 0;
 
   sizeup_dir(fssize);
-       
-  uint32_t initb;
 
-  initb = bitmapsize((uint32_t) (1 + fssize->inocount), block_size);
-  initb += bitmapsize((uint32_t) fssize->zonecount, block_size);
+  initb = bitmapsize(1 + fssize->inocount, block_size);
+  initb += bitmapsize(fssize->zonecount, block_size);
   initb += START_BLOCK;
   initb += (fssize->inocount + inodes_per_block - 1) / inodes_per_block;
+  initz = (initb + zone_per_block - 1) >> zone_shift;
 
   fssize->blockcount = initb+ fssize->zonecount;
   lct = prev_lct;
   fseek(proto, point, SEEK_SET);
 }
 
-void sizeup_dir(struct fs_size * fssize)
+void
+sizeup_dir(struct fs_size * fssize)
 {
   char *token[MAX_TOKENS], *p;
   char line[LINE_LEN]; 
   FILE *f;
-  size_t size;
+  off_t size;
   int dir_entries = 2;
-  zone_t dir_zones = 0;
-  zone_t nr_dzones, nr_indirzones;
-
-  /* how many data blocks are addressed using a single indirect block? */
-  int indir_addressed = V2_INDIRECTS(block_size);
-
-  /* number of file zones we can address directly from the inode */
-  nr_dzones = V2_NR_DZONES;
-
-  /* number of file zones we can address directly and with a single indirect */
-  nr_indirzones = V2_NR_DZONES + indir_addressed;
+  zone_t dir_zones = 0, fzones, indirects;
 
   while (1) {
-       getline(line, token);
+       get_line(line, token);
        p = token[0];
        if (*p == '$') {
-               dir_zones = (dir_entries / (NR_DIR_ENTRIES(block_size)));               
-               if(dir_entries % (NR_DIR_ENTRIES(block_size)))
+               dir_zones = (dir_entries / (NR_DIR_ENTRIES(block_size) * zone_per_block));
+               if(dir_entries % (NR_DIR_ENTRIES(block_size) * zone_per_block))
                        dir_zones++;
-               if(dir_zones > nr_dzones)
+               if(dir_zones > NR_DZONES)
                        dir_zones++;    /* Max single indir */
                fssize->zonecount += dir_zones;
                return;
@@ -458,32 +479,29 @@ void sizeup_dir(struct fs_size * fssize)
        } else if (*p == 's') {
                fssize->zonecount++; /* Symlink contents is always stored a block */
        } else {
-               if ((f = fopen(token[4], "r")) == NULL) {
-                       fprintf(stderr, "%s: Can't open %s: %s\n",
-                               progname, token[4], strerror(errno));
-                               pexit("dynamic size detection failed");
+               if ((f = fopen(token[4], "rb")) == NULL) {
+                       pexit("dynamic size detection failed: can't open %s",
+                           token[4]);
+               } else if (fseek(f, 0, SEEK_END) < 0) {
+                       pexit("dynamic size detection failed: seek to end of %s",
+                           token[4]);
+               } else if ( (size = ftell(f)) == (off_t)(-1)) {
+                       pexit("dynamic size detection failed: can't tell size of %s",
+                           token[4]);
                } else {
-                       int indirects = 0;
-                       if (fseek(f, 0, SEEK_END) < 0) {
-                       fprintf(stderr, "%s: Can't seek to end of %s\n",
-                               progname, token[4]);
-                               pexit("dynamic size detection failed");
-                       }
-                       size = ftell(f);
                        fclose(f);
-                       zone_t fzones= roundup(size, block_size) / block_size;
-                       if (fzones > nr_dzones)
+                       fzones = roundup(size, zone_size) / zone_size;
+                       indirects = 0;
+                       /* XXX overflow? fzones is u32, size is potentially 64-bit */
+                       if (fzones > NR_DZONES)
                                indirects++; /* single indirect needed */
                        if (fzones > nr_indirzones) {
-                               int dindirect = 0;
-                               int dindirzones = fzones - nr_indirzones;
-
-                               /* how many zones needed to point to data
-                                * blocks?
+                               /* Each further group of 'indir_per_zone'
+                                * needs one supplementary indirect zone:
                                 */
-                               dindirect = 1 + roundup(dindirzones,
-                                       indir_addressed) / indir_addressed;
-                               indirects += dindirect;
+                               indirects += roundup(fzones - nr_indirzones,
+                                   indir_per_zone) / indir_per_zone;
+                               indirects++;    /* + double indirect needed!*/
                        }
                        fssize->zonecount += fzones + indirects;
                }
@@ -494,8 +512,8 @@ void sizeup_dir(struct fs_size * fssize)
 /*================================================================
  *                    sizeup  -  determine device size
  *===============================================================*/
-block_t sizeup(device)
-char *device;
+block_t
+sizeup(char * device)
 {
   block_t d;
 #if defined(__minix)
@@ -523,16 +541,22 @@ char *device;
 
   resize = add64u(mul64u(d, block_size), rem);
   if(cmp64(resize, bytes) != 0) {
-       d = ULONG_MAX;
-       fprintf(stderr, "mkfs: truncating FS at %u blocks\n", d);
+       /* Assume block_t is unsigned */
+       d = (block_t)(-1ul);
+       fprintf(stderr, "%s: truncating FS at %lu blocks\n",
+               progname, (unsigned long)d);
   }
 #else
   size = lseek(fd, 0, SEEK_END);
-  if (size == (off_t) -1) {
-         fprintf(stderr, "Cannot get device size fd=%d\n", fd);
-         exit(-1);
-  }
-  d = size / block_size;
+  if (size == (off_t) -1)
+         err(1, "cannot get device size fd=%d: %s", fd, device);
+  /* Assume block_t is unsigned */
+  if (size / block_size > (block_t)(-1ul)) {
+       d = (block_t)(-1ul);
+       fprintf(stderr, "%s: truncating FS at %lu blocks\n",
+               progname, (unsigned long)d);
+  } else
+       d = size / block_size;
 #endif
 
   return d;
@@ -541,12 +565,13 @@ char *device;
 /*
  * copied from fslib
  */
-static int bitmapsize(uint32_t nr_bits, size_t blk_size)
+static int
+bitmapsize(bit_t nr_bits, size_t blk_size)
 {
   block_t nr_blocks;
 
-  nr_blocks = (int) (nr_bits / FS_BITS_PER_BLOCK(blk_size));
-  if (((uint32_t) nr_blocks * FS_BITS_PER_BLOCK(blk_size)) < nr_bits)
+  nr_blocks = nr_bits / FS_BITS_PER_BLOCK(blk_size);
+  if (nr_blocks * FS_BITS_PER_BLOCK(blk_size) < nr_bits)
        ++nr_blocks;
   return(nr_blocks);
 }
@@ -555,50 +580,54 @@ static int bitmapsize(uint32_t nr_bits, size_t blk_size)
  *                 super  -  construct a superblock
  *===============================================================*/
 
-void super(zones, inodes)
-zone_t zones;
-ino_t inodes;
+void
+super(zone_t zones, ino_t inodes)
 {
-  unsigned int i;
-  int inodeblks;
-  int initblks;
-  uint32_t nb;
-  zone_t v2sq;
-  zone_t zo;
+  block_t inodeblks, initblks, i;
+  unsigned long nb;
+  long long ind_per_zone, zo;
+  void *buf;
   struct super_block *sup;
-  char *buf, *cp;
 
-  buf = alloc_block();
-
-  for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
-  sup = (struct super_block *) buf;    /* lint - might use a union */
+  sup = buf = alloc_block();
 
+#ifdef MFSFLAG_CLEAN
   /* The assumption is that mkfs will create a clean FS. */
   sup->s_flags = MFSFLAG_CLEAN;
+#endif
 
   sup->s_ninodes = inodes;
+  /* Check for overflow; cannot happen on V3 file systems */
+  if(inodes != sup->s_ninodes)
+       errx(1, "Too much inodes for that version of Minix FS.");
   sup->s_nzones = 0;   /* not used in V2 - 0 forces errors early */
   sup->s_zones = zones;
+  /* Check for overflow; can only happen on V1 file systems */
+  if(zones != sup->s_zones)
+       errx(1, "Too much zones (blocks) for that version of Minix FS.");
   
-#define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
-  sup->s_imap_blocks = nb = bitmapsize((uint32_t) (1 + inodes), block_size);
-  /* Checks for an overflow nb is uint32_t while s_imap_blocks is of type 
+#ifndef MFS_STATIC_BLOCK_SIZE
+#define BIGGERBLOCKS "Please try a larger block size for an FS of this size."
+#else
+#define BIGGERBLOCKS "Please use MinixFS V3 for an FS of this size."
+#endif
+  sup->s_imap_blocks = nb = bitmapsize(1 + inodes, block_size);
+  /* Checks for an overflow: nb is uint32_t while s_imap_blocks is of type
    * int16_t */
   if(sup->s_imap_blocks != nb) {
-       fprintf(stderr, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS);
-       exit(1);
+       errx(1, "too many inode bitmap blocks.\n" BIGGERBLOCKS);
   }
-  sup->s_zmap_blocks = nb = bitmapsize((uint32_t) zones, block_size);
+  sup->s_zmap_blocks = nb = bitmapsize(zones, block_size);
   /* Idem here check for overflow */
   if(nb != sup->s_zmap_blocks) {
-       fprintf(stderr, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS);
-       exit(1);
+       errx(1, "too many block bitmap blocks.\n" BIGGERBLOCKS);
   }
   inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks;
   inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
   initblks = inode_offset + inodeblks;
-  sup->s_firstdatazone_old = nb = initblks;
-  if(nb >= zones) pexit("bit maps too large");
+  sup->s_firstdatazone_old = nb =
+       (initblks + (1 << zone_shift) - 1) >> zone_shift;
+  if(nb >= zones) errx(1, "bit maps too large");
   if(nb != sup->s_firstdatazone_old) {
        /* The field is too small to store the value. Fortunately, the value
         * can be computed from other fields. We set the on-disk field to zero
@@ -609,31 +638,51 @@ ino_t inodes;
   }
   sup->s_firstdatazone = nb;
   zoff = sup->s_firstdatazone - 1;
-  sup->s_log_zone_size = 0;
-  {
-       v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
-       zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
-       {
-               sup->s_magic = SUPER_V3;
-               sup->s_block_size = block_size;
-               sup->s_disk_version = 0;
-#define MAX_MAX_SIZE   (INT_MAX)
-               if(MAX_MAX_SIZE/block_size < zo) {
-                       sup->s_max_size = (int32_t) MAX_MAX_SIZE;
-               }
-               else {
-                       sup->s_max_size = zo * block_size;
-               }
-       }
-  }
+  sup->s_log_zone_size = zone_shift;
+  sup->s_magic = SUPER_MAGIC;
+#ifdef MFS_SUPER_BLOCK_SIZE
+  sup->s_block_size = block_size;
+  /* Check for overflow */
+  if(block_size != sup->MFS_SUPER_BLOCK_SIZE)
+       errx(1, "block_size too large.");
+  sup->s_disk_version = 0;
+#endif
 
-  if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
-       pexit("super() couldn't seek");
+  ind_per_zone = (long long) indir_per_zone;
+  zo = NR_DZONES + ind_per_zone + ind_per_zone*ind_per_zone;
+#ifndef MAX_MAX_SIZE
+#define MAX_MAX_SIZE   (INT32_MAX)
+#endif
+  if(MAX_MAX_SIZE/block_size < zo) {
+       sup->s_max_size = MAX_MAX_SIZE;
   }
-  if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
-       pexit("super() couldn't write");
+  else {
+       sup->s_max_size = zo * block_size;
   }
 
+  if (verbose>1) {
+       fprintf(stderr, "Super block values:\n"
+           "\tnumber of inodes\t%12d\n"
+           "\tnumber of zones \t%12d\n"
+           "\tinode bit map blocks\t%12d\n"
+           "\tzone bit map blocks\t%12d\n"
+           "\tfirst data zone \t%12d\n"
+           "\tblocks per zone shift\t%12d\n"
+           "\tmaximum file size\t%12d\n"
+           "\tmagic number\t\t%#12X\n",
+           sup->s_ninodes, sup->s_zones,
+           sup->s_imap_blocks, sup->s_zmap_blocks, sup->s_firstdatazone,
+           sup->s_log_zone_size, sup->s_max_size, sup->s_magic);
+#ifdef MFS_SUPER_BLOCK_SIZE
+       fprintf(stderr, "\tblock size\t\t%12d\n", sup->s_block_size);
+#endif
+  }
+
+  if (lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) == (off_t) -1)
+       err(1, "super() couldn't seek");
+  if (write(fd, buf, SUPER_BLOCK_BYTES) != SUPER_BLOCK_BYTES)
+       err(1, "super() couldn't write");
+
   /* Clear maps and inodes. */
   for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero);
 
@@ -653,8 +702,8 @@ ino_t inodes;
 /*================================================================
  *              rootdir  -  install the root directory
  *===============================================================*/
-void rootdir(inode)
-ino_t inode;
+void
+rootdir(ino_t inode)
 {
   zone_t z;
 
@@ -666,17 +715,22 @@ ino_t inode;
   incr_link(inode);
 }
 
-void enter_symlink(ino_t inode, char *lnk)
+void
+enter_symlink(ino_t inode, char *lnk)
 {
   zone_t z;
+  size_t len;
   char *buf;
 
   buf = alloc_block();
   z = alloc_zone();
+  len = strlen(lnk);
+  if (len >= block_size)
+       pexit("symlink too long, max length is %u", (unsigned)block_size - 1);
   strcpy(buf, lnk);
-  put_block(z, buf);
+  put_block((z << zone_shift), buf);
 
-  add_zone(inode, z, (size_t) strlen(lnk), current_time);
+  add_zone(inode, z, len, current_time);
 
   free(buf);
 }
@@ -685,8 +739,8 @@ void enter_symlink(ino_t inode, char *lnk)
 /*================================================================
  *         eat_dir  -  recursively install directory
  *===============================================================*/
-void eat_dir(parent)
-ino_t parent;
+void
+eat_dir(ino_t parent)
 {
   /* Read prototype lines and set up directory. Recurse if need be. */
   char *token[MAX_TOKENS], *p;
@@ -697,7 +751,7 @@ ino_t parent;
   size_t size;
 
   while (1) {
-       getline(line, token);
+       get_line(line, token);
        p = token[0];
        if (*p == '$') return;
        p = token[1];
@@ -748,100 +802,97 @@ ino_t parent;
  *             eat_file  -  copy file to MINIX
  *===============================================================*/
 /* Zonesize >= blocksize */
-void eat_file(inode, f)
-ino_t inode;
-int f;
+void
+eat_file(ino_t inode, int f)
 {
-  int ct, k;
+  int ct = 0, i, j;
   zone_t z = 0;
   char *buf;
-  uint32_t timeval;
+  time_t timeval;
 
   buf = alloc_block();
 
   do {
-       for (k = 0; k < block_size; k++) buf[k] = 0;
-       if ((ct = read(f, buf, block_size)) > 0) {
-               z = alloc_zone();
-               put_block(z, buf);
+       for (i = 0, j = 0; i < zone_per_block; i++, j += ct) {
+               memset(buf, 0, block_size);
+               if ((ct = read(f, buf, block_size)) > 0) {
+                       if (i == 0) z = alloc_zone();
+                       put_block((z << zone_shift) + i, buf);
+               }
        }
        timeval = (dflag ? current_time : file_time(f));
-       if (ct) add_zone(inode, z, (size_t) ct, timeval);
+       if (ct) add_zone(inode, z, (size_t) j, timeval);
   } while (ct == block_size);
   close(f);
   free(buf);
 }
 
-d2_inode *get_inoblock(ino_t i, block_t *blockno, d2_inode **ino)
-{
-       int off;
-       d2_inode *inoblock = alloc_block();
-       *blockno = ((i - 1) / inodes_per_block) + inode_offset;
-       off = (i - 1) % inodes_per_block;
-       get_block(*blockno, (char *) inoblock);
-       *ino = inoblock + off;
-       return inoblock;
-}
-
-int dir_try_enter(zone_t z, ino_t child, char *name)
+int
+dir_try_enter(zone_t z, ino_t child, char const *name)
 {
-       char *p1, *p2;
-       struct direct *dir_entry = alloc_block();
-       int r = 0;
-       int i;
+  struct direct *dir_entry = alloc_block();
+  int r = 0;
+  block_t b;
+  int i, l;
 
-       get_block(z, (char *) dir_entry);
+  b = z << zone_shift;
+  for (l = 0; l < zone_per_block; l++, b++) {
+       get_block(b, dir_entry);
 
        for (i = 0; i < NR_DIR_ENTRIES(block_size); i++)
-               if (!dir_entry[i].mfs_d_ino)
+               if (!dir_entry[i].d_ino)
                        break;
 
        if(i < NR_DIR_ENTRIES(block_size)) {
-               int j;
-
                r = 1;
-               dir_entry[i].mfs_d_ino = child;
-               p1 = name;
-               p2 = dir_entry[i].mfs_d_name;
-               j = sizeof(dir_entry[i].mfs_d_name);
-               assert(j == 60);
-               while (j--) {
-                       *p2++ = *p1;
-                       if (*p1 != 0) p1++;
-               }
+               dir_entry[i].d_ino = child;
+               assert(sizeof(dir_entry[i].d_name) == MFS_DIRSIZ);
+               if (verbose && strlen(name) > MFS_DIRSIZ)
+                       fprintf(stderr, "File name %s is too long, truncated\n", name);
+               strncpy(dir_entry[i].d_name, name, MFS_DIRSIZ);
+               put_block(b, dir_entry);
+               break;
        }
+  }
 
-       put_block(z, (char *) dir_entry);
-       free(dir_entry);
+  free(dir_entry);
 
-       return r;
+  return r;
 }
 
 /*================================================================
  *         directory & inode management assist group
  *===============================================================*/
-void enter_dir(ino_t parent, char const *name, ino_t child)
+void
+enter_dir(ino_t parent, char const *name, ino_t child)
 {
   /* Enter child in parent directory */
   /* Works for dir > 1 block and zone > block */
   unsigned int k;
-  block_t b;
+  block_t b, indir;
   zone_t z;
+  int off;
+  struct inode *ino;
+  struct inode *inoblock = alloc_block();
   zone_t *indirblock = alloc_block();
-  d2_inode *ino;
-  d2_inode *inoblock = get_inoblock(parent, &b, &ino);
 
   assert(!(block_size % sizeof(struct direct)));
 
-  for (k = 0; k < V2_NR_DZONES; k++) {
-       z = ino->d2_zone[k];
+  /* Obtain the inode structure */
+  b = ((parent - 1) / inodes_per_block) + inode_offset;
+  off = (parent - 1) % inodes_per_block;
+  get_block(b, inoblock);
+  ino = inoblock + off;
+
+  for (k = 0; k < NR_DZONES; k++) {
+       z = ino->i_zone[k];
        if (z == 0) {
                z = alloc_zone();
-               ino->d2_zone[k] = z;
+               ino->i_zone[k] = z;
        }
 
        if(dir_try_enter(z, child, __UNCONST(name))) {
-               put_block(b, (char *) inoblock);
+               put_block(b, inoblock);
                free(inoblock);
                free(indirblock);
                return;
@@ -849,160 +900,175 @@ void enter_dir(ino_t parent, char const *name, ino_t child)
   }
 
   /* no space in directory using just direct blocks; try indirect */
-  if (ino->d2_zone[S_INDIRECT_IDX] == 0)
-       ino->d2_zone[S_INDIRECT_IDX] = alloc_zone();
-
-  get_block(ino->d2_zone[S_INDIRECT_IDX], (char *) indirblock);
-
-  for(k = 0; k < V2_INDIRECTS(block_size); k++) {
-       z = indirblock[k];
-       if(!z) z = indirblock[k] = alloc_zone();
-
+  if (ino->i_zone[S_INDIRECT_IDX] == 0)
+       ino->i_zone[S_INDIRECT_IDX] = alloc_zone();
+
+  indir = ino->i_zone[S_INDIRECT_IDX] << zone_shift;
+  --indir; /* Compensate for ++indir below */
+  for(k = 0; k < (indir_per_zone); k++) {
+       if (k % indir_per_block == 0)
+               get_block(++indir, indirblock);
+       z = indirblock[k % indir_per_block];
+       if(!z) {
+               z = indirblock[k % indir_per_block] = alloc_zone();
+               put_block(indir, indirblock);
+       }
        if(dir_try_enter(z, child, __UNCONST(name))) {
-               put_block(b, (char *) inoblock);
-               put_block(ino->d2_zone[S_INDIRECT_IDX], (char *) indirblock);
+               put_block(b, inoblock);
                free(inoblock);
                free(indirblock);
                return;
        }
   }
 
-  printf("Directory-inode %u beyond direct blocks.  Could not enter %s\n",
-         parent, name);
-  pexit("Halt");
+  pexit("Directory-inode %u beyond single indirect blocks.  Could not enter %s",
+         (unsigned)parent, name);
 }
 
 
-void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time)
+void
+add_zone(ino_t n, zone_t z, size_t bytes, time_t mtime)
 {
   /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
 
-  int off, i;
-  block_t b, inodeblock;
-  zone_t dindir, indir;
-  zone_t *dinblk, *blk;
-  d2_inode *p;
-  d2_inode *inode;
-
-  if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
-       pexit("Couldn't allocate indirect block");
+  int off, i, j;
+  block_t b;
+  zone_t indir, dindir;
+  struct inode *p, *inode;
+  zone_t *blk, *dblk;
 
-  if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
-       pexit("Couldn't allocate block of inodes");
+  assert(inodes_per_block*sizeof(*inode) == block_size);
+  if(!(inode = alloc_block()))
+       err(1, "Couldn't allocate block of inodes");
 
-  inodeblock = b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
-  off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
-  get_block(b, (char *) inode);
+  b = ((n - 1) / inodes_per_block) + inode_offset;
+  off = (n - 1) % inodes_per_block;
+  get_block(b, inode);
   p = &inode[off];
-  p->d2_size += bytes;
-  p->d2_mtime = cur_time;
-  for (i = 0; i < V2_NR_DZONES; i++)
-       if (p->d2_zone[i] == 0) {
-               p->d2_zone[i] = z;
-               put_block(inodeblock, (char *) inode);
-               free(blk);
+  p->i_size += bytes;
+  p->i_mtime = mtime;
+#ifndef MFS_INODE_ONLY_MTIME /* V1 file systems did not have them... */
+  p->i_atime = p->i_ctime = current_time;
+#endif
+  for (i = 0; i < NR_DZONES; i++)
+       if (p->i_zone[i] == 0) {
+               p->i_zone[i] = z;
+               put_block(b, inode);
                free(inode);
                return;
        }
-  put_block(inodeblock, (char *) inode);
+
+  assert(indir_per_block*sizeof(*blk) == block_size);
+  if(!(blk = alloc_block()))
+       err(1, "Couldn't allocate indirect block");
 
   /* File has grown beyond a small file. */
-  if (p->d2_zone[S_INDIRECT_IDX] == 0)
-       p->d2_zone[S_INDIRECT_IDX] = alloc_zone();
-  indir = p->d2_zone[S_INDIRECT_IDX];
-  put_block(inodeblock, (char *) inode);
-  b = indir;
-  get_block(b, (char *) blk);
-  for (i = 0; i < V2_INDIRECTS(block_size); i++)
-       if (blk[i] == 0) {
+  if (p->i_zone[S_INDIRECT_IDX] == 0)
+       p->i_zone[S_INDIRECT_IDX] = alloc_zone();
+  indir = p->i_zone[S_INDIRECT_IDX] << zone_shift;
+  put_block(b, inode);
+  --indir; /* Compensate for ++indir below */
+  for (i = 0; i < (indir_per_zone); i++) {
+       if (i % indir_per_block == 0)
+               get_block(++indir, blk);
+       if (blk[i % indir_per_block] == 0) {
                blk[i] = z;
-               put_block(b, (char *) blk);
+               put_block(indir, blk);
                free(blk);
                free(inode);
                return;
        }
-  put_block(b, (char *) blk);
-
-  if(!(dinblk = malloc(block_size)))
-       pexit("Couldn't allocate double indirect block");
-
-  /* We need a double indirect. */
-  if (!p->d2_zone[D_INDIRECT_IDX]) p->d2_zone[D_INDIRECT_IDX] = alloc_zone();
-  dindir = p->d2_zone[D_INDIRECT_IDX];
-  get_block(dindir, (char *) dinblk);
-  put_block(inodeblock, (char *) inode);
-
-  /* Iterate over pointers to the next indirect block */
-  for (i = 0; i < V2_INDIRECTS(block_size); i++) {
-       int j;
-       if (dinblk[i] == 0) dinblk[i] = alloc_zone();
-       indir = dinblk[i];
-       get_block(indir, (char *) blk);
-       for (j = 0; j < V2_INDIRECTS(block_size); j++) {
-               if (blk[j] == 0) {
-                       blk[j] = z;
-                       put_block(indir, (char *) blk);
-                       put_block(dindir, (char *) dinblk);
-                       free(blk);
-                       free(dinblk);
+  }
+
+  /* File has grown beyond single indirect; we need a double indirect */
+  assert(indir_per_block*sizeof(*dblk) == block_size);
+  if(!(dblk = alloc_block()))
+       err(1, "Couldn't allocate double indirect block");
+
+  if (p->i_zone[D_INDIRECT_IDX] == 0)
+       p->i_zone[D_INDIRECT_IDX] = alloc_zone();
+  dindir = p->i_zone[D_INDIRECT_IDX] << zone_shift;
+  put_block(b, inode);
+  --dindir; /* Compensate for ++indir below */
+  for (j = 0; j < (indir_per_zone); j++) {
+       if (j % indir_per_block == 0)
+               get_block(++dindir, dblk);
+       if (dblk[j % indir_per_block] == 0)
+               dblk[j % indir_per_block] = alloc_zone();
+       indir = dblk[j % indir_per_block] << zone_shift;
+       --indir; /* Compensate for ++indir below */
+       for (i = 0; i < (indir_per_zone); i++) {
+               if (i % indir_per_block == 0)
+                       get_block(++indir, blk);
+               if (blk[i % indir_per_block] == 0) {
+                       blk[i] = z;
+                       put_block(dindir, dblk);
+                       put_block(indir, blk);
+                       free(dblk);
+                       free(blk);
                        free(inode);
                        return;
                }
        }
-       put_block(indir, (char *) blk);
   }
 
   pexit("File has grown beyond double indirect");
 }
 
 
-void incr_link(n)
-ino_t n;
+/* Increment the link count to inode n */
+void
+incr_link(ino_t n)
 {
-  /* Increment the link count to inode n */
   int off;
   static int enter = 0;
+  static struct inode *inodes = NULL;
   block_t b;
 
-  if(enter) exit(1);
+  if (enter++) pexit("internal error: recursive call to incr_link()");
 
   b = ((n - 1) / inodes_per_block) + inode_offset;
   off = (n - 1) % inodes_per_block;
   {
-       static d2_inode *inode2 = NULL;
-       int s;
-
-       s = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
-       if(!inode2 && !(inode2 = malloc(s)))
-               pexit("couldn't allocate a block of inodes");
-
-       get_block(b, (char *) inode2);
-       inode2[off].d2_nlinks++;
-       put_block(b, (char *) inode2);
+       assert(sizeof(*inodes) * inodes_per_block == block_size);
+       if(!inodes && !(inodes = alloc_block()))
+               err(1, "couldn't allocate a block of inodes");
+
+       get_block(b, inodes);
+       inodes[off].i_nlinks++;
+       /* Check overflow (particularly on V1)... */
+       if (inodes[off].i_nlinks <= 0)
+               pexit("Too many links to a directory");
+       put_block(b, inodes);
   }
   enter = 0;
 }
 
 
-void incr_size(n, count)
-ino_t n;
-size_t count;
+/* Increment the file-size in inode n */
+void
+incr_size(ino_t n, size_t count)
 {
-  /* Increment the file-size in inode n */
   block_t b;
   int off;
 
   b = ((n - 1) / inodes_per_block) + inode_offset;
   off = (n - 1) % inodes_per_block;
   {
-       d2_inode *inode2;
-       if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
-               pexit("couldn't allocate a block of inodes");
-
-       get_block(b, (char *) inode2);
-       inode2[off].d2_size += count;
-       put_block(b, (char *) inode2);
-       free(inode2);
+       struct inode *inodes;
+
+       assert(inodes_per_block * sizeof(*inodes) == block_size);
+       if(!(inodes = alloc_block()))
+               err(1, "couldn't allocate a block of inodes");
+
+       get_block(b, inodes);
+       /* Check overflow; avoid compiler spurious warnings */
+       if (inodes[off].i_size+(int)count < inodes[off].i_size ||
+           inodes[off].i_size > MAX_MAX_SIZE-(int)count)
+               pexit("File has become too big to be handled by MFS");
+       inodes[off].i_size += count;
+       put_block(b, inodes);
+       free(inodes);
   }
 }
 
@@ -1010,88 +1076,90 @@ size_t count;
 /*================================================================
  *                  allocation assist group
  *===============================================================*/
-static ino_t alloc_inode(mode, usrid, grpid)
-int mode, usrid, grpid;
+static ino_t
+alloc_inode(int mode, int usrid, int grpid)
 {
   ino_t num;
   int off;
   block_t b;
+  struct inode *inodes;
 
   num = next_inode++;
   if (num > nrinodes) {
-       fprintf(stderr, "have %d inodoes\n", nrinodes);
-       pexit("File system does not have enough inodes");
+       pexit("File system does not have enough inodes (only %d)", nrinodes);
   }
   b = ((num - 1) / inodes_per_block) + inode_offset;
   off = (num - 1) % inodes_per_block;
-  {
-       d2_inode *inode2;
-
-       if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
-               pexit("couldn't allocate a block of inodes");
 
-       get_block(b, (char *) inode2);
-       inode2[off].d2_mode = mode;
-       inode2[off].d2_uid = usrid;
-       inode2[off].d2_gid = grpid;
-       put_block(b, (char *) inode2);
+  assert(inodes_per_block * sizeof(*inodes) == block_size);
+  if(!(inodes = alloc_block()))
+       err(1, "couldn't allocate a block of inodes");
 
-       free(inode2);
+  get_block(b, inodes);
+  if (inodes[off].i_mode) {
+       pexit("allocation new inode %d with non-zero mode - this cannot happen",
+               num);
   }
+  inodes[off].i_mode = mode;
+  inodes[off].i_uid = usrid;
+  inodes[off].i_gid = grpid;
+  if (verbose && (inodes[off].i_uid != usrid || inodes[off].i_gid != grpid))
+       fprintf(stderr, "Uid/gid %d.%d do not fit within inode, truncated\n", usrid, grpid);
+  put_block(b, inodes);
 
-  /* Code bellow assumes the bit is in the first inode map block. */
-  assert(num < block_size * 8);
+  free(inodes);
 
   /* Set the bit in the bit map. */
-  insert_bit((block_t) INODE_MAP, (int) num);
+  insert_bit((block_t) INODE_MAP, num);
   return(num);
 }
 
 
-static zone_t alloc_zone()
+/* Allocate a new zone */
+static zone_t
+alloc_zone(void)
 {
-  /* Allocate a new zone */
   /* Works for zone > block */
   block_t b;
-  zone_t z,z_number;
-  unsigned int bits_per_block;
+  int i;
+  zone_t z;
 
   z = next_zone++;
-  b = z;
-  if ((b + 1) > nrblocks)
+  b = z << zone_shift;
+  if (b > nrblocks - zone_per_block)
        pexit("File system not big enough for all the files");
-  put_block(b, zero);  /* give an empty zone */
-
+  for (i = 0; i < zone_per_block; i++)
+       put_block(b + i, zero); /* give an empty zone */
   
-  bits_per_block = block_size * 8;
-  /* translate to block number */
-  z_number = z - zoff;
-
-  insert_bit(zone_map  + ( z_number / bits_per_block ), (int) (z_number % bits_per_block ));   /* lint, NOT OK because
-                                                * z hasn't been broken
-                                                * up into block +
-                                                * offset yet. */
+  insert_bit(zone_map, z - zoff);
   return z;
 }
 
 
-void insert_bit(block, bit)
-block_t block;
-int bit;
+/* Insert one bit into the bitmap */
+void
+insert_bit(block_t map, bit_t bit)
 {
-  /* Insert 'count' bits in the bitmap */
-  int w, s;
+  int boff, w, s;
+  unsigned int bits_per_block;
+  block_t map_block;
   bitchunk_t *buf;
 
-  buf = (bitchunk_t *) alloc_block();
+  buf = alloc_block();
 
-  assert(bit >=0);
-  assert(bit < block_size * 8);
-  get_block(block, (char *) buf);
-  w = bit / (8 * sizeof(bitchunk_t));
-  s = bit % (8 * sizeof(bitchunk_t));
+  bits_per_block = FS_BITS_PER_BLOCK(block_size);
+  map_block = map + bit / bits_per_block;
+  if (map_block >= inode_offset)
+       pexit("insertbit invades inodes area - this cannot happen");
+  boff = bit % bits_per_block;
+
+  assert(boff >=0);
+  assert(boff < FS_BITS_PER_BLOCK(block_size));
+  get_block(map_block, buf);
+  w = boff / FS_BITCHUNK_BITS;
+  s = boff % FS_BITCHUNK_BITS;
   buf[w] |= (1 << s);
-  put_block(block, (char *) buf);
+  put_block(map_block, buf);
 
   free(buf);
 }
@@ -1100,8 +1168,7 @@ int bit;
 /*================================================================
  *             proto-file processing assist group
  *===============================================================*/
-int mode_con(p)
-char *p;
+int mode_con(char *p)
 {
   /* Convert string to mode */
   int o1, o2, o3, mode;
@@ -1118,15 +1185,17 @@ char *p;
   if (c1 == 'b') mode |= S_IFBLK;
   if (c1 == 'c') mode |= S_IFCHR;
   if (c1 == 's') mode |= S_IFLNK;
+  if (c1 == 'l') mode |= S_IFLNK;      /* just to be somewhat ls-compatible*/
+/* XXX note: some other mkfs programs consider L to create hardlinks */
   if (c1 == '-') mode |= S_IFREG;
   if (c2 == 'u') mode |= S_ISUID;
   if (c3 == 'g') mode |= S_ISGID;
+/* XXX There are no way to encode S_ISVTX */
   return(mode);
 }
 
-void getline(line, parse)
-char *parse[MAX_TOKENS];
-char line[LINE_LEN];
+void
+get_line(char line[LINE_LEN], char *parse[MAX_TOKENS])
 {
   /* Read a line and break it up in tokens */
   int k;
@@ -1134,18 +1203,17 @@ char line[LINE_LEN];
   int d;
 
   for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
-  for (k = 0; k < LINE_LEN; k++) line[k] = 0;
+  memset(line, 0, LINE_LEN);
   k = 0;
-  parse[0] = 0;
   p = line;
   while (1) {
        if (++k > LINE_LEN) pexit("Line too long");
        d = fgetc(proto);
        if (d == EOF) pexit("Unexpected end-of-file");
        *p = d;
-       if (*p == '\n') lct++;
        if (*p == ' ' || *p == '\t') *p = 0;
        if (*p == '\n') {
+               lct++;
                *p++ = 0;
                *p = '\n';
                break;
@@ -1155,7 +1223,6 @@ char line[LINE_LEN];
 
   k = 0;
   p = line;
-  lastp = line;
   while (1) {
        c = *p++;
        if (c == '\n') return;
@@ -1171,10 +1238,13 @@ char line[LINE_LEN];
 /*================================================================
  *                     other stuff
  *===============================================================*/
-void check_mtab(device)
-char *device;                  /* /dev/hd1 or whatever */
+
+/*
+ * Check to see if the special file named 'device' is mounted.
+ */
+void
+check_mtab(const char *device)         /* /dev/hd1 or whatever */
 {
-/* Check to see if the special file named in s is mounted. */
 #if defined(__minix)
   int n, r;
   struct stat sb;
@@ -1186,9 +1256,7 @@ char *device;                     /* /dev/hd1 or whatever */
   {
        if (errno == ENOENT)
                return; /* Does not exist, and therefore not mounted. */
-       fprintf(stderr, "%s: stat %s failed: %s\n",
-               progname, device, strerror(errno));
-       exit(1);
+       err(1, "stat %s failed", device);
   }
   if (!S_ISBLK(sb.st_mode))
   {
@@ -1202,9 +1270,7 @@ char *device;                     /* /dev/hd1 or whatever */
        if (n < 0) return;
        if (strcmp(device, dev) == 0) {
                /* Can't mkfs on top of a mounted file system. */
-               fprintf(stderr, "%s: %s is mounted on %s\n",
-                       progname, device, mount_point);
-               exit(1);
+               errx(1, "%s is mounted on %s", device, mount_point);
        }
   }
 #elif defined(__linux__)
@@ -1313,73 +1379,86 @@ error:
        endmntent (f);
        fprintf(stderr, "Error while checking if device %s is mounted\n", device);
        exit(-1);
+#else
+       (void) device;  /* shut up warnings about unused variable... */
 #endif
 }
 
 
-uint32_t file_time(f)
-int f;
+time_t
+file_time(int f)
 {
   struct stat statbuf;
-  fstat(f, &statbuf);
+
+  if (!fstat(f, &statbuf))
+       return current_time;
+  if (statbuf.st_mtime<0 || statbuf.st_mtime>(uint32_t)(-1))
+       return current_time;
   return(statbuf.st_mtime);
 }
 
 
-__dead void pexit(char const * s)
+__dead void
+pexit(char const * s, ...)
 {
-  fprintf(stderr, "%s: %s\n", progname, s);
+  va_list va;
+
+  va_start(va, s);
+  vwarn(s, va);
+  va_end(va);
   if (lct != 0)
-       fprintf(stderr, "Line %d being processed when error detected.\n", lct);
+       warnx("Line %d being processed when error detected.\n", lct);
   exit(2);
 }
 
 
-void copy(from, to, count)
-char *from, *to;
-size_t count;
+void *
+alloc_block(void)
 {
-  while (count--) *to++ = *from++;
-}
-
-void *alloc_block()
-{
-       char *buf;
+       void *buf;
 
        if(!(buf = malloc(block_size))) {
-               pexit("couldn't allocate filesystem buffer");
+               err(1, "couldn't allocate filesystem buffer");
        }
-       bzero(buf, block_size);
+       memset(buf, 0, block_size);
 
        return buf;
 }
 
-void print_fs()
+void
+print_fs(void)
 {
   int i, j;
   ino_t k;
-  d2_inode *inode2;
+  struct inode *inode2;
   unsigned short *usbuf;
   block_t b;
   struct direct *dir;
 
-  if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
-       pexit("couldn't allocate a block of inodes");
-
-  if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
-       pexit("malloc of directory entry failed");
+  assert(inodes_per_block * sizeof(*inode2) == block_size);
+  if(!(inode2 = alloc_block()))
+       err(1, "couldn't allocate a block of inodes");
 
-  usbuf = (unsigned short *) alloc_block();
+  assert(NR_DIR_ENTRIES(block_size)*sizeof(*dir) == block_size);
+  if(!(dir = alloc_block()))
+       err(1, "couldn't allocate a block of directory entries");
 
-  get_super_block((char *) usbuf);
+  usbuf = alloc_block();
+  get_super_block(usbuf);
   printf("\nSuperblock: ");
-  for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
-  get_block((block_t) 2, (char *) usbuf);
+  for (i = 0; i < 8; i++) printf("%06ho ", usbuf[i]);
+  printf("\n            ");
+  for (i = 0; i < 8; i++) printf("%#04hX ", usbuf[i]);
+  printf("\n            ");
+  for (i = 8; i < 15; i++) printf("%06ho ", usbuf[i]);
+  printf("\n            ");
+  for (i = 8; i < 15; i++) printf("%#04hX ", usbuf[i]);
+  get_block((block_t) INODE_MAP, usbuf);
   printf("...\nInode map:  ");
-  for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
-  get_block((block_t) 3, (char *) usbuf);
+  for (i = 0; i < 9; i++) printf("%06ho ", usbuf[i]);
+  get_block((block_t) zone_map, usbuf);
   printf("...\nZone  map:  ");
-  for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
+  for (i = 0; i < 9; i++) printf("%06ho ", usbuf[i]);
   printf("...\n");
 
   free(usbuf);
@@ -1387,51 +1466,57 @@ void print_fs()
 
   k = 0;
   for (b = inode_offset; k < nrinodes; b++) {
-       get_block(b, (char *) inode2);
+       get_block(b, inode2);
        for (i = 0; i < inodes_per_block; i++) {
                k = inodes_per_block * (int) (b - inode_offset) + i + 1;
                /* Lint but OK */
                if (k > nrinodes) break;
                {
-                       if (inode2[i].d2_mode != 0) {
-                               printf("Inode %2u:  mode=", k);
-                               printf("%06o", inode2[i].d2_mode);
+                       if (inode2[i].i_mode != 0) {
+                               printf("Inode %3u:  mode=", (unsigned)k);
+                               printf("%06o", (unsigned)inode2[i].i_mode);
                                printf("  uid=%2d  gid=%2d  size=",
-                               inode2[i].d2_uid, inode2[i].d2_gid);
-                               printf("%6d", inode2[i].d2_size);
-                               printf("  zone[0]=%u\n", inode2[i].d2_zone[0]);
+                                       (int)inode2[i].i_uid, (int)inode2[i].i_gid);
+                               printf("%6ld", (long)inode2[i].i_size);
+                               printf("  zone[0]=%u\n", (unsigned)inode2[i].i_zone[0]);
                        }
-                       if ((inode2[i].d2_mode & S_IFMT) == S_IFDIR) {
+                       if ((inode2[i].i_mode & S_IFMT) == S_IFDIR) {
                                /* This is a directory */
-                               get_block(inode2[i].d2_zone[0], (char *) dir);
+                               get_block(inode2[i].i_zone[0] << zone_shift, dir);
                                for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
-                                       if (dir[j].mfs_d_ino)
-                                               printf("\tInode %2u: %s\n", dir[j].mfs_d_ino, dir[j].mfs_d_name);
+                                       if (dir[j].d_ino)
+                                               printf("\tInode %2u: %s\n",
+                                                       (unsigned)dir[j].d_ino,
+                                                       dir[j].d_name);
                        }
                }
        }
   }
 
-  printf("%d inodes used.     %d zones used.\n", next_inode - 1, next_zone);
+  if (zone_shift)
+       printf("%d inodes used.     %u zones (%u blocks) used.\n",
+               (int)next_inode-1, next_zone, next_zone*zone_per_block);
+  else
+       printf("%d inodes used.     %u zones used.\n", (int)next_inode-1, next_zone);
   free(dir);
   free(inode2);
 }
 
 
-int read_and_set(n)
-block_t n;
-{
-/* The first time a block is read, it returns all 0s, unless there has
+/*
+ * The first time a block is read, it returns all 0s, unless there has
  * been a write.  This routine checks to see if a block has been accessed.
  */
-
+int
+read_and_set(block_t n)
+{
   int w, s, mask, r;
 
   w = n / 8;
   
   assert(n < nrblocks);
   if(w >= umap_array_elements) {
-       pexit("umap array too small - this can't happen");
+       errx(1, "umap array too small - this can't happen");
   }
   s = n % 8;
   mask = 1 << s;
@@ -1440,77 +1525,66 @@ block_t n;
   return(r);
 }
 
-__dead void usage()
+__dead void
+usage(void)
 {
-  fprintf(stderr,
-         "Usage: %s [-12dlot] [-b blocks] [-i inodes]\n"
-               "\t[-x extra] [-B blocksize] special [proto]\n",
-         progname);
-  exit(1);
+  fprintf(stderr, "Usage: %s [-dltv] [-b blocks] [-i inodes] [-z zone_shift]\n"
+      "\t[-x extra] [-B blocksize] special [proto]\n",
+      progname);
+  exit(4);
 }
 
-void special(string)
-char *string;
+void
+special(char * string)
 {
   fd = creat(string, 0777);
   close(fd);
   fd = open(string, O_RDWR);
-  if (fd < 0) pexit("Can't open special file");
+  if (fd < 0) err(1, "Can't open special file %s", string);
 }
 
 
 
-void get_block(n, buf)
-block_t n;
-char *buf;
-{
 /* Read a block. */
-
-  int k;
+void
+get_block(block_t n, void *buf)
+{
+  ssize_t k;
 
   /* First access returns a zero block */
   if (read_and_set(n) == 0) {
-       copy(zero, buf, block_size);
+       memcpy(buf, zero, block_size);
        return;
   }
-  lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL);
+  if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t)(-1))
+       pexit("get_block couldn't seek");
   k = read(fd, buf, block_size);
-  if (k != block_size) {
-       pexit("get_block couldn't read");
-  }
+  if (k != block_size)
+       pexit("get_block couldn't read block #%u", (unsigned)n);
 }
 
-void get_super_block(buf)
-char *buf;
+/* Read the super block. */
+void
+get_super_block(void *buf)
 {
-/* Read a block. */
-
-  int k;
+  ssize_t k;
 
-  if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
-       perror("lseek");
-       pexit("seek failed");
-  }
-  k = read(fd, buf, _STATIC_BLOCK_SIZE);
-  if (k != _STATIC_BLOCK_SIZE) {
-       pexit("get_super_block couldn't read");
-  }
+  if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) == (off_t) -1)
+       err(1, "seek for superblock failed");
+  k = read(fd, buf, SUPER_BLOCK_BYTES);
+  if (k != SUPER_BLOCK_BYTES)
+       err(1, "get_super_block couldn't read super block");
 }
 
-void put_block(n, buf)
-block_t n;
-char *buf;
-{
 /* Write a block. */
+void
+put_block(block_t n, void *buf)
+{
 
   (void) read_and_set(n);
 
-  /* XXX - check other lseeks too. */
-  if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1) {
+  if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1)
        pexit("put_block couldn't seek");
-  }
-  if (write(fd, buf, block_size) != block_size) {
-       pexit("put_block couldn't write");
-  }
+  if (write(fd, buf, block_size)!= block_size)
+       pexit("put_block couldn't write block #%u", (unsigned)n);
 }
-
index d90757aa1e0a32676bd276c719e2efc5667fce72..bdb0752632988a68b707156282a0246dc9ce1d6e 100644 (file)
@@ -1,8 +1,7 @@
-#ifndef __MFS_SUPER_H__
-#define __MFS_SUPER_H__
+#ifndef _MKFS_MFS_SUPER_H__
+#define _MKFS_MFS_SUPER_H__
 
-/* Super block table.  The root file system and every mounted file system
- * has an entry here.  The entry holds information about the sizes of the bit
+/* Super block table.  The entry holds information about the sizes of the bit
  * maps and inodes.  The s_ninodes field gives the number of inodes available
  * for files and directories, including the root directory.  Inode 0 is 
  * on the disk, but not used.  Thus s_ninodes = 4 means that 5 bits will be
  *    inodes        (s_ninodes + 'inodes per block' - 1)/'inodes per block'
  *    unused        whatever is needed to fill out the current zone
  *    data zones    (s_zones - s_firstdatazone) << s_log_zone_size
- *
- * A super_block slot is free if s_dev == NO_DEV. 
  */
 
-EXTERN struct super_block {
+struct super_block {
   uint32_t s_ninodes;          /* # usable inodes on the minor device */
   uint16_t  s_nzones;          /* total device size, including bit maps etc */
   int16_t s_imap_blocks;       /* # of blocks used by inode bit map */
@@ -35,38 +32,22 @@ EXTERN struct super_block {
 
   /* The following items are valid on disk only for V3 and above */
 
-  /* The block size in bytes. Minimum MIN_BLOCK SIZE. SECTOR_SIZE
-   * multiple. If V1 or V2 filesystem, this should be
-   * initialised to STATIC_BLOCK_SIZE.
-   */
   int16_t s_pad2;              /* try to avoid compiler-dependent padding */
+  /* The block size in bytes. Minimum MIN_BLOCK SIZE. SECTOR_SIZE multiple.*/
   uint16_t s_block_size;       /* block size in bytes. */
   int8_t s_disk_version;       /* filesystem format sub-version */
 
   /* The following items are only used when the super_block is in memory.
    * If this ever changes, i.e. more fields after s_disk_version has to go to
-   * disk, update LAST_ONDISK_FIELD in super.c as that controls which part of the
-   * struct is copied to and from disk.
+   * disk, update LAST_ONDISK_FIELD in servers/mfs/super.c as that controls
+   * which part of the struct is copied to and from disk.
    */
-  
-  /*struct inode *s_isup;*/    /* inode for root dir of mounted file sys */
-  /*struct inode *s_imount;*/   /* inode mounted on */
+/* XXX padding inserted here... */
+
   unsigned s_inodes_per_block; /* precalculated from magic number */
   uint32_t s_firstdatazone;    /* number of first data zone (big) */
-  dev_t s_dev;                 /* whose super block is this? */
-  int32_t s_rd_only;           /* set to 1 iff file sys mounted read only */
-  int32_t s_native;            /* set to 1 iff not byte swapped file system */
-  int32_t s_version;           /* file system version, zero means bad magic */
-  int32_t s_ndzones;           /* # direct zones in an inode */
-  int32_t s_nindirs;           /* # indirect zones per indirect block */
-  uint32_t s_isearch;          /* inodes below this bit number are in use */
-  uint32_t s_zsearch;          /* all zones below this bit number are in use*/
-  int8_t s_is_root;
 } superblock;
 
-#define IMAP           0       /* operating on the inode bit map */
-#define ZMAP           1       /* operating on the zone bit map */
-
 /* s_flags contents; undefined flags are guaranteed to be zero on disk
  * (not counting future versions of mfs setting them!)
  */
@@ -79,5 +60,15 @@ EXTERN struct super_block {
  */
 #define MFSFLAG_MANDATORY_MASK 0xff00
 
-#endif
+/* The block size should be registered on disk, even
+ * multiple. If V1 or V2 filesystem, this should be
+ * initialised to STATIC_BLOCK_SIZE.
+ */
+#define        MFS_SUPER_BLOCK_SIZE    s_block_size
+
+/* To keep the super block on disk clean, the MFS server only read/write up to
+ * and including this field:
+ */
+#define LAST_ONDISK_FIELD      s_disk_version
 
+#endif
index 22e12b10296237608df45eeb92936460eb943136..a13e9f729d09ac5452a02a4b489b46a8213f2bbe 100644 (file)
@@ -1,34 +1,18 @@
-#ifndef __MFS_TYPE_H__
-#define __MFS_TYPE_H__
-
+#ifndef _MKFS_MFS_TYPE_H__
+#define _MKFS_MFS_TYPE_H__
 
 /* Declaration of the V2 inode as it is on the disk (not in core). */
-typedef struct {               /* V2.x disk inode */
-  uint16_t d2_mode;            /* file type, protection, etc. */
-  uint16_t d2_nlinks;          /* how many links to this file. HACK! */
-  int16_t d2_uid;              /* user id of the file's owner. */
-  uint16_t d2_gid;             /* group number HACK! */
-  int32_t d2_size;             /* current file size in bytes */
-  int32_t d2_atime;            /* when was file data last accessed */
-  int32_t d2_mtime;            /* when was file data last changed */
-  int32_t d2_ctime;            /* when was inode data last changed */
-  uint32_t d2_zone[V2_NR_TZONES];/* block nums for direct, ind, and dbl ind */
-} d2_inode;
-
-struct buf {
-  /* Data portion of the buffer. */
-  union fsdata_u *bp;
-
-  /* Header portion of the buffer. */
-  struct buf *b_next;          /* used to link all free bufs in a chain */
-  struct buf *b_prev;          /* used to link all free bufs the other way */
-  struct buf *b_hash;          /* used to link bufs on hash chains */
-  uint32_t b_blocknr;          /* block number of its (minor) device */
-  dev_t b_dev;                 /* major | minor device where block resides */
-  char b_dirt;                 /* BP_CLEAN or BP_DIRTY */
-  char b_count;                        /* number of users of this buffer */
-  unsigned int b_bytes;                /* Number of bytes allocated in bp */
+/* The same structure is used for V3. */
+struct inode { /* V2/V3 disk inode */
+  uint16_t i_mode;             /* file type, protection, etc. */
+  uint16_t i_nlinks;           /* how many links to this file. */
+  int16_t i_uid;               /* user id of the file's owner. */
+  uint16_t i_gid;              /* group number */
+  uint32_t i_size;             /* current file size in bytes */
+  uint32_t i_atime;            /* when was file data last accessed */
+  uint32_t i_mtime;            /* when was file data last changed */
+  uint32_t i_ctime;            /* when was inode data last changed */
+  uint32_t i_zone[NR_TZONES];  /* zone nums for direct, ind, and dbl ind */
 };
 
 #endif
-