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
,
74 static int print
= PRINT_FS
;
75 static unsigned int argument_is_device
= 0;
78 probe_partmap (grub_disk_t disk
)
80 grub_partition_t part
;
81 grub_disk_memberlist_t list
= NULL
, tmp
;
83 if (disk
->partition
== NULL
)
85 grub_util_info ("no partition map found for %s", disk
->name
);
88 for (part
= disk
->partition
; part
; part
= part
->parent
)
89 printf ("%s ", part
->partmap
->name
);
91 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
)
92 grub_diskfilter_print_partmap (disk
);
94 /* In case of LVM/RAID, check the member devices as well. */
95 if (disk
->dev
->memberlist
)
97 list
= disk
->dev
->memberlist (disk
);
101 probe_partmap (list
->disk
);
109 probe_cryptodisk_uuid (grub_disk_t disk
)
111 grub_disk_memberlist_t list
= NULL
, tmp
;
113 /* In case of LVM/RAID, check the member devices as well. */
114 if (disk
->dev
->memberlist
)
116 list
= disk
->dev
->memberlist (disk
);
120 probe_cryptodisk_uuid (list
->disk
);
125 if (disk
->dev
->id
== GRUB_DISK_DEVICE_CRYPTODISK_ID
)
126 grub_util_cryptodisk_print_uuid (disk
);
130 probe_raid_level (grub_disk_t disk
)
132 /* disk might be NULL in the case of a LVM physical volume with no LVM
133 signature. Ignore such cases here. */
137 if (disk
->dev
->id
!= GRUB_DISK_DEVICE_DISKFILTER_ID
)
140 if (disk
->name
[0] != 'm' || disk
->name
[1] != 'd')
143 if (!((struct grub_diskfilter_lv
*) disk
->data
)->segments
)
145 return ((struct grub_diskfilter_lv
*) disk
->data
)->segments
->type
;
148 /* Since OF path names can have "," characters in them, and GRUB
149 internally uses "," to indicate partitions (unlike OF which uses
150 ":" for this purpose) we escape such commas. */
152 escape_of_path (const char *orig_path
)
154 char *new_path
, *d
, c
;
157 if (!strchr (orig_path
, ','))
158 return (char *) xstrdup (orig_path
);
160 new_path
= xmalloc (strlen (orig_path
) * 2 + 1);
164 while ((c
= *p
++) != '\0')
176 guess_bios_drive (const char *orig_path
)
180 canon
= canonicalize_file_name (orig_path
);
183 ptr
= strrchr (orig_path
, '/');
188 if ((ptr
[0] == 's' || ptr
[0] == 'h') && ptr
[1] == 'd')
190 int num
= ptr
[2] - 'a';
192 return xasprintf ("hd%d", num
);
194 if (ptr
[0] == 'f' && ptr
[1] == 'd')
196 int num
= atoi (ptr
+ 2);
198 return xasprintf ("fd%d", num
);
205 guess_efi_drive (const char *orig_path
)
209 canon
= canonicalize_file_name (orig_path
);
212 ptr
= strrchr (orig_path
, '/');
217 if ((ptr
[0] == 's' || ptr
[0] == 'h') && ptr
[1] == 'd')
219 int num
= ptr
[2] - 'a';
221 return xasprintf ("hd%d", num
);
223 if (ptr
[0] == 'f' && ptr
[1] == 'd')
225 int num
= atoi (ptr
+ 2);
227 return xasprintf ("fd%d", num
);
234 guess_baremetal_drive (const char *orig_path
)
238 canon
= canonicalize_file_name (orig_path
);
241 ptr
= strrchr (orig_path
, '/');
246 if (ptr
[0] == 'h' && ptr
[1] == 'd')
248 int num
= ptr
[2] - 'a';
250 return xasprintf ("ata%d", num
);
252 if (ptr
[0] == 's' && ptr
[1] == 'd')
254 int num
= ptr
[2] - 'a';
256 return xasprintf ("ahci%d", num
);
263 print_full_name (const char *drive
, grub_device_t dev
)
265 char *dname
= escape_of_path (drive
);
266 if (dev
->disk
->partition
)
268 char *pname
= grub_partition_get_name (dev
->disk
->partition
);
269 printf ("%s,%s", dname
, pname
);
273 printf ("%s", dname
);
278 probe_abstraction (grub_disk_t disk
)
280 grub_disk_memberlist_t list
= NULL
, tmp
;
283 if (disk
->dev
->memberlist
)
284 list
= disk
->dev
->memberlist (disk
);
287 probe_abstraction (list
->disk
);
294 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
295 && grub_memcmp (disk
->name
, "lvm/", sizeof ("lvm/") - 1) == 0)
298 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
299 && grub_memcmp (disk
->name
, "ldm/", sizeof ("ldm/") - 1) == 0)
302 if (disk
->dev
->id
== GRUB_DISK_DEVICE_CRYPTODISK_ID
)
303 grub_util_cryptodisk_print_abstraction (disk
);
305 raid_level
= probe_raid_level (disk
);
308 printf ("diskfilter ");
309 if (disk
->dev
->raidname
)
310 printf ("%s ", disk
->dev
->raidname (disk
));
313 printf ("raid5rec ");
315 printf ("raid6rec ");
319 probe (const char *path
, char **device_names
, char delim
)
321 char **drives_names
= NULL
;
322 char **curdev
, **curdrive
;
323 char *grub_path
= NULL
;
328 grub_path
= canonicalize_file_name (path
);
330 grub_util_error (_("failed to get canonical path of %s"), path
);
331 device_names
= grub_guess_root_devices (grub_path
);
336 grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path
);
338 if (print
== PRINT_DEVICE
)
340 for (curdev
= device_names
; *curdev
; curdev
++)
342 printf ("%s", *curdev
);
348 if (print
== PRINT_DISK
)
350 for (curdev
= device_names
; *curdev
; curdev
++)
353 disk
= grub_util_get_os_disk (*curdev
);
365 for (curdev
= device_names
; *curdev
; curdev
++)
367 grub_util_pull_device (*curdev
);
371 drives_names
= xmalloc (sizeof (drives_names
[0]) * (ndev
+ 1));
373 for (curdev
= device_names
, curdrive
= drives_names
; *curdev
; curdev
++,
376 *curdrive
= grub_util_get_grub_dev (*curdev
);
378 grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"),
383 if (print
== PRINT_DRIVE
)
385 for (curdrive
= drives_names
; *curdrive
; curdrive
++)
387 printf ("(%s)", *curdrive
);
393 if (print
== PRINT_ZERO_CHECK
)
395 for (curdev
= drives_names
; *curdev
; curdev
++)
397 grub_device_t dev
= NULL
;
398 grub_uint32_t buffer
[32768];
399 grub_disk_addr_t addr
;
400 grub_disk_addr_t dsize
;
402 grub_util_info ("opening %s", *curdev
);
403 dev
= grub_device_open (*curdev
);
404 if (! dev
|| !dev
->disk
)
405 grub_util_error ("%s", grub_errmsg
);
407 dsize
= grub_disk_get_size (dev
->disk
);
408 for (addr
= 0; addr
< dsize
;
409 addr
+= sizeof (buffer
) / GRUB_DISK_SECTOR_SIZE
)
411 grub_size_t sz
= sizeof (buffer
);
414 if (sizeof (buffer
) / GRUB_DISK_SECTOR_SIZE
> dsize
- addr
)
415 sz
= (dsize
- addr
) * GRUB_DISK_SECTOR_SIZE
;
416 grub_disk_read (dev
->disk
, addr
, 0, sz
, buffer
);
418 for (ptr
= buffer
; ptr
< buffer
+ sz
/ sizeof (*buffer
); ptr
++)
421 grub_printf ("false\n");
422 grub_device_close (dev
);
427 grub_device_close (dev
);
429 grub_printf ("true\n");
432 if (print
== PRINT_FS
|| print
== PRINT_FS_UUID
433 || print
== PRINT_FS_LABEL
)
435 grub_device_t dev
= NULL
;
438 grub_util_info ("opening %s", drives_names
[0]);
439 dev
= grub_device_open (drives_names
[0]);
441 grub_util_error ("%s", grub_errmsg
);
443 fs
= grub_fs_probe (dev
);
445 grub_util_error ("%s", grub_errmsg
);
447 if (print
== PRINT_FS
)
449 printf ("%s", fs
->name
);
452 else if (print
== PRINT_FS_UUID
)
456 grub_util_error (_("%s does not support UUIDs"), fs
->name
);
458 if (fs
->uuid (dev
, &uuid
) != GRUB_ERR_NONE
)
459 grub_util_error ("%s", grub_errmsg
);
464 else if (print
== PRINT_FS_LABEL
)
468 grub_util_error (_("filesystem `%s' does not support labels"),
471 if (fs
->label (dev
, &label
) != GRUB_ERR_NONE
)
472 grub_util_error ("%s", grub_errmsg
);
474 printf ("%s", label
);
480 for (curdrive
= drives_names
, curdev
= device_names
; *curdrive
;
481 curdrive
++, curdev
++)
483 grub_device_t dev
= NULL
;
485 grub_util_info ("opening %s", *curdrive
);
486 dev
= grub_device_open (*curdrive
);
488 grub_util_error ("%s", grub_errmsg
);
490 if (print
== PRINT_HINT_STR
)
492 const char *osdev
= grub_util_biosdisk_get_osdev (dev
->disk
);
493 const char *ofpath
= osdev
? grub_util_devname_to_ofpath (osdev
) : 0;
494 char *biosname
, *bare
, *efi
;
499 char *tmp
= xmalloc (strlen (ofpath
) + sizeof ("ieee1275/"));
501 p
= stpcpy (tmp
, "ieee1275/");
503 printf ("--hint-ieee1275='");
504 print_full_name (tmp
, dev
);
509 biosname
= guess_bios_drive (*curdev
);
512 printf ("--hint-bios=");
513 print_full_name (biosname
, dev
);
518 efi
= guess_efi_drive (*curdev
);
521 printf ("--hint-efi=");
522 print_full_name (efi
, dev
);
527 bare
= guess_baremetal_drive (*curdev
);
530 printf ("--hint-baremetal=");
531 print_full_name (bare
, dev
);
536 /* FIXME: Add ARC hint. */
538 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
542 print_full_name (map
, dev
);
547 grub_device_close (dev
);
551 if ((print
== PRINT_COMPATIBILITY_HINT
|| print
== PRINT_BIOS_HINT
552 || print
== PRINT_IEEE1275_HINT
|| print
== PRINT_BAREMETAL_HINT
553 || print
== PRINT_EFI_HINT
|| print
== PRINT_ARC_HINT
)
554 && dev
->disk
->dev
->id
!= GRUB_DISK_DEVICE_HOSTDISK_ID
)
556 print_full_name (dev
->disk
->name
, dev
);
561 if (print
== PRINT_COMPATIBILITY_HINT
)
565 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
568 print_full_name (map
, dev
);
570 grub_device_close (dev
);
571 /* Compatibility hint is one device only. */
574 biosname
= guess_bios_drive (*curdev
);
577 print_full_name (biosname
, dev
);
581 grub_device_close (dev
);
582 /* Compatibility hint is one device only. */
588 if (print
== PRINT_BIOS_HINT
)
591 biosname
= guess_bios_drive (*curdev
);
594 print_full_name (biosname
, dev
);
598 grub_device_close (dev
);
601 if (print
== PRINT_IEEE1275_HINT
)
603 const char *osdev
= grub_util_biosdisk_get_osdev (dev
->disk
);
604 const char *ofpath
= grub_util_devname_to_ofpath (osdev
);
607 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
610 print_full_name (map
, dev
);
616 char *tmp
= xmalloc (strlen (ofpath
) + sizeof ("ieee1275/"));
618 p
= stpcpy (tmp
, "ieee1275/");
620 print_full_name (tmp
, dev
);
625 grub_device_close (dev
);
628 if (print
== PRINT_EFI_HINT
)
632 biosname
= guess_efi_drive (*curdev
);
634 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
637 print_full_name (map
, dev
);
642 print_full_name (biosname
, dev
);
647 grub_device_close (dev
);
651 if (print
== PRINT_BAREMETAL_HINT
)
656 biosname
= guess_baremetal_drive (*curdev
);
658 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
661 print_full_name (map
, dev
);
666 print_full_name (biosname
, dev
);
671 grub_device_close (dev
);
675 if (print
== PRINT_ARC_HINT
)
679 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
682 print_full_name (map
, dev
);
687 grub_device_close (dev
);
691 if (print
== PRINT_ABSTRACTION
)
693 probe_abstraction (dev
->disk
);
695 grub_device_close (dev
);
699 if (print
== PRINT_CRYPTODISK_UUID
)
701 probe_cryptodisk_uuid (dev
->disk
);
703 grub_device_close (dev
);
707 if (print
== PRINT_PARTMAP
)
709 /* Check if dev->disk itself is contained in a partmap. */
710 probe_partmap (dev
->disk
);
712 grub_device_close (dev
);
716 if (print
== PRINT_MSDOS_PARTTYPE
)
718 if (dev
->disk
->partition
719 && strcmp(dev
->disk
->partition
->partmap
->name
, "msdos") == 0)
720 printf ("%02x", dev
->disk
->partition
->msdostype
);
723 grub_device_close (dev
);
729 for (curdrive
= drives_names
; *curdrive
; curdrive
++)
734 static struct argp_option options
[] = {
735 {"device", 'd', 0, 0,
736 N_("given argument is a system device, not a path"), 0},
737 {"device-map", 'm', N_("FILE"), 0,
738 N_("use FILE as the device map [default=%s]"), 0},
739 {"target", 't', "(fs|fs_uuid|fs_label|drive|device|partmap|abstraction|cryptodisk_uuid|msdos_parttype)", 0,
740 N_("print filesystem module, GRUB drive, system device, partition map module, abstraction module or cryptographic container UUID [default=fs]"), 0},
741 {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
746 help_filter (int key
, const char *text
, void *input
__attribute__ ((unused
)))
751 return xasprintf (text
, DEFAULT_DEVICE_MAP
);
754 return (char *) text
;
768 argp_parser (int key
, char *arg
, struct argp_state
*state
)
770 /* Get the input argument from argp_parse, which we
771 know is a pointer to our arguments structure. */
772 struct arguments
*arguments
= state
->input
;
777 argument_is_device
= 1;
781 if (arguments
->dev_map
)
782 free (arguments
->dev_map
);
784 arguments
->dev_map
= xstrdup (arg
);
788 if (!strcmp (arg
, "fs"))
790 else if (!strcmp (arg
, "fs_uuid"))
791 print
= PRINT_FS_UUID
;
792 else if (!strcmp (arg
, "fs_label"))
793 print
= PRINT_FS_LABEL
;
794 else if (!strcmp (arg
, "drive"))
796 else if (!strcmp (arg
, "device"))
797 print
= PRINT_DEVICE
;
798 else if (!strcmp (arg
, "partmap"))
799 print
= PRINT_PARTMAP
;
800 else if (!strcmp (arg
, "abstraction"))
801 print
= PRINT_ABSTRACTION
;
802 else if (!strcmp (arg
, "cryptodisk_uuid"))
803 print
= PRINT_CRYPTODISK_UUID
;
804 else if (!strcmp (arg
, "msdos_parttype"))
805 print
= PRINT_MSDOS_PARTTYPE
;
806 else if (!strcmp (arg
, "hints_string"))
807 print
= PRINT_HINT_STR
;
808 else if (!strcmp (arg
, "bios_hints"))
809 print
= PRINT_BIOS_HINT
;
810 else if (!strcmp (arg
, "ieee1275_hints"))
811 print
= PRINT_IEEE1275_HINT
;
812 else if (!strcmp (arg
, "baremetal_hints"))
813 print
= PRINT_BAREMETAL_HINT
;
814 else if (!strcmp (arg
, "efi_hints"))
815 print
= PRINT_EFI_HINT
;
816 else if (!strcmp (arg
, "arc_hints"))
817 print
= PRINT_ARC_HINT
;
818 else if (!strcmp (arg
, "compatibility_hint"))
819 print
= PRINT_COMPATIBILITY_HINT
;
820 else if (strcmp (arg
, "zero_check") == 0)
821 print
= PRINT_ZERO_CHECK
;
822 else if (!strcmp (arg
, "disk"))
829 arguments
->zero_delim
= 1;
836 case ARGP_KEY_NO_ARGS
:
837 fprintf (stderr
, "%s", _("No path or device is specified.\n"));
842 assert (arguments
->ndevices
< arguments
->device_max
);
843 arguments
->devices
[arguments
->ndevices
++] = xstrdup(arg
);
847 return ARGP_ERR_UNKNOWN
;
852 static struct argp argp
= {
853 options
, argp_parser
, N_("[OPTION]... [PATH|DEVICE]"),
855 Probe device information for a given path (or device, if the -d option is given)."),
856 NULL
, help_filter
, NULL
860 main (int argc
, char *argv
[])
863 struct arguments arguments
;
865 set_program_name (argv
[0]);
867 grub_util_init_nls ();
869 memset (&arguments
, 0, sizeof (struct arguments
));
870 arguments
.device_max
= argc
+ 1;
871 arguments
.devices
= xmalloc ((arguments
.device_max
+ 1)
872 * sizeof (arguments
.devices
[0]));
873 memset (arguments
.devices
, 0, (arguments
.device_max
+ 1)
874 * sizeof (arguments
.devices
[0]));
876 /* Parse our arguments */
877 if (argp_parse (&argp
, argc
, argv
, 0, 0, &arguments
) != 0)
879 fprintf (stderr
, "%s", _("Error in parsing command line arguments\n"));
884 grub_env_set ("debug", "all");
886 /* Obtain ARGUMENT. */
887 if (arguments
.ndevices
!= 1 && !argument_is_device
)
889 char *program
= xstrdup(program_name
);
890 fprintf (stderr
, _("Unknown extra argument `%s'."), arguments
.devices
[1]);
891 fprintf (stderr
, "\n");
892 argp_help (&argp
, stderr
, ARGP_HELP_STD_USAGE
, program
);
897 /* Initialize the emulated biosdisk driver. */
898 grub_util_biosdisk_init (arguments
.dev_map
? : DEFAULT_DEVICE_MAP
);
900 /* Initialize all modules. */
902 grub_gcry_init_all ();
905 grub_mdraid09_fini ();
906 grub_mdraid1x_fini ();
907 grub_diskfilter_fini ();
908 grub_diskfilter_init ();
909 grub_mdraid09_init ();
910 grub_mdraid1x_init ();
913 if (print
== PRINT_BIOS_HINT
914 || print
== PRINT_IEEE1275_HINT
|| print
== PRINT_BAREMETAL_HINT
915 || print
== PRINT_EFI_HINT
|| print
== PRINT_ARC_HINT
)
920 if (arguments
.zero_delim
)
924 if (argument_is_device
)
925 probe (NULL
, arguments
.devices
, delim
);
927 probe (arguments
.devices
[0], NULL
, delim
);
929 if (!arguments
.zero_delim
&& (print
== PRINT_BIOS_HINT
930 || print
== PRINT_IEEE1275_HINT
931 || print
== PRINT_BAREMETAL_HINT
932 || print
== PRINT_EFI_HINT
933 || print
== PRINT_ARC_HINT
))
936 /* Free resources. */
937 grub_gcry_fini_all ();
939 grub_util_biosdisk_fini ();
943 for (i
= 0; i
< arguments
.ndevices
; i
++)
944 free (arguments
.devices
[i
]);
946 free (arguments
.devices
);
948 free (arguments
.dev_map
);