+static int
+efi_get_info(int fd, struct dk_cinfo *dki_info)
+{
+#if defined(__linux__)
+ char *path;
+ char *dev_path;
+ int rval = 0;
+
+ memset(dki_info, 0, sizeof(*dki_info));
+
+ path = calloc(PATH_MAX, 1);
+ if (path == NULL)
+ goto error;
+
+ /*
+ * The simplest way to get the partition number under linux is
+ * to parse it out of the /dev/<disk><parition> block device name.
+ * The kernel creates this using the partition number when it
+ * populates /dev/ so it may be trusted. The tricky bit here is
+ * that the naming convention is based on the block device type.
+ * So we need to take this in to account when parsing out the
+ * partition information. Another issue is that the libefi API
+ * API only provides the open fd and not the file path. To handle
+ * this realpath(3) is used to resolve the block device name from
+ * /proc/self/fd/<fd>. Aside from the partition number we collect
+ * some additional device info.
+ */
+ (void) sprintf(path, "/proc/self/fd/%d", fd);
+ dev_path = realpath(path, NULL);
+ free(path);
+
+ if (dev_path == NULL)
+ goto error;
+
+ if ((strncmp(dev_path, "/dev/sd", 7) == 0)) {
+ strcpy(dki_info->dki_cname, "sd");
+ dki_info->dki_ctype = DKC_SCSI_CCS;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/hd", 7) == 0)) {
+ strcpy(dki_info->dki_cname, "hd");
+ dki_info->dki_ctype = DKC_DIRECT;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/md", 7) == 0)) {
+ strcpy(dki_info->dki_cname, "pseudo");
+ dki_info->dki_ctype = DKC_MD;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/dm-", 8) == 0)) {
+ strcpy(dki_info->dki_cname, "pseudo");
+ dki_info->dki_ctype = DKC_VBD;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9-]p%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/ram", 8) == 0)) {
+ strcpy(dki_info->dki_cname, "pseudo");
+ dki_info->dki_ctype = DKC_PCMCIA_MEM;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/loop", 9) == 0)) {
+ strcpy(dki_info->dki_cname, "pseudo");
+ dki_info->dki_ctype = DKC_VBD;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else {
+ strcpy(dki_info->dki_dname, "unknown");
+ strcpy(dki_info->dki_cname, "unknown");
+ dki_info->dki_ctype = DKC_UNKNOWN;
+ }
+
+ switch (rval) {
+ case 0:
+ errno = EINVAL;
+ goto error;
+ case 1:
+ dki_info->dki_partition = 0;
+ }
+
+ free(dev_path);
+#else
+ if (ioctl(fd, DKIOCINFO, (caddr_t)dki_info) == -1)
+ goto error;
+#endif