]> git.proxmox.com Git - grub2.git/blame - disk/efi/efidisk.c
2008-07-17 Pavel Roskin <proski@gnu.org>
[grub2.git] / disk / efi / efidisk.c
CommitLineData
9cacaa17 1/*
2 * GRUB -- GRand Unified Bootloader
5a79f472 3 * Copyright (C) 2006,2007 Free Software Foundation, Inc.
9cacaa17 4 *
5a79f472 5 * GRUB is free software: you can redistribute it and/or modify
9cacaa17 6 * it under the terms of the GNU General Public License as published by
5a79f472 7 * the Free Software Foundation, either version 3 of the License, or
9cacaa17 8 * (at your option) any later version.
9 *
5a79f472 10 * GRUB is distributed in the hope that it will be useful,
9cacaa17 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
5a79f472 16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
9cacaa17 17 */
18
19#include <grub/disk.h>
2965c7cc 20#include <grub/partition.h>
9cacaa17 21#include <grub/mm.h>
22#include <grub/types.h>
23#include <grub/misc.h>
24#include <grub/err.h>
25#include <grub/term.h>
26#include <grub/efi/api.h>
27#include <grub/efi/efi.h>
28#include <grub/efi/disk.h>
29
30struct grub_efidisk_data
31{
32 grub_efi_handle_t handle;
33 grub_efi_device_path_t *device_path;
34 grub_efi_device_path_t *last_device_path;
35 grub_efi_block_io_t *block_io;
36 grub_efi_disk_io_t *disk_io;
37 struct grub_efidisk_data *next;
38};
39
40/* GUIDs. */
41static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID;
42static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
9cacaa17 43
44static struct grub_efidisk_data *fd_devices;
45static struct grub_efidisk_data *hd_devices;
46static struct grub_efidisk_data *cd_devices;
47
48/* Duplicate a device path. */
49static grub_efi_device_path_t *
50duplicate_device_path (const grub_efi_device_path_t *dp)
51{
52 grub_efi_device_path_t *p;
53 grub_size_t total_size = 0;
54
55 for (p = (grub_efi_device_path_t *) dp;
56 ;
57 p = GRUB_EFI_NEXT_DEVICE_PATH (p))
58 {
59 total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p);
60 if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p))
61 break;
62 }
63
64 p = grub_malloc (total_size);
65 if (! p)
66 return 0;
67
68 grub_memcpy (p, dp, total_size);
69 return p;
70}
71
72/* Return the device path node right before the end node. */
73static grub_efi_device_path_t *
74find_last_device_path (const grub_efi_device_path_t *dp)
75{
76 grub_efi_device_path_t *next, *p;
77
78 if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
79 return 0;
80
81 for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p);
82 ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next);
83 p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next))
84 ;
85
86 return p;
87}
88
89/* Compare device paths. */
90static int
91compare_device_paths (const grub_efi_device_path_t *dp1,
92 const grub_efi_device_path_t *dp2)
93{
94 if (! dp1 || ! dp2)
95 /* Return non-zero. */
96 return 1;
97
98 while (1)
99 {
100 grub_efi_uint8_t type1, type2;
101 grub_efi_uint8_t subtype1, subtype2;
102 grub_efi_uint16_t len1, len2;
103 int ret;
104
105 type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
106 type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
107
108 if (type1 != type2)
109 return (int) type2 - (int) type1;
110
111 subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
112 subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
113
114 if (subtype1 != subtype2)
115 return (int) subtype1 - (int) subtype2;
116
117 len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
118 len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
119
120 if (len1 != len2)
121 return (int) len1 - (int) len2;
122
123 ret = grub_memcmp (dp1, dp2, len1);
124 if (ret != 0)
125 return ret;
126
127 if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
128 break;
129
130 dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
131 dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
132 }
133
134 return 0;
135}
136
137static struct grub_efidisk_data *
138make_devices (void)
139{
140 grub_efi_uintn_t num_handles;
141 grub_efi_handle_t *handles;
142 grub_efi_handle_t *handle;
143 struct grub_efidisk_data *devices = 0;
144
145 /* Find handles which support the disk io interface. */
146 handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_guid,
147 0, &num_handles);
148 if (! handles)
149 return 0;
150
151 /* Make a linked list of devices. */
152 for (handle = handles; num_handles--; handle++)
153 {
154 grub_efi_device_path_t *dp;
155 grub_efi_device_path_t *ldp;
156 struct grub_efidisk_data *d;
157 grub_efi_block_io_t *bio;
158 grub_efi_disk_io_t *dio;
159
7f362539 160 dp = grub_efi_get_device_path (*handle);
9cacaa17 161 if (! dp)
162 continue;
163
164 ldp = find_last_device_path (dp);
165 if (! ldp)
166 /* This is empty. Why? */
167 continue;
168
169 bio = grub_efi_open_protocol (*handle, &block_io_guid,
170 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
171 dio = grub_efi_open_protocol (*handle, &disk_io_guid,
172 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
173 if (! bio || ! dio)
174 /* This should not happen... Why? */
175 continue;
176
177 d = grub_malloc (sizeof (*d));
178 if (! d)
179 {
180 /* Uggh. */
181 grub_free (handles);
182 return 0;
183 }
184
185 d->handle = *handle;
186 d->device_path = dp;
187 d->last_device_path = ldp;
188 d->block_io = bio;
189 d->disk_io = dio;
190 d->next = devices;
191 devices = d;
192 }
193
194 grub_free (handles);
195
196 return devices;
197}
198
199/* Find the parent device. */
200static struct grub_efidisk_data *
201find_parent_device (struct grub_efidisk_data *devices,
202 struct grub_efidisk_data *d)
203{
204 grub_efi_device_path_t *dp, *ldp;
205 struct grub_efidisk_data *parent;
206
207 dp = duplicate_device_path (d->device_path);
208 if (! dp)
209 return 0;
210
211 ldp = find_last_device_path (dp);
212 ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
213 ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
214 ldp->length[0] = sizeof (*ldp);
215 ldp->length[1] = 0;
216
217 for (parent = devices; parent; parent = parent->next)
218 {
219 /* Ignore itself. */
220 if (parent == d)
221 continue;
222
223 if (compare_device_paths (parent->device_path, dp) == 0)
224 {
225 /* Found. */
226 if (! parent->last_device_path)
227 parent = 0;
228
229 break;
230 }
231 }
232
233 grub_free (dp);
234 return parent;
235}
236
2965c7cc 237static int
238iterate_child_devices (struct grub_efidisk_data *devices,
239 struct grub_efidisk_data *d,
240 int (*hook) (struct grub_efidisk_data *child))
241{
242 struct grub_efidisk_data *p;
243
244 for (p = devices; p; p = p->next)
245 {
246 grub_efi_device_path_t *dp, *ldp;
247
248 dp = duplicate_device_path (p->device_path);
249 if (! dp)
250 return 0;
251
252 ldp = find_last_device_path (dp);
253 ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
254 ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
255 ldp->length[0] = sizeof (*ldp);
256 ldp->length[1] = 0;
257
258 if (compare_device_paths (dp, d->device_path) == 0)
259 if (hook (p))
260 {
261 grub_free (dp);
262 return 1;
263 }
264
265 grub_free (dp);
266 }
267
268 return 0;
269}
270
9cacaa17 271/* Add a device into a list of devices in an ascending order. */
272static void
273add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
274{
275 struct grub_efidisk_data **p;
276 struct grub_efidisk_data *n;
277
278 for (p = devices; *p; p = &((*p)->next))
279 {
280 int ret;
281
2965c7cc 282 ret = compare_device_paths (find_last_device_path ((*p)->device_path),
283 find_last_device_path (d->device_path));
284 if (ret == 0)
285 ret = compare_device_paths ((*p)->device_path,
286 d->device_path);
9cacaa17 287 if (ret == 0)
288 return;
289 else if (ret > 0)
290 break;
291 }
292
293 n = grub_malloc (sizeof (*n));
294 if (! n)
295 return;
296
297 grub_memcpy (n, d, sizeof (*n));
298 n->next = (*p);
299 (*p) = n;
300}
301
302/* Name the devices. */
303static void
304name_devices (struct grub_efidisk_data *devices)
305{
306 struct grub_efidisk_data *d;
307
308 /* First, identify devices by media device paths. */
309 for (d = devices; d; d = d->next)
310 {
311 grub_efi_device_path_t *dp;
312
313 dp = d->last_device_path;
314 if (! dp)
315 continue;
316
317 if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
318 {
319 int is_hard_drive = 0;
320
321 switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp))
322 {
323 case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
324 is_hard_drive = 1;
325 /* Fall through by intention. */
326 case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
327 {
328 struct grub_efidisk_data *parent;
329
330 parent = find_parent_device (devices, d);
331 if (parent)
332 {
333 if (is_hard_drive)
334 {
335#if 0
336 grub_printf ("adding a hard drive by a partition: ");
337 grub_print_device_path (parent->device_path);
338#endif
339 add_device (&hd_devices, parent);
340 }
341 else
342 {
343#if 0
344 grub_printf ("adding a cdrom by a partition: ");
345 grub_print_device_path (parent->device_path);
346#endif
347 add_device (&cd_devices, parent);
348 }
349
350 /* Mark the parent as used. */
351 parent->last_device_path = 0;
352 }
353 }
354 /* Mark itself as used. */
355 d->last_device_path = 0;
356 break;
357
358 default:
359 /* For now, ignore the others. */
360 break;
361 }
362 }
363 }
364
365 /* Let's see what can be added more. */
366 for (d = devices; d; d = d->next)
367 {
368 grub_efi_device_path_t *dp;
369 grub_efi_block_io_media_t *m;
370
371 dp = d->last_device_path;
372 if (! dp)
373 continue;
374
375 m = d->block_io->media;
376 if (m->logical_partition)
377 {
378 /* Only one partition in a non-media device. Assume that this
379 is a floppy drive. */
380#if 0
381 grub_printf ("adding a floppy by guessing: ");
382 grub_print_device_path (d->device_path);
383#endif
384 add_device (&fd_devices, d);
385 }
386 else if (m->read_only && m->block_size > GRUB_DISK_SECTOR_SIZE)
387 {
388 /* This check is too heuristic, but assume that this is a
389 CDROM drive. */
390#if 0
391 grub_printf ("adding a cdrom by guessing: ");
392 grub_print_device_path (d->device_path);
393#endif
394 add_device (&cd_devices, d);
395 }
396 else
397 {
398 /* The default is a hard drive. */
399#if 0
400 grub_printf ("adding a hard drive by guessing: ");
401 grub_print_device_path (d->device_path);
402#endif
403 add_device (&hd_devices, d);
404 }
405 }
406}
407
408static void
409free_devices (struct grub_efidisk_data *devices)
410{
411 struct grub_efidisk_data *p, *q;
412
413 for (p = devices; p; p = q)
414 {
415 q = p->next;
416 grub_free (p);
417 }
418}
419
420/* Enumerate all disks to name devices. */
421static void
422enumerate_disks (void)
423{
424 struct grub_efidisk_data *devices;
425
426 devices = make_devices ();
427 if (! devices)
428 return;
429
430 name_devices (devices);
431 free_devices (devices);
432}
433
434static int
435grub_efidisk_iterate (int (*hook) (const char *name))
436{
437 struct grub_efidisk_data *d;
438 char buf[16];
439 int count;
440
441 for (d = fd_devices, count = 0; d; d = d->next, count++)
442 {
443 grub_sprintf (buf, "fd%d", count);
444 grub_dprintf ("efidisk", "iterating %s\n", buf);
445 if (hook (buf))
446 return 1;
447 }
448
449 for (d = hd_devices, count = 0; d; d = d->next, count++)
450 {
451 grub_sprintf (buf, "hd%d", count);
452 grub_dprintf ("efidisk", "iterating %s\n", buf);
453 if (hook (buf))
454 return 1;
455 }
456
457 for (d = cd_devices, count = 0; d; d = d->next, count++)
458 {
459 grub_sprintf (buf, "cd%d", count);
460 grub_dprintf ("efidisk", "iterating %s\n", buf);
461 if (hook (buf))
462 return 1;
463 }
464
465 return 0;
466}
467
468static int
469get_drive_number (const char *name)
470{
471 unsigned long drive;
472
473 if ((name[0] != 'f' && name[0] != 'h' && name[0] != 'c') || name[1] != 'd')
474 goto fail;
475
476 drive = grub_strtoul (name + 2, 0, 10);
477 if (grub_errno != GRUB_ERR_NONE)
478 goto fail;
479
480 return (int) drive ;
481
482 fail:
483 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a efidisk");
484 return -1;
485}
486
487static struct grub_efidisk_data *
488get_device (struct grub_efidisk_data *devices, int num)
489{
490 struct grub_efidisk_data *d;
491
492 for (d = devices; d && num; d = d->next, num--)
493 ;
494
495 if (num == 0)
496 return d;
497
498 return 0;
499}
500
501static grub_err_t
502grub_efidisk_open (const char *name, struct grub_disk *disk)
503{
504 int num;
505 struct grub_efidisk_data *d = 0;
506 grub_efi_block_io_media_t *m;
507
508 grub_dprintf ("efidisk", "opening %s\n", name);
509
510 num = get_drive_number (name);
511 if (num < 0)
512 return grub_errno;
513
514 switch (name[0])
515 {
516 case 'f':
517 disk->has_partitions = 0;
518 d = get_device (fd_devices, num);
519 break;
520 case 'c':
521 /* FIXME: a CDROM should have partitions, but not implemented yet. */
522 disk->has_partitions = 0;
523 d = get_device (cd_devices, num);
524 break;
525 case 'h':
526 disk->has_partitions = 1;
527 d = get_device (hd_devices, num);
528 break;
529 default:
530 /* Never reach here. */
531 break;
532 }
533
534 if (! d)
535 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device");
536
537 disk->id = ((num << 8) | name[0]);
538 m = d->block_io->media;
539 /* FIXME: Probably it is better to store the block size in the disk,
540 and total sectors should be replaced with total blocks. */
541 grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n",
4ad2d049 542 m, (unsigned long long) m->last_block, m->block_size);
9cacaa17 543 disk->total_sectors = (m->last_block
544 * (m->block_size >> GRUB_DISK_SECTOR_BITS));
545 disk->data = d;
546
547 grub_dprintf ("efidisk", "opening %s succeeded\n", name);
548
549 return GRUB_ERR_NONE;
550}
551
552static void
553grub_efidisk_close (struct grub_disk *disk __attribute__ ((unused)))
554{
555 /* EFI disks do not allocate extra memory, so nothing to do here. */
7f362539 556 grub_dprintf ("efidisk", "closing %s\n", disk->name);
9cacaa17 557}
558
559static grub_err_t
524a1e6a 560grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
561 grub_size_t size, char *buf)
9cacaa17 562{
563 /* For now, use the disk io interface rather than the block io's. */
564 struct grub_efidisk_data *d;
565 grub_efi_disk_io_t *dio;
566 grub_efi_block_io_t *bio;
567 grub_efi_status_t status;
568
569 d = disk->data;
570 dio = d->disk_io;
571 bio = d->block_io;
572
524a1e6a 573 grub_dprintf ("efidisk",
4ad2d049 574 "reading 0x%lx sectors at the sector 0x%llx from %s\n",
575 (unsigned long) size, (unsigned long long) sector, disk->name);
9cacaa17 576
20011694 577 status = efi_call_5 (dio->read, dio, bio->media->media_id,
9cacaa17 578 (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
579 (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
580 buf);
581 if (status != GRUB_EFI_SUCCESS)
582 return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error");
583
584 return GRUB_ERR_NONE;
585}
586
587static grub_err_t
524a1e6a 588grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector,
589 grub_size_t size, const char *buf)
9cacaa17 590{
591 /* For now, use the disk io interface rather than the block io's. */
592 struct grub_efidisk_data *d;
593 grub_efi_disk_io_t *dio;
594 grub_efi_block_io_t *bio;
595 grub_efi_status_t status;
596
597 d = disk->data;
598 dio = d->disk_io;
599 bio = d->block_io;
600
524a1e6a 601 grub_dprintf ("efidisk",
4ad2d049 602 "writing 0x%lx sectors at the sector 0x%llx to %s\n",
603 (unsigned long) size, (unsigned long long) sector, disk->name);
9cacaa17 604
20011694 605 status = efi_call_5 (dio->write, dio, bio->media->media_id,
9cacaa17 606 (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
607 (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
608 (void *) buf);
609 if (status != GRUB_EFI_SUCCESS)
610 return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error");
611
612 return GRUB_ERR_NONE;
613}
614
615static struct grub_disk_dev grub_efidisk_dev =
616 {
617 .name = "efidisk",
618 .id = GRUB_DISK_DEVICE_EFIDISK_ID,
619 .iterate = grub_efidisk_iterate,
620 .open = grub_efidisk_open,
621 .close = grub_efidisk_close,
622 .read = grub_efidisk_read,
623 .write = grub_efidisk_write,
624 .next = 0
625 };
626
627void
628grub_efidisk_init (void)
629{
630 enumerate_disks ();
631 grub_disk_dev_register (&grub_efidisk_dev);
632}
633
634void
635grub_efidisk_fini (void)
636{
637 free_devices (fd_devices);
638 free_devices (hd_devices);
639 free_devices (cd_devices);
640 grub_disk_dev_unregister (&grub_efidisk_dev);
641}
2965c7cc 642
643/* Some utility functions to map GRUB devices with EFI devices. */
644grub_efi_handle_t
645grub_efidisk_get_device_handle (grub_disk_t disk)
646{
647 struct grub_efidisk_data *d;
648 char type;
649
650 if (disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID)
651 return 0;
652
653 d = disk->data;
654 type = disk->name[0];
655
656 switch (type)
657 {
658 case 'f':
659 /* This is the simplest case. */
660 return d->handle;
661
662 case 'c':
663 /* FIXME: probably this is not correct. */
664 return d->handle;
665
666 case 'h':
667 /* If this is the whole disk, just return its own data. */
668 if (! disk->partition)
669 return d->handle;
670
671 /* Otherwise, we must query the corresponding device to the firmware. */
672 {
673 struct grub_efidisk_data *devices;
674 grub_efi_handle_t handle = 0;
675 auto int find_partition (struct grub_efidisk_data *c);
676
677 int find_partition (struct grub_efidisk_data *c)
678 {
679 grub_efi_hard_drive_device_path_t hd;
680
681 grub_memcpy (&hd, c->last_device_path, sizeof (hd));
682
683 if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
684 == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
7f362539 685 && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
2965c7cc 686 == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
687 && (grub_partition_get_start (disk->partition)
688 == hd.partition_start)
689 && (grub_partition_get_len (disk->partition)
690 == hd.partition_size))
691 {
692 handle = c->handle;
693 return 1;
694 }
695
696 return 0;
697 }
698
699 devices = make_devices ();
700 iterate_child_devices (devices, d, find_partition);
701 free_devices (devices);
702
703 if (handle != 0)
704 return handle;
705 }
706 break;
707
708 default:
709 break;
710 }
711
712 return 0;
713}
714
715char *
716grub_efidisk_get_device_name (grub_efi_handle_t *handle)
717{
718 grub_efi_device_path_t *dp, *ldp;
719
7f362539 720 dp = grub_efi_get_device_path (handle);
2965c7cc 721 if (! dp)
722 return 0;
723
724 ldp = find_last_device_path (dp);
725 if (! ldp)
726 return 0;
727
728 if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
729 && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
730 == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
731 {
732 /* This is a hard disk partition. */
733 grub_disk_t parent = 0;
734 char *partition_name = 0;
735 char *device_name;
736 grub_efi_device_path_t *dup_dp, *dup_ldp;
737 grub_efi_hard_drive_device_path_t hd;
738 auto int find_parent_disk (const char *name);
739 auto int find_partition (grub_disk_t disk, const grub_partition_t part);
740
741 /* Find the disk which is the parent of a given hard disk partition. */
742 int find_parent_disk (const char *name)
743 {
744 grub_disk_t disk;
745
746 disk = grub_disk_open (name);
747 if (! disk)
748 return 1;
749
750 if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
751 {
752 struct grub_efidisk_data *d;
753
754 d = disk->data;
755 if (compare_device_paths (d->device_path, dup_dp) == 0)
756 {
757 parent = disk;
758 return 1;
759 }
760 }
761
762 grub_disk_close (disk);
763 return 0;
764 }
765
766 /* Find the identical partition. */
767 int find_partition (grub_disk_t disk __attribute__ ((unused)),
768 const grub_partition_t part)
769 {
770 if (grub_partition_get_start (part) == hd.partition_start
771 && grub_partition_get_len (part) == hd.partition_size)
772 {
773 partition_name = grub_partition_get_name (part);
774 return 1;
775 }
776
777 return 0;
778 }
779
780 /* It is necessary to duplicate the device path so that GRUB
781 can overwrite it. */
782 dup_dp = duplicate_device_path (dp);
783 if (! dup_dp)
784 return 0;
785
786 dup_ldp = find_last_device_path (dup_dp);
787 dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
788 dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
789 dup_ldp->length[0] = sizeof (*dup_ldp);
790 dup_ldp->length[1] = 0;
791
792 grub_efidisk_iterate (find_parent_disk);
793 grub_free (dup_dp);
794
795 if (! parent)
796 return 0;
797
798 /* Find a partition which matches the hard drive device path. */
799 grub_memcpy (&hd, ldp, sizeof (hd));
800 grub_partition_iterate (parent, find_partition);
801
802 if (! partition_name)
803 {
804 grub_disk_close (parent);
805 return 0;
806 }
807
808 device_name = grub_malloc (grub_strlen (parent->name) + 1
809 + grub_strlen (partition_name) + 1);
810 if (! device_name)
811 {
812 grub_free (partition_name);
813 grub_disk_close (parent);
814 return 0;
815 }
816
817 grub_sprintf (device_name, "%s,%s", parent->name, partition_name);
818 grub_free (partition_name);
819 grub_disk_close (parent);
820 return device_name;
821 }
822 else
823 {
824 /* This should be an entire disk. */
825 auto int find_disk (const char *name);
826 char *device_name = 0;
827
828 int find_disk (const char *name)
829 {
830 grub_disk_t disk;
831
832 disk = grub_disk_open (name);
833 if (! disk)
834 return 1;
835
836 if (disk->id == GRUB_DISK_DEVICE_EFIDISK_ID)
837 {
838 struct grub_efidisk_data *d;
839
840 d = disk->data;
841 if (compare_device_paths (d->device_path, dp) == 0)
842 {
843 device_name = grub_strdup (disk->name);
844 grub_disk_close (disk);
845 return 1;
846 }
847 }
848
849 grub_disk_close (disk);
850 return 0;
851
852 }
853
854 grub_efidisk_iterate (find_disk);
855 return device_name;
856 }
857
858 return 0;
859}