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/gpt_partition.h>
31 #include <grub/emu/hostdisk.h>
32 #include <grub/emu/getroot.h>
33 #include <grub/term.h>
35 #include <grub/diskfilter.h>
36 #include <grub/i18n.h>
37 #include <grub/emu/misc.h>
38 #include <grub/util/ofpath.h>
39 #include <grub/crypto.h>
40 #include <grub/cryptodisk.h>
50 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
51 #pragma GCC diagnostic ignored "-Wmissing-declarations"
53 #pragma GCC diagnostic error "-Wmissing-prototypes"
54 #pragma GCC diagnostic error "-Wmissing-declarations"
66 PRINT_CRYPTODISK_UUID
,
73 PRINT_COMPATIBILITY_HINT
,
80 static const char *targets
[] =
83 [PRINT_FS_UUID
] = "fs_uuid",
84 [PRINT_FS_LABEL
] = "fs_label",
85 [PRINT_DRIVE
] = "drive",
86 [PRINT_DEVICE
] = "device",
87 [PRINT_PARTMAP
] = "partmap",
88 [PRINT_ABSTRACTION
] = "abstraction",
89 [PRINT_CRYPTODISK_UUID
] = "cryptodisk_uuid",
90 [PRINT_HINT_STR
] = "hints_string",
91 [PRINT_BIOS_HINT
] = "bios_hints",
92 [PRINT_IEEE1275_HINT
] = "ieee1275_hints",
93 [PRINT_BAREMETAL_HINT
] = "baremetal_hints",
94 [PRINT_EFI_HINT
] = "efi_hints",
95 [PRINT_ARC_HINT
] = "arc_hints",
96 [PRINT_COMPATIBILITY_HINT
] = "compatibility_hint",
97 [PRINT_MSDOS_PARTTYPE
] = "msdos_parttype",
98 [PRINT_GPT_PARTTYPE
] = "gpt_parttype",
99 [PRINT_ZERO_CHECK
] = "zero_check",
100 [PRINT_DISK
] = "disk",
103 static int print
= PRINT_FS
;
104 static unsigned int argument_is_device
= 0;
107 get_targets_string (void)
109 char **arr
= xmalloc (sizeof (targets
));
115 memcpy (arr
, targets
, sizeof (targets
));
116 qsort (arr
, ARRAY_SIZE (targets
), sizeof (char *), grub_qsort_strcmp
);
117 for (i
= 0; i
< ARRAY_SIZE (targets
); i
++)
118 len
+= grub_strlen (targets
[i
]) + 2;
119 ptr
= str
= xmalloc (len
);
120 for (i
= 0; i
< ARRAY_SIZE (targets
); i
++)
122 ptr
= grub_stpcpy (ptr
, arr
[i
]);
133 do_print (const char *x
, void *data
)
135 char delim
= *(const char *) data
;
136 grub_printf ("%s%c", x
, delim
);
140 probe_partmap (grub_disk_t disk
, char delim
)
142 grub_partition_t part
;
143 grub_disk_memberlist_t list
= NULL
, tmp
;
145 if (disk
->partition
== NULL
)
147 grub_util_info ("no partition map found for %s", disk
->name
);
150 for (part
= disk
->partition
; part
; part
= part
->parent
)
151 printf ("%s%c", part
->partmap
->name
, delim
);
153 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
)
154 grub_diskfilter_get_partmap (disk
, do_print
, &delim
);
156 /* In case of LVM/RAID, check the member devices as well. */
157 if (disk
->dev
->memberlist
)
159 list
= disk
->dev
->memberlist (disk
);
163 probe_partmap (list
->disk
, delim
);
171 probe_cryptodisk_uuid (grub_disk_t disk
, char delim
)
173 grub_disk_memberlist_t list
= NULL
, tmp
;
175 /* In case of LVM/RAID, check the member devices as well. */
176 if (disk
->dev
->memberlist
)
178 list
= disk
->dev
->memberlist (disk
);
182 probe_cryptodisk_uuid (list
->disk
, delim
);
187 if (disk
->dev
->id
== GRUB_DISK_DEVICE_CRYPTODISK_ID
)
189 const char *uu
= grub_util_cryptodisk_get_uuid (disk
);
190 grub_printf ("%s%c", uu
, delim
);
195 probe_raid_level (grub_disk_t disk
)
197 /* disk might be NULL in the case of a LVM physical volume with no LVM
198 signature. Ignore such cases here. */
202 if (disk
->dev
->id
!= GRUB_DISK_DEVICE_DISKFILTER_ID
)
205 if (disk
->name
[0] != 'm' || disk
->name
[1] != 'd')
208 if (!((struct grub_diskfilter_lv
*) disk
->data
)->segments
)
210 return ((struct grub_diskfilter_lv
*) disk
->data
)->segments
->type
;
214 probe_abstraction (grub_disk_t disk
, char delim
)
216 grub_disk_memberlist_t list
= NULL
, tmp
;
219 if (disk
->dev
->memberlist
)
220 list
= disk
->dev
->memberlist (disk
);
223 probe_abstraction (list
->disk
, delim
);
230 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
231 && (grub_memcmp (disk
->name
, "lvm/", sizeof ("lvm/") - 1) == 0 ||
232 grub_memcmp (disk
->name
, "lvmid/", sizeof ("lvmid/") - 1) == 0))
233 printf ("lvm%c", delim
);
235 if (disk
->dev
->id
== GRUB_DISK_DEVICE_DISKFILTER_ID
236 && grub_memcmp (disk
->name
, "ldm/", sizeof ("ldm/") - 1) == 0)
237 printf ("ldm%c", delim
);
239 if (disk
->dev
->id
== GRUB_DISK_DEVICE_CRYPTODISK_ID
)
240 grub_util_cryptodisk_get_abstraction (disk
, do_print
, &delim
);
242 raid_level
= probe_raid_level (disk
);
245 printf ("diskfilter%c", delim
);
246 if (disk
->dev
->raidname
)
247 printf ("%s%c", disk
->dev
->raidname (disk
), delim
);
250 printf ("raid5rec%c", delim
);
252 printf ("raid6rec%c", delim
);
256 probe (const char *path
, char **device_names
, char delim
)
258 char **drives_names
= NULL
;
259 char **curdev
, **curdrive
;
260 char *grub_path
= NULL
;
265 grub_path
= canonicalize_file_name (path
);
267 grub_util_error (_("failed to get canonical path of `%s'"), path
);
268 device_names
= grub_guess_root_devices (grub_path
);
273 grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path
);
275 if (print
== PRINT_DEVICE
)
277 for (curdev
= device_names
; *curdev
; curdev
++)
279 printf ("%s", *curdev
);
285 if (print
== PRINT_DISK
)
287 for (curdev
= device_names
; *curdev
; curdev
++)
290 disk
= grub_util_get_os_disk (*curdev
);
303 for (curdev
= device_names
; *curdev
; curdev
++)
305 grub_util_pull_device (*curdev
);
309 drives_names
= xmalloc (sizeof (drives_names
[0]) * (ndev
+ 1));
311 for (curdev
= device_names
, curdrive
= drives_names
; *curdev
; curdev
++,
314 *curdrive
= grub_util_get_grub_dev (*curdev
);
316 grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"),
321 if (print
== PRINT_DRIVE
)
323 for (curdrive
= drives_names
; *curdrive
; curdrive
++)
325 printf ("(%s)", *curdrive
);
331 if (print
== PRINT_ZERO_CHECK
)
333 for (curdev
= drives_names
; *curdev
; curdev
++)
335 grub_device_t dev
= NULL
;
336 grub_uint32_t buffer
[32768];
337 grub_disk_addr_t addr
;
338 grub_disk_addr_t dsize
;
340 grub_util_info ("opening %s", *curdev
);
341 dev
= grub_device_open (*curdev
);
342 if (! dev
|| !dev
->disk
)
343 grub_util_error ("%s", grub_errmsg
);
345 dsize
= grub_disk_get_size (dev
->disk
);
346 for (addr
= 0; addr
< dsize
;
347 addr
+= sizeof (buffer
) / GRUB_DISK_SECTOR_SIZE
)
349 grub_size_t sz
= sizeof (buffer
);
352 if (sizeof (buffer
) / GRUB_DISK_SECTOR_SIZE
> dsize
- addr
)
353 sz
= (dsize
- addr
) * GRUB_DISK_SECTOR_SIZE
;
354 grub_disk_read (dev
->disk
, addr
, 0, sz
, buffer
);
356 for (ptr
= buffer
; ptr
< buffer
+ sz
/ sizeof (*buffer
); ptr
++)
359 grub_printf ("false\n");
360 grub_device_close (dev
);
365 grub_device_close (dev
);
367 grub_printf ("true\n");
370 if (print
== PRINT_FS
|| print
== PRINT_FS_UUID
371 || print
== PRINT_FS_LABEL
)
373 grub_device_t dev
= NULL
;
376 grub_util_info ("opening %s", drives_names
[0]);
377 dev
= grub_device_open (drives_names
[0]);
379 grub_util_error ("%s", grub_errmsg
);
381 fs
= grub_fs_probe (dev
);
383 grub_util_error ("%s", grub_errmsg
);
385 if (print
== PRINT_FS
)
387 printf ("%s", fs
->name
);
390 else if (print
== PRINT_FS_UUID
)
394 grub_util_error (_("%s does not support UUIDs"), fs
->name
);
396 if (fs
->uuid (dev
, &uuid
) != GRUB_ERR_NONE
)
397 grub_util_error ("%s", grub_errmsg
);
402 else if (print
== PRINT_FS_LABEL
)
406 grub_util_error (_("filesystem `%s' does not support labels"),
409 if (fs
->label (dev
, &label
) != GRUB_ERR_NONE
)
410 grub_util_error ("%s", grub_errmsg
);
412 printf ("%s", label
);
415 grub_device_close (dev
);
419 for (curdrive
= drives_names
, curdev
= device_names
; *curdrive
;
420 curdrive
++, curdev
++)
422 grub_device_t dev
= NULL
;
424 grub_util_info ("opening %s", *curdrive
);
425 dev
= grub_device_open (*curdrive
);
427 grub_util_error ("%s", grub_errmsg
);
429 if (print
== PRINT_HINT_STR
)
431 const char *osdev
= grub_util_biosdisk_get_osdev (dev
->disk
);
432 const char *ofpath
= osdev
? grub_util_devname_to_ofpath (osdev
) : 0;
433 char *biosname
, *bare
, *efi
;
438 char *tmp
= xmalloc (strlen (ofpath
) + sizeof ("ieee1275/"));
440 p
= grub_stpcpy (tmp
, "ieee1275/");
442 printf ("--hint-ieee1275='");
443 grub_util_fprint_full_disk_name (stdout
, tmp
, dev
);
448 biosname
= grub_util_guess_bios_drive (*curdev
);
451 printf ("--hint-bios=");
452 grub_util_fprint_full_disk_name (stdout
, biosname
, dev
);
457 efi
= grub_util_guess_efi_drive (*curdev
);
460 printf ("--hint-efi=");
461 grub_util_fprint_full_disk_name (stdout
, efi
, dev
);
466 bare
= grub_util_guess_baremetal_drive (*curdev
);
469 printf ("--hint-baremetal=");
470 grub_util_fprint_full_disk_name (stdout
, bare
, dev
);
475 /* FIXME: Add ARC hint. */
477 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
481 grub_util_fprint_full_disk_name (stdout
, map
, dev
);
489 grub_device_close (dev
);
493 if ((print
== PRINT_COMPATIBILITY_HINT
|| print
== PRINT_BIOS_HINT
494 || print
== PRINT_IEEE1275_HINT
|| print
== PRINT_BAREMETAL_HINT
495 || print
== PRINT_EFI_HINT
|| print
== PRINT_ARC_HINT
)
496 && dev
->disk
->dev
->id
!= GRUB_DISK_DEVICE_HOSTDISK_ID
)
498 grub_util_fprint_full_disk_name (stdout
, dev
->disk
->name
, dev
);
500 grub_device_close (dev
);
504 if (print
== PRINT_COMPATIBILITY_HINT
)
508 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
511 grub_util_fprint_full_disk_name (stdout
, map
, dev
);
513 grub_device_close (dev
);
514 /* Compatibility hint is one device only. */
517 biosname
= grub_util_guess_bios_drive (*curdev
);
520 grub_util_fprint_full_disk_name (stdout
, biosname
, dev
);
524 grub_device_close (dev
);
525 /* Compatibility hint is one device only. */
531 if (print
== PRINT_BIOS_HINT
)
534 biosname
= grub_util_guess_bios_drive (*curdev
);
537 grub_util_fprint_full_disk_name (stdout
, biosname
, dev
);
541 grub_device_close (dev
);
544 if (print
== PRINT_IEEE1275_HINT
)
546 const char *osdev
= grub_util_biosdisk_get_osdev (dev
->disk
);
547 char *ofpath
= grub_util_devname_to_ofpath (osdev
);
550 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
553 grub_util_fprint_full_disk_name (stdout
, map
, dev
);
559 char *tmp
= xmalloc (strlen (ofpath
) + sizeof ("ieee1275/"));
561 p
= grub_stpcpy (tmp
, "ieee1275/");
563 grub_util_fprint_full_disk_name (stdout
, tmp
, dev
);
569 grub_device_close (dev
);
572 if (print
== PRINT_EFI_HINT
)
576 biosname
= grub_util_guess_efi_drive (*curdev
);
578 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
581 grub_util_fprint_full_disk_name (stdout
, map
, dev
);
586 grub_util_fprint_full_disk_name (stdout
, biosname
, dev
);
591 grub_device_close (dev
);
595 if (print
== PRINT_BAREMETAL_HINT
)
600 biosname
= grub_util_guess_baremetal_drive (*curdev
);
602 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
605 grub_util_fprint_full_disk_name (stdout
, map
, dev
);
610 grub_util_fprint_full_disk_name (stdout
, biosname
, dev
);
615 grub_device_close (dev
);
619 if (print
== PRINT_ARC_HINT
)
623 map
= grub_util_biosdisk_get_compatibility_hint (dev
->disk
);
626 grub_util_fprint_full_disk_name (stdout
, map
, dev
);
631 grub_device_close (dev
);
635 if (print
== PRINT_ABSTRACTION
)
637 probe_abstraction (dev
->disk
, delim
);
638 grub_device_close (dev
);
642 if (print
== PRINT_CRYPTODISK_UUID
)
644 probe_cryptodisk_uuid (dev
->disk
, delim
);
645 grub_device_close (dev
);
649 if (print
== PRINT_PARTMAP
)
651 /* Check if dev->disk itself is contained in a partmap. */
652 probe_partmap (dev
->disk
, delim
);
653 grub_device_close (dev
);
657 if (print
== PRINT_MSDOS_PARTTYPE
)
659 if (dev
->disk
->partition
660 && strcmp(dev
->disk
->partition
->partmap
->name
, "msdos") == 0)
661 printf ("%02x", dev
->disk
->partition
->msdostype
);
664 grub_device_close (dev
);
668 if (print
== PRINT_GPT_PARTTYPE
)
670 if (dev
->disk
->partition
671 && strcmp (dev
->disk
->partition
->partmap
->name
, "gpt") == 0)
673 struct grub_gpt_partentry gptdata
;
674 grub_partition_t p
= dev
->disk
->partition
;
675 dev
->disk
->partition
= dev
->disk
->partition
->parent
;
677 if (grub_disk_read (dev
->disk
, p
->offset
, p
->index
,
678 sizeof (gptdata
), &gptdata
) == 0)
680 grub_gpt_part_type_t gpttype
;
681 gpttype
.data1
= grub_le_to_cpu32 (gptdata
.type
.data1
);
682 gpttype
.data2
= grub_le_to_cpu16 (gptdata
.type
.data2
);
683 gpttype
.data3
= grub_le_to_cpu16 (gptdata
.type
.data3
);
684 grub_memcpy (gpttype
.data4
, gptdata
.type
.data4
, 8);
686 grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
687 gpttype
.data1
, gpttype
.data2
,
688 gpttype
.data3
, gpttype
.data4
[0],
689 gpttype
.data4
[1], gpttype
.data4
[2],
690 gpttype
.data4
[3], gpttype
.data4
[4],
691 gpttype
.data4
[5], gpttype
.data4
[6],
694 dev
->disk
->partition
= p
;
697 grub_device_close (dev
);
703 for (curdrive
= drives_names
; *curdrive
; curdrive
++)
708 static struct argp_option options
[] = {
709 {"device", 'd', 0, 0,
710 N_("given argument is a system device, not a path"), 0},
711 {"device-map", 'm', N_("FILE"), 0,
712 N_("use FILE as the device map [default=%s]"), 0},
713 {"target", 't', N_("TARGET"), 0, 0, 0},
714 {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
715 {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0},
719 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
722 help_filter (int key
, const char *text
, void *input
__attribute__ ((unused
)))
727 return xasprintf (text
, DEFAULT_DEVICE_MAP
);
731 char *ret
, *t
= get_targets_string ();
733 ret
= xasprintf ("%s\n%s %s [default=%s]", _("print TARGET"),
734 _("available targets:"), t
, targets
[print
]);
740 return (char *) text
;
744 #pragma GCC diagnostic error "-Wformat-nonliteral"
756 argp_parser (int key
, char *arg
, struct argp_state
*state
)
758 /* Get the input argument from argp_parse, which we
759 know is a pointer to our arguments structure. */
760 struct arguments
*arguments
= state
->input
;
765 argument_is_device
= 1;
769 if (arguments
->dev_map
)
770 free (arguments
->dev_map
);
772 arguments
->dev_map
= xstrdup (arg
);
779 for (i
= PRINT_FS
; i
< ARRAY_SIZE (targets
); i
++)
780 if (strcmp (arg
, targets
[i
]) == 0)
785 if (i
== ARRAY_SIZE (targets
))
791 arguments
->zero_delim
= 1;
798 case ARGP_KEY_NO_ARGS
:
799 fprintf (stderr
, "%s", _("No path or device is specified.\n"));
804 assert (arguments
->ndevices
< arguments
->device_max
);
805 arguments
->devices
[arguments
->ndevices
++] = xstrdup(arg
);
809 return ARGP_ERR_UNKNOWN
;
814 static struct argp argp
= {
815 options
, argp_parser
, N_("[OPTION]... [PATH|DEVICE]"),
817 Probe device information for a given path (or device, if the -d option is given)."),
818 NULL
, help_filter
, NULL
822 main (int argc
, char *argv
[])
825 struct arguments arguments
;
827 grub_util_host_init (&argc
, &argv
);
829 memset (&arguments
, 0, sizeof (struct arguments
));
830 arguments
.device_max
= argc
+ 1;
831 arguments
.devices
= xmalloc ((arguments
.device_max
+ 1)
832 * sizeof (arguments
.devices
[0]));
833 memset (arguments
.devices
, 0, (arguments
.device_max
+ 1)
834 * sizeof (arguments
.devices
[0]));
836 /* Parse our arguments */
837 if (argp_parse (&argp
, argc
, argv
, 0, 0, &arguments
) != 0)
839 fprintf (stderr
, "%s", _("Error in parsing command line arguments\n"));
844 grub_env_set ("debug", "all");
846 /* Obtain ARGUMENT. */
847 if (arguments
.ndevices
!= 1 && !argument_is_device
)
849 char *program
= xstrdup(program_name
);
850 fprintf (stderr
, _("Unknown extra argument `%s'."), arguments
.devices
[1]);
851 fprintf (stderr
, "\n");
852 argp_help (&argp
, stderr
, ARGP_HELP_STD_USAGE
, program
);
857 /* Initialize the emulated biosdisk driver. */
858 grub_util_biosdisk_init (arguments
.dev_map
? : DEFAULT_DEVICE_MAP
);
860 /* Initialize all modules. */
862 grub_gcry_init_all ();
865 grub_mdraid09_fini ();
866 grub_mdraid1x_fini ();
867 grub_diskfilter_fini ();
868 grub_diskfilter_init ();
869 grub_mdraid09_init ();
870 grub_mdraid1x_init ();
873 if (print
== PRINT_BIOS_HINT
874 || print
== PRINT_IEEE1275_HINT
|| print
== PRINT_BAREMETAL_HINT
875 || print
== PRINT_EFI_HINT
|| print
== PRINT_ARC_HINT
)
880 if (arguments
.zero_delim
)
884 if (argument_is_device
)
885 probe (NULL
, arguments
.devices
, delim
);
887 probe (arguments
.devices
[0], NULL
, delim
);
892 /* Free resources. */
893 grub_gcry_fini_all ();
895 grub_util_biosdisk_fini ();
899 for (i
= 0; i
< arguments
.ndevices
; i
++)
900 free (arguments
.devices
[i
]);
902 free (arguments
.devices
);
904 free (arguments
.dev_map
);