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