On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:
> On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
> > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
> > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> > > > >Synopsis:      vmm/vmd fails to boot bsd.rd
> > > > >Category:      vmm
> > > > >Environment:
> > > >         System      : OpenBSD 6.9
> > > >         Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 
> > > > 12:57:12 MST 2021
> > > >                          
> > > > [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > > >
> > > >         Architecture: OpenBSD.amd64
> > > >         Machine     : amd64
> > > > >Description:
> > > >
> > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> > > > is able to be booted in this manner.
> > > This is most likely due to the recent switch to compressed bsd.rd;
> > > dry a gzcat(1)ed copy of bsd.rd instead.
> >
> > Ah, yes this works.
> >
> > Is this expected behavior or should vmd be taught how to read the
> > compressed kernel?
> >
> 
> Sure. A diff would be welcome (libz is already in the tree and ready to use 
> for
> this).

I expect this may need some cleanup, but with this patch I am able to
boot the compressed bsd.rd.

It replaces passing the kernel image around as a FILE* to a wrapper
struct that may represent either a FILE* or gzFile.  The struct points
to a function pointer to dispatch to the correct read or seek
functions.

This isn't wrapping gztell, which is used to discover the size of the
bios firmware image, and so that will continue to error if you try to
load a compressed bios.  I don't think we would want to wrap that,
since seeking to the end to discover the size would result in
decompressing everything twice.

diff b711551f3ad0c8a480c9d1297568b8616c06bdec /usr/src
blob - 1770ac337a9996c76fb09de6f04909b3bb890658
file + usr.sbin/vmd/Makefile
--- usr.sbin/vmd/Makefile
+++ usr.sbin/vmd/Makefile
@@ -14,7 +14,7 @@ CFLAGS+=      -Wmissing-declarations
 CFLAGS+=       -Wshadow -Wpointer-arith -Wcast-qual
 CFLAGS+=       -Wsign-compare
 
-LDADD+=                -lutil -lpthread -levent
+LDADD+=                -lutil -lpthread -levent -lz
 DPADD+=                ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
 
 YFLAGS=
blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
file + usr.sbin/vmd/loadfile.h
--- usr.sbin/vmd/loadfile.h
+++ usr.sbin/vmd/loadfile.h
@@ -73,8 +73,10 @@
 #define PML2_PAGE 0x13000
 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
 
-int loadfile_elf(FILE *, struct vm_create_params *,
+struct bootimage;
+
+int loadfile_elf(struct bootimage *, struct vm_create_params *,
     struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
 
-size_t mread(FILE *, paddr_t, size_t);
+size_t mread(struct bootimage *, paddr_t, size_t);
 
blob - 116094260948b50b9f1eda63d3241b77bfddb39d
file + usr.sbin/vmd/loadfile_elf.c
--- usr.sbin/vmd/loadfile_elf.c
+++ usr.sbin/vmd/loadfile_elf.c
@@ -115,8 +115,8 @@ union {
 
 static void setsegment(struct mem_segment_descriptor *, uint32_t,
     size_t, int, int, int, int);
-static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
-static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
+static int elf32_exec(struct bootimage *, Elf32_Ehdr *, u_long *, int);
+static int elf64_exec(struct bootimage *, Elf64_Ehdr *, u_long *, int);
 static size_t create_bios_memmap(struct vm_create_params *, bios_memmap_t *);
 static uint32_t push_bootargs(bios_memmap_t *, size_t, bios_bootmac_t *);
 static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
@@ -263,7 +263,7 @@ push_pt_64(void)
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_elf(FILE *fp, struct vm_create_params *vcp,
+loadfile_elf(struct bootimage *f, struct vm_create_params *vcp,
     struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
     unsigned int bootdevice)
 {
@@ -274,17 +274,17 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
        bios_memmap_t memmap[VMM_MAX_MEM_RANGES + 1];
        bios_bootmac_t bm, *bootmac = NULL;
 
-       if ((r = fread(&hdr, 1, sizeof(hdr), fp)) != sizeof(hdr))
+       if ((r = f->ops->read(f, &hdr, sizeof(hdr))) != sizeof(hdr))
                return 1;
 
        memset(&marks, 0, sizeof(marks));
        if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
            hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
-               r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
+               r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
                is_i386 = 1;
        } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
            hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
-               r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
+               r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
        } else
                errno = ENOEXEC;
 
@@ -490,7 +490,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t 
  * into the guest address space at paddr 'addr'.
  *
  * Parameters:
- *  fd: file descriptor of the kernel image file to read from.
+ *  f: kernel image file to read from.
  *  addr: guest paddr_t to load to
  *  sz: number of bytes to load
  *
@@ -498,7 +498,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t 
  *  returns 'sz' if successful, or 0 otherwise.
  */
 size_t
-mread(FILE *fp, paddr_t addr, size_t sz)
+mread(struct bootimage *f, paddr_t addr, size_t sz)
 {
        size_t ct;
        size_t i, rd, osz;
@@ -518,7 +518,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
                else
                        ct = sz;
 
-               if (fread(buf, 1, ct, fp) != ct) {
+               if (f->ops->read(f, buf, ct) != ct) {
                        log_warn("%s: error %d in mread", __progname, errno);
                        return (0);
                }
@@ -542,7 +542,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
                else
                        ct = PAGE_SIZE;
 
-               if (fread(buf, 1, ct, fp) != ct) {
+               if (f->ops->read(f, buf, ct) != ct) {
                        log_warn("%s: error %d in mread", __progname, errno);
                        return (0);
                }
@@ -665,7 +665,7 @@ mbcopy(void *src, paddr_t dst, int sz)
  *  1 if unsuccessful
  */
 static int
-elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
+elf64_exec(struct bootimage *f, Elf64_Ehdr *elf, u_long *marks, int flags)
 {
        Elf64_Shdr *shp;
        Elf64_Phdr *phdr;
@@ -680,12 +680,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
        sz = elf->e_phnum * sizeof(Elf64_Phdr);
        phdr = malloc(sz);
 
-       if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+       if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
                free(phdr);
                return 1;
        }
 
-       if (fread(phdr, 1, sz, fp) != sz) {
+       if (f->ops->read(f, phdr, sz) != sz) {
                free(phdr);
                return 1;
        }
@@ -725,12 +725,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
                    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
                        /* Read in segment. */
-                       if (fseeko(fp, (off_t)phdr[i].p_offset,
+                       if (f->ops->seek(f, (off_t)phdr[i].p_offset,
                            SEEK_SET) == -1) {
                                free(phdr);
                                return 1;
                        }
-                       if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+                       if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
                            phdr[i].p_filesz) {
                                free(phdr);
                                return 1;
@@ -770,14 +770,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
                maxp += sizeof(Elf64_Ehdr);
 
        if (flags & (LOAD_SYM | COUNT_SYM)) {
-               if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+               if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
                        warn("lseek section headers");
                        return 1;
                }
                sz = elf->e_shnum * sizeof(Elf64_Shdr);
                shp = malloc(sz);
 
-               if (fread(shp, 1, sz, fp) != sz) {
+               if (f->ops->read(f, shp, sz) != sz) {
                        free(shp);
                        return 1;
                }
@@ -787,13 +787,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
 
                size_t shstrsz = shp[elf->e_shstrndx].sh_size;
                char *shstr = malloc(shstrsz);
-               if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+               if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
                    SEEK_SET) == -1) {
                        free(shstr);
                        free(shp);
                        return 1;
                }
-               if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+               if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
                        free(shstr);
                        free(shp);
                        return 1;
@@ -816,13 +816,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
                            !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
                            !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
                                if (havesyms && (flags & LOAD_SYM)) {
-                                       if (fseeko(fp, (off_t)shp[i].sh_offset,
+                                       if (f->ops->seek(f,
+                                           (off_t)shp[i].sh_offset,
                                            SEEK_SET) == -1) {
                                                free(shstr);
                                                free(shp);
                                                return 1;
                                        }
-                                       if (mread(fp, maxp,
+                                       if (mread(f, maxp,
                                            shp[i].sh_size) != shp[i].sh_size) {
                                                free(shstr);
                                                free(shp);
@@ -875,7 +876,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  * This function is used for 32 bit kernels.
  *
  * Parameters:
- *  fd: file descriptor of the kernel to load
+ *  f: kernel file to load
  *  elf: ELF header of the kernel
  *  marks: array to store the offsets of various kernel structures
  *      (start, bss, etc)
@@ -887,7 +888,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  *  1 if unsuccessful
  */
 static int
-elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
+elf32_exec(struct bootimage *f, Elf32_Ehdr *elf, u_long *marks, int flags)
 {
        Elf32_Shdr *shp;
        Elf32_Phdr *phdr;
@@ -902,12 +903,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
        sz = elf->e_phnum * sizeof(Elf32_Phdr);
        phdr = malloc(sz);
 
-       if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+       if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
                free(phdr);
                return 1;
        }
 
-       if (fread(phdr, 1, sz, fp) != sz) {
+       if (f->ops->read(f, phdr, sz) != sz) {
                free(phdr);
                return 1;
        }
@@ -947,12 +948,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
                    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
                        /* Read in segment. */
-                       if (fseeko(fp, (off_t)phdr[i].p_offset,
+                       if (f->ops->seek(f, (off_t)phdr[i].p_offset,
                            SEEK_SET) == -1) {
                                free(phdr);
                                return 1;
                        }
-                       if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+                       if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
                            phdr[i].p_filesz) {
                                free(phdr);
                                return 1;
@@ -992,14 +993,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
                maxp += sizeof(Elf32_Ehdr);
 
        if (flags & (LOAD_SYM | COUNT_SYM)) {
-               if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+               if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
                        warn("lseek section headers");
                        return 1;
                }
                sz = elf->e_shnum * sizeof(Elf32_Shdr);
                shp = malloc(sz);
 
-               if (fread(shp, 1, sz, fp) != sz) {
+               if (f->ops->read(f, shp, sz) != sz) {
                        free(shp);
                        return 1;
                }
@@ -1009,13 +1010,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
 
                size_t shstrsz = shp[elf->e_shstrndx].sh_size;
                char *shstr = malloc(shstrsz);
-               if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+               if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
                    SEEK_SET) == -1) {
                        free(shstr);
                        free(shp);
                        return 1;
                }
-               if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+               if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
                        free(shstr);
                        free(shp);
                        return 1;
@@ -1037,13 +1038,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
                            shp[i].sh_type == SHT_STRTAB ||
                            !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
                                if (havesyms && (flags & LOAD_SYM)) {
-                                       if (fseeko(fp, (off_t)shp[i].sh_offset,
+                                       if (f->ops->seek(f,
+                                           (off_t)shp[i].sh_offset,
                                            SEEK_SET) == -1) {
                                                free(shstr);
                                                free(shp);
                                                return 1;
                                        }
-                                       if (mread(fp, maxp,
+                                       if (mread(f, maxp,
                                            shp[i].sh_size) != shp[i].sh_size) {
                                                free(shstr);
                                                free(shp);
blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
file + usr.sbin/vmd/vm.c
--- usr.sbin/vmd/vm.c
+++ usr.sbin/vmd/vm.c
@@ -84,7 +84,7 @@ void vcpu_exit_inout(struct vm_run_params *);
 int vcpu_exit_eptviolation(struct vm_run_params *);
 uint8_t vcpu_exit_pci(struct vm_run_params *);
 int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
-int loadfile_bios(FILE *, struct vcpu_reg_state *);
+int loadfile_bios(struct bootimage *, struct vcpu_reg_state *);
 int send_vm(int, struct vm_create_params *);
 int dump_send_header(int);
 int dump_vmr(int , struct vm_mem_range *);
@@ -212,7 +212,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 = 
  * directly into memory.
  *
  * Parameters:
- *  fp: file of a kernel file to load
+ *  f: BIOS file to load
  *  (out) vrs: register state to set on init for this kernel
  *
  * Return values:
@@ -220,7 +220,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 = 
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
+loadfile_bios(struct bootimage *f, struct vcpu_reg_state *vrs)
 {
        off_t    size, off;
 
@@ -228,8 +228,10 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
        memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
 
        /* Get the size of the BIOS image and seek to the beginning */
-       if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
-           fseeko(fp, 0, SEEK_SET) == -1)
+       if (f->type != FILE_STDIO)
+               return (-1); /* XXX: we don't wrap gztell */
+       if (f->ops->seek(f, 0, SEEK_END) == -1 || (size = ftello(f->f)) == -1 ||
+           f->ops->seek(f, 0, SEEK_SET) == -1)
                return (-1);
 
        /* The BIOS image must end at 1M */
@@ -237,7 +239,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
                return (-1);
 
        /* Read BIOS image into memory */
-       if (mread(fp, off, size) != (size_t)size) {
+       if (mread(f, off, size) != (size_t)size) {
                errno = EIO;
                return (-1);
        }
@@ -277,7 +279,7 @@ start_vm(struct vmd_vm *vm, int fd)
        struct vcpu_reg_state    vrs;
        int                      nicfds[VMM_MAX_NICS_PER_VM];
        int                      ret;
-       FILE                    *fp;
+       struct bootimage        *f;
        struct vmboot_params     vmboot;
        size_t                   i;
        struct vm_rwregs_params  vrp;
@@ -332,13 +334,13 @@ start_vm(struct vmd_vm *vm, int fd)
                memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
 
                /* Find and open kernel image */
-               if ((fp = vmboot_open(vm->vm_kernel,
+               if ((f = vmboot_open(vm->vm_kernel,
                    vm->vm_disks[0], vmc->vmc_diskbases[0],
                    vmc->vmc_disktypes[0], &vmboot)) == NULL)
                        fatalx("failed to open kernel - exiting");
 
                /* Load kernel image */
-               ret = loadfile_elf(fp, vcp, &vrs,
+               ret = loadfile_elf(f, vcp, &vrs,
                    vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
 
                /*
@@ -346,12 +348,12 @@ start_vm(struct vmd_vm *vm, int fd)
                 * with vm->vm_kernel and not loaded from the disk)
                 */
                if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
-                       ret = loadfile_bios(fp, &vrs);
+                       ret = loadfile_bios(f, &vrs);
 
                if (ret)
                        fatal("failed to load kernel or BIOS - exiting");
 
-               vmboot_close(fp, &vmboot);
+               vmboot_close(f, &vmboot);
        }
 
        if (vm->vm_kernel != -1)
blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
file + usr.sbin/vmd/vmboot.c
--- usr.sbin/vmd/vmboot.c
+++ usr.sbin/vmd/vmboot.c
@@ -32,6 +32,7 @@
 #include <fcntl.h>
 #include <err.h>
 #include <vis.h>
+#include <zlib.h>
 
 #include "vmd.h"
 #include "vmboot.h"
@@ -46,6 +47,9 @@ int    vmboot_strategy(void *, int, daddr_t, size_t, voi
 off_t   vmboot_findopenbsd(struct open_file *, off_t, struct disklabel *);
 void   *vmboot_loadfile(struct open_file *, char *, size_t *);
 
+static struct bootimage        *vmboot_fdopen(int);
+static struct bootimage        *wrap_stdio(FILE *);
+
 int
 vmboot_bootcmd(char *line, struct vmboot_params *bp)
 {
@@ -384,7 +388,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
        return (p);
 }
 
-FILE *
+struct bootimage *
 vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
     struct vmboot_params *vmboot)
 {
@@ -392,6 +396,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
        char                    *buf = NULL;
        size_t                   size;
        FILE                    *fp = NULL;
+       struct bootimage        *f = NULL;
        struct disklabel         dl;
        struct virtio_backing   *vfp;
        off_t                    sz;
@@ -402,7 +407,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
 
        /* First open kernel directly if specified by fd */
        if (kernel_fd != -1)
-               return (fdopen(kernel_fd, "r"));
+               return (vmboot_fdopen(kernel_fd));
 
        if (disk_fd == NULL || nfd < 1)
                return (NULL);
@@ -481,21 +486,127 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
                    vmboot->vbp_device, vmboot->vbp_image);
        }
 
-       return (fp);
+       if ((f = wrap_stdio(fp)) == NULL)
+               goto fail;
+
+       return (f);
   fail:
-       vmboot_close(fp, vmboot);
+       vmboot_close(f, vmboot);
        return (NULL);
 }
 
 void
-vmboot_close(FILE *fp, struct vmboot_params *vmboot)
+vmboot_close(struct bootimage *f, struct vmboot_params *vmboot)
 {
        struct virtio_backing   *vfp = vmboot->vbp_arg;
 
-       if (fp != NULL)
-               fclose(fp);
+       switch (f->type) {
+       case FILE_STDIO:
+               fclose(f->f);
+               break;
+       case FILE_GZIP:
+               gzclose(f->gzf);
+               break;
+       default:
+               /* can't happen */
+               errx(2, "invalid file type");
+       }
+
        if (vfp != NULL)
                vfp->close(vfp->p, 1);
+       free(f);
        free(vmboot->vbp_arg);
        free(vmboot->vbp_buf);
 }
+
+size_t
+stdio_read(struct bootimage *f, void *ptr, size_t nbytes)
+{
+       if (f->type != FILE_STDIO)
+               return (0);
+       return (fread(ptr, 1, nbytes, f->f));
+}
+
+int
+stdio_seek(struct bootimage *f, off_t offset, int whence)
+{
+       if (f->type != FILE_STDIO)
+               return (-1); /* XXX set errno? */
+       return (fseeko(f->f, offset, whence));
+}
+
+
+size_t
+gzip_read(struct bootimage *f, void *ptr, size_t nbytes)
+{
+       if (f->type != FILE_GZIP)
+               return (0); /* XXX set errno? */
+       return ((ssize_t)gzread(f->gzf, ptr, nbytes));
+}
+
+int
+gzip_seek(struct bootimage *f, off_t offset, int whence)
+{
+       if (f->type != FILE_GZIP)
+               return (-1); /* XXX set errno? */
+       return ((int)gzseek(f->gzf, offset, whence));
+}
+
+static const struct bootimage_ops stdio_ops = {
+       stdio_read,
+       stdio_seek,
+};
+static const struct bootimage_ops gzip_ops = {
+       gzip_read,
+       gzip_seek,
+};
+
+static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+static struct bootimage *
+vmboot_fdopen(int fd)
+{
+       struct bootimage *f;
+       struct stat sb;
+       u_char magic[2];
+
+       if (fstat(fd, &sb) == -1)
+               return (NULL);
+       if (S_ISDIR(sb.st_mode)) {
+               errno = EISDIR;
+               return (NULL);
+       }
+
+       if ((f = calloc(1, sizeof *f)) == NULL)
+               return (NULL);
+
+       if (pread(fd, magic, sizeof(magic), 0) != 2)
+               return NULL;
+       if (magic[0] == gz_magic[0] && magic[1] == gz_magic[1]) {
+               f->type = FILE_GZIP;
+               f->ops = &gzip_ops;
+               if ((f->gzf = gzdopen(fd, "r")) != NULL)
+                       return f;
+       } else {
+               f->type = FILE_STDIO;
+               f->ops = &stdio_ops;
+               if ((f->f = fdopen(fd, "r")) != NULL)
+                       return f;
+       }
+
+       free(f);
+       return NULL;
+}
+
+static struct bootimage *
+wrap_stdio(FILE *fp)
+{
+       struct bootimage *f;
+
+       if ((f = calloc(1, sizeof *f)) == NULL)
+               return (NULL);
+       f->type = FILE_STDIO;
+       f->ops = &stdio_ops;
+       f->f = fp;
+       return (f);
+}
blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
file + usr.sbin/vmd/vmd.h
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -30,6 +30,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <pthread.h>
+#include <zlib.h>
 
 #include "proc.h"
 
@@ -475,9 +476,31 @@ int         config_getif(struct privsep *, struct imsg *);
 int     config_getcdrom(struct privsep *, struct imsg *);
 
 /* vmboot.c */
-FILE   *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
-void    vmboot_close(FILE *, struct vmboot_params *);
+struct bootimage_ops;
 
+struct bootimage {
+       int                      type;
+#define FILE_STDIO             0
+#define FILE_GZIP              1
+       FILE                    *f;
+       gzFile                  *gzf;
+       struct bootimage_ops const *ops;
+};
+
+struct bootimage_ops {
+       size_t  (*read)(struct bootimage *, void *, size_t);
+       int     (*seek)(struct bootimage *, off_t, int);
+};
+
+size_t stdio_read(struct bootimage *f, void *, size_t);
+int    stdio_seek(struct bootimage *, off_t, int);
+size_t gzip_read(struct bootimage *f, void *, size_t);
+int    gzip_seek(struct bootimage *, off_t, int);
+
+struct bootimage *vmboot_open(int, int *, int, unsigned int,
+    struct vmboot_params *);
+void   vmboot_close(struct bootimage *, struct vmboot_params *);
+
 /* parse.y */
 int     parse_config(const char *);
 int     cmdline_symset(char *);

Reply via email to