Josh Rickmar writes:
> On Wed, Mar 10, 2021 at 01:11:30PM -0500, Josh Rickmar wrote: >> 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. > > Hmm, let's rename "stdio" to "stream" for the regular uncompressed > files. Otherwise this diff is the same as before. I believe you can simplify this and assume the file is gzip compressed and wrap the file descriptor with a call to gzdopen(3) to create a gzFile. The gz{read,write,tell,etc.}(3) calls should operate on both gzip compressed and non-compressed files (in "transparent mode"). That's at least my experience using gzdopen(3) and gzread(3). > > 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_STREAM) > + 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_stream(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_stream(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_STREAM: > + 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 > +stream_read(struct bootimage *f, void *ptr, size_t nbytes) > +{ > + if (f->type != FILE_STREAM) > + return (0); > + return (fread(ptr, 1, nbytes, f->f)); > +} > + > +int > +stream_seek(struct bootimage *f, off_t offset, int whence) > +{ > + if (f->type != FILE_STREAM) > + 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 stream_ops = { > + stream_read, > + stream_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_STREAM; > + f->ops = &stream_ops; > + if ((f->f = fdopen(fd, "r")) != NULL) > + return f; > + } > + > + free(f); > + return NULL; > +} > + > +static struct bootimage * > +wrap_stream(FILE *fp) > +{ > + struct bootimage *f; > + > + if ((f = calloc(1, sizeof *f)) == NULL) > + return (NULL); > + f->type = FILE_STREAM; > + f->ops = &stream_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_STREAM 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 stream_read(struct bootimage *f, void *, size_t); > +int stream_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 *); -- -Dave Voutila
