From owner-svn-src-stable@freebsd.org Tue Apr 24 18:13:29 2018 Return-Path: Delivered-To: svn-src-stable@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 778B5FAE522; Tue, 24 Apr 2018 18:13:29 +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 25A0368BC8; Tue, 24 Apr 2018 18:13:29 +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 2080B16A7A; Tue, 24 Apr 2018 18:13:29 +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 w3OIDTX7063082; Tue, 24 Apr 2018 18:13:29 GMT (envelope-from benno@FreeBSD.org) Received: (from benno@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w3OIDSxA063079; Tue, 24 Apr 2018 18:13:28 GMT (envelope-from benno@FreeBSD.org) Message-Id: <201804241813.w3OIDSxA063079@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: benno set sender to benno@FreeBSD.org using -f From: Benno Rice Date: Tue, 24 Apr 2018 18:13:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r332955 - in stable/11: stand/i386 stand/i386/isoboot stand/libsa sys/fs/cd9660 X-SVN-Group: stable-11 X-SVN-Commit-Author: benno X-SVN-Commit-Paths: in stable/11: stand/i386 stand/i386/isoboot stand/libsa sys/fs/cd9660 X-SVN-Commit-Revision: 332955 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Apr 2018 18:13:29 -0000 Author: benno Date: Tue Apr 24 18:13:28 2018 New Revision: 332955 URL: https://svnweb.freebsd.org/changeset/base/332955 Log: MFC r332084 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. Sponsored by: iXsystems, Inc. Added: stable/11/stand/i386/isoboot/ - copied from r332084, head/stand/i386/isoboot/ stable/11/stand/libsa/cd9660read.c - copied unchanged from r332084, head/stand/libsa/cd9660read.c Modified: stable/11/stand/i386/Makefile stable/11/sys/fs/cd9660/iso.h Directory Properties: stable/11/ (props changed) Modified: stable/11/stand/i386/Makefile ============================================================================== --- stable/11/stand/i386/Makefile Tue Apr 24 18:11:33 2018 (r332954) +++ stable/11/stand/i386/Makefile Tue Apr 24 18:13:28 2018 (r332955) @@ -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: stable/11/stand/libsa/cd9660read.c (from r332084, head/stand/libsa/cd9660read.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/11/stand/libsa/cd9660read.c Tue Apr 24 18:13:28 2018 (r332955, copy of r332084, head/stand/libsa/cd9660read.c) @@ -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: stable/11/sys/fs/cd9660/iso.h ============================================================================== --- stable/11/sys/fs/cd9660/iso.h Tue Apr 24 18:11:33 2018 (r332954) +++ stable/11/sys/fs/cd9660/iso.h Tue Apr 24 18:13:28 2018 (r332955) @@ -93,7 +93,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