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