home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / mkfs.minix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-10  |  12.6 KB  |  506 lines

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