1 /* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */
3 /* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
5 * This program can make version 1, 2 and 3 file systems, as follows:
6 * mkfs /dev/fd0 1200 # Version 3 (default)
7 * mkfs -1 /dev/fd0 360 # Version 1
9 * Note that the version 1 and 2 file systems produced by this program are not
10 * compatible with the original version 1 and 2 file system layout.
13 #include <sys/types.h>
28 #include <minix/partition.h>
29 #include <minix/u64.h>
30 #include <sys/ioctl.h>
35 #define EXTERN /* get rid of EXTERN by making it null */
39 #define max(a,b) ((a) > (b) ? (a) : (b))
53 #define BIT_MAP_SHIFT 13
54 #define INODE_MAX ((unsigned) 65535)
55 #define SECTOR_SIZE 512
59 maybedefine O_RDONLY
4 /* O_RDONLY | BINARY_BIT */
60 maybedefine BWRITE
5 /* O_WRONLY | BINARY_BIT */
64 #define mul64u(a,b) ((a) * (b))
65 #define lseek64(a,b,c,d) lseek(a,b,c)
72 typedef uint32_t block_t
;
73 typedef uint32_t zone_t
;
79 int next_zone
, next_inode
, zone_size
, zone_shift
= 0, zoff
;
81 int inode_offset
, lct
= 0, disk
, fd
, print
= 0, file
= 0;
82 unsigned int nrinodes
;
83 int override
= 0, simple
= 0, dflag
;
84 int donttest
; /* skip test if it fits on medium */
87 uint32_t current_time
, bin_time
;
89 char *umap_array
; /* bit map tells if block read yet */
90 int umap_array_elements
= 0;
91 block_t zone_map
; /* where is zone map? (depends on # inodes) */
95 int extra_space_percent
;
99 #if defined(__NBSD_LIBC) || !defined(__minix)
100 #define getline _mkfs_getline
103 int main(int argc
, char **argv
);
104 block_t
sizeup(char *device
);
105 void super(zone_t zones
, ino_t inodes
);
106 void rootdir(ino_t inode
);
107 void eat_dir(ino_t parent
);
108 void eat_file(ino_t inode
, int f
);
109 void enter_dir(ino_t parent
, char *name
, ino_t child
);
110 void incr_size(ino_t n
, size_t count
);
111 static ino_t
alloc_inode(int mode
, int usrid
, int grpid
);
112 static zone_t
alloc_zone(void);
113 void add_zone(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
);
114 void add_z_1(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
);
115 void add_z_2(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
);
116 void incr_link(ino_t n
);
117 void insert_bit(block_t block
, int bit
);
118 int mode_con(char *p
);
119 void getline(char line
[LINE_LEN
], char *parse
[MAX_TOKENS
]);
120 void check_mtab(char *devname
);
121 uint32_t file_time(int f
);
123 void copy(char *from
, char *to
, size_t count
);
125 int read_and_set(block_t n
);
126 void special(char *string
);
127 void get_block(block_t n
, char *buf
);
128 void get_super_block(char *buf
);
129 void put_block(block_t n
, char *buf
);
130 void cache_init(void);
132 void mx_read(int blocknr
, char *buf
);
133 void mx_write(int blocknr
, char *buf
);
134 void dexit(char *s
, int sectnum
, int err
);
136 char *alloc_block(void);
142 void detect_fs_size(void);
143 void sizeup_dir(void);
144 void detect_size(void);
146 static int bitmapsize(uint32_t nr_bits
, size_t block_size
);
148 /*================================================================
149 * mkfs - make filesystem
150 *===============================================================*/
155 int nread
, mode
, usrid
, grpid
, ch
;
156 block_t blocks
, maxblocks
;
161 char *token
[MAX_TOKENS
], line
[LINE_LEN
];
164 /* Get two times, the current time and the mod time of the binary of
165 * mkfs itself. When the -d flag is used, the later time is put into
166 * the i_mtimes of all the files. This feature is useful when
167 * producing a set of file systems, and one wants all the times to be
168 * identical. First you set the time of the mkfs binary to what you
171 current_time
= time((time_t *) 0); /* time mkfs is being run */
172 stat(argv
[0], &statbuf
);
173 bin_time
= statbuf
.st_mtime
; /* time when mkfs binary was last modified */
175 /* Process switches. */
180 inodes_per_block
= 0;
182 extra_space_percent
= 0;
183 while ((ch
= getopt(argc
, argv
, "12b:di:lotB:x:")) != EOF
)
187 inodes_per_block
= V1_INODES_PER_BLOCK
;
193 blocks
= strtoul(optarg
, (char **) NULL
, 0);
197 current_time
= bin_time
;
200 i
= strtoul(optarg
, (char **) NULL
, 0);
202 case 'l': print
= 1; break;
203 case 'o': override
= 1; break;
204 case 't': donttest
= 1; break;
205 case 'B': block_size
= atoi(optarg
); break;
206 case 'x': extra_space_percent
= atoi(optarg
); break;
210 if (argc
== optind
) usage();
212 /* Percentage of extra size must be nonnegative.
213 * It can legitimately be bigger than 100 but has to make some sort of sense.
215 if(extra_space_percent
< 0 || extra_space_percent
> 2000) usage();
217 if(fs_version
== 3) {
218 if(!block_size
) block_size
= _MAX_BLOCK_SIZE
; /* V3 default block size */
219 if(block_size
%SECTOR_SIZE
|| block_size
< _MIN_BLOCK_SIZE
) {
220 fprintf(stderr
, "block size must be multiple of sector (%d) "
221 "and at least %d bytes\n",
222 SECTOR_SIZE
, _MIN_BLOCK_SIZE
);
223 pexit("specified block size illegal");
225 if(block_size
%V2_INODE_SIZE
) {
226 fprintf(stderr
, "block size must be a multiple of inode size (%d bytes)\n",
228 pexit("specified block size illegal");
232 pexit("Can't specify a block size if FS version is <3");
234 block_size
= _STATIC_BLOCK_SIZE
; /* V1/V2 block size */
237 zone_shift
= 0; /* for future use */
238 zone_size
= 1 << zone_shift
; /* nr of blocks per zone */
240 if(!inodes_per_block
)
241 inodes_per_block
= V2_INODES_PER_BLOCK(block_size
);
243 /* now that the block size is known, do buffer allocations where
246 zero
= alloc_block();
247 bzero(zero
, block_size
);
249 /* Determine the size of the device if not specified as -b or proto. */
250 maxblocks
= sizeup(argv
[optind
]);
251 if (argc
- optind
== 1 && blocks
== 0) {
253 /* blocks == 0 is checked later, but leads to a funny way of
254 * reporting a 0-sized device (displays usage).
257 fprintf(stderr
, "%s: zero size device.\n", progname
);
262 /* The remaining args must be 'special proto', or just 'special' if the
263 * no. of blocks has already been specified.
265 if (argc
- optind
!= 2 && (argc
- optind
!= 1 || blocks
== 0)) usage();
267 if (blocks
> maxblocks
) {
268 fprintf(stderr
, "%s: %s: number of blocks too large for device.\n",
269 progname
, argv
[optind
]);
274 check_mtab(argv
[optind
]);
276 /* Check and start processing proto. */
277 optarg
= argv
[++optind
];
278 if (optind
< argc
&& (proto
= fopen(optarg
, "r")) != NULL
) {
279 /* Prototype file is readable. */
281 getline(line
, token
); /* skip boot block info */
283 /* Read the line with the block and inode counts. */
284 getline(line
, token
);
285 blocks
= atol(token
[0]);
286 inodes
= atoi(token
[1]);
288 /* Process mode line for root directory. */
289 getline(line
, token
);
290 mode
= mode_con(token
[0]);
291 usrid
= atoi(token
[1]);
292 grpid
= atoi(token
[2]);
294 if(blocks
<= 0 && inodes
<= 0){
295 block_t extrablocks
= 0;
296 ino_t extrainodes
= 0;
297 if(blocks
< 0) extrablocks
= -blocks
;
298 if(inodes
< 0) extrainodes
= -inodes
;
300 blocks
= blockcount
+ extrablocks
;
301 inodes
= inocount
+ extrainodes
;
302 blocks
+= blocks
*extra_space_percent
/100;
303 inodes
+= inodes
*extra_space_percent
/100;
304 printf("dynamically sized filesystem: %d blocks, %d inodes\n", blocks
,
305 (unsigned int) inodes
);
310 /* Maybe the prototype file is just a size. Check. */
311 blocks
= strtoul(optarg
, (char **) NULL
, 0);
312 if (blocks
== 0) pexit("Can't open prototype file");
316 uint32_t kb
= div64u(mul64u(blocks
, block_size
), 1024);
318 uint32_t kb
= ((unsigned long long) blocks
* block_size
) / 1024;
321 if (kb
>= 100000) i
= kb
/ 4;
323 /* round up to fill inode block */
324 i
+= inodes_per_block
- 1;
325 i
= i
/ inodes_per_block
* inodes_per_block
;
326 if (i
> INODE_MAX
&& fs_version
< 3) i
= INODE_MAX
;
329 if (blocks
< 5) pexit("Block count too small");
330 if (i
< 1) pexit("Inode count too small");
331 if (i
> INODE_MAX
&& fs_version
< 3) pexit("Inode count too large");
334 /* Make simple file system of the given size, using defaults. */
346 bytes
= 1 + blocks
/8;
347 if(!(umap_array
= malloc(bytes
))) {
348 fprintf(stderr
, "mkfs: can't allocate block bitmap (%u bytes).\n",
352 umap_array_elements
= bytes
;
356 special(argv
[--optind
]);
363 testb
= (short *) alloc_block();
365 /* Try writing the last block of partition or diskette. */
366 if(lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
) < 0) {
367 pexit("couldn't seek to last block to test size (1)");
371 testb
[block_size
/2-1] = 0x1F2F;
372 if ((w
=write(fd
, (char *) testb
, block_size
)) != block_size
) {
373 if(w
< 0) perror("write");
374 printf("%d/%u\n", w
, block_size
);
375 pexit("File system is too big for minor device (write)");
377 sync(); /* flush write, so if error next read fails */
378 if(lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
) < 0) {
379 pexit("couldn't seek to last block to test size (2)");
383 nread
= read(fd
, (char *) testb
, block_size
);
384 if (nread
!= block_size
|| testb
[0] != 0x3245 || testb
[1] != 0x11FF ||
385 testb
[block_size
/2-1] != 0x1F2F) {
386 if(nread
< 0) perror("read");
387 printf("nread = %d\n", nread
);
388 printf("testb = 0x%x 0x%x 0x%x\n", testb
[0], testb
[1], testb
[block_size
-1]);
389 pexit("File system is too big for minor device (read)");
391 lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
);
394 if (write(fd
, (char *) testb
, block_size
) != block_size
)
395 pexit("File system is too big for minor device (write2)");
396 lseek(fd
, 0L, SEEK_SET
);
401 /* Make the file-system */
405 put_block((block_t
) 0, zero
); /* Write a null boot block. */
407 zones
= nrblocks
>> zone_shift
;
409 super(zones
, inodes
);
411 root_inum
= alloc_inode(mode
, usrid
, grpid
);
413 if (simple
== 0) eat_dir(root_inum
);
415 if (print
) print_fs();
422 /*================================================================
423 * detect_fs_size - determine image size dynamically
424 *===============================================================*/
425 void detect_fs_size()
427 uint32_t point
= ftell(proto
);
429 inocount
= 1; /* root directory node */
436 initb
= bitmapsize((uint32_t) (1 + inocount
), block_size
);
437 initb
+= bitmapsize((uint32_t) zonecount
, block_size
);
438 initb
+= START_BLOCK
;
439 initb
+= (inocount
+ inodes_per_block
- 1) / inodes_per_block
;
440 initb
= (initb
+ (1 << zone_shift
) - 1) >> zone_shift
;
442 blockcount
= initb
+zonecount
*zone_size
;
443 fseek(proto
, point
, SEEK_SET
);
448 char *token
[MAX_TOKENS
], *p
;
453 zone_t dir_zones
= 0;
456 if (fs_version
== 1) {
457 nr_dzones
= V1_NR_DZONES
;
459 nr_dzones
= V2_NR_DZONES
;
463 getline(line
, token
);
466 dir_zones
= (dir_entries
/ (NR_DIR_ENTRIES(block_size
) * zone_size
));
467 if(dir_entries
% (NR_DIR_ENTRIES(block_size
) * zone_size
))
469 /* Assumes directory fits in direct blocks */
470 zonecount
+= dir_zones
;
480 } else if (*p
== 'b' || *p
== 'c') {
483 if ((f
= fopen(token
[4], "r")) == NULL
) {
484 fprintf(stderr
, "%s: Can't open %s: %s\n",
485 progname
, token
[4], strerror(errno
));
486 pexit("dynamic size detection failed");
488 if (fseek(f
, 0, SEEK_END
) < 0) {
489 fprintf(stderr
, "%s: Can't seek to end of %s\n",
491 pexit("dynamic size detection failed");
495 zone_t fzones
= (size
/ (zone_size
* block_size
));
496 if (size
% (zone_size
* block_size
))
498 if (fzones
> nr_dzones
)
499 fzones
++; /* Assumes files fit within single indirect */
506 /*================================================================
507 * sizeup - determine device size
508 *===============================================================*/
509 block_t
sizeup(device
)
521 if ((fd
= open(device
, O_RDONLY
)) == -1) {
523 perror("sizeup open");
528 if(minix_sizeup(device
, &bytes
) < 0) {
533 d
= div64u(bytes
, block_size
);
534 rem
= rem64u(bytes
, block_size
);
536 resize
= add64u(mul64u(d
, block_size
), rem
);
537 if(cmp64(resize
, bytes
) != 0) {
539 fprintf(stderr
, "mkfs: truncating FS at %u blocks\n", d
);
542 size
= lseek(fd
, 0, SEEK_END
);
543 if (size
== (off_t
) -1) {
544 fprintf(stderr
, "Cannot get device size fd=%d\n", fd
);
547 d
= size
/ block_size
;
556 static int bitmapsize(nr_bits
, block_size
)
562 nr_blocks
= (int) (nr_bits
/ FS_BITS_PER_BLOCK(block_size
));
563 if (((uint32_t) nr_blocks
* FS_BITS_PER_BLOCK(block_size
)) < nr_bits
) ++nr_blocks
;
567 /*================================================================
568 * super - construct a superblock
569 *===============================================================*/
571 void super(zones
, inodes
)
581 struct super_block
*sup
;
586 for (cp
= buf
; cp
< &buf
[block_size
]; cp
++) *cp
= 0;
587 sup
= (struct super_block
*) buf
; /* lint - might use a union */
589 /* The assumption is that mkfs will create a clean FS. */
590 sup
->s_flags
= MFSFLAG_CLEAN
;
592 sup
->s_ninodes
= inodes
;
593 if (fs_version
== 1) {
594 sup
->s_nzones
= zones
;
595 if (sup
->s_nzones
!= zones
) pexit("too many zones");
597 sup
->s_nzones
= 0; /* not used in V2 - 0 forces errors early */
598 sup
->s_zones
= zones
;
601 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
602 sup
->s_imap_blocks
= nb
= bitmapsize((uint32_t) (1 + inodes
), block_size
);
603 if(sup
->s_imap_blocks
!= nb
) {
604 fprintf(stderr
, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS
);
607 sup
->s_zmap_blocks
= nb
= bitmapsize((uint32_t) zones
, block_size
);
608 if(nb
!= sup
->s_zmap_blocks
) {
609 fprintf(stderr
, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS
);
612 inode_offset
= START_BLOCK
+ sup
->s_imap_blocks
+ sup
->s_zmap_blocks
;
613 inodeblks
= (inodes
+ inodes_per_block
- 1) / inodes_per_block
;
614 initblks
= inode_offset
+ inodeblks
;
615 sup
->s_firstdatazone_old
= nb
=
616 (initblks
+ (1 << zone_shift
) - 1) >> zone_shift
;
617 if(nb
>= zones
) pexit("bit maps too large");
618 if(nb
!= sup
->s_firstdatazone_old
) {
619 /* The field is too small to store the value. Fortunately, the value
620 * can be computed from other fields. We set the on-disk field to zero
621 * to indicate that it must not be used. Eventually, we can always set
622 * the on-disk field to zero, and stop using it.
624 sup
->s_firstdatazone_old
= 0;
626 sup
->s_firstdatazone
= nb
;
627 zoff
= sup
->s_firstdatazone
- 1;
628 sup
->s_log_zone_size
= zone_shift
;
629 if (fs_version
== 1) {
630 sup
->s_magic
= SUPER_MAGIC
; /* identify super blocks */
631 v1sq
= (zone_t
) V1_INDIRECTS
* V1_INDIRECTS
;
632 zo
= V1_NR_DZONES
+ (int) V1_INDIRECTS
+ v1sq
;
633 sup
->s_max_size
= zo
* block_size
;
635 v2sq
= (zone_t
) V2_INDIRECTS(block_size
) * V2_INDIRECTS(block_size
);
636 zo
= V2_NR_DZONES
+ (zone_t
) V2_INDIRECTS(block_size
) + v2sq
;
637 if(fs_version
== 2) {
638 sup
->s_magic
= SUPER_V2
;/* identify super blocks */
639 sup
->s_max_size
= zo
* block_size
;
641 sup
->s_magic
= SUPER_V3
;
642 sup
->s_block_size
= block_size
;
643 sup
->s_disk_version
= 0;
644 #define MAX_MAX_SIZE (INT_MAX)
645 if(MAX_MAX_SIZE
/block_size
< zo
) {
646 sup
->s_max_size
= (int32_t) MAX_MAX_SIZE
;
649 sup
->s_max_size
= zo
* block_size
;
654 if (lseek(fd
, (off_t
) _STATIC_BLOCK_SIZE
, SEEK_SET
) == (off_t
) -1) {
655 pexit("super() couldn't seek");
657 if (write(fd
, buf
, _STATIC_BLOCK_SIZE
) != _STATIC_BLOCK_SIZE
) {
658 pexit("super() couldn't write");
661 /* Clear maps and inodes. */
662 for (i
= START_BLOCK
; i
< initblks
; i
++) put_block((block_t
) i
, zero
);
664 next_zone
= sup
->s_firstdatazone
;
667 zone_map
= INODE_MAP
+ sup
->s_imap_blocks
;
669 insert_bit(zone_map
, 0); /* bit zero must always be allocated */
670 insert_bit((block_t
) INODE_MAP
, 0); /* inode zero not used but
671 * must be allocated */
677 /*================================================================
678 * rootdir - install the root directory
679 *===============================================================*/
686 add_zone(inode
, z
, 2 * sizeof(struct direct
), current_time
);
687 enter_dir(inode
, ".", inode
);
688 enter_dir(inode
, "..", inode
);
694 /*================================================================
695 * eat_dir - recursively install directory
696 *===============================================================*/
700 /* Read prototype lines and set up directory. Recurse if need be. */
701 char *token
[MAX_TOKENS
], *p
;
703 int mode
, usrid
, grpid
, maj
, min
, f
;
709 getline(line
, token
);
711 if (*p
== '$') return;
714 usrid
= atoi(token
[2]);
715 grpid
= atoi(token
[3]);
716 n
= alloc_inode(mode
, usrid
, grpid
);
718 /* Enter name in directory and update directory's size. */
719 enter_dir(parent
, token
[0], n
);
720 incr_size(parent
, sizeof(struct direct
));
722 /* Check to see if file is directory or special. */
725 /* This is a directory. */
726 z
= alloc_zone(); /* zone for new directory */
727 add_zone(n
, z
, 2 * sizeof(struct direct
), current_time
);
728 enter_dir(n
, ".", n
);
729 enter_dir(n
, "..", parent
);
733 } else if (*p
== 'b' || *p
== 'c') {
735 maj
= atoi(token
[4]);
736 min
= atoi(token
[5]);
738 if (token
[6]) size
= atoi(token
[6]);
739 size
= block_size
* size
;
740 add_zone(n
, (zone_t
) (makedev(maj
,min
)), size
, current_time
);
742 /* Regular file. Go read it. */
743 if ((f
= open(token
[4], O_RDONLY
)) < 0) {
744 fprintf(stderr
, "%s: Can't open %s: %s\n",
745 progname
, token
[4], strerror(errno
));
754 /*================================================================
755 * eat_file - copy file to MINIX
756 *===============================================================*/
757 /* Zonesize >= blocksize */
758 void eat_file(inode
, f
)
770 for (i
= 0, j
= 0; i
< zone_size
; i
++, j
+= ct
) {
771 for (k
= 0; k
< block_size
; k
++) buf
[k
] = 0;
772 if ((ct
= read(f
, buf
, block_size
)) > 0) {
773 if (i
== 0) z
= alloc_zone();
774 put_block((z
<< zone_shift
) + i
, buf
);
777 timeval
= (dflag
? current_time
: file_time(f
));
778 if (ct
) add_zone(inode
, z
, (size_t) j
, timeval
);
779 } while (ct
== block_size
);
786 /*================================================================
787 * directory & inode management assist group
788 *===============================================================*/
789 void enter_dir(parent
, name
, child
)
793 /* Enter child in parent directory */
794 /* Works for dir > 1 block and zone > block */
795 unsigned int i
, j
, k
, l
, off
;
799 struct direct
*dir_entry
;
800 d1_inode ino1
[V1_INODES_PER_BLOCK
];
804 b
= ((parent
- 1) / inodes_per_block
) + inode_offset
;
805 off
= (parent
- 1) % inodes_per_block
;
807 if(!(dir_entry
= malloc(NR_DIR_ENTRIES(block_size
) * sizeof(*dir_entry
))))
808 pexit("couldn't allocate directory entry");
810 if(!(ino2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*ino2
))))
811 pexit("couldn't allocate block of inodes entry");
813 if (fs_version
== 1) {
814 get_block(b
, (char *) ino1
);
815 nr_dzones
= V1_NR_DZONES
;
817 get_block(b
, (char *) ino2
);
818 nr_dzones
= V2_NR_DZONES
;
820 for (k
= 0; k
< nr_dzones
; k
++) {
821 if (fs_version
== 1) {
822 z
= ino1
[off
].d1_zone
[k
];
825 ino1
[off
].d1_zone
[k
] = z
;
828 z
= ino2
[off
].d2_zone
[k
];
831 ino2
[off
].d2_zone
[k
] = z
;
834 for (l
= 0; l
< zone_size
; l
++) {
835 get_block((z
<< zone_shift
) + l
, (char *) dir_entry
);
836 for (i
= 0; i
< NR_DIR_ENTRIES(block_size
); i
++) {
837 if (dir_entry
[i
].mfs_d_ino
== 0) {
838 dir_entry
[i
].mfs_d_ino
= child
;
840 p2
= dir_entry
[i
].mfs_d_name
;
841 j
= sizeof(dir_entry
[i
].mfs_d_name
);
847 put_block((z
<< zone_shift
) + l
, (char *) dir_entry
);
848 if (fs_version
== 1) {
849 put_block(b
, (char *) ino1
);
851 put_block(b
, (char *) ino2
);
861 printf("Directory-inode %lu beyond direct blocks. Could not enter %s\n",
867 void add_zone(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
)
869 if (fs_version
== 1) {
870 add_z_1(n
, z
, bytes
, cur_time
);
872 add_z_2(n
, z
, bytes
, cur_time
);
876 void add_z_1(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
)
878 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
883 uint16_t blk
[V1_INDIRECTS
];
885 d1_inode inode
[V1_INODES_PER_BLOCK
];
887 b
= ((n
- 1) / V1_INODES_PER_BLOCK
) + inode_offset
;
888 off
= (n
- 1) % V1_INODES_PER_BLOCK
;
889 get_block(b
, (char *) inode
);
892 p
->d1_mtime
= cur_time
;
893 for (i
= 0; i
< V1_NR_DZONES
; i
++)
894 if (p
->d1_zone
[i
] == 0) {
895 p
->d1_zone
[i
] = (uint16_t) z
;
896 put_block(b
, (char *) inode
);
899 put_block(b
, (char *) inode
);
901 /* File has grown beyond a small file. */
902 if (p
->d1_zone
[V1_NR_DZONES
] == 0)
903 p
->d1_zone
[V1_NR_DZONES
] = (uint16_t) alloc_zone();
904 indir
= p
->d1_zone
[V1_NR_DZONES
];
905 put_block(b
, (char *) inode
);
906 b
= indir
<< zone_shift
;
907 get_block(b
, (char *) blk
);
908 for (i
= 0; i
< V1_INDIRECTS
; i
++)
910 blk
[i
] = (uint16_t) z
;
911 put_block(b
, (char *) blk
);
914 pexit("File has grown beyond single indirect");
917 void add_z_2(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
)
919 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
928 if(!(blk
= malloc(V2_INDIRECTS(block_size
)*sizeof(*blk
))))
929 pexit("Couldn't allocate indirect block");
931 if(!(inode
= malloc(V2_INODES_PER_BLOCK(block_size
)*sizeof(*inode
))))
932 pexit("Couldn't allocate block of inodes");
934 b
= ((n
- 1) / V2_INODES_PER_BLOCK(block_size
)) + inode_offset
;
935 off
= (n
- 1) % V2_INODES_PER_BLOCK(block_size
);
936 get_block(b
, (char *) inode
);
939 p
->d2_mtime
= cur_time
;
940 for (i
= 0; i
< V2_NR_DZONES
; i
++)
941 if (p
->d2_zone
[i
] == 0) {
943 put_block(b
, (char *) inode
);
948 put_block(b
, (char *) inode
);
950 /* File has grown beyond a small file. */
951 if (p
->d2_zone
[V2_NR_DZONES
] == 0) p
->d2_zone
[V2_NR_DZONES
] = alloc_zone();
952 indir
= p
->d2_zone
[V2_NR_DZONES
];
953 put_block(b
, (char *) inode
);
954 b
= indir
<< zone_shift
;
955 get_block(b
, (char *) blk
);
956 for (i
= 0; i
< V2_INDIRECTS(block_size
); i
++)
959 put_block(b
, (char *) blk
);
964 pexit("File has grown beyond single indirect");
971 /* Increment the link count to inode n */
973 static int enter
= 0;
978 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
979 off
= (n
- 1) % inodes_per_block
;
980 if (fs_version
== 1) {
981 d1_inode inode1
[V1_INODES_PER_BLOCK
];
983 get_block(b
, (char *) inode1
);
984 inode1
[off
].d1_nlinks
++;
985 put_block(b
, (char *) inode1
);
987 static d2_inode
*inode2
= NULL
;
990 n
= sizeof(*inode2
) * V2_INODES_PER_BLOCK(block_size
);
991 if(!inode2
&& !(inode2
= malloc(n
)))
992 pexit("couldn't allocate a block of inodes");
994 get_block(b
, (char *) inode2
);
995 inode2
[off
].d2_nlinks
++;
996 put_block(b
, (char *) inode2
);
1002 void incr_size(n
, count
)
1006 /* Increment the file-size in inode n */
1010 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
1011 off
= (n
- 1) % inodes_per_block
;
1012 if (fs_version
== 1) {
1013 d1_inode inode1
[V1_INODES_PER_BLOCK
];
1015 get_block(b
, (char *) inode1
);
1016 inode1
[off
].d1_size
+= count
;
1017 put_block(b
, (char *) inode1
);
1020 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
1021 pexit("couldn't allocate a block of inodes");
1023 get_block(b
, (char *) inode2
);
1024 inode2
[off
].d2_size
+= count
;
1025 put_block(b
, (char *) inode2
);
1031 /*================================================================
1032 * allocation assist group
1033 *===============================================================*/
1034 static ino_t
alloc_inode(mode
, usrid
, grpid
)
1035 int mode
, usrid
, grpid
;
1042 if (num
> nrinodes
) {
1043 fprintf(stderr
, "have %d inodoes\n", nrinodes
);
1044 pexit("File system does not have enough inodes");
1046 b
= ((num
- 1) / inodes_per_block
) + inode_offset
;
1047 off
= (num
- 1) % inodes_per_block
;
1048 if (fs_version
== 1) {
1049 d1_inode inode1
[V1_INODES_PER_BLOCK
];
1051 get_block(b
, (char *) inode1
);
1052 inode1
[off
].d1_mode
= mode
;
1053 inode1
[off
].d1_uid
= usrid
;
1054 inode1
[off
].d1_gid
= grpid
;
1055 put_block(b
, (char *) inode1
);
1059 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
1060 pexit("couldn't allocate a block of inodes");
1062 get_block(b
, (char *) inode2
);
1063 inode2
[off
].d2_mode
= mode
;
1064 inode2
[off
].d2_uid
= usrid
;
1065 inode2
[off
].d2_gid
= grpid
;
1066 put_block(b
, (char *) inode2
);
1071 /* Set the bit in the bit map. */
1072 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
1073 insert_bit((block_t
) INODE_MAP
, (int) num
);
1078 static zone_t
alloc_zone()
1080 /* Allocate a new zone */
1081 /* Works for zone > block */
1087 b
= z
<< zone_shift
;
1088 if ((b
+ zone_size
) > nrblocks
)
1089 pexit("File system not big enough for all the files");
1090 for (i
= 0; i
< zone_size
; i
++)
1091 put_block(b
+ i
, zero
); /* give an empty zone */
1092 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
1093 insert_bit(zone_map
, (int) (z
- zoff
)); /* lint, NOT OK because
1094 * z hasn't been broken
1101 void insert_bit(block
, bit
)
1105 /* Insert 'count' bits in the bitmap */
1107 #if defined(__minix)
1113 #if defined(__minix)
1114 buf
= (bitchunk_t
*) alloc_block();
1116 buf
= (uint32_t *) alloc_block();
1119 get_block(block
, (char *) buf
);
1120 #if defined(__minix)
1121 w
= bit
/ (8 * sizeof(bitchunk_t
));
1122 s
= bit
% (8 * sizeof(bitchunk_t
));
1124 w
= bit
/ (8 * sizeof(uint32_t));
1125 s
= bit
% (8 * sizeof(uint32_t));
1128 put_block(block
, (char *) buf
);
1134 /*================================================================
1135 * proto-file processing assist group
1136 *===============================================================*/
1140 /* Convert string to mode */
1141 int o1
, o2
, o3
, mode
;
1150 mode
= (o1
<< 6) | (o2
<< 3) | o3
;
1151 if (c1
== 'd') mode
|= S_IFDIR
;
1152 if (c1
== 'b') mode
|= S_IFBLK
;
1153 if (c1
== 'c') mode
|= S_IFCHR
;
1154 if (c1
== '-') mode
|= S_IFREG
;
1155 if (c2
== 'u') mode
|= S_ISUID
;
1156 if (c3
== 'g') mode
|= S_ISGID
;
1160 void getline(line
, parse
)
1161 char *parse
[MAX_TOKENS
];
1162 char line
[LINE_LEN
];
1164 /* Read a line and break it up in tokens */
1169 for (k
= 0; k
< MAX_TOKENS
; k
++) parse
[k
] = 0;
1170 for (k
= 0; k
< LINE_LEN
; k
++) line
[k
] = 0;
1175 if (++k
> LINE_LEN
) pexit("Line too long");
1177 if (d
== EOF
) pexit("Unexpected end-of-file");
1179 if (*p
== '\n') lct
++;
1180 if (*p
== ' ' || *p
== '\t') *p
= 0;
1194 if (c
== '\n') return;
1195 if (c
== 0) continue;
1199 } while (c
!= 0 && c
!= '\n');
1204 /*================================================================
1206 *===============================================================*/
1207 void check_mtab(device
)
1208 char *device
; /* /dev/hd1 or whatever */
1210 /* Check to see if the special file named in s is mounted. */
1211 #if defined(__minix)
1214 char special
[PATH_MAX
+ 1], mounted_on
[PATH_MAX
+ 1], version
[10], rw_flag
[10];
1216 r
= stat(device
, &sb
);
1219 if (errno
== ENOENT
)
1220 return; /* Does not exist, and therefore not mounted. */
1221 fprintf(stderr
, "%s: stat %s failed: %s\n",
1222 progname
, device
, strerror(errno
));
1225 if (!S_ISBLK(sb
.st_mode
))
1227 /* Not a block device and therefore not mounted. */
1231 if (load_mtab("mkfs") < 0) return;
1233 n
= get_mtab_entry(special
, mounted_on
, version
, rw_flag
);
1235 if (strcmp(device
, special
) == 0) {
1236 /* Can't mkfs on top of a mounted file system. */
1237 fprintf(stderr
, "%s: %s is mounted on %s\n",
1238 progname
, device
, mounted_on
);
1242 #elif defined(__linux__)
1243 /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite.
1247 dev_t file_dev
=0, file_rdev
=0;
1251 char *mtab_file
= "/proc/mounts";
1253 if ((f
= setmntent (mtab_file
, "r")) == NULL
)
1256 if (stat(device
, &st_buf
) == 0) {
1257 if (S_ISBLK(st_buf
.st_mode
)) {
1258 file_rdev
= st_buf
.st_rdev
;
1260 file_dev
= st_buf
.st_dev
;
1261 file_ino
= st_buf
.st_ino
;
1265 while ((mnt
= getmntent (f
)) != NULL
) {
1266 if (strcmp(device
, mnt
->mnt_fsname
) == 0)
1268 if (stat(mnt
->mnt_fsname
, &st_buf
) == 0) {
1269 if (S_ISBLK(st_buf
.st_mode
)) {
1270 if (file_rdev
&& (file_rdev
== st_buf
.st_rdev
))
1273 if (file_dev
&& ((file_dev
== st_buf
.st_dev
) &&
1274 (file_ino
== st_buf
.st_ino
)))
1282 * Do an extra check to see if this is the root device. We
1283 * can't trust /etc/mtab, and /proc/mounts will only list
1284 * /dev/root for the root filesystem. Argh. Instead we
1285 * check if the given device has the same major/minor number
1286 * as the device that the root directory is on.
1288 if (file_rdev
&& stat("/", &st_buf
) == 0) {
1289 if (st_buf
.st_dev
== file_rdev
) {
1295 /* Validate the entry in case /etc/mtab is out of date */
1297 * We need to be paranoid, because some broken distributions
1298 * (read: Slackware) don't initialize /etc/mtab before checking
1299 * all of the non-root filesystems on the disk.
1301 if (stat(mnt
->mnt_dir
, &st_buf
) < 0) {
1302 if (errno
== ENOENT
) {
1307 if (file_rdev
&& (st_buf
.st_dev
!= file_rdev
)) {
1311 fprintf(stderr
, "Device %s is mounted, exiting\n", device
);
1315 * Check to see if we're referring to the root filesystem.
1316 * If so, do a manual check to see if we can open /etc/mtab
1317 * read/write, since if the root is mounted read/only, the
1318 * contents of /etc/mtab may not be accurate.
1320 if (!strcmp(mnt
->mnt_dir
, "/")) {
1322 fprintf(stderr
, "Device %s is mounted as root file system!\n",
1330 if ((stat(device
, &st_buf
) != 0) ||
1331 !S_ISBLK(st_buf
.st_mode
))
1333 fd
= open(device
, O_RDONLY
| O_EXCL
);
1335 if (errno
== EBUSY
) {
1336 fprintf(stderr
, "Device %s is used by the system\n", device
);
1346 fprintf(stderr
, "Error while checking if device %s is mounted\n", device
);
1352 uint32_t file_time(f
)
1356 struct stat statbuf
;
1358 return(statbuf
.st_mtime
);
1359 #else /* fstat not supported by DOS */
1368 fprintf(stderr
, "%s: %s\n", progname
, s
);
1370 fprintf(stderr
, "Line %d being processed when error detected.\n", lct
);
1376 void copy(from
, to
, count
)
1380 while (count
--) *to
++ = *from
++;
1387 if(!(buf
= malloc(block_size
))) {
1388 pexit("couldn't allocate filesystem buffer");
1390 bzero(buf
, block_size
);
1399 d1_inode inode1
[V1_INODES_PER_BLOCK
];
1401 unsigned short *usbuf
;
1405 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
1406 pexit("couldn't allocate a block of inodes");
1408 if(!(dir
= malloc(NR_DIR_ENTRIES(block_size
)*sizeof(*dir
))))
1409 pexit("malloc of directory entry failed");
1411 usbuf
= (unsigned short *) alloc_block();
1413 get_super_block((char *) usbuf
);
1414 printf("\nSuperblock: ");
1415 for (i
= 0; i
< 8; i
++) printf("%06o ", usbuf
[i
]);
1416 get_block((block_t
) 2, (char *) usbuf
);
1417 printf("...\nInode map: ");
1418 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
1419 get_block((block_t
) 3, (char *) usbuf
);
1420 printf("...\nZone map: ");
1421 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
1428 for (b
= inode_offset
; k
< nrinodes
; b
++) {
1429 if (fs_version
== 1) {
1430 get_block(b
, (char *) inode1
);
1432 get_block(b
, (char *) inode2
);
1434 for (i
= 0; i
< inodes_per_block
; i
++) {
1435 k
= inodes_per_block
* (int) (b
- inode_offset
) + i
+ 1;
1437 if (k
> nrinodes
) break;
1438 if (fs_version
== 1) {
1439 if (inode1
[i
].d1_mode
!= 0) {
1440 printf("Inode %2lu: mode=", k
);
1441 printf("%06o", inode1
[i
].d1_mode
);
1442 printf(" uid=%2d gid=%2d size=",
1443 inode1
[i
].d1_uid
, inode1
[i
].d1_gid
);
1444 printf("%6d", inode1
[i
].d1_size
);
1445 printf(" zone[0]=%d\n", inode1
[i
].d1_zone
[0]);
1447 if ((inode1
[i
].d1_mode
& S_IFMT
) == S_IFDIR
) {
1448 /* This is a directory */
1449 get_block(inode1
[i
].d1_zone
[0], (char *) dir
);
1450 for (j
= 0; j
< NR_DIR_ENTRIES(block_size
); j
++)
1451 if (dir
[j
].mfs_d_ino
)
1452 printf("\tInode %2u: %s\n", dir
[j
].mfs_d_ino
, dir
[j
].mfs_d_name
);
1455 if (inode2
[i
].d2_mode
!= 0) {
1456 printf("Inode %2lu: mode=", k
);
1457 printf("%06o", inode2
[i
].d2_mode
);
1458 printf(" uid=%2d gid=%2d size=",
1459 inode2
[i
].d2_uid
, inode2
[i
].d2_gid
);
1460 printf("%6d", inode2
[i
].d2_size
);
1461 printf(" zone[0]=%u\n", inode2
[i
].d2_zone
[0]);
1463 if ((inode2
[i
].d2_mode
& S_IFMT
) == S_IFDIR
) {
1464 /* This is a directory */
1465 get_block(inode2
[i
].d2_zone
[0], (char *) dir
);
1466 for (j
= 0; j
< NR_DIR_ENTRIES(block_size
); j
++)
1467 if (dir
[j
].mfs_d_ino
)
1468 printf("\tInode %2u: %s\n", dir
[j
].mfs_d_ino
, dir
[j
].mfs_d_name
);
1474 printf("%d inodes used. %d zones used.\n", next_inode
- 1, next_zone
);
1483 /* The first time a block is read, it returns all 0s, unless there has
1484 * been a write. This routine checks to see if a block has been accessed.
1490 if(w
>= umap_array_elements
) {
1491 pexit("umap array too small - this can't happen");
1495 r
= (umap_array
[w
] & mask
? 1 : 0);
1496 umap_array
[w
] |= mask
;
1503 "Usage: %s [-12dlot] [-b blocks] [-i inodes]\n"
1504 "\t[-x extra] [-B blocksize] special [proto]\n",
1509 /*================================================================
1510 * get_block & put_block for MS-DOS
1511 *===============================================================*/
1515 * These are the get_block and put_block routines
1516 * when compiling & running mkfs.c under MS-DOS.
1518 * It requires the (asembler) routines absread & abswrite
1519 * from the file diskio.asm. Since these routines just do
1520 * as they are told (read & write the sector specified),
1521 * a local cache is used to minimize the i/o-overhead for
1522 * frequently used blocks.
1524 * The global variable "file" determines whether the output
1525 * is to a disk-device or to a binary file.
1529 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1532 char *derrtab
[14] = {
1534 "disk is read-only",
1539 "internal error: bad request structure length",
1541 "unknown media type",
1543 "printer out of paper (?)",
1549 #define CACHE_SIZE 20 /* 20 block-buffers */
1553 char blockbuf
[BLOCK_SIZE
];
1557 } cache
[CACHE_SIZE
];
1560 void special(string
)
1564 if (string
[1] == ':' && string
[2] == 0) {
1565 /* Format: d: or d:fname */
1566 disk
= (string
[0] & ~32) - 'A';
1567 if (disk
> 1 && !override
) /* safety precaution */
1568 pexit("Bad drive specifier for special");
1571 if ((fd
= creat(string
, BWRITE
)) == 0)
1572 pexit("Can't open special file");
1576 void get_block(n
, buf
)
1580 /* Get a block to the user */
1581 struct cache
*bp
, *fp
;
1583 /* First access returns a zero block */
1584 if (read_and_set(n
) == 0) {
1585 copy(zero
, buf
, block_size
);
1589 /* Look for block in cache */
1591 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) {
1592 if (bp
->blocknum
== n
) {
1593 copy(bp
, buf
, block_size
);
1598 /* Remember clean block */
1601 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1606 /* Block not in cache, get it */
1608 /* No clean buf, flush one */
1609 for (bp
= cache
, fp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1610 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1611 mx_write(fp
->blocknum
, fp
);
1617 copy(fp
, buf
, block_size
);
1620 void put_block(n
, buf
)
1624 /* Accept block from user */
1625 struct cache
*fp
, *bp
;
1627 (void) read_and_set(n
);
1629 /* Look for block in cache */
1631 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) {
1632 if (bp
->blocknum
== n
) {
1633 copy(buf
, bp
, block_size
);
1638 /* Remember clean block */
1641 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1646 /* Block not in cache */
1648 /* No clean buf, flush one */
1649 for (bp
= cache
, fp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1650 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1651 mx_write(fp
->blocknum
, fp
);
1656 copy(buf
, fp
, block_size
);
1662 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) bp
->blocknum
= -1;
1667 /* Flush all dirty blocks to disk */
1670 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1672 mx_write(bp
->blocknum
, bp
);
1677 /*==================================================================
1678 * hard read & write etc.
1679 *=================================================================*/
1680 #define MAX_RETRIES 5
1683 void mx_read(blocknr
, buf
)
1688 /* Read the requested MINIX-block in core */
1689 char (*bp
)[PH_SECTSIZE
];
1690 int sectnum
, retries
, err
;
1693 lseek(fd
, (off_t
) blocknr
* block_size
, 0);
1694 if (read(fd
, buf
, block_size
) != block_size
)
1695 pexit("mx_read: error reading file");
1697 sectnum
= blocknr
* (block_size
/ PH_SECTSIZE
);
1698 for (bp
= buf
; bp
< &buf
[block_size
]; bp
++) {
1699 retries
= MAX_RETRIES
;
1701 err
= absread(disk
, sectnum
, bp
);
1702 while (err
&& --retries
);
1707 dexit("mx_read", sectnum
, err
);
1713 void mx_write(blocknr
, buf
)
1717 /* Write the MINIX-block to disk */
1718 char (*bp
)[PH_SECTSIZE
];
1719 int retries
, sectnum
, err
;
1722 lseek(fd
, blocknr
* block_size
, 0);
1723 if (write(fd
, buf
, block_size
) != block_size
) {
1724 pexit("mx_write: error writing file");
1727 sectnum
= blocknr
* (block_size
/ PH_SECTSIZE
);
1728 for (bp
= buf
; bp
< &buf
[block_size
]; bp
++) {
1729 retries
= MAX_RETRIES
;
1731 err
= abswrite(disk
, sectnum
, bp
);
1732 } while (err
&& --retries
);
1737 dexit("mx_write", sectnum
, err
);
1744 void dexit(s
, sectnum
, err
)
1748 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1749 s
, sectnum
, err
, derrtab
[err
]);
1755 /*================================================================
1756 * get_block & put_block for UNIX
1757 *===============================================================*/
1760 void special(string
)
1763 fd
= creat(string
, 0777);
1765 fd
= open(string
, O_RDWR
);
1766 if (fd
< 0) pexit("Can't open special file");
1771 void get_block(n
, buf
)
1779 /* First access returns a zero block */
1780 if (read_and_set(n
) == 0) {
1781 copy(zero
, buf
, block_size
);
1784 lseek64(fd
, mul64u(n
, block_size
), SEEK_SET
, NULL
);
1785 k
= read(fd
, buf
, block_size
);
1786 if (k
!= block_size
) {
1787 pexit("get_block couldn't read");
1791 void get_super_block(buf
)
1798 if(lseek(fd
, (off_t
) SUPER_BLOCK_BYTES
, SEEK_SET
) < 0) {
1800 pexit("seek failed");
1802 k
= read(fd
, buf
, _STATIC_BLOCK_SIZE
);
1803 if (k
!= _STATIC_BLOCK_SIZE
) {
1804 pexit("get_super_block couldn't read");
1808 void put_block(n
, buf
)
1812 /* Write a block. */
1814 (void) read_and_set(n
);
1816 /* XXX - check other lseeks too. */
1817 if (lseek64(fd
, mul64u(n
, block_size
), SEEK_SET
, NULL
) == (off_t
) -1) {
1818 pexit("put_block couldn't seek");
1820 if (write(fd
, buf
, block_size
) != block_size
) {
1821 pexit("put_block couldn't write");
1826 /* Dummy routines to keep source file clean from #ifdefs */