diff --git a/.bzrignore b/.bzrignore index daf9da53a..32b96b154 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,5 +1,6 @@ 00_header 10_* +20_linux_xen 30_os-prober 40_custom 41_custom diff --git a/ChangeLog b/ChangeLog index 0ab95813a..bc6b8fd18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,336 @@ +2010-08-01 Vladimir Serbinenko + + * lib/arg.c (grub_arg_show_help): Add the necessary spacing. + +2010-08-01 Vladimir Serbinenko + + * kern/emu/getroot.c (find_mount_point_from_dir): Compile only if + [HAVE_LIBZFS && HAVE_LIBNVPAIR] + +2010-08-01 Colin Watson + + * util/grub-mkrescue.in: Remove ${efi_dir} after building efi.img. + +2010-08-01 Colin Watson + + * script/yylex.l (NAME): Remove [:digit:], redundant with [:alnum:]. + +2010-08-01 Colin Watson + + * docs/grub.texi (Simple configuration): Document GRUB_CMDLINE_XEN + and GRUB_CMDLINE_XEN_DEFAULT. Recommend setting + GRUB_GFXPAYLOAD_LINUX=text rather than unsetting it in order to + disable gfxpayload. + (Shell-like scripting): Add real content. + (Serial terminal): Suggest `terminal_input serial; terminal_output + serial' rather than putting the two commands on separate lines, + since console input will be inoperative after the first command. + (menuentry): Document --class, --users, and --hotkey options. + (terminfo): Describe what `visually-ordered UTF-8' means (thanks, + Vladimir Serbinenko). + +2010-08-01 Vladimir Serbinenko +2010-08-01 Colin Watson + + * kern/misc.c (grub_memset): Optimise to reduce cache stalls. + +2010-08-01 Robert Millan + + Prevent accidental use of uninitialized libzfs_handle. + + * util/grub-probe.c (main): Move grub_util_init_libzfs() call to ... + * kern/emu/getroot.c (find_root_device_from_libzfs): ... here. + * util/misc.c (grub_util_init_libzfs): Make this function idempotent. + +2010-08-01 Colin Watson + + * util/grub.d/20_linux_xen.in: Don't use UUID for LVM root (matching + util/grub.d/10_linux.in). Fixes Debian bug #591093. + +2010-08-01 Robert Millan + + * kern/emu/getroot.c: Include `'. + +2010-07-31 Robert Millan + + * util/grub.d/10_kfreebsd.in: Make module handling more generic. + +2010-07-31 Robert Millan + + * kern/emu/misc.c: Add missing license header. + +2010-07-31 Robert Millan + + * configure.ac: Check for `libzfs.h' and `libnvpair.h'. + + * include/grub/util/libnvpair.h: Include `'. + [HAVE_LIBNVPAIR_H]: Include `' instead of + declaring libnvpair prototypes ourselves. + * include/grub/util/libzfs.h: Include `'. + [HAVE_LIBZFS_H]: Include `' instead of + declaring libzfs prototypes ourselves. + + (libzfs_handle): Moved to ... + * include/grub/util/misc.h (libzfs_handle): ... here. + Include `'. + +2010-07-30 Robert Millan + + * include/grub/emu/misc.h: Add missing license header. + +2010-07-30 Robert Millan + + Enable `grub-probe -t device' resolution on ZFS. + + * configure.ac: Check for getfsstat(), libzfs and libnvpair. + * include/grub/util/libnvpair.h: New file. + * include/grub/util/libzfs.h: New file. + + * kern/emu/getroot.c: Include `' and `'. + [HAVE_LIBZFS && HAVE_LIBNVPAIR]: Include `' and + `'. + [HAVE_GETFSSTAT]: Include `'. + + (find_mount_point_from_dir): New static function. + [HAVE_LIBZFS && HAVE_LIBNVPAIR] (find_root_device_from_libzfs): New + function. + [HAVE_LIBZFS && HAVE_LIBNVPAIR] (grub_guess_root_device): Use + find_root_device_from_libzfs() before ressorting to find_root_device(). + + * include/grub/util/misc.h (grub_util_init_libzfs): New function + prototype. + * util/misc.c: Include `'. + (grub_util_init_libzfs): New function. + [HAVE_LIBZFS] (libzfs_handle): New global variable. + [HAVE_LIBZFS] (fini_libzfs): New static function. + (grub_util_init_libzfs): New function. + * util/grub-probe.c (main): Call grub_util_init_libzfs(). + +2010-07-30 Robert Millan + + * include/grub/emu/misc.h (grub_make_system_path_relative_to_its_root) + (xmalloc, xrealloc, xstrdup, xasprintf): Add + `warn_unused_result' attribute. + * include/grub/misc.h (grub_strdup, grub_strndup, grub_strlen) + (grub_xasprintf, grub_xvasprintf): Likewise. + * include/grub/emu/misc.h (xasprintf): Remove duplicate prototype. + +2010-07-29 Robert Millan + + * util/grub-probe.c (PRINT_FS_LABEL): New enum value. + (probe): Handle `PRINT_FS_LABEL'. + (main): Handle `-t fs_label'. + +2010-07-29 Robert Millan + + * configure.ac: Remove grub-mkisofs checks. + +2010-07-28 Vladimir Serbinenko + + * util/ieee1275/grub-install.in: Don't use empty grub_device. + Reported by: Lennart Sorensen. + +2010-07-20 Vladimir Serbinenko + + * util/grub.d/00_header.in: Remove compatibility with terminal.mod + prior to terminal_input/terminal_output separation. It's been over 1.5 + years and those versions weren't widely deployed. + +2010-07-22 Colin Watson + + * disk/raid.c (insert_array): Don't count named arrays when looking + for unused array numbers. + Reported and tested by: Michael Guntsche. + +2010-07-20 Colin Watson + + * bus/usb/emu/usb.c (grub_usb_poll_devices): Add a dummy + implementation of this so that grub-emu links again, with a note + that this should support hotplugging in the future. + +2010-07-20 Colin Watson + + * kern/emu/getroot.c (grub_util_get_grub_dev): Use xasprintf. + +2010-07-20 Colin Watson + + * disk/loopback.c (grub_cmd_loopback): Don't leak a grub_file_t + handle on failure. + (grub_loopback_close): Remove empty function. + (grub_loopback_dev): Remove close method. + +2010-07-20 Colin Watson + + Disable EFI cursor when the EFI console becomes inactive. + + * term/efi/console.c (grub_efi_console_init): New function. + (grub_efi_console_fini): New function. + (grub_console_term_output): Register init and fini methods. + +2010-07-20 Vladimir Serbinenko + + * tests/util/grub-shell-tester.in: Remove bashism and declare as + sh script. + +2010-07-20 Vladimir Serbinenko + + * disk/loopback.c (grub_loopback): Replace filename with file. + (delete_loopback): Handle new semantics. + (grub_cmd_loopback): Likewise. + (grub_loopback_iterate): Likewise. + (grub_loopback_close): Likewise. + +2010-07-20 Vladimir Serbinenko + + * util/i386/efi/grub-install.in: Revert to platform-specific behaviour + with -p "". + Reported by: Tito Keitel. + +2010-07-20 Vladimir Serbinenko + + * docs/grub.texi (Naming convention): Document new naming convention. + +2010-07-20 Vadim Solomin +2010-07-20 Colin Watson + + Generate device.map in something closer to the old ordering. + + * util/deviceiter.c (struct device): New declaration. + (compare_file_names): Rename to ... + (compare_devices): ... this. Sort by kernel name in preference to + the stable by-id name, but keep the latter as a fallback comparison. + Update header comment. + (grub_util_iterate_devices) [__linux__]: Construct and sort an array + of `struct device' rather than of plain file names. + +2010-07-20 Thomas Frauendorfer + + * lib/i386/relocator_asm.S [! __x86_64__]: Don't try to disable amd64 + on i386. + +2010-07-20 Vladimir Serbinenko + + * commands/acpi.c (setup_common_tables): Use sizeof instead of + hardcoding size. + (setv1table): Likewise. + +2010-07-20 Colin Watson + + * disk/raid.c (insert_array): Use md/%s to name mdadm 1.x devices, + removing the homehost if present. + * kern/emu/getroot.c (get_mdadm_name) [__linux__]: New function. + (grub_util_get_grub_dev): Use md/%s to name mdadm 1.x devices, + removing the homehost if present. + (grub_util_get_grub_dev) [__linux__]: Get the array name from mdadm + if possible. + * util/i386/pc/grub-setup.c (main): Handle md/* devices. + + * disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Add start_sector + parameter. Set its pointer target to 0. + * disk/mdraid_linux.c (grub_mdraid_detect): Add start_sector + parameter. Set its pointer target to 0 for 0.9 metadata, or to the + `data_offset' value from the superblock for 1.x metadata. + * disk/raid.c (grub_raid_read): Offset reads by the start sector of + data on the device. + (insert_array): Record the start sector of data on the device. + (grub_raid_register): Pass start_sector parameters to + grub_raid_list->detect and insert_array. + * include/grub/raid.h (struct grub_raid_array): Add start_sector + member. + (struct grub_raid): Add start_sector parameter to `detect'. + + * disk/mdraid_linux.c (struct grub_raid_super_1x): Remove + __attribute__ ((packed)), leaving a comment. + (grub_mdraid_detect): Split out 0.9 and 1.x detection to ... + (grub_mdraid_detect_09): ... here and ... + (grub_mdraid_detect_1x): ... here. + +2010-07-20 Peter Henn + + * disk/mdraid_linux.c (grub_mdraid_detect): Fix calculation of 1.x + chunk size and disk size, which are already given as sector counts + as distinct from the 0.90 units. Fetch the correct device number + from the role table instead of using the table index. + +2010-07-20 Felix Zielcke + + * disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Set array->name to NULL. + * disk/mdraid_linux.c (grub_raid_super_1x): New structure. + (WriteMostly1): New macro. + Set array->name to NULL for metadata format 0.90. Add support for + metadata 1.x. Fix some comments. + * disk/raid.c (): Add support for name based RAID arrays. Fix a + few comments. + * util/getroot.c (grub_util_get_grub_dev): Add support for + /dev/md/name style devices. + +2010-07-20 Colin Watson + + * .bzrignore: Ignore 20_linux_xen. + +2010-07-17 Colin Watson + + * util/import_unicode.py: Remove unnecessary imports. + +2010-07-17 Aleš Nesrsta + + Hotplugging and USB hub support. + + * bus/usb/ohci.c (grub_ohci_td): Add convenience fields. + (grub_ohci): Likewise. + (GRUB_OHCI_REG_CONTROL_BULK_ENABLE): New definition. + (GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE): Likewise. + (GRUB_OHCI_RESET_CONNECT_CHANGE): Likewise. + (GRUB_OHCI_CTRL_EDS): Likewise. + (GRUB_OHCI_BULK_EDS): Likewise. + (GRUB_OHCI_TDS): Likewise. + (GRUB_OHCI_ED_ADDR_MASK): Likewise. + (grub_ohci_ed_phys2virt): New function. + (grub_ohci_virt_to_phys): Likewise. + (grub_ohci_td_phys2virt): Likewise. + (grub_ohci_td_virt2phys): Likewise. + (grub_ohci_pci_iter): Allocate memory and don't wait for stable + attachment. + (grub_ohci_find_ed): New function. + (grub_ohci_alloc_td): Likewise. + (grub_ohci_free_td): Likewise. + (grub_ohci_free_tds): Likewise. + (grub_ohci_transfer): Use previously allocated memory. + (grub_ohci_portstatus): Reset status changed bit. + (grub_ohci_detect_dev): Supply status changed. + (grub_ohci_fini_hw): Free memory. + (grub_ohci_restore_hw): Reallocate memory. + * bus/usb/uhci.c (grub_uhci_portstatus): Don't reset on disable. + Reset status change. + (grub_uhci_detect_dev): Supply status_change. + * bus/usb/usb.c (attach_hooks): New var. + (grub_usb_device_attach): New function. + (grub_usb_register_attach_hook_class): Likewise. + (grub_usb_unregister_attach_hook_class): Likewise. + * bus/usb/usbhub.c (grub_usb_hub_add_dev): Handle errors correctly. + (grub_usb_add_hub): Reset connection changed bit. + (attach_root_port): New function. + (grub_usb_root_hub): Likewise. + (poll_nonroot_hub): Likewise. + (grub_usb_poll_devices): Likewise. + * commands/usbtest.c (grub_cmd_usbtest): Poll devices before listing. + * disk/usbms.c (grub_usbms_open): Use device hooks. + (grub_usbms_iterate) :Poll devices. + (grub_usbms_finddevs): Split into ... + (grub_usbms_attach): ... this ... + (grub_usbms_attach): ... and this. + * include/grub/usb.h (grub_usb_controller_dev): Supply status_changed + in detect_dev. + (grub_usb_interface): New fields attached and detach_hook. + (grub_usb_attach_hook_class): New type. + (grub_usb_attach_desc): New struct. + (grub_usb_register_attach_hook_class): New function. + (grub_usb_unregister_attach_hook_class): Likewise. + (grub_usb_poll_devices): Likewise. + (grub_usb_device_attach): Likewise. + * include/grub/usbtrans.h (GRUB_USB_HUB_FEATURE_C_CONNECTED): New const. + (GRUB_USB_HUB_STATUS_C_CONNECTED): Likewise. + 2010-07-17 Vladimir Serbinenko * include/grub/bsdlabel.h (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION): New definition. diff --git a/boot/mips/yeeloong/fwstart.S b/boot/mips/yeeloong/fwstart.S index 7fe5d7ac2..425458401 100644 --- a/boot/mips/yeeloong/fwstart.S +++ b/boot/mips/yeeloong/fwstart.S @@ -20,7 +20,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/bus/usb/emu/usb.c b/bus/usb/emu/usb.c index 187857b5b..7d52decb2 100644 --- a/bus/usb/emu/usb.c +++ b/bus/usb/emu/usb.c @@ -78,6 +78,12 @@ grub_libusb_devices (void) return GRUB_USB_ERR_NONE; } +void +grub_usb_poll_devices (void) +{ + /* TODO: recheck grub_usb_devs */ +} + int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c index d8abb343a..aa96ed5e6 100644 --- a/bus/usb/ohci.c +++ b/bus/usb/ohci.c @@ -459,7 +459,7 @@ grub_ohci_pci_iter (grub_pci_device_t dev, grub_dma_free (o->hcca_chunk); grub_free (o); - return 1; + return 0; } diff --git a/commands/acpi.c b/commands/acpi.c index 5bbfd008b..884ddf000 100644 --- a/commands/acpi.c +++ b/commands/acpi.c @@ -325,7 +325,8 @@ setup_common_tables (void) /* If it's FADT correct DSDT and FACS addresses. */ fadt = (struct grub_acpi_fadt *) cur->addr; - if (grub_memcmp (fadt->hdr.signature, "FACP", 4) == 0) + if (grub_memcmp (fadt->hdr.signature, "FACP", + sizeof (fadt->hdr.signature)) == 0) { fadt->dsdt_addr = PTR_TO_UINT32 (table_dsdt); fadt->facs_addr = facs_addr; @@ -351,16 +352,16 @@ setup_common_tables (void) rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr; playground_ptr += sizeof (struct grub_acpi_table_header) + 4 * numoftables; - rsdt_entry = (grub_uint32_t *)(rsdt + 1); + rsdt_entry = (grub_uint32_t *) (rsdt + 1); /* Fill RSDT header. */ grub_memcpy (&(rsdt->signature), "RSDT", 4); rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables; rsdt->revision = 1; - grub_memcpy (&(rsdt->oemid), root_oemid, 6); - grub_memcpy (&(rsdt->oemtable), root_oemtable, 4); + grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid)); + grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable)); rsdt->oemrev = root_oemrev; - grub_memcpy (&(rsdt->creator_id), root_creator_id, 6); + grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id)); rsdt->creator_rev = root_creator_rev; for (cur = acpi_tables; cur; cur = cur->next) @@ -378,7 +379,8 @@ setv1table (void) /* Create RSDP. */ rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr; playground_ptr += sizeof (struct grub_acpi_rsdp_v10); - grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", 8); + grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", + sizeof (rsdpv1_new->signature)); grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid)); rsdpv1_new->revision = 0; rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (rsdt_addr); diff --git a/conf/mips-yeeloong.rmk b/conf/mips-yeeloong.rmk index deb6dd33f..365ca1ca5 100644 --- a/conf/mips-yeeloong.rmk +++ b/conf/mips-yeeloong.rmk @@ -27,7 +27,7 @@ kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ video/fb/fbfill.c video/fb/fbutil.c video/bitmap.c \ video/bitmap_scale.c video/sm712.c bus/pci.c bus/bonito.c \ term/gfxterm.c commands/extcmd.c lib/arg.c \ - bus/cs5536.c term/serial.c term/terminfo.c term/tparm.c \ + bus/cs5536.c term/serial.c term/ns8250.c term/terminfo.c term/tparm.c \ symlist.c kernel_img_CFLAGS = $(COMMON_CFLAGS) -DUSE_ASCII_FAILBACK kernel_img_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/configure.ac b/configure.ac index 55c2625cb..6169a2fb5 100644 --- a/configure.ac +++ b/configure.ac @@ -246,15 +246,9 @@ else AC_PATH_PROG(HELP2MAN, help2man) fi -# Check for functions. -AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf) - -# For grub-mkisofs -AC_HEADER_MAJOR -AC_HEADER_DIRENT -AC_CHECK_FUNCS(memmove sbrk strdup lstat getuid getgid) -AC_CHECK_HEADERS(sys/mkdev.h sys/sysmacros.h malloc.h termios.h sys/types.h) -AC_CHECK_HEADERS(unistd.h string.h strings.h sys/stat.h sys/fcntl.h limits.h) +# Check for functions and headers. +AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf getfsstat) +AC_CHECK_HEADERS(libzfs.h libnvpair.h) # For opendisk() and getrawpartition() on NetBSD. # Used in util/deviceiter.c and in util/hostdisk.c. @@ -806,6 +800,15 @@ if test x"$device_mapper_excuse" = x ; then [device_mapper_excuse="need devmapper library"]) fi +AC_CHECK_LIB([zfs], [libzfs_init], + [LDFLAGS="$LDFLAGS -lzfs" + AC_DEFINE([HAVE_LIBZFS], [1], + [Define to 1 if you have the ZFS library.])],) +AC_CHECK_LIB([nvpair], [nvlist_print], + [LDFLAGS="$LDFLAGS -lnvpair" + AC_DEFINE([HAVE_LIBNVPAIR], [1], + [Define to 1 if you have the NVPAIR library.])],) + AC_SUBST(ASFLAGS) # Output files. diff --git a/disk/dmraid_nvidia.c b/disk/dmraid_nvidia.c index c4e3922cf..d3f45935c 100644 --- a/disk/dmraid_nvidia.c +++ b/disk/dmraid_nvidia.c @@ -89,7 +89,8 @@ struct grub_nv_super } __attribute__ ((packed)); static grub_err_t -grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) +grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector) { grub_disk_addr_t sector; struct grub_nv_super sb; @@ -132,6 +133,7 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) "unsupported RAID level: %d", sb.array.raid_level); } + array->name = NULL; array->number = 0; array->total_devs = sb.array.total_volumes; array->chunk_size = sb.array.stripe_block_size; @@ -144,6 +146,8 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) grub_memcpy (array->uuid, (char *) &sb.array.signature, sizeof (sb.array.signature)); + *start_sector = 0; + return 0; } diff --git a/disk/loopback.c b/disk/loopback.c index 1b525e05f..509e9e33f 100644 --- a/disk/loopback.c +++ b/disk/loopback.c @@ -28,7 +28,7 @@ struct grub_loopback { char *devname; - char *filename; + grub_file_t file; int has_partitions; struct grub_loopback *next; }; @@ -63,7 +63,7 @@ delete_loopback (const char *name) *prev = dev->next; grub_free (dev->devname); - grub_free (dev->filename); + grub_file_close (dev->file); grub_free (dev); return 0; @@ -76,6 +76,7 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) struct grub_arg_list *state = state = cmd->state; grub_file_t file; struct grub_loopback *newdev; + grub_err_t ret; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); @@ -91,9 +92,6 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) if (! file) return grub_errno; - /* Close the file, the only reason for opening it is validation. */ - grub_file_close (file); - /* First try to replace the old device. */ for (newdev = loopback_list; newdev; newdev = newdev->next) if (grub_strcmp (newdev->devname, args[0]) == 0) @@ -103,10 +101,10 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) { char *newname = grub_strdup (args[1]); if (! newname) - return grub_errno; + goto fail; - grub_free (newdev->filename); - newdev->filename = newname; + grub_file_close (newdev->file); + newdev->file = file; /* Set has_partitions when `--partitions' was used. */ newdev->has_partitions = state[1].set; @@ -117,22 +115,16 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) /* Unable to replace it, make a new entry. */ newdev = grub_malloc (sizeof (struct grub_loopback)); if (! newdev) - return grub_errno; + goto fail; newdev->devname = grub_strdup (args[0]); if (! newdev->devname) { grub_free (newdev); - return grub_errno; + goto fail; } - newdev->filename = grub_strdup (args[1]); - if (! newdev->filename) - { - grub_free (newdev->devname); - grub_free (newdev); - return grub_errno; - } + newdev->file = file; /* Set has_partitions when `--partitions' was used. */ newdev->has_partitions = state[1].set; @@ -142,6 +134,11 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) loopback_list = newdev; return 0; + +fail: + ret = grub_errno; + grub_file_close (file); + return ret; } @@ -160,7 +157,6 @@ grub_loopback_iterate (int (*hook) (const char *name)) static grub_err_t grub_loopback_open (const char *name, grub_disk_t disk) { - grub_file_t file; struct grub_loopback *dev; for (dev = loopback_list; dev; dev = dev->next) @@ -170,29 +166,17 @@ grub_loopback_open (const char *name, grub_disk_t disk) if (! dev) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); - file = grub_file_open (dev->filename); - if (! file) - return grub_errno; - /* Use the filesize for the disk size, round up to a complete sector. */ - disk->total_sectors = ((file->size + GRUB_DISK_SECTOR_SIZE - 1) + disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) / GRUB_DISK_SECTOR_SIZE); disk->id = (unsigned long) dev; disk->has_partitions = dev->has_partitions; - disk->data = file; + disk->data = dev->file; return 0; } -static void -grub_loopback_close (grub_disk_t disk) -{ - grub_file_t file = (grub_file_t) disk->data; - - grub_file_close (file); -} - static grub_err_t grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) @@ -234,7 +218,6 @@ static struct grub_disk_dev grub_loopback_dev = .id = GRUB_DISK_DEVICE_LOOPBACK_ID, .iterate = grub_loopback_iterate, .open = grub_loopback_open, - .close = grub_loopback_close, .read = grub_loopback_read, .write = grub_loopback_write, .next = 0 diff --git a/disk/mdraid_linux.c b/disk/mdraid_linux.c index 306c66a8b..d5a0aad47 100644 --- a/disk/mdraid_linux.c +++ b/disk/mdraid_linux.c @@ -1,7 +1,7 @@ -/* mdraid_linux.c - module to handle linux softraid. */ +/* mdraid_linux.c - module to handle Linux Software RAID. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -159,63 +159,254 @@ struct grub_raid_super_09 struct grub_raid_disk_09 this_disk; } __attribute__ ((packed)); -static grub_err_t -grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array) +/* + * The version-1 superblock : + * All numeric fields are little-endian. + * + * Total size: 256 bytes plus 2 per device. + * 1K allows 384 devices. + */ + +struct grub_raid_super_1x +{ + /* Constant array information - 128 bytes. */ + grub_uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian. */ + grub_uint32_t major_version; /* 1. */ + grub_uint32_t feature_map; /* Bit 0 set if 'bitmap_offset' is meaningful. */ + grub_uint32_t pad0; /* Always set to 0 when writing. */ + + grub_uint8_t set_uuid[16]; /* User-space generated. */ + char set_name[32]; /* Set and interpreted by user-space. */ + + grub_uint64_t ctime; /* Lo 40 bits are seconds, top 24 are microseconds or 0. */ + grub_uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5. */ + grub_uint32_t layout; /* only for raid5 and raid10 currently. */ + grub_uint64_t size; /* Used size of component devices, in 512byte sectors. */ + + grub_uint32_t chunksize; /* In 512byte sectors. */ + grub_uint32_t raid_disks; + grub_uint32_t bitmap_offset; /* Sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + + /* These are only valid with feature bit '4'. */ + grub_uint32_t new_level; /* New level we are reshaping to. */ + grub_uint64_t reshape_position; /* Next address in array-space for reshape. */ + grub_uint32_t delta_disks; /* Change in number of raid_disks. */ + grub_uint32_t new_layout; /* New layout. */ + grub_uint32_t new_chunk; /* New chunk size (512byte sectors). */ + grub_uint8_t pad1[128 - 124]; /* Set to 0 when written. */ + + /* Constant this-device information - 64 bytes. */ + grub_uint64_t data_offset; /* Sector start of data, often 0. */ + grub_uint64_t data_size; /* Sectors in this device that can be used for data. */ + grub_uint64_t super_offset; /* Sector start of this superblock. */ + grub_uint64_t recovery_offset; /* Sectors before this offset (from data_offset) have been recovered. */ + grub_uint32_t dev_number; /* Permanent identifier of this device - not role in raid. */ + grub_uint32_t cnt_corrected_read; /* Number of read errors that were corrected by re-writing. */ + grub_uint8_t device_uuid[16]; /* User-space setable, ignored by kernel. */ + grub_uint8_t devflags; /* Per-device flags. Only one defined... */ + grub_uint8_t pad2[64 - 57]; /* Set to 0 when writing. */ + + /* Array state information - 64 bytes. */ + grub_uint64_t utime; /* 40 bits second, 24 btes microseconds. */ + grub_uint64_t events; /* Incremented when superblock updated. */ + grub_uint64_t resync_offset; /* Data before this offset (from data_offset) known to be in sync. */ + grub_uint32_t sb_csum; /* Checksum upto devs[max_dev]. */ + grub_uint32_t max_dev; /* Size of devs[] array to consider. */ + grub_uint8_t pad3[64 - 32]; /* Set to 0 when writing. */ + + /* Device state information. Indexed by dev_number. + * 2 bytes per device. + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + grub_uint16_t dev_roles[0]; /* Role in array, or 0xffff for a spare, or 0xfffe for faulty. */ +}; +/* Could be __attribute__ ((packed)), but since all members in this struct + are already appropriately aligned, we can omit this and avoid suboptimal + assembly in some cases. */ + +#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */ + +static grub_err_t +grub_mdraid_detect_09 (grub_disk_addr_t sector, + struct grub_raid_super_09 *sb, + struct grub_raid_array *array, + grub_disk_addr_t *start_sector) { - grub_disk_addr_t sector; - grub_uint64_t size; - struct grub_raid_super_09 sb; grub_uint32_t *uuid; - /* The sector where the RAID superblock is stored, if available. */ - size = grub_disk_get_size (disk); - sector = NEW_SIZE_SECTORS (size); - - if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb)) - return grub_errno; - - /* Look whether there is a RAID superblock. */ - if (sb.md_magic != SB_MAGIC) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); - - /* FIXME: Also support version 1.0. */ - if (sb.major_version != 0 || sb.minor_version != 90) + if (sb->major_version != 0 || sb->minor_version != 90) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported RAID version: %d.%d", - sb.major_version, sb.minor_version); + sb->major_version, sb->minor_version); - /* FIXME: Check the checksum. */ + /* FIXME: Check the checksum. */ /* Multipath. */ - if ((int) sb.level == -4) - sb.level = 1; + if ((int) sb->level == -4) + sb->level = 1; - if (sb.level != 0 && sb.level != 1 && sb.level != 4 && - sb.level != 5 && sb.level != 6 && sb.level != 10) + if (sb->level != 0 && sb->level != 1 && sb->level != 4 && + sb->level != 5 && sb->level != 6 && sb->level != 10) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID level: %d", sb.level); + "unsupported RAID level: %d", sb->level); - array->number = sb.md_minor; - array->level = sb.level; - array->layout = sb.layout; - array->total_devs = sb.raid_disks; - array->disk_size = (sb.size) ? sb.size * 2 : sector; - array->chunk_size = sb.chunk_size >> 9; - array->index = sb.this_disk.number; + array->name = NULL; + array->number = sb->md_minor; + array->level = sb->level; + array->layout = sb->layout; + array->total_devs = sb->raid_disks; + array->disk_size = (sb->size) ? sb->size * 2 : sector; + array->chunk_size = sb->chunk_size >> 9; + array->index = sb->this_disk.number; array->uuid_len = 16; array->uuid = grub_malloc (16); if (!array->uuid) - return grub_errno; + return grub_errno; uuid = (grub_uint32_t *) array->uuid; - uuid[0] = sb.set_uuid0; - uuid[1] = sb.set_uuid1; - uuid[2] = sb.set_uuid2; - uuid[3] = sb.set_uuid3; + uuid[0] = sb->set_uuid0; + uuid[1] = sb->set_uuid1; + uuid[2] = sb->set_uuid2; + uuid[3] = sb->set_uuid3; + + *start_sector = 0; return 0; } +static grub_err_t +grub_mdraid_detect_1x (grub_disk_t disk, grub_disk_addr_t sector, + struct grub_raid_super_1x *sb, + struct grub_raid_array *array, + grub_disk_addr_t *start_sector) +{ + grub_uint64_t sb_size; + struct grub_raid_super_1x *real_sb; + + if (sb->major_version != 1) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID version: %d", + sb->major_version); + + /* Multipath. */ + if ((int) sb->level == -4) + sb->level = 1; + + if (sb->level != 0 && sb->level != 1 && sb->level != 4 && + sb->level != 5 && sb->level != 6 && sb->level != 10) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID level: %d", sb->level); + + /* 1.x superblocks don't have a fixed size on disk. So we have to + read it again now that we now the max device count. */ + sb_size = sizeof (struct grub_raid_super_1x) + 2 * grub_le_to_cpu32 (sb->max_dev); + real_sb = grub_malloc (sb_size); + if (! real_sb) + return grub_errno; + + if (grub_disk_read (disk, sector, 0, sb_size, real_sb)) + { + grub_free (real_sb); + return grub_errno; + } + + array->name = grub_strdup (real_sb->set_name); + if (! array->name) + { + grub_free (real_sb); + return grub_errno; + } + + array->number = 0; + array->level = grub_le_to_cpu32 (real_sb->level); + array->layout = grub_le_to_cpu32 (real_sb->layout); + array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks); + array->disk_size = grub_le_to_cpu64 (real_sb->size); + array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize); + if (grub_le_to_cpu32 (real_sb->dev_number) < + grub_le_to_cpu32 (real_sb->max_dev)) + array->index = grub_le_to_cpu16 + (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); + else + array->index = 0xffff; /* disk will be later not used! */ + array->uuid_len = 16; + array->uuid = grub_malloc (16); + if (!array->uuid) + { + grub_free (real_sb); + return grub_errno; + } + + grub_memcpy (array->uuid, real_sb->set_uuid, 16); + + *start_sector = real_sb->data_offset; + + grub_free (real_sb); + return 0; +} + +static grub_err_t +grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector) +{ + grub_disk_addr_t sector; + grub_uint64_t size; + struct grub_raid_super_09 sb_09; + struct grub_raid_super_1x sb_1x; + grub_uint8_t minor_version; + + /* The sector where the mdraid 0.90 superblock is stored, if available. */ + size = grub_disk_get_size (disk); + sector = NEW_SIZE_SECTORS (size); + + if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb_09)) + return grub_errno; + + /* Look whether there is a mdraid 0.90 superblock. */ + if (sb_09.md_magic == SB_MAGIC) + return grub_mdraid_detect_09 (sector, &sb_09, array, start_sector); + + /* Check for an 1.x superblock. + * It's always aligned to a 4K boundary + * and depending on the minor version it can be: + * 0: At least 8K, but less than 12K, from end of device + * 1: At start of device + * 2: 4K from start of device. + */ + + for (minor_version = 0; minor_version < 3; ++minor_version) + { + switch (minor_version) + { + case 0: + sector = (size - 8 * 2) & ~(4 * 2 - 1); + break; + case 1: + sector = 0; + break; + case 2: + sector = 4 * 2; + break; + } + + if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), + &sb_1x)) + return grub_errno; + + if (sb_1x.magic == SB_MAGIC) + return grub_mdraid_detect_1x (disk, sector, &sb_1x, array, + start_sector); + } + + /* Neither 0.90 nor 1.x. */ + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); +} + static struct grub_raid grub_mdraid_dev = { .name = "mdraid", .detect = grub_mdraid_detect, diff --git a/disk/raid.c b/disk/raid.c index 2d544afdc..7dfd4bd81 100644 --- a/disk/raid.c +++ b/disk/raid.c @@ -1,7 +1,7 @@ /* raid.c - module to read RAID arrays. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -254,7 +254,8 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; err = grub_disk_read (array->device[k], - read_sector + j * far_ofs + b, + array->start_sector[k] + + read_sector + j * far_ofs + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); @@ -366,7 +367,8 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; err = grub_disk_read (array->device[disknr], - read_sector + b, 0, + array->start_sector[disknr] + + read_sector + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); @@ -475,12 +477,12 @@ grub_raid_write (grub_disk_t disk __attribute ((unused)), static grub_err_t insert_array (grub_disk_t disk, struct grub_raid_array *new_array, - const char *scanner_name) + grub_disk_addr_t start_sector, const char *scanner_name) { struct grub_raid_array *array = 0, *p; /* See whether the device is part of an array we have already seen a - device from. */ + device from. */ for (p = array_list; p != NULL; p = p->next) if ((p->uuid_len == new_array->uuid_len) && (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len))) @@ -491,7 +493,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* Do some checks before adding the device to the array. */ /* FIXME: Check whether the update time of the superblocks are - the same. */ + the same. */ if (array->total_devs == array->nr_devs) /* We found more members of the array than the array @@ -502,7 +504,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, if (array->device[new_array->index] != NULL) /* We found multiple devices with the same number. Again, - this shouldn't happen.*/ + this shouldn't happen. */ grub_dprintf ("raid", "Found two disks with the number %d?!?", new_array->number); @@ -524,46 +526,72 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, *array = *new_array; array->nr_devs = 0; grub_memset (&array->device, 0, sizeof (array->device)); + grub_memset (&array->start_sector, 0, sizeof (array->start_sector)); - /* Check whether we don't have multiple arrays with the same number. */ + if (array->name) + goto skip_duplicate_check; + /* Check whether we don't have multiple arrays with the same number. */ for (p = array_list; p != NULL; p = p->next) { - if (p->number == array->number) - break; + if (! p->name && p->number == array->number) + break; } if (p) { - /* The number is already in use, so we need to find an new number. */ + /* The number is already in use, so we need to find a new one. */ int i = 0; - while (1) - { - for (p = array_list; p != NULL; p = p->next) - { - if (p->number == i) - break; - } + while (1) + { + for (p = array_list; p != NULL; p = p->next) + { + if (! p->name && p->number == i) + break; + } - if (!p) - { - /* We found an unused number. */ - array->number = i; - break; - } + if (! p) + { + /* We found an unused number. */ + array->number = i; + break; + } - i++; - } - } - - array->name = grub_xasprintf ("md%d", array->number); + i++; + } + } + skip_duplicate_check: + /* mdraid 1.x superblocks have only a name stored not a number. + Use it directly as GRUB device. */ if (! array->name) - { - grub_free (array->uuid); - grub_free (array); + { + array->name = grub_xasprintf ("md%d", array->number); + if (! array->name) + { + grub_free (array->uuid); + grub_free (array); - return grub_errno; - } + return grub_errno; + } + } + else + { + /* Strip off the homehost if present. */ + char *colon = grub_strchr (array->name, ':'); + char *new_name = grub_xasprintf ("md/%s", + colon ? colon + 1 : array->name); + + if (! new_name) + { + grub_free (array->uuid); + grub_free (array); + + return grub_errno; + } + + grub_free (array->name); + array->name = new_name; + } grub_dprintf ("raid", "Found array %s (%s)\n", array->name, scanner_name); @@ -580,6 +608,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* Add the device to the array. */ array->device[new_array->index] = disk; + array->start_sector[new_array->index] = start_sector; array->nr_devs++; return 0; @@ -621,6 +650,7 @@ grub_raid_register (grub_raid_t raid) { grub_disk_t disk; struct grub_raid_array array; + grub_disk_addr_t start_sector; grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); @@ -629,8 +659,8 @@ grub_raid_register (grub_raid_t raid) return 0; if ((disk->total_sectors != GRUB_ULONG_MAX) && - (! grub_raid_list->detect (disk, &array)) && - (! insert_array (disk, &array, grub_raid_list->name))) + (! grub_raid_list->detect (disk, &array, &start_sector)) && + (! insert_array (disk, &array, start_sector, grub_raid_list->name))) return 0; /* This error usually means it's not raid, no need to display diff --git a/docs/grub.texi b/docs/grub.texi index 5d412ecd4..583cf98cb 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -444,12 +444,13 @@ disk. The number @samp{0} is the drive number, which is counted from disk. @example -(hd0,2) +(hd0,msdos2) @end example Here, @samp{hd} means it is a hard disk drive. The first integer -@samp{0} indicates the drive number, that is, the first hard disk, while -the second integer, @samp{1}, indicates the partition number (or the +@samp{0} indicates the drive number, that is, the first hard disk, +the string @samp{msdos} indicates the partition scheme, while +the second integer, @samp{2}, indicates the partition number (or the @sc{pc} slice number in the BSD terminology). The partition numbers are counted from @emph{one}, not from zero (as was the case in previous versions of GRUB). This expression means the second partition of the @@ -457,7 +458,7 @@ first hard disk drive. In this case, GRUB uses one partition of the disk, instead of the whole disk. @example -(hd0,5) +(hd0,msdos5) @end example This specifies the first @dfn{extended partition} of the first hard disk @@ -466,18 +467,15 @@ counted from @samp{5}, regardless of the actual number of primary partitions on your hard disk. @example -(hd1,a) +(hd1,msdos1,bsd1) @end example -This means the BSD @samp{a} partition of the second hard disk. If you -need to specify which @sc{pc} slice number should be used, use something -like this: @samp{(hd1,1,a)}. If the @sc{pc} slice number is omitted, -GRUB searches for the first @sc{pc} slice which has a BSD @samp{a} -partition. +This means the BSD @samp{a} partition on first @sc{pc} slice number +of the second hard disk. Of course, to actually access the disks or partitions with GRUB, you need to use the device specification in a command, like @samp{set -root=(fd0)} or @samp{parttool (hd0,3) hidden-}. To help you find out +root=(fd0)} or @samp{parttool (hd0,msdos3) hidden-}. To help you find out which number specifies a partition you want, the GRUB command-line (@pxref{Command-line interface}) options have argument completion. This means that, for example, you only need to type @@ -501,7 +499,7 @@ Now the question is, how to specify a file? Again, consider an example: @example -(hd0,1)/vmlinuz +(hd0,msdos1)/vmlinuz @end example This specifies the file named @samp{vmlinuz}, found on the first @@ -1064,6 +1062,11 @@ only to the default menu entry, after those listed in As @samp{GRUB_CMDLINE_LINUX} and @samp{GRUB_CMDLINE_LINUX_DEFAULT}, but for NetBSD. +@item GRUB_CMDLINE_XEN +@itemx GRUB_CMDLINE_XEN_DEFAULT +As @samp{GRUB_CMDLINE_LINUX} and @samp{GRUB_CMDLINE_LINUX_DEFAULT}, but for +Linux and Xen. + @item GRUB_DISABLE_LINUX_UUID Normally, @command{grub-mkconfig} will generate menu entries that use universally-unique identifiers (UUIDs) to identify the root filesystem to @@ -1115,8 +1118,8 @@ try several modes in sequence. Depending on your kernel, your distribution, your graphics card, and the phase of the moon, note that using this option may cause GNU/Linux to suffer from various display problems, particularly during the early part of the -boot sequence. If you have problems, simply unset this option and GRUB will -tell Linux to boot in normal text mode. +boot sequence. If you have problems, set this option to @samp{text} and +GRUB will tell Linux to boot in normal text mode. @item GRUB_DISABLE_OS_PROBER Normally, @command{grub-mkconfig} will try to use the external @@ -1145,6 +1148,142 @@ that file, making sure to leave at least the first two lines intact. @node Shell-like scripting @section Writing full configuration files directly +@c Some of this section is derived from the GNU Bash manual page, also +@c copyrighted by the FSF. + +@file{grub.cfg} is written in GRUB's built-in scripting language, which has +a syntax quite similar to that of GNU Bash and other Bourne shell +derivatives. + +@heading Words + +A @dfn{word} is a sequence of characters considered as a single unit by +GRUB. Words are separated by @dfn{metacharacters}, which are the following +plus space, tab, and newline: + +@example +@{ @} | & $ ; < > +@end example + +Quoting may be used to include metacharacters in words; see below. + +@heading Reserved words + +Reserved words have a special meaning to GRUB. The following words are +recognised as reserved when unquoted and either the first word of a simple +command or the third word of a @code{for} command: + +@example +! [[ ]] @{ @} +case do done elif else esac fi for function +if in menuentry select then time until while +@end example + +Not all of these reserved words have a useful purpose yet; some are reserved +for future expansion. + +@heading Quoting + +Quoting is used to remove the special meaning of certain characters or +words. It can be used to treat metacharacters as part of a word, to prevent +reserved words from being recognised as such, and to prevent variable +expansion. + +There are three quoting mechanisms: the escape character, single quotes, and +double quotes. + +A non-quoted backslash (\) is the @dfn{escape character}. It preserves the +literal value of the next character that follows, with the exception of +newline. + +Enclosing characters in single quotes preserves the literal value of each +character within the quotes. A single quote may not occur between single +quotes, even when preceded by a backslash. + +Enclosing characters in double quotes preserves the literal value of all +characters within the quotes, with the exception of @samp{$} and @samp{\}. +The @samp{$} character retains its special meaning within double quotes. +The backslash retains its special meaning only when followed by one of the +following characters: @samp{$}, @samp{"}, @samp{\}, or newline. A +backslash-newline pair is treated as a line continuation (that is, it is +removed from the input stream and effectively ignored). A double quote may +be quoted within double quotes by preceding it with a backslash. + +@heading Variable expansion + +The @samp{$} character introduces variable expansion. The variable name to +be expanded may be enclosed in braces, which are optional but serve to +protect the variable to be expanded from characters immediately following it +which could be interpreted as part of the name. + +Normal variable names begin with an alphabetic character, followed by zero +or more alphanumeric characters. + +Positional variable names consist of one or more digits. These are reserved +for future expansion. + +The special variable name @samp{?} expands to the exit status of the most +recently executed command. + +@heading Comments + +A word beginning with @samp{#} causes that word and all remaining characters +on that line to be ignored. + +@heading Simple commands + +A @dfn{simple command} is a sequence of words separated by spaces or tabs +and terminated by a semicolon or a newline. The first word specifies the +command to be executed. The remaining words are passed as arguments to the +invoked command. + +The return value of a simple command is its exit status. + +@heading Compound commands + +A @dfn{compound command} is one of the following: + +@table @asis +@item for @var{name} in @var{word} @dots{}; do @var{list}; done +The list of words following @code{in} is expanded, generating a list of +items. The variable @var{name} is set to each element of this list in turn, +and @var{list} is executed each time. The return value is the exit status +of the last command that executes. If the expansion of the items following +@code{in} results in an empty list, no commands are executed, and the return +status is 0. + +@item if @var{list}; then @var{list}; [elif @var{list}; then @var{list};] @dots{} [else @var{list};] fi +The @code{if} @var{list} is executed. If its exit status is zero, the +@code{then} @var{list} is executed. Otherwise, each @code{elif} @var{list} +is executed in turn, and if its exit status is zero, the corresponding +@code{then} @var{list} is executed and the command completes. Otherwise, +the @code{else} @var{list} is executed, if present. The exit status is the +exit status of the last command executed, or zero if no condition tested +true. + +@item while @var{cond}; do @var{list}; done +@itemx until @var{cond}; do @var{list}; done +The @code{while} command continuously executes the @code{do} @var{list} as +long as the last command in @var{cond} returns an exit status of zero. The +@code{until} command is identical to the @code{while} command, except that +the test is negated; the @code{do} @var{list} is executed as long as the +last command in @var{cond} returns a non-zero exit status. The exit status +of the @code{while} and @code{until} commands is the exit status of the last +@code{do} @var{list} command executed, or zero if none was executed. + +@item function @var{name} @{ @var{command}; @dots{} @} +This defines a function named @var{name}. The @dfn{body} of the function is +the list of commands within braces, each of which must be terminated with a +semicolon or a newline. This list of commands will be executed whenever +@var{name} is specified as the name of a simple command. Function +definitions do not affect the exit status in @code{$?}. When executed, the +exit status of a function is the exit status of the last command executed in +the body. + +@item menuentry @var{title} [@option{--class=class} @dots{}] [@option{--users=users}] [@option{--hotkey=key}] @{ @var{command}; @dots{} @} +@xref{menuentry}. +@end table + @node Embedded configuration @section Embedding a configuration file into GRUB @@ -1310,8 +1449,7 @@ simple. Here is an example: @example @group grub> @kbd{serial --unit=0 --speed=9600} -grub> @kbd{terminal_input serial} -grub> @kbd{terminal_output serial} +grub> @kbd{terminal_input serial; terminal_output serial} @end group @end example @@ -1322,11 +1460,14 @@ command accepts many other options, so please refer to @ref{serial}, for more details. The commands @command{terminal_input} (@pxref{terminal_input}) and -@command{terminal_output} (@pxref{terminal_output} choose which type of +@command{terminal_output} (@pxref{terminal_output}) choose which type of terminal you want to use. In the case above, the terminal will be a serial terminal, but you can also pass @code{console} to the command, as @samp{terminal serial console}. In this case, a terminal in which -you press any key will be selected as a GRUB terminal. +you press any key will be selected as a GRUB terminal. In the example above, +note that you need to put both commands on the same command line, as you +will lose the ability to type commands on the console after the first +command. However, note that GRUB assumes that your terminal emulator is compatible with VT100 by default. This is true for most terminal @@ -1791,9 +1932,26 @@ These commands can only be used in the menu: @node menuentry @subsection menuentry -@deffn Command title name @dots{} -Start a new boot entry, and set its name to the contents of the rest of -the line, starting with the first non-space character. +@deffn Command menuentry @var{title} @ + [@option{--class=class} @dots{}] [@option{--users=users}] @ + [@option{--hotkey=key}] @ + @{ @var{command}; @dots{} @} +This defines a GRUB menu entry named @var{title}. When this entry is +selected from the menu, GRUB will set the @var{chosen} environment variable +to @var{title}, execute the list of commands given within braces, and if the +last command in the list returned successfully and a kernel was loaded it +will execute the @command{boot} command. + +The @option{--class} option may be used any number of times to group menu +entries into classes. Menu themes may display different classes using +different styles. + +The @option{--users} option grants specific users access to specific menu +entries. @xref{Security}. + +The @option{--hotkey} option associates a hotkey with a menu entry. +@var{key} may be a single letter, or one of the aliases @samp{backspace}, +@samp{tab}, or @samp{delete}. @end deffn @@ -1887,7 +2045,9 @@ The @option{-a} (@option{--ascii}), @option{-u} (@option{--utf8}), and @option{-v} (@option{--visual-utf8}) options control how non-ASCII text is displayed. @option{-a} specifies an ASCII-only terminal; @option{-u} specifies logically-ordered UTF-8; and @option{-v} specifies -visually-ordered UTF-8. +"visually-ordered UTF-8" (in other words, arranged such that a terminal +emulator without bidirectional text support will display right-to-left text +in the proper order; this is not really proper UTF-8, but a workaround). If no option or terminal type is specified, the current terminal type is printed. diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index f34cd4287..dc48d91a8 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -1,3 +1,21 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + #ifndef GRUB_EMU_MISC_H #define GRUB_EMU_MISC_H 1 @@ -26,12 +44,12 @@ extern const char *program_name; void grub_init_all (void); void grub_fini_all (void); -char *grub_make_system_path_relative_to_its_root (const char *path); +char *grub_make_system_path_relative_to_its_root (const char *path) __attribute__ ((warn_unused_result)); -void * EXPORT_FUNC(xmalloc) (grub_size_t size); -void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size); -char * EXPORT_FUNC(xstrdup) (const char *str); -char * EXPORT_FUNC(xasprintf) (const char *fmt, ...); +void * EXPORT_FUNC(xmalloc) (grub_size_t size) __attribute__ ((warn_unused_result)); +void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size) __attribute__ ((warn_unused_result)); +char * EXPORT_FUNC(xstrdup) (const char *str) __attribute__ ((warn_unused_result)); +char * EXPORT_FUNC(xasprintf) (const char *fmt, ...) __attribute__ ((warn_unused_result)); void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...); void EXPORT_FUNC(grub_util_info) (const char *fmt, ...); @@ -45,7 +63,6 @@ int EXPORT_FUNC(vasprintf) (char **buf, const char *fmt, va_list ap); int EXPORT_FUNC(asprintf) (char **buf, const char *fmt, ...); #endif -char * EXPORT_FUNC(xasprintf) (const char *fmt, ...); extern char * canonicalize_file_name (const char *path); #ifdef HAVE_DEVICE_MAPPER diff --git a/include/grub/misc.h b/include/grub/misc.h index 9194ca8ad..eab01b0fb 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -231,10 +231,10 @@ grub_strtol (const char *str, char **end, int base) } } -char *EXPORT_FUNC(grub_strdup) (const char *s); -char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n); +char *EXPORT_FUNC(grub_strdup) (const char *s) __attribute__ ((warn_unused_result)); +char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) __attribute__ ((warn_unused_result)); void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); -grub_size_t EXPORT_FUNC(grub_strlen) (const char *s); +grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) __attribute__ ((warn_unused_result)); int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -261,8 +261,8 @@ int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, va_list args); char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); -char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args); + __attribute__ ((format (printf, 1, 2))) __attribute__ ((warn_unused_result)); +char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) __attribute__ ((warn_unused_result)); void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, diff --git a/include/grub/raid.h b/include/grub/raid.h index 8fa4c3814..711a7f79c 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -1,7 +1,7 @@ /* raid.h - On disk structures for RAID. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,8 @@ struct grub_raid_array char *name; /* That will be "md". */ unsigned int nr_devs; /* The number of devices we've found so far. */ grub_disk_t device[GRUB_RAID_MAX_DEVICES]; /* Array of total_devs devices. */ + grub_disk_addr_t start_sector[GRUB_RAID_MAX_DEVICES]; + /* Start of each device, in 512 byte sectors. */ struct grub_raid_array *next; }; @@ -58,7 +60,8 @@ struct grub_raid { const char *name; - grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array); + grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector); struct grub_raid *next; }; diff --git a/include/grub/util/libnvpair.h b/include/grub/util/libnvpair.h new file mode 100644 index 000000000..26f7e9d0f --- /dev/null +++ b/include/grub/util/libnvpair.h @@ -0,0 +1,39 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_LIBNVPAIR_UTIL_HEADER +#define GRUB_LIBNVPAIR_UTIL_HEADER 1 + +#include + +#ifdef HAVE_LIBNVPAIR_H +#include +#else /* ! HAVE_LIBNVPAIR_H */ + +#include /* FILE */ + +typedef void nvlist_t; + +int nvlist_lookup_string (nvlist_t *, const char *, char **); +int nvlist_lookup_nvlist (nvlist_t *, const char *, nvlist_t **); +int nvlist_lookup_nvlist_array (nvlist_t *, const char *, nvlist_t ***, unsigned int *); +void nvlist_print (FILE *, nvlist_t *); + +#endif /* ! HAVE_LIBNVPAIR_H */ + +#endif diff --git a/include/grub/util/libzfs.h b/include/grub/util/libzfs.h new file mode 100644 index 000000000..9fbfd40d1 --- /dev/null +++ b/include/grub/util/libzfs.h @@ -0,0 +1,45 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_LIBZFS_UTIL_HEADER +#define GRUB_LIBZFS_UTIL_HEADER 1 + +#include + +#ifdef HAVE_LIBZFS_H +#include +#else /* ! HAVE_LIBZFS_H */ + +#include + +typedef void libzfs_handle_t; +typedef void zpool_handle_t; + +extern libzfs_handle_t *libzfs_init (); +extern void libzfs_fini (libzfs_handle_t *); + +extern zpool_handle_t *zpool_open (libzfs_handle_t *, const char *); +extern void zpool_close (zpool_handle_t *); + +extern int zpool_get_physpath (zpool_handle_t *, const char *); + +extern nvlist_t *zpool_get_config (zpool_handle_t *, nvlist_t **); + +#endif /* ! HAVE_LIBZFS_H */ + +#endif diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 48dfbb868..3614c79c2 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -29,6 +29,7 @@ #include #include #include +#include char *grub_util_get_path (const char *dir, const char *file); size_t grub_util_get_fp_size (FILE *fp); @@ -60,4 +61,7 @@ char *canonicalize_file_name (const char *path); void grub_util_init_nls (void); +void grub_util_init_libzfs (void); +extern libzfs_handle_t *libzfs_handle; + #endif /* ! GRUB_UTIL_MISC_HEADER */ diff --git a/kern/emu/getroot.c b/kern/emu/getroot.c index 24b2cd486..032608d1b 100644 --- a/kern/emu/getroot.c +++ b/kern/emu/getroot.c @@ -1,7 +1,7 @@ /* getroot.c - Get root device */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +20,17 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #ifdef __GNU__ #include @@ -36,6 +39,20 @@ #include #endif +#ifdef __linux__ +# include +# include +#endif + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +# include +# include +#endif + +#ifdef HAVE_GETFSSTAT +# include +#endif + #include #include #include @@ -81,6 +98,66 @@ xgetcwd (void) return path; } +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + +static char * +find_mount_point_from_dir (const char *dir) +{ + struct stat st; + typeof (st.st_dev) fs; + char *prev, *next, *slash, *statdir; + + if (stat (dir, &st) == -1) + error (1, errno, "stat (%s)", dir); + + fs = st.st_dev; + + prev = xstrdup (dir); + + while (1) + { + /* Remove last slash. */ + next = xstrdup (prev); + slash = strrchr (next, '/'); + if (! slash) + { + free (next); + free (prev); + return NULL; + } + *slash = '\0'; + + /* A next empty string counts as /. */ + if (next[0] == '\0') + statdir = "/"; + else + statdir = next; + + if (stat (statdir, &st) == -1) + error (1, errno, "stat (%s)", next); + + if (st.st_dev != fs) + { + /* Found mount point. */ + free (next); + return prev; + } + + free (prev); + prev = next; + + /* We've already seen an empty string, which means we + reached /. Nothing left to do. */ + if (prev[0] == '\0') + { + free (prev); + return xstrdup ("/"); + } + } +} + +#endif + #ifdef __linux__ /* Statting something on a btrfs filesystem always returns a virtual device @@ -161,6 +238,90 @@ find_root_device_from_mountinfo (const char *dir) #endif /* __linux__ */ +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + +/* ZFS has similar problems to those of btrfs (see above). */ +static char * +find_root_device_from_libzfs (const char *dir) +{ + char *device = NULL; + char *poolname = NULL; + char *poolfs = NULL; + char *mnt_point; + char *slash; + + mnt_point = find_mount_point_from_dir (dir); + +#ifdef HAVE_GETFSSTAT + { + int mnt_count = getfsstat (NULL, 0, MNT_WAIT); + if (mnt_count == -1) + error (1, errno, "getfsstat"); + + struct statfs *mnt = xmalloc (mnt_count * sizeof (*mnt)); + + mnt_count = getfsstat (mnt, mnt_count * sizeof (*mnt), MNT_WAIT); + if (mnt_count == -1) + error (1, errno, "getfsstat"); + + unsigned int i; + for (i = 0; i < (unsigned) mnt_count; i++) + if (!strcmp (mnt[i].f_fstypename, "zfs") + && !strcmp (mnt[i].f_mntonname, mnt_point)) + { + poolname = xstrdup (mnt[i].f_mntfromname); + break; + } + + free (mnt); + } +#endif + + if (! poolname) + return NULL; + + slash = strchr (poolname, '/'); + if (slash) + { + *slash = '\0'; + poolfs = slash + 1; + } + + { + zpool_handle_t *zpool; + nvlist_t *nvlist; + nvlist_t **nvlist_array; + unsigned int nvlist_count; + + grub_util_init_libzfs (); + + zpool = zpool_open (libzfs_handle, poolname); + nvlist = zpool_get_config (zpool, NULL); + + if (nvlist_lookup_nvlist (nvlist, "vdev_tree", &nvlist) != 0) + error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); + + if (nvlist_lookup_nvlist_array (nvlist, "children", &nvlist_array, &nvlist_count) != 0) + error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); + + do + { + assert (nvlist_count > 0); + } while (nvlist_lookup_nvlist_array (nvlist_array[0], "children", + &nvlist_array, &nvlist_count) == 0); + + if (nvlist_lookup_string (nvlist_array[0], "path", &device) != 0) + error (1, errno, "nvlist_lookup_string (\"path\")"); + + zpool_close (zpool); + } + + free (poolname); + + return device; +} +#endif + #ifdef __MINGW32__ static char * @@ -453,6 +614,12 @@ grub_guess_root_device (const char *dir) return os_dev; #endif /* __linux__ */ +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + os_dev = find_root_device_from_libzfs (dir); + if (os_dev) + return os_dev; +#endif + if (stat (dir, &st) < 0) grub_util_error ("cannot stat `%s'", dir); @@ -516,10 +683,89 @@ grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) return GRUB_DEV_ABSTRACTION_NONE; } +#ifdef __linux__ +static char * +get_mdadm_name (const char *os_dev) +{ + int mdadm_pipe[2]; + pid_t mdadm_pid; + char *name = NULL; + + if (pipe (mdadm_pipe) < 0) + { + grub_util_warn ("Unable to create pipe for mdadm: %s", strerror (errno)); + return NULL; + } + + mdadm_pid = fork (); + if (mdadm_pid < 0) + grub_util_warn ("Unable to fork mdadm: %s", strerror (errno)); + else if (mdadm_pid == 0) + { + /* Child. */ + char *argv[5]; + + close (mdadm_pipe[0]); + dup2 (mdadm_pipe[1], STDOUT_FILENO); + close (mdadm_pipe[1]); + + /* execvp has inconvenient types, hence the casts. None of these + strings will actually be modified. */ + argv[0] = (char *) "mdadm"; + argv[1] = (char *) "--detail"; + argv[2] = (char *) "--export"; + argv[3] = (char *) os_dev; + argv[4] = NULL; + execvp ("mdadm", argv); + exit (127); + } + else + { + /* Parent. Read mdadm's output. */ + FILE *mdadm; + char *buf = NULL; + size_t len = 0; + + close (mdadm_pipe[1]); + mdadm = fdopen (mdadm_pipe[0], "r"); + if (! mdadm) + { + grub_util_warn ("Unable to open stream from mdadm: %s", + strerror (errno)); + goto out; + } + + while (getline (&buf, &len, mdadm) > 0) + { + if (strncmp (buf, "MD_NAME=", sizeof ("MD_NAME=") - 1) == 0) + { + char *name_start, *colon; + size_t name_len; + + free (name); + name_start = buf + sizeof ("MD_NAME=") - 1; + /* Strip off the homehost if present. */ + colon = strchr (name_start, ':'); + name = strdup (colon ? colon + 1 : name_start); + name_len = strlen (name); + if (name[name_len - 1] == '\n') + name[name_len - 1] = '\0'; + } + } + +out: + close (mdadm_pipe[0]); + waitpid (mdadm_pid, NULL, 0); + } + + return name; +} +#endif /* __linux__ */ + char * grub_util_get_grub_dev (const char *os_dev) { - char *grub_dev; + char *grub_dev = NULL; switch (grub_util_get_dev_abstraction (os_dev)) { @@ -600,9 +846,36 @@ grub_util_get_grub_dev (const char *os_dev) grub_dev = xasprintf ("md%s", p); free (p); } + else if (os_dev[7] == '/') + { + /* mdraid 1.x with a free name. */ + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md/") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md/%s", p); + free (p); + } else grub_util_error ("unknown kind of RAID device `%s'", os_dev); +#ifdef __linux__ + { + char *mdadm_name = get_mdadm_name (os_dev); + + if (mdadm_name) + { + free (grub_dev); + grub_dev = xasprintf ("md/%s", mdadm_name); + free (mdadm_name); + } + } +#endif /* __linux__ */ + break; default: /* GRUB_DEV_ABSTRACTION_NONE */ diff --git a/kern/emu/misc.c b/kern/emu/misc.c index 38395fca8..851da7a07 100644 --- a/kern/emu/misc.c +++ b/kern/emu/misc.c @@ -1,3 +1,21 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + #include #include diff --git a/kern/misc.c b/kern/misc.c index c13c96e30..b37ef230c 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -518,12 +518,39 @@ grub_strndup (const char *s, grub_size_t n) } void * -grub_memset (void *s, int c, grub_size_t n) +grub_memset (void *s, int c, grub_size_t len) { - unsigned char *p = (unsigned char *) s; + void *p = s; + grub_uint8_t pattern8 = c; - while (n--) - *p++ = (unsigned char) c; + if (len >= 3 * sizeof (unsigned long)) + { + unsigned long patternl = 0; + grub_size_t i; + + for (i = 0; i < sizeof (unsigned long); i++) + patternl |= ((unsigned long) pattern8) << (8 * i); + + while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1))) + { + *(grub_uint8_t *) p = pattern8; + p = (grub_uint8_t *) p + 1; + len--; + } + while (len >= sizeof (unsigned long)) + { + *(unsigned long *) p = patternl; + p = (unsigned long *) p + 1; + len -= sizeof (unsigned long); + } + } + + while (len > 0) + { + *(grub_uint8_t *) p = pattern8; + p = (grub_uint8_t *) p + 1; + len--; + } return s; } diff --git a/lib/arg.c b/lib/arg.c index 400314d30..a9b8a520e 100644 --- a/lib/arg.c +++ b/lib/arg.c @@ -144,8 +144,10 @@ grub_arg_show_help (grub_extcmd_t cmd) } } - /* FIXME: add spacing back. */ - grub_xputs (_(opt->doc)); + while (spacing--) + grub_xputs (" "); + + grub_printf ("%s\n", _(opt->doc)); switch (opt->shortarg) { diff --git a/lib/i386/relocator_asm.S b/lib/i386/relocator_asm.S index 6b803db13..22490a3f8 100644 --- a/lib/i386/relocator_asm.S +++ b/lib/i386/relocator_asm.S @@ -157,11 +157,13 @@ LOCAL(cont1): andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax movl %eax, %cr0 +#ifdef __x86_64__ /* Disable amd64. */ movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx rdmsr andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax wrmsr +#endif /* Turn off PAE. */ movl %cr4, %eax diff --git a/script/yylex.l b/script/yylex.l index 7d4ea9e4e..e9659832b 100644 --- a/script/yylex.l +++ b/script/yylex.l @@ -116,7 +116,7 @@ COMMENT #.*$ CHAR [^{}|&$;<> \t\n\'\"\\] DIGITS [[:digit:]]+ -NAME [[:alpha:]_][[:alnum:][:digit:]_]* +NAME [[:alpha:]_][[:alnum:]_]* ESC \\. VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\} diff --git a/term/efi/console.c b/term/efi/console.c index d3240590b..dca002910 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -311,6 +311,20 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), efi_call_2 (o->enable_cursor, o, on); } +static grub_err_t +grub_efi_console_init (struct grub_term_output *term) +{ + grub_console_setcursor (term, 1); + return 0; +} + +static grub_err_t +grub_efi_console_fini (struct grub_term_output *term) +{ + grub_console_setcursor (term, 0); + return 0; +} + static struct grub_term_input grub_console_term_input = { .name = "console", @@ -321,6 +335,8 @@ static struct grub_term_input grub_console_term_input = static struct grub_term_output grub_console_term_output = { .name = "console", + .init = grub_efi_console_init, + .fini = grub_efi_console_fini, .putchar = grub_console_putchar, .getwh = grub_console_getwh, .getxy = grub_console_getxy, diff --git a/term/ns8250.c b/term/ns8250.c index 6bf8c5b59..315d3527f 100644 --- a/term/ns8250.c +++ b/term/ns8250.c @@ -210,7 +210,7 @@ static struct grub_serial_port com_ports[GRUB_SERIAL_PORT_NUM]; void grub_ns8250_init (void) { - int i; + unsigned i; for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++) if (serial_hw_io_addr[i]) { @@ -231,7 +231,7 @@ char * grub_serial_ns8250_add_port (grub_port_t port) { struct grub_serial_port *p; - int i; + unsigned i; for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++) if (com_ports[i].port == port) return com_names[i]; diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in index e9507c8f5..ed34a5e17 100644 --- a/tests/util/grub-shell-tester.in +++ b/tests/util/grub-shell-tester.in @@ -1,4 +1,4 @@ -#! /bin/bash -e +#! /bin/sh -e # Compares GRUB script output with BASH output. # Copyright (C) 2009,2010 Free Software Foundation, Inc. @@ -84,7 +84,7 @@ done if [ "x${source}" = x ] ; then tmpfile=`mktemp` - while read; do + while read REPLY; do echo $REPLY >> ${tmpfile} done source=${tmpfile} diff --git a/util/deviceiter.c b/util/deviceiter.c index bbcc00a91..1cf511934 100644 --- a/util/deviceiter.c +++ b/util/deviceiter.c @@ -467,13 +467,30 @@ clear_seen_devices (void) } #ifdef __linux__ -/* Like strcmp, but doesn't require a cast for use as a qsort comparator. */ -static int -compare_file_names (const void *a, const void *b) +struct device { - const char *left = *(const char **) a; - const char *right = *(const char **) b; - return strcmp (left, right); + char *stable; + char *kernel; +}; + +/* Sort by the kernel name for preference since that most closely matches + older device.map files, but sort by stable by-id names as a fallback. + This is because /dev/disk/by-id/ usually has a few alternative + identifications of devices (e.g. ATA vs. SATA). + check_device_readable_unique will ensure that we only get one for any + given disk, but sort the list so that the choice of which one we get is + stable. */ +static int +compare_devices (const void *a, const void *b) +{ + const struct device *left = (const struct device *) a; + const struct device *right = (const struct device *) b; + int ret; + ret = strcmp (left->kernel, right->kernel); + if (ret) + return ret; + else + return strcmp (left->stable, right->stable); } #endif /* __linux__ */ @@ -507,10 +524,10 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), if (dir) { struct dirent *entry; - char **names; - size_t names_len = 0, names_max = 1024, i; + struct device *devs; + size_t devs_len = 0, devs_max = 1024, i; - names = xmalloc (names_max * sizeof (*names)); + devs = xmalloc (devs_max * sizeof (*devs)); /* Dump all the directory entries into names, resizing if necessary. */ @@ -526,35 +543,34 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), /* Skip RAID entries; they are handled by upper layers. */ if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0) continue; - if (names_len >= names_max) + if (devs_len >= devs_max) { - names_max *= 2; - names = xrealloc (names, names_max * sizeof (*names)); + devs_max *= 2; + devs = xrealloc (devs, devs_max * sizeof (*devs)); } - names[names_len++] = xasprintf (entry->d_name); + devs[devs_len].stable = + xasprintf ("/dev/disk/by-id/%s", entry->d_name); + devs[devs_len].kernel = + canonicalize_file_name (devs[devs_len].stable); + devs_len++; } - /* /dev/disk/by-id/ usually has a few alternative identifications of - devices (e.g. ATA vs. SATA). check_device_readable_unique will - ensure that we only get one for any given disk, but sort the list - so that the choice of which one we get is stable. */ - qsort (names, names_len, sizeof (*names), &compare_file_names); + qsort (devs, devs_len, sizeof (*devs), &compare_devices); closedir (dir); /* Now add all the devices in sorted order. */ - for (i = 0; i < names_len; ++i) + for (i = 0; i < devs_len; ++i) { - char *path = xasprintf ("/dev/disk/by-id/%s", names[i]); - if (check_device_readable_unique (path)) + if (check_device_readable_unique (devs[i].stable)) { - if (hook (path, 0)) + if (hook (devs[i].stable, 0)) goto out; } - free (path); - free (names[i]); + free (devs[i].stable); + free (devs[i].kernel); } - free (names); + free (devs); } } diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in index e498acee7..b7d9eb4eb 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -296,6 +296,7 @@ if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then mformat -C -f 2880 -L 16 -i "${iso9660_dir}"/efi.img :: mcopy -s -i "${iso9660_dir}"/efi.img ${efi_dir}/efi ::/ + rm -rf ${efi_dir} grub_mkisofs_arguments="${grub_mkisofs_arguments} --efi-boot efi.img" fi diff --git a/util/grub-probe.c b/util/grub-probe.c index dff87907a..56cbc5592 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -50,6 +50,7 @@ enum { PRINT_FS, PRINT_FS_UUID, + PRINT_FS_LABEL, PRINT_DRIVE, PRINT_DEVICE, PRINT_PARTMAP, @@ -291,6 +292,16 @@ probe (const char *path, char *device_name) printf ("%s\n", uuid); } + else if (print == PRINT_FS_LABEL) + { + char *label; + if (! fs->label) + grub_util_error ("%s does not support labels", fs->name); + + fs->label (dev, &label); + + printf ("%s\n", label); + } end: if (dev) @@ -326,7 +337,7 @@ Probe device information for a given path (or device, if the -d option is given) \n\ -d, --device given argument is a system device, not a path\n\ -m, --device-map=FILE use FILE as the device map [default=%s]\n\ - -t, --target=(fs|fs_uuid|drive|device|partmap|abstraction)\n\ + -t, --target=(fs|fs_uuid|fs_label|drive|device|partmap|abstraction)\n\ print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ @@ -375,6 +386,8 @@ main (int argc, char *argv[]) print = PRINT_FS; else if (!strcmp (optarg, "fs_uuid")) print = PRINT_FS_UUID; + else if (!strcmp (optarg, "fs_label")) + print = PRINT_FS_LABEL; else if (!strcmp (optarg, "drive")) print = PRINT_DRIVE; else if (!strcmp (optarg, "device")) diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 75c8b0fa2..2f39650e9 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -137,11 +137,7 @@ case x${GRUB_TERMINAL_INPUT} in ;; x*) cat << EOF -if terminal_input ${GRUB_TERMINAL_INPUT} ; then true ; else - # For backward compatibility with versions of terminal.mod that don't - # understand terminal_input - terminal ${GRUB_TERMINAL_INPUT} -fi +terminal_input ${GRUB_TERMINAL_INPUT} EOF ;; esac @@ -152,11 +148,7 @@ case x${GRUB_TERMINAL_OUTPUT} in ;; x*) cat << EOF -if terminal_output ${GRUB_TERMINAL_OUTPUT} ; then true ; else - # For backward compatibility with versions of terminal.mod that don't - # understand terminal_output - terminal ${GRUB_TERMINAL_OUTPUT} -fi +terminal_output ${GRUB_TERMINAL_OUTPUT} EOF ;; esac diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 9915abdf1..f32da3013 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -51,6 +51,10 @@ kfreebsd_entry () if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi + if [ -z "${prepare_module_dir_cache}" ]; then + prepare_module_dir_cache="$(prepare_grub_to_access_device $(grub-probe -t device "${module_dir}") | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" cat << EOF echo '$(printf "$(gettext_quoted "Loading kernel of FreeBSD %s ...")" ${version})' @@ -63,9 +67,10 @@ EOF EOF fi - if test -n "${acpi_ko}" ; then + if test -e "${module_dir}/acpi.ko" ; then + printf '%s\n' "${prepare_module_dir_cache}" cat << EOF - kfreebsd_module_elf ${acpi_ko_rel_dirname}/${acpi_ko_basename} + kfreebsd_module_elf ${module_dir_rel}/acpi.ko EOF fi @@ -103,19 +108,17 @@ while [ "x$list" != "x" ] ; do version=`echo $basename | sed -e "s,^[^0-9]*-,,g;s/\.gz$//g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` - acpi_ko= - for i in "/lib/modules/${version}/acpi.ko" "/lib/modules/${alt_version}/acpi.ko" \ - "/boot/kernel/acpi.ko"; do + module_dir= + for i in "/lib/modules/${version}" "/lib/modules/${alt_version}" \ + "/boot/kernel"; do if test -e "$i" ; then - acpi_ko="$i" + module_dir="$i" break fi done - if test -n "${acpi_ko}" ; then - echo "Found ACPI module: ${acpi_ko}" >&2 - acpi_ko_basename=`basename ${acpi_ko}` - acpi_ko_dirname=`dirname ${acpi_ko}` - acpi_ko_rel_dirname=`make_system_path_relative_to_its_root $acpi_ko_dirname` + if test -n "${module_dir}" ; then + echo "Found kernel module directory: ${module_dir}" >&2 + module_dir_rel=$(make_system_path_relative_to_its_root $module_dir) fi kfreebsd_entry "${OS}" "${version}" diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in index 8612c96b0..e631c0a4a 100644 --- a/util/grub.d/20_linux_xen.in +++ b/util/grub.d/20_linux_xen.in @@ -44,7 +44,8 @@ case ${GRUB_DEVICE} in esac if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ - || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then + || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ + || uses_abstraction "${GRUB_DEVICE}" lvm; then LINUX_ROOT_DEVICE=${GRUB_DEVICE} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} diff --git a/util/i386/efi/grub-install.in b/util/i386/efi/grub-install.in index 269317cd0..d8554a328 100644 --- a/util/i386/efi/grub-install.in +++ b/util/i386/efi/grub-install.in @@ -246,7 +246,7 @@ devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_ma # The order in this list is critical. Be careful when modifying it. modules="$modules $fs_module $partmap_module $devabstraction_module" -$grub_mkimage -O ${target_cpu}-efi --output=${grubdir}/grub.efi $modules || exit 1 +$grub_mkimage -p "" -O ${target_cpu}-efi --output=${grubdir}/grub.efi $modules || exit 1 # Prompt the user to check if the device map is correct. echo "Installation finished. No error reported." diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 8b2f52bb4..524572fad 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -812,14 +812,14 @@ main (int argc, char *argv[]) must_embed = 1; if (root_dev[0] == 'm' && root_dev[1] == 'd' - && root_dev[2] >= '0' && root_dev[2] <= '9') + && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/')) { /* FIXME: we can avoid this on RAID1. */ must_embed = 1; } if (dest_dev[0] == 'm' && dest_dev[1] == 'd' - && dest_dev[2] >= '0' && dest_dev[2] <= '9') + && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/')) { char **devicelist; int i; diff --git a/util/ieee1275/grub-install.in b/util/ieee1275/grub-install.in index 98fd5d65a..98de5f348 100644 --- a/util/ieee1275/grub-install.in +++ b/util/ieee1275/grub-install.in @@ -212,7 +212,7 @@ fi # this command is allowed to fail (--target=fs already grants us that the # filesystem will be accessible). partmap_module= -for x in `$grub_probe --target=partmap --device ${grub_device} 2> /dev/null`; do +for x in `$grub_probe --target=partmap --device-map=${device_map} ${grubdir} 2> /dev/null`; do partmap_module="$partmap_module part_$x"; done diff --git a/util/import_unicode.py b/util/import_unicode.py index 1ee162d3f..8d17e7ef6 100644 --- a/util/import_unicode.py +++ b/util/import_unicode.py @@ -18,8 +18,6 @@ import re import sys -import os -import datetime if len (sys.argv) < 3: print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) diff --git a/util/misc.c b/util/misc.c index 91bc25a55..2eff256bf 100644 --- a/util/misc.c +++ b/util/misc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -293,6 +294,28 @@ grub_util_init_nls (void) textdomain (PACKAGE); #endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */ } + +#ifdef HAVE_LIBZFS +libzfs_handle_t *libzfs_handle; + +static void +fini_libzfs (void) +{ + libzfs_fini (libzfs_handle); +} +#endif + +void +grub_util_init_libzfs (void) +{ +#ifdef HAVE_LIBZFS + if (! libzfs_handle) + { + libzfs_handle = libzfs_init (); + atexit (fini_libzfs); + } +#endif +} #endif int