xref: /illumos-gate/usr/src/grub/grub-0.97/stage2/disk_io.c (revision 2eef1f2b3c0d57d3f401f917b9f38f01456fd554)
1 /* disk_io.c - implement abstract BIOS disk input and output */
2 /*
3  *  GRUB  --  GRand Unified Bootloader
4  *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 
22 #include <shared.h>
23 #include <filesys.h>
24 
25 #ifdef SUPPORT_NETBOOT
26 # include <grub.h>
27 #endif
28 
29 #ifdef GRUB_UTIL
30 # include <device.h>
31 #endif
32 
33 /* instrumentation variables */
34 void (*disk_read_hook) (unsigned int, int, int) = NULL;
35 void (*disk_read_func) (unsigned int, int, int) = NULL;
36 
37 #ifndef STAGE1_5
38 int print_possibilities;
39 
40 static int do_completion;
41 static int unique;
42 static char *unique_string;
43 
44 #endif
45 
46 int fsmax;
47 struct fsys_entry fsys_table[NUM_FSYS + 1] =
48 {
49   /* TFTP should come first because others don't handle net device.  */
50 # ifdef FSYS_TFTP
51   {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},
52 # endif
53 # ifdef FSYS_FAT
54   {"fat", fat_mount, fat_read, fat_dir, 0, 0},
55 # endif
56 # ifdef FSYS_EXT2FS
57   {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
58 # endif
59 # ifdef FSYS_MINIX
60   {"minix", minix_mount, minix_read, minix_dir, 0, 0},
61 # endif
62 # ifdef FSYS_REISERFS
63   {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0, reiserfs_embed},
64 # endif
65 # ifdef FSYS_VSTAFS
66   {"vstafs", vstafs_mount, vstafs_read, vstafs_dir, 0, 0},
67 # endif
68 # ifdef FSYS_JFS
69   {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
70 # endif
71 # ifdef FSYS_XFS
72   {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
73 # endif
74 # ifdef FSYS_UFS
75   {"ufs", ufs_mount, ufs_read, ufs_dir, 0, ufs_embed},
76 # endif
77 # ifdef FSYS_UFS2
78   {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed},
79 # endif
80 # ifdef FSYS_ZFS
81   {"zfs", zfs_mount, zfs_read, zfs_open, 0, zfs_embed},
82 # endif
83 # ifdef FSYS_ISO9660
84   {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
85 # endif
86   /* XX FFS should come last as it's superblock is commonly crossing tracks
87      on floppies from track 1 to 2, while others only use 1.  */
88 # ifdef FSYS_FFS
89   {"ffs", ffs_mount, ffs_read, ffs_dir, 0, ffs_embed},
90 # endif
91   {0, 0, 0, 0, 0, 0}
92 };
93 
94 
95 /* These have the same format as "boot_drive" and "install_partition", but
96    are meant to be working values. */
97 unsigned long current_drive = GRUB_INVALID_DRIVE;
98 unsigned long current_partition;
99 
100 #ifndef STAGE1_5
101 /* The register ESI should contain the address of the partition to be
102    used for loading a chain-loader when chain-loading the loader.  */
103 unsigned long boot_part_addr = 0;
104 #endif
105 
106 /*
107  *  Global variables describing details of the filesystem
108  */
109 
110 /* FIXME: BSD evil hack */
111 #include "freebsd.h"
112 int bsd_evil_hack;
113 
114 /* filesystem type */
115 int fsys_type = NUM_FSYS;
116 #ifndef NO_BLOCK_FILES
117 static int block_file = 0;
118 #endif /* NO_BLOCK_FILES */
119 
120 /* these are the translated numbers for the open partition */
121 unsigned long part_start;
122 unsigned long part_length;
123 
124 int current_slice;
125 
126 /* ZFS root filesystem for booting */
127 char current_rootpool[MAXNAMELEN];
128 char current_bootfs[MAXNAMELEN];
129 uint64_t current_bootfs_obj;
130 char current_bootpath[MAXPATHLEN];
131 char current_devid[MAXPATHLEN];
132 int is_zfs_mount;
133 unsigned long best_drive;
134 unsigned long best_part;
135 int find_best_root;
136 
137 /* disk buffer parameters */
138 int buf_drive = -1;
139 unsigned int buf_track;
140 struct geometry buf_geom;
141 
142 /* filesystem common variables */
143 int filepos;
144 int filemax;
145 
146 static inline unsigned long
147 grub_log2 (unsigned long word)
148 {
149   asm volatile ("bsfl %1,%0"
150 		: "=r" (word)
151 		: "r" (word));
152   return word;
153 }
154 #define log2 grub_log2
155 
156 int
157 rawread(int drive, unsigned int sector, int byte_offset, int byte_len,
158 	char *buf)
159 {
160   int slen, sectors_per_vtrack;
161   int sector_size_bits = log2 (buf_geom.sector_size);
162 
163   if (byte_len <= 0)
164     return 1;
165 
166   while (byte_len > 0 && !errnum)
167     {
168       int soff, num_sect, size = byte_len;
169       unsigned int track;
170       char *bufaddr;
171 
172       /*
173        *  Check track buffer.  If it isn't valid or it is from the
174        *  wrong disk, then reset the disk geometry.
175        */
176       if (buf_drive != drive)
177 	{
178 	  if (get_diskinfo (drive, &buf_geom))
179 	    {
180 	      errnum = ERR_NO_DISK;
181 	      return 0;
182 	    }
183 	  buf_drive = drive;
184 	  buf_track = BUF_CACHE_INVALID;
185 	  sector_size_bits = log2 (buf_geom.sector_size);
186 	}
187 
188       /* Make sure that SECTOR is valid.  */
189       if (sector >= buf_geom.total_sectors)
190 	{
191 	  errnum = ERR_GEOM;
192 	  return 0;
193 	}
194 
195       slen = ((byte_offset + byte_len + buf_geom.sector_size - 1)
196 	      >> sector_size_bits);
197 
198       /* Eliminate a buffer overflow.  */
199       if ((buf_geom.sectors << sector_size_bits) > BUFFERLEN)
200 	sectors_per_vtrack = (BUFFERLEN >> sector_size_bits);
201       else
202 	sectors_per_vtrack = buf_geom.sectors;
203 
204       /* Get the first sector of track.  */
205       soff = sector % sectors_per_vtrack;
206       track = sector - soff;
207       num_sect = sectors_per_vtrack - soff;
208       bufaddr = ((char *) BUFFERADDR
209 		 + (soff << sector_size_bits) + byte_offset);
210 
211       if (track != buf_track)
212 	{
213 	  int bios_err, read_len = sectors_per_vtrack;
214 	  unsigned int read_start = track;
215 
216 	  /*
217 	   *  If there's more than one read in this entire loop, then
218 	   *  only make the earlier reads for the portion needed.  This
219 	   *  saves filling the buffer with data that won't be used!
220 	   */
221 	  if (slen > num_sect)
222 	    {
223 	      read_start = sector;
224 	      read_len = num_sect;
225 	      bufaddr = (char *) BUFFERADDR + byte_offset;
226 	    }
227 
228 	  bios_err = biosdisk (BIOSDISK_READ, drive, &buf_geom,
229 			       read_start, read_len, BUFFERSEG);
230 	  if (bios_err)
231 	    {
232 	      buf_track = BUF_CACHE_INVALID;
233 
234 	      if (bios_err == BIOSDISK_ERROR_GEOMETRY)
235 		errnum = ERR_GEOM;
236 	      else
237 		{
238 		  /*
239 		   *  If there was an error, try to load only the
240 		   *  required sector(s) rather than failing completely.
241 		   */
242 		  if (slen > num_sect
243 		      || biosdisk (BIOSDISK_READ, drive, &buf_geom,
244 				   sector, slen, BUFFERSEG))
245 		    errnum = ERR_READ;
246 
247 		  bufaddr = (char *) BUFFERADDR + byte_offset;
248 		}
249 	    }
250 	  else
251 	    buf_track = track;
252 
253 	  if ((buf_track == 0 || sector == 0)
254 	      && (PC_SLICE_TYPE (BUFFERADDR, 0) == PC_SLICE_TYPE_EZD
255 		  || PC_SLICE_TYPE (BUFFERADDR, 1) == PC_SLICE_TYPE_EZD
256 		  || PC_SLICE_TYPE (BUFFERADDR, 2) == PC_SLICE_TYPE_EZD
257 		  || PC_SLICE_TYPE (BUFFERADDR, 3) == PC_SLICE_TYPE_EZD))
258 	    {
259 	      /* This is a EZD disk map sector 0 to sector 1 */
260 	      if (buf_track == 0 || slen >= 2)
261 		{
262 		  /* We already read the sector 1, copy it to sector 0 */
263 		  memmove ((char *) BUFFERADDR,
264 			   (char *) BUFFERADDR + buf_geom.sector_size,
265 			   buf_geom.sector_size);
266 		}
267 	      else
268 		{
269 		  if (biosdisk (BIOSDISK_READ, drive, &buf_geom,
270 				1, 1, BUFFERSEG))
271 		    errnum = ERR_READ;
272 		}
273 	    }
274 	}
275 
276       if (size > ((num_sect << sector_size_bits) - byte_offset))
277 	size = (num_sect << sector_size_bits) - byte_offset;
278 
279       /*
280        *  Instrumentation to tell which sectors were read and used.
281        */
282       if (disk_read_func)
283 	{
284 	  unsigned int sector_num = sector;
285 	  int length = buf_geom.sector_size - byte_offset;
286 	  if (length > size)
287 	    length = size;
288 	  (*disk_read_func) (sector_num++, byte_offset, length);
289 	  length = size - length;
290 	  if (length > 0)
291 	    {
292 	      while (length > buf_geom.sector_size)
293 		{
294 		  (*disk_read_func) (sector_num++, 0, buf_geom.sector_size);
295 		  length -= buf_geom.sector_size;
296 		}
297 	      (*disk_read_func) (sector_num, 0, length);
298 	    }
299 	}
300 
301       grub_memmove (buf, bufaddr, size);
302 
303       buf += size;
304       byte_len -= size;
305       sector += num_sect;
306       byte_offset = 0;
307     }
308 
309   return (!errnum);
310 }
311 
312 
313 int
314 devread(unsigned int sector, int byte_offset, int byte_len, char *buf)
315 {
316   /*
317    *  Check partition boundaries
318    */
319   if ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS))
320 	>= part_length)
321     {
322       errnum = ERR_OUTSIDE_PART;
323       return 0;
324     }
325 
326   /*
327    *  Get the read to the beginning of a partition.
328    */
329   sector += byte_offset >> SECTOR_BITS;
330   byte_offset &= SECTOR_SIZE - 1;
331 
332 #if !defined(STAGE1_5)
333   if (disk_read_hook && debug)
334     printf ("<%u, %d, %d>", sector, byte_offset, byte_len);
335 #endif /* !STAGE1_5 */
336 
337   /*
338    *  Call RAWREAD, which is very similar, but:
339    *
340    *    --  It takes an extra parameter, the drive number.
341    *    --  It requires that "sector" is relative to the beginning
342    *            of the disk.
343    *    --  It doesn't handle offsets of more than 511 bytes into the
344    *            sector.
345    */
346   return rawread (current_drive, part_start + sector, byte_offset,
347 		  byte_len, buf);
348 }
349 
350 #ifndef STAGE1_5
351 int
352 rawwrite(int drive, unsigned int sector, char *buf)
353 {
354   if (sector == 0)
355     {
356       if (biosdisk (BIOSDISK_READ, drive, &buf_geom, 0, 1, SCRATCHSEG))
357 	{
358 	  errnum = ERR_WRITE;
359 	  return 0;
360 	}
361 
362       if (PC_SLICE_TYPE (SCRATCHADDR, 0) == PC_SLICE_TYPE_EZD
363 	  || PC_SLICE_TYPE (SCRATCHADDR, 1) == PC_SLICE_TYPE_EZD
364 	  || PC_SLICE_TYPE (SCRATCHADDR, 2) == PC_SLICE_TYPE_EZD
365 	  || PC_SLICE_TYPE (SCRATCHADDR, 3) == PC_SLICE_TYPE_EZD)
366 	sector = 1;
367     }
368 
369   memmove ((char *) SCRATCHADDR, buf, SECTOR_SIZE);
370   if (biosdisk (BIOSDISK_WRITE, drive, &buf_geom,
371 		sector, 1, SCRATCHSEG))
372     {
373       errnum = ERR_WRITE;
374       return 0;
375     }
376 
377   if (sector - sector % buf_geom.sectors == buf_track)
378     /* Clear the cache.  */
379     buf_track = BUF_CACHE_INVALID;
380 
381   return 1;
382 }
383 
384 int
385 devwrite(unsigned int sector, int sector_count, char *buf)
386 {
387 #if defined(GRUB_UTIL) && defined(__linux__)
388   if (current_partition != 0xFFFFFF
389       && is_disk_device (device_map, current_drive))
390     {
391       /* If the grub shell is running under Linux and the user wants to
392 	 embed a Stage 1.5 into a partition instead of a MBR, use system
393 	 calls directly instead of biosdisk, because of the bug in
394 	 Linux. *sigh*  */
395       return write_to_partition (device_map, current_drive, current_partition,
396 				 sector, sector_count, buf);
397     }
398   else
399 #endif /* GRUB_UTIL && __linux__ */
400     {
401       int i;
402 
403       for (i = 0; i < sector_count; i++)
404 	{
405 	  if (! rawwrite (current_drive, part_start + sector + i,
406 			  buf + (i << SECTOR_BITS)))
407 	      return 0;
408 
409 	}
410       return 1;
411     }
412 }
413 
414 static int
415 sane_partition (void)
416 {
417   /* network drive */
418   if (current_drive == NETWORK_DRIVE)
419     return 1;
420 
421   if (!(current_partition & 0xFF000000uL)
422       && ((current_drive & 0xFFFFFF7F) < 8
423 	  || current_drive == cdrom_drive)
424       && (current_partition & 0xFF) == 0xFF
425       && ((current_partition & 0xFF00) == 0xFF00
426 	  || (current_partition & 0xFF00) < 0x1000)
427       && ((current_partition >> 16) == 0xFF
428 	  || (current_drive & 0x80)))
429     return 1;
430 
431   errnum = ERR_DEV_VALUES;
432   return 0;
433 }
434 #endif /* ! STAGE1_5 */
435 
436 static void
437 attempt_mount (void)
438 {
439 #ifndef STAGE1_5
440   for (fsys_type = 0; fsys_type < NUM_FSYS; fsys_type++)
441     if ((fsys_table[fsys_type].mount_func) ())
442       break;
443 
444   if (fsys_type == NUM_FSYS && errnum == ERR_NONE)
445     errnum = ERR_FSYS_MOUNT;
446 #else
447   fsys_type = 0;
448   if ((*(fsys_table[fsys_type].mount_func)) () != 1)
449     {
450       fsys_type = NUM_FSYS;
451       errnum = ERR_FSYS_MOUNT;
452     }
453 #endif
454 }
455 
456 
457 #ifndef STAGE1_5
458 /* Turn on the active flag for the partition SAVED_PARTITION in the
459    drive SAVED_DRIVE. If an error occurs, return zero, otherwise return
460    non-zero.  */
461 int
462 make_saved_active (void)
463 {
464   char mbr[512];
465 
466   if (saved_drive & 0x80)
467     {
468       /* Hard disk */
469       int part = saved_partition >> 16;
470 
471       /* If the partition is not a primary partition, the active flag is
472 	 meaningless. (XXX: Really?)  */
473       if (part > 3)
474 	{
475 	  errnum = ERR_DEV_VALUES;
476 	  return 0;
477 	}
478 
479       /* Read the MBR in the scratch space.  */
480       if (! rawread (saved_drive, 0, 0, SECTOR_SIZE, mbr))
481 	return 0;
482 
483       /* If the partition is an extended partition, setting the active
484 	 flag violates the specification by IBM.  */
485       if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (mbr, part)))
486 	{
487 	  errnum = ERR_DEV_VALUES;
488 	  return 0;
489 	}
490 
491       /* Check if the active flag is disabled.  */
492       if (PC_SLICE_FLAG (mbr, part) != PC_SLICE_FLAG_BOOTABLE)
493 	{
494 	  int i;
495 
496 	  /* Clear all the active flags in this table.  */
497 	  for (i = 0; i < 4; i++)
498 	    PC_SLICE_FLAG (mbr, i) = 0;
499 
500 	  /* Set the flag.  */
501 	  PC_SLICE_FLAG (mbr, part) = PC_SLICE_FLAG_BOOTABLE;
502 
503 	  /* Write back the MBR.  */
504 	  if (! rawwrite (saved_drive, 0, mbr))
505 	    return 0;
506 	}
507     }
508   else
509     {
510       /* If the drive is not a hard disk drive, you shouldn't call this
511 	 function. (XXX: Should I just ignore this error?)  */
512       errnum = ERR_DEV_VALUES;
513       return 0;
514     }
515 
516   return 1;
517 }
518 
519 /* Hide/Unhide CURRENT_PARTITION.  */
520 int
521 set_partition_hidden_flag (int hidden)
522 {
523   unsigned long part = 0xFFFFFF;
524   unsigned long start, len, offset, ext_offset;
525   int entry, type;
526   char mbr[512];
527 
528   /* The drive must be a hard disk.  */
529   if (! (current_drive & 0x80))
530     {
531       errnum = ERR_BAD_ARGUMENT;
532       return 1;
533     }
534 
535   /* The partition must be a PC slice.  */
536   if ((current_partition >> 16) == 0xFF
537       || (current_partition & 0xFFFF) != 0xFFFF)
538     {
539       errnum = ERR_BAD_ARGUMENT;
540       return 1;
541     }
542 
543   /* Look for the partition.  */
544   while (next_partition (current_drive, 0xFFFFFF, &part, &type,
545 			 &start, &len, &offset, &entry,
546 			 &ext_offset, mbr))
547     {
548       if (part == current_partition)
549 	{
550 	  /* Found.  */
551 	  if (hidden)
552 	    PC_SLICE_TYPE (mbr, entry) |= PC_SLICE_TYPE_HIDDEN_FLAG;
553 	  else
554 	    PC_SLICE_TYPE (mbr, entry) &= ~PC_SLICE_TYPE_HIDDEN_FLAG;
555 
556 	  /* Write back the MBR to the disk.  */
557 	  buf_track = BUF_CACHE_INVALID;
558 	  if (! rawwrite (current_drive, offset, mbr))
559 	    return 1;
560 
561 	  /* Succeed.  */
562 	  return 0;
563 	}
564     }
565 
566   return 1;
567 }
568 
569 
570 static void
571 check_and_print_mount (void)
572 {
573   attempt_mount ();
574   if (errnum == ERR_FSYS_MOUNT)
575     errnum = ERR_NONE;
576   if (!errnum)
577     print_fsys_type ();
578   print_error ();
579 }
580 #endif /* STAGE1_5 */
581 
582 
583 /* Get the information on next partition on the drive DRIVE.
584    The caller must not modify the contents of the arguments when
585    iterating this function. The partition representation in GRUB will
586    be stored in *PARTITION. Likewise, the partition type in *TYPE, the
587    start sector in *START, the length in *LEN, the offset of the
588    partition table in *OFFSET, the entry number in the table in *ENTRY,
589    the offset of the extended partition in *EXT_OFFSET.
590    BUF is used to store a MBR, the boot sector of a partition, or
591    a BSD label sector, and it must be at least 512 bytes length.
592    When calling this function first, *PARTITION must be initialized to
593    0xFFFFFF. The return value is zero if fails, otherwise non-zero.  */
594 int
595 next_partition (unsigned long drive, unsigned long dest,
596 		unsigned long *partition, int *type,
597 		unsigned long *start, unsigned long *len,
598 		unsigned long *offset, int *entry,
599 		unsigned long *ext_offset, char *buf)
600 {
601   /* Forward declarations.  */
602   auto int next_bsd_partition (void);
603   auto int next_solaris_partition(void);
604   auto int next_pc_slice (void);
605 
606   /* Get next BSD partition in current PC slice.  */
607   int next_bsd_partition (void)
608     {
609       int i;
610       int bsd_part_no = (*partition & 0xFF00) >> 8;
611 
612       /* If this is the first time...  */
613       if (bsd_part_no == 0xFF)
614 	{
615 	  /* Check if the BSD label is within current PC slice.  */
616 	  if (*len < BSD_LABEL_SECTOR + 1)
617 	    {
618 	      errnum = ERR_BAD_PART_TABLE;
619 	      return 0;
620 	    }
621 
622 	  /* Read the BSD label.  */
623 	  if (! rawread (drive, *start + BSD_LABEL_SECTOR,
624 			 0, SECTOR_SIZE, buf))
625 	    return 0;
626 
627 	  /* Check if it is valid.  */
628 	  if (! BSD_LABEL_CHECK_MAG (buf))
629 	    {
630 	      errnum = ERR_BAD_PART_TABLE;
631 	      return 0;
632 	    }
633 
634 	  bsd_part_no = -1;
635 	}
636 
637       /* Search next valid BSD partition.  */
638       for (i = bsd_part_no + 1; i < BSD_LABEL_NPARTS (buf); i++)
639 	{
640 	  if (BSD_PART_TYPE (buf, i))
641 	    {
642 	      /* Note that *TYPE and *PARTITION were set
643 		 for current PC slice.  */
644 	      *type = (BSD_PART_TYPE (buf, i) << 8) | (*type & 0xFF);
645 	      *start = BSD_PART_START (buf, i);
646 	      *len = BSD_PART_LENGTH (buf, i);
647 	      *partition = (*partition & 0xFF00FF) | (i << 8);
648 
649 #ifndef STAGE1_5
650 	      /* XXX */
651 	      if ((drive & 0x80) && BSD_LABEL_DTYPE (buf) == DTYPE_SCSI)
652 		bsd_evil_hack = 4;
653 #endif /* ! STAGE1_5 */
654 
655 	      return 1;
656 	    }
657 	}
658 
659       errnum = ERR_NO_PART;
660       return 0;
661     }
662 
663   /* Get next Solaris partition in current PC slice.  */
664   int next_solaris_partition (void)
665     {
666       static unsigned long pcs_start;
667       int i;
668       int sol_part_no = (*partition & 0xFF00) >> 8;
669 
670       /* If this is the first time...  */
671       if (sol_part_no == 0xFF)
672 	{
673 	  /* Check if the Solaris label is within current PC slice.  */
674 	  if (*len < SOL_LABEL_LOC + 1)
675 	    {
676 	      errnum = ERR_BAD_PART_TABLE;
677 	      return 0;
678 	    }
679 
680 	  /* Read the Solaris label.  */
681 	  if (! rawread (drive, *start + SOL_LABEL_LOC, 0, SECTOR_SIZE, buf))
682 	    return 0;
683 
684 	  /* Check if it is valid.  */
685 	  if (! SOL_LABEL_CHECK_MAG (buf))
686 	    {
687 	      errnum = ERR_BAD_PART_TABLE;
688 	      return 0;
689 	    }
690 
691 	  sol_part_no = -1;
692 	  pcs_start = *start;	/* save the start of pc slice */
693 	}
694 
695       /* Search next valid Solaris partition.  */
696       for (i = sol_part_no + 1; i < SOL_LABEL_NPARTS; i++)
697 	{
698 	  if (SOL_PART_EXISTS (buf, i))
699 	    {
700 	      /* SOL_PART_START is relative to fdisk partition */
701 	      *start = SOL_PART_START (buf, i) + pcs_start;
702 	      *len = SOL_PART_LENGTH (buf, i);
703 	      *partition = (*partition & 0xFF00FF) | (i << 8);
704 
705 	      return 1;
706 	    }
707 	}
708 
709       errnum = ERR_NO_PART;
710       return 0;
711     }
712 
713   /* Get next PC slice. Be careful of that this function may return
714      an empty PC slice (i.e. a partition whose type is zero) as well.  */
715   int next_pc_slice (void)
716     {
717       int pc_slice_no = (*partition & 0xFF0000) >> 16;
718 
719       /* If this is the first time...  */
720       if (pc_slice_no == 0xFF)
721 	{
722 	  *offset = 0;
723 	  *ext_offset = 0;
724 	  *entry = -1;
725 	  pc_slice_no = -1;
726 	}
727 
728       /* Read the MBR or the boot sector of the extended partition.  */
729       if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
730 	return 0;
731 
732       /* Check if it is valid.  */
733       if (! PC_MBR_CHECK_SIG (buf))
734 	{
735 	  errnum = ERR_BAD_PART_TABLE;
736 	  return 0;
737 	}
738 
739       /* Increase the entry number.  */
740       (*entry)++;
741 
742       /* If this is out of current partition table...  */
743       if (*entry == PC_SLICE_MAX)
744 	{
745 	  int i;
746 
747 	  /* Search the first extended partition in current table.  */
748 	  for (i = 0; i < PC_SLICE_MAX; i++)
749 	    {
750 	      if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (buf, i)))
751 		{
752 		  /* Found. Set the new offset and the entry number,
753 		     and restart this function.  */
754 		  *offset = *ext_offset + PC_SLICE_START (buf, i);
755 		  if (! *ext_offset)
756 		    *ext_offset = *offset;
757 		  *entry = -1;
758 		  return next_pc_slice ();
759 		}
760 	    }
761 
762 	  errnum = ERR_NO_PART;
763 	  return 0;
764 	}
765 
766       *type = PC_SLICE_TYPE (buf, *entry);
767       *start = *offset + PC_SLICE_START (buf, *entry);
768       *len = PC_SLICE_LENGTH (buf, *entry);
769 
770       /* The calculation of a PC slice number is complicated, because of
771 	 the rather odd definition of extended partitions. Even worse,
772 	 there is no guarantee that this is consistent with every
773 	 operating systems. Uggh.  */
774       if (pc_slice_no < PC_SLICE_MAX
775 	  || (! IS_PC_SLICE_TYPE_EXTENDED (*type)
776 	      && *type != PC_SLICE_TYPE_NONE))
777 	pc_slice_no++;
778 
779       *partition = (pc_slice_no << 16) | 0xFFFF;
780       return 1;
781     }
782 
783   /* Start the body of this function.  */
784 
785 #ifndef STAGE1_5
786   if (current_drive == NETWORK_DRIVE)
787     return 0;
788 #endif
789 
790   /* check for Solaris partition */
791   if (*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_SOLARIS (*type & 0xff))
792     {
793       if (next_solaris_partition ())
794 	return 1;
795       errnum = ERR_NONE;
796     }
797 
798   /* If previous partition is a BSD partition or a PC slice which
799      contains BSD partitions...  */
800   if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
801       || ! (drive & 0x80))
802     {
803       if (*type == PC_SLICE_TYPE_NONE)
804 	*type = PC_SLICE_TYPE_FREEBSD;
805 
806       /* Get next BSD partition, if any.  */
807       if (next_bsd_partition ())
808 	return 1;
809 
810       /* If the destination partition is a BSD partition and current
811 	 BSD partition has any error, abort the operation.  */
812       if ((dest & 0xFF00) != 0xFF00
813 	  && ((dest & 0xFF0000) == 0xFF0000
814 	      || (dest & 0xFF0000) == (*partition & 0xFF0000)))
815 	return 0;
816 
817       /* Ignore the error.  */
818       errnum = ERR_NONE;
819     }
820 
821   return next_pc_slice ();
822 }
823 
824 #ifndef STAGE1_5
825 static unsigned long cur_part_offset;
826 static unsigned long cur_part_addr;
827 #endif
828 
829 /* Open a partition.  */
830 int
831 real_open_partition (int flags)
832 {
833   unsigned long dest_partition = current_partition;
834   unsigned long part_offset;
835   unsigned long ext_offset;
836   int entry;
837   char buf[SECTOR_SIZE];
838   int unix_part, pc_slice;
839 
840   /* For simplicity.  */
841   auto int next (void);
842   int next (void)
843     {
844       int ret = next_partition (current_drive, dest_partition,
845 				&current_partition, &current_slice,
846 				&part_start, &part_length,
847 				&part_offset, &entry, &ext_offset, buf);
848       unix_part = (current_partition >> 8) & 0xFF;
849       pc_slice = current_partition >> 16;
850       return ret;
851     }
852 
853 #ifndef STAGE1_5
854   /* network drive */
855   if (current_drive == NETWORK_DRIVE)
856     return 1;
857 
858   if (! sane_partition ())
859     return 0;
860 #endif
861 
862   bsd_evil_hack = 0;
863   current_slice = 0;
864   part_start = 0;
865 
866   /* Make sure that buf_geom is valid. */
867   if (buf_drive != current_drive)
868     {
869       if (get_diskinfo (current_drive, &buf_geom))
870 	{
871 	  errnum = ERR_NO_DISK;
872 	  return 0;
873 	}
874       buf_drive = current_drive;
875       buf_track = BUF_CACHE_INVALID;
876     }
877   part_length = buf_geom.total_sectors;
878 
879   /* If this is the whole disk, return here.  */
880   if (! flags && current_partition == 0xFFFFFF)
881     return 1;
882 
883   if (flags)
884     dest_partition = 0xFFFFFF;
885 
886   /* Initialize CURRENT_PARTITION for next_partition.  */
887   current_partition = 0xFFFFFF;
888 
889   while (next ())
890     {
891 #ifndef STAGE1_5
892     loop_start:
893 
894       cur_part_offset = part_offset;
895       cur_part_addr = BOOT_PART_TABLE + (entry << 4);
896 #endif /* ! STAGE1_5 */
897 
898       /* If this is a valid partition...  */
899       if (current_slice)
900 	{
901 #ifndef STAGE1_5
902 	  /* Display partition information.  */
903 	  if (flags && ! IS_PC_SLICE_TYPE_EXTENDED (current_slice))
904 	    {
905 	      if (! do_completion)
906 		{
907 		  if (current_drive & 0x80)
908 		    grub_printf ("   Partition num: %d, ",
909 				 current_partition >> 16);
910 
911 		  if (! IS_PC_SLICE_TYPE_BSD (current_slice) &&
912 		      ! IS_PC_SLICE_TYPE_SOLARIS (current_slice))
913 		    check_and_print_mount ();
914 		  else
915 		    {
916 		      int got_part = 0;
917 		      int saved_slice = current_slice;
918 
919 		      while (next ())
920 			{
921 			  if (unix_part == 0xFF)
922 			    break;
923 
924 			  if (! got_part)
925 			    {
926 			      grub_printf ("[BSD/SOLARIS sub-partitions immediately follow]\n");
927 			      got_part = 1;
928 			    }
929 
930 			  grub_printf ("     BSD/SOLARIS Partition num: \'%c\', ",
931 				       unix_part + 'a');
932 			  check_and_print_mount ();
933 			}
934 
935 		      if (! got_part)
936 			grub_printf (" No BSD/SOLARIS sub-partition found, partition type 0x%x\n",
937 				     saved_slice);
938 
939 		      if (errnum)
940 			{
941 			  errnum = ERR_NONE;
942 			  break;
943 			}
944 
945 		      goto loop_start;
946 		    }
947 		}
948 	      else
949 		{
950 		  if (unix_part != 0xFF)
951 		    {
952 		      char str[16];
953 
954 		      if (! (current_drive & 0x80)
955 			  || (dest_partition >> 16) == pc_slice)
956 			grub_sprintf (str, "%c)", unix_part + 'a');
957 		      else
958 			grub_sprintf (str, "%d,%c)",
959 				      pc_slice, unix_part + 'a');
960 		      print_a_completion (str);
961 		    }
962 		  else if (! IS_PC_SLICE_TYPE_BSD (current_slice) &&
963 		      ! IS_PC_SLICE_TYPE_SOLARIS (current_slice))
964 		    {
965 		      char str[8];
966 
967 		      grub_sprintf (str, "%d)", pc_slice);
968 		      print_a_completion (str);
969 		    }
970 		}
971 	    }
972 
973 	  errnum = ERR_NONE;
974 #endif /* ! STAGE1_5 */
975 
976 	  /* Check if this is the destination partition.  */
977 	  if (! flags
978 	      && (dest_partition == current_partition
979 		  || ((dest_partition >> 16) == 0xFF
980 		      && ((dest_partition >> 8) & 0xFF) == unix_part)))
981 	    return 1;
982 	}
983     }
984 
985 #ifndef STAGE1_5
986   if (flags)
987     {
988       if (! (current_drive & 0x80))
989 	{
990 	  current_partition = 0xFFFFFF;
991 	  check_and_print_mount ();
992 	}
993 
994       errnum = ERR_NONE;
995       return 1;
996     }
997 #endif /* ! STAGE1_5 */
998 
999   return 0;
1000 }
1001 
1002 
1003 int
1004 open_partition (void)
1005 {
1006   return real_open_partition (0);
1007 }
1008 
1009 
1010 #ifndef STAGE1_5
1011 /* XX used for device completion in 'set_device' and 'print_completions' */
1012 static int incomplete, disk_choice;
1013 static enum
1014 {
1015   PART_UNSPECIFIED = 0,
1016   PART_DISK,
1017   PART_CHOSEN,
1018 }
1019 part_choice;
1020 #endif /* ! STAGE1_5 */
1021 
1022 int
1023 set_bootfs(char *fsname)
1024 {
1025 	grub_memmove(current_bootfs, fsname, MAXNAMELEN);
1026 }
1027 
1028 char *
1029 set_device (char *device)
1030 {
1031 #ifdef STAGE1_5
1032     /* In Stage 1.5, the first 4 bytes of FILENAME has a device number.  */
1033   unsigned long dev = *((unsigned long *) device);
1034   int drive = (dev >> 24) & 0xFF;
1035   int partition = dev & 0xFFFFFF;
1036 
1037   /* If DRIVE is disabled, use SAVED_DRIVE instead.  */
1038   if (drive == GRUB_INVALID_DRIVE)
1039     current_drive = saved_drive;
1040   else
1041     current_drive = drive;
1042 
1043   /* The `partition' part must always have a valid number.  */
1044   current_partition = partition;
1045 
1046   return device + sizeof (unsigned long);
1047 
1048 #else /* ! STAGE1_5 */
1049 
1050   int result = 0;
1051 
1052   incomplete = 0;
1053   disk_choice = 1;
1054   part_choice = PART_UNSPECIFIED;
1055   current_drive = saved_drive;
1056   current_partition = 0xFFFFFF;
1057 
1058   if (*device == '(' && !*(device + 1))
1059     /* user has given '(' only, let disk_choice handle what disks we have */
1060     return device + 1;
1061 
1062   if (*device == '(' && *(++device))
1063     {
1064       if (*device != ',' && *device != ')')
1065 	{
1066 	  char ch = *device;
1067 #ifdef SUPPORT_NETBOOT
1068 	  if (*device == 'f' || *device == 'h'
1069 	      || (*device == 'n' && network_ready)
1070 	      || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1071 #else
1072 	  if (*device == 'f' || *device == 'h'
1073 	      || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1074 #endif /* SUPPORT_NETBOOT */
1075 	    {
1076 	      /* user has given '([fhn]', check for resp. add 'd' and
1077 		 let disk_choice handle what disks we have */
1078 	      if (!*(device + 1))
1079 		{
1080 		  device++;
1081 		  *device++ = 'd';
1082 		  *device = '\0';
1083 		  return device;
1084 		}
1085 	      else if (*(device + 1) == 'd' && !*(device + 2))
1086 		return device + 2;
1087 	    }
1088 
1089 	  if ((*device == 'f'
1090 	       || *device == 'h'
1091 #ifdef SUPPORT_NETBOOT
1092 	       || (*device == 'n' && network_ready)
1093 #endif
1094 	       || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1095 	      && (device += 2, (*(device - 1) != 'd')))
1096 	    errnum = ERR_NUMBER_PARSING;
1097 
1098 #ifdef SUPPORT_NETBOOT
1099 	  if (ch == 'n' && network_ready)
1100 	    current_drive = NETWORK_DRIVE;
1101 	  else
1102 #endif /* SUPPORT_NETBOOT */
1103 	    {
1104 	      if (ch == 'c' && cdrom_drive != GRUB_INVALID_DRIVE)
1105 		current_drive = cdrom_drive;
1106 	      else
1107 		{
1108 		  safe_parse_maxint (&device, (int *) &current_drive);
1109 
1110 		  disk_choice = 0;
1111 		  if (ch == 'h')
1112 		    current_drive += 0x80;
1113 		}
1114 	    }
1115 	}
1116 
1117       if (errnum)
1118 	return 0;
1119 
1120       if (*device == ')')
1121 	{
1122 	  part_choice = PART_CHOSEN;
1123 	  result = 1;
1124 	}
1125       else if (*device == ',')
1126 	{
1127 	  /* Either an absolute PC, BSD, or Solaris partition. */
1128 	  disk_choice = 0;
1129 	  part_choice ++;
1130 	  device++;
1131 
1132 	  if (*device >= '0' && *device <= '9')
1133 	    {
1134 	      part_choice ++;
1135 	      current_partition = 0;
1136 
1137 	      if (!(current_drive & 0x80)
1138 		  || !safe_parse_maxint (&device, (int *) &current_partition)
1139 		  || current_partition > 254)
1140 		{
1141 		  errnum = ERR_DEV_FORMAT;
1142 		  return 0;
1143 		}
1144 
1145 	      current_partition = (current_partition << 16) + 0xFFFF;
1146 
1147 	      if (*device == ',')
1148 		device++;
1149 
1150 	      if (*device >= 'a' && *device <= 'p')
1151 		{
1152 		  current_partition = (((*(device++) - 'a') << 8)
1153 				       | (current_partition & 0xFF00FF));
1154 		}
1155 	    }
1156 	  else if (*device >= 'a' && *device <= 'p')
1157 	    {
1158 	      part_choice ++;
1159 	      current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF;
1160 	    }
1161 
1162 	  if (*device == ')')
1163 	    {
1164 	      if (part_choice == PART_DISK)
1165 		{
1166 		  current_partition = saved_partition;
1167 		  part_choice ++;
1168 		}
1169 
1170 	      result = 1;
1171 	    }
1172 	}
1173     }
1174 
1175   if (! sane_partition ())
1176     return 0;
1177 
1178   if (result)
1179     return device + 1;
1180   else
1181     {
1182       if (!*device)
1183 	incomplete = 1;
1184       errnum = ERR_DEV_FORMAT;
1185     }
1186 
1187   return 0;
1188 
1189 #endif /* ! STAGE1_5 */
1190 }
1191 
1192 /*
1193  *  This performs a "mount" on the current device, both drive and partition
1194  *  number.
1195  */
1196 
1197 int
1198 open_device (void)
1199 {
1200   if (open_partition ())
1201     attempt_mount ();
1202 
1203   if (errnum != ERR_NONE)
1204     return 0;
1205 
1206   return 1;
1207 }
1208 
1209 
1210 #ifndef STAGE1_5
1211 int
1212 set_bootdev (int hdbias)
1213 {
1214   int i, j;
1215 
1216   /* Copy the boot partition information to 0x7be-0x7fd for chain-loading.  */
1217   if ((saved_drive & 0x80) && cur_part_addr)
1218     {
1219       if (rawread (saved_drive, cur_part_offset,
1220 		   0, SECTOR_SIZE, (char *) SCRATCHADDR))
1221 	{
1222 	  char *dst, *src;
1223 
1224 	  /* Need only the partition table.
1225 	     XXX: We cannot use grub_memmove because BOOT_PART_TABLE
1226 	     (0x07be) is less than 0x1000.  */
1227 	  dst = (char *) BOOT_PART_TABLE;
1228 	  src = (char *) SCRATCHADDR + BOOTSEC_PART_OFFSET;
1229 	  while (dst < (char *) BOOT_PART_TABLE + BOOTSEC_PART_LENGTH)
1230 	    *dst++ = *src++;
1231 
1232 	  /* Set the active flag of the booted partition.  */
1233 	  for (i = 0; i < 4; i++)
1234 	    PC_SLICE_FLAG (BOOT_PART_TABLE, i) = 0;
1235 
1236 	  *((unsigned char *) cur_part_addr) = PC_SLICE_FLAG_BOOTABLE;
1237 	  boot_part_addr = cur_part_addr;
1238 	}
1239       else
1240 	return 0;
1241     }
1242 
1243   /*
1244    *  Set BSD boot device.
1245    */
1246   i = (saved_partition >> 16) + 2;
1247   if (saved_partition == 0xFFFFFF)
1248     i = 1;
1249   else if ((saved_partition >> 16) == 0xFF)
1250     i = 0;
1251 
1252   /* FIXME: extremely evil hack!!! */
1253   j = 2;
1254   if (saved_drive & 0x80)
1255     j = bsd_evil_hack;
1256 
1257   return MAKEBOOTDEV (j, (i >> 4), (i & 0xF),
1258 		      ((saved_drive - hdbias) & 0x7F),
1259 		      ((saved_partition >> 8) & 0xFF));
1260 }
1261 #endif /* STAGE1_5 */
1262 
1263 
1264 static char *
1265 setup_part (char *filename)
1266 {
1267 #ifdef STAGE1_5
1268 
1269   if (! (filename = set_device (filename)))
1270     {
1271       current_drive = GRUB_INVALID_DRIVE;
1272       return 0;
1273     }
1274 
1275 # ifndef NO_BLOCK_FILES
1276   if (*filename != '/')
1277     open_partition ();
1278   else
1279 # endif /* ! NO_BLOCK_FILES */
1280     open_device ();
1281 
1282 #else /* ! STAGE1_5 */
1283 
1284   if (*filename == '(')
1285     {
1286       if ((filename = set_device (filename)) == 0)
1287 	{
1288 	  current_drive = GRUB_INVALID_DRIVE;
1289 	  return 0;
1290 	}
1291 # ifndef NO_BLOCK_FILES
1292       if (*filename != '/' && current_drive != NETWORK_DRIVE)
1293 	open_partition ();
1294       else
1295 # endif /* ! NO_BLOCK_FILES */
1296 	open_device ();
1297     }
1298   else if (saved_drive != current_drive
1299 	   || saved_partition != current_partition
1300 	   || (*filename == '/' && fsys_type == NUM_FSYS)
1301 	   || buf_drive == -1)
1302     {
1303       current_drive = saved_drive;
1304       current_partition = saved_partition;
1305       /* allow for the error case of "no filesystem" after the partition
1306          is found.  This makes block files work fine on no filesystem */
1307 # ifndef NO_BLOCK_FILES
1308       if (*filename != '/' && current_drive != NETWORK_DRIVE)
1309 	open_partition ();
1310       else
1311 # endif /* ! NO_BLOCK_FILES */
1312 	open_device ();
1313     }
1314 
1315 #endif /* ! STAGE1_5 */
1316 
1317   if (errnum && (*filename == '/' || errnum != ERR_FSYS_MOUNT))
1318     return 0;
1319   else
1320     errnum = 0;
1321 
1322 #ifndef STAGE1_5
1323   if (!sane_partition ())
1324     return 0;
1325 #endif
1326 
1327   return filename;
1328 }
1329 
1330 
1331 #ifndef STAGE1_5
1332 /*
1333  *  This prints the filesystem type or gives relevant information.
1334  */
1335 
1336 void
1337 print_fsys_type (void)
1338 {
1339   if (! do_completion)
1340     {
1341       grub_printf (" Filesystem type ");
1342 
1343       if (fsys_type != NUM_FSYS)
1344 	grub_printf ("is %s, ", fsys_table[fsys_type].name);
1345       else
1346 	grub_printf ("unknown, ");
1347 
1348       if (current_partition == 0xFFFFFF)
1349 	grub_printf ("using whole disk\n");
1350       else
1351 	grub_printf ("partition type 0x%x\n", current_slice & 0xFF);
1352     }
1353 }
1354 #endif /* STAGE1_5 */
1355 
1356 #ifndef STAGE1_5
1357 /* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
1358    part into UNIQUE_STRING.  */
1359 void
1360 print_a_completion (char *name)
1361 {
1362   /* If NAME is "." or "..", do not count it.  */
1363   if (grub_strcmp (name, ".") == 0 || grub_strcmp (name, "..") == 0)
1364     return;
1365 
1366   if (do_completion)
1367     {
1368       char *buf = unique_string;
1369 
1370       if (! unique)
1371 	while ((*buf++ = *name++))
1372 	  ;
1373       else
1374 	{
1375 	  while (*buf && (*buf == *name))
1376 	    {
1377 	      buf++;
1378 	      name++;
1379 	    }
1380 	  /* mismatch, strip it.  */
1381 	  *buf = '\0';
1382 	}
1383     }
1384   else
1385     grub_printf (" %s", name);
1386 
1387   unique++;
1388 }
1389 
1390 /*
1391  *  This lists the possible completions of a device string, filename, or
1392  *  any sane combination of the two.
1393  */
1394 
1395 int
1396 print_completions (int is_filename, int is_completion)
1397 {
1398   char *buf = (char *) COMPLETION_BUF;
1399   char *ptr = buf;
1400 
1401   unique_string = (char *) UNIQUE_BUF;
1402   *unique_string = 0;
1403   unique = 0;
1404   do_completion = is_completion;
1405 
1406   if (! is_filename)
1407     {
1408       /* Print the completions of builtin commands.  */
1409       struct builtin **builtin;
1410 
1411       if (! is_completion)
1412 	grub_printf (" Possible commands are:");
1413 
1414       for (builtin = builtin_table; (*builtin); builtin++)
1415 	{
1416 	  /* If *BUILTIN cannot be run in the command-line, skip it.  */
1417 	  if (! ((*builtin)->flags & BUILTIN_CMDLINE))
1418 	    continue;
1419 
1420 	  if (substring (buf, (*builtin)->name) <= 0)
1421 	    print_a_completion ((*builtin)->name);
1422 	}
1423 
1424       if (is_completion && *unique_string)
1425 	{
1426 	  if (unique == 1)
1427 	    {
1428 	      char *u = unique_string + grub_strlen (unique_string);
1429 
1430 	      *u++ = ' ';
1431 	      *u = 0;
1432 	    }
1433 
1434 	  grub_strcpy (buf, unique_string);
1435 	}
1436 
1437       if (! is_completion)
1438 	grub_putchar ('\n');
1439 
1440       print_error ();
1441       do_completion = 0;
1442       if (errnum)
1443 	return -1;
1444       else
1445 	return unique - 1;
1446     }
1447 
1448   if (*buf == '/' || (ptr = set_device (buf)) || incomplete)
1449     {
1450       errnum = 0;
1451 
1452       if (*buf == '(' && (incomplete || ! *ptr))
1453 	{
1454 	  if (! part_choice)
1455 	    {
1456 	      /* disk completions */
1457 	      int disk_no, i, j;
1458 	      struct geometry geom;
1459 
1460 	      if (! is_completion)
1461 		grub_printf (" Possible disks are: ");
1462 
1463 	      if (!ptr
1464 		  || *(ptr-1) != 'd'
1465 #ifdef SUPPORT_NETBOOT
1466 		  || *(ptr-2) != 'n'
1467 #endif /* SUPPORT_NETBOOT */
1468 		  || *(ptr-2) != 'c')
1469 		{
1470 		  for (i = (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'h') ? 1:0);
1471 		       i < (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'f') ? 1:2);
1472 		       i++)
1473 		    {
1474 		      for (j = 0; j < 8; j++)
1475 			{
1476 			  disk_no = (i * 0x80) + j;
1477 			  if ((disk_choice || disk_no == current_drive)
1478 			      && ! get_diskinfo (disk_no, &geom))
1479 			    {
1480 			      char dev_name[8];
1481 
1482 			      grub_sprintf (dev_name, "%cd%d", i ? 'h':'f', j);
1483 			      print_a_completion (dev_name);
1484 			    }
1485 			}
1486 		    }
1487 		}
1488 
1489 	      if (cdrom_drive != GRUB_INVALID_DRIVE
1490 		  && (disk_choice || cdrom_drive == current_drive)
1491 		  && (!ptr
1492 		      || *(ptr-1) == '('
1493 		      || (*(ptr-1) == 'd' && *(ptr-2) == 'c')))
1494 		print_a_completion ("cd");
1495 
1496 # ifdef SUPPORT_NETBOOT
1497 	      if (network_ready
1498 		  && (disk_choice || NETWORK_DRIVE == current_drive)
1499 		  && (!ptr
1500 		      || *(ptr-1) == '('
1501 		      || (*(ptr-1) == 'd' && *(ptr-2) == 'n')))
1502 		print_a_completion ("nd");
1503 # endif /* SUPPORT_NETBOOT */
1504 
1505 	      if (is_completion && *unique_string)
1506 		{
1507 		  ptr = buf;
1508 		  while (*ptr != '(')
1509 		    ptr--;
1510 		  ptr++;
1511 		  grub_strcpy (ptr, unique_string);
1512 		  if (unique == 1)
1513 		    {
1514 		      ptr += grub_strlen (ptr);
1515 		      if (*unique_string == 'h')
1516 			{
1517 			  *ptr++ = ',';
1518 			  *ptr = 0;
1519 			}
1520 		      else
1521 			{
1522 			  *ptr++ = ')';
1523 			  *ptr = 0;
1524 			}
1525 		    }
1526 		}
1527 
1528 	      if (! is_completion)
1529 		grub_putchar ('\n');
1530 	    }
1531 	  else
1532 	    {
1533 	      /* partition completions */
1534 	      if (part_choice == PART_CHOSEN
1535 		  && open_partition ()
1536 		  && ! IS_PC_SLICE_TYPE_BSD (current_slice))
1537 		{
1538 		  unique = 1;
1539 		  ptr = buf + grub_strlen (buf);
1540 		  if (*(ptr - 1) != ')')
1541 		    {
1542 		      *ptr++ = ')';
1543 		      *ptr = 0;
1544 		    }
1545 		}
1546 	      else
1547 		{
1548 		  if (! is_completion)
1549 		    grub_printf (" Possible partitions are:\n");
1550 		  real_open_partition (1);
1551 
1552 		  if (is_completion && *unique_string)
1553 		    {
1554 		      ptr = buf;
1555 		      while (*ptr++ != ',')
1556 			;
1557 		      grub_strcpy (ptr, unique_string);
1558 		    }
1559 		}
1560 	    }
1561 	}
1562       else if (ptr && *ptr == '/')
1563 	{
1564 	  /* filename completions */
1565 	  if (! is_completion)
1566 	    grub_printf (" Possible files are:");
1567 
1568 	  dir (buf);
1569 
1570 	  if (is_completion && *unique_string)
1571 	    {
1572 	      ptr += grub_strlen (ptr);
1573 	      while (*ptr != '/')
1574 		ptr--;
1575 	      ptr++;
1576 
1577 	      grub_strcpy (ptr, unique_string);
1578 
1579 	      if (unique == 1)
1580 		{
1581 		  ptr += grub_strlen (unique_string);
1582 
1583 		  /* Check if the file UNIQUE_STRING is a directory.  */
1584 		  *ptr = '/';
1585 		  *(ptr + 1) = 0;
1586 
1587 		  dir (buf);
1588 
1589 		  /* Restore the original unique value.  */
1590 		  unique = 1;
1591 
1592 		  if (errnum)
1593 		    {
1594 		      /* Regular file */
1595 		      errnum = 0;
1596 		      *ptr = ' ';
1597 		      *(ptr + 1) = 0;
1598 		    }
1599 		}
1600 	    }
1601 
1602 	  if (! is_completion)
1603 	    grub_putchar ('\n');
1604 	}
1605       else
1606 	errnum = ERR_BAD_FILENAME;
1607     }
1608 
1609   print_error ();
1610   do_completion = 0;
1611   if (errnum)
1612     return -1;
1613   else
1614     return unique - 1;
1615 }
1616 #endif /* STAGE1_5 */
1617 
1618 
1619 /*
1620  *  This is the generic file open function.
1621  */
1622 
1623 int
1624 grub_open (char *filename)
1625 {
1626 #ifndef NO_DECOMPRESSION
1627   compressed_file = 0;
1628 #endif /* NO_DECOMPRESSION */
1629 
1630   /* if any "dir" function uses/sets filepos, it must
1631      set it to zero before returning if opening a file! */
1632   filepos = 0;
1633 
1634   if (!(filename = setup_part (filename)))
1635     return 0;
1636 
1637 #ifndef NO_BLOCK_FILES
1638   block_file = 0;
1639 #endif /* NO_BLOCK_FILES */
1640 
1641   /* This accounts for partial filesystem implementations. */
1642   fsmax = MAXINT;
1643 
1644   if (*filename != '/' && current_drive != NETWORK_DRIVE)
1645     {
1646 #ifndef NO_BLOCK_FILES
1647       char *ptr = filename;
1648       int tmp, list_addr = BLK_BLKLIST_START;
1649       filemax = 0;
1650 
1651       while (list_addr < BLK_MAX_ADDR)
1652 	{
1653 	  tmp = 0;
1654 	  safe_parse_maxint (&ptr, &tmp);
1655 	  errnum = 0;
1656 
1657 	  if (*ptr != '+')
1658 	    {
1659 	      if ((*ptr && *ptr != '/' && !isspace (*ptr))
1660 		  || tmp == 0 || tmp > filemax)
1661 		errnum = ERR_BAD_FILENAME;
1662 	      else
1663 		filemax = tmp;
1664 
1665 	      break;
1666 	    }
1667 
1668 	  /* since we use the same filesystem buffer, mark it to
1669 	     be remounted */
1670 	  fsys_type = NUM_FSYS;
1671 
1672 	  BLK_BLKSTART (list_addr) = tmp;
1673 	  ptr++;
1674 
1675 	  if (!safe_parse_maxint (&ptr, &tmp)
1676 	      || tmp == 0
1677 	      || (*ptr && *ptr != ',' && *ptr != '/' && !isspace (*ptr)))
1678 	    {
1679 	      errnum = ERR_BAD_FILENAME;
1680 	      break;
1681 	    }
1682 
1683 	  BLK_BLKLENGTH (list_addr) = tmp;
1684 
1685 	  filemax += (tmp * SECTOR_SIZE);
1686 	  list_addr += BLK_BLKLIST_INC_VAL;
1687 
1688 	  if (*ptr != ',')
1689 	    break;
1690 
1691 	  ptr++;
1692 	}
1693 
1694       if (list_addr < BLK_MAX_ADDR && ptr != filename && !errnum)
1695 	{
1696 	  block_file = 1;
1697 	  BLK_CUR_FILEPOS = 0;
1698 	  BLK_CUR_BLKLIST = BLK_BLKLIST_START;
1699 	  BLK_CUR_BLKNUM = 0;
1700 
1701 #ifndef NO_DECOMPRESSION
1702 	  return gunzip_test_header ();
1703 #else /* NO_DECOMPRESSION */
1704 	  return 1;
1705 #endif /* NO_DECOMPRESSION */
1706 	}
1707 #else /* NO_BLOCK_FILES */
1708       errnum = ERR_BAD_FILENAME;
1709 #endif /* NO_BLOCK_FILES */
1710     }
1711 
1712   if (!errnum && fsys_type == NUM_FSYS)
1713     errnum = ERR_FSYS_MOUNT;
1714 
1715 # ifndef STAGE1_5
1716   /* set "dir" function to open a file */
1717   print_possibilities = 0;
1718 # endif
1719 
1720   if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename))
1721     {
1722 #ifndef NO_DECOMPRESSION
1723       return gunzip_test_header ();
1724 #else /* NO_DECOMPRESSION */
1725       return 1;
1726 #endif /* NO_DECOMPRESSION */
1727     }
1728 
1729   return 0;
1730 }
1731 
1732 
1733 int
1734 grub_read (char *buf, int len)
1735 {
1736   /* Make sure "filepos" is a sane value */
1737   if ((filepos < 0) || (filepos > filemax))
1738     filepos = filemax;
1739 
1740   /* Make sure "len" is a sane value */
1741   if ((len < 0) || (len > (filemax - filepos)))
1742     len = filemax - filepos;
1743 
1744   /* if target file position is past the end of
1745      the supported/configured filesize, then
1746      there is an error */
1747   if (filepos + len > fsmax)
1748     {
1749       errnum = ERR_FILELENGTH;
1750       return 0;
1751     }
1752 
1753 #ifndef NO_DECOMPRESSION
1754   if (compressed_file)
1755     return gunzip_read (buf, len);
1756 #endif /* NO_DECOMPRESSION */
1757 
1758 #ifndef NO_BLOCK_FILES
1759   if (block_file)
1760     {
1761       int size, off, ret = 0;
1762 
1763       while (len && !errnum)
1764 	{
1765 	  /* we may need to look for the right block in the list(s) */
1766 	  if (filepos < BLK_CUR_FILEPOS)
1767 	    {
1768 	      BLK_CUR_FILEPOS = 0;
1769 	      BLK_CUR_BLKLIST = BLK_BLKLIST_START;
1770 	      BLK_CUR_BLKNUM = 0;
1771 	    }
1772 
1773 	  /* run BLK_CUR_FILEPOS up to filepos */
1774 	  while (filepos > BLK_CUR_FILEPOS)
1775 	    {
1776 	      if ((filepos - (BLK_CUR_FILEPOS & ~(SECTOR_SIZE - 1)))
1777 		  >= SECTOR_SIZE)
1778 		{
1779 		  BLK_CUR_FILEPOS += SECTOR_SIZE;
1780 		  BLK_CUR_BLKNUM++;
1781 
1782 		  if (BLK_CUR_BLKNUM >= BLK_BLKLENGTH (BLK_CUR_BLKLIST))
1783 		    {
1784 		      BLK_CUR_BLKLIST += BLK_BLKLIST_INC_VAL;
1785 		      BLK_CUR_BLKNUM = 0;
1786 		    }
1787 		}
1788 	      else
1789 		BLK_CUR_FILEPOS = filepos;
1790 	    }
1791 
1792 	  off = filepos & (SECTOR_SIZE - 1);
1793 	  size = ((BLK_BLKLENGTH (BLK_CUR_BLKLIST) - BLK_CUR_BLKNUM)
1794 		  * SECTOR_SIZE) - off;
1795 	  if (size > len)
1796 	    size = len;
1797 
1798 	  disk_read_func = disk_read_hook;
1799 
1800 	  /* read current block and put it in the right place in memory */
1801 	  devread (BLK_BLKSTART (BLK_CUR_BLKLIST) + BLK_CUR_BLKNUM,
1802 		   off, size, buf);
1803 
1804 	  disk_read_func = NULL;
1805 
1806 	  len -= size;
1807 	  filepos += size;
1808 	  ret += size;
1809 	  buf += size;
1810 	}
1811 
1812       if (errnum)
1813 	ret = 0;
1814 
1815       return ret;
1816     }
1817 #endif /* NO_BLOCK_FILES */
1818 
1819   if (fsys_type == NUM_FSYS)
1820     {
1821       errnum = ERR_FSYS_MOUNT;
1822       return 0;
1823     }
1824 
1825   return (*(fsys_table[fsys_type].read_func)) (buf, len);
1826 }
1827 
1828 #ifndef STAGE1_5
1829 /* Reposition a file offset.  */
1830 int
1831 grub_seek (int offset)
1832 {
1833   if (offset > filemax || offset < 0)
1834     return -1;
1835 
1836   filepos = offset;
1837   return offset;
1838 }
1839 
1840 int
1841 dir (char *dirname)
1842 {
1843 #ifndef NO_DECOMPRESSION
1844   compressed_file = 0;
1845 #endif /* NO_DECOMPRESSION */
1846 
1847   if (!(dirname = setup_part (dirname)))
1848     return 0;
1849 
1850   if (*dirname != '/')
1851     errnum = ERR_BAD_FILENAME;
1852 
1853   if (fsys_type == NUM_FSYS)
1854     errnum = ERR_FSYS_MOUNT;
1855 
1856   if (errnum)
1857     return 0;
1858 
1859   /* set "dir" function to list completions */
1860   print_possibilities = 1;
1861 
1862   return (*(fsys_table[fsys_type].dir_func)) (dirname);
1863 }
1864 #endif /* STAGE1_5 */
1865 
1866 void
1867 grub_close (void)
1868 {
1869 #ifndef NO_BLOCK_FILES
1870   if (block_file)
1871     return;
1872 #endif /* NO_BLOCK_FILES */
1873 
1874   if (fsys_table[fsys_type].close_func != 0)
1875     (*(fsys_table[fsys_type].close_func)) ();
1876 }
1877