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 #if HAVE_NBTOOL_CONFIG_H
14 #include "nbtool_config.h"
17 #include <sys/cdefs.h>
18 #include <sys/types.h>
34 #include <minix/partition.h>
35 #include <minix/u64.h>
36 #include <minix/minlib.h>
37 #include <sys/ioctl.h>
42 #define EXTERN /* get rid of EXTERN by making it null */
46 #define max(a,b) ((a) > (b) ? (a) : (b))
54 #define BIT_MAP_SHIFT 13
55 #define INODE_MAX ((unsigned) 65535)
56 #define SECTOR_SIZE 512
60 #define mul64u(a,b) ((a) * (b))
61 #define lseek64(a,b,c,d) lseek(a,b,c)
68 typedef uint32_t block_t
;
69 typedef uint32_t zone_t
;
75 int next_zone
, next_inode
, 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 uint32_t current_time
, bin_time
;
85 char *umap_array
; /* bit map tells if block read yet */
86 int umap_array_elements
= 0;
87 block_t zone_map
; /* where is zone map? (depends on # inodes) */
90 int extra_space_percent
;
94 #if defined(__NBSD_LIBC) || !defined(__minix)
95 #define getline _mkfs_getline
98 int main(int argc
, char **argv
);
99 block_t
sizeup(char *device
);
100 void super(zone_t zones
, ino_t inodes
);
101 void rootdir(ino_t inode
);
102 int dir_try_enter(zone_t z
, ino_t child
, char *name
);
103 void eat_dir(ino_t parent
);
104 void eat_file(ino_t inode
, int f
);
105 void enter_dir(ino_t parent
, char const *name
, ino_t child
);
106 void enter_symlink(ino_t inode
, char *link
);
107 d2_inode
*get_inoblock(ino_t i
, block_t
*blockno
, d2_inode
**ino
);
108 void incr_size(ino_t n
, size_t count
);
109 static ino_t
alloc_inode(int mode
, int usrid
, int grpid
);
110 static zone_t
alloc_zone(void);
111 void add_zone(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
);
112 void add_z_1(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
);
113 void add_z_2(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
);
114 void incr_link(ino_t n
);
115 void insert_bit(block_t block
, int bit
);
116 int mode_con(char *p
);
117 void getline(char line
[LINE_LEN
], char *parse
[MAX_TOKENS
]);
118 void check_mtab(char *devname
);
119 uint32_t file_time(int f
);
120 __dead
void pexit(char const *s
);
121 void copy(char *from
, char *to
, size_t count
);
123 int read_and_set(block_t n
);
124 void special(char *string
);
125 void get_block(block_t n
, char *buf
);
126 void get_super_block(char *buf
);
127 void put_block(block_t n
, char *buf
);
128 void mx_read(int blocknr
, char *buf
);
129 void mx_write(int blocknr
, char *buf
);
130 void dexit(char *s
, int sectnum
, int err
);
131 __dead
void usage(void);
132 void *alloc_block(void);
138 void detect_fs_size(void);
139 void sizeup_dir(void);
140 void detect_size(void);
142 static int bitmapsize(uint32_t nr_bits
, size_t block_size
);
144 /*================================================================
145 * mkfs - make filesystem
146 *===============================================================*/
151 int nread
, mode
, usrid
, grpid
, ch
;
152 block_t blocks
, maxblocks
;
157 char *token
[MAX_TOKENS
], line
[LINE_LEN
];
160 /* Get two times, the current time and the mod time of the binary of
161 * mkfs itself. When the -d flag is used, the later time is put into
162 * the i_mtimes of all the files. This feature is useful when
163 * producing a set of file systems, and one wants all the times to be
164 * identical. First you set the time of the mkfs binary to what you
167 current_time
= time((time_t *) 0); /* time mkfs is being run */
168 stat(argv
[0], &statbuf
);
169 bin_time
= statbuf
.st_mtime
; /* time when mkfs binary was last modified */
171 /* Process switches. */
175 inodes_per_block
= 0;
177 extra_space_percent
= 0;
178 while ((ch
= getopt(argc
, argv
, "b:di:lotB:x:")) != EOF
)
181 blocks
= strtoul(optarg
, (char **) NULL
, 0);
185 current_time
= bin_time
;
188 i
= strtoul(optarg
, (char **) NULL
, 0);
190 case 'l': print
= 1; break;
191 case 'o': override
= 1; break;
192 case 't': donttest
= 1; break;
193 case 'B': block_size
= atoi(optarg
); break;
194 case 'x': extra_space_percent
= atoi(optarg
); break;
198 if (argc
== optind
) usage();
200 /* Percentage of extra size must be nonnegative.
201 * It can legitimately be bigger than 100 but has to make some sort of sense.
203 if(extra_space_percent
< 0 || extra_space_percent
> 2000) usage();
206 if(!block_size
) block_size
= _MAX_BLOCK_SIZE
; /* V3 default block size */
207 if(block_size
%SECTOR_SIZE
|| block_size
< _MIN_BLOCK_SIZE
) {
208 fprintf(stderr
, "block size must be multiple of sector (%d) "
209 "and at least %d bytes\n",
210 SECTOR_SIZE
, _MIN_BLOCK_SIZE
);
211 pexit("specified block size illegal");
213 if(block_size
%V2_INODE_SIZE
) {
214 fprintf(stderr
, "block size must be a multiple of inode size (%d bytes)\n",
216 pexit("specified block size illegal");
220 if(!inodes_per_block
)
221 inodes_per_block
= V2_INODES_PER_BLOCK(block_size
);
223 /* now that the block size is known, do buffer allocations where
226 zero
= alloc_block();
227 bzero(zero
, block_size
);
229 /* Determine the size of the device if not specified as -b or proto. */
230 maxblocks
= sizeup(argv
[optind
]);
231 if (argc
- optind
== 1 && blocks
== 0) {
233 /* blocks == 0 is checked later, but leads to a funny way of
234 * reporting a 0-sized device (displays usage).
237 fprintf(stderr
, "%s: zero size device.\n", progname
);
242 /* The remaining args must be 'special proto', or just 'special' if the
243 * no. of blocks has already been specified.
245 if (argc
- optind
!= 2 && (argc
- optind
!= 1 || blocks
== 0)) usage();
247 if (blocks
> maxblocks
) {
248 fprintf(stderr
, "%s: %s: number of blocks too large for device.\n",
249 progname
, argv
[optind
]);
254 check_mtab(argv
[optind
]);
256 /* Check and start processing proto. */
257 optarg
= argv
[++optind
];
258 if (optind
< argc
&& (proto
= fopen(optarg
, "r")) != NULL
) {
259 /* Prototype file is readable. */
261 getline(line
, token
); /* skip boot block info */
263 /* Read the line with the block and inode counts. */
264 getline(line
, token
);
265 blocks
= atol(token
[0]);
266 inodes
= atoi(token
[1]);
268 /* Process mode line for root directory. */
269 getline(line
, token
);
270 mode
= mode_con(token
[0]);
271 usrid
= atoi(token
[1]);
272 grpid
= atoi(token
[2]);
274 if(blocks
<= 0 && inodes
<= 0){
278 blocks
+= blocks
*extra_space_percent
/100;
279 inodes
+= inodes
*extra_space_percent
/100;
280 printf("dynamically sized filesystem: %d blocks, %d inodes\n", blocks
,
281 (unsigned int) inodes
);
286 /* Maybe the prototype file is just a size. Check. */
287 blocks
= strtoul(optarg
, (char **) NULL
, 0);
288 if (blocks
== 0) pexit("Can't open prototype file");
292 uint32_t kb
= div64u(mul64u(blocks
, block_size
), 1024);
294 uint32_t kb
= ((unsigned long long) blocks
* block_size
) / 1024;
297 if (kb
>= 100000) i
= kb
/ 4;
299 /* round up to fill inode block */
300 i
+= inodes_per_block
- 1;
301 i
= i
/ inodes_per_block
* inodes_per_block
;
303 if (blocks
< 5) pexit("Block count too small");
304 if (i
< 1) pexit("Inode count too small");
307 /* Make simple file system of the given size, using defaults. */
319 bytes
= 1 + blocks
/8;
320 if(!(umap_array
= malloc(bytes
))) {
321 fprintf(stderr
, "mkfs: can't allocate block bitmap (%u bytes).\n",
325 umap_array_elements
= bytes
;
329 special(argv
[--optind
]);
335 testb
= (short *) alloc_block();
337 /* Try writing the last block of partition or diskette. */
338 if(lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
) < 0) {
339 pexit("couldn't seek to last block to test size (1)");
343 testb
[block_size
/2-1] = 0x1F2F;
344 if ((w
=write(fd
, (char *) testb
, block_size
)) != block_size
) {
345 if(w
< 0) perror("write");
346 printf("%d/%u\n", w
, block_size
);
347 pexit("File system is too big for minor device (write)");
349 sync(); /* flush write, so if error next read fails */
350 if(lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
) < 0) {
351 pexit("couldn't seek to last block to test size (2)");
355 nread
= read(fd
, (char *) testb
, block_size
);
356 if (nread
!= block_size
|| testb
[0] != 0x3245 || testb
[1] != 0x11FF ||
357 testb
[block_size
/2-1] != 0x1F2F) {
358 if(nread
< 0) perror("read");
359 printf("nread = %d\n", nread
);
360 printf("testb = 0x%x 0x%x 0x%x\n", testb
[0], testb
[1], testb
[block_size
-1]);
361 pexit("File system is too big for minor device (read)");
363 lseek64(fd
, mul64u(blocks
- 1, block_size
), SEEK_SET
, NULL
);
366 if (write(fd
, (char *) testb
, block_size
) != block_size
)
367 pexit("File system is too big for minor device (write2)");
368 lseek(fd
, 0L, SEEK_SET
);
372 /* Make the file-system */
374 put_block((block_t
) 0, zero
); /* Write a null boot block. */
378 super(zones
, inodes
);
380 root_inum
= alloc_inode(mode
, usrid
, grpid
);
382 if (simple
== 0) eat_dir(root_inum
);
384 if (print
) print_fs();
390 /*================================================================
391 * detect_fs_size - determine image size dynamically
392 *===============================================================*/
393 void detect_fs_size()
395 uint32_t point
= ftell(proto
);
397 inocount
= 1; /* root directory node */
404 initb
= bitmapsize((uint32_t) (1 + inocount
), block_size
);
405 initb
+= bitmapsize((uint32_t) zonecount
, block_size
);
406 initb
+= START_BLOCK
;
407 initb
+= (inocount
+ inodes_per_block
- 1) / inodes_per_block
;
409 blockcount
= initb
+zonecount
;
410 fseek(proto
, point
, SEEK_SET
);
415 char *token
[MAX_TOKENS
], *p
;
420 zone_t dir_zones
= 0;
423 nr_dzones
= V2_NR_DZONES
;
426 getline(line
, token
);
429 dir_zones
= (dir_entries
/ (NR_DIR_ENTRIES(block_size
)));
430 if(dir_entries
% (NR_DIR_ENTRIES(block_size
)))
432 if(dir_zones
> nr_dzones
)
433 dir_zones
++; /* Max single indir */
434 zonecount
+= dir_zones
;
444 } else if (*p
== 'b' || *p
== 'c') {
446 } else if (*p
== 's') {
447 zonecount
++; /* Symlink contents is always stored a block */
449 if ((f
= fopen(token
[4], "r")) == NULL
) {
450 fprintf(stderr
, "%s: Can't open %s: %s\n",
451 progname
, token
[4], strerror(errno
));
452 pexit("dynamic size detection failed");
454 if (fseek(f
, 0, SEEK_END
) < 0) {
455 fprintf(stderr
, "%s: Can't seek to end of %s\n",
457 pexit("dynamic size detection failed");
461 zone_t fzones
= (size
/ block_size
);
462 if (size
% block_size
)
464 if (fzones
> nr_dzones
)
465 fzones
++; /* Assumes files fit within single indirect */
472 /*================================================================
473 * sizeup - determine device size
474 *===============================================================*/
475 block_t
sizeup(device
)
487 if ((fd
= open(device
, O_RDONLY
)) == -1) {
489 perror("sizeup open");
494 if(minix_sizeup(device
, &bytes
) < 0) {
499 d
= div64u(bytes
, block_size
);
500 rem
= rem64u(bytes
, block_size
);
502 resize
= add64u(mul64u(d
, block_size
), rem
);
503 if(cmp64(resize
, bytes
) != 0) {
505 fprintf(stderr
, "mkfs: truncating FS at %u blocks\n", d
);
508 size
= lseek(fd
, 0, SEEK_END
);
509 if (size
== (off_t
) -1) {
510 fprintf(stderr
, "Cannot get device size fd=%d\n", fd
);
513 d
= size
/ block_size
;
522 static int bitmapsize(uint32_t nr_bits
, size_t blk_size
)
526 nr_blocks
= (int) (nr_bits
/ FS_BITS_PER_BLOCK(blk_size
));
527 if (((uint32_t) nr_blocks
* FS_BITS_PER_BLOCK(blk_size
)) < nr_bits
)
532 /*================================================================
533 * super - construct a superblock
534 *===============================================================*/
536 void super(zones
, inodes
)
546 struct super_block
*sup
;
551 for (cp
= buf
; cp
< &buf
[block_size
]; cp
++) *cp
= 0;
552 sup
= (struct super_block
*) buf
; /* lint - might use a union */
554 /* The assumption is that mkfs will create a clean FS. */
555 sup
->s_flags
= MFSFLAG_CLEAN
;
557 sup
->s_ninodes
= inodes
;
558 sup
->s_nzones
= 0; /* not used in V2 - 0 forces errors early */
559 sup
->s_zones
= zones
;
561 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
562 sup
->s_imap_blocks
= nb
= bitmapsize((uint32_t) (1 + inodes
), block_size
);
563 if(sup
->s_imap_blocks
!= nb
) {
564 fprintf(stderr
, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS
);
567 sup
->s_zmap_blocks
= nb
= bitmapsize((uint32_t) zones
, block_size
);
568 if(nb
!= sup
->s_zmap_blocks
) {
569 fprintf(stderr
, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS
);
572 inode_offset
= START_BLOCK
+ sup
->s_imap_blocks
+ sup
->s_zmap_blocks
;
573 inodeblks
= (inodes
+ inodes_per_block
- 1) / inodes_per_block
;
574 initblks
= inode_offset
+ inodeblks
;
575 sup
->s_firstdatazone_old
= nb
= initblks
;
576 if(nb
>= zones
) pexit("bit maps too large");
577 if(nb
!= sup
->s_firstdatazone_old
) {
578 /* The field is too small to store the value. Fortunately, the value
579 * can be computed from other fields. We set the on-disk field to zero
580 * to indicate that it must not be used. Eventually, we can always set
581 * the on-disk field to zero, and stop using it.
583 sup
->s_firstdatazone_old
= 0;
585 sup
->s_firstdatazone
= nb
;
586 zoff
= sup
->s_firstdatazone
- 1;
587 sup
->s_log_zone_size
= 0;
589 v2sq
= (zone_t
) V2_INDIRECTS(block_size
) * V2_INDIRECTS(block_size
);
590 zo
= V2_NR_DZONES
+ (zone_t
) V2_INDIRECTS(block_size
) + v2sq
;
592 sup
->s_magic
= SUPER_V3
;
593 sup
->s_block_size
= block_size
;
594 sup
->s_disk_version
= 0;
595 #define MAX_MAX_SIZE (INT_MAX)
596 if(MAX_MAX_SIZE
/block_size
< zo
) {
597 sup
->s_max_size
= (int32_t) MAX_MAX_SIZE
;
600 sup
->s_max_size
= zo
* block_size
;
605 if (lseek(fd
, (off_t
) _STATIC_BLOCK_SIZE
, SEEK_SET
) == (off_t
) -1) {
606 pexit("super() couldn't seek");
608 if (write(fd
, buf
, _STATIC_BLOCK_SIZE
) != _STATIC_BLOCK_SIZE
) {
609 pexit("super() couldn't write");
612 /* Clear maps and inodes. */
613 for (i
= START_BLOCK
; i
< initblks
; i
++) put_block((block_t
) i
, zero
);
615 next_zone
= sup
->s_firstdatazone
;
618 zone_map
= INODE_MAP
+ sup
->s_imap_blocks
;
620 insert_bit(zone_map
, 0); /* bit zero must always be allocated */
621 insert_bit((block_t
) INODE_MAP
, 0); /* inode zero not used but
622 * must be allocated */
628 /*================================================================
629 * rootdir - install the root directory
630 *===============================================================*/
637 add_zone(inode
, z
, 2 * sizeof(struct direct
), current_time
);
638 enter_dir(inode
, ".", inode
);
639 enter_dir(inode
, "..", inode
);
644 void enter_symlink(ino_t inode
, char *lnk
)
654 add_zone(inode
, z
, (size_t) strlen(lnk
), current_time
);
660 /*================================================================
661 * eat_dir - recursively install directory
662 *===============================================================*/
666 /* Read prototype lines and set up directory. Recurse if need be. */
667 char *token
[MAX_TOKENS
], *p
;
669 int mode
, usrid
, grpid
, maj
, min
, f
;
675 getline(line
, token
);
677 if (*p
== '$') return;
680 usrid
= atoi(token
[2]);
681 grpid
= atoi(token
[3]);
682 n
= alloc_inode(mode
, usrid
, grpid
);
684 /* Enter name in directory and update directory's size. */
685 enter_dir(parent
, token
[0], n
);
686 incr_size(parent
, sizeof(struct direct
));
688 /* Check to see if file is directory or special. */
691 /* This is a directory. */
692 z
= alloc_zone(); /* zone for new directory */
693 add_zone(n
, z
, 2 * sizeof(struct direct
), current_time
);
694 enter_dir(n
, ".", n
);
695 enter_dir(n
, "..", parent
);
699 } else if (*p
== 'b' || *p
== 'c') {
701 maj
= atoi(token
[4]);
702 min
= atoi(token
[5]);
704 if (token
[6]) size
= atoi(token
[6]);
705 size
= block_size
* size
;
706 add_zone(n
, (zone_t
) (makedev(maj
,min
)), size
, current_time
);
707 } else if (*p
== 's') {
708 enter_symlink(n
, token
[4]);
710 /* Regular file. Go read it. */
711 if ((f
= open(token
[4], O_RDONLY
)) < 0) {
712 fprintf(stderr
, "%s: Can't open %s: %s\n",
713 progname
, token
[4], strerror(errno
));
722 /*================================================================
723 * eat_file - copy file to MINIX
724 *===============================================================*/
725 /* Zonesize >= blocksize */
726 void eat_file(inode
, f
)
738 for (k
= 0; k
< block_size
; k
++) buf
[k
] = 0;
739 if ((ct
= read(f
, buf
, block_size
)) > 0) {
743 timeval
= (dflag
? current_time
: file_time(f
));
744 if (ct
) add_zone(inode
, z
, (size_t) ct
, timeval
);
745 } while (ct
== block_size
);
750 d2_inode
*get_inoblock(ino_t i
, block_t
*blockno
, d2_inode
**ino
)
753 d2_inode
*inoblock
= alloc_block();
754 *blockno
= ((i
- 1) / inodes_per_block
) + inode_offset
;
755 off
= (i
- 1) % inodes_per_block
;
756 get_block(*blockno
, (char *) inoblock
);
757 *ino
= inoblock
+ off
;
761 int dir_try_enter(zone_t z
, ino_t child
, char *name
)
764 struct direct
*dir_entry
= alloc_block();
768 get_block(z
, (char *) dir_entry
);
770 for (i
= 0; i
< NR_DIR_ENTRIES(block_size
); i
++)
771 if (!dir_entry
[i
].mfs_d_ino
)
774 if(i
< NR_DIR_ENTRIES(block_size
)) {
778 dir_entry
[i
].mfs_d_ino
= child
;
780 p2
= dir_entry
[i
].mfs_d_name
;
781 j
= sizeof(dir_entry
[i
].mfs_d_name
);
789 put_block(z
, (char *) dir_entry
);
795 /*================================================================
796 * directory & inode management assist group
797 *===============================================================*/
798 void enter_dir(ino_t parent
, char const *name
, ino_t child
)
800 /* Enter child in parent directory */
801 /* Works for dir > 1 block and zone > block */
805 zone_t
*indirblock
= alloc_block();
807 d2_inode
*inoblock
= get_inoblock(parent
, &b
, &ino
);
809 assert(!(block_size
% sizeof(struct direct
)));
811 for (k
= 0; k
< V2_NR_DZONES
; k
++) {
818 if(dir_try_enter(z
, child
, __UNCONST(name
))) {
819 put_block(b
, (char *) inoblock
);
826 /* no space in directory using just direct blocks; try indirect */
827 if (ino
->d2_zone
[V2_NR_DZONES
] == 0)
828 ino
->d2_zone
[V2_NR_DZONES
] = alloc_zone();
830 get_block(ino
->d2_zone
[V2_NR_DZONES
], (char *) indirblock
);
832 for(k
= 0; k
< V2_INDIRECTS(block_size
); k
++) {
834 if(!z
) z
= indirblock
[k
] = alloc_zone();
836 if(dir_try_enter(z
, child
, __UNCONST(name
))) {
837 put_block(b
, (char *) inoblock
);
838 put_block(ino
->d2_zone
[V2_NR_DZONES
], (char *) indirblock
);
845 printf("Directory-inode %u beyond direct blocks. Could not enter %s\n",
851 void add_zone(ino_t n
, zone_t z
, size_t bytes
, uint32_t cur_time
)
853 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
862 if(!(blk
= malloc(V2_INDIRECTS(block_size
)*sizeof(*blk
))))
863 pexit("Couldn't allocate indirect block");
865 if(!(inode
= malloc(V2_INODES_PER_BLOCK(block_size
)*sizeof(*inode
))))
866 pexit("Couldn't allocate block of inodes");
868 b
= ((n
- 1) / V2_INODES_PER_BLOCK(block_size
)) + inode_offset
;
869 off
= (n
- 1) % V2_INODES_PER_BLOCK(block_size
);
870 get_block(b
, (char *) inode
);
873 p
->d2_mtime
= cur_time
;
874 for (i
= 0; i
< V2_NR_DZONES
; i
++)
875 if (p
->d2_zone
[i
] == 0) {
877 put_block(b
, (char *) inode
);
882 put_block(b
, (char *) inode
);
884 /* File has grown beyond a small file. */
885 if (p
->d2_zone
[V2_NR_DZONES
] == 0) p
->d2_zone
[V2_NR_DZONES
] = alloc_zone();
886 indir
= p
->d2_zone
[V2_NR_DZONES
];
887 put_block(b
, (char *) inode
);
889 get_block(b
, (char *) blk
);
890 for (i
= 0; i
< V2_INDIRECTS(block_size
); i
++)
893 put_block(b
, (char *) blk
);
898 pexit("File has grown beyond single indirect");
905 /* Increment the link count to inode n */
907 static int enter
= 0;
912 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
913 off
= (n
- 1) % inodes_per_block
;
915 static d2_inode
*inode2
= NULL
;
918 s
= sizeof(*inode2
) * V2_INODES_PER_BLOCK(block_size
);
919 if(!inode2
&& !(inode2
= malloc(s
)))
920 pexit("couldn't allocate a block of inodes");
922 get_block(b
, (char *) inode2
);
923 inode2
[off
].d2_nlinks
++;
924 put_block(b
, (char *) inode2
);
930 void incr_size(n
, count
)
934 /* Increment the file-size in inode n */
938 b
= ((n
- 1) / inodes_per_block
) + inode_offset
;
939 off
= (n
- 1) % inodes_per_block
;
942 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
943 pexit("couldn't allocate a block of inodes");
945 get_block(b
, (char *) inode2
);
946 inode2
[off
].d2_size
+= count
;
947 put_block(b
, (char *) inode2
);
953 /*================================================================
954 * allocation assist group
955 *===============================================================*/
956 static ino_t
alloc_inode(mode
, usrid
, grpid
)
957 int mode
, usrid
, grpid
;
964 if (num
> nrinodes
) {
965 fprintf(stderr
, "have %d inodoes\n", nrinodes
);
966 pexit("File system does not have enough inodes");
968 b
= ((num
- 1) / inodes_per_block
) + inode_offset
;
969 off
= (num
- 1) % inodes_per_block
;
973 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
974 pexit("couldn't allocate a block of inodes");
976 get_block(b
, (char *) inode2
);
977 inode2
[off
].d2_mode
= mode
;
978 inode2
[off
].d2_uid
= usrid
;
979 inode2
[off
].d2_gid
= grpid
;
980 put_block(b
, (char *) inode2
);
985 /* Set the bit in the bit map. */
986 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
987 insert_bit((block_t
) INODE_MAP
, (int) num
);
992 static zone_t
alloc_zone()
994 /* Allocate a new zone */
995 /* Works for zone > block */
1001 if ((b
+ 1) > nrblocks
)
1002 pexit("File system not big enough for all the files");
1003 put_block(b
, zero
); /* give an empty zone */
1004 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
1005 insert_bit(zone_map
, (int) (z
- zoff
)); /* lint, NOT OK because
1006 * z hasn't been broken
1013 void insert_bit(block
, bit
)
1017 /* Insert 'count' bits in the bitmap */
1019 #if defined(__minix)
1025 #if defined(__minix)
1026 buf
= (bitchunk_t
*) alloc_block();
1028 buf
= (uint32_t *) alloc_block();
1031 get_block(block
, (char *) buf
);
1032 #if defined(__minix)
1033 w
= bit
/ (8 * sizeof(bitchunk_t
));
1034 s
= bit
% (8 * sizeof(bitchunk_t
));
1036 w
= bit
/ (8 * sizeof(uint32_t));
1037 s
= bit
% (8 * sizeof(uint32_t));
1040 put_block(block
, (char *) buf
);
1046 /*================================================================
1047 * proto-file processing assist group
1048 *===============================================================*/
1052 /* Convert string to mode */
1053 int o1
, o2
, o3
, mode
;
1062 mode
= (o1
<< 6) | (o2
<< 3) | o3
;
1063 if (c1
== 'd') mode
|= S_IFDIR
;
1064 if (c1
== 'b') mode
|= S_IFBLK
;
1065 if (c1
== 'c') mode
|= S_IFCHR
;
1066 if (c1
== 's') mode
|= S_IFLNK
;
1067 if (c1
== '-') mode
|= S_IFREG
;
1068 if (c2
== 'u') mode
|= S_ISUID
;
1069 if (c3
== 'g') mode
|= S_ISGID
;
1073 void getline(line
, parse
)
1074 char *parse
[MAX_TOKENS
];
1075 char line
[LINE_LEN
];
1077 /* Read a line and break it up in tokens */
1082 for (k
= 0; k
< MAX_TOKENS
; k
++) parse
[k
] = 0;
1083 for (k
= 0; k
< LINE_LEN
; k
++) line
[k
] = 0;
1088 if (++k
> LINE_LEN
) pexit("Line too long");
1090 if (d
== EOF
) pexit("Unexpected end-of-file");
1092 if (*p
== '\n') lct
++;
1093 if (*p
== ' ' || *p
== '\t') *p
= 0;
1107 if (c
== '\n') return;
1108 if (c
== 0) continue;
1112 } while (c
!= 0 && c
!= '\n');
1117 /*================================================================
1119 *===============================================================*/
1120 void check_mtab(device
)
1121 char *device
; /* /dev/hd1 or whatever */
1123 /* Check to see if the special file named in s is mounted. */
1124 #if defined(__minix)
1127 char dev
[PATH_MAX
], mount_point
[PATH_MAX
],
1128 type
[MNTNAMELEN
], flags
[MNTFLAGLEN
];
1130 r
= stat(device
, &sb
);
1133 if (errno
== ENOENT
)
1134 return; /* Does not exist, and therefore not mounted. */
1135 fprintf(stderr
, "%s: stat %s failed: %s\n",
1136 progname
, device
, strerror(errno
));
1139 if (!S_ISBLK(sb
.st_mode
))
1141 /* Not a block device and therefore not mounted. */
1145 if (load_mtab(__UNCONST("mkfs")) < 0) return;
1147 n
= get_mtab_entry(dev
, mount_point
, type
, flags
);
1149 if (strcmp(device
, dev
) == 0) {
1150 /* Can't mkfs on top of a mounted file system. */
1151 fprintf(stderr
, "%s: %s is mounted on %s\n",
1152 progname
, device
, mount_point
);
1156 #elif defined(__linux__)
1157 /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite.
1161 dev_t file_dev
=0, file_rdev
=0;
1165 char *mtab_file
= "/proc/mounts";
1167 if ((f
= setmntent (mtab_file
, "r")) == NULL
)
1170 if (stat(device
, &st_buf
) == 0) {
1171 if (S_ISBLK(st_buf
.st_mode
)) {
1172 file_rdev
= st_buf
.st_rdev
;
1174 file_dev
= st_buf
.st_dev
;
1175 file_ino
= st_buf
.st_ino
;
1179 while ((mnt
= getmntent (f
)) != NULL
) {
1180 if (strcmp(device
, mnt
->mnt_fsname
) == 0)
1182 if (stat(mnt
->mnt_fsname
, &st_buf
) == 0) {
1183 if (S_ISBLK(st_buf
.st_mode
)) {
1184 if (file_rdev
&& (file_rdev
== st_buf
.st_rdev
))
1187 if (file_dev
&& ((file_dev
== st_buf
.st_dev
) &&
1188 (file_ino
== st_buf
.st_ino
)))
1196 * Do an extra check to see if this is the root device. We
1197 * can't trust /etc/mtab, and /proc/mounts will only list
1198 * /dev/root for the root filesystem. Argh. Instead we
1199 * check if the given device has the same major/minor number
1200 * as the device that the root directory is on.
1202 if (file_rdev
&& stat("/", &st_buf
) == 0) {
1203 if (st_buf
.st_dev
== file_rdev
) {
1209 /* Validate the entry in case /etc/mtab is out of date */
1211 * We need to be paranoid, because some broken distributions
1212 * (read: Slackware) don't initialize /etc/mtab before checking
1213 * all of the non-root filesystems on the disk.
1215 if (stat(mnt
->mnt_dir
, &st_buf
) < 0) {
1216 if (errno
== ENOENT
) {
1221 if (file_rdev
&& (st_buf
.st_dev
!= file_rdev
)) {
1225 fprintf(stderr
, "Device %s is mounted, exiting\n", device
);
1229 * Check to see if we're referring to the root filesystem.
1230 * If so, do a manual check to see if we can open /etc/mtab
1231 * read/write, since if the root is mounted read/only, the
1232 * contents of /etc/mtab may not be accurate.
1234 if (!strcmp(mnt
->mnt_dir
, "/")) {
1236 fprintf(stderr
, "Device %s is mounted as root file system!\n",
1244 if ((stat(device
, &st_buf
) != 0) ||
1245 !S_ISBLK(st_buf
.st_mode
))
1247 fd
= open(device
, O_RDONLY
| O_EXCL
);
1249 if (errno
== EBUSY
) {
1250 fprintf(stderr
, "Device %s is used by the system\n", device
);
1260 fprintf(stderr
, "Error while checking if device %s is mounted\n", device
);
1266 uint32_t file_time(f
)
1269 struct stat statbuf
;
1271 return(statbuf
.st_mtime
);
1275 __dead
void pexit(char const * s
)
1277 fprintf(stderr
, "%s: %s\n", progname
, s
);
1279 fprintf(stderr
, "Line %d being processed when error detected.\n", lct
);
1284 void copy(from
, to
, count
)
1288 while (count
--) *to
++ = *from
++;
1295 if(!(buf
= malloc(block_size
))) {
1296 pexit("couldn't allocate filesystem buffer");
1298 bzero(buf
, block_size
);
1308 unsigned short *usbuf
;
1312 if(!(inode2
= malloc(V2_INODES_PER_BLOCK(block_size
) * sizeof(*inode2
))))
1313 pexit("couldn't allocate a block of inodes");
1315 if(!(dir
= malloc(NR_DIR_ENTRIES(block_size
)*sizeof(*dir
))))
1316 pexit("malloc of directory entry failed");
1318 usbuf
= (unsigned short *) alloc_block();
1320 get_super_block((char *) usbuf
);
1321 printf("\nSuperblock: ");
1322 for (i
= 0; i
< 8; i
++) printf("%06o ", usbuf
[i
]);
1323 get_block((block_t
) 2, (char *) usbuf
);
1324 printf("...\nInode map: ");
1325 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
1326 get_block((block_t
) 3, (char *) usbuf
);
1327 printf("...\nZone map: ");
1328 for (i
= 0; i
< 9; i
++) printf("%06o ", usbuf
[i
]);
1335 for (b
= inode_offset
; k
< nrinodes
; b
++) {
1336 get_block(b
, (char *) inode2
);
1337 for (i
= 0; i
< inodes_per_block
; i
++) {
1338 k
= inodes_per_block
* (int) (b
- inode_offset
) + i
+ 1;
1340 if (k
> nrinodes
) break;
1342 if (inode2
[i
].d2_mode
!= 0) {
1343 printf("Inode %2u: mode=", k
);
1344 printf("%06o", inode2
[i
].d2_mode
);
1345 printf(" uid=%2d gid=%2d size=",
1346 inode2
[i
].d2_uid
, inode2
[i
].d2_gid
);
1347 printf("%6d", inode2
[i
].d2_size
);
1348 printf(" zone[0]=%u\n", inode2
[i
].d2_zone
[0]);
1350 if ((inode2
[i
].d2_mode
& S_IFMT
) == S_IFDIR
) {
1351 /* This is a directory */
1352 get_block(inode2
[i
].d2_zone
[0], (char *) dir
);
1353 for (j
= 0; j
< NR_DIR_ENTRIES(block_size
); j
++)
1354 if (dir
[j
].mfs_d_ino
)
1355 printf("\tInode %2u: %s\n", dir
[j
].mfs_d_ino
, dir
[j
].mfs_d_name
);
1361 printf("%d inodes used. %d zones used.\n", next_inode
- 1, next_zone
);
1370 /* The first time a block is read, it returns all 0s, unless there has
1371 * been a write. This routine checks to see if a block has been accessed.
1377 if(w
>= umap_array_elements
) {
1378 pexit("umap array too small - this can't happen");
1382 r
= (umap_array
[w
] & mask
? 1 : 0);
1383 umap_array
[w
] |= mask
;
1390 "Usage: %s [-12dlot] [-b blocks] [-i inodes]\n"
1391 "\t[-x extra] [-B blocksize] special [proto]\n",
1396 void special(string
)
1399 fd
= creat(string
, 0777);
1401 fd
= open(string
, O_RDWR
);
1402 if (fd
< 0) pexit("Can't open special file");
1407 void get_block(n
, buf
)
1415 /* First access returns a zero block */
1416 if (read_and_set(n
) == 0) {
1417 copy(zero
, buf
, block_size
);
1420 lseek64(fd
, mul64u(n
, block_size
), SEEK_SET
, NULL
);
1421 k
= read(fd
, buf
, block_size
);
1422 if (k
!= block_size
) {
1423 pexit("get_block couldn't read");
1427 void get_super_block(buf
)
1434 if(lseek(fd
, (off_t
) SUPER_BLOCK_BYTES
, SEEK_SET
) < 0) {
1436 pexit("seek failed");
1438 k
= read(fd
, buf
, _STATIC_BLOCK_SIZE
);
1439 if (k
!= _STATIC_BLOCK_SIZE
) {
1440 pexit("get_super_block couldn't read");
1444 void put_block(n
, buf
)
1448 /* Write a block. */
1450 (void) read_and_set(n
);
1452 /* XXX - check other lseeks too. */
1453 if (lseek64(fd
, mul64u(n
, block_size
), SEEK_SET
, NULL
) == (off_t
) -1) {
1454 pexit("put_block couldn't seek");
1456 if (write(fd
, buf
, block_size
) != block_size
) {
1457 pexit("put_block couldn't write");