]> git.proxmox.com Git - grub2.git/blob - util/grub-probe.c
Fix IEEE1275 bugs in grub-probe
[grub2.git] / util / grub-probe.c
1 /* grub-probe.c - probe device information for a given path */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20 #include <config.h>
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>
27 #include <grub/fs.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>
33 #include <grub/env.h>
34 #include <grub/raid.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>
40
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <sys/stat.h>
46
47 #define _GNU_SOURCE 1
48 #include <getopt.h>
49
50 #include "progname.h"
51
52 enum {
53 PRINT_FS,
54 PRINT_FS_UUID,
55 PRINT_FS_LABEL,
56 PRINT_DRIVE,
57 PRINT_DEVICE,
58 PRINT_PARTMAP,
59 PRINT_ABSTRACTION,
60 PRINT_CRYPTODISK_UUID,
61 PRINT_HINT_STR,
62 PRINT_BIOS_HINT,
63 PRINT_IEEE1275_HINT,
64 PRINT_BAREMETAL_HINT,
65 PRINT_EFI_HINT,
66 PRINT_ARC_HINT,
67 PRINT_COMPATIBILITY_HINT
68 };
69
70 static int print = PRINT_FS;
71 static unsigned int argument_is_device = 0;
72
73 static void
74 probe_partmap (grub_disk_t disk)
75 {
76 grub_partition_t part;
77 grub_disk_memberlist_t list = NULL, tmp;
78
79 if (disk->partition == NULL)
80 {
81 grub_util_info ("no partition map found for %s", disk->name);
82 }
83
84 for (part = disk->partition; part; part = part->parent)
85 printf ("%s ", part->partmap->name);
86
87 /* In case of LVM/RAID, check the member devices as well. */
88 if (disk->dev->memberlist)
89 {
90 list = disk->dev->memberlist (disk);
91 }
92 while (list)
93 {
94 probe_partmap (list->disk);
95 tmp = list->next;
96 free (list);
97 list = tmp;
98 }
99 }
100
101 static void
102 probe_cryptodisk_uuid (grub_disk_t disk)
103 {
104 grub_disk_memberlist_t list = NULL, tmp;
105
106 /* In case of LVM/RAID, check the member devices as well. */
107 if (disk->dev->memberlist)
108 {
109 list = disk->dev->memberlist (disk);
110 }
111 while (list)
112 {
113 probe_cryptodisk_uuid (list->disk);
114 tmp = list->next;
115 free (list);
116 list = tmp;
117 }
118 if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
119 grub_util_cryptodisk_print_uuid (disk);
120 }
121
122 static int
123 probe_raid_level (grub_disk_t disk)
124 {
125 /* disk might be NULL in the case of a LVM physical volume with no LVM
126 signature. Ignore such cases here. */
127 if (!disk)
128 return -1;
129
130 if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID)
131 return -1;
132
133 return ((struct grub_raid_array *) disk->data)->level;
134 }
135
136 /* Since OF path names can have "," characters in them, and GRUB
137 internally uses "," to indicate partitions (unlike OF which uses
138 ":" for this purpose) we escape such commas. */
139 static char *
140 escape_of_path (const char *orig_path)
141 {
142 char *new_path, *d, c;
143 const char *p;
144
145 if (!strchr (orig_path, ','))
146 return (char *) orig_path;
147
148 new_path = xmalloc (strlen (orig_path) * 2 + sizeof ("ieee1275/"));
149
150 p = orig_path;
151 grub_strcpy (new_path, "ieee1275/");
152 d = new_path + sizeof ("ieee1275/") - 1;
153 while ((c = *p++) != '\0')
154 {
155 if (c == ',')
156 *d++ = '\\';
157 *d++ = c;
158 }
159 *d = 0;
160
161 free ((char *) orig_path);
162
163 return new_path;
164 }
165
166 static char *
167 guess_bios_drive (const char *orig_path)
168 {
169 char *canon;
170 char *ptr;
171 canon = canonicalize_file_name (orig_path);
172 if (!canon)
173 return NULL;
174 ptr = strrchr (orig_path, '/');
175 if (ptr)
176 ptr++;
177 else
178 ptr = canon;
179 if ((ptr[0] == 's' || ptr[0] == 'h') && ptr[1] == 'd')
180 {
181 int num = ptr[2] - 'a';
182 free (canon);
183 return xasprintf ("hd%d", num);
184 }
185 if (ptr[0] == 'f' && ptr[1] == 'd')
186 {
187 int num = atoi (ptr + 2);
188 free (canon);
189 return xasprintf ("fd%d", num);
190 }
191 free (canon);
192 return NULL;
193 }
194
195 static char *
196 guess_efi_drive (const char *orig_path)
197 {
198 char *canon;
199 char *ptr;
200 canon = canonicalize_file_name (orig_path);
201 if (!canon)
202 return NULL;
203 ptr = strrchr (orig_path, '/');
204 if (ptr)
205 ptr++;
206 else
207 ptr = canon;
208 if ((ptr[0] == 's' || ptr[0] == 'h') && ptr[1] == 'd')
209 {
210 int num = ptr[2] - 'a';
211 free (canon);
212 return xasprintf ("hd%d", num);
213 }
214 if (ptr[0] == 'f' && ptr[1] == 'd')
215 {
216 int num = atoi (ptr + 2);
217 free (canon);
218 return xasprintf ("fd%d", num);
219 }
220 free (canon);
221 return NULL;
222 }
223
224 static char *
225 guess_baremetal_drive (const char *orig_path)
226 {
227 char *canon;
228 char *ptr;
229 canon = canonicalize_file_name (orig_path);
230 if (!canon)
231 return NULL;
232 ptr = strrchr (orig_path, '/');
233 if (ptr)
234 ptr++;
235 else
236 ptr = canon;
237 if (ptr[0] == 'h' && ptr[1] == 'd')
238 {
239 int num = ptr[2] - 'a';
240 free (canon);
241 return xasprintf ("ata%d", num);
242 }
243 if (ptr[0] == 's' && ptr[1] == 'd')
244 {
245 int num = ptr[2] - 'a';
246 free (canon);
247 return xasprintf ("ahci%d", num);
248 }
249 free (canon);
250 return NULL;
251 }
252
253 static void
254 print_full_name (const char *drive, grub_device_t dev)
255 {
256 if (dev->disk->partition)
257 {
258 char *pname = grub_partition_get_name (dev->disk->partition);
259 printf ("%s,%s", drive, pname);
260 free (pname);
261 }
262 else
263 printf ("%s", drive);
264 }
265
266 static void
267 probe_abstraction (grub_disk_t disk)
268 {
269 grub_disk_memberlist_t list = NULL, tmp;
270 int raid_level;
271
272 if (disk->dev->memberlist)
273 list = disk->dev->memberlist (disk);
274 while (list)
275 {
276 probe_abstraction (list->disk);
277
278 tmp = list->next;
279 free (list);
280 list = tmp;
281 }
282
283 if (disk->dev->id == GRUB_DISK_DEVICE_LVM_ID)
284 printf ("lvm ");
285
286 if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
287 grub_util_cryptodisk_print_abstraction (disk);
288
289 raid_level = probe_raid_level (disk);
290 if (raid_level >= 0)
291 {
292 printf ("raid ");
293 if (disk->dev->raidname)
294 printf ("%s ", disk->dev->raidname (disk));
295 }
296 if (raid_level == 5)
297 printf ("raid5rec ");
298 if (raid_level == 6)
299 printf ("raid6rec ");
300 }
301
302 static void
303 probe (const char *path, char *device_name)
304 {
305 char *drive_name = NULL;
306 char *grub_path = NULL;
307 char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL;
308 grub_device_t dev = NULL;
309 grub_fs_t fs;
310
311 if (path == NULL)
312 {
313 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__sun__)
314 if (! grub_util_check_char_device (device_name))
315 grub_util_error (_("%s is not a character device"), device_name);
316 #else
317 if (! grub_util_check_block_device (device_name))
318 grub_util_error (_("%s is not a block device"), device_name);
319 #endif
320 }
321 else
322 {
323 grub_path = canonicalize_file_name (path);
324 device_name = grub_guess_root_device (grub_path);
325 }
326
327 if (! device_name)
328 grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path);
329
330 if (print == PRINT_DEVICE)
331 {
332 printf ("%s\n", device_name);
333 goto end;
334 }
335
336 drive_name = grub_util_get_grub_dev (device_name);
337 if (! drive_name)
338 grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"),
339 device_name);
340
341 if (print == PRINT_DRIVE)
342 {
343 printf ("(%s)\n", drive_name);
344 goto end;
345 }
346
347 grub_util_info ("opening %s", drive_name);
348 dev = grub_device_open (drive_name);
349 if (! dev)
350 grub_util_error ("%s", _(grub_errmsg));
351
352 if (print == PRINT_HINT_STR)
353 {
354 const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
355 const char *orig_path = grub_util_devname_to_ofpath (osdev);
356 char *biosname, *bare, *efi;
357 const char *map;
358
359 if (orig_path)
360 {
361 char *ofpath = escape_of_path (orig_path);
362 printf ("--hint-ieee1275='");
363 print_full_name (ofpath, dev);
364 printf ("' ");
365 free (ofpath);
366 }
367
368 biosname = guess_bios_drive (device_name);
369 if (biosname)
370 {
371 printf ("--hint-bios=");
372 print_full_name (biosname, dev);
373 printf (" ");
374 }
375 free (biosname);
376
377 efi = guess_efi_drive (device_name);
378 if (efi)
379 {
380 printf ("--hint-efi=");
381 print_full_name (efi, dev);
382 printf (" ");
383 }
384 free (efi);
385
386 bare = guess_baremetal_drive (device_name);
387 if (bare)
388 {
389 printf ("--hint-baremetal=");
390 print_full_name (bare, dev);
391 printf (" ");
392 }
393 free (bare);
394
395 /* FIXME: Add ARC hint. */
396
397 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
398 if (map)
399 {
400 printf ("--hint='");
401 print_full_name (map, dev);
402 printf ("' ");
403 }
404 printf ("\n");
405
406 goto end;
407 }
408
409 if (print == PRINT_COMPATIBILITY_HINT)
410 {
411 const char *map;
412 char *biosname;
413 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
414 if (map)
415 {
416 print_full_name (map, dev);
417 printf ("\n");
418 goto end;
419 }
420 biosname = guess_bios_drive (device_name);
421 if (biosname)
422 print_full_name (biosname, dev);
423 printf ("\n");
424 free (biosname);
425 goto end;
426 }
427
428 if (print == PRINT_BIOS_HINT)
429 {
430 char *biosname;
431 biosname = guess_bios_drive (device_name);
432 if (biosname)
433 print_full_name (biosname, dev);
434 printf ("\n");
435 free (biosname);
436 goto end;
437 }
438 if (print == PRINT_IEEE1275_HINT)
439 {
440 const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
441 const char *orig_path = grub_util_devname_to_ofpath (osdev);
442 char *ofpath = escape_of_path (orig_path);
443 const char *map;
444
445 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
446 if (map)
447 {
448 printf (" ");
449 print_full_name (map, dev);
450 }
451
452 printf (" ");
453 print_full_name (ofpath, dev);
454
455 printf ("\n");
456 free (ofpath);
457 goto end;
458 }
459 if (print == PRINT_EFI_HINT)
460 {
461 char *biosname;
462 char *name;
463 const char *map;
464 biosname = guess_efi_drive (device_name);
465
466 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
467 if (map)
468 {
469 printf (" ");
470 print_full_name (map, dev);
471 }
472 if (biosname)
473 {
474 printf (" ");
475 print_full_name (biosname, dev);
476 }
477
478 printf ("\n");
479 free (biosname);
480 goto end;
481 }
482
483 if (print == PRINT_BAREMETAL_HINT)
484 {
485 char *biosname;
486 char *name;
487 const char *map;
488
489 biosname = guess_baremetal_drive (device_name);
490
491 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
492 if (map)
493 {
494 printf (" ");
495 print_full_name (map, dev);
496 }
497 if (biosname)
498 {
499 printf (" ");
500 print_full_name (biosname, dev);
501 }
502
503 printf ("\n");
504 free (biosname);
505 goto end;
506 }
507
508 if (print == PRINT_ARC_HINT)
509 {
510 const char *map;
511
512 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
513 if (map)
514 {
515 printf (" ");
516 print_full_name (map, dev);
517 }
518 printf ("\n");
519
520 /* FIXME */
521
522 goto end;
523 }
524
525 if (print == PRINT_ABSTRACTION)
526 {
527 probe_abstraction (dev->disk);
528 printf ("\n");
529 goto end;
530 }
531
532 if (print == PRINT_CRYPTODISK_UUID)
533 {
534 probe_cryptodisk_uuid (dev->disk);
535 printf ("\n");
536 goto end;
537 }
538
539 if (print == PRINT_PARTMAP)
540 {
541 /* Check if dev->disk itself is contained in a partmap. */
542 probe_partmap (dev->disk);
543 printf ("\n");
544 goto end;
545 }
546
547 fs = grub_fs_probe (dev);
548 if (! fs)
549 grub_util_error ("%s", _(grub_errmsg));
550
551 if (print == PRINT_FS)
552 {
553 printf ("%s\n", fs->name);
554 }
555 else if (print == PRINT_FS_UUID)
556 {
557 char *uuid;
558 if (! fs->uuid)
559 grub_util_error (_("%s does not support UUIDs"), fs->name);
560
561 if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE)
562 grub_util_error ("%s", grub_errmsg);
563
564 printf ("%s\n", uuid);
565 }
566 else if (print == PRINT_FS_LABEL)
567 {
568 char *label;
569 if (! fs->label)
570 grub_util_error (_("%s does not support labels"), fs->name);
571
572 if (fs->label (dev, &label) != GRUB_ERR_NONE)
573 grub_util_error ("%s", _(grub_errmsg));
574
575 printf ("%s\n", label);
576 }
577
578 end:
579 if (dev)
580 grub_device_close (dev);
581 free (grub_path);
582 free (filebuf_via_grub);
583 free (filebuf_via_sys);
584 free (drive_name);
585 }
586
587 static struct option options[] =
588 {
589 {"device", no_argument, 0, 'd'},
590 {"device-map", required_argument, 0, 'm'},
591 {"target", required_argument, 0, 't'},
592 {"help", no_argument, 0, 'h'},
593 {"version", no_argument, 0, 'V'},
594 {"verbose", no_argument, 0, 'v'},
595 {0, 0, 0, 0}
596 };
597
598 static void
599 usage (int status)
600 {
601 if (status)
602 fprintf (stderr,
603 _("Try `%s --help' for more information.\n"), program_name);
604 else
605 printf (_("\
606 Usage: %s [OPTION]... [PATH|DEVICE]\n\
607 \n\
608 Probe device information for a given path (or device, if the -d option is given).\n\
609 \n\
610 -d, --device given argument is a system device, not a path\n\
611 -m, --device-map=FILE use FILE as the device map [default=%s]\n\
612 -t, --target=(fs|fs_uuid|fs_label|drive|device|partmap|abstraction|cryptodisk_uuid)\n\
613 print filesystem module, GRUB drive, system device, partition map module, abstraction module or CRYPTO UUID [default=fs]\n\
614 -h, --help display this message and exit\n\
615 -V, --version print version information and exit\n\
616 -v, --verbose print verbose messages\n\
617 \n\
618 Report bugs to <%s>.\n\
619 "), program_name,
620 DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT);
621
622 exit (status);
623 }
624
625 int
626 main (int argc, char *argv[])
627 {
628 char *dev_map = 0;
629 char *argument;
630
631 set_program_name (argv[0]);
632
633 grub_util_init_nls ();
634
635 /* Check for options. */
636 while (1)
637 {
638 int c = getopt_long (argc, argv, "dm:t:hVv", options, 0);
639
640 if (c == -1)
641 break;
642 else
643 switch (c)
644 {
645 case 'd':
646 argument_is_device = 1;
647 break;
648
649 case 'm':
650 if (dev_map)
651 free (dev_map);
652
653 dev_map = xstrdup (optarg);
654 break;
655
656 case 't':
657 if (!strcmp (optarg, "fs"))
658 print = PRINT_FS;
659 else if (!strcmp (optarg, "fs_uuid"))
660 print = PRINT_FS_UUID;
661 else if (!strcmp (optarg, "fs_label"))
662 print = PRINT_FS_LABEL;
663 else if (!strcmp (optarg, "drive"))
664 print = PRINT_DRIVE;
665 else if (!strcmp (optarg, "device"))
666 print = PRINT_DEVICE;
667 else if (!strcmp (optarg, "partmap"))
668 print = PRINT_PARTMAP;
669 else if (!strcmp (optarg, "abstraction"))
670 print = PRINT_ABSTRACTION;
671 else if (!strcmp (optarg, "cryptodisk_uuid"))
672 print = PRINT_CRYPTODISK_UUID;
673 else if (!strcmp (optarg, "hints_string"))
674 print = PRINT_HINT_STR;
675 else if (!strcmp (optarg, "bios_hints"))
676 print = PRINT_BIOS_HINT;
677 else if (!strcmp (optarg, "ieee1275_hints"))
678 print = PRINT_IEEE1275_HINT;
679 else if (!strcmp (optarg, "baremetal_hints"))
680 print = PRINT_BAREMETAL_HINT;
681 else if (!strcmp (optarg, "efi_hints"))
682 print = PRINT_EFI_HINT;
683 else if (!strcmp (optarg, "arc_hints"))
684 print = PRINT_ARC_HINT;
685 else if (!strcmp (optarg, "compatibility_hint"))
686 print = PRINT_COMPATIBILITY_HINT;
687 else
688 usage (1);
689 break;
690
691 case 'h':
692 usage (0);
693 break;
694
695 case 'V':
696 printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
697 return 0;
698
699 case 'v':
700 verbosity++;
701 break;
702
703 default:
704 usage (1);
705 break;
706 }
707 }
708
709 if (verbosity > 1)
710 grub_env_set ("debug", "all");
711
712 /* Obtain ARGUMENT. */
713 if (optind >= argc)
714 {
715 fprintf (stderr, _("No path or device is specified.\n"));
716 usage (1);
717 }
718
719 if (optind + 1 != argc)
720 {
721 fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind + 1]);
722 usage (1);
723 }
724
725 argument = argv[optind];
726
727 /* Initialize the emulated biosdisk driver. */
728 grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP);
729
730 /* Initialize all modules. */
731 grub_init_all ();
732 grub_gcry_init_all ();
733
734 grub_lvm_fini ();
735 grub_mdraid09_fini ();
736 grub_mdraid1x_fini ();
737 grub_raid_fini ();
738 grub_raid_init ();
739 grub_mdraid09_init ();
740 grub_mdraid1x_init ();
741 grub_lvm_init ();
742
743 /* Do it. */
744 if (argument_is_device)
745 probe (NULL, argument);
746 else
747 probe (argument, NULL);
748
749 /* Free resources. */
750 grub_gcry_fini_all ();
751 grub_fini_all ();
752 grub_util_biosdisk_fini ();
753
754 free (dev_map);
755
756 return 0;
757 }