source: trunk/minix/commands/simple/origmkfs.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 33.7 KB
Line 
1/* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */
2
3/* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
4 *
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
8 *
9 */
10
11#include <sys/types.h>
12#include <sys/dir.h>
13#include <sys/stat.h>
14#include <stdio.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <limits.h>
18#include <stdlib.h>
19#include <dirent.h>
20#include <string.h>
21#include <time.h>
22#include <unistd.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>
32#endif
33
34#undef EXTERN
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>
39
40#ifndef DOS
41#ifndef UNIX
42#define UNIX
43#endif
44#endif
45
46#undef BLOCK_SIZE
47#define BLOCK_SIZE 1024
48
49#define INODE_MAP 2
50#define MAX_TOKENS 10
51#define LINE_LEN 200
52#define BIN 2
53#define BINGRP 2
54#define BIT_MAP_SHIFT 13
55#define N_BLOCKS (1024L * 1024)
56#define N_BLOCKS16 (128L * 1024)
57#define INODE_MAX ((unsigned) 65535)
58
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.)
63 */
64#define MAX_INIT (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS)
65
66
67#ifdef DOS
68maybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */
69 maybedefine BWRITE 5 /* O_WRONLY | BINARY_BIT */
70#endif
71
72#if (MACHINE == ATARI)
73int isdev;
74#endif
75
76extern char *optarg;
77extern int optind;
78
79int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
80block_t nrblocks;
81int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
82unsigned int nrinodes;
83int override = 0, simple = 0, dflag;
84int donttest; /* skip test if it fits on medium */
85char *progname;
86
87long current_time, bin_time;
88char zero[BLOCK_SIZE], *lastp;
89char umap[MAX_INIT / 8]; /* bit map tells if block read yet */
90block_t zone_map; /* where is zone map? (depends on # inodes) */
91int inodes_per_block;
92int fs_version;
93block_t max_nrblocks;
94
95FILE *proto;
96
97_PROTOTYPE(int main, (int argc, char **argv));
98_PROTOTYPE(block_t sizeup, (char *device));
99_PROTOTYPE(void super, (zone_t zones, Ino_t inodes));
100_PROTOTYPE(void rootdir, (Ino_t inode));
101_PROTOTYPE(void eat_dir, (Ino_t parent));
102_PROTOTYPE(void eat_file, (Ino_t inode, int f));
103_PROTOTYPE(void enter_dir, (Ino_t parent, char *name, Ino_t child));
104_PROTOTYPE(void incr_size, (Ino_t n, long count));
105_PROTOTYPE(PRIVATE ino_t alloc_inode, (int mode, int usrid, int grpid));
106_PROTOTYPE(PRIVATE zone_t alloc_zone, (void));
107_PROTOTYPE(void add_zone, (Ino_t n, zone_t z, long bytes, long cur_time));
108_PROTOTYPE(void add_z_1, (Ino_t n, zone_t z, long bytes, long cur_time));
109_PROTOTYPE(void add_z_2, (Ino_t n, zone_t z, long bytes, long cur_time));
110_PROTOTYPE(void incr_link, (Ino_t n));
111_PROTOTYPE(void insert_bit, (block_t block, int bit));
112_PROTOTYPE(int mode_con, (char *p));
113_PROTOTYPE(void getline, (char line[LINE_LEN], char *parse[MAX_TOKENS]));
114_PROTOTYPE(void check_mtab, (char *devname));
115_PROTOTYPE(long file_time, (int f));
116_PROTOTYPE(void pexit, (char *s));
117_PROTOTYPE(void copy, (char *from, char *to, int count));
118_PROTOTYPE(void print_fs, (void));
119_PROTOTYPE(int read_and_set, (block_t n));
120_PROTOTYPE(void special, (char *string));
121_PROTOTYPE(void get_block, (block_t n, char buf[BLOCK_SIZE]));
122_PROTOTYPE(void put_block, (block_t n, char buf[BLOCK_SIZE]));
123_PROTOTYPE(void cache_init, (void));
124_PROTOTYPE(void flush, (void));
125_PROTOTYPE(void mx_read, (int blocknr, char buf[BLOCK_SIZE]));
126_PROTOTYPE(void mx_write, (int blocknr, char buf[BLOCK_SIZE]));
127_PROTOTYPE(void dexit, (char *s, int sectnum, int err));
128_PROTOTYPE(void usage, (void));
129
130/*================================================================
131 * mkfs - make filesystem
132 *===============================================================*/
133int main(argc, argv)
134int argc;
135char *argv[];
136{
137 int nread, mode, usrid, grpid, ch;
138 block_t blocks;
139 block_t i;
140 ino_t root_inum;
141 ino_t inodes;
142 zone_t zones;
143 char *token[MAX_TOKENS], line[LINE_LEN];
144 struct stat statbuf;
145
146 /* Get two times, the current time and the mod time of the binary of
147 * mkfs itself. When the -d flag is used, the later time is put into
148 * the i_mtimes of all the files. This feature is useful when
149 * producing a set of file systems, and one wants all the times to be
150 * identical. First you set the time of the mkfs binary to what you
151 * want, then go.
152 */
153 current_time = time((time_t *) 0); /* time mkfs is being run */
154 stat(argv[0], &statbuf);
155 bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
156
157 /* Process switches. */
158 progname = argv[0];
159 blocks = 0;
160 i = 0;
161 fs_version = 2;
162 inodes_per_block = V2_INODES_PER_BLOCK(BLOCK_SIZE);
163 max_nrblocks = N_BLOCKS;
164 while ((ch = getopt(argc, argv, "1b:di:lot")) != EOF)
165 switch (ch) {
166 case '1':
167 fs_version = 1;
168 inodes_per_block = V1_INODES_PER_BLOCK;
169 max_nrblocks = 0xFFFF;
170 break;
171 case 'b':
172 blocks = strtoul(optarg, (char **) NULL, 0);
173 break;
174 case 'd':
175 dflag = 1;
176 current_time = bin_time;
177 break;
178 case 'i':
179 i = strtoul(optarg, (char **) NULL, 0);
180 break;
181 case 'l': print = 1; break;
182 case 'o': override = 1; break;
183 case 't': donttest = 1; break;
184 default: usage();
185 }
186
187 /* Determine the size of the device if not specified as -b or proto. */
188 if (argc - optind == 1 && blocks == 0) blocks = sizeup(argv[optind]);
189 printf("%lu blocks\n", blocks);
190
191 /* The remaining args must be 'special proto', or just 'special' if the
192 * block size has already been specified.
193 */
194 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
195
196 /* Check special. */
197 check_mtab(argv[optind]);
198
199 /* Check and start processing proto. */
200 optarg = argv[++optind];
201 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
202 /* Prototype file is readable. */
203 lct = 1;
204 getline(line, token); /* skip boot block info */
205
206 /* Read the line with the block and inode counts. */
207 getline(line, token);
208 blocks = atol(token[0]);
209 if (blocks > max_nrblocks) {
210 printf("%d > %d\n", blocks, max_nrblocks);
211 pexit("Block count too large");
212 }
213 if (sizeof(char *) == 2 && blocks > N_BLOCKS16) {
214 fprintf(stderr,
215 "%s: warning: FS is larger than the %dM that fsck can check!\n",
216 progname, (int) (N_BLOCKS16 / (1024L * 1024)));
217 }
218 inodes = atoi(token[1]);
219
220 /* Process mode line for root directory. */
221 getline(line, token);
222 mode = mode_con(token[0]);
223 usrid = atoi(token[1]);
224 grpid = atoi(token[2]);
225 } else {
226 lct = 0;
227 if (optind < argc) {
228 /* Maybe the prototype file is just a size. Check. */
229 blocks = strtoul(optarg, (char **) NULL, 0);
230 if (blocks == 0) pexit("Can't open prototype file");
231 }
232 if (i == 0) {
233 /* The default for inodes is 3 blocks per inode, rounded up
234 * to fill an inode block. Above 20M, the average files are
235 * sure to be larger because it is hard to fill up 20M with
236 * tiny files, so reduce the default number of inodes. This
237 * default can always be overridden by using the -i option.
238 */
239 i = blocks / 3;
240 if (blocks >= 20000) i = blocks / 4;
241 if (blocks >= 40000) i = blocks / 5;
242 if (blocks >= 60000) i = blocks / 6;
243 if (blocks >= 80000) i = blocks / 7;
244 if (blocks >= 100000) i = blocks / 8;
245 i += inodes_per_block - 1;
246 i = i / inodes_per_block * inodes_per_block;
247 if (i > INODE_MAX) i = INODE_MAX;
248 }
249 if (blocks < 5) pexit("Block count too small");
250 if (blocks > max_nrblocks) {
251 printf("%d > %d\n", blocks, max_nrblocks);
252 pexit("Block count too large");
253 }
254 if (i < 1) pexit("Inode count too small");
255 if (i > INODE_MAX) pexit("Inode count too large");
256 inodes = (ino_t) i;
257
258 /* Make simple file system of the given size, using defaults. */
259 mode = 040777;
260 usrid = BIN;
261 grpid = BINGRP;
262 simple = 1;
263 }
264 nrblocks = blocks;
265 nrinodes = inodes;
266
267 /* Open special. */
268 special(argv[--optind]);
269
270#ifdef UNIX
271 if (!donttest) {
272 static short testb[BLOCK_SIZE / sizeof(short)];
273
274 /* Try writing the last block of partition or diskette. */
275 lseek(fd, (off_t) (blocks - 1) * BLOCK_SIZE, SEEK_SET);
276 testb[0] = 0x3245;
277 testb[1] = 0x11FF;
278 if (write(fd, (char *) testb, BLOCK_SIZE) != BLOCK_SIZE)
279 pexit("File system is too big for minor device");
280 sync(); /* flush write, so if error next read fails */
281 lseek(fd, (off_t) (blocks - 1) * BLOCK_SIZE, SEEK_SET);
282 testb[0] = 0;
283 testb[1] = 0;
284 nread = read(fd, (char *) testb, BLOCK_SIZE);
285 if (nread != BLOCK_SIZE || testb[0] != 0x3245 || testb[1] != 0x11FF)
286 pexit("File system is too big for minor device");
287 lseek(fd, (off_t) (blocks - 1) * BLOCK_SIZE, SEEK_SET);
288 testb[0] = 0;
289 testb[1] = 0;
290 if (write(fd, (char *) testb, BLOCK_SIZE) != BLOCK_SIZE)
291 pexit("File system is too big for minor device");
292 lseek(fd, 0L, SEEK_SET);
293 }
294#endif
295
296 /* Make the file-system */
297
298 cache_init();
299
300#if (MACHINE == ATARI)
301 if (isdev) {
302 char block0[BLOCK_SIZE];
303 get_block((block_t) 0, block0);
304 /* Need to read twice; first time gets an empty block */
305 get_block((block_t) 0, block0);
306 /* Zero parts of the boot block so the disk won't be
307 * recognized as a tos disk any more. */
308 block0[0] = block0[1] = 0; /* branch code to boot code */
309 strncpy(&block0[2], "MINIX ", (size_t) 6);
310 block0[16] = 0; /* number of FATS */
311 block0[17] = block0[18] = 0; /* number of dir entries */
312 block0[22] = block0[23] = 0; /* sectors/FAT */
313 bzero(&block0[30], 480);/* boot code */
314 put_block((block_t) 0, block0);
315 } else
316#endif
317
318 put_block((block_t) 0, zero); /* Write a null boot block. */
319
320 zone_shift = 0; /* for future use */
321 zones = nrblocks >> zone_shift;
322
323 super(zones, inodes);
324
325 root_inum = alloc_inode(mode, usrid, grpid);
326 rootdir(root_inum);
327 if (simple == 0) eat_dir(root_inum);
328
329 if (print) print_fs();
330 flush();
331 return(0);
332
333 /* NOTREACHED */
334} /* end main */
335
336
337/*================================================================
338 * sizeup - determine device size
339 *===============================================================*/
340block_t sizeup(device)
341char *device;
342{
343 int fd;
344 struct partition entry;
345
346 if ((fd = open(device, O_RDONLY)) == -1) return 0;
347 if (ioctl(fd, DIOCGETP, &entry) == -1) entry.size = cvu64(0);
348 close(fd);
349 return div64u(entry.size, BLOCK_SIZE);
350}
351
352
353/*================================================================
354 * super - construct a superblock
355 *===============================================================*/
356
357void super(zones, inodes)
358zone_t zones;
359ino_t inodes;
360{
361 unsigned int i;
362 int inodeblks;
363 int initblks;
364
365 zone_t initzones, nrzones, v1sq, v2sq;
366 zone_t zo;
367 struct super_block *sup;
368 char buf[BLOCK_SIZE], *cp;
369
370 for (cp = buf; cp < &buf[BLOCK_SIZE]; cp++) *cp = 0;
371 sup = (struct super_block *) buf; /* lint - might use a union */
372
373 sup->s_ninodes = inodes;
374 if (fs_version == 1) {
375 sup->s_nzones = zones;
376 } else {
377 sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */
378 sup->s_zones = zones;
379 }
380 sup->s_imap_blocks = bitmapsize((bit_t) (1 + inodes), BLOCK_SIZE);
381 sup->s_zmap_blocks = bitmapsize((bit_t) zones, BLOCK_SIZE);
382 inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2;
383 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
384 initblks = inode_offset + inodeblks;
385 initzones = (initblks + (1 << zone_shift) - 1) >> zone_shift;
386 nrzones = nrblocks >> zone_shift;
387 sup->s_firstdatazone = (initblks + (1 << zone_shift) - 1) >> zone_shift;
388 zoff = sup->s_firstdatazone - 1;
389 sup->s_log_zone_size = zone_shift;
390 if (fs_version == 1) {
391 sup->s_magic = SUPER_MAGIC; /* identify super blocks */
392 v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS;
393 zo = V1_NR_DZONES + (long) V1_INDIRECTS + v1sq;
394 } else {
395 sup->s_magic = SUPER_V2;/* identify super blocks */
396 v2sq = (zone_t) V2_INDIRECTS(BLOCK_SIZE) * V2_INDIRECTS(BLOCK_SIZE);
397 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(BLOCK_SIZE) + v2sq;
398 }
399 sup->s_max_size = zo * BLOCK_SIZE;
400 zone_size = 1 << zone_shift; /* nr of blocks per zone */
401
402 put_block((block_t) 1, buf);
403
404 /* Clear maps and inodes. */
405 for (i = 2; i < initblks; i++) put_block((block_t) i, zero);
406
407 next_zone = sup->s_firstdatazone;
408 next_inode = 1;
409
410 zone_map = INODE_MAP + sup->s_imap_blocks;
411
412 insert_bit(zone_map, 0); /* bit zero must always be allocated */
413 insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but
414 * must be allocated */
415}
416
417
418/*================================================================
419 * rootdir - install the root directory
420 *===============================================================*/
421void rootdir(inode)
422ino_t inode;
423{
424 zone_t z;
425
426 z = alloc_zone();
427 add_zone(inode, z, 32L, current_time);
428 enter_dir(inode, ".", inode);
429 enter_dir(inode, "..", inode);
430 incr_link(inode);
431 incr_link(inode);
432}
433
434
435/*================================================================
436 * eat_dir - recursively install directory
437 *===============================================================*/
438void eat_dir(parent)
439ino_t parent;
440{
441 /* Read prototype lines and set up directory. Recurse if need be. */
442 char *token[MAX_TOKENS], *p;
443 char line[LINE_LEN];
444 int mode, usrid, grpid, maj, min, f;
445 ino_t n;
446 zone_t z;
447 long size;
448
449 while (1) {
450 getline(line, token);
451 p = token[0];
452 if (*p == '$') return;
453 p = token[1];
454 mode = mode_con(p);
455 usrid = atoi(token[2]);
456 grpid = atoi(token[3]);
457 if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n");
458 n = alloc_inode(mode, usrid, grpid);
459
460 /* Enter name in directory and update directory's size. */
461 enter_dir(parent, token[0], n);
462 incr_size(parent, 16L);
463
464 /* Check to see if file is directory or special. */
465 incr_link(n);
466 if (*p == 'd') {
467 /* This is a directory. */
468 z = alloc_zone(); /* zone for new directory */
469 add_zone(n, z, 32L, current_time);
470 enter_dir(n, ".", n);
471 enter_dir(n, "..", parent);
472 incr_link(parent);
473 incr_link(n);
474 eat_dir(n);
475 } else if (*p == 'b' || *p == 'c') {
476 /* Special file. */
477 maj = atoi(token[4]);
478 min = atoi(token[5]);
479 size = 0;
480 if (token[6]) size = atoi(token[6]);
481 size = BLOCK_SIZE * size;
482 add_zone(n, (zone_t) ((maj << 8) | min), size, current_time);
483 } else {
484 /* Regular file. Go read it. */
485 if ((f = open(token[4], O_RDONLY)) < 0) {
486 fprintf(stderr, "%s: Can't open %s: %s\n",
487 progname, token[4], strerror(errno));
488 } else
489 eat_file(n, f);
490 }
491 }
492
493}
494
495/*================================================================
496 * eat_file - copy file to MINIX
497 *===============================================================*/
498/* Zonesize >= blocksize */
499void eat_file(inode, f)
500ino_t inode;
501int f;
502{
503 int ct, i, j, k;
504 zone_t z;
505 char buf[BLOCK_SIZE];
506 long timeval;
507
508 do {
509 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
510 for (k = 0; k < BLOCK_SIZE; k++) buf[k] = 0;
511 if ((ct = read(f, buf, BLOCK_SIZE)) > 0) {
512 if (i == 0) z = alloc_zone();
513 put_block((z << zone_shift) + i, buf);
514 }
515 }
516 timeval = (dflag ? current_time : file_time(f));
517 if (ct) add_zone(inode, z, (long) j, timeval);
518 } while (ct == BLOCK_SIZE);
519 close(f);
520}
521
522
523
524/*================================================================
525 * directory & inode management assist group
526 *===============================================================*/
527void enter_dir(parent, name, child)
528ino_t parent, child;
529char *name;
530{
531 /* Enter child in parent directory */
532 /* Works for dir > 1 block and zone > block */
533 int i, j, k, l, off;
534 block_t b;
535 zone_t z;
536 char *p1, *p2;
537 struct direct dir_entry[NR_DIR_ENTRIES(BLOCK_SIZE)];
538 d1_inode ino1[V1_INODES_PER_BLOCK];
539 d2_inode ino2[V2_INODES_PER_BLOCK(BLOCK_SIZE)];
540 int nr_dzones;
541
542 b = ((parent - 1) / inodes_per_block) + inode_offset;
543 off = (parent - 1) % inodes_per_block;
544
545 if (fs_version == 1) {
546 get_block(b, (char *) ino1);
547 nr_dzones = V1_NR_DZONES;
548 } else {
549 get_block(b, (char *) ino2);
550 nr_dzones = V2_NR_DZONES;
551 }
552 for (k = 0; k < nr_dzones; k++) {
553 if (fs_version == 1) {
554 z = ino1[off].d1_zone[k];
555 if (z == 0) {
556 z = alloc_zone();
557 ino1[off].d1_zone[k] = z;
558 }
559 } else {
560 z = ino2[off].d2_zone[k];
561 if (z == 0) {
562 z = alloc_zone();
563 ino2[off].d2_zone[k] = z;
564 }
565 }
566 for (l = 0; l < zone_size; l++) {
567 get_block((z << zone_shift) + l, (char *) dir_entry);
568 for (i = 0; i < NR_DIR_ENTRIES(BLOCK_SIZE); i++) {
569 if (dir_entry[i].d_ino == 0) {
570 dir_entry[i].d_ino = child;
571 p1 = name;
572 p2 = dir_entry[i].d_name;
573 j = 14;
574 while (j--) {
575 *p2++ = *p1;
576 if (*p1 != 0) p1++;
577 }
578 put_block((z << zone_shift) + l, (char *) dir_entry);
579 if (fs_version == 1) {
580 put_block(b, (char *) ino1);
581 } else {
582 put_block(b, (char *) ino2);
583 }
584 return;
585 }
586 }
587 }
588 }
589
590 printf("Directory-inode %d beyond direct blocks. Could not enter %s\n",
591 parent, name);
592 pexit("Halt");
593}
594
595
596void add_zone(n, z, bytes, cur_time)
597ino_t n;
598zone_t z;
599long bytes, cur_time;
600{
601 if (fs_version == 1) {
602 add_z_1(n, z, bytes, cur_time);
603 } else {
604 add_z_2(n, z, bytes, cur_time);
605 }
606}
607
608void add_z_1(n, z, bytes, cur_time)
609ino_t n;
610zone_t z;
611long bytes, cur_time;
612{
613 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
614
615 int off, i;
616 block_t b;
617 zone_t indir;
618 zone1_t blk[V1_INDIRECTS];
619 d1_inode *p;
620 d1_inode inode[V1_INODES_PER_BLOCK];
621
622 b = ((n - 1) / V1_INODES_PER_BLOCK) + inode_offset;
623 off = (n - 1) % V1_INODES_PER_BLOCK;
624 get_block(b, (char *) inode);
625 p = &inode[off];
626 p->d1_size += bytes;
627 p->d1_mtime = cur_time;
628 for (i = 0; i < V1_NR_DZONES; i++)
629 if (p->d1_zone[i] == 0) {
630 p->d1_zone[i] = (zone1_t) z;
631 put_block(b, (char *) inode);
632 return;
633 }
634 put_block(b, (char *) inode);
635
636 /* File has grown beyond a small file. */
637 if (p->d1_zone[V1_NR_DZONES] == 0)
638 p->d1_zone[V1_NR_DZONES] = (zone1_t) alloc_zone();
639 indir = p->d1_zone[V1_NR_DZONES];
640 put_block(b, (char *) inode);
641 b = indir << zone_shift;
642 get_block(b, (char *) blk);
643 for (i = 0; i < V1_INDIRECTS; i++)
644 if (blk[i] == 0) {
645 blk[i] = (zone1_t) z;
646 put_block(b, (char *) blk);
647 return;
648 }
649 pexit("File has grown beyond single indirect");
650}
651
652void add_z_2(n, z, bytes, cur_time)
653ino_t n;
654zone_t z;
655long bytes, cur_time;
656{
657 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
658
659 int off, i;
660 block_t b;
661 zone_t indir;
662 zone_t blk[V2_INDIRECTS(BLOCK_SIZE)];
663 d2_inode *p;
664 d2_inode inode[V2_INODES_PER_BLOCK(BLOCK_SIZE)];
665
666 b = ((n - 1) / V2_INODES_PER_BLOCK(BLOCK_SIZE)) + inode_offset;
667 off = (n - 1) % V2_INODES_PER_BLOCK(BLOCK_SIZE);
668 get_block(b, (char *) inode);
669 p = &inode[off];
670 p->d2_size += bytes;
671 p->d2_mtime = cur_time;
672 for (i = 0; i < V2_NR_DZONES; i++)
673 if (p->d2_zone[i] == 0) {
674 p->d2_zone[i] = z;
675 put_block(b, (char *) inode);
676 return;
677 }
678 put_block(b, (char *) inode);
679
680 /* File has grown beyond a small file. */
681 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
682 indir = p->d2_zone[V2_NR_DZONES];
683 put_block(b, (char *) inode);
684 b = indir << zone_shift;
685 get_block(b, (char *) blk);
686 for (i = 0; i < V2_INDIRECTS(BLOCK_SIZE); i++)
687 if (blk[i] == 0) {
688 blk[i] = z;
689 put_block(b, (char *) blk);
690 return;
691 }
692 pexit("File has grown beyond single indirect");
693}
694
695
696void incr_link(n)
697ino_t n;
698{
699 /* Increment the link count to inode n */
700 int off;
701 block_t b;
702
703 b = ((n - 1) / inodes_per_block) + inode_offset;
704 off = (n - 1) % inodes_per_block;
705 if (fs_version == 1) {
706 d1_inode inode1[V1_INODES_PER_BLOCK];
707
708 get_block(b, (char *) inode1);
709 inode1[off].d1_nlinks++;
710 put_block(b, (char *) inode1);
711 } else {
712 d2_inode inode2[V2_INODES_PER_BLOCK(BLOCK_SIZE)];
713
714 get_block(b, (char *) inode2);
715 inode2[off].d2_nlinks++;
716 put_block(b, (char *) inode2);
717 }
718}
719
720
721void incr_size(n, count)
722ino_t n;
723long count;
724{
725 /* Increment the file-size in inode n */
726 block_t b;
727 int off;
728
729 b = ((n - 1) / inodes_per_block) + inode_offset;
730 off = (n - 1) % inodes_per_block;
731 if (fs_version == 1) {
732 d1_inode inode1[V1_INODES_PER_BLOCK];
733
734 get_block(b, (char *) inode1);
735 inode1[off].d1_size += count;
736 put_block(b, (char *) inode1);
737 } else {
738 d2_inode inode2[V2_INODES_PER_BLOCK(BLOCK_SIZE)];
739
740 get_block(b, (char *) inode2);
741 inode2[off].d2_size += count;
742 put_block(b, (char *) inode2);
743 }
744}
745
746
747/*================================================================
748 * allocation assist group
749 *===============================================================*/
750PRIVATE ino_t alloc_inode(mode, usrid, grpid)
751int mode, usrid, grpid;
752{
753 ino_t num;
754 int off;
755 block_t b;
756
757 num = next_inode++;
758 if (num > nrinodes) pexit("File system does not have enough inodes");
759 b = ((num - 1) / inodes_per_block) + inode_offset;
760 off = (num - 1) % inodes_per_block;
761 if (fs_version == 1) {
762 d1_inode inode1[V1_INODES_PER_BLOCK];
763
764 get_block(b, (char *) inode1);
765 inode1[off].d1_mode = mode;
766 inode1[off].d1_uid = usrid;
767 inode1[off].d1_gid = grpid;
768 put_block(b, (char *) inode1);
769 } else {
770 d2_inode inode2[V2_INODES_PER_BLOCK(BLOCK_SIZE)];
771
772 get_block(b, (char *) inode2);
773 inode2[off].d2_mode = mode;
774 inode2[off].d2_uid = usrid;
775 inode2[off].d2_gid = grpid;
776 put_block(b, (char *) inode2);
777 }
778
779 /* Set the bit in the bit map. */
780 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
781 insert_bit((block_t) INODE_MAP, (int) num);
782 return(num);
783}
784
785
786PRIVATE zone_t alloc_zone()
787{
788 /* Allocate a new zone */
789 /* Works for zone > block */
790 block_t b;
791 int i;
792 zone_t z;
793
794 z = next_zone++;
795 b = z << zone_shift;
796 if ((b + zone_size) > nrblocks)
797 pexit("File system not big enough for all the files");
798 for (i = 0; i < zone_size; i++)
799 put_block(b + i, zero); /* give an empty zone */
800 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
801 insert_bit(zone_map, (int) (z - zoff)); /* lint, NOT OK because
802 * z hasn't been broken
803 * up into block +
804 * offset yet. */
805 return(z);
806}
807
808
809void insert_bit(block, bit)
810block_t block;
811int bit;
812{
813 /* Insert 'count' bits in the bitmap */
814 int w, s;
815 short buf[BLOCK_SIZE / sizeof(short)];
816
817 if (block < 0) pexit("insert_bit called with negative argument");
818 get_block(block, (char *) buf);
819 w = bit / (8 * sizeof(short));
820 s = bit % (8 * sizeof(short));
821 buf[w] |= (1 << s);
822 put_block(block, (char *) buf);
823}
824
825
826/*================================================================
827 * proto-file processing assist group
828 *===============================================================*/
829int mode_con(p)
830char *p;
831{
832 /* Convert string to mode */
833 int o1, o2, o3, mode;
834 char c1, c2, c3;
835
836 c1 = *p++;
837 c2 = *p++;
838 c3 = *p++;
839 o1 = *p++ - '0';
840 o2 = *p++ - '0';
841 o3 = *p++ - '0';
842 mode = (o1 << 6) | (o2 << 3) | o3;
843 if (c1 == 'd') mode += I_DIRECTORY;
844 if (c1 == 'b') mode += I_BLOCK_SPECIAL;
845 if (c1 == 'c') mode += I_CHAR_SPECIAL;
846 if (c1 == '-') mode += I_REGULAR;
847 if (c2 == 'u') mode += I_SET_UID_BIT;
848 if (c3 == 'g') mode += I_SET_GID_BIT;
849 return(mode);
850}
851
852void getline(line, parse)
853char *parse[MAX_TOKENS];
854char line[LINE_LEN];
855{
856 /* Read a line and break it up in tokens */
857 int k;
858 char c, *p;
859 int d;
860
861 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
862 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
863 k = 0;
864 parse[0] = 0;
865 p = line;
866 while (1) {
867 if (++k > LINE_LEN) pexit("Line too long");
868 d = fgetc(proto);
869 if (d == EOF) pexit("Unexpected end-of-file");
870 *p = d;
871 if (*p == '\n') lct++;
872 if (*p == ' ' || *p == '\t') *p = 0;
873 if (*p == '\n') {
874 *p++ = 0;
875 *p = '\n';
876 break;
877 }
878 p++;
879 }
880
881 k = 0;
882 p = line;
883 lastp = line;
884 while (1) {
885 c = *p++;
886 if (c == '\n') return;
887 if (c == 0) continue;
888 parse[k++] = p - 1;
889 do {
890 c = *p++;
891 } while (c != 0 && c != '\n');
892 }
893}
894
895
896/*================================================================
897 * other stuff
898 *===============================================================*/
899void check_mtab(devname)
900char *devname; /* /dev/hd1 or whatever */
901{
902/* Check to see if the special file named in s is mounted. */
903
904 int n;
905 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
906
907 if (load_mtab("mkfs") < 0) return;
908 while (1) {
909 n = get_mtab_entry(special, mounted_on, version, rw_flag);
910 if (n < 0) return;
911 if (strcmp(devname, special) == 0) {
912 /* Can't mkfs on top of a mounted file system. */
913 fprintf(stderr, "%s: %s is mounted on %s\n",
914 progname, devname, mounted_on);
915 exit(1);
916 }
917 }
918}
919
920
921long file_time(f)
922int f;
923{
924#ifdef UNIX
925 struct stat statbuf;
926 fstat(f, &statbuf);
927 return(statbuf.st_mtime);
928#else /* fstat not supported by DOS */
929 return(0L);
930#endif
931}
932
933
934void pexit(s)
935char *s;
936{
937 fprintf(stderr, "%s: %s\n", progname, s);
938 if (lct != 0)
939 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
940 flush();
941 exit(2);
942}
943
944
945void copy(from, to, count)
946char *from, *to;
947int count;
948{
949 while (count--) *to++ = *from++;
950}
951
952
953void print_fs()
954{
955 int i, j;
956 ino_t k;
957 d1_inode inode1[V1_INODES_PER_BLOCK];
958 d2_inode inode2[V2_INODES_PER_BLOCK(BLOCK_SIZE)];
959 unsigned short usbuf[BLOCK_SIZE / sizeof(unsigned short)];
960 block_t b, inode_limit;
961 struct direct dir[NR_DIR_ENTRIES(BLOCK_SIZE)];
962
963 get_block((block_t) 1, (char *) usbuf);
964 printf("\nSuperblock: ");
965 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
966 get_block((block_t) 2, (char *) usbuf);
967 printf("...\nInode map: ");
968 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
969 get_block((block_t) 3, (char *) usbuf);
970 printf("...\nZone map: ");
971 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
972 printf("...\n");
973
974 k = 0;
975 for (b = inode_offset; k < nrinodes; b++) {
976 if (fs_version == 1) {
977 get_block(b, (char *) inode1);
978 } else {
979 get_block(b, (char *) inode2);
980 }
981 for (i = 0; i < inodes_per_block; i++) {
982 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
983 /* Lint but OK */
984 if (k > nrinodes) break;
985 if (fs_version == 1) {
986 if (inode1[i].d1_mode != 0) {
987 printf("Inode %2d: mode=", k);
988 printf("%06o", inode1[i].d1_mode);
989 printf(" uid=%2d gid=%2d size=",
990 inode1[i].d1_uid, inode1[i].d1_gid);
991 printf("%6ld", inode1[i].d1_size);
992 printf(" zone[0]=%d\n", inode1[i].d1_zone[0]);
993 }
994 if ((inode1[i].d1_mode & I_TYPE) == I_DIRECTORY) {
995 /* This is a directory */
996 get_block(inode1[i].d1_zone[0], (char *) dir);
997 for (j = 0; j < NR_DIR_ENTRIES(BLOCK_SIZE); j++)
998 if (dir[j].d_ino)
999 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
1000 }
1001 } else {
1002 if (inode2[i].d2_mode != 0) {
1003 printf("Inode %2d: mode=", k);
1004 printf("%06o", inode2[i].d2_mode);
1005 printf(" uid=%2d gid=%2d size=",
1006 inode2[i].d2_uid, inode2[i].d2_gid);
1007 printf("%6ld", inode2[i].d2_size);
1008 printf(" zone[0]=%ld\n", inode2[i].d2_zone[0]);
1009 }
1010 if ((inode2[i].d2_mode & I_TYPE) == I_DIRECTORY) {
1011 /* This is a directory */
1012 get_block(inode2[i].d2_zone[0], (char *) dir);
1013 for (j = 0; j < NR_DIR_ENTRIES(BLOCK_SIZE); j++)
1014 if (dir[j].d_ino)
1015 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
1016 }
1017 }
1018 }
1019 }
1020
1021 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
1022}
1023
1024
1025int read_and_set(n)
1026block_t n;
1027{
1028/* The first time a block is read, it returns all 0s, unless there has
1029 * been a write. This routine checks to see if a block has been accessed.
1030 */
1031
1032 int w, s, mask, r;
1033
1034 if (sizeof(char *) == 2 && n >= MAX_INIT) pexit("can't initialize past 128M");
1035 w = n / 8;
1036 s = n % 8;
1037 mask = 1 << s;
1038 r = (umap[w] & mask ? 1 : 0);
1039 umap[w] |= mask;
1040 return(r);
1041}
1042
1043void usage()
1044{
1045 fprintf(stderr,
1046 "Usage: %s [-1dlot] [-b blocks] [-i inodes] special [proto]\n",
1047 progname);
1048 exit(1);
1049}
1050
1051/*================================================================
1052 * get_block & put_block for MS-DOS
1053 *===============================================================*/
1054#ifdef DOS
1055
1056/*
1057 * These are the get_block and put_block routines
1058 * when compiling & running mkfs.c under MS-DOS.
1059 *
1060 * It requires the (asembler) routines absread & abswrite
1061 * from the file diskio.asm. Since these routines just do
1062 * as they are told (read & write the sector specified),
1063 * a local cache is used to minimize the i/o-overhead for
1064 * frequently used blocks.
1065 *
1066 * The global variable "file" determines whether the output
1067 * is to a disk-device or to a binary file.
1068 */
1069
1070
1071#define PH_SECTSIZE 512 /* size of a physical disk-sector */
1072
1073
1074char *derrtab[14] = {
1075 "no error",
1076 "disk is read-only",
1077 "unknown unit",
1078 "device not ready",
1079 "bad command",
1080 "data error",
1081 "internal error: bad request structure length",
1082 "seek error",
1083 "unknown media type",
1084 "sector not found",
1085 "printer out of paper (?)",
1086 "write fault",
1087 "read error",
1088 "general error"
1089};
1090
1091#define CACHE_SIZE 20 /* 20 block-buffers */
1092
1093
1094struct cache {
1095 char blockbuf[BLOCK_SIZE];
1096 block_t blocknum;
1097 int dirty;
1098 int usecnt;
1099} cache[CACHE_SIZE];
1100
1101
1102void special(string)
1103char *string;
1104{
1105
1106 if (string[1] == ':' && string[2] == 0) {
1107 /* Format: d: or d:fname */
1108 disk = (string[0] & ~32) - 'A';
1109 if (disk > 1 && !override) /* safety precaution */
1110 pexit("Bad drive specifier for special");
1111 } else {
1112 file = 1;
1113 if ((fd = creat(string, BWRITE)) == 0)
1114 pexit("Can't open special file");
1115 }
1116}
1117
1118void get_block(n, buf)
1119block_t n;
1120char buf[BLOCK_SIZE];
1121{
1122 /* Get a block to the user */
1123 struct cache *bp, *fp;
1124
1125 /* First access returns a zero block */
1126 if (read_and_set(n) == 0) {
1127 copy(zero, buf, BLOCK_SIZE);
1128 return;
1129 }
1130
1131 /* Look for block in cache */
1132 fp = 0;
1133 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1134 if (bp->blocknum == n) {
1135 copy(bp, buf, BLOCK_SIZE);
1136 bp->usecnt++;
1137 return;
1138 }
1139
1140 /* Remember clean block */
1141 if (bp->dirty == 0)
1142 if (fp) {
1143 if (fp->usecnt > bp->usecnt) fp = bp;
1144 } else
1145 fp = bp;
1146 }
1147
1148 /* Block not in cache, get it */
1149 if (!fp) {
1150 /* No clean buf, flush one */
1151 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1152 if (fp->usecnt > bp->usecnt) fp = bp;
1153 mx_write(fp->blocknum, fp);
1154 }
1155 mx_read(n, fp);
1156 fp->dirty = 0;
1157 fp->usecnt = 0;
1158 fp->blocknum = n;
1159 copy(fp, buf, BLOCK_SIZE);
1160}
1161
1162void put_block(n, buf)
1163block_t n;
1164char buf[BLOCK_SIZE];
1165{
1166 /* Accept block from user */
1167 struct cache *fp, *bp;
1168
1169 (void) read_and_set(n);
1170
1171 /* Look for block in cache */
1172 fp = 0;
1173 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1174 if (bp->blocknum == n) {
1175 copy(buf, bp, BLOCK_SIZE);
1176 bp->dirty = 1;
1177 return;
1178 }
1179
1180 /* Remember clean block */
1181 if (bp->dirty == 0)
1182 if (fp) {
1183 if (fp->usecnt > bp->usecnt) fp = bp;
1184 } else
1185 fp = bp;
1186 }
1187
1188 /* Block not in cache */
1189 if (!fp) {
1190 /* No clean buf, flush one */
1191 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1192 if (fp->usecnt > bp->usecnt) fp = bp;
1193 mx_write(fp->blocknum, fp);
1194 }
1195 fp->dirty = 1;
1196 fp->usecnt = 1;
1197 fp->blocknum = n;
1198 copy(buf, fp, BLOCK_SIZE);
1199}
1200
1201void cache_init()
1202{
1203 struct cache *bp;
1204 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
1205}
1206
1207void flush()
1208{
1209 /* Flush all dirty blocks to disk */
1210 struct cache *bp;
1211
1212 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
1213 if (bp->dirty) {
1214 mx_write(bp->blocknum, bp);
1215 bp->dirty = 0;
1216 }
1217}
1218
1219/*==================================================================
1220 * hard read & write etc.
1221 *=================================================================*/
1222#define MAX_RETRIES 5
1223
1224
1225void mx_read(blocknr, buf)
1226int blocknr;
1227char buf[BLOCK_SIZE];
1228{
1229
1230 /* Read the requested MINIX-block in core */
1231 char (*bp)[PH_SECTSIZE];
1232 int sectnum, retries, err;
1233
1234 if (file) {
1235 lseek(fd, (off_t) blocknr * BLOCK_SIZE, 0);
1236 if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE)
1237 pexit("mx_read: error reading file");
1238 } else {
1239 sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE);
1240 for (bp = buf; bp < &buf[BLOCK_SIZE]; bp++) {
1241 retries = MAX_RETRIES;
1242 do
1243 err = absread(disk, sectnum, bp);
1244 while (err && --retries);
1245
1246 if (retries) {
1247 sectnum++;
1248 } else {
1249 dexit("mx_read", sectnum, err);
1250 }
1251 }
1252 }
1253}
1254
1255void mx_write(blocknr, buf)
1256int blocknr;
1257char buf[BLOCK_SIZE];
1258{
1259 /* Write the MINIX-block to disk */
1260 char (*bp)[PH_SECTSIZE];
1261 int retries, sectnum, err;
1262
1263 if (file) {
1264 lseek(fd, blocknr * BLOCK_SIZE, 0);
1265 if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) {
1266 pexit("mx_write: error writing file");
1267 }
1268 } else {
1269 sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE);
1270 for (bp = buf; bp < &buf[BLOCK_SIZE]; bp++) {
1271 retries = MAX_RETRIES;
1272 do {
1273 err = abswrite(disk, sectnum, bp);
1274 } while (err && --retries);
1275
1276 if (retries) {
1277 sectnum++;
1278 } else {
1279 dexit("mx_write", sectnum, err);
1280 }
1281 }
1282 }
1283}
1284
1285
1286void dexit(s, sectnum, err)
1287int sectnum, err;
1288char *s;
1289{
1290 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1291 s, sectnum, err, derrtab[err]);
1292 exit(2);
1293}
1294
1295#endif
1296
1297/*================================================================
1298 * get_block & put_block for UNIX
1299 *===============================================================*/
1300#ifdef UNIX
1301
1302void special(string)
1303char *string;
1304{
1305 fd = creat(string, 0777);
1306 close(fd);
1307 fd = open(string, O_RDWR);
1308 if (fd < 0) pexit("Can't open special file");
1309#if (MACHINE == ATARI)
1310 {
1311 struct stat statbuf;
1312
1313 if (fstat(fd, &statbuf) < 0) return;
1314 isdev = (statbuf.st_mode & S_IFMT) == S_IFCHR
1315 ||
1316 (statbuf.st_mode & S_IFMT) == S_IFBLK
1317 ;
1318 }
1319#endif
1320}
1321
1322
1323
1324void get_block(n, buf)
1325block_t n;
1326char buf[BLOCK_SIZE];
1327{
1328/* Read a block. */
1329
1330 int k;
1331
1332 /* First access returns a zero block */
1333 if (read_and_set(n) == 0) {
1334 copy(zero, buf, BLOCK_SIZE);
1335 return;
1336 }
1337 lseek(fd, (off_t) n * BLOCK_SIZE, SEEK_SET);
1338 k = read(fd, buf, BLOCK_SIZE);
1339 if (k != BLOCK_SIZE) {
1340 pexit("get_block couldn't read");
1341 }
1342}
1343
1344void put_block(n, buf)
1345block_t n;
1346char buf[BLOCK_SIZE];
1347{
1348/* Write a block. */
1349
1350 (void) read_and_set(n);
1351
1352 /* XXX - check other lseeks too. */
1353 if (lseek(fd, (off_t) n * BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
1354 pexit("put_block couldn't seek");
1355 }
1356 if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) {
1357 pexit("put_block couldn't write");
1358 }
1359}
1360
1361
1362/* Dummy routines to keep source file clean from #ifdefs */
1363
1364void flush()
1365{
1366 return;
1367}
1368
1369void cache_init()
1370{
1371 return;
1372}
1373
1374#endif
Note: See TracBrowser for help on using the repository browser.