Home | History | Annotate | Download | only in stage2
      1 /*
      2  *  GRUB  --  GRand Unified Bootloader
      3  *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc.
      4  *
      5  *  This program is free software; you can redistribute it and/or modify
      6  *  it under the terms of the GNU General Public License as published by
      7  *  the Free Software Foundation; either version 2 of the License, or
      8  *  (at your option) any later version.
      9  *
     10  *  This program is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  *  GNU General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU General Public License
     16  *  along with this program; if not, write to the Free Software
     17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     18  */
     19 
     20 /* Restrictions:
     21    This is MINIX V1 only (yet)
     22    Disk creation is like:
     23    mkfs.minix -c DEVICE
     24 */
     25 
     26 #ifdef FSYS_MINIX
     27 
     28 #include "shared.h"
     29 #include "filesys.h"
     30 
     31 /* #define DEBUG_MINIX */
     32 
     33 /* indirect blocks */
     34 static int mapblock1, mapblock2, namelen;
     35 
     36 /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
     37 #define DEV_BSIZE 512
     38 
     39 /* include/linux/fs.h */
     40 #define BLOCK_SIZE_BITS 10
     41 #define BLOCK_SIZE 	(1<<BLOCK_SIZE_BITS)
     42 
     43 /* made up, defaults to 1 but can be passed via mount_opts */
     44 #define WHICH_SUPER 1
     45 /* kind of from fs/ext2/super.c (is OK for minix) */
     46 #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */
     47 
     48 /* include/asm-i386/type.h */
     49 typedef __signed__ char __s8;
     50 typedef unsigned char __u8;
     51 typedef __signed__ short __s16;
     52 typedef unsigned short __u16;
     53 typedef __signed__ int __s32;
     54 typedef unsigned int __u32;
     55 
     56 /* include/linux/minix_fs.h */
     57 #define MINIX_ROOT_INO 1
     58 
     59 /* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
     60 #define MINIX_LINK_MAX  250
     61 #define MINIX2_LINK_MAX 65530
     62 
     63 #define MINIX_I_MAP_SLOTS       8
     64 #define MINIX_Z_MAP_SLOTS       64
     65 #define MINIX_SUPER_MAGIC       0x137F          /* original minix fs */
     66 #define MINIX_SUPER_MAGIC2      0x138F          /* minix fs, 30 char names */
     67 #define MINIX2_SUPER_MAGIC      0x2468          /* minix V2 fs */
     68 #define MINIX2_SUPER_MAGIC2     0x2478          /* minix V2 fs, 30 char names */
     69 #define MINIX_VALID_FS          0x0001          /* Clean fs. */
     70 #define MINIX_ERROR_FS          0x0002          /* fs has errors. */
     71 
     72 #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
     73 #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
     74 
     75 #define MINIX_V1                0x0001          /* original minix fs */
     76 #define MINIX_V2                0x0002          /* minix V2 fs */
     77 
     78 /* originally this is :
     79 #define INODE_VERSION(inode)    inode->i_sb->u.minix_sb.s_version
     80    here we have */
     81 #define INODE_VERSION(inode)	(SUPERBLOCK->s_version)
     82 
     83 /*
     84  * This is the original minix inode layout on disk.
     85  * Note the 8-bit gid and atime and ctime.
     86  */
     87 struct minix_inode {
     88 	__u16 i_mode;
     89 	__u16 i_uid;
     90 	__u32 i_size;
     91 	__u32 i_time;
     92 	__u8  i_gid;
     93 	__u8  i_nlinks;
     94 	__u16 i_zone[9];
     95 };
     96 
     97 /*
     98  * The new minix inode has all the time entries, as well as
     99  * long block numbers and a third indirect block (7+1+1+1
    100  * instead of 7+1+1). Also, some previously 8-bit values are
    101  * now 16-bit. The inode is now 64 bytes instead of 32.
    102  */
    103 struct minix2_inode {
    104 	__u16 i_mode;
    105 	__u16 i_nlinks;
    106 	__u16 i_uid;
    107 	__u16 i_gid;
    108 	__u32 i_size;
    109 	__u32 i_atime;
    110 	__u32 i_mtime;
    111 	__u32 i_ctime;
    112 	__u32 i_zone[10];
    113 };
    114 
    115 /*
    116  * minix super-block data on disk
    117  */
    118 struct minix_super_block {
    119         __u16 s_ninodes;
    120         __u16 s_nzones;
    121         __u16 s_imap_blocks;
    122         __u16 s_zmap_blocks;
    123         __u16 s_firstdatazone;
    124         __u16 s_log_zone_size;
    125         __u32 s_max_size;
    126         __u16 s_magic;
    127         __u16 s_state;
    128         __u32 s_zones;
    129 };
    130 
    131 struct minix_dir_entry {
    132         __u16 inode;
    133         char name[0];
    134 };
    135 
    136 /* made up, these are pointers into FSYS_BUF */
    137 /* read once, always stays there: */
    138 #define SUPERBLOCK \
    139     ((struct minix_super_block *)(FSYS_BUF))
    140 #define INODE \
    141     ((struct minix_inode *)((int) SUPERBLOCK + BLOCK_SIZE))
    142 #define DATABLOCK1 \
    143     ((int)((int)INODE + sizeof(struct minix_inode)))
    144 #define DATABLOCK2 \
    145     ((int)((int)DATABLOCK1 + BLOCK_SIZE))
    146 
    147 /* linux/stat.h */
    148 #define S_IFMT  00170000
    149 #define S_IFLNK  0120000
    150 #define S_IFREG  0100000
    151 #define S_IFDIR  0040000
    152 #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
    153 #define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
    154 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
    155 
    156 #define PATH_MAX                1024	/* include/linux/limits.h */
    157 #define MAX_LINK_COUNT             5	/* number of symbolic links to follow */
    158 
    159 /* check filesystem types and read superblock into memory buffer */
    160 int
    161 minix_mount (void)
    162 {
    163   if (((current_drive & 0x80) || current_slice != 0)
    164       && ! IS_PC_SLICE_TYPE_MINIX (current_slice)
    165       && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
    166     return 0;			/* The partition is not of MINIX type */
    167 
    168   if (part_length < (SBLOCK +
    169 		     (sizeof (struct minix_super_block) / DEV_BSIZE)))
    170     return 0;			/* The partition is too short */
    171 
    172   if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
    173 		(char *) SUPERBLOCK))
    174     return 0;			/* Cannot read superblock */
    175 
    176   switch (SUPERBLOCK->s_magic)
    177     {
    178     case MINIX_SUPER_MAGIC:
    179       namelen = 14;
    180       break;
    181     case MINIX_SUPER_MAGIC2:
    182       namelen = 30;
    183       break;
    184     default:
    185       return 0;			/* Unsupported type */
    186     }
    187 
    188   return 1;
    189 }
    190 
    191 /* Takes a file system block number and reads it into BUFFER. */
    192 static int
    193 minix_rdfsb (int fsblock, int buffer)
    194 {
    195   return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
    196 		  BLOCK_SIZE, (char *) buffer);
    197 }
    198 
    199 /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
    200    a physical block (the location in the file system) via an inode. */
    201 static int
    202 minix_block_map (int logical_block)
    203 {
    204   int i;
    205 
    206   if (logical_block < 7)
    207     return INODE->i_zone[logical_block];
    208 
    209   logical_block -= 7;
    210   if (logical_block < 512)
    211     {
    212       i = INODE->i_zone[7];
    213 
    214       if (!i || ((mapblock1 != 1)
    215 		 && !minix_rdfsb (i, DATABLOCK1)))
    216 	{
    217 	  errnum = ERR_FSYS_CORRUPT;
    218 	  return -1;
    219 	}
    220       mapblock1 = 1;
    221       return ((__u16 *) DATABLOCK1) [logical_block];
    222     }
    223 
    224   logical_block -= 512;
    225   i = INODE->i_zone[8];
    226   if (!i || ((mapblock1 != 2)
    227 	     && !minix_rdfsb (i, DATABLOCK1)))
    228     {
    229       errnum = ERR_FSYS_CORRUPT;
    230       return -1;
    231     }
    232   mapblock1 = 2;
    233   i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
    234   if (!i || ((mapblock2 != i)
    235 	     && !minix_rdfsb (i, DATABLOCK2)))
    236     {
    237       errnum = ERR_FSYS_CORRUPT;
    238       return -1;
    239     }
    240   mapblock2 = i;
    241   return ((__u16 *) DATABLOCK2)[logical_block & 511];
    242 }
    243 
    244 /* read from INODE into BUF */
    245 int
    246 minix_read (char *buf, int len)
    247 {
    248   int logical_block;
    249   int offset;
    250   int map;
    251   int ret = 0;
    252   int size = 0;
    253 
    254   while (len > 0)
    255     {
    256       /* find the (logical) block component of our location */
    257       logical_block = filepos >> BLOCK_SIZE_BITS;
    258       offset = filepos & (BLOCK_SIZE - 1);
    259       map = minix_block_map (logical_block);
    260 #ifdef DEBUG_MINIX
    261       printf ("map=%d\n", map);
    262 #endif
    263       if (map < 0)
    264 	break;
    265 
    266       size = BLOCK_SIZE;
    267       size -= offset;
    268       if (size > len)
    269 	size = len;
    270 
    271       disk_read_func = disk_read_hook;
    272 
    273       devread (map * (BLOCK_SIZE / DEV_BSIZE),
    274 	       offset, size, buf);
    275 
    276       disk_read_func = NULL;
    277 
    278       buf += size;
    279       len -= size;
    280       filepos += size;
    281       ret += size;
    282     }
    283 
    284   if (errnum)
    285     ret = 0;
    286 
    287   return ret;
    288 }
    289 
    290 /* preconditions: minix_mount already executed, therefore supblk in buffer
    291      known as SUPERBLOCK
    292    returns: 0 if error, nonzero iff we were able to find the file successfully
    293    postconditions: on a nonzero return, buffer known as INODE contains the
    294      inode of the file we were trying to look up
    295    side effects: none yet  */
    296 int
    297 minix_dir (char *dirname)
    298 {
    299   int current_ino = MINIX_ROOT_INO;  /* start at the root */
    300   int updir_ino = current_ino;	     /* the parent of the current directory */
    301   int ino_blk;			     /* fs pointer of the inode's info */
    302 
    303   int str_chk = 0;		     /* used ot hold the results of a string
    304 				        compare */
    305 
    306   struct minix_inode * raw_inode;    /* inode info for current_ino */
    307 
    308   char linkbuf[PATH_MAX];	     /* buffer for following sym-links */
    309   int link_count = 0;
    310 
    311   char * rest;
    312   char ch;
    313 
    314   int off;			     /* offset within block of directory
    315 					entry */
    316   int loc;			     /* location within a directory */
    317   int blk;			     /* which data blk within dir entry */
    318   long map;			     /* fs pointer of a particular block from
    319 					dir entry */
    320   struct minix_dir_entry * dp;	     /* pointer to directory entry */
    321 
    322   /* loop invariants:
    323      current_ino = inode to lookup
    324      dirname = pointer to filename component we are cur looking up within
    325      the directory known pointed to by current_ino (if any) */
    326 
    327 #ifdef DEBUG_MINIX
    328   printf ("\n");
    329 #endif
    330 
    331   while (1)
    332     {
    333 #ifdef DEBUG_MINIX
    334       printf ("inode %d, dirname %s\n", current_ino, dirname);
    335 #endif
    336 
    337       ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
    338 		 + (current_ino - 1) / MINIX_INODES_PER_BLOCK);
    339       if (! minix_rdfsb (ino_blk, (int) INODE))
    340 	return 0;
    341 
    342       /* reset indirect blocks! */
    343       mapblock2 = mapblock1 = -1;
    344 
    345       raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
    346 
    347       /* copy inode to fixed location */
    348       memmove ((void *) INODE, (void *) raw_inode,
    349 	       sizeof (struct minix_inode));
    350 
    351       /* If we've got a symbolic link, then chase it. */
    352       if (S_ISLNK (INODE->i_mode))
    353 	{
    354 	  int len;
    355 
    356 	  if (++link_count > MAX_LINK_COUNT)
    357 	    {
    358 	      errnum = ERR_SYMLINK_LOOP;
    359 	      return 0;
    360 	    }
    361 #ifdef DEBUG_MINIX
    362 	  printf ("S_ISLNK (%s)\n", dirname);
    363 #endif
    364 
    365 	  /* Find out how long our remaining name is. */
    366 	  len = 0;
    367 	  while (dirname[len] && !isspace (dirname[len]))
    368 	    len++;
    369 
    370 	  /* Get the symlink size. */
    371 	  filemax = (INODE->i_size);
    372 	  if (filemax + len > sizeof (linkbuf) - 2)
    373 	    {
    374 	      errnum = ERR_FILELENGTH;
    375 	      return 0;
    376 	    }
    377 
    378 	  if (len)
    379 	    {
    380 	      /* Copy the remaining name to the end of the symlink data.
    381 	         Note that DIRNAME and LINKBUF may overlap! */
    382 	      memmove (linkbuf + filemax, dirname, len);
    383 	    }
    384 	  linkbuf[filemax + len] = '\0';
    385 
    386 	  /* Read the necessary blocks, and reset the file pointer. */
    387 	  len = grub_read (linkbuf, filemax);
    388 	  filepos = 0;
    389 	  if (!len)
    390 	    return 0;
    391 
    392 #ifdef DEBUG_MINIX
    393 	  printf ("symlink=%s\n", linkbuf);
    394 #endif
    395 
    396 	  dirname = linkbuf;
    397 	  if (*dirname == '/')
    398 	    {
    399 	      /* It's an absolute link, so look it up in root. */
    400 	      current_ino = MINIX_ROOT_INO;
    401 	      updir_ino = current_ino;
    402 	    }
    403 	  else
    404 	    {
    405 	      /* Relative, so look it up in our parent directory. */
    406 	      current_ino = updir_ino;
    407 	    }
    408 
    409 	  /* Try again using the new name. */
    410 	  continue;
    411 	}
    412 
    413       /* If end of filename, INODE points to the file's inode */
    414       if (!*dirname || isspace (*dirname))
    415 	{
    416 	  if (!S_ISREG (INODE->i_mode))
    417 	    {
    418 	      errnum = ERR_BAD_FILETYPE;
    419 	      return 0;
    420 	    }
    421 
    422 	  filemax = (INODE->i_size);
    423 	  return 1;
    424 	}
    425 
    426       /* else we have to traverse a directory */
    427       updir_ino = current_ino;
    428 
    429       /* skip over slashes */
    430       while (*dirname == '/')
    431 	dirname++;
    432 
    433       /* if this isn't a directory of sufficient size to hold our file,
    434 	 abort */
    435       if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
    436 	{
    437 	  errnum = ERR_BAD_FILETYPE;
    438 	  return 0;
    439 	}
    440 
    441       /* skip to next slash or end of filename (space) */
    442       for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
    443 	   rest++);
    444 
    445       /* look through this directory and find the next filename component */
    446       /* invariant: rest points to slash after the next filename component */
    447       *rest = 0;
    448       loc = 0;
    449 
    450       do
    451 	{
    452 #ifdef DEBUG_MINIX
    453 	  printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
    454 #endif
    455 
    456 	  /* if our location/byte offset into the directory exceeds the size,
    457 	     give up */
    458 	  if (loc >= INODE->i_size)
    459 	    {
    460 	      if (print_possibilities < 0)
    461 		{
    462 #if 0
    463 		  putchar ('\n');
    464 #endif
    465 		}
    466 	      else
    467 		{
    468 		  errnum = ERR_FILE_NOT_FOUND;
    469 		  *rest = ch;
    470 		}
    471 	      return (print_possibilities < 0);
    472 	    }
    473 
    474 	  /* else, find the (logical) block component of our location */
    475 	  blk = loc >> BLOCK_SIZE_BITS;
    476 
    477 	  /* we know which logical block of the directory entry we are looking
    478 	     for, now we have to translate that to the physical (fs) block on
    479 	     the disk */
    480 	  map = minix_block_map (blk);
    481 #ifdef DEBUG_MINIX
    482 	  printf ("fs block=%d\n", map);
    483 #endif
    484 	  mapblock2 = -1;
    485 	  if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
    486 	    {
    487 	      errnum = ERR_FSYS_CORRUPT;
    488 	      *rest = ch;
    489 	      return 0;
    490 	    }
    491 	  off = loc & (BLOCK_SIZE - 1);
    492 	  dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
    493 	  /* advance loc prematurely to next on-disk directory entry  */
    494 	  loc += sizeof (dp->inode) + namelen;
    495 
    496 	  /* NOTE: minix filenames are NULL terminated if < NAMELEN
    497 	     else exact */
    498 
    499 #ifdef DEBUG_MINIX
    500 	  printf ("directory entry ino=%d\n", dp->inode);
    501 	  if (dp->inode)
    502 	    printf ("entry=%s\n", dp->name);
    503 #endif
    504 
    505 	  if (dp->inode)
    506 	    {
    507 	      int saved_c = dp->name[namelen];
    508 
    509 	      dp->name[namelen] = 0;
    510 	      str_chk = substring (dirname, dp->name);
    511 
    512 # ifndef STAGE1_5
    513 	      if (print_possibilities && ch != '/'
    514 		  && (!*dirname || str_chk <= 0))
    515 		{
    516 		  if (print_possibilities > 0)
    517 		    print_possibilities = -print_possibilities;
    518 		  print_a_completion (dp->name);
    519 		}
    520 # endif
    521 
    522 	      dp->name[namelen] = saved_c;
    523 	    }
    524 
    525 	}
    526       while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
    527 
    528       current_ino = dp->inode;
    529       *(dirname = rest) = ch;
    530     }
    531   /* never get here */
    532 }
    533 
    534 #endif /* FSYS_MINIX */
    535