From owner-svn-src-all@freebsd.org Thu Apr 5 19:40:47 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 975E5F9D3A3; Thu, 5 Apr 2018 19:40:47 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 442806D46A; Thu, 5 Apr 2018 19:40:47 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 3ED6326FE5; Thu, 5 Apr 2018 19:40:47 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w35Jelck001771; Thu, 5 Apr 2018 19:40:47 GMT (envelope-from benno@FreeBSD.org) Received: (from benno@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w35JekjT001765; Thu, 5 Apr 2018 19:40:46 GMT (envelope-from benno@FreeBSD.org) Message-Id: <201804051940.w35JekjT001765@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: benno set sender to benno@FreeBSD.org using -f From: Benno Rice Date: Thu, 5 Apr 2018 19:40:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r332084 - in head: stand/i386 stand/i386/isoboot stand/libsa sys/fs/cd9660 X-SVN-Group: head X-SVN-Commit-Author: benno X-SVN-Commit-Paths: in head: stand/i386 stand/i386/isoboot stand/libsa sys/fs/cd9660 X-SVN-Commit-Revision: 332084 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 Apr 2018 19:40:47 -0000 Author: benno Date: Thu Apr 5 19:40:46 2018 New Revision: 332084 URL: https://svnweb.freebsd.org/changeset/base/332084 Log: Add isoboot(8) for booting BIOS systems from HDDs containing ISO images. This is part of a project for adding the ability to create hybrid CD/USB boot images. In the BIOS case when booting from something that isn't a CD we need some extra boot code to actually find our next stage (loader) within an ISO9660 filesystem. This code will reside in a GPT partition (similar to gptboot(8) from which it is derived) and looks for /boot/loader in an ISO9660 filesystem on the image. Reviewed by: imp Sponsored by: iXsystems, Inc. Differential Revision: https://reviews.freebsd.org/D14914 Added: head/stand/i386/isoboot/ head/stand/i386/isoboot/Makefile - copied, changed from r332081, head/stand/i386/gptboot/Makefile head/stand/i386/isoboot/isoboot.8 (contents, props changed) head/stand/i386/isoboot/isoboot.c - copied, changed from r332083, head/stand/i386/gptboot/gptboot.c head/stand/libsa/cd9660read.c (contents, props changed) Modified: head/stand/i386/Makefile head/sys/fs/cd9660/iso.h Modified: head/stand/i386/Makefile ============================================================================== --- head/stand/i386/Makefile Thu Apr 5 19:29:22 2018 (r332083) +++ head/stand/i386/Makefile Thu Apr 5 19:40:46 2018 (r332084) @@ -5,7 +5,7 @@ NO_OBJ=t .include SUBDIR.yes= mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot \ - libi386 + isoboot libi386 SUBDIR.${MK_LOADER_FIREWIRE}+= libfirewire Copied and modified: head/stand/i386/isoboot/Makefile (from r332081, head/stand/i386/gptboot/Makefile) ============================================================================== --- head/stand/i386/gptboot/Makefile Thu Apr 5 18:19:48 2018 (r332081, copy source) +++ head/stand/i386/isoboot/Makefile Thu Apr 5 19:40:46 2018 (r332084) @@ -4,10 +4,11 @@ HAVE_GELI= yes .include -.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC} +.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \ + ${BOOTSRC}/i386/common ${SASRC} -FILES= gptboot -MAN= gptboot.8 +FILES= isoboot +MAN= isoboot.8 NM?= nm @@ -19,15 +20,10 @@ REL1= 0x700 ORG1= 0x7c00 ORG2= 0x0 -# Decide level of UFS support. -GPTBOOT_UFS?= UFS1_AND_UFS2 -#GPTBOOT_UFS?= UFS2_ONLY -#GPTBOOT_UFS?= UFS1_ONLY +ISOBOOTSIZE?= 30720 -CFLAGS+=-DBOOTPROG=\"gptboot\" \ +CFLAGS+=-DBOOTPROG=\"isoboot\" \ -O1 \ - -DGPT \ - -D${GPTBOOT_UFS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ @@ -40,14 +36,17 @@ CFLAGS+=-DBOOTPROG=\"gptboot\" \ -Winline -Wno-pointer-sign CFLAGS.gcc+= --param max-inline-insns-single=100 +CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL} LD_FLAGS+=${LD_FLAGS_BIN} -CLEANFILES+= gptboot +CLEANFILES+= isoboot -gptboot: gptldr.bin gptboot.bin ${BTXKERN} +isoboot: gptldr.bin isoboot.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l gptldr.bin \ - -o ${.TARGET} gptboot.bin + -o ${.TARGET} isoboot.bin + @set -- `ls -l ${.TARGET}`; x=$$((${ISOBOOTSIZE}-$$5)); \ + echo "$$x bytes available"; test $$x -ge 0 CLEANFILES+= gptldr.bin gptldr.out gptldr.o @@ -57,16 +56,13 @@ gptldr.bin: gptldr.out gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o -CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o crc32.o drv.o \ +CLEANFILES+= isoboot.bin isoboot.out isoboot.o sio.o crc32.o drv.o \ cons.o ${OPENCRYPTO_XTS} -gptboot.bin: gptboot.out - ${OBJCOPY} -S -O binary gptboot.out ${.TARGET} +isoboot.bin: isoboot.out + ${OBJCOPY} -S -O binary isoboot.out ${.TARGET} -gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o ${OPENCRYPTO_XTS} +isoboot.out: ${BTXCRT} isoboot.o sio.o crc32.o drv.o cons.o ${OPENCRYPTO_XTS} ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBGELIBOOT} ${LIBSA32} .include - -# XXX: clang integrated-as doesn't grok .codeNN directives yet -CFLAGS.gptldr.S= ${CLANG_NO_IAS} Added: head/stand/i386/isoboot/isoboot.8 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/stand/i386/isoboot/isoboot.8 Thu Apr 5 19:40:46 2018 (r332084) @@ -0,0 +1,69 @@ +.\" Copyright (c) 2018 iXsystems, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd March 30, 2018 +.Dt ISOBOOT 8 +.Os +.Sh NAME +.Nm isoboot +.Nd Boot code for hybrid ISO/USB images on BIOS-based computers +.Sh DESCRIPTION +.Nm +is used on BIOS-based computers to boot from an ISO image that has +been written to a USB flash drive or other HDD-like device. +.Nm +is installed in a +.Cm freebsd-boot +partition with +.Xr mkimg 1 . +.Sh IMPLEMENTATION NOTES +The El Torito standard for bootable CDs provides a 32KB "System Area" +at the beginning of an image. +To create an image that is able to be booted by the BIOS as either a +CD-ROM ("ISO") and as a more HDD-like image (e.g. on a USB flash drive) +it is necessary to have both a standard El Torito boot catalog +containing a HDD-style partition table and boot code. +.Nm +is intended to be placed in a GPT partition to allow the system to find +the standard +.Fx +.Xr loader 8 +in the ISO filesystem later in the image. +.Sh BOOTING +.Nm +looks for an ISO filesystem image on the device it was booted from and +seeks to read either the primary +.Fx +.Xr loader 8 +or kernel from there. +.Sh SEE ALSO +.Xr mkimg 1 +.Sh HISTORY +.Nm +appeared in FreeBSD 12.0. +.Sh AUTHORS +This manual page written by +.An Benno Rice Aq benno@FreeBSD.org . Copied and modified: head/stand/i386/isoboot/isoboot.c (from r332083, head/stand/i386/gptboot/gptboot.c) ============================================================================== --- head/stand/i386/gptboot/gptboot.c Thu Apr 5 19:29:22 2018 (r332083, copy source) +++ head/stand/i386/isoboot/isoboot.c Thu Apr 5 19:40:46 2018 (r332084) @@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$"); extern uint32_t _end; -static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { RBX_DUAL, @@ -85,9 +84,6 @@ static struct dsk dsk; static char kname[1024]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; -#ifdef LOADER_GELI_SUPPORT -static struct geli_boot_args geliargs; -#endif static vm_offset_t high_heap_base; static uint32_t bios_basemem, bios_extmem, high_heap_size; @@ -102,27 +98,21 @@ static struct bios_smap smap; static char *heap_next; static char *heap_end; +int main(void); + static void load(void); static int parse_cmds(char *, int *); -static int dskread(void *, daddr_t, unsigned); -#ifdef LOADER_GELI_SUPPORT -static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, - size_t bytes); -#endif -#include "ufsread.c" -#include "gpt.c" -#ifdef LOADER_GELI_SUPPORT -#include "geliboot.c" -static char gelipw[GELI_PW_MAXLEN]; -static struct keybuf *gelibuf; -#endif +static uint8_t ls, dsk_meta; +static uint32_t fs_off; +#include "cd9660read.c" + static inline int -xfsread(ufs_ino_t inode, void *buf, size_t nbyte) +xfsread(uint64_t inode, void *buf, size_t nbyte) { - if ((size_t)fsread(inode, buf, nbyte) != nbyte) { + if ((size_t)cd9660_fsread(inode, buf, nbyte) != nbyte) { printf("Invalid %s\n", "format"); return (-1); } @@ -221,52 +211,22 @@ bios_getmem(void) } } -static int -gptinit(void) -{ - - if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) { - printf("%s: unable to load GPT\n", BOOTPROG); - return (-1); - } - if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) { - printf("%s: no UFS partition was found\n", BOOTPROG); - return (-1); - } -#ifdef LOADER_GELI_SUPPORT - if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end - - gpttable[curent].ent_lba_start)) == 0) { - if (geli_havekey(&dsk) != 0 && geli_passphrase(gelipw, - dsk.unit, 'p', curent + 1, &dsk) != 0) { - printf("%s: unable to decrypt GELI key\n", BOOTPROG); - return (-1); - } - } -#endif - - dsk_meta = 0; - return (0); -} - -int main(void); - int main(void) { char cmd[512], cmdtmp[512]; ssize_t sz; int autoboot, dskupdated; - ufs_ino_t ino; + uint64_t ino; - dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); - bios_getmem(); if (high_heap_size > 0) { heap_end = PTOV(high_heap_base + high_heap_size); heap_next = PTOV(high_heap_base); } else { - heap_next = (char *)dmadat + sizeof(*dmadat); + heap_next = (char *) + (roundup2(__base + (int32_t)&_end, 0x10000) - __base); heap_end = (char *)PTOV(bios_basemem); } setheap(heap_next, heap_end); @@ -285,30 +245,20 @@ main(void) bootinfo.bi_memsizes_valid++; bootinfo.bi_bios_dev = dsk.drive; -#ifdef LOADER_GELI_SUPPORT - geli_init(); -#endif - /* Process configuration file */ - - if (gptinit() != 0) - return (-1); - autoboot = 1; *cmd = '\0'; for (;;) { *kname = '\0'; - if ((ino = lookup(PATH_CONFIG)) || - (ino = lookup(PATH_DOTCONFIG))) { - sz = fsread(ino, cmd, sizeof(cmd) - 1); + if ((ino = cd9660_lookup(PATH_CONFIG)) || + (ino = cd9660_lookup(PATH_DOTCONFIG))) { + sz = cd9660_fsread(ino, cmd, sizeof(cmd) - 1); cmd[(sz < 0) ? 0 : sz] = '\0'; } if (*cmd != '\0') { memcpy(cmdtmp, cmd, sizeof(cmdtmp)); if (parse_cmds(cmdtmp, &dskupdated)) break; - if (dskupdated && gptinit() != 0) - break; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s", PATH_CONFIG, cmd); *cmd = '\0'; @@ -332,9 +282,6 @@ main(void) load(); memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); load(); - gptbootfailed(&dsk); - if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1) - break; dsk_meta = 0; } @@ -359,14 +306,12 @@ main(void) putchar('\a'); continue; } - if (dskupdated && gptinit() != 0) - continue; load(); } /* NOTREACHED */ } -/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ +/* Needed so btxld can link us properly; do not remove. */ void exit(int x) { @@ -385,11 +330,11 @@ load(void) static Elf32_Phdr ep[2]; static Elf32_Shdr es[2]; caddr_t p; - ufs_ino_t ino; + uint64_t ino; uint32_t addr, x; int fmt, i, j; - if (!(ino = lookup(kname))) { + if (!(ino = cd9660_lookup(kname))) { if (!ls) { printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], @@ -470,23 +415,9 @@ load(void) bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); bootinfo.bi_bios_dev = dsk.drive; -#ifdef LOADER_GELI_SUPPORT - geliargs.size = sizeof(geliargs); - explicit_bzero(gelipw, sizeof(gelipw)); - gelibuf = malloc(sizeof(struct keybuf) + - (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); - geli_fill_keybuf(gelibuf); - geliargs.notapw = '\0'; - geliargs.keybuf_sentinel = KEYBUF_SENTINEL; - geliargs.keybuf = gelibuf; -#endif __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), - MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), - KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo) -#ifdef LOADER_GELI_SUPPORT - , geliargs -#endif - ); + MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.unit, 0), + KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo)); } static int @@ -589,59 +520,3 @@ parse_cmds(char *cmdstr, int *dskupdated) } return (0); } - -static int -dskread(void *buf, daddr_t lba, unsigned nblk) -{ - int err; - - err = drvread(&dsk, buf, lba + dsk.start, nblk); - -#ifdef LOADER_GELI_SUPPORT - if (err == 0 && is_geli(&dsk) == 0) { - /* Decrypt */ - if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE)) - return (err); - } -#endif - - return (err); -} - -#ifdef LOADER_GELI_SUPPORT -/* - * Read function compartible with the ZFS callback, required to keep the GELI - * Implementation the same for both UFS and ZFS - */ -static int -vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes) -{ - char *p; - daddr_t lba; - unsigned int nb; - struct dsk *dskp; - - dskp = (struct dsk *)priv; - - if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) - return (-1); - - p = buf; - lba = off / DEV_BSIZE; - lba += dskp->start; - - while (bytes > 0) { - nb = bytes / DEV_BSIZE; - if (nb > VBLKSIZE / DEV_BSIZE) - nb = VBLKSIZE / DEV_BSIZE; - if (drvread(dskp, dmadat->blkbuf, lba, nb)) - return (-1); - memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE); - p += nb * DEV_BSIZE; - lba += nb; - bytes -= nb * DEV_BSIZE; - } - - return (0); -} -#endif /* LOADER_GELI_SUPPORT */ Added: head/stand/libsa/cd9660read.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/stand/libsa/cd9660read.c Thu Apr 5 19:40:46 2018 (r332084) @@ -0,0 +1,364 @@ +/* + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Originally derived from libsa/cd9660.c: */ +/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +static uint64_t cd9660_lookup(const char *); +static ssize_t cd9660_fsread(uint64_t, void *, size_t); + +#define SUSP_CONTINUATION "CE" +#define SUSP_PRESENT "SP" +#define SUSP_STOP "ST" +#define SUSP_EXTREF "ER" +#define RRIP_NAME "NM" + +typedef struct { + ISO_SUSP_HEADER h; + u_char signature [ISODCL ( 5, 6)]; + u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ +} ISO_SUSP_PRESENT; + +static int +read_iso_block(void *buffer, daddr_t blkno) +{ + + return (drvread(&dsk, buffer, blkno * 4, 4)); +} + +static ISO_SUSP_HEADER * +susp_lookup_record(const char *identifier, struct iso_directory_record *dp, + int lenskip) +{ + static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; + ISO_SUSP_HEADER *sh; + ISO_RRIP_CONT *shc; + char *p, *end; + int error; + + p = dp->name + isonum_711(dp->name_len) + lenskip; + /* Names of even length have a padding byte after the name. */ + if ((isonum_711(dp->name_len) & 1) == 0) + p++; + end = (char *)dp + isonum_711(dp->length); + while (p + 3 < end) { + sh = (ISO_SUSP_HEADER *)p; + if (bcmp(sh->type, identifier, 2) == 0) + return (sh); + if (bcmp(sh->type, SUSP_STOP, 2) == 0) + return (NULL); + if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { + shc = (ISO_RRIP_CONT *)sh; + error = read_iso_block(susp_buffer, + isonum_733(shc->location)); + + /* Bail if it fails. */ + if (error != 0) + return (NULL); + p = susp_buffer + isonum_733(shc->offset); + end = p + isonum_733(shc->length); + } else { + /* Ignore this record and skip to the next. */ + p += isonum_711(sh->length); + + /* Avoid infinite loops with corrupted file systems */ + if (isonum_711(sh->length) == 0) + return (NULL); + } + } + return (NULL); +} + +static const char * +rrip_lookup_name(struct iso_directory_record *dp, int lenskip, size_t *len) +{ + ISO_RRIP_ALTNAME *p; + + if (len == NULL) + return (NULL); + + p = (ISO_RRIP_ALTNAME *)susp_lookup_record(RRIP_NAME, dp, lenskip); + if (p == NULL) + return (NULL); + switch (*p->flags) { + case ISO_SUSP_CFLAG_CURRENT: + *len = 1; + return ("."); + case ISO_SUSP_CFLAG_PARENT: + *len = 2; + return (".."); + case 0: + *len = isonum_711(p->h.length) - 5; + return ((char *)p + 5); + default: + /* + * We don't handle hostnames or continued names as they are + * too hard, so just bail and use the default name. + */ + return (NULL); + } +} + +static int +rrip_check(struct iso_directory_record *dp, int *lenskip) +{ + ISO_SUSP_PRESENT *sp; + ISO_RRIP_EXTREF *er; + char *p; + + /* First, see if we can find a SP field. */ + p = dp->name + isonum_711(dp->name_len); + if (p > (char *)dp + isonum_711(dp->length)) { + return (0); + } + sp = (ISO_SUSP_PRESENT *)p; + if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) { + return (0); + } + if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) { + return (0); + } + if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) { + return (0); + } + *lenskip = isonum_711(sp->len_skp); + + /* + * Now look for an ER field. If RRIP is present, then there must + * be at least one of these. It would be more pedantic to walk + * through the list of fields looking for a Rock Ridge ER field. + */ + er = (ISO_RRIP_EXTREF *)susp_lookup_record(SUSP_EXTREF, dp, 0); + if (er == NULL) { + return (0); + } + return (1); +} + +static int +dirmatch(const char *path, struct iso_directory_record *dp, int use_rrip, + int lenskip) +{ + size_t len; + const char *cp = NULL, *name = NULL; + int i, icase; + + if (use_rrip) + cp = rrip_lookup_name(dp, lenskip, &len); + else + cp = NULL; + if (cp == NULL) { + len = isonum_711(dp->name_len); + cp = dp->name; + icase = 1; + } else + icase = 0; + name = cp; + for (i = len; --i >= 0; path++, cp++) { + if (!*path || *path == '/') + break; + if (*path == *cp) + continue; + if (!icase && toupper(*path) == *cp) + continue; + return 0; + } + if (*path && *path != '/') { + return 0; + } + /* + * Allow stripping of trailing dots and the version number. + * Note that this will find the first instead of the last version + * of a file. + */ + if (i >= 0 && (*cp == ';' || *cp == '.')) { + /* This is to prevent matching of numeric extensions */ + if (*cp == '.' && cp[1] != ';') { + return 0; + } + while (--i >= 0) + if (*++cp != ';' && (*cp < '0' || *cp > '9')) { + return 0; + } + } + return 1; +} + +static uint64_t +cd9660_lookup(const char *path) +{ + static char blkbuf[ISO_DEFAULT_BLOCK_SIZE]; + struct iso_primary_descriptor *vd; + struct iso_directory_record rec; + struct iso_directory_record *dp = NULL; + size_t dsize, off; + daddr_t bno, boff; + int rc, first, use_rrip, lenskip; + uint64_t cookie; + + for (bno = 16;; bno++) { + rc = read_iso_block(blkbuf, bno); + vd = (struct iso_primary_descriptor *)blkbuf; + + if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) + return (0); + if (isonum_711(vd->type) == ISO_VD_END) + return (0); + if (isonum_711(vd->type) == ISO_VD_PRIMARY) + break; + } + + rec = *(struct iso_directory_record *) vd->root_directory_record; + if (*path == '/') path++; /* eat leading '/' */ + + first = 1; + use_rrip = 0; + while (*path) { + bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + dsize = isonum_733(rec.size); + off = 0; + boff = 0; + + while (off < dsize) { + if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { + rc = read_iso_block(blkbuf, bno + boff); + if (rc) { + return (0); + } + boff++; + dp = (struct iso_directory_record *) blkbuf; + } + if (isonum_711(dp->length) == 0) { + /* skip to next block, if any */ + off = boff * ISO_DEFAULT_BLOCK_SIZE; + continue; + } + + /* See if RRIP is in use. */ + if (first) + use_rrip = rrip_check(dp, &lenskip); + + if (dirmatch(path, dp, use_rrip, + first ? 0 : lenskip)) { + first = 0; + break; + } else + first = 0; + + dp = (struct iso_directory_record *) + ((char *) dp + isonum_711(dp->length)); + /* If the new block has zero length, it is padding. */ + if (isonum_711(dp->length) == 0) { + /* Skip to next block, if any. */ + off = boff * ISO_DEFAULT_BLOCK_SIZE; + continue; + } + off += isonum_711(dp->length); + } + if (off >= dsize) { + return (0); + } + + rec = *dp; + while (*path && *path != '/') /* look for next component */ + path++; + if (*path) path++; /* skip '/' */ + } + + if ((isonum_711(rec.flags) & 2) != 0) { + return (0); + } + + cookie = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + cookie = (cookie << 32) | isonum_733(rec.size); + + return (cookie); +} + +static ssize_t +cd9660_fsread(uint64_t cookie, void *buf, size_t nbytes) +{ + static char blkbuf[ISO_DEFAULT_BLOCK_SIZE]; + static daddr_t curstart = 0, curblk = 0; + daddr_t blk, blk_off; + off_t byte_off; + size_t size, remaining, n; + char *s; + + size = cookie & 0xffffffff; + blk = (cookie >> 32) & 0xffffffff; + + /* Make sure we're looking at the right file. */ + if (((blk << 32) | size) != cookie) { + return (-1); + } + + if (blk != curstart) { + curstart = blk; + fs_off = 0; + } + + size -= fs_off; + if (size < nbytes) { + nbytes = size; + } + remaining = nbytes; + s = buf; + + while (remaining > 0) { + blk_off = fs_off >> ISO_DEFAULT_BLOCK_SHIFT; + byte_off = fs_off & (ISO_DEFAULT_BLOCK_SIZE - 1); + + if (curblk != curstart + blk_off) { + curblk = curstart + blk_off; + read_iso_block(blkbuf, curblk); + } + + if (remaining < ISO_DEFAULT_BLOCK_SIZE - byte_off) { + n = remaining; + } else { + n = ISO_DEFAULT_BLOCK_SIZE - byte_off; + } + memcpy(s, blkbuf + byte_off, n); + remaining -= n; + s += n; + + fs_off += n; + } + + return (nbytes); +} Modified: head/sys/fs/cd9660/iso.h ============================================================================== --- head/sys/fs/cd9660/iso.h Thu Apr 5 19:29:22 2018 (r332083) +++ head/sys/fs/cd9660/iso.h Thu Apr 5 19:40:46 2018 (r332084) @@ -95,7 +95,8 @@ struct iso_primary_descriptor { char application_data [ISODCL (884, 1395)]; char unused5 [ISODCL (1396, 2048)]; }; -#define ISO_DEFAULT_BLOCK_SIZE 2048 +#define ISO_DEFAULT_BLOCK_SHIFT 11 +#define ISO_DEFAULT_BLOCK_SIZE (1 << ISO_DEFAULT_BLOCK_SHIFT) /* * Used by Microsoft Joliet extension to ISO9660. Almost the same