summaryrefslogtreecommitdiff
path: root/usr/src/lib/libefi
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libefi')
-rw-r--r--usr/src/lib/libefi/common/crc32_efi.c5
-rw-r--r--usr/src/lib/libefi/common/rdwr_efi.c112
2 files changed, 97 insertions, 20 deletions
diff --git a/usr/src/lib/libefi/common/crc32_efi.c b/usr/src/lib/libefi/common/crc32_efi.c
index 1dba28ad72..73039f1478 100644
--- a/usr/src/lib/libefi/common/crc32_efi.c
+++ b/usr/src/lib/libefi/common/crc32_efi.c
@@ -23,8 +23,9 @@
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
#include <sys/crc32.h>
diff --git a/usr/src/lib/libefi/common/rdwr_efi.c b/usr/src/lib/libefi/common/rdwr_efi.c
index afbc4c4f00..74f65378b1 100644
--- a/usr/src/lib/libefi/common/rdwr_efi.c
+++ b/usr/src/lib/libefi/common/rdwr_efi.c
@@ -132,12 +132,98 @@ int efi_debug = 0;
extern unsigned int efi_crc32(const unsigned char *, unsigned int);
static int efi_read(int, struct dk_gpt *);
+/*
+ * In normal operation, libefi just passes everything down to the kernel driver
+ * (and - usually - cmlb), as that code needs to react to any partitioning
+ * changes by changing device nodes under /dev/?dsk/ and the like.
+ *
+ * However, if we are running against an un-labeled lofi device on an older
+ * version of illumos, these ioctl()s aren't emulated. This can be a problem if
+ * we're in a non-global zone, which doesn't support labeled lofi, and our
+ * kernel is downrev.
+ *
+ * In this case, we'll simply emulate the ioctl()s that libefi actually needs,
+ * except those for efi_type(). They basically boil down to simple reads and
+ * writes, though this does skip a bunch of error checking.
+ *
+ * As a final wrinkle, rather than rely on an updated libefi, smartos-live's
+ * format_image tool directly builds and uses this source.
+ */
+static int
+do_ioctl(int fd, int cmd, void *arg)
+{
+ struct dk_cinfo cinfo;
+ struct dk_minfo minfo;
+ dk_efi_t *efi = arg;
+ int saved_errno;
+ size_t len;
+ int error;
+
+ error = ioctl(fd, cmd, arg);
+
+ saved_errno = errno;
+
+ if (error != -1 || errno != ENOTTY ||
+ ioctl(fd, DKIOCINFO, (caddr_t)&cinfo) != 0 ||
+ strcmp(cinfo.dki_cname, "lofi") != 0 ||
+ ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&minfo) != 0) {
+ errno = saved_errno;
+ return (error);
+ }
+
+ switch (cmd) {
+ case DKIOCGMBOOT:
+ len = (size_t)pread(fd, arg, minfo.dki_lbsize, 0);
+ error = (len == minfo.dki_lbsize) ? 0 : -1;
+ break;
+
+ case DKIOCSMBOOT:
+ len = (size_t)pwrite(fd, arg, minfo.dki_lbsize, 0);
+ error = (len == minfo.dki_lbsize) ? 0 : -1;
+ break;
+
+ case DKIOCGETEFI:
+ len = (size_t)pread(fd, (caddr_t)(uintptr_t)efi->dki_data_64,
+ efi->dki_length, efi->dki_lba * minfo.dki_lbsize);
+ error = (len == efi->dki_length) ? 0 : -1;
+ break;
+
+ case DKIOCSETEFI:
+ len = (size_t)pwrite(fd, (caddr_t)(uintptr_t)efi->dki_data_64,
+ efi->dki_length, efi->dki_lba * minfo.dki_lbsize);
+ error = (len == efi->dki_length) ? 0 : -1;
+ break;
+
+ default:
+ errno = saved_errno;
+ break;
+ }
+
+ if (error == 0)
+ errno = 0;
+
+ return (error);
+}
+
+static int
+efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
+{
+ void *data = dk_ioc->dki_data;
+ int error;
+
+ dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
+ error = do_ioctl(fd, cmd, (void *)dk_ioc);
+ dk_ioc->dki_data = data;
+
+ return (error);
+}
+
static int
read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
{
struct dk_minfo disk_info;
- if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
+ if ((do_ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
return (errno);
*capacity = disk_info.dki_capacity;
*lbsize = disk_info.dki_lbsize;
@@ -196,6 +282,7 @@ efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
"the maximum number of partitions supported is %lu\n",
MAX_PARTS);
}
+ errno = EINVAL;
return (-1);
}
@@ -246,7 +333,7 @@ efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
if ((mbr = calloc(1, lbsize)) == NULL)
return (VT_ERROR);
- if ((ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) {
+ if ((do_ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) {
free(mbr);
return (VT_ERROR);
}
@@ -305,19 +392,6 @@ efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
}
static int
-efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
-{
- void *data = dk_ioc->dki_data;
- int error;
-
- dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
- error = ioctl(fd, cmd, (void *)dk_ioc);
- dk_ioc->dki_data = data;
-
- return (error);
-}
-
-static int
check_label(int fd, dk_efi_t *dk_ioc)
{
efi_gpt_t *efi;
@@ -380,7 +454,7 @@ efi_read(int fd, struct dk_gpt *vtoc)
/*
* get the partition number for this file descriptor.
*/
- if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
+ if (do_ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
if (efi_debug) {
(void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
}
@@ -404,7 +478,7 @@ efi_read(int fd, struct dk_gpt *vtoc)
}
/* get the LBA size */
- if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
+ if (do_ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
if (efi_debug) {
(void) fprintf(stderr,
"assuming LBA 512 bytes %d\n",
@@ -997,7 +1071,7 @@ efi_write(int fd, struct dk_gpt *vtoc)
int nblocks;
diskaddr_t lba_backup_gpt_hdr;
- if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
+ if (do_ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
switch (errno) {
@@ -1181,6 +1255,8 @@ efi_free(struct dk_gpt *ptr)
* Input: File descriptor
* Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
* Otherwise 0.
+ *
+ * This always returns 0 for an un-labeled lofi device.
*/
int
efi_type(int fd)