1 /* grub-probe.c - probe device information for a given path */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/emu/misc.h>
23 #include <grub/util/misc.h>
24 #include <grub/device.h>
25 #include <grub/disk.h>
26 #include <grub/file.h>
28 #include <grub/partition.h>
29 #include <grub/msdos_partition.h>
30 #include <grub/emu/hostdisk.h>
31 #include <grub/emu/getroot.h>
32 #include <grub/term.h>
34 #include <grub/diskfilter.h>
35 #include <grub/i18n.h>
36 #include <grub/emu/misc.h>
37 #include <grub/util/ofpath.h>
38 #include <grub/crypto.h>
39 #include <grub/cryptodisk.h>
61 PRINT_CRYPTODISK_UUID
,
68 PRINT_COMPATIBILITY_HINT
,
73 static int print
= PRINT_FS
;
74 static unsigned int argument_is_device
= 0;
77 probe_partmap (grub_disk_t disk
)
79 grub_partition_t part
;
80 grub_disk_memberlist_t list
= NULL
, tmp
;
82 if (disk
->partition
== NULL
)
84 grub_util_info ("no partition map found for %s", disk
->name
);
87 for (part
= disk
->partition
; part
; part
= part
->parent
)
88 printf ("%s ", part
->partmap
->name
);
90 /* In case of LVM/RAID, check the member devices as well. */
91 if (disk
->dev
->memberlist
)
93 list
= disk
->dev
->memberlist (disk
);
97 probe_partmap (list
->disk
);
105 probe_cryptodisk_uuid (grub_disk_t disk
)
107 grub_disk_memberlist_t list
= NULL
, tmp
;
109 /* In case of LVM/RAID, check the member devices as well. */
110 if (disk
->dev
->memberlist
)
112 list
= disk
->dev
->memberlist (disk
);
116 probe_cryptodisk_uuid (list
->disk
);
121 if (disk
->dev
->id
== GRUB_DISK_DEVICE_CRYPTODISK_ID
)
122 grub_util_cryptodisk_print_uuid (disk
);
126 probe_raid_level (grub_disk_t disk
)
128 /* disk might be NULL in the case of a LVM physical volume with no LVM
129 signature. Ignore such cases here. */
133 if (disk
->dev
->id
!= GRUB_DISK_DEVICE_DISKFILTER_ID
)
136 if (disk
->name
[0] != 'm' || disk
->name
[1] != 'd')
139 if (!((struct grub_diskfilter_lv
*) disk
->data
)->segments
)
141 return ((struct grub_diskfilter_lv
*) disk
->data
)->segments
->type
;
144 /* Since OF path names can have "," characters in them, and GRUB
145 internally uses "," to indicate partitions (unlike OF which uses
146 ":" for this purpose) we escape such commas. */
148 escape_of_path (const char *orig_path
)
150 char *new_path
, *d
, c
;
153 if (!strchr (orig_path
, ','))
154 return (char *) xstrdup (orig_path
);
156 new_path
= xmalloc (strlen (orig_path
) * 2 + sizeof ("ieee1275/"));
159 grub_strcpy (new_path
, "ieee1275/");
160 d
= new_path
+ sizeof ("ieee1275/") - 1;
161 while ((c
= *p
++) != '\0')
169 free ((char *) orig_path
);
175 guess_bios_drive (const char *orig_path
)
179 canon
= canonicalize_file_name (orig_path
);
182 ptr
= strrchr (orig_path
, '/');
187 if ((ptr
[0] == 's' || ptr
[0] == 'h') && ptr
[1] == 'd')
189 int num
= ptr
[2] - 'a';
191 return xasprintf ("hd%d", num
);
193 if (ptr
[0] == 'f' && ptr
[1] == 'd')
195 int num
= atoi (ptr
+ 2);
197 return xasprintf ("fd%d", num
);
204 guess_efi_drive (const char *orig_path
)
208 canon
= canonicalize_file_name (orig_path
);
211 ptr
= strrchr (orig_path
, '/');
216 if ((ptr
[0] == 's' || ptr
[0] == 'h') && ptr
[1] == 'd')
218 int num
= ptr
[2] - 'a';
220 return xasprintf ("hd%d", num
);
222 if (ptr
[0] == 'f' && ptr
[1] == 'd')
224 int num
= atoi (ptr
+ 2);
226 return xasprintf ("fd%d", num
);
233 guess_baremetal_drive (const char *orig_path
)
237 canon
= canonicalize_file_name (orig_path
);
240 ptr
= strrchr (orig_path
, '/');
245 if (ptr
[0] == 'h' && ptr
[1] == 'd')
247 int num
= ptr
[2] - 'a';
249 return xasprintf ("ata%d", num
);
251 if (ptr
[0] == 's' && ptr
[1] == 'd')
253 int num
= ptr
[2] - 'a';
255 return xasprintf ("ahci%d", num
);
262 print_full_name (const char *drive
, grub_device_t dev
)
264 char *dname
= escape_of_path (drive
);
265 if (dev
->disk
->partition
)
267 char *pname
= grub_partition_get_name (dev
->disk
->partition
);
268 printf ("%s,%s", dname
, pname
);
272 printf ("%s", dname
);
277 probe_abstraction (grub_disk_t disk
)
279 grub_disk_memberlist_t list
= NULL
, tmp
;
282 if (disk
->dev
->memberlist
)
283 list
= disk
->dev
->memberlist (disk
);
286 probe_abstraction (list
->disk
);
293 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
294 && grub_memcmp (disk
->name
, "lvm/", sizeof ("lvm/") - 1) == 0)
297 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
298 && grub_memcmp (disk
->name
, "ldm/", sizeof ("ldm/") - 1) == 0)
301 if (disk
->dev
->id
== GRUB_DISK_DEVICE_CRYPTODISK_ID
)
302 grub_util_cryptodisk_print_abstraction (disk
);
304 raid_level
= probe_raid_level (disk
);
308 if (disk
->dev
->raidname
)
309 printf ("%s ", disk
->dev
->raidname (disk
));
312 printf ("raid5rec ");
314 printf ("raid6rec ");
318 probe (const char *path
, char **device_names
, char delim
)
320 char **drives_names
= NULL
;
321 char **curdev
, **curdrive
;
322 char *grub_path
= NULL
;
327 grub_path
= canonicalize_file_name (path
);
329 grub_util_error (_("failed to get canonical path of %s"), path
);
330 device_names
= grub_guess_root_devices (grub_path
);
335 grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path
);
337 if (print
== PRINT_DEVICE
)
339 for (curdev
= device_names
; *curdev
; curdev
++)
341 printf ("%s", *curdev
);
347 if (print
== PRINT_DISK
)
349 for (curdev
= device_names
; *curdev
; curdev
++)
352 disk
= grub_util_get_os_disk (*curdev
);
364 for (curdev
= device_names
; *curdev
; curdev
++)
366 grub_util_pull_device (*curdev
);
370 drives_names
= xmalloc (sizeof (drives_names
[0]) * (ndev
+ 1));
372 for (curdev
= device_names
, curdrive
= drives_names
; *curdev
; curdev
++,
375 *curdrive
= grub_util_get_grub_dev (*curdev
);
377 grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"),
382 if (print
== PRINT_DRIVE
)
384 for (curdrive
= drives_names
; *curdrive
; curdrive
++)
386 printf ("(%s)", *curdrive
);
392 if (print
== PRINT_FS
|| print
== PRINT_FS_UUID
393 || print
== PRINT_FS_LABEL
)
395 grub_device_t dev
= NULL
;
398 grub_util_info ("opening %s", drives_names
[0]);
399 dev
= grub_device_open (drives_names
[0]);
401 grub_util_error ("%s", _(grub_errmsg
));
403 fs
= grub_fs_probe (dev
);
405 grub_util_error ("%s", _(grub_errmsg
));
407 if (print
== PRINT_FS
)
409 printf ("%s", fs
->name
);
412 else if (print
== PRINT_FS_UUID
)
416 grub_util_error (_("%s does not support UUIDs"), fs
->name
);
418 if (fs
->uuid (dev
, &uuid
) != GRUB_ERR_NONE
)
419 grub_util_error ("%s", grub_errmsg
);
424 else if (print
== PRINT_FS_LABEL
)
428 grub_util_error (_("%s does not support labels"), fs
->name
);
430 if (fs
->label (dev
, &label
) != GRUB_ERR_NONE
)
431 grub_util_error ("%s", _(grub_errmsg
));
433 printf ("%s", label
);
439 for (curdrive
= drives_names
, curdev
= device_names
; *curdrive
;
440 curdrive
++, curdev
++)
442 grub_device_t dev
= NULL
;
444 grub_util_info ("opening %s", *curdrive
);
445 dev
= grub_device_open (*curdrive
);
447 grub_util_error ("%s", _(grub_errmsg
));
449 if (print
== PRINT_HINT_STR
)
451 const char *osdev
= grub_util_biosdisk_get_osdev (dev
->disk
);
452 const char *ofpath
= osdev
? grub_util_devname_to_ofpath (osdev
) : 0;
453 char *biosname
, *bare
, *efi
;
458 printf ("--hint-ieee1275='");
459 print_full_name (ofpath
, dev
);
463 biosname
= guess_bios_drive (*curdev
);
466 printf ("--hint-bios=");
467 print_full_name (biosname
, dev
);
472 efi
= guess_efi_drive (*curdev
);
475 printf ("--hint-efi=");
476 print_full_name (efi
, dev
);
481 bare
= guess_baremetal_drive (*curdev
);
484 printf ("--hint-baremetal=");
485 print_full_name (bare
, dev
);
490 /* FIXME: Add ARC hint. */
492 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
496 print_full_name (map
, dev
);
501 grub_device_close (dev
);
505 if ((print
== PRINT_COMPATIBILITY_HINT
|| print
== PRINT_BIOS_HINT
506 || print
== PRINT_IEEE1275_HINT
|| print
== PRINT_BAREMETAL_HINT
507 || print
== PRINT_EFI_HINT
|| print
== PRINT_ARC_HINT
)
508 && dev
->disk
->dev
->id
!= GRUB_DISK_DEVICE_HOSTDISK_ID
)
510 print_full_name (dev
->disk
->name
, dev
);
515 if (print
== PRINT_COMPATIBILITY_HINT
)
519 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
522 print_full_name (map
, dev
);
524 grub_device_close (dev
);
525 /* Compatibility hint is one device only. */
528 biosname
= guess_bios_drive (*curdev
);
531 print_full_name (biosname
, dev
);
535 grub_device_close (dev
);
536 /* Compatibility hint is one device only. */
542 if (print
== PRINT_BIOS_HINT
)
545 biosname
= guess_bios_drive (*curdev
);
548 print_full_name (biosname
, dev
);
552 grub_device_close (dev
);
555 if (print
== PRINT_IEEE1275_HINT
)
557 const char *osdev
= grub_util_biosdisk_get_osdev (dev
->disk
);
558 const char *ofpath
= grub_util_devname_to_ofpath (osdev
);
561 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
564 print_full_name (map
, dev
);
570 print_full_name (ofpath
, dev
);
574 grub_device_close (dev
);
577 if (print
== PRINT_EFI_HINT
)
582 biosname
= guess_efi_drive (*curdev
);
584 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
587 print_full_name (map
, dev
);
592 print_full_name (biosname
, dev
);
597 grub_device_close (dev
);
601 if (print
== PRINT_BAREMETAL_HINT
)
607 biosname
= guess_baremetal_drive (*curdev
);
609 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
612 print_full_name (map
, dev
);
617 print_full_name (biosname
, dev
);
622 grub_device_close (dev
);
626 if (print
== PRINT_ARC_HINT
)
630 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
633 print_full_name (map
, dev
);
638 grub_device_close (dev
);
642 if (print
== PRINT_ABSTRACTION
)
644 probe_abstraction (dev
->disk
);
646 grub_device_close (dev
);
650 if (print
== PRINT_CRYPTODISK_UUID
)
652 probe_cryptodisk_uuid (dev
->disk
);
654 grub_device_close (dev
);
658 if (print
== PRINT_PARTMAP
)
660 /* Check if dev->disk itself is contained in a partmap. */
661 probe_partmap (dev
->disk
);
663 grub_device_close (dev
);
667 if (print
== PRINT_MSDOS_PARTTYPE
)
669 if (dev
->disk
->partition
670 && strcmp(dev
->disk
->partition
->partmap
->name
, "msdos") == 0)
671 printf ("%02x", dev
->disk
->partition
->msdostype
);
674 grub_device_close (dev
);
680 for (curdrive
= drives_names
; *curdrive
; curdrive
++)
685 static struct argp_option options
[] = {
686 {"device", 'd', 0, 0,
687 N_("given argument is a system device, not a path"), 0},
688 {"device-map", 'm', N_("FILE"), 0,
689 N_("use FILE as the device map [default=%s]"), 0},
690 {"target", 't', "(fs|fs_uuid|fs_label|drive|device|partmap|abstraction|cryptodisk_uuid|msdos_parttype)", 0,
691 N_("print filesystem module, GRUB drive, system device, partition map module, abstraction module or CRYPTO UUID [default=fs]"), 0},
692 {"verbose", 'v', 0, 0, N_("Print verbose messages."), 0},
698 help_filter (int key
, const char *text
, void *input
__attribute__ ((unused
)))
703 return xasprintf (text
, DEFAULT_DEVICE_MAP
);
706 return (char *) text
;
720 argp_parser (int key
, char *arg
, struct argp_state
*state
)
722 /* Get the input argument from argp_parse, which we
723 know is a pointer to our arguments structure. */
724 struct arguments
*arguments
= state
->input
;
731 argument_is_device
= 1;
735 if (arguments
->dev_map
)
736 free (arguments
->dev_map
);
738 arguments
->dev_map
= xstrdup (arg
);
742 if (!strcmp (arg
, "fs"))
744 else if (!strcmp (arg
, "fs_uuid"))
745 print
= PRINT_FS_UUID
;
746 else if (!strcmp (arg
, "fs_label"))
747 print
= PRINT_FS_LABEL
;
748 else if (!strcmp (arg
, "drive"))
750 else if (!strcmp (arg
, "device"))
751 print
= PRINT_DEVICE
;
752 else if (!strcmp (arg
, "partmap"))
753 print
= PRINT_PARTMAP
;
754 else if (!strcmp (arg
, "abstraction"))
755 print
= PRINT_ABSTRACTION
;
756 else if (!strcmp (arg
, "cryptodisk_uuid"))
757 print
= PRINT_CRYPTODISK_UUID
;
758 else if (!strcmp (arg
, "msdos_parttype"))
759 print
= PRINT_MSDOS_PARTTYPE
;
760 else if (!strcmp (arg
, "hints_string"))
761 print
= PRINT_HINT_STR
;
762 else if (!strcmp (arg
, "bios_hints"))
763 print
= PRINT_BIOS_HINT
;
764 else if (!strcmp (arg
, "ieee1275_hints"))
765 print
= PRINT_IEEE1275_HINT
;
766 else if (!strcmp (arg
, "baremetal_hints"))
767 print
= PRINT_BAREMETAL_HINT
;
768 else if (!strcmp (arg
, "efi_hints"))
769 print
= PRINT_EFI_HINT
;
770 else if (!strcmp (arg
, "arc_hints"))
771 print
= PRINT_ARC_HINT
;
772 else if (!strcmp (arg
, "compatibility_hint"))
773 print
= PRINT_COMPATIBILITY_HINT
;
774 else if (!strcmp (arg
, "disk"))
781 arguments
->zero_delim
= 1;
788 case ARGP_KEY_NO_ARGS
:
789 fprintf (stderr
, "%s", _("No path or device is specified.\n"));
794 assert (arguments
->ndevices
< arguments
->device_max
);
795 arguments
->devices
[arguments
->ndevices
++] = xstrdup(arg
);
799 return ARGP_ERR_UNKNOWN
;
804 static struct argp argp
= {
805 options
, argp_parser
, N_("[OPTION]... [PATH|DEVICE]"),
807 Probe device information for a given path (or device, if the -d option is given)."),
808 NULL
, help_filter
, NULL
812 main (int argc
, char *argv
[])
815 struct arguments arguments
;
817 set_program_name (argv
[0]);
819 grub_util_init_nls ();
821 memset (&arguments
, 0, sizeof (struct arguments
));
822 arguments
.device_max
= argc
+ 1;
823 arguments
.devices
= xmalloc ((arguments
.device_max
+ 1)
824 * sizeof (arguments
.devices
[0]));
825 memset (arguments
.devices
, 0, (arguments
.device_max
+ 1)
826 * sizeof (arguments
.devices
[0]));
828 /* Parse our arguments */
829 if (argp_parse (&argp
, argc
, argv
, 0, 0, &arguments
) != 0)
831 fprintf (stderr
, "%s", _("Error in parsing command line arguments\n"));
836 grub_env_set ("debug", "all");
838 /* Obtain ARGUMENT. */
839 if (arguments
.ndevices
!= 1 && !argument_is_device
)
841 char *program
= xstrdup(program_name
);
842 fprintf (stderr
, _("Unknown extra argument `%s'.\n"), argv
[optind
+ 1]);
843 argp_help (&argp
, stderr
, ARGP_HELP_STD_USAGE
, program
);
848 /* Initialize the emulated biosdisk driver. */
849 grub_util_biosdisk_init (arguments
.dev_map
? : DEFAULT_DEVICE_MAP
);
851 /* Initialize all modules. */
853 grub_gcry_init_all ();
856 grub_mdraid09_fini ();
857 grub_mdraid1x_fini ();
858 grub_diskfilter_fini ();
859 grub_diskfilter_init ();
860 grub_mdraid09_init ();
861 grub_mdraid1x_init ();
864 if (print
== PRINT_COMPATIBILITY_HINT
|| print
== PRINT_BIOS_HINT
865 || print
== PRINT_IEEE1275_HINT
|| print
== PRINT_BAREMETAL_HINT
866 || print
== PRINT_EFI_HINT
|| print
== PRINT_ARC_HINT
)
871 if (arguments
.zero_delim
)
875 if (argument_is_device
)
876 probe (NULL
, arguments
.devices
, delim
);
878 probe (arguments
.devices
[0], NULL
, delim
);
880 if (!arguments
.zero_delim
&& (print
== PRINT_COMPATIBILITY_HINT
881 || print
== PRINT_BIOS_HINT
882 || print
== PRINT_IEEE1275_HINT
883 || print
== PRINT_BAREMETAL_HINT
884 || print
== PRINT_EFI_HINT
885 || print
== PRINT_ARC_HINT
))
888 /* Free resources. */
889 grub_gcry_fini_all ();
891 grub_util_biosdisk_fini ();
895 for (i
= 0; i
< arguments
.ndevices
; i
++)
896 free (arguments
.devices
[i
]);
898 free (arguments
.devices
);
900 free (arguments
.dev_map
);