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 both version 1 and version 2 file systems, as follows:
6 * mkfs /dev/fd0 1200 # Version 2 (default)
7 * mkfs -1 /dev/fd0 360 # Version 1
11 #include <sys/types.h>
23 #include <minix/config.h>
24 #include <minix/const.h>
25 #include <minix/type.h>
26 #include <minix/minlib.h>
27 #include "../../servers/fs/const.h"
28 #if (MACHINE == IBM_PC)
29 #include <minix/partition.h>
30 #include <minix/u64.h>
31 #include <sys/ioctl.h>
35 #define EXTERN /* get rid of EXTERN by making it null */
36 #include "../../servers/fs/type.h"
37 #include "../../servers/fs/super.h"
38 #include <minix/fslib.h>
47 #define BLOCK_SIZE 1024
54 #define BIT_MAP_SHIFT 13
55 #define N_BLOCKS (1024L * 1024)
56 #define N_BLOCKS16 (128L * 1024)
57 #define INODE_MAX ((unsigned) 65535)
59 /* You can make a really large file system on a 16-bit system, but the array
60 * of bits that get_block()/putblock() needs gets a bit big, so we can only
61 * prefill MAX_INIT blocks. (16-bit fsck can't check a file system larger
62 * than N_BLOCKS16 anyway.)
64 #define MAX_INIT (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS)
68 maybedefine O_RDONLY
4 /* O_RDONLY | BINARY_BIT */
69 maybedefine BWRITE
5 /* O_WRONLY | BINARY_BIT */
75 int next_zone
, next_inode
, zone_size
, zone_shift
= 0, zoff
;
77 int inode_offset
, lct
= 0, disk
, fd
, print
= 0, file
= 0;
78 unsigned int nrinodes
;
79 int override
= 0, simple
= 0, dflag
;
80 int donttest
; /* skip test if it fits on medium */
83 long current_time
, bin_time
;
84 char zero
[BLOCK_SIZE
], *lastp
;
85 char umap
[MAX_INIT
/ 8]; /* bit map tells if block read yet */
86 block_t zone_map
; /* where is zone map? (depends on # inodes) */
93 _PROTOTYPE(int main
, (int argc
, char **argv
));
94 _PROTOTYPE(block_t sizeup
, (char *device
));
95 _PROTOTYPE(void super
, (zone_t zones
, Ino_t inodes
));
96 _PROTOTYPE(void rootdir
, (Ino_t inode
));
97 _PROTOTYPE(void eat_dir
, (Ino_t parent
));
98 _PROTOTYPE(void eat_file
, (Ino_t inode
, int f
));
99 _PROTOTYPE(void enter_dir
, (Ino_t parent
, char *name
, Ino_t child
));
100 _PROTOTYPE(void incr_size
, (Ino_t n
, long count
));
101 _PROTOTYPE(PRIVATE ino_t alloc_inode
, (int mode
, int usrid
, int grpid
));
102 _PROTOTYPE(PRIVATE zone_t alloc_zone
, (void));
103 _PROTOTYPE(void add_zone
, (Ino_t n
, zone_t z
, long bytes
, long cur_time
));
104 _PROTOTYPE(void add_z_1
, (Ino_t n
, zone_t z
, long bytes
, long cur_time
));
105 _PROTOTYPE(void add_z_2
, (Ino_t n
, zone_t z
, long bytes
, long cur_time
));
106 _PROTOTYPE(void incr_link
, (Ino_t n
));
107 _PROTOTYPE(void insert_bit
, (block_t block
, int bit
));
108 _PROTOTYPE(int mode_con
, (char *p
));
109 _PROTOTYPE(void getline
, (char line
[LINE_LEN
], char *parse
[MAX_TOKENS
]));
110 _PROTOTYPE(void check_mtab
, (char *devname
));
111 _PROTOTYPE(long file_time
, (int f
));
112 _PROTOTYPE(void pexit
, (char *s
));
113 _PROTOTYPE(void copy
, (char *from
, char *to
, int count
));
114 _PROTOTYPE(void print_fs
, (void));
115 _PROTOTYPE(int read_and_set
, (block_t n
));
116 _PROTOTYPE(void special
, (char *string
));
117 _PROTOTYPE(void get_block
, (block_t n
, char buf
[BLOCK_SIZE
]));
118 _PROTOTYPE(void put_block
, (block_t n
, char buf
[BLOCK_SIZE
]));
119 _PROTOTYPE(void cache_init
, (void));
120 _PROTOTYPE(void flush
, (void));
121 _PROTOTYPE(void mx_read
, (int blocknr
, char buf
[BLOCK_SIZE
]));
122 _PROTOTYPE(void mx_write
, (int blocknr
, char buf
[BLOCK_SIZE
]));
123 _PROTOTYPE(void dexit
, (char *s
, int sectnum
, int err
));
124 _PROTOTYPE(void usage
, (void));
126 /*================================================================
127 * mkfs - make filesystem
128 *===============================================================*/
133 int nread
, mode
, usrid
, grpid
, ch
;
139 char *token
[MAX_TOKENS
], line
[LINE_LEN
];
142 /* Get two times, the current time and the mod time of the binary of
143 * mkfs itself. When the -d flag is used, the later time is put into
144 * the i_mtimes of all the files. This feature is useful when
145 * producing a set of file systems, and one wants all the times to be
146 * identical. First you set the time of the mkfs binary to what you
149 current_time
= time((time_t *) 0); /* time mkfs is being run */
150 stat(argv
[0], &statbuf
);
151 bin_time
= statbuf
.st_mtime
; /* time when mkfs binary was last modified */
153 /* Process switches. */
158 inodes_per_block
= V2_INODES_PER_BLOCK(BLOCK_SIZE
);
159 max_nrblocks
= N_BLOCKS
;
160 while ((ch
= getopt(argc
, argv
, "1b:di:lot")) != EOF
)
164 inodes_per_block
= V1_INODES_PER_BLOCK
;
165 max_nrblocks
= 0xFFFF;
168 blocks
= strtoul(optarg
, (char **) NULL
, 0);
172 current_time
= bin_time
;
175 i
= strtoul(optarg
, (char **) NULL
, 0);
177 case 'l': print
= 1; break;
178 case 'o': override
= 1; break;
179 case 't': donttest
= 1; break;
183 /* Determine the size of the device if not specified as -b or proto. */
184 if (argc
- optind
== 1 && blocks
== 0) blocks
= sizeup(argv
[optind
]);
185 printf("%lu blocks\n", blocks
);
187 /* The remaining args must be 'special proto', or just 'special' if the
188 * block size has already been specified.
190 if (argc
- optind
!= 2 && (argc
- optind
!= 1 || blocks
== 0)) usage();
193 check_mtab(argv
[optind
]);
195 /* Check and start processing proto. */
196 optarg
= argv
[++optind
];
197 if (optind
< argc
&& (proto
= fopen(optarg
, "r")) != NULL
) {
198 /* Prototype file is readable. */
200 getline(line
, token
); /* skip boot block info */
202 /* Read the line with the block and inode counts. */
203 getline(line
, token
);
204 blocks
= atol(token
[0]);
205 if (blocks
> max_nrblocks
) {
206 printf("%d > %d\n", blocks
, max_nrblocks
);
207 pexit("Block count too large");
209 if (sizeof(char *) == 2 && blocks
> N_BLOCKS16
) {
211 "%s: warning: FS is larger than the %dM that fsck can check!\n",
212 progname
, (int) (N_BLOCKS16
/ (1024L * 1024)));
214 inodes
= atoi(token
[1]);
216 /* Process mode line for root directory. */
217 getline(line
, token
);
218 mode
= mode_con(token
[0]);
219 usrid
= atoi(token
[1]);
220 grpid
= atoi(token
[2]);
224 /* Maybe the prototype file is just a size. Check. */
225 blocks
= strtoul(optarg
, (char **) NULL
, 0);
226 if (blocks
== 0) pexit("Can't open prototype file");
229 /* The default for inodes is 3 blocks per inode, rounded up
230 * to fill an inode block. Above 20M, the average files are
231 * sure to be larger because it is hard to fill up 20M with
232 * tiny files, so reduce the default number of inodes. This
233 * default can always be overridden by using the -i option.
236 if (blocks
>= 20000) i
= blocks
/ 4;
237 if (blocks
>= 40000) i
= blocks
/ 5;
238 if (blocks
>= 60000) i
= blocks
/ 6;
239 if (blocks
>= 80000) i
= blocks
/ 7;
240 if (blocks
>= 100000) i
= blocks
/ 8;
241 i
+= inodes_per_block
- 1;
242 i
= i
/ inodes_per_block
* inodes_per_block
;
243 if (i
> INODE_MAX
) i
= INODE_MAX
;
245 if (blocks
< 5) pexit("Block count too small");
246 if (blocks
> max_nrblocks
) {
247 printf("%d > %d\n", blocks
, max_nrblocks
);
248 pexit("Block count too large");
250 if (i
< 1) pexit("Inode count too small");
251 if (i
> INODE_MAX
) pexit("Inode count too large");
254 /* Make simple file system of the given size, using defaults. */
264 special(argv
[--optind
]);
268 static short testb
[BLOCK_SIZE
/ sizeof(short)];
270 /* Try writing the last block of partition or diskette. */
271 lseek(fd
, (off_t
) (blocks
- 1) * BLOCK_SIZE
, SEEK_SET
);
274 if (write(fd
, (char *) testb
, BLOCK_SIZE
) != BLOCK_SIZE
)
275 pexit("File system is too big for minor device");
276 sync(); /* flush write, so if error next read fails */
277 lseek(fd
, (off_t
) (blocks
- 1) * BLOCK_SIZE
, SEEK_SET
);
280 nread
= read(fd
, (char *) testb
, BLOCK_SIZE
);
281 if (nread
!= BLOCK_SIZE
|| testb
[0] != 0x3245 || testb
[1] != 0x11FF)
282 pexit("File system is too big for minor device");
283 lseek(fd
, (off_t
) (blocks
- 1) * BLOCK_SIZE
, SEEK_SET
);
286 if (write(fd
, (char *) testb
, BLOCK_SIZE
) != BLOCK_SIZE
)
287 pexit("File system is too big for minor device");
288 lseek(fd
, 0L, SEEK_SET
);
292 /* Make the file-system */
296 put_block((block_t
) 0, zero
); /* Write a null boot block. */
298 zone_shift
= 0; /* for future use */
299 zones
= nrblocks
>> zone_shift
;
301 super(zones
, inodes
);
303 root_inum
= alloc_inode(mode
, usrid
, grpid
);
305 if (simple
== 0) eat_dir(root_inum
);
307 if (print
) print_fs();
315 /*================================================================
316 * sizeup - determine device size
317 *===============================================================*/
318 block_t
sizeup(device
)
322 struct partition entry
;
324 if ((fd
= open(device
, O_RDONLY
)) == -1) return 0;
325 if (ioctl(fd
, DIOCGETP
, &entry
) == -1) entry
.size
= cvu64(0);
327 return div64u(entry
.size
, BLOCK_SIZE
);
331 /*================================================================
332 * super - construct a superblock
333 *===============================================================*/
335 void super(zones
, inodes
)
343 zone_t initzones
, nrzones
, v1sq
, v2sq
;
345 struct super_block
*sup
;
346 char buf
[BLOCK_SIZE
], *cp
;
348 for (cp
= buf
; cp
< &buf
[BLOCK_SIZE
]; cp
++) *cp
= 0;
349 sup
= (struct super_block
*) buf
; /* lint - might use a union */
351 sup
->s_ninodes
= inodes
;
352 if (fs_version
== 1) {
353 sup
->s_nzones
= zones
;
355 sup
->s_nzones
= 0; /* not used in V2 - 0 forces errors early */
356 sup
->s_zones
= zones
;
358 sup
->s_imap_blocks
= bitmapsize((bit_t
) (1 + inodes
), BLOCK_SIZE
);
359 sup
->s_zmap_blocks
= bitmapsize((bit_t
) zones
, BLOCK_SIZE
);
360 inode_offset
= sup
->s_imap_blocks
+ sup
->s_zmap_blocks
+ 2;
361 inodeblks
= (inodes
+ inodes_per_block
- 1) / inodes_per_block
;
362 initblks
= inode_offset
+ inodeblks
;
363 initzones
= (initblks
+ (1 << zone_shift
) - 1) >> zone_shift
;
364 nrzones
= nrblocks
>> zone_shift
;
365 sup
->s_firstdatazone
= (initblks
+ (1 << zone_shift
) - 1) >> zone_shift
;
366 zoff
= sup
->s_firstdatazone
- 1;
367 sup
->s_log_zone_size
= zone_shift
;
368 if (fs_version
== 1) {
369 sup
->s_magic
= SUPER_MAGIC
; /* identify super blocks */
370 v1sq
= (zone_t
) V1_INDIRECTS
* V1_INDIRECTS
;
371 zo
= V1_NR_DZONES
+ (long) V1_INDIRECTS
+ v1sq
;
373 sup
->s_magic
= SUPER_V2
;/* identify super blocks */
374 v2sq
= (zone_t
) V2_INDIRECTS(BLOCK_SIZE
) * V2_INDIRECTS(BLOCK_SIZE
);
375 zo
= V2_NR_DZONES
+ (zone_t
) V2_INDIRECTS(BLOCK_SIZE
) + v2sq
;
377 sup
->s_max_size
= zo
* BLOCK_SIZE
;
378 zone_size
= 1 << zone_shift
; /* nr of blocks per zone */
380 put_block((block_t
) 1, buf
);
382 /* Clear maps and inodes. */
383 for (i
= 2; i
< initblks
; i
++) put_block((block_t
) i
, zero
);
385 next_zone
= sup
->s_firstdatazone
;
388 zone_map
= INODE_MAP
+ sup
->s_imap_blocks
;
390 insert_bit(zone_map
, 0); /* bit zero must always be allocated */
391 insert_bit((block_t
) INODE_MAP
, 0); /* inode zero not used but
392 * must be allocated */
396 /*================================================================
397 * rootdir - install the root directory
398 *===============================================================*/
405 add_zone(inode
, z
, 32L, current_time
);
406 enter_dir(inode
, ".", inode
);
407 enter_dir(inode
, "..", inode
);
413 /*================================================================
414 * eat_dir - recursively install directory
415 *===============================================================*/
419 /* Read prototype lines and set up directory. Recurse if need be. */
420 char *token
[MAX_TOKENS
], *p
;
422 int mode
, usrid
, grpid
, maj
, min
, f
;
428 getline(line
, token
);
430 if (*p
== '$') return;
433 usrid
= atoi(token
[2]);
434 grpid
= atoi(token
[3]);
435 if (grpid
& 0200) fprintf(stderr
, "A.S.Tanenbaum\n");
436 n
= alloc_inode(mode
, usrid
, grpid
);
438 /* Enter name in directory and update directory's size. */
439 enter_dir(parent
, token
[0], n
);
440 incr_size(parent
, 16L);
442 /* Check to see if file is directory or special. */
445 /* This is a directory. */
446 z
= alloc_zone(); /* zone for new directory */
447 add_zone(n
, z
, 32L, current_time
);
448 enter_dir(n
, ".", n
);
449 enter_dir(n
, "..", parent
);
453 } else if (*p
== 'b' || *p
== 'c') {
455 maj
= atoi(token
[4]);
456 min
= atoi(token
[5]);
458 if (token
[6]) size
= atoi(token
[6]);
459 size
= BLOCK_SIZE
* size
;
460 add_zone(n
, (zone_t
) ((maj
<< 8) | min
), size
, current_time
);
462 /* Regular file. Go read it. */
463 if ((f
= open(token
[4], O_RDONLY
)) < 0) {
464 fprintf(stderr
, "%s: Can't open %s: %s\n",
465 progname
, token
[4], strerror(errno
));
473 /*================================================================
474 * eat_file - copy file to MINIX
475 *===============================================================*/
476 /* Zonesize >= blocksize */
477 void eat_file(inode
, f
)
483 char buf
[BLOCK_SIZE
];
487 for (i
= 0, j
= 0; i
< zone_size
; i
++, j
+= ct
) {
488 for (k
= 0; k
< BLOCK_SIZE
; k
++) buf
[k
] = 0;
489 if ((ct
= read(f
, buf
, BLOCK_SIZE
)) > 0) {
490 if (i
== 0) z
= alloc_zone();
491 put_block((z
<< zone_shift
) + i
, buf
);
494 timeval
= (dflag
? current_time
: file_time(f
));
495 if (ct
) add_zone(inode
, z
, (long) j
, timeval
);
496 } while (ct
== BLOCK_SIZE
);
502 /*================================================================
503 * directory & inode management assist group
504 *===============================================================*/
505 void enter_dir(parent
, name
, child
)
509 /* Enter child in parent directory */
510 /* Works for dir > 1 block and zone > block */
515 struct direct dir_entry
[NR_DIR_ENTRIES(BLOCK_SIZE
)];
516 d1_inode ino1
[V1_INODES_PER_BLOCK
];
517 d2_inode ino2
[V2_INODES_PER_BLOCK(BLOCK_SIZE
)];
520 b
= ((parent
- 1) / inodes_per_block
) + inode_offset
;
521 off
= (parent
- 1) % inodes_per_block
;
523 if (fs_version
== 1) {
524 get_block(b
, (char *) ino1
);
525 nr_dzones
= V1_NR_DZONES
;
527 get_block(b
, (char *) ino2
);
528 nr_dzones
= V2_NR_DZONES
;
530 for (k
= 0; k
< nr_dzones
; k
++) {
531 if (fs_version
== 1) {
532 z
= ino1
[off
].d1_zone
[k
];
535 ino1
[off
].d1_zone
[k
] = z
;
538 z
= ino2
[off
].d2_zone
[k
];
541 ino2
[off
].d2_zone
[k
] = z
;
544 for (l
= 0; l
< zone_size
; l
++) {
545 get_block((z
<< zone_shift
) + l
, (char *) dir_entry
);
546 for (i
= 0; i
< NR_DIR_ENTRIES(BLOCK_SIZE
); i
++) {
547 if (dir_entry
[i
].d_ino
== 0) {
548 dir_entry
[i
].d_ino
= child
;
550 p2
= dir_entry
[i
].d_name
;
556 put_block((z
<< zone_shift
) + l
, (char *) dir_entry
);
557 if (fs_version
== 1) {
558 put_block(b
, (char *) ino1
);
560 put_block(b
, (char *) ino2
);
568 printf("Directory-inode %d beyond direct blocks. Could not enter %s\n",
574 void add_zone(n
, z
, bytes
, cur_time
)
577 long bytes
, cur_time
;
579 if (fs_version
== 1) {
580 add_z_1(n
, z
, bytes
, cur_time
);
582 add_z_2(n
, z
, bytes
, cur_time
);
586 void add_z_1(n
, z
, bytes
, cur_time
)
589 long bytes
, cur_time
;
591 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
596 zone1_t blk
[V1_INDIRECTS
];
598 d1_inode inode
[V1_INODES_PER_BLOCK
];
600 b
= ((n
- 1) / V1_INODES_PER_BLOCK
) + inode_offset
;
601 off
= (n
- 1) % V1_INODES_PER_BLOCK
;
602 get_block(b
, (char *) inode
);
605 p
->d1_mtime
= cur_time
;
606 for (i
= 0; i
< V1_NR_DZONES
; i
++)
607 if (p
->d1_zone
[i
] == 0) {
608 p
->d1_zone
[i
] = (zone1_t
) z
;
609 put_block(b
, (char *) inode
);
612 put_block(b
, (char *) inode
);
614 /* File has grown beyond a small file. */
615 if (p
->d1_zone
[V1_NR_DZONES
] == 0)
616 p
->d1_zone
[V1_NR_DZONES
] = (zone1_t
) alloc_zone();
617 indir
= p
->d1_zone
[V1_NR_DZONES
];
618 put_block(b
, (char *) inode
);
619 b
= indir
<< zone_shift
;
620 get_block(b
, (char *) blk
);
621 for (i
= 0; i
< V1_INDIRECTS
; i
++)
623 blk
[i
] = (zone1_t
) z
;
624 put_block(b
, (char *) blk
);
627 pexit("File has grown beyond single indirect");
630 void add_z_2(n
, z
, bytes
, cur_time
)
633 long bytes
, cur_time
;
635 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
640 zone_t blk
[V2_INDIRECTS(BLOCK_SIZE
)];
642 d2_inode inode
[V2_INODES_PER_BLOCK(BLOCK_SIZE
)];
644 b
= ((n
- 1) / V2_INODES_PER_BLOCK(BLOCK_SIZE
)) + inode_offset
;
645 off
= (n
- 1) % V2_INODES_PER_BLOCK(BLOCK_SIZE
);
646 get_block(b
, (char *) inode
);
649 p
->d2_mtime
= cur_time
;
650 for (i
= 0; i
< V2_NR_DZONES
; i
++)
651 if (p
->d2_zone
[i
] == 0) {
653 put_block(b
, (char *) inode
);
656 put_block(b
, (char *) inode
);
658 /* File has grown beyond a small file. */
659 if (p
->d2_zone
[V2_NR_DZONES
] == 0) p
->d2_zone
[V2_NR_DZONES
] = alloc_zone();
660 indir
= p
->d2_zone
[V2_NR_DZONES
];
661 put_block(b
, (char *) inode
);
662 b
= indir
<< zone_shift
;
663 get_block(b
, (char *) blk
);
664 for (i
= 0; i
< V2_INDIRECTS(BLOCK_SIZE
); i
++)
667 put_block(b
, (char *) blk
);
670 pexit("File has grown beyond single indirect");
677 /* Increment the link count to inode n */
681 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
682 off
= (n
- 1) % inodes_per_block
;
683 if (fs_version
== 1) {
684 d1_inode inode1
[V1_INODES_PER_BLOCK
];
686 get_block(b
, (char *) inode1
);
687 inode1
[off
].d1_nlinks
++;
688 put_block(b
, (char *) inode1
);
690 d2_inode inode2
[V2_INODES_PER_BLOCK(BLOCK_SIZE
)];
692 get_block(b
, (char *) inode2
);
693 inode2
[off
].d2_nlinks
++;
694 put_block(b
, (char *) inode2
);
699 void incr_size(n
, count
)
703 /* Increment the file-size in inode n */
707 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
708 off
= (n
- 1) % inodes_per_block
;
709 if (fs_version
== 1) {
710 d1_inode inode1
[V1_INODES_PER_BLOCK
];
712 get_block(b
, (char *) inode1
);
713 inode1
[off
].d1_size
+= count
;
714 put_block(b
, (char *) inode1
);
716 d2_inode inode2
[V2_INODES_PER_BLOCK(BLOCK_SIZE
)];
718 get_block(b
, (char *) inode2
);
719 inode2
[off
].d2_size
+= count
;
720 put_block(b
, (char *) inode2
);
725 /*================================================================
726 * allocation assist group
727 *===============================================================*/
728 PRIVATE ino_t
alloc_inode(mode
, usrid
, grpid
)
729 int mode
, usrid
, grpid
;
736 if (num
> nrinodes
) pexit("File system does not have enough inodes");
737 b
= ((num
- 1) / inodes_per_block
) + inode_offset
;
738 off
= (num
- 1) % inodes_per_block
;
739 if (fs_version
== 1) {
740 d1_inode inode1
[V1_INODES_PER_BLOCK
];
742 get_block(b
, (char *) inode1
);
743 inode1
[off
].d1_mode
= mode
;
744 inode1
[off
].d1_uid
= usrid
;
745 inode1
[off
].d1_gid
= grpid
;
746 put_block(b
, (char *) inode1
);
748 d2_inode inode2
[V2_INODES_PER_BLOCK(BLOCK_SIZE
)];
750 get_block(b
, (char *) inode2
);
751 inode2
[off
].d2_mode
= mode
;
752 inode2
[off
].d2_uid
= usrid
;
753 inode2
[off
].d2_gid
= grpid
;
754 put_block(b
, (char *) inode2
);
757 /* Set the bit in the bit map. */
758 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
759 insert_bit((block_t
) INODE_MAP
, (int) num
);
764 PRIVATE zone_t
alloc_zone()
766 /* Allocate a new zone */
767 /* Works for zone > block */
774 if ((b
+ zone_size
) > nrblocks
)
775 pexit("File system not big enough for all the files");
776 for (i
= 0; i
< zone_size
; i
++)
777 put_block(b
+ i
, zero
); /* give an empty zone */
778 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
779 insert_bit(zone_map
, (int) (z
- zoff
)); /* lint, NOT OK because
780 * z hasn't been broken
787 void insert_bit(block
, bit
)
791 /* Insert 'count' bits in the bitmap */
793 short buf
[BLOCK_SIZE
/ sizeof(short)];
795 if (block
< 0) pexit("insert_bit called with negative argument");
796 get_block(block
, (char *) buf
);
797 w
= bit
/ (8 * sizeof(short));
798 s
= bit
% (8 * sizeof(short));
800 put_block(block
, (char *) buf
);
804 /*================================================================
805 * proto-file processing assist group
806 *===============================================================*/
810 /* Convert string to mode */
811 int o1
, o2
, o3
, mode
;
820 mode
= (o1
<< 6) | (o2
<< 3) | o3
;
821 if (c1
== 'd') mode
+= I_DIRECTORY
;
822 if (c1
== 'b') mode
+= I_BLOCK_SPECIAL
;
823 if (c1
== 'c') mode
+= I_CHAR_SPECIAL
;
824 if (c1
== '-') mode
+= I_REGULAR
;
825 if (c2
== 'u') mode
+= I_SET_UID_BIT
;
826 if (c3
== 'g') mode
+= I_SET_GID_BIT
;
830 void getline(line
, parse
)
831 char *parse
[MAX_TOKENS
];
834 /* Read a line and break it up in tokens */
839 for (k
= 0; k
< MAX_TOKENS
; k
++) parse
[k
] = 0;
840 for (k
= 0; k
< LINE_LEN
; k
++) line
[k
] = 0;
845 if (++k
> LINE_LEN
) pexit("Line too long");
847 if (d
== EOF
) pexit("Unexpected end-of-file");
849 if (*p
== '\n') lct
++;
850 if (*p
== ' ' || *p
== '\t') *p
= 0;
864 if (c
== '\n') return;
865 if (c
== 0) continue;
869 } while (c
!= 0 && c
!= '\n');
874 /*================================================================
876 *===============================================================*/
877 void check_mtab(devname
)
878 char *devname
; /* /dev/hd1 or whatever */
880 /* Check to see if the special file named in s is mounted. */
883 char special
[PATH_MAX
+ 1], mounted_on
[PATH_MAX
+ 1], version
[10], rw_flag
[10];
885 if (load_mtab("mkfs") < 0) return;
887 n
= get_mtab_entry(special
, mounted_on
, version
, rw_flag
);
889 if (strcmp(devname
, special
) == 0) {
890 /* Can't mkfs on top of a mounted file system. */
891 fprintf(stderr
, "%s: %s is mounted on %s\n",
892 progname
, devname
, mounted_on
);
905 return(statbuf
.st_mtime
);
906 #else /* fstat not supported by DOS */
915 fprintf(stderr
, "%s: %s\n", progname
, s
);
917 fprintf(stderr
, "Line %d being processed when error detected.\n", lct
);
923 void copy(from
, to
, count
)
927 while (count
--) *to
++ = *from
++;
935 d1_inode inode1
[V1_INODES_PER_BLOCK
];
936 d2_inode inode2
[V2_INODES_PER_BLOCK(BLOCK_SIZE
)];
937 unsigned short usbuf
[BLOCK_SIZE
/ sizeof(unsigned short)];
938 block_t b
, inode_limit
;
939 struct direct dir
[NR_DIR_ENTRIES(BLOCK_SIZE
)];
941 get_block((block_t
) 1, (char *) usbuf
);
942 printf("\nSuperblock: ");
943 for (i
= 0; i
< 8; i
++) printf("%06o ", usbuf
[i
]);
944 get_block((block_t
) 2, (char *) usbuf
);
945 printf("...\nInode map: ");
946 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
947 get_block((block_t
) 3, (char *) usbuf
);
948 printf("...\nZone map: ");
949 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
953 for (b
= inode_offset
; k
< nrinodes
; b
++) {
954 if (fs_version
== 1) {
955 get_block(b
, (char *) inode1
);
957 get_block(b
, (char *) inode2
);
959 for (i
= 0; i
< inodes_per_block
; i
++) {
960 k
= inodes_per_block
* (int) (b
- inode_offset
) + i
+ 1;
962 if (k
> nrinodes
) break;
963 if (fs_version
== 1) {
964 if (inode1
[i
].d1_mode
!= 0) {
965 printf("Inode %2d: mode=", k
);
966 printf("%06o", inode1
[i
].d1_mode
);
967 printf(" uid=%2d gid=%2d size=",
968 inode1
[i
].d1_uid
, inode1
[i
].d1_gid
);
969 printf("%6ld", inode1
[i
].d1_size
);
970 printf(" zone[0]=%d\n", inode1
[i
].d1_zone
[0]);
972 if ((inode1
[i
].d1_mode
& I_TYPE
) == I_DIRECTORY
) {
973 /* This is a directory */
974 get_block(inode1
[i
].d1_zone
[0], (char *) dir
);
975 for (j
= 0; j
< NR_DIR_ENTRIES(BLOCK_SIZE
); j
++)
977 printf("\tInode %2d: %s\n", dir
[j
].d_ino
, dir
[j
].d_name
);
980 if (inode2
[i
].d2_mode
!= 0) {
981 printf("Inode %2d: mode=", k
);
982 printf("%06o", inode2
[i
].d2_mode
);
983 printf(" uid=%2d gid=%2d size=",
984 inode2
[i
].d2_uid
, inode2
[i
].d2_gid
);
985 printf("%6ld", inode2
[i
].d2_size
);
986 printf(" zone[0]=%ld\n", inode2
[i
].d2_zone
[0]);
988 if ((inode2
[i
].d2_mode
& I_TYPE
) == I_DIRECTORY
) {
989 /* This is a directory */
990 get_block(inode2
[i
].d2_zone
[0], (char *) dir
);
991 for (j
= 0; j
< NR_DIR_ENTRIES(BLOCK_SIZE
); j
++)
993 printf("\tInode %2d: %s\n", dir
[j
].d_ino
, dir
[j
].d_name
);
999 printf("%d inodes used. %d zones used.\n", next_inode
- 1, next_zone
);
1006 /* The first time a block is read, it returns all 0s, unless there has
1007 * been a write. This routine checks to see if a block has been accessed.
1012 if (sizeof(char *) == 2 && n
>= MAX_INIT
) pexit("can't initialize past 128M");
1016 r
= (umap
[w
] & mask
? 1 : 0);
1024 "Usage: %s [-1dlot] [-b blocks] [-i inodes] special [proto]\n",
1029 /*================================================================
1030 * get_block & put_block for MS-DOS
1031 *===============================================================*/
1035 * These are the get_block and put_block routines
1036 * when compiling & running mkfs.c under MS-DOS.
1038 * It requires the (asembler) routines absread & abswrite
1039 * from the file diskio.asm. Since these routines just do
1040 * as they are told (read & write the sector specified),
1041 * a local cache is used to minimize the i/o-overhead for
1042 * frequently used blocks.
1044 * The global variable "file" determines whether the output
1045 * is to a disk-device or to a binary file.
1049 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1052 char *derrtab
[14] = {
1054 "disk is read-only",
1059 "internal error: bad request structure length",
1061 "unknown media type",
1063 "printer out of paper (?)",
1069 #define CACHE_SIZE 20 /* 20 block-buffers */
1073 char blockbuf
[BLOCK_SIZE
];
1077 } cache
[CACHE_SIZE
];
1080 void special(string
)
1084 if (string
[1] == ':' && string
[2] == 0) {
1085 /* Format: d: or d:fname */
1086 disk
= (string
[0] & ~32) - 'A';
1087 if (disk
> 1 && !override
) /* safety precaution */
1088 pexit("Bad drive specifier for special");
1091 if ((fd
= creat(string
, BWRITE
)) == 0)
1092 pexit("Can't open special file");
1096 void get_block(n
, buf
)
1098 char buf
[BLOCK_SIZE
];
1100 /* Get a block to the user */
1101 struct cache
*bp
, *fp
;
1103 /* First access returns a zero block */
1104 if (read_and_set(n
) == 0) {
1105 copy(zero
, buf
, BLOCK_SIZE
);
1109 /* Look for block in cache */
1111 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) {
1112 if (bp
->blocknum
== n
) {
1113 copy(bp
, buf
, BLOCK_SIZE
);
1118 /* Remember clean block */
1121 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1126 /* Block not in cache, get it */
1128 /* No clean buf, flush one */
1129 for (bp
= cache
, fp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1130 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1131 mx_write(fp
->blocknum
, fp
);
1137 copy(fp
, buf
, BLOCK_SIZE
);
1140 void put_block(n
, buf
)
1142 char buf
[BLOCK_SIZE
];
1144 /* Accept block from user */
1145 struct cache
*fp
, *bp
;
1147 (void) read_and_set(n
);
1149 /* Look for block in cache */
1151 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) {
1152 if (bp
->blocknum
== n
) {
1153 copy(buf
, bp
, BLOCK_SIZE
);
1158 /* Remember clean block */
1161 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1166 /* Block not in cache */
1168 /* No clean buf, flush one */
1169 for (bp
= cache
, fp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1170 if (fp
->usecnt
> bp
->usecnt
) fp
= bp
;
1171 mx_write(fp
->blocknum
, fp
);
1176 copy(buf
, fp
, BLOCK_SIZE
);
1182 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++) bp
->blocknum
= -1;
1187 /* Flush all dirty blocks to disk */
1190 for (bp
= cache
; bp
< &cache
[CACHE_SIZE
]; bp
++)
1192 mx_write(bp
->blocknum
, bp
);
1197 /*==================================================================
1198 * hard read & write etc.
1199 *=================================================================*/
1200 #define MAX_RETRIES 5
1203 void mx_read(blocknr
, buf
)
1205 char buf
[BLOCK_SIZE
];
1208 /* Read the requested MINIX-block in core */
1209 char (*bp
)[PH_SECTSIZE
];
1210 int sectnum
, retries
, err
;
1213 lseek(fd
, (off_t
) blocknr
* BLOCK_SIZE
, 0);
1214 if (read(fd
, buf
, BLOCK_SIZE
) != BLOCK_SIZE
)
1215 pexit("mx_read: error reading file");
1217 sectnum
= blocknr
* (BLOCK_SIZE
/ PH_SECTSIZE
);
1218 for (bp
= buf
; bp
< &buf
[BLOCK_SIZE
]; bp
++) {
1219 retries
= MAX_RETRIES
;
1221 err
= absread(disk
, sectnum
, bp
);
1222 while (err
&& --retries
);
1227 dexit("mx_read", sectnum
, err
);
1233 void mx_write(blocknr
, buf
)
1235 char buf
[BLOCK_SIZE
];
1237 /* Write the MINIX-block to disk */
1238 char (*bp
)[PH_SECTSIZE
];
1239 int retries
, sectnum
, err
;
1242 lseek(fd
, blocknr
* BLOCK_SIZE
, 0);
1243 if (write(fd
, buf
, BLOCK_SIZE
) != BLOCK_SIZE
) {
1244 pexit("mx_write: error writing file");
1247 sectnum
= blocknr
* (BLOCK_SIZE
/ PH_SECTSIZE
);
1248 for (bp
= buf
; bp
< &buf
[BLOCK_SIZE
]; bp
++) {
1249 retries
= MAX_RETRIES
;
1251 err
= abswrite(disk
, sectnum
, bp
);
1252 } while (err
&& --retries
);
1257 dexit("mx_write", sectnum
, err
);
1264 void dexit(s
, sectnum
, err
)
1268 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1269 s
, sectnum
, err
, derrtab
[err
]);
1275 /*================================================================
1276 * get_block & put_block for UNIX
1277 *===============================================================*/
1280 void special(string
)
1283 fd
= creat(string
, 0777);
1285 fd
= open(string
, O_RDWR
);
1286 if (fd
< 0) pexit("Can't open special file");
1291 void get_block(n
, buf
)
1293 char buf
[BLOCK_SIZE
];
1299 /* First access returns a zero block */
1300 if (read_and_set(n
) == 0) {
1301 copy(zero
, buf
, BLOCK_SIZE
);
1304 lseek(fd
, (off_t
) n
* BLOCK_SIZE
, SEEK_SET
);
1305 k
= read(fd
, buf
, BLOCK_SIZE
);
1306 if (k
!= BLOCK_SIZE
) {
1307 pexit("get_block couldn't read");
1311 void put_block(n
, buf
)
1313 char buf
[BLOCK_SIZE
];
1315 /* Write a block. */
1317 (void) read_and_set(n
);
1319 /* XXX - check other lseeks too. */
1320 if (lseek(fd
, (off_t
) n
* BLOCK_SIZE
, SEEK_SET
) == (off_t
) -1) {
1321 pexit("put_block couldn't seek");
1323 if (write(fd
, buf
, BLOCK_SIZE
) != BLOCK_SIZE
) {
1324 pexit("put_block couldn't write");
1329 /* Dummy routines to keep source file clean from #ifdefs */