/* Add a device into a list of devices in an ascending order. */ static void add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d) { struct grub_efidisk_data **p; struct grub_efidisk_data *n; for (p = devices; *p; p = &((*p)->next)) { int ret; ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path), find_last_device_path (d->device_path)); if (ret == 0) ret = grub_efi_compare_device_paths ((*p)->device_path, d->device_path); if (ret == 0) return; else if (ret > 0) break; } n = grub_malloc (sizeof (*n)); if (! n) return; grub_memcpy (n, d, sizeof (*n)); n->next = (*p); (*p) = n; }
/* Find the parent device. */ static struct grub_efidisk_data * find_parent_device (struct grub_efidisk_data *devices, struct grub_efidisk_data *d) { grub_efi_device_path_t *dp, *ldp; struct grub_efidisk_data *parent; dp = duplicate_device_path (d->device_path); if (! dp) return 0; ldp = find_last_device_path (dp); ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ldp->length[0] = sizeof (*ldp); ldp->length[1] = 0; for (parent = devices; parent; parent = parent->next) { /* Ignore itself. */ if (parent == d) continue; if (grub_efi_compare_device_paths (parent->device_path, dp) == 0) break; } grub_free (dp); return parent; }
static int iterate_child_devices (struct grub_efidisk_data *devices, struct grub_efidisk_data *d, int (*hook) (struct grub_efidisk_data *child)) { struct grub_efidisk_data *p; for (p = devices; p; p = p->next) { grub_efi_device_path_t *dp, *ldp; dp = duplicate_device_path (p->device_path); if (! dp) return 0; ldp = find_last_device_path (dp); ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ldp->length[0] = sizeof (*ldp); ldp->length[1] = 0; if (compare_device_paths (dp, d->device_path) == 0) if (hook (p)) { grub_free (dp); return 1; } grub_free (dp); } return 0; }
static struct grub_efidisk_data * make_devices (void) { grub_efi_uintn_t num_handles; grub_efi_handle_t *handles; grub_efi_handle_t *handle; struct grub_efidisk_data *devices = 0; /* Find handles which support the disk io interface. */ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_guid, 0, &num_handles); if (! handles) return 0; /* Make a linked list of devices. */ for (handle = handles; num_handles--; handle++) { grub_efi_device_path_t *dp; grub_efi_device_path_t *ldp; struct grub_efidisk_data *d; grub_efi_block_io_t *bio; dp = grub_efi_get_device_path (*handle); if (! dp) continue; ldp = find_last_device_path (dp); if (! ldp) /* This is empty. Why? */ continue; bio = grub_efi_open_protocol (*handle, &block_io_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (! bio) /* This should not happen... Why? */ continue; d = grub_malloc (sizeof (*d)); if (! d) { /* Uggh. */ grub_free (handles); return 0; } d->handle = *handle; d->device_path = dp; d->last_device_path = ldp; d->block_io = bio; d->next = devices; devices = d; } grub_free (handles); return devices; }
static int is_child (struct grub_efidisk_data *child, struct grub_efidisk_data *parent) { grub_efi_device_path_t *dp, *ldp; int ret; dp = duplicate_device_path (child->device_path); if (! dp) return 0; ldp = find_last_device_path (dp); ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ldp->length[0] = sizeof (*ldp); ldp->length[1] = 0; ret = (grub_efi_compare_device_paths (dp, parent->device_path) == 0); grub_free (dp); return ret; }