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