]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/mkfs.minix.c
Imported from util-linux-2.5 tarball.
[thirdparty/util-linux.git] / disk-utils / mkfs.minix.c
CommitLineData
6dbe3af9
KZ
1/*
2 * mkfs.c - make a linux (minix) file-system.
3 *
4 * (C) 1991 Linus Torvalds. This file may be redistributed as per
5 * the Linux copyright.
6 */
7
8/*
726f69e2 9 * DD.MM.YY
6dbe3af9 10 *
726f69e2
KZ
11 * 24.11.91 - Time began. Used the fsck sources to get started.
12 *
13 * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
6dbe3af9
KZ
14 * The algorithm for ".badblocks" is a bit weird, but
15 * it should work. Oh, well.
16 *
726f69e2
KZ
17 * 25.01.92 - Added the -l option for getting the list of bad blocks
18 * out of a named file. (Dave Rivers, rivers@ponds.uucp)
6dbe3af9 19 *
726f69e2 20 * 28.02.92 - Added %-information when using -c.
6dbe3af9 21 *
726f69e2 22 * 28.02.93 - Added support for other namelengths than the original
6dbe3af9
KZ
23 * 14 characters so that I can test the new kernel routines..
24 *
726f69e2
KZ
25 * 09.10.93 - Make exit status conform to that required by fsutil
26 * (Rik Faith, faith@cs.unc.edu)
6dbe3af9 27 *
726f69e2
KZ
28 * 31.10.93 - Added inode request feature, for backup floppies: use
29 * 32 inodes, for a news partition use more.
30 * (Scott Heavner, sdh@po.cwru.edu)
6dbe3af9 31 *
726f69e2
KZ
32 * 03.01.94 - Added support for file system valid flag.
33 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
6dbe3af9 34 *
726f69e2
KZ
35 * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
36 * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
37 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
38 *
39 * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
40 * the filesystem is not misidentified as a MS-DOS FAT filesystem.
41 * (Daniel Quinlan, quinlan@yggdrasil.com)
6dbe3af9
KZ
42 *
43 * Usage: mkfs [-c] [-nXX] [-iXX] device size-in-blocks
44 * mkfs [-l filename ] device size-in-blocks
45 *
46 * -c for readablility checking (SLOW!)
47 * -l for getting a list of bad blocks from a file.
48 * -n for namelength (currently the kernel only uses 14 or 30)
49 * -i for number of inodes
50 *
51 * The device may be a block device or a image of one, but this isn't
52 * enforced (but it's not much fun on a character device :-).
53 */
54
55#include <stdio.h>
56#include <time.h>
57#include <unistd.h>
58#include <string.h>
59#include <signal.h>
60#include <fcntl.h>
61#include <ctype.h>
62#include <stdlib.h>
63#include <termios.h>
64#include <sys/stat.h>
65#include <mntent.h>
66
67#include <linux/fs.h>
68#include <linux/minix_fs.h>
69
70#ifndef __GNUC__
71#error "needs gcc for the bitop-__asm__'s"
72#endif
73
74#ifndef __linux__
75#define volatile
76#endif
77
78#define MINIX_ROOT_INO 1
79#define MINIX_BAD_INO 2
80
81#define TEST_BUFFER_BLOCKS 16
82#define MAX_GOOD_BLOCKS 512
83
84#define UPPER(size,n) ((size+((n)-1))/(n))
85#define INODE_SIZE (sizeof(struct minix_inode))
86#define INODE_BLOCKS UPPER(INODES,MINIX_INODES_PER_BLOCK)
87#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
88
89#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
90
91static char * program_name = "mkfs";
92static char * device_name = NULL;
93static int DEV = -1;
94static long BLOCKS = 0;
95static int check = 0;
96static int badblocks = 0;
97static int namelen = 30; /* default (changed to 30, per Linus's
98 suggestion, Sun Nov 21 08:05:07 1993) */
99static int dirsize = 16;
100static int magic = MINIX_SUPER_MAGIC;
101
102static char root_block[BLOCK_SIZE] = "\0";
103
104static char * inode_buffer = NULL;
105#define Inode (((struct minix_inode *) inode_buffer)-1)
106static char super_block_buffer[BLOCK_SIZE];
726f69e2 107static char boot_block_buffer[512];
6dbe3af9
KZ
108#define Super (*(struct minix_super_block *)super_block_buffer)
109#define INODES ((unsigned long)Super.s_ninodes)
110#define ZONES ((unsigned long)Super.s_nzones)
111#define IMAPS ((unsigned long)Super.s_imap_blocks)
112#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
113#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
114#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
115#define MAXSIZE ((unsigned long)Super.s_max_size)
116#define MAGIC (Super.s_magic)
117#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
118
119static char inode_map[BLOCK_SIZE * MINIX_I_MAP_SLOTS];
120static char zone_map[BLOCK_SIZE * MINIX_Z_MAP_SLOTS];
121
122static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
123static int used_good_blocks = 0;
124static unsigned long req_nr_inodes = 0;
125
126#define bitop(name,op) \
127static inline int name(char * addr,unsigned int nr) \
128{ \
129int __res; \
130__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
131:"=g" (__res) \
132:"r" (nr),"m" (*(addr)),"0" (0)); \
133return __res; \
134}
135
136bitop(bit,"")
137bitop(setbit,"s")
138bitop(clrbit,"r")
139
140#define inode_in_use(x) (bit(inode_map,(x)))
141#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
142
143#define mark_inode(x) (setbit(inode_map,(x)))
144#define unmark_inode(x) (clrbit(inode_map,(x)))
145
146#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
147#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
148
149/*
150 * Volatile to let gcc know that this doesn't return. When trying
151 * to compile this under minix, volatile gives a warning, as
152 * exit() isn't defined as volatile under minix.
153 */
154volatile void fatal_error(const char * fmt_string,int status)
155{
156 fprintf(stderr,fmt_string,program_name,device_name);
157 exit(status);
158}
159
160#define usage() fatal_error("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name blocks\n",16)
161#define die(str) fatal_error("%s: " str "\n",8)
162
163/*
164 * Check to make certain that our new filesystem won't be created on
165 * an already mounted partition. Code adapted from mke2fs, Copyright
166 * (C) 1994 Theodore Ts'o. Also licensed under GPL.
167 */
168static void check_mount(void)
169{
170 FILE * f;
171 struct mntent * mnt;
172
173 if ((f = setmntent (MOUNTED, "r")) == NULL)
174 return;
175 while ((mnt = getmntent (f)) != NULL)
176 if (strcmp (device_name, mnt->mnt_fsname) == 0)
177 break;
178 endmntent (f);
179 if (!mnt)
180 return;
181
182 die("%s is mounted; will not make a filesystem here!");
183}
184
185void write_tables(void)
186{
187 /* Mark the super block valid. */
188 Super.s_state |= MINIX_VALID_FS;
189 Super.s_state &= ~MINIX_ERROR_FS;
190
726f69e2
KZ
191 if (lseek(DEV, 0, SEEK_SET))
192 die("seek to boot block failed in write_tables");
193 if (512 != write(DEV, boot_block_buffer, 512))
194 die("unable to clear boot sector");
6dbe3af9
KZ
195 if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
196 die("seek failed in write_tables");
197 if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
198 die("unable to write super-block");
199 if (IMAPS*BLOCK_SIZE != write(DEV,inode_map,IMAPS*BLOCK_SIZE))
726f69e2 200 die("unable to write inode map");
6dbe3af9 201 if (ZMAPS*BLOCK_SIZE != write(DEV,zone_map,ZMAPS*BLOCK_SIZE))
726f69e2 202 die("unable to write zone map");
6dbe3af9 203 if (INODE_BUFFER_SIZE != write(DEV,inode_buffer,INODE_BUFFER_SIZE))
726f69e2
KZ
204 die("unable to write inodes");
205
6dbe3af9
KZ
206}
207
208void write_block(int blk, char * buffer)
209{
210 if (blk*BLOCK_SIZE != lseek(DEV, blk*BLOCK_SIZE, SEEK_SET))
211 die("seek failed in write_block");
212 if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
213 die("write failed in write_block");
214}
215
216int get_free_block(void)
217{
218 int blk;
219
220 if (used_good_blocks+1 >= MAX_GOOD_BLOCKS)
221 die("too many bad blocks");
222 if (used_good_blocks)
223 blk = good_blocks_table[used_good_blocks-1]+1;
224 else
225 blk = FIRSTZONE;
226 while (blk < ZONES && zone_in_use(blk))
227 blk++;
228 if (blk >= ZONES)
229 die("not enough good blocks");
230 good_blocks_table[used_good_blocks] = blk;
231 used_good_blocks++;
232 return blk;
233}
234
235void mark_good_blocks(void)
236{
237 int blk;
238
239 for (blk=0 ; blk < used_good_blocks ; blk++)
240 mark_zone(good_blocks_table[blk]);
241}
242
243inline int next(int zone)
244{
245 if (!zone)
246 zone = FIRSTZONE-1;
247 while (++zone < ZONES)
248 if (zone_in_use(zone))
249 return zone;
250 return 0;
251}
252
253void make_bad_inode(void)
254{
255 struct minix_inode * inode = &Inode[MINIX_BAD_INO];
256 int i,j,zone;
257 int ind=0,dind=0;
258 unsigned short ind_block[BLOCK_SIZE>>1];
259 unsigned short dind_block[BLOCK_SIZE>>1];
260
261#define NEXT_BAD (zone = next(zone))
262
263 if (!badblocks)
264 return;
265 mark_inode(MINIX_BAD_INO);
266 inode->i_nlinks = 1;
267 inode->i_time = time(NULL);
268 inode->i_mode = S_IFREG + 0000;
269 inode->i_size = badblocks*BLOCK_SIZE;
270 zone = next(0);
271 for (i=0 ; i<7 ; i++) {
272 inode->i_zone[i] = zone;
273 if (!NEXT_BAD)
274 goto end_bad;
275 }
276 inode->i_zone[7] = ind = get_free_block();
277 memset(ind_block,0,BLOCK_SIZE);
278 for (i=0 ; i<512 ; i++) {
279 ind_block[i] = zone;
280 if (!NEXT_BAD)
281 goto end_bad;
282 }
283 inode->i_zone[8] = dind = get_free_block();
284 memset(dind_block,0,BLOCK_SIZE);
285 for (i=0 ; i<512 ; i++) {
286 write_block(ind,(char *) ind_block);
287 dind_block[i] = ind = get_free_block();
288 memset(ind_block,0,BLOCK_SIZE);
289 for (j=0 ; j<512 ; j++) {
290 ind_block[j] = zone;
291 if (!NEXT_BAD)
292 goto end_bad;
293 }
294 }
295 die("too many bad blocks");
296end_bad:
297 if (ind)
298 write_block(ind, (char *) ind_block);
299 if (dind)
300 write_block(dind, (char *) dind_block);
301}
302
303void make_root_inode(void)
304{
305 struct minix_inode * inode = &Inode[MINIX_ROOT_INO];
306
307 mark_inode(MINIX_ROOT_INO);
308 inode->i_zone[0] = get_free_block();
309 inode->i_nlinks = 2;
310 inode->i_time = time(NULL);
311 if (badblocks)
312 inode->i_size = 3*dirsize;
313 else {
314 root_block[2*dirsize] = '\0';
315 root_block[2*dirsize+1] = '\0';
316 inode->i_size = 2*dirsize;
317 }
318 inode->i_mode = S_IFDIR + 0755;
319 write_block(inode->i_zone[0],root_block);
320}
321
322void setup_tables(void)
323{
324 int i;
325
326 memset(inode_map,0xff,sizeof(inode_map));
327 memset(zone_map,0xff,sizeof(zone_map));
328 memset(super_block_buffer,0,BLOCK_SIZE);
726f69e2 329 memset(boot_block_buffer,0,512);
6dbe3af9
KZ
330 MAGIC = magic;
331 ZONESIZE = 0;
332 MAXSIZE = (7+512+512*512)*1024;
333 ZONES = BLOCKS;
334/* some magic nrs: 1 inode / 3 blocks */
335 if ( req_nr_inodes == 0 )
336 INODES = BLOCKS/3;
337 else
338 INODES = req_nr_inodes;
339/* I don't want some off-by-one errors, so this hack... */
340 if ((INODES & 8191) > 8188)
341 INODES -= 5;
342 if ((INODES & 8191) < 10)
343 INODES -= 20;
344 IMAPS = UPPER(INODES,BITS_PER_BLOCK);
345 ZMAPS = 0;
346 while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK))
347 ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK);
348 FIRSTZONE = NORM_FIRSTZONE;
349 for (i = FIRSTZONE ; i<ZONES ; i++)
350 unmark_zone(i);
351 for (i = MINIX_ROOT_INO ; i<INODES ; i++)
352 unmark_inode(i);
353 inode_buffer = malloc(INODE_BUFFER_SIZE);
354 if (!inode_buffer)
726f69e2 355 die("unable to allocate buffer for inodes");
6dbe3af9
KZ
356 memset(inode_buffer,0,INODE_BUFFER_SIZE);
357 printf("%d inodes\n",INODES);
358 printf("%d blocks\n",ZONES);
359 printf("Firstdatazone=%d (%d)\n",FIRSTZONE,NORM_FIRSTZONE);
360 printf("Zonesize=%d\n",BLOCK_SIZE<<ZONESIZE);
361 printf("Maxsize=%d\n\n",MAXSIZE);
362}
363
364/*
365 * Perform a test of a block; return the number of
366 * blocks readable/writeable.
367 */
368long do_check(char * buffer, int try, unsigned int current_block)
369{
370 long got;
371
372 /* Seek to the correct loc. */
373 if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
374 current_block * BLOCK_SIZE ) {
375 die("seek failed during testing of blocks");
376 }
377
378
379 /* Try the read */
380 got = read(DEV, buffer, try * BLOCK_SIZE);
381 if (got < 0) got = 0;
382 if (got & (BLOCK_SIZE - 1 )) {
383 printf("Weird values in do_check: probably bugs\n");
384 }
385 got /= BLOCK_SIZE;
386 return got;
387}
388
389static unsigned int currently_testing = 0;
390
391void alarm_intr(int alnum)
392{
393 if (currently_testing >= ZONES)
394 return;
395 signal(SIGALRM,alarm_intr);
396 alarm(5);
397 if (!currently_testing)
398 return;
399 printf("%d ...", currently_testing);
400 fflush(stdout);
401}
402
403void check_blocks(void)
404{
405 int try,got;
406 static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
407
408 currently_testing=0;
409 signal(SIGALRM,alarm_intr);
410 alarm(5);
411 while (currently_testing < ZONES) {
412 if (lseek(DEV,currently_testing*BLOCK_SIZE,SEEK_SET) !=
413 currently_testing*BLOCK_SIZE)
414 die("seek failed in check_blocks");
415 try = TEST_BUFFER_BLOCKS;
416 if (currently_testing + try > ZONES)
417 try = ZONES-currently_testing;
418 got = do_check(buffer, try, currently_testing);
419 currently_testing += got;
420 if (got == try)
421 continue;
422 if (currently_testing < FIRSTZONE)
423 die("bad blocks before data-area: cannot make fs");
424 mark_zone(currently_testing);
425 badblocks++;
426 currently_testing++;
427 }
428 if (badblocks)
429 printf("%d bad block%s\n",badblocks,(badblocks>1)?"s":"");
430}
431
432void get_list_blocks(filename)
433char *filename;
434{
435 FILE *listfile;
436 unsigned long blockno;
437
438 listfile=fopen(filename,"r");
439 if(listfile == (FILE *)NULL) {
726f69e2 440 die("can't open file of bad blocks");
6dbe3af9
KZ
441 }
442 while(!feof(listfile)) {
443 fscanf(listfile,"%d\n", &blockno);
444 mark_zone(blockno);
445 badblocks++;
446 }
447 if(badblocks) {
448 printf("%d bad block%s\n", badblocks, (badblocks>1)?"s":"");
449 }
450}
451
452int main(int argc, char ** argv)
453{
454 int i;
455 char * tmp;
456 struct stat statbuf;
457 char * listfile = NULL;
458
459 if (argc && *argv)
460 program_name = *argv;
461 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
462 die("bad inode size");
463 while (argc-- > 1) {
464 argv++;
465 if (argv[0][0] != '-')
466 if (device_name) {
467 BLOCKS = strtol(argv[0],&tmp,0);
468 if (*tmp) {
469 printf("strtol error: number of"
470 " blocks not specified");
471 usage();
472 }
473 } else
474 device_name = argv[0];
475 else {
476 if(argv[0][1] == 'l') {
477 listfile = argv[1];
478 argv++;
479 if (!(argc--))
480 usage();
481 } else {
482 if(argv[0][1] == 'i') {
483 req_nr_inodes
484 = (unsigned long)atol(argv[1]);
485 argv++;
486 if (!(argc--))
487 usage();
488 } else while (*(++argv[0])) {
489 switch (argv[0][0]) {
490 case 'c': check=1; break;
491 case 'n':
492 i = strtoul(argv[0]+1,&tmp,0);
493 if (*tmp)
494 usage();
495 argv[0][1] = '\0';
496 if (i == 14)
497 magic = MINIX_SUPER_MAGIC;
498 else if (i == 30)
499 magic = MINIX_SUPER_MAGIC2;
500 else
501 usage();
502 namelen = i;
503 dirsize = i+2;
504 break;
505 default: usage();
506 }
507 }
508 }
509 }
510 }
511 if (!device_name || BLOCKS<10 || BLOCKS > 65536) {
512 usage();
513 }
514 check_mount(); /* is it already mounted? */
515 tmp = root_block;
516 tmp[0] = 1;
517 tmp[1] = 0;
518 strcpy(tmp+2,".");
519 tmp += dirsize;
520 tmp[0] = 1;
521 tmp[1] = 0;
522 strcpy(tmp+2,"..");
523 tmp += dirsize;
524 tmp[0] = 2;
525 tmp[1] = 0;
526 strcpy(tmp+2,".badblocks");
527 DEV = open(device_name,O_RDWR );
528 if (DEV<0)
529 die("unable to open %s");
530 if (fstat(DEV,&statbuf)<0)
531 die("unable to stat %s");
532 if (!S_ISBLK(statbuf.st_mode))
533 check=0;
534 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
726f69e2 535 die("will not try to make filesystem on '%s'");
6dbe3af9
KZ
536 setup_tables();
537 if (check)
538 check_blocks();
539 else if (listfile)
540 get_list_blocks(listfile);
541 make_root_inode();
542 make_bad_inode();
543 mark_good_blocks();
544 write_tables();
545 return 0;
546}