diff --git a/ChangeLog b/ChangeLog index cdf079ce9..0ab39ba8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2012-02-03 Vladimir Serbinenko + + Support install on multi-device filesystems. + + * include/grub/emu/getroot.h (grub_guess_root_device): Renamed to ... + (grub_guess_root_devices): ...this. Return char **. All users updated. + * include/grub/emu/misc.h (grub_find_root_device_from_mountinfo): + Removed. + * util/getroot.c (find_root_device_from_libzfs): Moved pool logic to ... + (find_root_devices_from_poolname): ... here. + (grub_find_root_devices_from_mountinfo): Return char **. Make static. + Support zfs-fuse. + (grub_guess_root_device): Rename to ... + (grub_guess_root_devices): ... this. Return char **. All users updated. + * util/grub-install.in: Handle multi-device filesystems. + * util/grub-probe.c (probe). Make device_names a char **. Add delim + argument. All users updated. + Handle multi-device filesystems. + Use 'delim' as separator. + Remove device check to allow filesystems on file. + (main): Support -0 argument. Handle multi-device. + * util/grub-setup.c (setup): Remove root argument. Handle multi-device. + Fix a cross-device check while on it. + (arguments): Remove root_dev. + (argp_parser): Remove -r. + (main): Remove root_dev. + 2012-02-01 Vladimir Serbinenko * grub-core/fs/zfs/zfscrypt.c: Add link to documentation. diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h index 6921e567c..83455ddda 100644 --- a/include/grub/emu/getroot.h +++ b/include/grub/emu/getroot.h @@ -30,7 +30,7 @@ enum grub_dev_abstraction_types { }; char *grub_find_device (const char *dir, dev_t dev); -char *grub_guess_root_device (const char *dir); +char **grub_guess_root_devices (const char *dir); int grub_util_get_dev_abstraction (const char *os_dev); char *grub_util_get_grub_dev (const char *os_dev); char *grub_make_system_path_relative_to_its_root (const char *path); diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index a9365f6a1..7c4652004 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -80,6 +80,4 @@ extern char * canonicalize_file_name (const char *path); int grub_device_mapper_supported (void); #endif -char *grub_find_root_device_from_mountinfo (const char *dir, char **relroot); - #endif /* GRUB_EMU_MISC_H */ diff --git a/util/getroot.c b/util/getroot.c index cae7611ab..12a11b926 100644 --- a/util/getroot.c +++ b/util/getroot.c @@ -180,6 +180,149 @@ xgetcwd (void) return path; } +static char ** +find_root_devices_from_poolname (char *poolname) +{ + char **devices = 0; + size_t ndevices = 0; + size_t devices_allocated = 0; + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + zpool_handle_t *zpool; + libzfs_handle_t *libzfs; + nvlist_t *config, *vdev_tree; + nvlist_t **children, **path; + unsigned int nvlist_count; + unsigned int i; + char *device = 0; + + libzfs = grub_get_libzfs_handle (); + if (! libzfs) + return NULL; + + zpool = zpool_open (libzfs, poolname); + config = zpool_get_config (zpool, NULL); + + if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0) + error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); + + if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0) + error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); + assert (nvlist_count > 0); + + while (nvlist_lookup_nvlist_array (children[0], "children", + &children, &nvlist_count) == 0) + assert (nvlist_count > 0); + + for (i = 0; i < nvlist_count; i++) + { + if (nvlist_lookup_string (children[i], "path", &device) != 0) + error (1, errno, "nvlist_lookup_string (\"path\")"); + + struct stat st; + if (stat (device, &st) == 0) + { +#ifdef __sun__ + if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1) + == 0) + device = xasprintf ("/dev/rdsk/%s", + device + sizeof ("/dev/dsk/") - 1); + else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1) + == 0 + && grub_memcmp (device + strlen (device) - 4, + ",raw", 4) != 0) + device = xasprintf ("%s,raw", device); + else +#endif + device = xstrdup (device); + if (ndevices >= devices_allocated) + { + devices_allocated = 2 * (devices_allocated + 8); + devices = xrealloc (devices, sizeof (devices[0]) + * devices_allocated); + } + devices[ndevices++] = device; + } + + device = NULL; + } + + zpool_close (zpool); +#else + char *cmd; + FILE *fp; + int ret; + char *line; + size_t len; + int st; + + char name[PATH_MAX + 1], state[257], readlen[257], writelen[257]; + char cksum[257], notes[257]; + unsigned int dummy; + + cmd = xasprintf ("zpool status %s", poolname); + fp = popen (cmd, "r"); + free (cmd); + + st = 0; + while (1) + { + line = NULL; + ret = getline (&line, &len, fp); + if (ret == -1) + break; + + if (sscanf (line, " %s %256s %256s %256s %256s %256s", + name, state, readlen, writelen, cksum, notes) >= 5) + switch (st) + { + case 0: + if (!strcmp (name, "NAME") + && !strcmp (state, "STATE") + && !strcmp (readlen, "READ") + && !strcmp (writelen, "WRITE") + && !strcmp (cksum, "CKSUM")) + st++; + break; + case 1: + if (!strcmp (name, poolname)) + st++; + break; + case 2: + if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy) + && !sscanf (name, "raidz%u", &dummy) + && !strcmp (state, "ONLINE")) + { + char *tmp; + if (ndevices >= devices_allocated) + { + devices_allocated = 2 * (devices_allocated + 8); + devices = xrealloc (devices, sizeof (devices[0]) + * devices_allocated); + } + devices[ndevices++] = xasprintf ("/dev/%s", name); + } + break; + } + + free (line); + } + + pclose (fp); +#endif + if (devices) + { + if (ndevices >= devices_allocated) + { + devices_allocated = 2 * (devices_allocated + 8); + devices = xrealloc (devices, sizeof (devices[0]) + * devices_allocated); + } + devices[ndevices++] = 0; + } + return devices; +} + #ifdef __linux__ #define ESCAPED_PATH_MAX (4 * PATH_MAX) @@ -219,13 +362,13 @@ unescape (char *str) *optr = 0; } -char * -grub_find_root_device_from_mountinfo (const char *dir, char **relroot) +static char ** +grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) { FILE *fp; char *buf = NULL; size_t len = 0; - char *ret = NULL; + char **ret = NULL; int entry_len = 0, entry_max = 4; struct mountinfo_entry *entries; struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" }; @@ -328,9 +471,33 @@ grub_find_root_device_from_mountinfo (const char *dir, char **relroot) if (!*entries[i].device) continue; - ret = strdup (entries[i].device); - if (relroot) - *relroot = strdup (entries[i].enc_root); + if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0) + { + char *slash; + slash = strchr (entries[i].device, '/'); + if (slash) + *slash = 0; + ret = find_root_devices_from_poolname (entries[i].device); + if (slash) + *slash = '/'; + if (relroot) + { + if (!slash) + *relroot = xasprintf ("/@%s", entries[i].enc_root); + else if (strchr (slash + 1, '@')) + *relroot = xasprintf ("/%s%s", slash + 1, entries[i].enc_root); + else + *relroot = xasprintf ("/%s@%s", slash + 1, entries[i].enc_root); + } + } + else + { + ret = xmalloc (2 * sizeof (ret[0])); + ret[0] = strdup (entries[i].device); + ret[1] = 0; + if (relroot) + *relroot = strdup (entries[i].enc_root); + } break; } @@ -342,10 +509,10 @@ grub_find_root_device_from_mountinfo (const char *dir, char **relroot) #endif /* __linux__ */ -static char * -find_root_device_from_libzfs (const char *dir) +static char ** +find_root_devices_from_libzfs (const char *dir) { - char *device = NULL; + char **device = NULL; char *poolname; char *poolfs; @@ -353,119 +520,7 @@ find_root_device_from_libzfs (const char *dir) if (! poolname) return NULL; -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - { - zpool_handle_t *zpool; - libzfs_handle_t *libzfs; - nvlist_t *config, *vdev_tree; - nvlist_t **children, **path; - unsigned int nvlist_count; - unsigned int i; - - libzfs = grub_get_libzfs_handle (); - if (! libzfs) - return NULL; - - zpool = zpool_open (libzfs, poolname); - config = zpool_get_config (zpool, NULL); - - if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0) - error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); - - if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0) - error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); - assert (nvlist_count > 0); - - while (nvlist_lookup_nvlist_array (children[0], "children", - &children, &nvlist_count) == 0) - assert (nvlist_count > 0); - - for (i = 0; i < nvlist_count; i++) - { - if (nvlist_lookup_string (children[i], "path", &device) != 0) - error (1, errno, "nvlist_lookup_string (\"path\")"); - - struct stat st; - if (stat (device, &st) == 0) - { -#ifdef __sun__ - if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1) - == 0) - device = xasprintf ("/dev/rdsk/%s", - device + sizeof ("/dev/dsk/") - 1); - else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1) - == 0 - && grub_memcmp (device + strlen (device) - 4, - ",raw", 4) != 0) - device = xasprintf ("%s,raw", device); - else -#endif - device = xstrdup (device); - break; - } - - device = NULL; - } - - zpool_close (zpool); - } -#else - { - char *cmd; - FILE *fp; - int ret; - char *line; - size_t len; - int st; - - char name[PATH_MAX + 1], state[257], readlen[257], writelen[257]; - char cksum[257], notes[257]; - unsigned int dummy; - - cmd = xasprintf ("zpool status %s", poolname); - fp = popen (cmd, "r"); - free (cmd); - - st = 0; - while (st < 3) - { - line = NULL; - ret = getline (&line, &len, fp); - if (ret == -1) - goto fail; - - if (sscanf (line, " %s %256s %256s %256s %256s %256s", - name, state, readlen, writelen, cksum, notes) >= 5) - switch (st) - { - case 0: - if (!strcmp (name, "NAME") - && !strcmp (state, "STATE") - && !strcmp (readlen, "READ") - && !strcmp (writelen, "WRITE") - && !strcmp (cksum, "CKSUM")) - st++; - break; - case 1: - if (!strcmp (name, poolname)) - st++; - break; - case 2: - if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy) - && !sscanf (name, "raidz%u", &dummy) - && !strcmp (state, "ONLINE")) - st++; - break; - } - - free (line); - } - device = xasprintf ("/dev/%s", name); - - fail: - pclose (fp); - } -#endif + device = find_root_devices_from_poolname (poolname); free (poolname); if (poolfs) @@ -706,10 +761,10 @@ grub_find_device (const char *path, dev_t dev) #endif /* __CYGWIN__ */ -char * -grub_guess_root_device (const char *dir) +char ** +grub_guess_root_devices (const char *dir) { - char *os_dev = NULL; + char **os_dev = NULL; #ifdef __GNU__ file_t file; mach_port_t *ports; @@ -743,9 +798,11 @@ grub_guess_root_device (const char *dir) if (data[name_len - 1] != '\0') grub_util_error (_("Storage name for `%s' not NUL-terminated"), dir); - os_dev = xmalloc (strlen ("/dev/") + data_len); - memcpy (os_dev, "/dev/", strlen ("/dev/")); - memcpy (os_dev + strlen ("/dev/"), data, data_len); + os_dev = xmalloc (2 * sizeof (os_dev[0])); + os_dev[0] = xmalloc (strlen ("/dev/") + data_len); + memcpy (os_dev[0], "/dev/", strlen ("/dev/")); + memcpy (os_dev[0] + strlen ("/dev/"), data, data_len); + os_dev[1] = 0; if (ports && num_ports > 0) { @@ -772,48 +829,56 @@ grub_guess_root_device (const char *dir) #ifdef __linux__ if (!os_dev) - os_dev = grub_find_root_device_from_mountinfo (dir, NULL); + os_dev = grub_find_root_devices_from_mountinfo (dir, NULL); #endif /* __linux__ */ if (!os_dev) - os_dev = find_root_device_from_libzfs (dir); + os_dev = find_root_devices_from_libzfs (dir); if (os_dev) { - char *tmp = os_dev; - os_dev = canonicalize_file_name (os_dev); - free (tmp); - } - - if (os_dev) - { - int dm = (strncmp (os_dev, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0); - int root = (strcmp (os_dev, "/dev/root") == 0); - if (!dm && !root) - return os_dev; - if (stat (os_dev, &st) >= 0) + char **cur; + for (cur = os_dev; *cur; cur++) { - free (os_dev); + char *tmp = *cur; + int root, dm; + *cur = canonicalize_file_name (*cur); + free (tmp); + root = (strcmp (*cur, "/dev/root") == 0); + dm = (strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0); + if (!dm && !root) + continue; + if (stat (*cur, &st) < 0) + break; + free (*cur); dev = st.st_rdev; - return grub_find_device (dm ? "/dev/mapper" : "/dev", dev); + *cur = grub_find_device (dm ? "/dev/mapper" : "/dev", dev); } + if (!*cur) + return os_dev; + for (cur = os_dev; *cur; cur++) + free (*cur); free (os_dev); + os_dev = 0; } if (stat (dir, &st) < 0) grub_util_error (_("cannot stat `%s'"), dir); dev = st.st_dev; + + os_dev = xmalloc (2 * sizeof (os_dev[0])); #ifdef __CYGWIN__ /* Cygwin specific function. */ - os_dev = grub_find_device (dir, dev); + os_dev[0] = grub_find_device (dir, dev); #else /* This might be truly slow, but is there any better way? */ - os_dev = grub_find_device ("/dev", dev); + os_dev[0] = grub_find_device ("/dev", dev); #endif + os_dev[1] = 0; #endif /* !__GNU__ */ return os_dev; @@ -2412,7 +2477,7 @@ grub_make_system_path_relative_to_its_root (const char *path) #ifdef __linux__ { char *bind; - grub_free (grub_find_root_device_from_mountinfo (buf2, &bind)); + grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind)); if (bind && bind[0] && bind[1]) { buf3 = bind; @@ -2445,7 +2510,7 @@ grub_make_system_path_relative_to_its_root (const char *path) #ifdef __linux__ { char *bind; - grub_free (grub_find_root_device_from_mountinfo (buf2, &bind)); + grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind)); if (bind && bind[0] && bind[1]) { char *temp = buf3; diff --git a/util/grub-install.in b/util/grub-install.in index 7e4bf1512..9d219bb93 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -473,7 +473,7 @@ if ! test -f "${grubdir}"/grubenv; then fi # Create the core image. First, auto-detect the filesystem module. -fs_module="`"$grub_probe" --device-map="${device_map}" --target=fs --device "${grub_device}"`" +fs_module="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=fs --device `" if test "x$fs_module" = x ; then echo "Auto-detection of a filesystem of ${grub_device} failed." 1>&2 echo "Try with --recheck." 1>&2 @@ -485,7 +485,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" --device-map="${device_map}" --target=partmap --device "${grub_device}" 2> /dev/null`; do +for x in `echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=partmap --device 2> /dev/null`; do case "$x" in netbsd | openbsd) partmap_module="$partmap_module part_bsd";; @@ -496,7 +496,7 @@ for x in `"$grub_probe" --device-map="${device_map}" --target=partmap --device " done # Device abstraction module, if any (lvm, raid). -devabstraction_module="`"$grub_probe" --device-map="${device_map}" --target=abstraction --device "${grub_device}"`" +devabstraction_module="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=abstraction --device`" if [ "x$disk_module" = xata ]; then disk_module=pata @@ -538,14 +538,14 @@ if [ "x${devabstraction_module}" = "x" ] ; then fi install_drive="`echo "${install_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`" fi - grub_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${grub_device}"`" || exit 1 + grub_drive="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=drive --device`" || exit 1 # Strip partition number grub_partition="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\3/'`" grub_drive="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`" if ([ "x$disk_module" != x ] && [ "x$disk_module" != xbiosdisk ]) || [ "x${grub_drive}" != "x${install_drive}" ] || ([ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${platform}" != x"ieee1275" ]); then # generic method (used on coreboot and ata mod) - uuid="`"$grub_probe" --device-map="${device_map}" --target=fs_uuid --device "${grub_device}"`" + uuid="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=fs_uuid --device`" if [ "x${uuid}" = "x" ] ; then if [ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${platform}" != x"ieee1275" ]; then echo "UUID needed with $platform, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 @@ -559,15 +559,15 @@ if [ "x${devabstraction_module}" = "x" ] ; then fi if [ x"$disk_module" != x ] && [ x"$disk_module" != xbiosdisk ]; then - hints="`"$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device "${grub_device}"`" + hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`" elif [ x"$platform" = xpc ]; then - hints="`"$grub_probe" --device-map="${device_map}" --target=bios_hints --device "${grub_device}"`" + hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=bios_hints --device`" elif [ x"$platform" = xefi ]; then - hints="`"$grub_probe" --device-map="${device_map}" --target=efi_hints --device "${grub_device}"`" + hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=efi_hints --device`" elif [ x"$platform" = xieee1275 ]; then - hints="`"$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device "${grub_device}"`" + hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device`" elif [ x"$platform" = xloongson ] || [ x"$platform" = xqemu ] || [ x"$platform" = xcoreboot ] || [ x"$platform" = xmultiboot ] || [ x"$platform" = xqemu-mips ]; then - hints="`"$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device "${grub_device}"`" + hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`" else echo "No hints available for your platform. Expect reduced performance" hints= @@ -587,7 +587,7 @@ if [ "x${devabstraction_module}" = "x" ] ; then fi else if [ x$GRUB_CRYPTODISK_ENABLE = xy ]; then - for uuid in "`"${grub_probe}" --device "${grub_device}" --target=cryptodisk_uuid`"; do + for uuid in "`echo "${grub_device}" | xargs "${grub_probe}" --target=cryptodisk_uuid --device`"; do echo "cryptomount -u $uuid" >> "${grubdir}/load.cfg" done config_opt="-c ${grubdir}/load.cfg " diff --git a/util/grub-probe.c b/util/grub-probe.c index 17edff6ce..1d1a82230 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -313,307 +313,342 @@ probe_abstraction (grub_disk_t disk) } static void -probe (const char *path, char *device_name) +probe (const char *path, char **device_names, char delim) { - char *drive_name = NULL; + char **drives_names = NULL; + char **curdev, **curdrive; char *grub_path = NULL; - char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL; - grub_device_t dev = NULL; - grub_fs_t fs; + int ndev = 0; - if (path == NULL) - { -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__sun__) - if (! grub_util_check_char_device (device_name)) - grub_util_error (_("%s is not a character device"), device_name); -#else - if (! grub_util_check_block_device (device_name)) - grub_util_error (_("%s is not a block device"), device_name); -#endif - } - else + if (path != NULL) { grub_path = canonicalize_file_name (path); - device_name = grub_guess_root_device (grub_path); + device_names = grub_guess_root_devices (grub_path); + free (grub_path); } - if (! device_name) + if (! device_names) grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path); if (print == PRINT_DEVICE) { - printf ("%s\n", device_name); - goto end; - } - - drive_name = grub_util_get_grub_dev (device_name); - if (! drive_name) - grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), - device_name); - - if (print == PRINT_DRIVE) - { - printf ("(%s)\n", drive_name); - goto end; - } - - grub_util_info ("opening %s", drive_name); - dev = grub_device_open (drive_name); - if (! dev) - grub_util_error ("%s", _(grub_errmsg)); - - if (print == PRINT_HINT_STR) - { - const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); - const char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0; - char *biosname, *bare, *efi; - const char *map; - - if (ofpath) + for (curdev = device_names; *curdev; curdev++) { - printf ("--hint-ieee1275='"); - print_full_name (ofpath, dev); - printf ("' "); + printf ("%s", *curdev); + putchar (delim); } - - biosname = guess_bios_drive (device_name); - if (biosname) - { - printf ("--hint-bios="); - print_full_name (biosname, dev); - printf (" "); - } - free (biosname); - - efi = guess_efi_drive (device_name); - if (efi) - { - printf ("--hint-efi="); - print_full_name (efi, dev); - printf (" "); - } - free (efi); - - bare = guess_baremetal_drive (device_name); - if (bare) - { - printf ("--hint-baremetal="); - print_full_name (bare, dev); - printf (" "); - } - free (bare); - - /* FIXME: Add ARC hint. */ - - map = grub_util_biosdisk_get_compatibility_hint (dev->disk); - if (map) - { - printf ("--hint='"); - print_full_name (map, dev); - printf ("' "); - } - printf ("\n"); - - goto end; + return; } - if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT - || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT - || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) - && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) + for (curdev = device_names; *curdev; curdev++) { - print_full_name (dev->disk->name, dev); - printf ("\n"); - goto end; + grub_util_pull_device (*curdev); + ndev++; } + + drives_names = xmalloc (sizeof (drives_names[0]) * (ndev + 1)); - if (print == PRINT_COMPATIBILITY_HINT) + for (curdev = device_names, curdrive = drives_names; *curdev; curdev++, + curdrive++) { - const char *map; - char *biosname; - map = grub_util_biosdisk_get_compatibility_hint (dev->disk); - if (map) - { - print_full_name (map, dev); - printf ("\n"); - goto end; - } - biosname = guess_bios_drive (device_name); - if (biosname) - print_full_name (biosname, dev); - printf ("\n"); - free (biosname); - goto end; + *curdrive = grub_util_get_grub_dev (*curdev); + if (! *curdrive) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + *curdev); } + *curdrive = 0; - if (print == PRINT_BIOS_HINT) + if (print == PRINT_FS || print == PRINT_FS_UUID + || print == PRINT_FS_LABEL) { - char *biosname; - biosname = guess_bios_drive (device_name); - if (biosname) - print_full_name (biosname, dev); - printf ("\n"); - free (biosname); - goto end; - } - if (print == PRINT_IEEE1275_HINT) - { - const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); - const char *ofpath = grub_util_devname_to_ofpath (osdev); - const char *map; + grub_device_t dev = NULL; + grub_fs_t fs; - map = grub_util_biosdisk_get_compatibility_hint (dev->disk); - if (map) - { - printf (" "); - print_full_name (map, dev); - } - - if (ofpath) - { - printf (" "); - print_full_name (ofpath, dev); - } - - printf ("\n"); - goto end; - } - if (print == PRINT_EFI_HINT) - { - char *biosname; - char *name; - const char *map; - biosname = guess_efi_drive (device_name); - - map = grub_util_biosdisk_get_compatibility_hint (dev->disk); - if (map) - { - printf (" "); - print_full_name (map, dev); - } - if (biosname) - { - printf (" "); - print_full_name (biosname, dev); - } - - printf ("\n"); - free (biosname); - goto end; - } - - if (print == PRINT_BAREMETAL_HINT) - { - char *biosname; - char *name; - const char *map; - - biosname = guess_baremetal_drive (device_name); - - map = grub_util_biosdisk_get_compatibility_hint (dev->disk); - if (map) - { - printf (" "); - print_full_name (map, dev); - } - if (biosname) - { - printf (" "); - print_full_name (biosname, dev); - } - - printf ("\n"); - free (biosname); - goto end; - } - - if (print == PRINT_ARC_HINT) - { - const char *map; - - map = grub_util_biosdisk_get_compatibility_hint (dev->disk); - if (map) - { - printf (" "); - print_full_name (map, dev); - } - printf ("\n"); - - /* FIXME */ - - goto end; - } - - if (print == PRINT_ABSTRACTION) - { - probe_abstraction (dev->disk); - printf ("\n"); - goto end; - } - - if (print == PRINT_CRYPTODISK_UUID) - { - probe_cryptodisk_uuid (dev->disk); - printf ("\n"); - goto end; - } - - if (print == PRINT_PARTMAP) - { - /* Check if dev->disk itself is contained in a partmap. */ - probe_partmap (dev->disk); - printf ("\n"); - goto end; - } - - if (print == PRINT_MSDOS_PARTTYPE) - { - if (dev->disk->partition - && strcmp(dev->disk->partition->partmap->name, "msdos") == 0) - printf ("%02x", dev->disk->partition->msdostype); - - printf ("\n"); - goto end; - } - - fs = grub_fs_probe (dev); - if (! fs) - grub_util_error ("%s", _(grub_errmsg)); - - if (print == PRINT_FS) - { - printf ("%s\n", fs->name); - } - else if (print == PRINT_FS_UUID) - { - char *uuid; - if (! fs->uuid) - grub_util_error (_("%s does not support UUIDs"), fs->name); - - if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) - grub_util_error ("%s", grub_errmsg); - - 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); - - if (fs->label (dev, &label) != GRUB_ERR_NONE) + grub_util_info ("opening %s", drives_names[0]); + dev = grub_device_open (drives_names[0]); + if (! dev) + grub_util_error ("%s", _(grub_errmsg)); + + fs = grub_fs_probe (dev); + if (! fs) grub_util_error ("%s", _(grub_errmsg)); - printf ("%s\n", label); + if (print == PRINT_FS) + { + printf ("%s", fs->name); + putchar (delim); + } + else if (print == PRINT_FS_UUID) + { + char *uuid; + if (! fs->uuid) + grub_util_error (_("%s does not support UUIDs"), fs->name); + + if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + printf ("%s", uuid); + putchar (delim); + } + else if (print == PRINT_FS_LABEL) + { + char *label; + if (! fs->label) + grub_util_error (_("%s does not support labels"), fs->name); + + if (fs->label (dev, &label) != GRUB_ERR_NONE) + grub_util_error ("%s", _(grub_errmsg)); + + printf ("%s", label); + putchar (delim); + } + goto end; + } + + for (curdrive = drives_names, curdev = device_names; *curdrive; + curdrive++, curdev++) + { + grub_device_t dev = NULL; + + grub_util_info ("opening %s", *curdrive); + dev = grub_device_open (*curdrive); + if (! dev) + grub_util_error ("%s", _(grub_errmsg)); + + if (print == PRINT_HINT_STR) + { + const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); + const char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0; + char *biosname, *bare, *efi; + const char *map; + + if (ofpath) + { + printf ("--hint-ieee1275='"); + print_full_name (ofpath, dev); + printf ("' "); + } + + biosname = guess_bios_drive (*curdev); + if (biosname) + { + printf ("--hint-bios="); + print_full_name (biosname, dev); + printf (" "); + } + free (biosname); + + efi = guess_efi_drive (*curdev); + if (efi) + { + printf ("--hint-efi="); + print_full_name (efi, dev); + printf (" "); + } + free (efi); + + bare = guess_baremetal_drive (*curdev); + if (bare) + { + printf ("--hint-baremetal="); + print_full_name (bare, dev); + printf (" "); + } + free (bare); + + /* FIXME: Add ARC hint. */ + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf ("--hint='"); + print_full_name (map, dev); + printf ("' "); + } + printf ("\n"); + + grub_device_close (dev); + continue; + } + + if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT + || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT + || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) + && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) + { + print_full_name (dev->disk->name, dev); + putchar (delim); + continue; + } + + if (print == PRINT_COMPATIBILITY_HINT) + { + const char *map; + char *biosname; + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + print_full_name (map, dev); + putchar (delim); + grub_device_close (dev); + /* Compatibility hint is one device only. */ + break; + } + biosname = guess_bios_drive (*curdev); + if (biosname) + { + print_full_name (biosname, dev); + putchar (delim); + } + free (biosname); + grub_device_close (dev); + /* Compatibility hint is one device only. */ + if (biosname) + break; + continue; + } + + if (print == PRINT_BIOS_HINT) + { + char *biosname; + biosname = guess_bios_drive (*curdev); + if (biosname) + { + print_full_name (biosname, dev); + putchar (delim); + } + free (biosname); + grub_device_close (dev); + continue; + } + if (print == PRINT_IEEE1275_HINT) + { + const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); + const char *ofpath = grub_util_devname_to_ofpath (osdev); + const char *map; + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + print_full_name (map, dev); + putchar (delim); + } + + if (ofpath) + { + print_full_name (ofpath, dev); + putchar (delim); + } + + grub_device_close (dev); + continue; + } + if (print == PRINT_EFI_HINT) + { + char *biosname; + char *name; + const char *map; + biosname = guess_efi_drive (*curdev); + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + print_full_name (map, dev); + putchar (delim); + } + if (biosname) + { + print_full_name (biosname, dev); + putchar (delim); + } + + free (biosname); + grub_device_close (dev); + continue; + } + + if (print == PRINT_BAREMETAL_HINT) + { + char *biosname; + char *name; + const char *map; + + biosname = guess_baremetal_drive (*curdev); + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + print_full_name (map, dev); + putchar (delim); + } + if (biosname) + { + print_full_name (biosname, dev); + putchar (delim); + } + + free (biosname); + grub_device_close (dev); + continue; + } + + if (print == PRINT_ARC_HINT) + { + const char *map; + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + print_full_name (map, dev); + putchar (delim); + } + + /* FIXME */ + grub_device_close (dev); + continue; + } + + if (print == PRINT_ABSTRACTION) + { + probe_abstraction (dev->disk); + putchar (delim); + grub_device_close (dev); + continue; + } + + if (print == PRINT_CRYPTODISK_UUID) + { + probe_cryptodisk_uuid (dev->disk); + putchar (delim); + grub_device_close (dev); + continue; + } + + if (print == PRINT_PARTMAP) + { + /* Check if dev->disk itself is contained in a partmap. */ + probe_partmap (dev->disk); + putchar (delim); + grub_device_close (dev); + continue; + } + + if (print == PRINT_MSDOS_PARTTYPE) + { + if (dev->disk->partition + && strcmp(dev->disk->partition->partmap->name, "msdos") == 0) + printf ("%02x", dev->disk->partition->msdostype); + + putchar (delim); + grub_device_close (dev); + continue; + } } end: - if (dev) - grub_device_close (dev); - free (grub_path); - free (filebuf_via_grub); - free (filebuf_via_sys); - free (drive_name); + for (curdrive = drives_names; *curdrive; curdrive++) + free (*curdrive); + free (drives_names); } static struct option options[] = @@ -658,7 +693,8 @@ int main (int argc, char *argv[]) { char *dev_map = 0; - char *argument; + int zero_delim = 0; + char delim; set_program_name (argv[0]); @@ -667,7 +703,7 @@ main (int argc, char *argv[]) /* Check for options. */ while (1) { - int c = getopt_long (argc, argv, "dm:t:hVv", options, 0); + int c = getopt_long (argc, argv, "dm:t:hVv0", options, 0); if (c == -1) break; @@ -726,6 +762,10 @@ main (int argc, char *argv[]) usage (0); break; + case '0': + zero_delim = 1; + break; + case 'V': printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); return 0; @@ -750,14 +790,12 @@ main (int argc, char *argv[]) usage (1); } - if (optind + 1 != argc) + if (optind + 1 != argc && !argument_is_device) { fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind + 1]); usage (1); } - argument = argv[optind]; - /* Initialize the emulated biosdisk driver. */ grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); @@ -774,11 +812,28 @@ main (int argc, char *argv[]) grub_mdraid1x_init (); grub_lvm_init (); + if (print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT + || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT + || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) + delim = ' '; + else + delim = '\n'; + + if (zero_delim) + delim = '\0'; + /* Do it. */ if (argument_is_device) - probe (NULL, argument); + probe (NULL, argv + optind, delim); else - probe (argument, NULL); + probe (argv[optind], NULL, delim); + + if (!zero_delim && (print == PRINT_COMPATIBILITY_HINT + || print == PRINT_BIOS_HINT + || print == PRINT_IEEE1275_HINT + || print == PRINT_BAREMETAL_HINT + || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT)) + putchar ('\n'); /* Free resources. */ grub_gcry_fini_all (); diff --git a/util/grub-setup.c b/util/grub-setup.c index 3db3d1f96..a50b0efed 100644 --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -133,15 +133,16 @@ write_rootdev (char *core_img, grub_device_t root_dev, static void setup (const char *dir, const char *boot_file, const char *core_file, - const char *root, const char *dest, int force, + const char *dest, int force, int fs_probe, int allow_floppy) { char *boot_path, *core_path, *core_path_dev, *core_path_dev_full; char *boot_img, *core_img; + char *root = 0; size_t boot_size, core_size; grub_uint16_t core_sectors; - grub_device_t root_dev, dest_dev; - struct grub_boot_blocklist *first_block, *block; + grub_device_t root_dev = 0, dest_dev; + struct grub_boot_blocklist *first_block, *block, *last_block; char *tmp_img; int i; grub_disk_addr_t first_sector; @@ -235,17 +236,56 @@ setup (const char *dir, - sizeof (*block)); grub_util_info ("root is `%s', dest is `%s'", root, dest); - /* Open the root device and the destination device. */ - grub_util_info ("Opening root"); - root_dev = grub_device_open (root); - if (! root_dev) - grub_util_error ("%s", _(grub_errmsg)); - grub_util_info ("Opening dest"); dest_dev = grub_device_open (dest); if (! dest_dev) grub_util_error ("%s", _(grub_errmsg)); + { + char **root_devices = grub_guess_root_devices (dir); + char **cur; + int found = 0; + + for (cur = root_devices; *cur; cur++) + { + char *drive; + grub_device_t try_dev; + + drive = grub_util_get_grub_dev (*cur); + if (!drive) + continue; + try_dev = grub_device_open (drive); + if (! try_dev) + continue; + if (!found && try_dev->disk->id == dest_dev->disk->id + && try_dev->disk->dev->id == dest_dev->disk->dev->id) + { + if (root_dev) + grub_device_close (root_dev); + free (root); + root_dev = try_dev; + root = drive; + found = 1; + continue; + } + if (!root_dev) + { + root_dev = try_dev; + root = drive; + continue; + } + grub_device_close (try_dev); + free (drive); + } + if (!root_dev) + { + grub_util_error ("guessing the root device failed, because of `%s'", + grub_errmsg); + } + grub_util_info ("guessed root_dev `%s' from " + "dir `%s'", root_dev->disk->name, dir); + } + grub_util_info ("setting the root device to `%s'", root); if (grub_env_set ("root", root) != GRUB_ERR_NONE) grub_util_error ("%s", _(grub_errmsg)); @@ -636,11 +676,12 @@ unable_to_embed: boot_devpath = (char *) (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE + GRUB_BOOT_MACHINE_BOOT_DEVPATH); - if (file->device->disk->id != dest_dev->disk->id) + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) { const char *dest_ofpath; dest_ofpath - = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk)); grub_util_info ("dest_ofpath is `%s'", dest_ofpath); strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); @@ -741,7 +782,6 @@ struct arguments char *core_file; char *dir; char *dev_map; - char *root_dev; int force; int fs_probe; int allow_floppy; @@ -802,13 +842,6 @@ argp_parser (int key, char *arg, struct argp_state *state) arguments->dev_map = xstrdup (arg); break; - case 'r': - if (arguments->root_dev) - free (arguments->root_dev); - - arguments->root_dev = xstrdup (arg); - break; - case 'f': arguments->force = 1; break; @@ -935,38 +968,11 @@ main (int argc, char *argv[]) grub_util_info ("Using `%s' as GRUB device", dest_dev); } - if (arguments.root_dev) - { - root_dev = get_device_name (arguments.root_dev); - - if (! root_dev) - grub_util_error (_("invalid root device `%s'"), arguments.root_dev); - - root_dev = xstrdup (root_dev); - } - else - { - char *root_device = - grub_guess_root_device (arguments.dir ? : DEFAULT_DIRECTORY); - - root_dev = grub_util_get_grub_dev (root_device); - if (! root_dev) - { - grub_util_info ("guessing the root device failed, because of `%s'", - grub_errmsg); - grub_util_error (_("cannot guess the root device. Specify the option " - "`--root-device'")); - } - grub_util_info ("guessed root device `%s' and root_dev `%s' from " - "dir `%s'", root_device, root_dev, - arguments.dir ? : DEFAULT_DIRECTORY); - } - /* Do the real work. */ setup (arguments.dir ? : DEFAULT_DIRECTORY, arguments.boot_file ? : DEFAULT_BOOT_FILE, arguments.core_file ? : DEFAULT_CORE_FILE, - root_dev, dest_dev, arguments.force, + dest_dev, arguments.force, arguments.fs_probe, arguments.allow_floppy); /* Free resources. */ @@ -976,7 +982,6 @@ main (int argc, char *argv[]) free (arguments.boot_file); free (arguments.core_file); free (arguments.dir); - free (arguments.root_dev); free (arguments.dev_map); free (arguments.device); free (root_dev);