]> git.proxmox.com Git - grub2.git/blame - util/grub-probe.c
fs/ntfs: Fix various OOB reads and writes (CVE-2023-4692, CVE-2023-4693)
[grub2.git] / util / grub-probe.c
CommitLineData
ddd5cee9 1/* grub-probe.c - probe device information for a given path */
8b5f3938 2/*
3 * GRUB -- GRand Unified Bootloader
2f1a3acf 4 * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
8b5f3938 5 *
5a79f472 6 * GRUB is free software: you can redistribute it and/or modify
8b5f3938 7 * it under the terms of the GNU General Public License as published by
5a79f472 8 * the Free Software Foundation, either version 3 of the License, or
8b5f3938 9 * (at your option) any later version.
10 *
5a79f472 11 * GRUB is distributed in the hope that it will be useful,
8b5f3938 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
5a79f472 17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
8b5f3938 18 */
19
20#include <config.h>
21#include <grub/types.h>
8c411768 22#include <grub/emu/misc.h>
8b5f3938 23#include <grub/util/misc.h>
24#include <grub/device.h>
25#include <grub/disk.h>
2a9525e6 26#include <grub/file.h>
8b5f3938 27#include <grub/fs.h>
28#include <grub/partition.h>
71acf5e5 29#include <grub/msdos_partition.h>
39cfdaa9 30#include <grub/gpt_partition.h>
0c0bcffc 31#include <grub/i386/pc/boot.h>
8c411768
BC
32#include <grub/emu/hostdisk.h>
33#include <grub/emu/getroot.h>
9cacaa17 34#include <grub/term.h>
0bf6d401 35#include <grub/env.h>
076e7c0f 36#include <grub/diskfilter.h>
8a4c07fd 37#include <grub/i18n.h>
6babad5e
VS
38#include <grub/emu/misc.h>
39#include <grub/util/ofpath.h>
50ad7d9c 40#include <grub/crypto.h>
8585e54b 41#include <grub/cryptodisk.h>
8b5f3938 42
43#include <stdio.h>
44#include <unistd.h>
45#include <string.h>
46#include <stdlib.h>
8e1e4e39 47#include <assert.h>
8b5f3938 48
49#define _GNU_SOURCE 1
ca3e2088
VS
50
51#pragma GCC diagnostic ignored "-Wmissing-prototypes"
52#pragma GCC diagnostic ignored "-Wmissing-declarations"
8e1e4e39 53#include <argp.h>
ca3e2088
VS
54#pragma GCC diagnostic error "-Wmissing-prototypes"
55#pragma GCC diagnostic error "-Wmissing-declarations"
8b5f3938 56
8a4c07fd
RM
57#include "progname.h"
58
1eb8c802 59enum {
60 PRINT_FS,
62191274 61 PRINT_FS_UUID,
0806b63c 62 PRINT_FS_LABEL,
1eb8c802 63 PRINT_DRIVE,
64 PRINT_DEVICE,
65 PRINT_PARTMAP,
0c0bcffc 66 PRINT_PARTUUID,
1eb8c802 67 PRINT_ABSTRACTION,
17785932 68 PRINT_CRYPTODISK_UUID,
6babad5e
VS
69 PRINT_HINT_STR,
70 PRINT_BIOS_HINT,
71 PRINT_IEEE1275_HINT,
72 PRINT_BAREMETAL_HINT,
73 PRINT_EFI_HINT,
74 PRINT_ARC_HINT,
66832792 75 PRINT_COMPATIBILITY_HINT,
8be63f2e 76 PRINT_MSDOS_PARTTYPE,
39cfdaa9 77 PRINT_GPT_PARTTYPE,
fe8c2f11 78 PRINT_ZERO_CHECK,
8be63f2e 79 PRINT_DISK
1eb8c802 80};
ddd5cee9 81
46f8d358
AB
82static const char *targets[] =
83 {
84 [PRINT_FS] = "fs",
85 [PRINT_FS_UUID] = "fs_uuid",
86 [PRINT_FS_LABEL] = "fs_label",
87 [PRINT_DRIVE] = "drive",
88 [PRINT_DEVICE] = "device",
89 [PRINT_PARTMAP] = "partmap",
0c0bcffc 90 [PRINT_PARTUUID] = "partuuid",
46f8d358
AB
91 [PRINT_ABSTRACTION] = "abstraction",
92 [PRINT_CRYPTODISK_UUID] = "cryptodisk_uuid",
93 [PRINT_HINT_STR] = "hints_string",
94 [PRINT_BIOS_HINT] = "bios_hints",
95 [PRINT_IEEE1275_HINT] = "ieee1275_hints",
96 [PRINT_BAREMETAL_HINT] = "baremetal_hints",
97 [PRINT_EFI_HINT] = "efi_hints",
98 [PRINT_ARC_HINT] = "arc_hints",
99 [PRINT_COMPATIBILITY_HINT] = "compatibility_hint",
100 [PRINT_MSDOS_PARTTYPE] = "msdos_parttype",
101 [PRINT_GPT_PARTTYPE] = "gpt_parttype",
102 [PRINT_ZERO_CHECK] = "zero_check",
103 [PRINT_DISK] = "disk",
104 };
105
29805028 106static int print = PRINT_FS;
79ca2d78 107static unsigned int argument_is_device = 0;
ddd5cee9 108
46f8d358
AB
109static char *
110get_targets_string (void)
111{
112 char **arr = xmalloc (sizeof (targets));
113 int len = 0;
114 char *str;
115 char *ptr;
116 unsigned i;
117
118 memcpy (arr, targets, sizeof (targets));
119 qsort (arr, ARRAY_SIZE (targets), sizeof (char *), grub_qsort_strcmp);
120 for (i = 0; i < ARRAY_SIZE (targets); i++)
121 len += grub_strlen (targets[i]) + 2;
122 ptr = str = xmalloc (len);
123 for (i = 0; i < ARRAY_SIZE (targets); i++)
124 {
125 ptr = grub_stpcpy (ptr, arr[i]);
126 *ptr++ = ',';
127 *ptr++ = ' ';
128 }
129 ptr[-2] = '\0';
130 free (arr);
131
132 return str;
133}
134
c2b86ae1
NV
135static int
136print_gpt_guid (grub_gpt_part_guid_t guid)
137{
138 guid.data1 = grub_le_to_cpu32 (guid.data1);
139 guid.data2 = grub_le_to_cpu16 (guid.data2);
140 guid.data3 = grub_le_to_cpu16 (guid.data3);
141
142 return grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
143 guid.data1, guid.data2, guid.data3, guid.data4[0],
144 guid.data4[1], guid.data4[2], guid.data4[3],
145 guid.data4[4], guid.data4[5], guid.data4[6],
146 guid.data4[7]);
147}
148
bf25f879 149static void
24024dac 150do_print (const char *x, void *data)
bf25f879 151{
24024dac
CW
152 char delim = *(const char *) data;
153 grub_printf ("%s%c", x, delim);
bf25f879
VS
154}
155
b92f0c18 156static void
24024dac 157probe_partmap (grub_disk_t disk, char delim)
b92f0c18 158{
15cb7d43 159 grub_partition_t part;
50ad7d9c 160 grub_disk_memberlist_t list = NULL, tmp;
15cb7d43 161
b92f0c18 162 if (disk->partition == NULL)
163 {
70a14d3d 164 grub_util_info ("no partition map found for %s", disk->name);
b92f0c18 165 }
b39f9d20 166
15cb7d43 167 for (part = disk->partition; part; part = part->parent)
24024dac 168 printf ("%s%c", part->partmap->name, delim);
50ad7d9c 169
4786a90f 170 if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID)
24024dac 171 grub_diskfilter_get_partmap (disk, do_print, &delim);
4786a90f 172
50ad7d9c 173 /* In case of LVM/RAID, check the member devices as well. */
38409196 174 if (disk->dev->disk_memberlist)
50ad7d9c 175 {
38409196 176 list = disk->dev->disk_memberlist (disk);
50ad7d9c
VS
177 }
178 while (list)
179 {
24024dac 180 probe_partmap (list->disk, delim);
50ad7d9c
VS
181 tmp = list->next;
182 free (list);
183 list = tmp;
184 }
b92f0c18 185}
186
0c0bcffc
NV
187static void
188probe_partuuid (grub_disk_t disk, char delim)
189{
190 grub_partition_t p = disk->partition;
191
192 /*
193 * Nested partitions not supported for now.
194 * Non-nested partitions must have disk->partition->parent == NULL
195 */
196 if (p && p->parent == NULL)
197 {
198 disk->partition = p->parent;
199
200 if (strcmp(p->partmap->name, "msdos") == 0)
201 {
202 /*
203 * The partition GUID for MSDOS is the partition number (starting
204 * with 1) prepended with the NT disk signature.
205 */
206 grub_uint32_t nt_disk_sig;
207
208 if (grub_disk_read (disk, 0, GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
209 sizeof(nt_disk_sig), &nt_disk_sig) == 0)
210 grub_printf ("%08x-%02x",
211 grub_le_to_cpu32(nt_disk_sig), 1 + p->number);
212 }
213 else if (strcmp(p->partmap->name, "gpt") == 0)
214 {
215 struct grub_gpt_partentry gptdata;
216
217 if (grub_disk_read (disk, p->offset, p->index,
218 sizeof(gptdata), &gptdata) == 0)
219 print_gpt_guid(gptdata.guid);
220 }
221
222 disk->partition = p;
223 }
224}
225
9d647e4e 226static void
24024dac 227probe_cryptodisk_uuid (grub_disk_t disk, char delim)
9d647e4e
VS
228{
229 grub_disk_memberlist_t list = NULL, tmp;
230
231 /* In case of LVM/RAID, check the member devices as well. */
38409196 232 if (disk->dev->disk_memberlist)
9d647e4e 233 {
38409196 234 list = disk->dev->disk_memberlist (disk);
9d647e4e
VS
235 }
236 while (list)
237 {
24024dac 238 probe_cryptodisk_uuid (list->disk, delim);
9d647e4e
VS
239 tmp = list->next;
240 free (list);
241 list = tmp;
242 }
8585e54b 243 if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
bf25f879
VS
244 {
245 const char *uu = grub_util_cryptodisk_get_uuid (disk);
24024dac 246 grub_printf ("%s%c", uu, delim);
bf25f879 247 }
b92f0c18 248}
249
f45d6cfc 250static int
251probe_raid_level (grub_disk_t disk)
252{
917dd370
CW
253 /* disk might be NULL in the case of a LVM physical volume with no LVM
254 signature. Ignore such cases here. */
255 if (!disk)
256 return -1;
257
076e7c0f 258 if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
f45d6cfc 259 return -1;
260
076e7c0f
VS
261 if (disk->name[0] != 'm' || disk->name[1] != 'd')
262 return -1;
263
264 if (!((struct grub_diskfilter_lv *) disk->data)->segments)
265 return -1;
266 return ((struct grub_diskfilter_lv *) disk->data)->segments->type;
f45d6cfc 267}
268
50ad7d9c 269static void
24024dac 270probe_abstraction (grub_disk_t disk, char delim)
50ad7d9c
VS
271{
272 grub_disk_memberlist_t list = NULL, tmp;
273 int raid_level;
274
38409196
VS
275 if (disk->dev->disk_memberlist)
276 list = disk->dev->disk_memberlist (disk);
50ad7d9c
VS
277 while (list)
278 {
24024dac 279 probe_abstraction (list->disk, delim);
50ad7d9c
VS
280
281 tmp = list->next;
282 free (list);
283 list = tmp;
284 }
285
076e7c0f 286 if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
775b284d
AB
287 && (grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0 ||
288 grub_memcmp (disk->name, "lvmid/", sizeof ("lvmid/") - 1) == 0))
24024dac 289 printf ("lvm%c", delim);
50ad7d9c 290
076e7c0f
VS
291 if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
292 && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0)
24024dac 293 printf ("ldm%c", delim);
076e7c0f 294
8585e54b 295 if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
24024dac 296 grub_util_cryptodisk_get_abstraction (disk, do_print, &delim);
50ad7d9c
VS
297
298 raid_level = probe_raid_level (disk);
299 if (raid_level >= 0)
300 {
24024dac 301 printf ("diskfilter%c", delim);
38409196
VS
302 if (disk->dev->disk_raidname)
303 printf ("%s%c", disk->dev->disk_raidname (disk), delim);
50ad7d9c
VS
304 }
305 if (raid_level == 5)
24024dac 306 printf ("raid5rec%c", delim);
50ad7d9c 307 if (raid_level == 6)
24024dac 308 printf ("raid6rec%c", delim);
50ad7d9c
VS
309}
310
8b5f3938 311static void
cf5f7ee7 312probe (const char *path, char **device_names, char delim)
8b5f3938 313{
cf5f7ee7
VS
314 char **drives_names = NULL;
315 char **curdev, **curdrive;
2a9525e6 316 char *grub_path = NULL;
cf5f7ee7 317 int ndev = 0;
b39f9d20 318
cf5f7ee7 319 if (path != NULL)
828bc390 320 {
27d1a67f 321 grub_path = grub_canonicalize_file_name (path);
65f08dbf 322 if (! grub_path)
22099030 323 grub_util_error (_("failed to get canonical path of `%s'"), path);
cf5f7ee7
VS
324 device_names = grub_guess_root_devices (grub_path);
325 free (grub_path);
828bc390 326 }
79ca2d78 327
cf5f7ee7 328 if (! device_names)
10f0117b 329 grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path);
ddd5cee9 330
331 if (print == PRINT_DEVICE)
332 {
cf5f7ee7
VS
333 for (curdev = device_names; *curdev; curdev++)
334 {
335 printf ("%s", *curdev);
336 putchar (delim);
337 }
f826d914 338 goto free_device_names;
ddd5cee9 339 }
340
8be63f2e
VS
341 if (print == PRINT_DISK)
342 {
343 for (curdev = device_names; *curdev; curdev++)
344 {
345 char *disk;
346 disk = grub_util_get_os_disk (*curdev);
347 if (!disk)
348 {
349 grub_print_error ();
350 continue;
351 }
352 printf ("%s", disk);
353 putchar (delim);
11aae26c 354 free (disk);
8be63f2e 355 }
f826d914 356 goto free_device_names;
8be63f2e
VS
357 }
358
cf5f7ee7 359 for (curdev = device_names; *curdev; curdev++)
ddd5cee9 360 {
cf5f7ee7
VS
361 grub_util_pull_device (*curdev);
362 ndev++;
8b5f3938 363 }
f725fa7c
PJ
364
365 drives_names = xcalloc (ndev + 1, sizeof (drives_names[0]));
8b5f3938 366
cf5f7ee7
VS
367 for (curdev = device_names, curdrive = drives_names; *curdev; curdev++,
368 curdrive++)
369 {
370 *curdrive = grub_util_get_grub_dev (*curdev);
371 if (! *curdrive)
372 grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"),
373 *curdev);
374 }
375 *curdrive = 0;
8b5f3938 376
65f08dbf
RL
377 if (print == PRINT_DRIVE)
378 {
379 for (curdrive = drives_names; *curdrive; curdrive++)
380 {
381 printf ("(%s)", *curdrive);
382 putchar (delim);
383 }
384 goto end;
385 }
386
fe8c2f11
VS
387 if (print == PRINT_ZERO_CHECK)
388 {
389 for (curdev = drives_names; *curdev; curdev++)
390 {
391 grub_device_t dev = NULL;
392 grub_uint32_t buffer[32768];
393 grub_disk_addr_t addr;
394 grub_disk_addr_t dsize;
395
396 grub_util_info ("opening %s", *curdev);
397 dev = grub_device_open (*curdev);
398 if (! dev || !dev->disk)
399 grub_util_error ("%s", grub_errmsg);
400
880dfd8f 401 dsize = grub_disk_native_sectors (dev->disk);
fe8c2f11
VS
402 for (addr = 0; addr < dsize;
403 addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE)
404 {
405 grub_size_t sz = sizeof (buffer);
406 grub_uint32_t *ptr;
407
408 if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr)
409 sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE;
410 grub_disk_read (dev->disk, addr, 0, sz, buffer);
411
412 for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++)
413 if (*ptr)
414 {
415 grub_printf ("false\n");
416 grub_device_close (dev);
417 goto end;
418 }
419 }
420
421 grub_device_close (dev);
422 }
423 grub_printf ("true\n");
424 }
425
cf5f7ee7
VS
426 if (print == PRINT_FS || print == PRINT_FS_UUID
427 || print == PRINT_FS_LABEL)
6babad5e 428 {
cf5f7ee7
VS
429 grub_device_t dev = NULL;
430 grub_fs_t fs;
6babad5e 431
cf5f7ee7
VS
432 grub_util_info ("opening %s", drives_names[0]);
433 dev = grub_device_open (drives_names[0]);
434 if (! dev)
36eb7379 435 grub_util_error ("%s", grub_errmsg);
cf5f7ee7
VS
436
437 fs = grub_fs_probe (dev);
438 if (! fs)
36eb7379 439 grub_util_error ("%s", grub_errmsg);
6babad5e 440
cf5f7ee7 441 if (print == PRINT_FS)
6babad5e 442 {
cf5f7ee7
VS
443 printf ("%s", fs->name);
444 putchar (delim);
6babad5e 445 }
cf5f7ee7 446 else if (print == PRINT_FS_UUID)
6babad5e 447 {
cf5f7ee7 448 char *uuid;
ad4bfeec 449 if (! fs->fs_uuid)
cf5f7ee7 450 grub_util_error (_("%s does not support UUIDs"), fs->name);
6babad5e 451
ad4bfeec 452 if (fs->fs_uuid (dev, &uuid) != GRUB_ERR_NONE)
cf5f7ee7
VS
453 grub_util_error ("%s", grub_errmsg);
454
455 printf ("%s", uuid);
456 putchar (delim);
6babad5e 457 }
cf5f7ee7
VS
458 else if (print == PRINT_FS_LABEL)
459 {
460 char *label;
ad4bfeec 461 if (! fs->fs_label)
9c4b5c13
VS
462 grub_util_error (_("filesystem `%s' does not support labels"),
463 fs->name);
6babad5e 464
ad4bfeec 465 if (fs->fs_label (dev, &label) != GRUB_ERR_NONE)
36eb7379 466 grub_util_error ("%s", grub_errmsg);
6babad5e 467
cf5f7ee7
VS
468 printf ("%s", label);
469 putchar (delim);
6babad5e 470 }
592fd0e4 471 grub_device_close (dev);
6babad5e
VS
472 goto end;
473 }
474
cf5f7ee7
VS
475 for (curdrive = drives_names, curdev = device_names; *curdrive;
476 curdrive++, curdev++)
63fe43f3 477 {
cf5f7ee7 478 grub_device_t dev = NULL;
63fe43f3 479
cf5f7ee7
VS
480 grub_util_info ("opening %s", *curdrive);
481 dev = grub_device_open (*curdrive);
482 if (! dev)
36eb7379 483 grub_util_error ("%s", grub_errmsg);
cf5f7ee7
VS
484
485 if (print == PRINT_HINT_STR)
6babad5e 486 {
cf5f7ee7 487 const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
4358e0c8 488 char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0;
cf5f7ee7
VS
489 char *biosname, *bare, *efi;
490 const char *map;
491
492 if (ofpath)
493 {
1c715b5a
VS
494 char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/"));
495 char *p;
ba44ca6d 496 p = grub_stpcpy (tmp, "ieee1275/");
1c715b5a 497 strcpy (p, ofpath);
cf5f7ee7 498 printf ("--hint-ieee1275='");
cd46aa6c 499 grub_util_fprint_full_disk_name (stdout, tmp, dev);
cf5f7ee7 500 printf ("' ");
1c715b5a 501 free (tmp);
4358e0c8 502 free (ofpath);
cf5f7ee7
VS
503 }
504
cd46aa6c 505 biosname = grub_util_guess_bios_drive (*curdev);
cf5f7ee7
VS
506 if (biosname)
507 {
508 printf ("--hint-bios=");
cd46aa6c 509 grub_util_fprint_full_disk_name (stdout, biosname, dev);
cf5f7ee7
VS
510 printf (" ");
511 }
512 free (biosname);
513
cd46aa6c 514 efi = grub_util_guess_efi_drive (*curdev);
cf5f7ee7
VS
515 if (efi)
516 {
517 printf ("--hint-efi=");
cd46aa6c 518 grub_util_fprint_full_disk_name (stdout, efi, dev);
cf5f7ee7
VS
519 printf (" ");
520 }
521 free (efi);
522
cd46aa6c 523 bare = grub_util_guess_baremetal_drive (*curdev);
cf5f7ee7
VS
524 if (bare)
525 {
526 printf ("--hint-baremetal=");
cd46aa6c 527 grub_util_fprint_full_disk_name (stdout, bare, dev);
cf5f7ee7
VS
528 printf (" ");
529 }
530 free (bare);
531
532 /* FIXME: Add ARC hint. */
533
534 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
535 if (map)
536 {
537 printf ("--hint='");
cd46aa6c 538 grub_util_fprint_full_disk_name (stdout, map, dev);
cf5f7ee7
VS
539 printf ("' ");
540 }
588744d0
VS
541 if (curdrive[1])
542 printf (" ");
543 else
544 printf ("\n");
cf5f7ee7
VS
545 }
546
03f1f24e 547 else if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT
cf5f7ee7
VS
548 || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT
549 || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT)
550 && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID)
6babad5e 551 {
cd46aa6c 552 grub_util_fprint_full_disk_name (stdout, dev->disk->name, dev);
cf5f7ee7 553 putchar (delim);
6babad5e
VS
554 }
555
03f1f24e 556 else if (print == PRINT_COMPATIBILITY_HINT)
63fe43f3 557 {
cf5f7ee7
VS
558 const char *map;
559 char *biosname;
560 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
561 if (map)
562 {
cd46aa6c 563 grub_util_fprint_full_disk_name (stdout, map, dev);
cf5f7ee7
VS
564 putchar (delim);
565 grub_device_close (dev);
566 /* Compatibility hint is one device only. */
567 break;
568 }
cd46aa6c 569 biosname = grub_util_guess_bios_drive (*curdev);
cf5f7ee7
VS
570 if (biosname)
571 {
cd46aa6c 572 grub_util_fprint_full_disk_name (stdout, biosname, dev);
cf5f7ee7 573 putchar (delim);
03f1f24e
AB
574 free (biosname);
575 /* Compatibility hint is one device only. */
576 grub_device_close (dev);
577 break;
cf5f7ee7 578 }
63fe43f3 579 }
6babad5e 580
03f1f24e 581 else if (print == PRINT_BIOS_HINT)
6babad5e 582 {
cf5f7ee7 583 char *biosname;
cd46aa6c 584 biosname = grub_util_guess_bios_drive (*curdev);
cf5f7ee7
VS
585 if (biosname)
586 {
cd46aa6c 587 grub_util_fprint_full_disk_name (stdout, biosname, dev);
cf5f7ee7 588 putchar (delim);
03f1f24e 589 free (biosname);
cf5f7ee7 590 }
6babad5e 591 }
03f1f24e 592 else if (print == PRINT_IEEE1275_HINT)
6babad5e 593 {
cf5f7ee7 594 const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
11aae26c 595 char *ofpath = grub_util_devname_to_ofpath (osdev);
cf5f7ee7
VS
596 const char *map;
597
598 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
599 if (map)
600 {
cd46aa6c 601 grub_util_fprint_full_disk_name (stdout, map, dev);
cf5f7ee7
VS
602 putchar (delim);
603 }
604
605 if (ofpath)
606 {
1c715b5a
VS
607 char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/"));
608 char *p;
ba44ca6d 609 p = grub_stpcpy (tmp, "ieee1275/");
1c715b5a 610 strcpy (p, ofpath);
cd46aa6c 611 grub_util_fprint_full_disk_name (stdout, tmp, dev);
1c715b5a 612 free (tmp);
11aae26c 613 free (ofpath);
cf5f7ee7
VS
614 putchar (delim);
615 }
6babad5e 616 }
03f1f24e 617 else if (print == PRINT_EFI_HINT)
6babad5e 618 {
cf5f7ee7 619 char *biosname;
cf5f7ee7 620 const char *map;
cd46aa6c 621 biosname = grub_util_guess_efi_drive (*curdev);
cf5f7ee7
VS
622
623 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
624 if (map)
625 {
cd46aa6c 626 grub_util_fprint_full_disk_name (stdout, map, dev);
cf5f7ee7
VS
627 putchar (delim);
628 }
629 if (biosname)
630 {
cd46aa6c 631 grub_util_fprint_full_disk_name (stdout, biosname, dev);
cf5f7ee7 632 putchar (delim);
03f1f24e 633 free (biosname);
cf5f7ee7 634 }
6babad5e 635 }
cf5f7ee7 636
03f1f24e 637 else if (print == PRINT_BAREMETAL_HINT)
6babad5e 638 {
cf5f7ee7 639 char *biosname;
cf5f7ee7
VS
640 const char *map;
641
cd46aa6c 642 biosname = grub_util_guess_baremetal_drive (*curdev);
cf5f7ee7
VS
643
644 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
645 if (map)
646 {
cd46aa6c 647 grub_util_fprint_full_disk_name (stdout, map, dev);
cf5f7ee7
VS
648 putchar (delim);
649 }
650 if (biosname)
651 {
cd46aa6c 652 grub_util_fprint_full_disk_name (stdout, biosname, dev);
cf5f7ee7 653 putchar (delim);
03f1f24e 654 free (biosname);
cf5f7ee7 655 }
6babad5e
VS
656 }
657
03f1f24e 658 else if (print == PRINT_ARC_HINT)
6babad5e 659 {
cf5f7ee7
VS
660 const char *map;
661
662 map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
663 if (map)
664 {
cd46aa6c 665 grub_util_fprint_full_disk_name (stdout, map, dev);
cf5f7ee7
VS
666 putchar (delim);
667 }
6babad5e 668 }
75f396cc 669
03f1f24e
AB
670 else if (print == PRINT_ABSTRACTION)
671 probe_abstraction (dev->disk, delim);
62191274 672
03f1f24e
AB
673 else if (print == PRINT_CRYPTODISK_UUID)
674 probe_cryptodisk_uuid (dev->disk, delim);
62191274 675
03f1f24e
AB
676 else if (print == PRINT_PARTMAP)
677 /* Check if dev->disk itself is contained in a partmap. */
678 probe_partmap (dev->disk, delim);
0806b63c 679
0c0bcffc
NV
680 else if (print == PRINT_PARTUUID)
681 {
682 probe_partuuid (dev->disk, delim);
683 putchar (delim);
684 }
685
03f1f24e 686 else if (print == PRINT_MSDOS_PARTTYPE)
cf5f7ee7
VS
687 {
688 if (dev->disk->partition
689 && strcmp(dev->disk->partition->partmap->name, "msdos") == 0)
690 printf ("%02x", dev->disk->partition->msdostype);
0806b63c 691
cf5f7ee7 692 putchar (delim);
cf5f7ee7 693 }
39cfdaa9 694
03f1f24e 695 else if (print == PRINT_GPT_PARTTYPE)
39cfdaa9
PFS
696 {
697 if (dev->disk->partition
698 && strcmp (dev->disk->partition->partmap->name, "gpt") == 0)
699 {
700 struct grub_gpt_partentry gptdata;
701 grub_partition_t p = dev->disk->partition;
702 dev->disk->partition = dev->disk->partition->parent;
703
704 if (grub_disk_read (dev->disk, p->offset, p->index,
705 sizeof (gptdata), &gptdata) == 0)
c2b86ae1 706 print_gpt_guid(gptdata.type);
39cfdaa9
PFS
707 dev->disk->partition = p;
708 }
709 putchar (delim);
39cfdaa9 710 }
03f1f24e
AB
711
712 grub_device_close (dev);
0806b63c 713 }
62191274 714
e0994b8b 715 end:
cf5f7ee7
VS
716 for (curdrive = drives_names; *curdrive; curdrive++)
717 free (*curdrive);
718 free (drives_names);
d5cc487d 719
f826d914 720free_device_names:
d5cc487d
AB
721 if (path != NULL)
722 {
723 for (curdev = device_names; *curdev; curdev++)
724 free (*curdev);
725 free (device_names);
726 }
8b5f3938 727}
728
8e1e4e39
VS
729static struct argp_option options[] = {
730 {"device", 'd', 0, 0,
731 N_("given argument is a system device, not a path"), 0},
732 {"device-map", 'm', N_("FILE"), 0,
733 N_("use FILE as the device map [default=%s]"), 0},
46f8d358 734 {"target", 't', N_("TARGET"), 0, 0, 0},
b525fd83 735 {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
9b35fe81 736 {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0},
8e1e4e39
VS
737 { 0, 0, 0, 0, 0, 0 }
738};
8b5f3938 739
ae558c2c
VS
740#pragma GCC diagnostic ignored "-Wformat-nonliteral"
741
8e1e4e39
VS
742static char *
743help_filter (int key, const char *text, void *input __attribute__ ((unused)))
8b5f3938 744{
8e1e4e39
VS
745 switch (key)
746 {
747 case 'm':
748 return xasprintf (text, DEFAULT_DEVICE_MAP);
749
46f8d358
AB
750 case 't':
751 {
afd6b6bb 752 char *ret, *t = get_targets_string (), *def;
46f8d358 753
afd6b6bb
VS
754 def = xasprintf (_("[default=%s]"), targets[print]);
755
756 ret = xasprintf ("%s\n%s %s %s", _("print TARGET"),
757 _("available targets:"), t, def);
46f8d358 758 free (t);
018f79da 759 free (def);
46f8d358
AB
760 return ret;
761 }
762
8e1e4e39
VS
763 default:
764 return (char *) text;
765 }
8b5f3938 766}
767
ae558c2c
VS
768#pragma GCC diagnostic error "-Wformat-nonliteral"
769
8e1e4e39 770struct arguments
8b5f3938 771{
8e1e4e39
VS
772 char **devices;
773 size_t device_max;
774 size_t ndevices;
775 char *dev_map;
776 int zero_delim;
777};
b39f9d20 778
8e1e4e39
VS
779static error_t
780argp_parser (int key, char *arg, struct argp_state *state)
781{
782 /* Get the input argument from argp_parse, which we
783 know is a pointer to our arguments structure. */
784 struct arguments *arguments = state->input;
2f1a3acf 785
8e1e4e39 786 switch (key)
8b5f3938 787 {
8e1e4e39
VS
788 case 'd':
789 argument_is_device = 1;
790 break;
791
792 case 'm':
793 if (arguments->dev_map)
794 free (arguments->dev_map);
795
796 arguments->dev_map = xstrdup (arg);
797 break;
798
799 case 't':
46f8d358
AB
800 {
801 int i;
802
803 for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++)
804 if (strcmp (arg, targets[i]) == 0)
805 {
806 print = i;
807 break;
808 }
809 if (i == ARRAY_SIZE (targets))
810 argp_usage (state);
811 }
8e1e4e39 812 break;
79ca2d78 813
8e1e4e39
VS
814 case '0':
815 arguments->zero_delim = 1;
816 break;
8b5f3938 817
8e1e4e39
VS
818 case 'v':
819 verbosity++;
820 break;
8b5f3938 821
8e1e4e39
VS
822 case ARGP_KEY_NO_ARGS:
823 fprintf (stderr, "%s", _("No path or device is specified.\n"));
824 argp_usage (state);
825 break;
ddd5cee9 826
8e1e4e39
VS
827 case ARGP_KEY_ARG:
828 assert (arguments->ndevices < arguments->device_max);
829 arguments->devices[arguments->ndevices++] = xstrdup(arg);
830 break;
8b5f3938 831
8e1e4e39
VS
832 default:
833 return ARGP_ERR_UNKNOWN;
834 }
835 return 0;
836}
cf5f7ee7 837
8e1e4e39
VS
838static struct argp argp = {
839 options, argp_parser, N_("[OPTION]... [PATH|DEVICE]"),
840 N_("\
841Probe device information for a given path (or device, if the -d option is given)."),
842 NULL, help_filter, NULL
843};
8b5f3938 844
8e1e4e39
VS
845int
846main (int argc, char *argv[])
847{
848 char delim;
849 struct arguments arguments;
8b5f3938 850
ae5540d3 851 grub_util_host_init (&argc, &argv);
8e1e4e39
VS
852
853 memset (&arguments, 0, sizeof (struct arguments));
854 arguments.device_max = argc + 1;
855 arguments.devices = xmalloc ((arguments.device_max + 1)
856 * sizeof (arguments.devices[0]));
857 memset (arguments.devices, 0, (arguments.device_max + 1)
858 * sizeof (arguments.devices[0]));
859
860 /* Parse our arguments */
861 if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
862 {
863 fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
864 exit(1);
8b5f3938 865 }
866
91a4bf68 867 if (verbosity > 1)
868 grub_env_set ("debug", "all");
869
79ca2d78 870 /* Obtain ARGUMENT. */
8e1e4e39 871 if (arguments.ndevices != 1 && !argument_is_device)
8b5f3938 872 {
8e1e4e39 873 char *program = xstrdup(program_name);
67093bc0
VS
874 fprintf (stderr, _("Unknown extra argument `%s'."), arguments.devices[1]);
875 fprintf (stderr, "\n");
8e1e4e39
VS
876 argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program);
877 free (program);
878 exit(1);
8b5f3938 879 }
880
8b5f3938 881 /* Initialize the emulated biosdisk driver. */
8e1e4e39 882 grub_util_biosdisk_init (arguments.dev_map ? : DEFAULT_DEVICE_MAP);
b39f9d20 883
daf0f0ba 884 /* Initialize all modules. */
885 grub_init_all ();
dcd73ec0 886 grub_gcry_init_all ();
8b5f3938 887
88b87c93 888 grub_lvm_fini ();
1e8d555b
VS
889 grub_mdraid09_fini ();
890 grub_mdraid1x_fini ();
076e7c0f
VS
891 grub_diskfilter_fini ();
892 grub_diskfilter_init ();
1e8d555b
VS
893 grub_mdraid09_init ();
894 grub_mdraid1x_init ();
88b87c93
VS
895 grub_lvm_init ();
896
0a1e473c 897 if (print == PRINT_BIOS_HINT
cf5f7ee7
VS
898 || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT
899 || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT)
900 delim = ' ';
901 else
902 delim = '\n';
903
8e1e4e39 904 if (arguments.zero_delim)
cf5f7ee7
VS
905 delim = '\0';
906
8b5f3938 907 /* Do it. */
79ca2d78 908 if (argument_is_device)
8e1e4e39 909 probe (NULL, arguments.devices, delim);
79ca2d78 910 else
8e1e4e39
VS
911 probe (arguments.devices[0], NULL, delim);
912
9b35fe81 913 if (delim == ' ')
cf5f7ee7 914 putchar ('\n');
b39f9d20 915
8b5f3938 916 /* Free resources. */
dcd73ec0 917 grub_gcry_fini_all ();
daf0f0ba 918 grub_fini_all ();
8b5f3938 919 grub_util_biosdisk_fini ();
b39f9d20 920
8e1e4e39
VS
921 {
922 size_t i;
923 for (i = 0; i < arguments.ndevices; i++)
924 free (arguments.devices[i]);
925 }
926 free (arguments.devices);
927
928 free (arguments.dev_map);
b39f9d20 929
8b5f3938 930 return 0;
931}