Merge branch 'master' of git://github.com/illumos/illumos-gate
[unleashed.git] / usr / src / grub / grub-0.97 / stage2 / disk_io.c
blob1b07c23f7ca44be80b942fb00ccced25c9376c0d
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.
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.
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.
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.
22 #include <shared.h>
23 #include <filesys.h>
24 #include <gpt.h>
26 #ifdef SUPPORT_NETBOOT
27 # include <grub.h>
28 #endif
30 #ifdef GRUB_UTIL
31 # include <device.h>
32 #endif
34 /* instrumentation variables */
35 void (*disk_read_hook) (unsigned long long, int, int) = NULL;
36 void (*disk_read_func) (unsigned long long, int, int) = NULL;
38 #ifndef STAGE1_5
39 int print_possibilities;
41 static int do_completion;
42 static int unique;
43 static char *unique_string;
45 #endif
47 int fsmax;
48 struct fsys_entry fsys_table[NUM_FSYS + 1] =
50 /* TFTP should come first because others don't handle net device. */
51 # ifdef FSYS_TFTP
52 {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},
53 # endif
54 # ifdef FSYS_FAT
55 {"fat", fat_mount, fat_read, fat_dir, 0, 0},
56 # endif
57 # ifdef FSYS_EXT2FS
58 {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
59 # endif
60 # ifdef FSYS_MINIX
61 {"minix", minix_mount, minix_read, minix_dir, 0, 0},
62 # endif
63 # ifdef FSYS_REISERFS
64 {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0, reiserfs_embed},
65 # endif
66 # ifdef FSYS_VSTAFS
67 {"vstafs", vstafs_mount, vstafs_read, vstafs_dir, 0, 0},
68 # endif
69 # ifdef FSYS_JFS
70 {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
71 # endif
72 # ifdef FSYS_XFS
73 {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
74 # endif
75 # ifdef FSYS_UFS
76 {"ufs", ufs_mount, ufs_read, ufs_dir, 0, ufs_embed},
77 # endif
78 # ifdef FSYS_UFS2
79 {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed},
80 # endif
81 # ifdef FSYS_ZFS
82 {"zfs", zfs_mount, zfs_read, zfs_open, 0, zfs_embed},
83 # endif
84 # ifdef FSYS_ISO9660
85 {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
86 # endif
87 /* XX FFS should come last as it's superblock is commonly crossing tracks
88 on floppies from track 1 to 2, while others only use 1. */
89 # ifdef FSYS_FFS
90 {"ffs", ffs_mount, ffs_read, ffs_dir, 0, ffs_embed},
91 # endif
92 {0, 0, 0, 0, 0, 0}
96 /* These have the same format as "boot_drive" and "install_partition", but
97 are meant to be working values. */
98 unsigned long current_drive = GRUB_INVALID_DRIVE;
99 unsigned long current_partition;
101 #ifndef STAGE1_5
102 /* The register ESI should contain the address of the partition to be
103 used for loading a chain-loader when chain-loading the loader. */
104 unsigned long boot_part_addr = 0;
105 #endif
108 * Global variables describing details of the filesystem
111 /* FIXME: BSD evil hack */
112 #include "freebsd.h"
113 int bsd_evil_hack;
115 /* filesystem type */
116 int fsys_type = NUM_FSYS;
117 #ifndef NO_BLOCK_FILES
118 static int block_file = 0;
119 #endif /* NO_BLOCK_FILES */
121 /* these are the translated numbers for the open partition */
122 unsigned long long part_start;
123 unsigned long long part_length;
125 int current_slice;
127 /* ZFS root filesystem for booting */
128 char current_rootpool[MAXNAMELEN];
129 char current_bootfs[MAXNAMELEN];
130 uint64_t current_bootfs_obj;
131 char current_bootpath[MAXPATHLEN];
132 char current_devid[MAXPATHLEN];
133 int is_zfs_mount;
134 unsigned long best_drive;
135 unsigned long best_part;
136 int find_best_root;
138 /* disk buffer parameters */
139 int buf_drive = -1;
140 unsigned long long buf_track;
141 struct geometry buf_geom;
143 /* filesystem common variables */
144 int filepos;
145 int filemax;
147 static inline unsigned long
148 grub_log2 (unsigned long word)
150 asm volatile ("bsfl %1,%0"
151 : "=r" (word)
152 : "r" (word));
153 return word;
155 #define log2 grub_log2
158 rawread(int drive, unsigned long long sector, int byte_offset, int byte_len,
159 char *buf)
161 int slen, sectors_per_vtrack;
162 int sector_size_bits = log2 (buf_geom.sector_size);
164 if (byte_len <= 0)
165 return 1;
167 while (byte_len > 0 && !errnum)
169 int soff, num_sect, size = byte_len;
170 unsigned long long track;
171 char *bufaddr;
174 * Check track buffer. If it isn't valid or it is from the
175 * wrong disk, then reset the disk geometry.
177 if (buf_drive != drive)
179 if (get_diskinfo (drive, &buf_geom))
181 errnum = ERR_NO_DISK;
182 return 0;
184 buf_drive = drive;
185 buf_track = BUF_CACHE_INVALID;
186 sector_size_bits = log2 (buf_geom.sector_size);
189 slen = ((byte_offset + byte_len + buf_geom.sector_size - 1)
190 >> sector_size_bits);
192 /* Eliminate a buffer overflow. */
193 if ((buf_geom.sectors << sector_size_bits) > BUFFERLEN)
194 sectors_per_vtrack = (BUFFERLEN >> sector_size_bits);
195 else
196 sectors_per_vtrack = buf_geom.sectors;
198 /* Get the first sector of track. */
199 soff = sector % sectors_per_vtrack;
200 track = sector - soff;
201 num_sect = sectors_per_vtrack - soff;
202 bufaddr = ((char *) BUFFERADDR
203 + (soff << sector_size_bits) + byte_offset);
205 if (track != buf_track)
207 int bios_err, read_len = sectors_per_vtrack;
208 unsigned long long read_start = track;
211 * If there's more than one read in this entire loop, then
212 * only make the earlier reads for the portion needed. This
213 * saves filling the buffer with data that won't be used!
215 if (slen > num_sect)
217 read_start = sector;
218 read_len = num_sect;
219 bufaddr = (char *) BUFFERADDR + byte_offset;
222 bios_err = biosdisk (BIOSDISK_READ, drive, &buf_geom,
223 read_start, read_len, BUFFERSEG);
224 if (bios_err)
226 buf_track = BUF_CACHE_INVALID;
228 if (bios_err == BIOSDISK_ERROR_GEOMETRY)
229 errnum = ERR_GEOM;
230 else
233 * If there was an error, try to load only the
234 * required sector(s) rather than failing completely.
236 if (slen > num_sect
237 || biosdisk (BIOSDISK_READ, drive, &buf_geom,
238 sector, slen, BUFFERSEG))
239 errnum = ERR_READ;
241 bufaddr = (char *) BUFFERADDR + byte_offset;
244 else
245 buf_track = track;
247 if ((buf_track == 0 || sector == 0)
248 && (PC_SLICE_TYPE (BUFFERADDR, 0) == PC_SLICE_TYPE_EZD
249 || PC_SLICE_TYPE (BUFFERADDR, 1) == PC_SLICE_TYPE_EZD
250 || PC_SLICE_TYPE (BUFFERADDR, 2) == PC_SLICE_TYPE_EZD
251 || PC_SLICE_TYPE (BUFFERADDR, 3) == PC_SLICE_TYPE_EZD))
253 /* This is a EZD disk map sector 0 to sector 1 */
254 if (buf_track == 0 || slen >= 2)
256 /* We already read the sector 1, copy it to sector 0 */
257 memmove ((char *) BUFFERADDR,
258 (char *) BUFFERADDR + buf_geom.sector_size,
259 buf_geom.sector_size);
261 else
263 if (biosdisk (BIOSDISK_READ, drive, &buf_geom,
264 1, 1, BUFFERSEG))
265 errnum = ERR_READ;
270 if (size > ((num_sect << sector_size_bits) - byte_offset))
271 size = (num_sect << sector_size_bits) - byte_offset;
274 * Instrumentation to tell which sectors were read and used.
276 if (disk_read_func)
278 unsigned long long sector_num = sector;
279 int length = buf_geom.sector_size - byte_offset;
280 if (length > size)
281 length = size;
282 (*disk_read_func) (sector_num++, byte_offset, length);
283 length = size - length;
284 if (length > 0)
286 while (length > buf_geom.sector_size)
288 (*disk_read_func) (sector_num++, 0, buf_geom.sector_size);
289 length -= buf_geom.sector_size;
291 (*disk_read_func) (sector_num, 0, length);
295 grub_memmove (buf, bufaddr, size);
297 buf += size;
298 byte_len -= size;
299 sector += num_sect;
300 byte_offset = 0;
303 return (!errnum);
308 devread(unsigned long long sector, int byte_offset, int byte_len, char *buf)
311 * Check partition boundaries
313 if ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS))
314 >= part_length)
316 errnum = ERR_OUTSIDE_PART;
317 return 0;
321 * Get the read to the beginning of a partition.
323 sector += byte_offset >> SECTOR_BITS;
324 byte_offset &= SECTOR_SIZE - 1;
326 #if !defined(STAGE1_5)
327 if (disk_read_hook && debug)
328 printf ("<%llu, %d, %d>", sector, byte_offset, byte_len);
329 #endif /* !STAGE1_5 */
332 * Call RAWREAD, which is very similar, but:
334 * -- It takes an extra parameter, the drive number.
335 * -- It requires that "sector" is relative to the beginning
336 * of the disk.
337 * -- It doesn't handle offsets of more than 511 bytes into the
338 * sector.
340 return rawread (current_drive, part_start + sector, byte_offset,
341 byte_len, buf);
344 #ifndef STAGE1_5
346 rawwrite(int drive, unsigned long long sector, char *buf)
348 if (sector == 0)
350 if (biosdisk (BIOSDISK_READ, drive, &buf_geom, 0, 1, SCRATCHSEG))
352 errnum = ERR_WRITE;
353 return 0;
356 if (PC_SLICE_TYPE (SCRATCHADDR, 0) == PC_SLICE_TYPE_EZD
357 || PC_SLICE_TYPE (SCRATCHADDR, 1) == PC_SLICE_TYPE_EZD
358 || PC_SLICE_TYPE (SCRATCHADDR, 2) == PC_SLICE_TYPE_EZD
359 || PC_SLICE_TYPE (SCRATCHADDR, 3) == PC_SLICE_TYPE_EZD)
360 sector = 1;
363 memmove ((char *) SCRATCHADDR, buf, SECTOR_SIZE);
364 if (biosdisk (BIOSDISK_WRITE, drive, &buf_geom,
365 sector, 1, SCRATCHSEG))
367 errnum = ERR_WRITE;
368 return 0;
371 if (sector - sector % buf_geom.sectors == buf_track)
372 /* Clear the cache. */
373 buf_track = BUF_CACHE_INVALID;
375 return 1;
379 devwrite(unsigned long long sector, int sector_count, char *buf)
381 #if defined(GRUB_UTIL) && defined(__linux__)
382 if (current_partition != 0xFFFFFF
383 && is_disk_device (device_map, current_drive))
385 /* If the grub shell is running under Linux and the user wants to
386 embed a Stage 1.5 into a partition instead of a MBR, use system
387 calls directly instead of biosdisk, because of the bug in
388 Linux. *sigh* */
389 return write_to_partition (device_map, current_drive, current_partition,
390 sector, sector_count, buf);
392 else
393 #endif /* GRUB_UTIL && __linux__ */
395 int i;
397 for (i = 0; i < sector_count; i++)
399 if (! rawwrite (current_drive, part_start + sector + i,
400 buf + (i << SECTOR_BITS)))
401 return 0;
404 return 1;
408 static int
409 sane_partition (void)
411 /* network drive */
412 if (current_drive == NETWORK_DRIVE)
413 return 1;
415 if (!(current_partition & 0xFF000000uL)
416 && ((current_drive & 0xFFFFFF7F) < 8
417 || current_drive == cdrom_drive)
418 && (current_partition & 0xFF) == 0xFF
419 && ((current_partition & 0xFF00) == 0xFF00
420 || (current_partition & 0xFF00) < 0x1000)
421 && ((current_partition >> 16) == 0xFF
422 || (current_drive & 0x80)))
423 return 1;
425 errnum = ERR_DEV_VALUES;
426 return 0;
428 #endif /* ! STAGE1_5 */
430 static void
431 attempt_mount (void)
433 #ifndef STAGE1_5
434 for (fsys_type = 0; fsys_type < NUM_FSYS; fsys_type++)
435 if ((fsys_table[fsys_type].mount_func) ())
436 break;
438 if (fsys_type == NUM_FSYS && errnum == ERR_NONE)
439 errnum = ERR_FSYS_MOUNT;
440 #else
441 fsys_type = 0;
442 if ((*(fsys_table[fsys_type].mount_func)) () != 1)
444 fsys_type = NUM_FSYS;
445 errnum = ERR_FSYS_MOUNT;
447 #endif
451 #ifndef STAGE1_5
452 /* Turn on the active flag for the partition SAVED_PARTITION in the
453 drive SAVED_DRIVE. If an error occurs, return zero, otherwise return
454 non-zero. */
456 make_saved_active (void)
458 char mbr[512];
460 if (saved_drive & 0x80)
462 /* Hard disk */
463 int part = saved_partition >> 16;
465 /* If the partition is not a primary partition, the active flag is
466 meaningless. (XXX: Really?) */
467 if (part > 3)
469 errnum = ERR_DEV_VALUES;
470 return 0;
473 /* Read the MBR in the scratch space. */
474 if (! rawread (saved_drive, 0, 0, SECTOR_SIZE, mbr))
475 return 0;
477 /* If the partition is an extended partition, setting the active
478 flag violates the specification by IBM. */
479 if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (mbr, part)))
481 errnum = ERR_DEV_VALUES;
482 return 0;
485 /* Check if the active flag is disabled. */
486 if (PC_SLICE_FLAG (mbr, part) != PC_SLICE_FLAG_BOOTABLE)
488 int i;
490 /* Clear all the active flags in this table. */
491 for (i = 0; i < 4; i++)
492 PC_SLICE_FLAG (mbr, i) = 0;
494 /* Set the flag. */
495 PC_SLICE_FLAG (mbr, part) = PC_SLICE_FLAG_BOOTABLE;
497 /* Write back the MBR. */
498 if (! rawwrite (saved_drive, 0, mbr))
499 return 0;
502 else
504 /* If the drive is not a hard disk drive, you shouldn't call this
505 function. (XXX: Should I just ignore this error?) */
506 errnum = ERR_DEV_VALUES;
507 return 0;
510 return 1;
513 /* Hide/Unhide CURRENT_PARTITION. */
515 set_partition_hidden_flag (int hidden)
517 unsigned long part = 0xFFFFFF;
518 unsigned long long start, len, offset, ext_offset, gpt_offset;
519 int entry, type, gpt_count, gpt_size;
520 char mbr[512];
522 /* The drive must be a hard disk. */
523 if (! (current_drive & 0x80))
525 errnum = ERR_BAD_ARGUMENT;
526 return 1;
529 /* The partition must be a PC slice. */
530 if ((current_partition >> 16) == 0xFF
531 || (current_partition & 0xFFFF) != 0xFFFF)
533 errnum = ERR_BAD_ARGUMENT;
534 return 1;
537 /* Look for the partition. */
538 while (next_partition (current_drive, 0xFFFFFF, &part, &type,
539 &start, &len, &offset, &entry,
540 &ext_offset, &gpt_offset, &gpt_count, &gpt_size, mbr))
542 /* The partition may not be a GPT partition. */
543 if (gpt_offset != 0)
545 errnum = ERR_BAD_ARGUMENT;
546 return 1;
549 if (part == current_partition)
551 /* Found. */
552 if (hidden)
553 PC_SLICE_TYPE (mbr, entry) |= PC_SLICE_TYPE_HIDDEN_FLAG;
554 else
555 PC_SLICE_TYPE (mbr, entry) &= ~PC_SLICE_TYPE_HIDDEN_FLAG;
557 /* Write back the MBR to the disk. */
558 buf_track = BUF_CACHE_INVALID;
559 if (! rawwrite (current_drive, offset, mbr))
560 return 1;
562 /* Succeed. */
563 return 0;
567 return 1;
571 static void
572 check_and_print_mount (void)
574 attempt_mount ();
575 if (errnum == ERR_FSYS_MOUNT)
576 errnum = ERR_NONE;
577 if (!errnum)
578 print_fsys_type ();
579 print_error ();
581 #endif /* STAGE1_5 */
584 /* Get the information on next partition on the drive DRIVE.
585 The caller must not modify the contents of the arguments when
586 iterating this function. The partition representation in GRUB will
587 be stored in *PARTITION. Likewise, the partition type in *TYPE, the
588 start sector in *START, the length in *LEN, the offset of the
589 partition table in *OFFSET, the entry number in the table in *ENTRY,
590 the offset of the extended partition in *EXT_OFFSET.
591 BUF is used to store a MBR, the boot sector of a partition, or
592 a BSD label sector, and it must be at least 512 bytes length.
593 When calling this function first, *PARTITION must be initialized to
594 0xFFFFFF. The return value is zero if fails, otherwise non-zero. */
596 next_partition (unsigned long drive, unsigned long dest,
597 unsigned long *partition, int *type,
598 unsigned long long *start, unsigned long long *len,
599 unsigned long long *offset, int *entry,
600 unsigned long long *ext_offset,
601 unsigned long long *gpt_offset, int *gpt_count,
602 int *gpt_size, char *buf)
604 /* Forward declarations. */
605 auto int next_bsd_partition (void);
606 auto int next_solaris_partition(void);
607 auto int next_pc_slice (void);
608 auto int next_gpt_slice(void);
610 /* Get next BSD partition in current PC slice. */
611 int next_bsd_partition (void)
613 int i;
614 int bsd_part_no = (*partition & 0xFF00) >> 8;
616 /* If this is the first time... */
617 if (bsd_part_no == 0xFF)
619 /* Check if the BSD label is within current PC slice. */
620 if (*len < BSD_LABEL_SECTOR + 1)
622 errnum = ERR_BAD_PART_TABLE;
623 return 0;
626 /* Read the BSD label. */
627 if (! rawread (drive, *start + BSD_LABEL_SECTOR,
628 0, SECTOR_SIZE, buf))
629 return 0;
631 /* Check if it is valid. */
632 if (! BSD_LABEL_CHECK_MAG (buf))
634 errnum = ERR_BAD_PART_TABLE;
635 return 0;
638 bsd_part_no = -1;
641 /* Search next valid BSD partition. */
642 for (i = bsd_part_no + 1; i < BSD_LABEL_NPARTS (buf); i++)
644 if (BSD_PART_TYPE (buf, i))
646 /* Note that *TYPE and *PARTITION were set
647 for current PC slice. */
648 *type = (BSD_PART_TYPE (buf, i) << 8) | (*type & 0xFF);
649 *start = BSD_PART_START (buf, i);
650 *len = BSD_PART_LENGTH (buf, i);
651 *partition = (*partition & 0xFF00FF) | (i << 8);
653 #ifndef STAGE1_5
654 /* XXX */
655 if ((drive & 0x80) && BSD_LABEL_DTYPE (buf) == DTYPE_SCSI)
656 bsd_evil_hack = 4;
657 #endif /* ! STAGE1_5 */
659 return 1;
663 errnum = ERR_NO_PART;
664 return 0;
667 /* Get next Solaris partition in current PC slice. */
668 int next_solaris_partition (void)
670 static unsigned long pcs_start;
671 int i;
672 int sol_part_no = (*partition & 0xFF00) >> 8;
674 /* If this is the first time... */
675 if (sol_part_no == 0xFF)
677 /* Check if the Solaris label is within current PC slice. */
678 if (*len < SOL_LABEL_LOC + 1)
680 errnum = ERR_BAD_PART_TABLE;
681 return 0;
684 /* Read the Solaris label. */
685 if (! rawread (drive, *start + SOL_LABEL_LOC, 0, SECTOR_SIZE, buf))
686 return 0;
688 /* Check if it is valid. */
689 if (! SOL_LABEL_CHECK_MAG (buf))
691 errnum = ERR_BAD_PART_TABLE;
692 return 0;
695 sol_part_no = -1;
696 pcs_start = *start; /* save the start of pc slice */
699 /* Search next valid Solaris partition. */
700 for (i = sol_part_no + 1; i < SOL_LABEL_NPARTS; i++)
702 if (SOL_PART_EXISTS (buf, i))
704 /* SOL_PART_START is relative to fdisk partition */
705 *start = SOL_PART_START (buf, i) + pcs_start;
706 *len = SOL_PART_LENGTH (buf, i);
707 *partition = (*partition & 0xFF00FF) | (i << 8);
709 return 1;
713 errnum = ERR_NO_PART;
714 return 0;
717 /* Get next PC slice. Be careful of that this function may return
718 an empty PC slice (i.e. a partition whose type is zero) as well. */
719 int next_pc_slice (void)
721 int pc_slice_no = (*partition & 0xFF0000) >> 16;
723 /* If this is the first time... */
724 if (pc_slice_no == 0xFF)
726 *offset = 0;
727 *ext_offset = 0;
728 *entry = -1;
729 pc_slice_no = -1;
732 /* Read the MBR or the boot sector of the extended partition. */
733 if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
734 return 0;
736 /* Check if it is valid. */
737 if (! PC_MBR_CHECK_SIG (buf))
739 errnum = ERR_BAD_PART_TABLE;
740 return 0;
743 /* If this is a GPT partition table, read it as such. */
744 if (*entry == -1 && *offset == 0 && PC_SLICE_TYPE (buf, 0) == PC_SLICE_TYPE_GPT)
746 struct grub_gpt_header *hdr = (struct grub_gpt_header *) buf;
748 /* Read in the GPT Partition table header. */
749 if (! rawread (drive, 1, 0, SECTOR_SIZE, buf))
750 return 0;
752 if (hdr->magic == GPT_HEADER_MAGIC && hdr->version == 0x10000)
754 /* Let gpt_offset point to the first entry in the GPT
755 partition table. This can also be used by callers of
756 next_partition to determine if a entry comes from a
757 GPT partition table or not. */
758 *gpt_offset = hdr->partitions;
759 *gpt_count = hdr->maxpart;
760 *gpt_size = hdr->partentry_size;
762 return next_gpt_slice();
764 else
766 /* This is not a valid header for a GPT partition table.
767 Re-read the MBR or the boot sector of the extended
768 partition. */
769 if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
770 return 0;
774 /* Not a GPT partition. */
775 *gpt_offset = 0;
777 /* Increase the entry number. */
778 (*entry)++;
780 /* If this is out of current partition table... */
781 if (*entry == PC_SLICE_MAX)
783 int i;
785 /* Search the first extended partition in current table. */
786 for (i = 0; i < PC_SLICE_MAX; i++)
788 if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (buf, i)))
790 /* Found. Set the new offset and the entry number,
791 and restart this function. */
792 *offset = *ext_offset + PC_SLICE_START (buf, i);
793 if (! *ext_offset)
794 *ext_offset = *offset;
795 *entry = -1;
796 return next_pc_slice ();
800 errnum = ERR_NO_PART;
801 return 0;
804 *type = PC_SLICE_TYPE (buf, *entry);
805 *start = *offset + PC_SLICE_START (buf, *entry);
806 *len = PC_SLICE_LENGTH (buf, *entry);
808 /* The calculation of a PC slice number is complicated, because of
809 the rather odd definition of extended partitions. Even worse,
810 there is no guarantee that this is consistent with every
811 operating systems. Uggh. */
812 if (pc_slice_no < PC_SLICE_MAX
813 || (! IS_PC_SLICE_TYPE_EXTENDED (*type)
814 && *type != PC_SLICE_TYPE_NONE))
815 pc_slice_no++;
817 *partition = (pc_slice_no << 16) | 0xFFFF;
818 return 1;
821 /* Get the next GPT slice. */
822 int next_gpt_slice (void)
824 struct grub_gpt_partentry *gptentry = (struct grub_gpt_partentry *) buf;
825 /* Make GPT partitions show up as PC slices. */
826 int pc_slice_no = (*partition & 0xFF0000) >> 16;
828 /* If this is the first time... */
829 if (pc_slice_no == 0xFF)
831 pc_slice_no = -1;
832 *entry = -1;
835 do {
836 (*entry)++;
838 if (*entry >= *gpt_count)
840 errnum = ERR_NO_PART;
841 return 0;
843 /* Read in the GPT Partition table entry. */
844 if (! rawread (drive, (*gpt_offset) + GPT_ENTRY_SECTOR (*gpt_size, *entry), GPT_ENTRY_INDEX (*gpt_size, *entry), *gpt_size, buf))
845 return 0;
846 } while (! (gptentry->type1 && gptentry->type2));
848 pc_slice_no++;
849 *start = gptentry->start;
850 *len = gptentry->end - gptentry->start + 1;
851 *type = PC_SLICE_TYPE_EXT2FS;
852 *entry = pc_slice_no;
853 *partition = (*entry << 16) | 0xFFFF;
855 return 1;
858 /* Start the body of this function. */
860 #ifndef STAGE1_5
861 if (current_drive == NETWORK_DRIVE)
862 return 0;
863 #endif
865 /* check for Solaris partition */
866 if (*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_SOLARIS (*type & 0xff))
868 if (next_solaris_partition ())
869 return 1;
870 errnum = ERR_NONE;
873 if (*partition != 0xFFFFFF && *gpt_offset != 0)
874 return next_gpt_slice ();
876 /* If previous partition is a BSD partition or a PC slice which
877 contains BSD partitions... */
878 if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
879 || ! (drive & 0x80))
881 if (*type == PC_SLICE_TYPE_NONE)
882 *type = PC_SLICE_TYPE_FREEBSD;
884 /* Get next BSD partition, if any. */
885 if (next_bsd_partition ())
886 return 1;
888 /* If the destination partition is a BSD partition and current
889 BSD partition has any error, abort the operation. */
890 if ((dest & 0xFF00) != 0xFF00
891 && ((dest & 0xFF0000) == 0xFF0000
892 || (dest & 0xFF0000) == (*partition & 0xFF0000)))
893 return 0;
895 /* Ignore the error. */
896 errnum = ERR_NONE;
899 return next_pc_slice ();
902 #ifndef STAGE1_5
903 static unsigned long cur_part_offset;
904 static unsigned long cur_part_addr;
905 #endif
907 /* Open a partition. */
909 real_open_partition (int flags)
911 unsigned long dest_partition = current_partition;
912 unsigned long long part_offset;
913 unsigned long long ext_offset;
914 unsigned long long gpt_offset;
915 int gpt_count;
916 int gpt_size;
917 int entry;
918 char buf[SECTOR_SIZE];
919 int unix_part, pc_slice;
921 /* For simplicity. */
922 auto int next (void);
923 int next (void)
925 int ret = next_partition (current_drive, dest_partition,
926 &current_partition, &current_slice,
927 &part_start, &part_length,
928 &part_offset, &entry, &ext_offset,
929 &gpt_offset, &gpt_count, &gpt_size, buf);
930 unix_part = (current_partition >> 8) & 0xFF;
931 pc_slice = current_partition >> 16;
932 return ret;
935 #ifndef STAGE1_5
936 /* network drive */
937 if (current_drive == NETWORK_DRIVE)
938 return 1;
940 if (! sane_partition ())
941 return 0;
942 #endif
944 bsd_evil_hack = 0;
945 current_slice = 0;
946 part_start = 0;
948 /* Make sure that buf_geom is valid. */
949 if (buf_drive != current_drive)
951 if (get_diskinfo (current_drive, &buf_geom))
953 errnum = ERR_NO_DISK;
954 return 0;
956 buf_drive = current_drive;
957 buf_track = BUF_CACHE_INVALID;
959 part_length =
960 (buf_geom.total_sectors > MAXUINT) ? MAXUINT : buf_geom.total_sectors;
962 /* If this is the whole disk, return here. */
963 if (! flags && current_partition == 0xFFFFFF)
964 return 1;
966 if (flags)
967 dest_partition = 0xFFFFFF;
969 /* Initialize CURRENT_PARTITION for next_partition. */
970 current_partition = 0xFFFFFF;
972 while (next ())
974 #ifndef STAGE1_5
975 loop_start:
977 cur_part_offset = part_offset;
978 cur_part_addr = BOOT_PART_TABLE + (entry << 4);
979 #endif /* ! STAGE1_5 */
981 /* If this is a valid partition... */
982 if (current_slice)
984 #ifndef STAGE1_5
985 /* Display partition information. */
986 if (flags && ! IS_PC_SLICE_TYPE_EXTENDED (current_slice))
988 if (! do_completion)
990 if (current_drive & 0x80)
991 grub_printf (" Partition num: %d, ",
992 current_partition >> 16);
994 if (! IS_PC_SLICE_TYPE_BSD (current_slice) &&
995 ! IS_PC_SLICE_TYPE_SOLARIS (current_slice))
996 check_and_print_mount ();
997 else
999 int got_part = 0;
1000 int saved_slice = current_slice;
1002 while (next ())
1004 if (unix_part == 0xFF)
1005 break;
1007 if (! got_part)
1009 grub_printf ("[BSD/SOLARIS sub-partitions immediately follow]\n");
1010 got_part = 1;
1013 grub_printf (" BSD/SOLARIS Partition num: \'%c\', ",
1014 unix_part + 'a');
1015 check_and_print_mount ();
1018 if (! got_part)
1019 grub_printf (" No BSD/SOLARIS sub-partition found, partition type 0x%x\n",
1020 saved_slice);
1022 if (errnum)
1024 errnum = ERR_NONE;
1025 break;
1028 goto loop_start;
1031 else
1033 if (unix_part != 0xFF)
1035 char str[16];
1037 if (! (current_drive & 0x80)
1038 || (dest_partition >> 16) == pc_slice)
1039 grub_sprintf (str, "%c)", unix_part + 'a');
1040 else
1041 grub_sprintf (str, "%d,%c)",
1042 pc_slice, unix_part + 'a');
1043 print_a_completion (str);
1045 else if (! IS_PC_SLICE_TYPE_BSD (current_slice) &&
1046 ! IS_PC_SLICE_TYPE_SOLARIS (current_slice))
1048 char str[8];
1050 grub_sprintf (str, "%d)", pc_slice);
1051 print_a_completion (str);
1056 errnum = ERR_NONE;
1057 #endif /* ! STAGE1_5 */
1059 /* Check if this is the destination partition. */
1060 if (! flags
1061 && (dest_partition == current_partition
1062 || ((dest_partition >> 16) == 0xFF
1063 && ((dest_partition >> 8) & 0xFF) == unix_part)))
1064 return 1;
1068 #ifndef STAGE1_5
1069 if (flags)
1071 if (! (current_drive & 0x80))
1073 current_partition = 0xFFFFFF;
1074 check_and_print_mount ();
1077 errnum = ERR_NONE;
1078 return 1;
1080 #endif /* ! STAGE1_5 */
1082 return 0;
1087 open_partition (void)
1089 return real_open_partition (0);
1093 #ifndef STAGE1_5
1094 /* XX used for device completion in 'set_device' and 'print_completions' */
1095 static int incomplete, disk_choice;
1096 static enum
1098 PART_UNSPECIFIED = 0,
1099 PART_DISK,
1100 PART_CHOSEN,
1102 part_choice;
1103 #endif /* ! STAGE1_5 */
1105 char *
1106 set_device (char *device)
1108 #ifdef STAGE1_5
1109 /* In Stage 1.5, the first 4 bytes of FILENAME has a device number. */
1110 unsigned long dev = *((unsigned long *) device);
1111 int drive = (dev >> 24) & 0xFF;
1112 int partition = dev & 0xFFFFFF;
1114 /* If DRIVE is disabled, use SAVED_DRIVE instead. */
1115 if (drive == GRUB_INVALID_DRIVE)
1116 current_drive = saved_drive;
1117 else
1118 current_drive = drive;
1120 /* The `partition' part must always have a valid number. */
1121 current_partition = partition;
1123 return device + sizeof (unsigned long);
1125 #else /* ! STAGE1_5 */
1127 int result = 0;
1129 incomplete = 0;
1130 disk_choice = 1;
1131 part_choice = PART_UNSPECIFIED;
1132 current_drive = saved_drive;
1133 current_partition = 0xFFFFFF;
1135 if (*device == '(' && !*(device + 1))
1136 /* user has given '(' only, let disk_choice handle what disks we have */
1137 return device + 1;
1139 if (*device == '(' && *(++device))
1141 if (*device != ',' && *device != ')')
1143 char ch = *device;
1144 #ifdef SUPPORT_NETBOOT
1145 if (*device == 'f' || *device == 'h'
1146 || (*device == 'n' && network_ready)
1147 || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1148 #else
1149 if (*device == 'f' || *device == 'h'
1150 || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1151 #endif /* SUPPORT_NETBOOT */
1153 /* user has given '([fhn]', check for resp. add 'd' and
1154 let disk_choice handle what disks we have */
1155 if (!*(device + 1))
1157 device++;
1158 *device++ = 'd';
1159 *device = '\0';
1160 return device;
1162 else if (*(device + 1) == 'd' && !*(device + 2))
1163 return device + 2;
1166 if ((*device == 'f'
1167 || *device == 'h'
1168 #ifdef SUPPORT_NETBOOT
1169 || (*device == 'n' && network_ready)
1170 #endif
1171 || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1172 && (device += 2, (*(device - 1) != 'd')))
1173 errnum = ERR_NUMBER_PARSING;
1175 #ifdef SUPPORT_NETBOOT
1176 if (ch == 'n' && network_ready)
1177 current_drive = NETWORK_DRIVE;
1178 else
1179 #endif /* SUPPORT_NETBOOT */
1181 if (ch == 'c' && cdrom_drive != GRUB_INVALID_DRIVE)
1182 current_drive = cdrom_drive;
1183 else
1185 safe_parse_maxint (&device, (int *) &current_drive);
1187 disk_choice = 0;
1188 if (ch == 'h')
1189 current_drive += 0x80;
1194 if (errnum)
1195 return 0;
1197 if (*device == ')')
1199 part_choice = PART_CHOSEN;
1200 result = 1;
1202 else if (*device == ',')
1204 /* Either an absolute PC, BSD, or Solaris partition. */
1205 disk_choice = 0;
1206 part_choice ++;
1207 device++;
1209 if (*device >= '0' && *device <= '9')
1211 part_choice ++;
1212 current_partition = 0;
1214 if (!(current_drive & 0x80)
1215 || !safe_parse_maxint (&device, (int *) &current_partition)
1216 || current_partition > 254)
1218 errnum = ERR_DEV_FORMAT;
1219 return 0;
1222 current_partition = (current_partition << 16) + 0xFFFF;
1224 if (*device == ',')
1225 device++;
1227 if (*device >= 'a' && *device <= 'p')
1229 current_partition = (((*(device++) - 'a') << 8)
1230 | (current_partition & 0xFF00FF));
1233 else if (*device >= 'a' && *device <= 'p')
1235 part_choice ++;
1236 current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF;
1239 if (*device == ')')
1241 if (part_choice == PART_DISK)
1243 current_partition = saved_partition;
1244 part_choice ++;
1247 result = 1;
1252 if (! sane_partition ())
1253 return 0;
1255 if (result)
1256 return device + 1;
1257 else
1259 if (!*device)
1260 incomplete = 1;
1261 errnum = ERR_DEV_FORMAT;
1264 return 0;
1266 #endif /* ! STAGE1_5 */
1270 * This performs a "mount" on the current device, both drive and partition
1271 * number.
1275 open_device (void)
1277 if (open_partition ())
1278 attempt_mount ();
1280 if (errnum != ERR_NONE)
1281 return 0;
1283 return 1;
1287 #ifndef STAGE1_5
1289 set_bootdev (int hdbias)
1291 int i, j;
1293 /* Copy the boot partition information to 0x7be-0x7fd for chain-loading. */
1294 if ((saved_drive & 0x80) && cur_part_addr)
1296 if (rawread (saved_drive, cur_part_offset,
1297 0, SECTOR_SIZE, (char *) SCRATCHADDR))
1299 char *dst, *src;
1301 /* Need only the partition table.
1302 XXX: We cannot use grub_memmove because BOOT_PART_TABLE
1303 (0x07be) is less than 0x1000. */
1304 dst = (char *) BOOT_PART_TABLE;
1305 src = (char *) SCRATCHADDR + BOOTSEC_PART_OFFSET;
1306 while (dst < (char *) BOOT_PART_TABLE + BOOTSEC_PART_LENGTH)
1307 *dst++ = *src++;
1309 /* Set the active flag of the booted partition. */
1310 for (i = 0; i < 4; i++)
1311 PC_SLICE_FLAG (BOOT_PART_TABLE, i) = 0;
1313 *((unsigned char *) cur_part_addr) = PC_SLICE_FLAG_BOOTABLE;
1314 boot_part_addr = cur_part_addr;
1316 else
1317 return 0;
1321 * Set BSD boot device.
1323 i = (saved_partition >> 16) + 2;
1324 if (saved_partition == 0xFFFFFF)
1325 i = 1;
1326 else if ((saved_partition >> 16) == 0xFF)
1327 i = 0;
1329 /* FIXME: extremely evil hack!!! */
1330 j = 2;
1331 if (saved_drive & 0x80)
1332 j = bsd_evil_hack;
1334 return MAKEBOOTDEV (j, (i >> 4), (i & 0xF),
1335 ((saved_drive - hdbias) & 0x7F),
1336 ((saved_partition >> 8) & 0xFF));
1338 #endif /* STAGE1_5 */
1341 static char *
1342 setup_part (char *filename)
1344 #ifdef STAGE1_5
1346 if (! (filename = set_device (filename)))
1348 current_drive = GRUB_INVALID_DRIVE;
1349 return 0;
1352 # ifndef NO_BLOCK_FILES
1353 if (*filename != '/')
1354 open_partition ();
1355 else
1356 # endif /* ! NO_BLOCK_FILES */
1357 open_device ();
1359 #else /* ! STAGE1_5 */
1361 if (*filename == '(')
1363 if ((filename = set_device (filename)) == 0)
1365 current_drive = GRUB_INVALID_DRIVE;
1366 return 0;
1368 # ifndef NO_BLOCK_FILES
1369 if (*filename != '/' && current_drive != NETWORK_DRIVE)
1370 open_partition ();
1371 else
1372 # endif /* ! NO_BLOCK_FILES */
1373 open_device ();
1375 else if (saved_drive != current_drive
1376 || saved_partition != current_partition
1377 || (*filename == '/' && fsys_type == NUM_FSYS)
1378 || buf_drive == -1)
1380 current_drive = saved_drive;
1381 current_partition = saved_partition;
1382 /* allow for the error case of "no filesystem" after the partition
1383 is found. This makes block files work fine on no filesystem */
1384 # ifndef NO_BLOCK_FILES
1385 if (*filename != '/' && current_drive != NETWORK_DRIVE)
1386 open_partition ();
1387 else
1388 # endif /* ! NO_BLOCK_FILES */
1389 open_device ();
1392 #endif /* ! STAGE1_5 */
1394 if (errnum && (*filename == '/' || errnum != ERR_FSYS_MOUNT))
1395 return 0;
1396 else
1397 errnum = 0;
1399 #ifndef STAGE1_5
1400 if (!sane_partition ())
1401 return 0;
1402 #endif
1404 return filename;
1408 #ifndef STAGE1_5
1410 * This prints the filesystem type or gives relevant information.
1413 void
1414 print_fsys_type (void)
1416 if (! do_completion)
1418 grub_printf (" Filesystem type ");
1420 if (fsys_type != NUM_FSYS)
1421 grub_printf ("is %s, ", fsys_table[fsys_type].name);
1422 else
1423 grub_printf ("unknown, ");
1425 if (current_partition == 0xFFFFFF)
1426 grub_printf ("using whole disk\n");
1427 else
1428 grub_printf ("partition type 0x%x\n", current_slice & 0xFF);
1431 #endif /* STAGE1_5 */
1433 #ifndef STAGE1_5
1434 /* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
1435 part into UNIQUE_STRING. */
1436 void
1437 print_a_completion (char *name)
1439 /* If NAME is "." or "..", do not count it. */
1440 if (grub_strcmp (name, ".") == 0 || grub_strcmp (name, "..") == 0)
1441 return;
1443 if (do_completion)
1445 char *buf = unique_string;
1447 if (! unique)
1448 while ((*buf++ = *name++))
1450 else
1452 while (*buf && (*buf == *name))
1454 buf++;
1455 name++;
1457 /* mismatch, strip it. */
1458 *buf = '\0';
1461 else
1462 grub_printf (" %s", name);
1464 unique++;
1468 * This lists the possible completions of a device string, filename, or
1469 * any sane combination of the two.
1473 print_completions (int is_filename, int is_completion)
1475 char *buf = (char *) COMPLETION_BUF;
1476 char *ptr = buf;
1478 unique_string = (char *) UNIQUE_BUF;
1479 *unique_string = 0;
1480 unique = 0;
1481 do_completion = is_completion;
1483 if (! is_filename)
1485 /* Print the completions of builtin commands. */
1486 struct builtin **builtin;
1488 if (! is_completion)
1489 grub_printf (" Possible commands are:");
1491 for (builtin = builtin_table; (*builtin); builtin++)
1493 /* If *BUILTIN cannot be run in the command-line, skip it. */
1494 if (! ((*builtin)->flags & BUILTIN_CMDLINE))
1495 continue;
1497 if (substring (buf, (*builtin)->name) <= 0)
1498 print_a_completion ((*builtin)->name);
1501 if (is_completion && *unique_string)
1503 if (unique == 1)
1505 char *u = unique_string + grub_strlen (unique_string);
1507 *u++ = ' ';
1508 *u = 0;
1511 grub_strcpy (buf, unique_string);
1514 if (! is_completion)
1515 grub_putchar ('\n');
1517 print_error ();
1518 do_completion = 0;
1519 if (errnum)
1520 return -1;
1521 else
1522 return unique - 1;
1525 if (*buf == '/' || (ptr = set_device (buf)) || incomplete)
1527 errnum = 0;
1529 if (*buf == '(' && (incomplete || ! *ptr))
1531 if (! part_choice)
1533 /* disk completions */
1534 int disk_no, i, j;
1535 struct geometry geom;
1537 if (! is_completion)
1538 grub_printf (" Possible disks are: ");
1540 if (!ptr
1541 || *(ptr-1) != 'd'
1542 #ifdef SUPPORT_NETBOOT
1543 || *(ptr-2) != 'n'
1544 #endif /* SUPPORT_NETBOOT */
1545 || *(ptr-2) != 'c')
1547 for (i = (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'h') ? 1:0);
1548 i < (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'f') ? 1:2);
1549 i++)
1551 for (j = 0; j < 8; j++)
1553 disk_no = (i * 0x80) + j;
1554 if ((disk_choice || disk_no == current_drive)
1555 && ! get_diskinfo (disk_no, &geom))
1557 char dev_name[8];
1559 grub_sprintf (dev_name, "%cd%d", i ? 'h':'f', j);
1560 print_a_completion (dev_name);
1566 if (cdrom_drive != GRUB_INVALID_DRIVE
1567 && (disk_choice || cdrom_drive == current_drive)
1568 && (!ptr
1569 || *(ptr-1) == '('
1570 || (*(ptr-1) == 'd' && *(ptr-2) == 'c')))
1571 print_a_completion ("cd");
1573 # ifdef SUPPORT_NETBOOT
1574 if (network_ready
1575 && (disk_choice || NETWORK_DRIVE == current_drive)
1576 && (!ptr
1577 || *(ptr-1) == '('
1578 || (*(ptr-1) == 'd' && *(ptr-2) == 'n')))
1579 print_a_completion ("nd");
1580 # endif /* SUPPORT_NETBOOT */
1582 if (is_completion && *unique_string)
1584 ptr = buf;
1585 while (*ptr != '(')
1586 ptr--;
1587 ptr++;
1588 grub_strcpy (ptr, unique_string);
1589 if (unique == 1)
1591 ptr += grub_strlen (ptr);
1592 if (*unique_string == 'h')
1594 *ptr++ = ',';
1595 *ptr = 0;
1597 else
1599 *ptr++ = ')';
1600 *ptr = 0;
1605 if (! is_completion)
1606 grub_putchar ('\n');
1608 else
1610 /* partition completions */
1611 if (part_choice == PART_CHOSEN
1612 && open_partition ()
1613 && ! IS_PC_SLICE_TYPE_BSD (current_slice))
1615 unique = 1;
1616 ptr = buf + grub_strlen (buf);
1617 if (*(ptr - 1) != ')')
1619 *ptr++ = ')';
1620 *ptr = 0;
1623 else
1625 if (! is_completion)
1626 grub_printf (" Possible partitions are:\n");
1627 real_open_partition (1);
1629 if (is_completion && *unique_string)
1631 ptr = buf;
1632 while (*ptr++ != ',')
1634 grub_strcpy (ptr, unique_string);
1639 else if (ptr && *ptr == '/')
1641 /* filename completions */
1642 if (! is_completion)
1643 grub_printf (" Possible files are:");
1645 dir (buf);
1647 if (is_completion && *unique_string)
1649 ptr += grub_strlen (ptr);
1650 while (*ptr != '/')
1651 ptr--;
1652 ptr++;
1654 grub_strcpy (ptr, unique_string);
1656 if (unique == 1)
1658 ptr += grub_strlen (unique_string);
1660 /* Check if the file UNIQUE_STRING is a directory. */
1661 *ptr = '/';
1662 *(ptr + 1) = 0;
1664 dir (buf);
1666 /* Restore the original unique value. */
1667 unique = 1;
1669 if (errnum)
1671 /* Regular file */
1672 errnum = 0;
1673 *ptr = ' ';
1674 *(ptr + 1) = 0;
1679 if (! is_completion)
1680 grub_putchar ('\n');
1682 else
1683 errnum = ERR_BAD_FILENAME;
1686 print_error ();
1687 do_completion = 0;
1688 if (errnum)
1689 return -1;
1690 else
1691 return unique - 1;
1693 #endif /* STAGE1_5 */
1697 * This is the generic file open function.
1701 grub_open (char *filename)
1703 #ifndef NO_DECOMPRESSION
1704 compressed_file = 0;
1705 #endif /* NO_DECOMPRESSION */
1707 /* if any "dir" function uses/sets filepos, it must
1708 set it to zero before returning if opening a file! */
1709 filepos = 0;
1711 if (!(filename = setup_part (filename)))
1712 return 0;
1714 #ifndef NO_BLOCK_FILES
1715 block_file = 0;
1716 #endif /* NO_BLOCK_FILES */
1718 /* This accounts for partial filesystem implementations. */
1719 fsmax = MAXINT;
1721 if (*filename != '/' && current_drive != NETWORK_DRIVE)
1723 #ifndef NO_BLOCK_FILES
1724 char *ptr = filename;
1725 int tmp, list_addr = BLK_BLKLIST_START;
1726 filemax = 0;
1728 while (list_addr < BLK_MAX_ADDR)
1730 tmp = 0;
1731 safe_parse_maxint (&ptr, &tmp);
1732 errnum = 0;
1734 if (*ptr != '+')
1736 if ((*ptr && *ptr != '/' && !isspace (*ptr))
1737 || tmp == 0 || tmp > filemax)
1738 errnum = ERR_BAD_FILENAME;
1739 else
1740 filemax = tmp;
1742 break;
1745 /* since we use the same filesystem buffer, mark it to
1746 be remounted */
1747 fsys_type = NUM_FSYS;
1749 BLK_BLKSTART (list_addr) = tmp;
1750 ptr++;
1752 if (!safe_parse_maxint (&ptr, &tmp)
1753 || tmp == 0
1754 || (*ptr && *ptr != ',' && *ptr != '/' && !isspace (*ptr)))
1756 errnum = ERR_BAD_FILENAME;
1757 break;
1760 BLK_BLKLENGTH (list_addr) = tmp;
1762 filemax += (tmp * SECTOR_SIZE);
1763 list_addr += BLK_BLKLIST_INC_VAL;
1765 if (*ptr != ',')
1766 break;
1768 ptr++;
1771 if (list_addr < BLK_MAX_ADDR && ptr != filename && !errnum)
1773 block_file = 1;
1774 BLK_CUR_FILEPOS = 0;
1775 BLK_CUR_BLKLIST = BLK_BLKLIST_START;
1776 BLK_CUR_BLKNUM = 0;
1778 #ifndef NO_DECOMPRESSION
1779 return gunzip_test_header ();
1780 #else /* NO_DECOMPRESSION */
1781 return 1;
1782 #endif /* NO_DECOMPRESSION */
1784 #else /* NO_BLOCK_FILES */
1785 errnum = ERR_BAD_FILENAME;
1786 #endif /* NO_BLOCK_FILES */
1789 if (!errnum && fsys_type == NUM_FSYS)
1790 errnum = ERR_FSYS_MOUNT;
1792 # ifndef STAGE1_5
1793 /* set "dir" function to open a file */
1794 print_possibilities = 0;
1795 # endif
1797 if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename))
1799 #ifndef NO_DECOMPRESSION
1800 return gunzip_test_header ();
1801 #else /* NO_DECOMPRESSION */
1802 return 1;
1803 #endif /* NO_DECOMPRESSION */
1806 return 0;
1811 grub_read (char *buf, int len)
1813 /* Make sure "filepos" is a sane value */
1814 if ((filepos < 0) || (filepos > filemax))
1815 filepos = filemax;
1817 /* Make sure "len" is a sane value */
1818 if ((len < 0) || (len > (filemax - filepos)))
1819 len = filemax - filepos;
1821 /* if target file position is past the end of
1822 the supported/configured filesize, then
1823 there is an error */
1824 if (filepos + len > fsmax)
1826 errnum = ERR_FILELENGTH;
1827 return 0;
1830 #ifndef NO_DECOMPRESSION
1831 if (compressed_file)
1832 return gunzip_read (buf, len);
1833 #endif /* NO_DECOMPRESSION */
1835 #ifndef NO_BLOCK_FILES
1836 if (block_file)
1838 int size, off, ret = 0;
1840 while (len && !errnum)
1842 /* we may need to look for the right block in the list(s) */
1843 if (filepos < BLK_CUR_FILEPOS)
1845 BLK_CUR_FILEPOS = 0;
1846 BLK_CUR_BLKLIST = BLK_BLKLIST_START;
1847 BLK_CUR_BLKNUM = 0;
1850 /* run BLK_CUR_FILEPOS up to filepos */
1851 while (filepos > BLK_CUR_FILEPOS)
1853 if ((filepos - (BLK_CUR_FILEPOS & ~(SECTOR_SIZE - 1)))
1854 >= SECTOR_SIZE)
1856 BLK_CUR_FILEPOS += SECTOR_SIZE;
1857 BLK_CUR_BLKNUM++;
1859 if (BLK_CUR_BLKNUM >= BLK_BLKLENGTH (BLK_CUR_BLKLIST))
1861 BLK_CUR_BLKLIST += BLK_BLKLIST_INC_VAL;
1862 BLK_CUR_BLKNUM = 0;
1865 else
1866 BLK_CUR_FILEPOS = filepos;
1869 off = filepos & (SECTOR_SIZE - 1);
1870 size = ((BLK_BLKLENGTH (BLK_CUR_BLKLIST) - BLK_CUR_BLKNUM)
1871 * SECTOR_SIZE) - off;
1872 if (size > len)
1873 size = len;
1875 disk_read_func = disk_read_hook;
1877 /* read current block and put it in the right place in memory */
1878 devread (BLK_BLKSTART (BLK_CUR_BLKLIST) + BLK_CUR_BLKNUM,
1879 off, size, buf);
1881 disk_read_func = NULL;
1883 len -= size;
1884 filepos += size;
1885 ret += size;
1886 buf += size;
1889 if (errnum)
1890 ret = 0;
1892 return ret;
1894 #endif /* NO_BLOCK_FILES */
1896 if (fsys_type == NUM_FSYS)
1898 errnum = ERR_FSYS_MOUNT;
1899 return 0;
1902 return (*(fsys_table[fsys_type].read_func)) (buf, len);
1905 #ifndef STAGE1_5
1906 /* Reposition a file offset. */
1908 grub_seek (int offset)
1910 if (offset > filemax || offset < 0)
1911 return -1;
1913 filepos = offset;
1914 return offset;
1918 dir (char *dirname)
1920 #ifndef NO_DECOMPRESSION
1921 compressed_file = 0;
1922 #endif /* NO_DECOMPRESSION */
1924 if (!(dirname = setup_part (dirname)))
1925 return 0;
1927 if (*dirname != '/')
1928 errnum = ERR_BAD_FILENAME;
1930 if (fsys_type == NUM_FSYS)
1931 errnum = ERR_FSYS_MOUNT;
1933 if (errnum)
1934 return 0;
1936 /* set "dir" function to list completions */
1937 print_possibilities = 1;
1939 return (*(fsys_table[fsys_type].dir_func)) (dirname);
1941 #endif /* STAGE1_5 */
1943 void
1944 grub_close (void)
1946 #ifndef NO_BLOCK_FILES
1947 if (block_file)
1948 return;
1949 #endif /* NO_BLOCK_FILES */
1951 if (fsys_table[fsys_type].close_func != 0)
1952 (*(fsys_table[fsys_type].close_func)) ();