diff options
Diffstat (limited to 'stand/libsa')
90 files changed, 19836 insertions, 0 deletions
diff --git a/stand/libsa/Makefile b/stand/libsa/Makefile new file mode 100644 index 000000000000..9aa228847c83 --- /dev/null +++ b/stand/libsa/Makefile @@ -0,0 +1,159 @@ +# $FreeBSD$ +# Originally from $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $ +# +# Notes: +# - We don't use the libc strerror/sys_errlist because the string table is +# quite large. +# + +MK_PROFILE= no +MK_SSP= no + +.include <bsd.init.mk> + +INTERNALLIB= +LIBSA_CPUARCH?=${MACHINE_CPUARCH} +LIBC_SRC= ${SRCTOP}/lib/libc + +LIB?= sa +NO_PIC= +WARNS?= 0 + +CFLAGS+= -I${SASRC} + +# standalone components and stuff we have modified locally +SRCS+= gzguts.h zutil.h __main.c assert.c bcd.c environment.c getopt.c gets.c \ + globals.c pager.c panic.c printf.c strdup.c strerror.c strtol.c strtoul.c \ + random.c sbrk.c twiddle.c zalloc.c zalloc_malloc.c + +# private (pruned) versions of libc string functions +SRCS+= strcasecmp.c + +.PATH: ${LIBC_SRC}/net + +SRCS+= ntoh.c + +# string functions from libc +.PATH: ${LIBC_SRC}/string +SRCS+= bcmp.c bcopy.c bzero.c ffs.c fls.c \ + memccpy.c memchr.c memcmp.c memcpy.c memmove.c memset.c \ + qdivrem.c strcat.c strchr.c strcmp.c strcpy.c stpcpy.c stpncpy.c \ + strcspn.c strlcat.c strlcpy.c strlen.c strncat.c strncmp.c strncpy.c \ + strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c +.if ${MACHINE_CPUARCH} == "arm" +.PATH: ${LIBC_SRC}/arm/gen + +# Do not generate movt/movw, because the relocation fixup for them does not +# translate to the -Bsymbolic -pie format required by self_reloc() in loader(8). +# Also, the fpu is not available in a standalone environment. +.if ${COMPILER_VERSION} < 30800 +CFLAGS.clang+= -mllvm -arm-use-movt=0 +.else +CFLAGS.clang+= -mno-movt +.endif +CFLAGS.clang+= -mfpu=none + +# Compiler support functions +.PATH: ${SRCTOP}/contrib/compiler-rt/lib/builtins/ +# __clzsi2 and ctzsi2 for various builtin functions +SRCS+= clzsi2.c ctzsi2.c +# Divide and modulus functions called by the compiler +SRCS+= divmoddi4.c divmodsi4.c divdi3.c divsi3.c moddi3.c modsi3.c +SRCS+= udivmoddi4.c udivmodsi4.c udivdi3.c udivsi3.c umoddi3.c umodsi3.c + +.PATH: ${SRCTOP}/contrib/compiler-rt/lib/builtins/arm/ +SRCS+= aeabi_idivmod.S aeabi_ldivmod.S aeabi_uidivmod.S aeabi_uldivmod.S +SRCS+= aeabi_memcmp.S aeabi_memcpy.S aeabi_memmove.S aeabi_memset.S +.endif + +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "riscv" +.PATH: ${LIBC_SRC}/${MACHINE_CPUARCH}/gen +.endif + +.if ${MACHINE_CPUARCH} == "powerpc" +.PATH: ${LIBC_SRC}/quad +SRCS+= ashldi3.c ashrdi3.c +SRCS+= syncicache.c +.endif + +# uuid functions from libc +.PATH: ${LIBC_SRC}/uuid +SRCS+= uuid_create_nil.c uuid_equal.c uuid_from_string.c uuid_is_nil.c uuid_to_string.c + +# _setjmp/_longjmp +.PATH: ${SASRC}/${LIBSA_CPUARCH} +SRCS+= _setjmp.S + +# decompression functionality from libbz2 +# NOTE: to actually test this functionality after libbz2 upgrade compile +# loader(8) with LOADER_BZIP2_SUPPORT defined +.PATH: ${SRCTOP}/contrib/bzip2 +CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS +SRCS+= libsa_bzlib_private.h + +.for file in bzlib.c crctable.c decompress.c huffman.c randtable.c +SRCS+= _${file} +CLEANFILES+= _${file} + +_${file}: ${file} + sed "s|bzlib_private\.h|libsa_bzlib_private.h|" \ + ${.ALLSRC} > ${.TARGET} +.endfor + +CLEANFILES+= libsa_bzlib_private.h +libsa_bzlib_private.h: bzlib_private.h + sed -e 's|<stdlib.h>|"stand.h"|' \ + ${.ALLSRC} > ${.TARGET} + +# decompression functionality from zlib +.PATH: ${SRCTOP}/contrib/zlib +CFLAGS+=-DHAVE_MEMCPY -I${SRCTOP}/contrib/zlib +SRCS+= adler32.c crc32.c libsa_zutil.h libsa_gzguts.h + +.for file in infback.c inffast.c inflate.c inftrees.c zutil.c +SRCS+= _${file} +CLEANFILES+= _${file} + +_${file}: ${file} + sed -e "s|zutil\.h|libsa_zutil.h|" \ + -e "s|gzguts\.h|libsa_gzguts.h|" \ + ${.ALLSRC} > ${.TARGET} +.endfor + +# depend on stand.h being able to be included multiple times +.for file in zutil.h gzguts.h +CLEANFILES+= libsa_${file} +libsa_${file}: ${file} + sed -e 's|<fcntl.h>|"stand.h"|' \ + -e 's|<stddef.h>|"stand.h"|' \ + -e 's|<string.h>|"stand.h"|' \ + -e 's|<stdio.h>|"stand.h"|' \ + -e 's|<stdlib.h>|"stand.h"|' \ + ${.ALLSRC} > ${.TARGET} +.endfor + +# io routines +SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \ + fstat.c close.c lseek.c open.c read.c write.c readdir.c + +# network routines +SRCS+= arp.c ether.c ip.c inet_ntoa.c in_cksum.c net.c udp.c netif.c rpc.c + +# network info services: +SRCS+= bootp.c rarp.c bootparam.c + +# boot filesystems +SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c +SRCS+= dosfs.c ext2fs.c +SRCS+= splitfs.c +SRCS+= pkgfs.c +.if ${MK_NAND} != "no" +SRCS+= nandfs.c +.endif + +# explicit_bzero +.PATH: ${SYSDIR}/libkern +SRCS+= explicit_bzero.c + +.include <bsd.stand.mk> +.include <bsd.lib.mk> diff --git a/stand/libsa/Makefile.depend b/stand/libsa/Makefile.depend new file mode 100644 index 000000000000..1d86fce1441d --- /dev/null +++ b/stand/libsa/Makefile.depend @@ -0,0 +1,15 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/arpa \ + include/xlocale \ + lib/libbz2 \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/stand/libsa/__main.c b/stand/libsa/__main.c new file mode 100644 index 000000000000..e38f33865c05 --- /dev/null +++ b/stand/libsa/__main.c @@ -0,0 +1,43 @@ +/* $NetBSD: __main.c,v 1.4 1996/03/14 18:52:03 christos Exp $ */ + +/* + * Copyright (c) 1993 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +void __main(void); + +void +__main(void) +{ +} diff --git a/stand/libsa/amd64/_setjmp.S b/stand/libsa/amd64/_setjmp.S new file mode 100644 index 000000000000..6d9a5fa13f8d --- /dev/null +++ b/stand/libsa/amd64/_setjmp.S @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) + .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90" +#endif /* LIBC_SCCS and not lint */ +#include <machine/asm.h> +__FBSDID("$FreeBSD$"); + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from the last call to + * _setjmp(a) + * by restoring registers from the environment 'a'. + * The previous signal state is NOT restored. + */ + +ENTRY(_setjmp) + movq %rdi,%rax + movq 0(%rsp),%rdx /* retval */ + movq %rdx, 0(%rax) /* 0; retval */ + movq %rbx, 8(%rax) /* 1; rbx */ + movq %rsp,16(%rax) /* 2; rsp */ + movq %rbp,24(%rax) /* 3; rbp */ + movq %r12,32(%rax) /* 4; r12 */ + movq %r13,40(%rax) /* 5; r13 */ + movq %r14,48(%rax) /* 6; r14 */ + movq %r15,56(%rax) /* 7; r15 */ + fnstcw 64(%rax) /* 8; fpu cw */ + stmxcsr 68(%rax) /* and mxcsr */ + xorq %rax,%rax + ret +END(_setjmp) + + .weak CNAME(_longjmp) +ENTRY(_longjmp) + movq %rdi,%rdx + /* Restore the mxcsr, but leave exception flags intact. */ + stmxcsr -4(%rsp) + movl 68(%rdx),%eax + andl $0xffffffc0,%eax + movl -4(%rsp),%edi + andl $0x3f,%edi + xorl %eax,%edi + movl %edi,-4(%rsp) + ldmxcsr -4(%rsp) + movq %rsi,%rax /* retval */ + movq 0(%rdx),%rcx + movq 8(%rdx),%rbx + movq 16(%rdx),%rsp + movq 24(%rdx),%rbp + movq 32(%rdx),%r12 + movq 40(%rdx),%r13 + movq 48(%rdx),%r14 + movq 56(%rdx),%r15 + fldcw 64(%rdx) + testq %rax,%rax + jnz 1f + incq %rax +1: movq %rcx,0(%rsp) + ret +END(_longjmp) diff --git a/stand/libsa/arp.c b/stand/libsa/arp.c new file mode 100644 index 000000000000..841010c3195c --- /dev/null +++ b/stand/libsa/arp.c @@ -0,0 +1,305 @@ +/* $NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <netinet/in_systm.h> + +#include <string.h> + +#include "stand.h" +#include "net.h" + +/* Cache stuff */ +#define ARP_NUM 8 /* need at most 3 arp entries */ + +struct arp_list { + struct in_addr addr; + u_char ea[6]; +} arp_list[ARP_NUM] = { + /* XXX - net order `INADDR_BROADCAST' must be a constant */ + { {0xffffffff}, BA } +}; +int arp_num = 1; + +/* Local forwards */ +static ssize_t arpsend(struct iodesc *, void *, size_t); +static ssize_t arprecv(struct iodesc *, void **, void **, time_t); + +/* Broadcast an ARP packet, asking who has addr on interface d */ +u_char * +arpwhohas(struct iodesc *d, struct in_addr addr) +{ + int i; + struct ether_arp *ah; + struct arp_list *al; + void *pkt; + struct { + struct ether_header eh; + struct { + struct ether_arp arp; + u_char pad[18]; /* 60 - sizeof(...) */ + } data; + } wbuf; + + /* Try for cached answer first */ + for (i = 0, al = arp_list; i < arp_num; ++i, ++al) + if (addr.s_addr == al->addr.s_addr) + return (al->ea); + + /* Don't overflow cache */ + if (arp_num > ARP_NUM - 1) { + arp_num = 1; /* recycle */ + printf("arpwhohas: overflowed arp_list!\n"); + } + +#ifdef ARP_DEBUG + if (debug) + printf("arpwhohas: send request for %s\n", inet_ntoa(addr)); +#endif + + bzero((char*)&wbuf.data, sizeof(wbuf.data)); + ah = &wbuf.data.arp; + ah->arp_hrd = htons(ARPHRD_ETHER); + ah->arp_pro = htons(ETHERTYPE_IP); + ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */ + ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */ + ah->arp_op = htons(ARPOP_REQUEST); + MACPY(d->myea, ah->arp_sha); + bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa)); + /* Leave zeros in arp_tha */ + bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa)); + + /* Store ip address in cache (incomplete entry). */ + al->addr = addr; + + pkt = NULL; + ah = NULL; + i = sendrecv(d, + arpsend, &wbuf.data, sizeof(wbuf.data), + arprecv, &pkt, (void **)&ah); + if (i == -1) { + panic("arp: no response for %s\n", + inet_ntoa(addr)); + } + + /* Store ethernet address in cache */ +#ifdef ARP_DEBUG + if (debug) { + struct ether_header *eh; + + eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN); + printf("arp: response from %s\n", + ether_sprintf(eh->ether_shost)); + printf("arp: cacheing %s --> %s\n", + inet_ntoa(addr), ether_sprintf(ah->arp_sha)); + } +#endif + MACPY(ah->arp_sha, al->ea); + ++arp_num; + + free(pkt); + return (al->ea); +} + +static ssize_t +arpsend(struct iodesc *d, void *pkt, size_t len) +{ + +#ifdef ARP_DEBUG + if (debug) + printf("arpsend: called\n"); +#endif + + return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP)); +} + +/* + * Returns 0 if this is the packet we're waiting for + * else -1 (and errno == 0) + */ +static ssize_t +arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft) +{ + ssize_t n; + struct ether_arp *ah; + u_int16_t etype; /* host order */ + void *ptr; + +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: "); +#endif + + ptr = NULL; + n = readether(d, &ptr, (void **)&ah, tleft, &etype); + errno = 0; /* XXX */ + if (n == -1 || n < sizeof(struct ether_arp)) { +#ifdef ARP_DEBUG + if (debug) + printf("bad len=%d\n", n); +#endif + free(ptr); + return (-1); + } + + if (etype != ETHERTYPE_ARP) { +#ifdef ARP_DEBUG + if (debug) + printf("not arp type=%d\n", etype); +#endif + free(ptr); + return (-1); + } + + /* Ethernet address now checked in readether() */ + if (ah->arp_hrd != htons(ARPHRD_ETHER) || + ah->arp_pro != htons(ETHERTYPE_IP) || + ah->arp_hln != sizeof(ah->arp_sha) || + ah->arp_pln != sizeof(ah->arp_spa) ) + { +#ifdef ARP_DEBUG + if (debug) + printf("bad hrd/pro/hln/pln\n"); +#endif + free(ptr); + return (-1); + } + + if (ah->arp_op == htons(ARPOP_REQUEST)) { +#ifdef ARP_DEBUG + if (debug) + printf("is request\n"); +#endif + arp_reply(d, ah); + free(ptr); + return (-1); + } + + if (ah->arp_op != htons(ARPOP_REPLY)) { +#ifdef ARP_DEBUG + if (debug) + printf("not ARP reply\n"); +#endif + free(ptr); + return (-1); + } + + /* Is the reply from the source we want? */ + if (bcmp(&arp_list[arp_num].addr, + ah->arp_spa, sizeof(ah->arp_spa))) + { +#ifdef ARP_DEBUG + if (debug) + printf("unwanted address\n"); +#endif + free(ptr); + return (-1); + } + /* We don't care who the reply was sent to. */ + + /* We have our answer. */ +#ifdef ARP_DEBUG + if (debug) + printf("got it\n"); +#endif + *pkt = ptr; + *payload = ah; + return (n); +} + +/* + * Convert an ARP request into a reply and send it. + * Notes: Re-uses buffer. Pad to length = 46. + */ +void +arp_reply(struct iodesc *d, void *pkt) +{ + struct ether_arp *arp = pkt; + + if (arp->arp_hrd != htons(ARPHRD_ETHER) || + arp->arp_pro != htons(ETHERTYPE_IP) || + arp->arp_hln != sizeof(arp->arp_sha) || + arp->arp_pln != sizeof(arp->arp_spa) ) + { +#ifdef ARP_DEBUG + if (debug) + printf("arp_reply: bad hrd/pro/hln/pln\n"); +#endif + return; + } + + if (arp->arp_op != htons(ARPOP_REQUEST)) { +#ifdef ARP_DEBUG + if (debug) + printf("arp_reply: not request!\n"); +#endif + return; + } + + /* If we are not the target, ignore the request. */ + if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa))) + return; + +#ifdef ARP_DEBUG + if (debug) { + printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha)); + } +#endif + + arp->arp_op = htons(ARPOP_REPLY); + /* source becomes target */ + bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha)); + bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa)); + /* here becomes source */ + bcopy(d->myea, arp->arp_sha, sizeof(arp->arp_sha)); + bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa)); + + /* + * No need to get fancy here. If the send fails, the + * requestor will just ask again. + */ + (void) sendether(d, pkt, sizeof(*arp) + 18, + arp->arp_tha, ETHERTYPE_ARP); +} diff --git a/stand/libsa/assert.c b/stand/libsa/assert.c new file mode 100644 index 000000000000..8eec63a4729a --- /dev/null +++ b/stand/libsa/assert.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1998 Michael Smith. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <assert.h> + +#include "stand.h" + +void +__assert(const char *func, const char *file, int line, const char *expression) +{ + if (func == NULL) + panic("Assertion failed: (%s), file %s, line %d.\n", + expression, file, line); + else + panic( + "Assertion failed: (%s), function %s, file %s, line %d.\n", + expression, func, file, line); +} diff --git a/stand/libsa/bcd.c b/stand/libsa/bcd.c new file mode 100644 index 000000000000..7bd67c91620a --- /dev/null +++ b/stand/libsa/bcd.c @@ -0,0 +1,38 @@ +/* + * Some data-tables that are often used. + * Cannot be copyrighted. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +u_char const bcd2bin_data[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +}; + +u_char const bin2bcd_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 +}; + +/* This is actually used with radix [2..36] */ +char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c new file mode 100644 index 000000000000..d770bf3bf516 --- /dev/null +++ b/stand/libsa/bootp.c @@ -0,0 +1,791 @@ +/* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stddef.h> +#include <sys/types.h> +#include <sys/limits.h> +#include <sys/endian.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include <string.h> + +#define BOOTP_DEBUGxx +#define SUPPORT_DHCP + +#define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */ +#define DHCP_ENV_PXE 10 /* assume pxe vendor options */ +#define DHCP_ENV_FREEBSD 11 /* assume freebsd vendor options */ +/* set DHCP_ENV to one of the values above to export dhcp options to kenv */ +#define DHCP_ENV DHCP_ENV_NO_VENDOR + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "bootp.h" + + +struct in_addr servip; + +static time_t bot; + +static char vm_rfc1048[4] = VM_RFC1048; +#ifdef BOOTP_VEND_CMU +static char vm_cmu[4] = VM_CMU; +#endif + +/* Local forwards */ +static ssize_t bootpsend(struct iodesc *, void *, size_t); +static ssize_t bootprecv(struct iodesc *, void **, void **, time_t); +static int vend_rfc1048(u_char *, u_int); +#ifdef BOOTP_VEND_CMU +static void vend_cmu(u_char *); +#endif + +#ifdef DHCP_ENV /* export the dhcp response to kenv */ +struct dhcp_opt; +static void setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts); +#else +#define setenv_(a, b, c) +#endif + +#ifdef SUPPORT_DHCP +static char expected_dhcpmsgtype = -1, dhcp_ok; +struct in_addr dhcp_serverip; +#endif +struct bootp *bootp_response; +size_t bootp_response_size; + +static void +bootp_fill_request(unsigned char *bp_vend) +{ + /* + * We are booting from PXE, we want to send the string + * 'PXEClient' to the DHCP server so you have the option of + * only responding to PXE aware dhcp requests. + */ + bp_vend[0] = TAG_CLASSID; + bp_vend[1] = 9; + bcopy("PXEClient", &bp_vend[2], 9); + bp_vend[11] = TAG_USER_CLASS; + /* len of each user class + number of user class */ + bp_vend[12] = 8; + /* len of the first user class */ + bp_vend[13] = 7; + bcopy("FreeBSD", &bp_vend[14], 7); + bp_vend[21] = TAG_PARAM_REQ; + bp_vend[22] = 7; + bp_vend[23] = TAG_ROOTPATH; + bp_vend[24] = TAG_HOSTNAME; + bp_vend[25] = TAG_SWAPSERVER; + bp_vend[26] = TAG_GATEWAY; + bp_vend[27] = TAG_SUBNET_MASK; + bp_vend[28] = TAG_INTF_MTU; + bp_vend[29] = TAG_SERVERID; + bp_vend[30] = TAG_END; +} + +/* Fetch required bootp infomation */ +void +bootp(int sock) +{ + void *pkt; + struct iodesc *d; + struct bootp *bp; + struct { + u_char header[HEADER_SIZE]; + struct bootp wbootp; + } wbuf; + struct bootp *rbootp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp: socket=%d\n", sock); +#endif + if (!bot) + bot = getsecs(); + + if (!(d = socktodesc(sock))) { + printf("bootp: bad socket. %d\n", sock); + return; + } +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp: d=%lx\n", (long)d); +#endif + + bp = &wbuf.wbootp; + bzero(bp, sizeof(*bp)); + + bp->bp_op = BOOTREQUEST; + bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ + bp->bp_hlen = 6; + bp->bp_xid = htonl(d->xid); + MACPY(d->myea, bp->bp_chaddr); + strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); + bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); +#ifdef SUPPORT_DHCP + bp->bp_vend[4] = TAG_DHCP_MSGTYPE; + bp->bp_vend[5] = 1; + bp->bp_vend[6] = DHCPDISCOVER; + bootp_fill_request(&bp->bp_vend[7]); + +#else + bp->bp_vend[4] = TAG_END; +#endif + + d->myip.s_addr = INADDR_ANY; + d->myport = htons(IPPORT_BOOTPC); + d->destip.s_addr = INADDR_BROADCAST; + d->destport = htons(IPPORT_BOOTPS); + +#ifdef SUPPORT_DHCP + expected_dhcpmsgtype = DHCPOFFER; + dhcp_ok = 0; +#endif + + if(sendrecv(d, + bootpsend, bp, sizeof(*bp), + bootprecv, &pkt, (void **)&rbootp) == -1) { + printf("bootp: no reply\n"); + return; + } + +#ifdef SUPPORT_DHCP + if(dhcp_ok) { + u_int32_t leasetime; + bp->bp_vend[6] = DHCPREQUEST; + bp->bp_vend[7] = TAG_REQ_ADDR; + bp->bp_vend[8] = 4; + bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); + bp->bp_vend[13] = TAG_SERVERID; + bp->bp_vend[14] = 4; + bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); + bp->bp_vend[19] = TAG_LEASETIME; + bp->bp_vend[20] = 4; + leasetime = htonl(300); + bcopy(&leasetime, &bp->bp_vend[21], 4); + bootp_fill_request(&bp->bp_vend[25]); + + expected_dhcpmsgtype = DHCPACK; + + free(pkt); + if(sendrecv(d, + bootpsend, bp, sizeof(*bp), + bootprecv, &pkt, (void **)&rbootp) == -1) { + printf("DHCPREQUEST failed\n"); + return; + } + } +#endif + + myip = d->myip = rbootp->bp_yiaddr; + servip = rbootp->bp_siaddr; + if (rootip.s_addr == INADDR_ANY) + rootip = servip; + bcopy(rbootp->bp_file, bootfile, sizeof(bootfile)); + bootfile[sizeof(bootfile) - 1] = '\0'; + + if (!netmask) { + if (IN_CLASSA(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSB_NET); + else + netmask = htonl(IN_CLASSC_NET); +#ifdef BOOTP_DEBUG + if (debug) + printf("'native netmask' is %s\n", intoa(netmask)); +#endif + } + +#ifdef BOOTP_DEBUG + if (debug) + printf("mask: %s\n", intoa(netmask)); +#endif + + /* We need a gateway if root is on a different net */ + if (!SAMENET(myip, rootip, netmask)) { +#ifdef BOOTP_DEBUG + if (debug) + printf("need gateway for root ip\n"); +#endif + } + + /* Toss gateway if on a different net */ + if (!SAMENET(myip, gateip, netmask)) { +#ifdef BOOTP_DEBUG + if (debug) + printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); +#endif + gateip.s_addr = 0; + } + + /* Bump xid so next request will be unique. */ + ++d->xid; + free(pkt); +} + +/* Transmit a bootp request */ +static ssize_t +bootpsend(struct iodesc *d, void *pkt, size_t len) +{ + struct bootp *bp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootpsend: d=%lx called.\n", (long)d); +#endif + + bp = pkt; + bp->bp_secs = htons((u_short)(getsecs() - bot)); + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootpsend: calling sendudp\n"); +#endif + + return (sendudp(d, pkt, len)); +} + +static ssize_t +bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft) +{ + ssize_t n; + struct bootp *bp; + void *ptr; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp_recvoffer: called\n"); +#endif + + ptr = NULL; + n = readudp(d, &ptr, (void **)&bp, tleft); + if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) + goto bad; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootprecv: checked. bp = %p, n = %zd\n", bp, n); +#endif + if (bp->bp_xid != htonl(d->xid)) { +#ifdef BOOTP_DEBUG + if (debug) { + printf("bootprecv: expected xid 0x%lx, got 0x%x\n", + d->xid, ntohl(bp->bp_xid)); + } +#endif + goto bad; + } + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootprecv: got one!\n"); +#endif + + /* Suck out vendor info */ + if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { + int vsize = n - offsetof(struct bootp, bp_vend); + if (vend_rfc1048(bp->bp_vend, vsize) != 0) + goto bad; + + /* Save copy of bootp reply or DHCP ACK message */ + if (bp->bp_op == BOOTREPLY && + ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) || + dhcp_ok == 0)) { + free(bootp_response); + bootp_response = malloc(n); + if (bootp_response != NULL) { + bootp_response_size = n; + bcopy(bp, bootp_response, bootp_response_size); + } + } + } +#ifdef BOOTP_VEND_CMU + else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) + vend_cmu(bp->bp_vend); +#endif + else + printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); + + *pkt = ptr; + *payload = bp; + return (n); +bad: + free(ptr); + errno = 0; + return (-1); +} + +int +dhcp_try_rfc1048(u_char *cp, u_int len) +{ + + expected_dhcpmsgtype = DHCPACK; + if (bcmp(vm_rfc1048, cp, sizeof(vm_rfc1048)) == 0) { + return (vend_rfc1048(cp, len)); + } + return (-1); +} + +static int +vend_rfc1048(u_char *cp, u_int len) +{ + u_char *ep; + int size; + u_char tag; + const char *val; + +#ifdef BOOTP_DEBUG + if (debug) + printf("vend_rfc1048 bootp info. len=%d\n", len); +#endif + ep = cp + len; + + /* Step over magic cookie */ + cp += sizeof(int); + + setenv_(cp, ep, NULL); + + while (cp < ep) { + tag = *cp++; + size = *cp++; + if (tag == TAG_END) + break; + + if (tag == TAG_SUBNET_MASK) { + bcopy(cp, &netmask, sizeof(netmask)); + } + if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); + } + if (tag == TAG_SWAPSERVER) { + /* let it override bp_siaddr */ + bcopy(cp, &rootip.s_addr, sizeof(rootip.s_addr)); + } + if (tag == TAG_ROOTPATH) { + if ((val = getenv("dhcp.root-path")) == NULL) + val = (const char *)cp; + strlcpy(rootpath, val, sizeof(rootpath)); + } + if (tag == TAG_HOSTNAME) { + if ((val = getenv("dhcp.host-name")) == NULL) + val = (const char *)cp; + strlcpy(hostname, val, sizeof(hostname)); + } + if (tag == TAG_INTF_MTU) { + intf_mtu = 0; + if ((val = getenv("dhcp.interface-mtu")) != NULL) { + unsigned long tmp; + char *end; + + errno = 0; + /* + * Do not allow MTU to exceed max IPv4 packet + * size, max value of 16-bit word. + */ + tmp = strtoul(val, &end, 0); + if (errno != 0 || + *val == '\0' || *end != '\0' || + tmp > USHRT_MAX) { + printf("%s: bad value: \"%s\", " + "ignoring\n", + "dhcp.interface-mtu", val); + } else { + intf_mtu = (u_int)tmp; + } + } + if (intf_mtu <= 0) + intf_mtu = be16dec(cp); + } +#ifdef SUPPORT_DHCP + if (tag == TAG_DHCP_MSGTYPE) { + if(*cp != expected_dhcpmsgtype) + return(-1); + dhcp_ok = 1; + } + if (tag == TAG_SERVERID) { + bcopy(cp, &dhcp_serverip.s_addr, + sizeof(dhcp_serverip.s_addr)); + } +#endif + cp += size; + } + return(0); +} + +#ifdef BOOTP_VEND_CMU +static void +vend_cmu(u_char *cp) +{ + struct cmu_vend *vp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("vend_cmu bootp info.\n"); +#endif + vp = (struct cmu_vend *)cp; + + if (vp->v_smask.s_addr != 0) { + netmask = vp->v_smask.s_addr; + } + if (vp->v_dgate.s_addr != 0) { + gateip = vp->v_dgate; + } +} +#endif + +#ifdef DHCP_ENV +/* + * Parse DHCP options and store them into kenv variables. + * Original code from Danny Braniss, modifications by Luigi Rizzo. + * + * The parser is driven by tables which specify the type and name of + * each dhcp option and how it appears in kenv. + * The first entry in the list contains the prefix used to set the kenv + * name (including the . if needed), the last entry must have a 0 tag. + * Entries do not need to be sorted though it helps for readability. + * + * Certain vendor-specific tables can be enabled according to DHCP_ENV. + * Set it to 0 if you don't want any. + */ +enum opt_fmt { __NONE = 0, + __8 = 1, __16 = 2, __32 = 4, /* Unsigned fields, value=size */ + __IP, /* IPv4 address */ + __TXT, /* C string */ + __BYTES, /* byte sequence, printed %02x */ + __INDIR, /* name=value */ + __ILIST, /* name=value;name=value ... */ + __VE, /* vendor specific, recurse */ +}; + +struct dhcp_opt { + uint8_t tag; + uint8_t fmt; + const char *desc; +}; + +static struct dhcp_opt vndr_opt[] = { /* Vendor Specific Options */ +#if DHCP_ENV == DHCP_ENV_FREEBSD /* FreeBSD table in the original code */ + {0, 0, "FreeBSD"}, /* prefix */ + {1, __TXT, "kernel"}, + {2, __TXT, "kernelname"}, + {3, __TXT, "kernel_options"}, + {4, __IP, "usr-ip"}, + {5, __TXT, "conf-path"}, + {6, __TXT, "rc.conf0"}, + {7, __TXT, "rc.conf1"}, + {8, __TXT, "rc.conf2"}, + {9, __TXT, "rc.conf3"}, + {10, __TXT, "rc.conf4"}, + {11, __TXT, "rc.conf5"}, + {12, __TXT, "rc.conf6"}, + {13, __TXT, "rc.conf7"}, + {14, __TXT, "rc.conf8"}, + {15, __TXT, "rc.conf9"}, + + {20, __TXT, "boot.nfsroot.options"}, + + {245, __INDIR, ""}, + {246, __INDIR, ""}, + {247, __INDIR, ""}, + {248, __INDIR, ""}, + {249, __INDIR, ""}, + {250, __INDIR, ""}, + {251, __INDIR, ""}, + {252, __INDIR, ""}, + {253, __INDIR, ""}, + {254, __INDIR, ""}, + +#elif DHCP_ENV == DHCP_ENV_PXE /* some pxe options, RFC4578 */ + {0, 0, "pxe"}, /* prefix */ + {93, __16, "system-architecture"}, + {94, __BYTES, "network-interface"}, + {97, __BYTES, "machine-identifier"}, +#else /* default (empty) table */ + {0, 0, "dhcp.vendor."}, /* prefix */ +#endif + {0, __TXT, "%soption-%d"} +}; + +static struct dhcp_opt dhcp_opt[] = { + /* DHCP Option names, formats and codes, from RFC2132. */ + {0, 0, "dhcp."}, // prefix + {1, __IP, "subnet-mask"}, + {2, __32, "time-offset"}, /* this is signed */ + {3, __IP, "routers"}, + {4, __IP, "time-servers"}, + {5, __IP, "ien116-name-servers"}, + {6, __IP, "domain-name-servers"}, + {7, __IP, "log-servers"}, + {8, __IP, "cookie-servers"}, + {9, __IP, "lpr-servers"}, + {10, __IP, "impress-servers"}, + {11, __IP, "resource-location-servers"}, + {12, __TXT, "host-name"}, + {13, __16, "boot-size"}, + {14, __TXT, "merit-dump"}, + {15, __TXT, "domain-name"}, + {16, __IP, "swap-server"}, + {17, __TXT, "root-path"}, + {18, __TXT, "extensions-path"}, + {19, __8, "ip-forwarding"}, + {20, __8, "non-local-source-routing"}, + {21, __IP, "policy-filter"}, + {22, __16, "max-dgram-reassembly"}, + {23, __8, "default-ip-ttl"}, + {24, __32, "path-mtu-aging-timeout"}, + {25, __16, "path-mtu-plateau-table"}, + {26, __16, "interface-mtu"}, + {27, __8, "all-subnets-local"}, + {28, __IP, "broadcast-address"}, + {29, __8, "perform-mask-discovery"}, + {30, __8, "mask-supplier"}, + {31, __8, "perform-router-discovery"}, + {32, __IP, "router-solicitation-address"}, + {33, __IP, "static-routes"}, + {34, __8, "trailer-encapsulation"}, + {35, __32, "arp-cache-timeout"}, + {36, __8, "ieee802-3-encapsulation"}, + {37, __8, "default-tcp-ttl"}, + {38, __32, "tcp-keepalive-interval"}, + {39, __8, "tcp-keepalive-garbage"}, + {40, __TXT, "nis-domain"}, + {41, __IP, "nis-servers"}, + {42, __IP, "ntp-servers"}, + {43, __VE, "vendor-encapsulated-options"}, + {44, __IP, "netbios-name-servers"}, + {45, __IP, "netbios-dd-server"}, + {46, __8, "netbios-node-type"}, + {47, __TXT, "netbios-scope"}, + {48, __IP, "x-font-servers"}, + {49, __IP, "x-display-managers"}, + {50, __IP, "dhcp-requested-address"}, + {51, __32, "dhcp-lease-time"}, + {52, __8, "dhcp-option-overload"}, + {53, __8, "dhcp-message-type"}, + {54, __IP, "dhcp-server-identifier"}, + {55, __8, "dhcp-parameter-request-list"}, + {56, __TXT, "dhcp-message"}, + {57, __16, "dhcp-max-message-size"}, + {58, __32, "dhcp-renewal-time"}, + {59, __32, "dhcp-rebinding-time"}, + {60, __TXT, "vendor-class-identifier"}, + {61, __TXT, "dhcp-client-identifier"}, + {64, __TXT, "nisplus-domain"}, + {65, __IP, "nisplus-servers"}, + {66, __TXT, "tftp-server-name"}, + {67, __TXT, "bootfile-name"}, + {68, __IP, "mobile-ip-home-agent"}, + {69, __IP, "smtp-server"}, + {70, __IP, "pop-server"}, + {71, __IP, "nntp-server"}, + {72, __IP, "www-server"}, + {73, __IP, "finger-server"}, + {74, __IP, "irc-server"}, + {75, __IP, "streettalk-server"}, + {76, __IP, "streettalk-directory-assistance-server"}, + {77, __TXT, "user-class"}, + {85, __IP, "nds-servers"}, + {86, __TXT, "nds-tree-name"}, + {87, __TXT, "nds-context"}, + {210, __TXT, "authenticate"}, + + /* use the following entries for arbitrary variables */ + {246, __ILIST, ""}, + {247, __ILIST, ""}, + {248, __ILIST, ""}, + {249, __ILIST, ""}, + {250, __INDIR, ""}, + {251, __INDIR, ""}, + {252, __INDIR, ""}, + {253, __INDIR, ""}, + {254, __INDIR, ""}, + {0, __TXT, "%soption-%d"} +}; + +/* + * parse a dhcp response, set environment variables translating options + * names and values according to the tables above. Also set dhcp.tags + * to the list of selected tags. + */ +static void +setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts) +{ + u_char *ncp; + u_char tag; + char tags[512], *tp; /* the list of tags */ + +#define FLD_SEP ',' /* separator in list of elements */ + ncp = cp; + tp = tags; + if (opts == NULL) + opts = dhcp_opt; + + while (ncp < ep) { + unsigned int size; /* option size */ + char *vp, *endv, buf[256]; /* the value buffer */ + struct dhcp_opt *op; + + tag = *ncp++; /* extract tag and size */ + size = *ncp++; + cp = ncp; /* current payload */ + ncp += size; /* point to the next option */ + + if (tag == TAG_END) + break; + if (tag == 0) + continue; + + for (op = opts+1; op->tag && op->tag != tag; op++) + ; + /* if not found we end up on the default entry */ + + /* + * Copy data into the buffer. libstand does not have snprintf so we + * need to be careful with sprintf(). With strings, the source is + * always <256 char so shorter than the buffer so we are safe; with + * other arguments, the longest string is inet_ntoa which is 16 bytes + * so we make sure to have always enough room in the string before + * trying an sprint. + */ + vp = buf; + *vp = '\0'; + endv = buf + sizeof(buf) - 1 - 16; /* last valid write position */ + + switch(op->fmt) { + case __NONE: + break; /* should not happen */ + + case __VE: /* recurse, vendor specific */ + setenv_(cp, cp+size, vndr_opt); + break; + + case __IP: /* ip address */ + for (; size > 0 && vp < endv; size -= 4, cp += 4) { + struct in_addr in_ip; /* ip addresses */ + if (vp != buf) + *vp++ = FLD_SEP; + bcopy(cp, &in_ip.s_addr, sizeof(in_ip.s_addr)); + sprintf(vp, "%s", inet_ntoa(in_ip)); + vp += strlen(vp); + } + break; + + case __BYTES: /* opaque byte string */ + for (; size > 0 && vp < endv; size -= 1, cp += 1) { + sprintf(vp, "%02x", *cp); + vp += strlen(vp); + } + break; + + case __TXT: + bcopy(cp, buf, size); /* cannot overflow */ + buf[size] = 0; + break; + + case __32: + case __16: + case __8: /* op->fmt is also the length of each field */ + for (; size > 0 && vp < endv; size -= op->fmt, cp += op->fmt) { + uint32_t v; + if (op->fmt == __32) + v = (cp[0]<<24) + (cp[1]<<16) + (cp[2]<<8) + cp[3]; + else if (op->fmt == __16) + v = (cp[0]<<8) + cp[1]; + else + v = cp[0]; + if (vp != buf) + *vp++ = FLD_SEP; + sprintf(vp, "%u", v); + vp += strlen(vp); + } + break; + + case __INDIR: /* name=value */ + case __ILIST: /* name=value;name=value... */ + bcopy(cp, buf, size); /* cannot overflow */ + buf[size] = '\0'; + for (endv = buf; endv; endv = vp) { + u_char *s = NULL; /* semicolon ? */ + + /* skip leading whitespace */ + while (*endv && strchr(" \t\n\r", *endv)) + endv++; + vp = strchr(endv, '='); /* find name=value separator */ + if (!vp) + break; + *vp++ = 0; + if (op->fmt == __ILIST && (s = strchr(vp, ';'))) + *s++ = '\0'; + setenv(endv, vp, 1); + vp = s; /* prepare for next round */ + } + buf[0] = '\0'; /* option already done */ + } + + if (tp - tags < sizeof(tags) - 5) { /* add tag to the list */ + if (tp != tags) + *tp++ = FLD_SEP; + sprintf(tp, "%d", tag); + tp += strlen(tp); + } + if (buf[0]) { + char env[128]; /* the string name */ + + if (op->tag == 0) + sprintf(env, op->desc, opts[0].desc, tag); + else + sprintf(env, "%s%s", opts[0].desc, op->desc); + /* + * Do not replace existing values in the environment, so that + * locally-obtained values can override server-provided values. + */ + setenv(env, buf, 0); + } + } + if (tp != tags) { + char env[128]; /* the string name */ + sprintf(env, "%stags", opts[0].desc); + setenv(env, tags, 1); + } +} +#endif /* additional dhcp */ diff --git a/stand/libsa/bootp.h b/stand/libsa/bootp.h new file mode 100644 index 000000000000..2e7049b872af --- /dev/null +++ b/stand/libsa/bootp.h @@ -0,0 +1,151 @@ +/* $NetBSD: bootp.h,v 1.4 1997/09/06 13:55:57 drochner Exp $ */ + +/* + * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. + * + * This file specifies the "implementation-independent" BOOTP protocol + * information which is common to both client and server. + * + * Copyright 1988 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * $FreeBSD$ + */ + +#ifndef _BOOTP_H_ +#define _BOOTP_H_ + +struct bootp { + unsigned char bp_op; /* packet opcode type */ + unsigned char bp_htype; /* hardware addr type */ + unsigned char bp_hlen; /* hardware addr length */ + unsigned char bp_hops; /* gateway hops */ + unsigned int bp_xid; /* transaction ID */ + unsigned short bp_secs; /* seconds since boot began */ + unsigned short bp_flags; + struct in_addr bp_ciaddr; /* client IP address */ + struct in_addr bp_yiaddr; /* 'your' IP address */ + struct in_addr bp_siaddr; /* server IP address */ + struct in_addr bp_giaddr; /* gateway IP address */ + unsigned char bp_chaddr[16]; /* client hardware address */ + unsigned char bp_sname[64]; /* server host name */ + unsigned char bp_file[128]; /* boot file name */ +#ifdef SUPPORT_DHCP +#define BOOTP_VENDSIZE 312 +#else +#define BOOTP_VENDSIZE 64 +#endif + unsigned char bp_vend[BOOTP_VENDSIZE]; /* vendor-specific area */ +}; + +/* + * UDP port numbers, server and client. + */ +#define IPPORT_BOOTPS 67 +#define IPPORT_BOOTPC 68 + +#define BOOTREPLY 2 +#define BOOTREQUEST 1 + + +/* + * Vendor magic cookie (v_magic) for CMU + */ +#define VM_CMU "CMU" + +/* + * Vendor magic cookie (v_magic) for RFC1048 + */ +#define VM_RFC1048 { 99, 130, 83, 99 } + + + +/* + * RFC1048 tag values used to specify what information is being supplied in + * the vendor field of the packet. + */ + +#define TAG_PAD ((unsigned char) 0) +#define TAG_SUBNET_MASK ((unsigned char) 1) +#define TAG_TIME_OFFSET ((unsigned char) 2) +#define TAG_GATEWAY ((unsigned char) 3) +#define TAG_TIME_SERVER ((unsigned char) 4) +#define TAG_NAME_SERVER ((unsigned char) 5) +#define TAG_DOMAIN_SERVER ((unsigned char) 6) +#define TAG_LOG_SERVER ((unsigned char) 7) +#define TAG_COOKIE_SERVER ((unsigned char) 8) +#define TAG_LPR_SERVER ((unsigned char) 9) +#define TAG_IMPRESS_SERVER ((unsigned char) 10) +#define TAG_RLP_SERVER ((unsigned char) 11) +#define TAG_HOSTNAME ((unsigned char) 12) +#define TAG_BOOTSIZE ((unsigned char) 13) +#define TAG_DUMPFILE ((unsigned char) 14) +#define TAG_DOMAINNAME ((unsigned char) 15) +#define TAG_SWAPSERVER ((unsigned char) 16) +#define TAG_ROOTPATH ((unsigned char) 17) +#define TAG_INTF_MTU ((unsigned char) 26) + +#ifdef SUPPORT_DHCP +#define TAG_REQ_ADDR ((unsigned char) 50) +#define TAG_LEASETIME ((unsigned char) 51) +#define TAG_OVERLOAD ((unsigned char) 52) +#define TAG_DHCP_MSGTYPE ((unsigned char) 53) +#define TAG_SERVERID ((unsigned char) 54) +#define TAG_PARAM_REQ ((unsigned char) 55) +#define TAG_MSG ((unsigned char) 56) +#define TAG_MAXSIZE ((unsigned char) 57) +#define TAG_T1 ((unsigned char) 58) +#define TAG_T2 ((unsigned char) 59) +#define TAG_CLASSID ((unsigned char) 60) +#define TAG_CLIENTID ((unsigned char) 61) +#define TAG_USER_CLASS ((unsigned char) 77) +#endif + +#define TAG_END ((unsigned char) 255) + +#ifdef SUPPORT_DHCP +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#endif + +/* + * "vendor" data permitted for CMU bootp clients. + */ + +struct cmu_vend { + unsigned char v_magic[4]; /* magic number */ + unsigned int v_flags; /* flags/opcodes, etc. */ + struct in_addr v_smask; /* Subnet mask */ + struct in_addr v_dgate; /* Default gateway */ + struct in_addr v_dns1, v_dns2; /* Domain name servers */ + struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */ + struct in_addr v_ts1, v_ts2; /* Time servers */ + unsigned char v_unused[25]; /* currently unused */ +}; + + +/* v_flags values */ +#define VF_SMASK 1 /* Subnet mask field contains valid data */ + +/* cached bootp response/dhcp ack */ +extern struct bootp *bootp_response; +extern size_t bootp_response_size; + +int dhcp_try_rfc1048(u_char *cp, u_int len); + +#endif /* _BOOTP_H_ */ diff --git a/stand/libsa/bootparam.c b/stand/libsa/bootparam.c new file mode 100644 index 000000000000..1de2d53d77fe --- /dev/null +++ b/stand/libsa/bootparam.c @@ -0,0 +1,435 @@ +/* $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $ */ + +/* + * Copyright (c) 1995 Gordon W. Ross + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon W. Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * RPC/bootparams + */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include <string.h> + +#include "rpcv2.h" + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" +#include "bootparam.h" + +#ifdef DEBUG_RPC +#define RPC_PRINTF(a) printf a +#else +#define RPC_PRINTF(a) +#endif + +struct in_addr bp_server_addr; /* net order */ +n_short bp_server_port; /* net order */ + +/* + * RPC definitions for bootparamd + */ +#define BOOTPARAM_PROG 100026 +#define BOOTPARAM_VERS 1 +#define BOOTPARAM_WHOAMI 1 +#define BOOTPARAM_GETFILE 2 + +/* + * Inet address in RPC messages + * (Note, really four ints, NOT chars. Blech.) + */ +struct xdr_inaddr { + u_int32_t atype; + int32_t addr[4]; +}; + +int xdr_inaddr_encode(char **p, struct in_addr ia); +int xdr_inaddr_decode(char **p, struct in_addr *ia); + +int xdr_string_encode(char **p, char *str, int len); +int xdr_string_decode(char **p, char *str, int *len_p); + + +/* + * RPC: bootparam/whoami + * Given client IP address, get: + * client name (hostname) + * domain name (domainname) + * gateway address + * + * The hostname and domainname are set here for convenience. + * + * Note - bpsin is initialized to the broadcast address, + * and will be replaced with the bootparam server address + * after this call is complete. Have to use PMAP_PROC_CALL + * to make sure we get responses only from a servers that + * know about us (don't want to broadcast a getport call). + */ +int +bp_whoami(int sockfd) +{ + /* RPC structures for PMAPPROC_CALLIT */ + struct args { + u_int32_t prog; + u_int32_t vers; + u_int32_t proc; + u_int32_t arglen; + struct xdr_inaddr xina; + } *args; + struct repl { + u_int16_t _pad; + u_int16_t port; + u_int32_t encap_len; + /* encapsulated data here */ + n_long capsule[64]; + } *repl; + struct { + n_long h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + char *send_tail, *recv_head; + struct iodesc *d; + void *pkt; + int len, x, rc; + + RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); + + rc = -1; + if (!(d = socktodesc(sockfd))) { + RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); + return (rc); + } + args = &sdata.d; + + /* + * Build request args for PMAPPROC_CALLIT. + */ + args->prog = htonl(BOOTPARAM_PROG); + args->vers = htonl(BOOTPARAM_VERS); + args->proc = htonl(BOOTPARAM_WHOAMI); + args->arglen = htonl(sizeof(struct xdr_inaddr)); + send_tail = (char*) &args->xina; + + /* + * append encapsulated data (client IP address) + */ + if (xdr_inaddr_encode(&send_tail, myip)) + return (rc); + + /* RPC: portmap/callit */ + d->myport = htons(--rpc_port); + d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ + /* rpc_call will set d->destport */ + + pkt = NULL; + len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, + args, send_tail - (char*)args, (void **)&repl, &pkt); + if (len < 8) { + printf("bootparamd: 'whoami' call failed\n"); + goto done; + } + + /* Save bootparam server address (from IP header). */ + rpc_fromaddr(repl, &bp_server_addr, &bp_server_port); + + /* + * Note that bp_server_port is now 111 due to the + * indirect call (using PMAPPROC_CALLIT), so get the + * actual port number from the reply data. + */ + bp_server_port = repl->port; + + RPC_PRINTF(("bp_whoami: server at %s:%d\n", + inet_ntoa(bp_server_addr), ntohs(bp_server_port))); + + /* We have just done a portmap call, so cache the portnum. */ + rpc_pmap_putcache(bp_server_addr, + BOOTPARAM_PROG, + BOOTPARAM_VERS, + (int)ntohs(bp_server_port)); + + /* + * Parse the encapsulated results from bootparam/whoami + */ + x = ntohl(repl->encap_len); + if (len < x) { + printf("bp_whoami: short reply, %d < %d\n", len, x); + goto done; + } + recv_head = (char*) repl->capsule; + + /* client name */ + hostnamelen = MAXHOSTNAMELEN-1; + if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { + RPC_PRINTF(("bp_whoami: bad hostname\n")); + goto done; + } + + /* domain name */ + domainnamelen = MAXHOSTNAMELEN-1; + if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { + RPC_PRINTF(("bp_whoami: bad domainname\n")); + goto done; + } + + /* gateway address */ + if (xdr_inaddr_decode(&recv_head, &gateip)) { + RPC_PRINTF(("bp_whoami: bad gateway\n")); + goto done; + } + + /* success */ + rc = 0; +done: + free(pkt); + return (rc); +} + + +/* + * RPC: bootparam/getfile + * Given client name and file "key", get: + * server name + * server IP address + * server pathname + */ +int +bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname) +{ + struct { + n_long h[RPC_HEADER_WORDS]; + n_long d[64]; + } sdata; + void *pkt; + char serv_name[FNAME_SIZE]; + char *rdata, *send_tail; + /* misc... */ + struct iodesc *d; + int rc = -1, sn_len, path_len, rlen; + + if (!(d = socktodesc(sockfd))) { + RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); + return (-1); + } + + send_tail = (char*) sdata.d; + + /* + * Build request message. + */ + + /* client name (hostname) */ + if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { + RPC_PRINTF(("bp_getfile: bad client\n")); + return (-1); + } + + /* key name (root or swap) */ + if (xdr_string_encode(&send_tail, key, strlen(key))) { + RPC_PRINTF(("bp_getfile: bad key\n")); + return (-1); + } + + /* RPC: bootparam/getfile */ + d->myport = htons(--rpc_port); + d->destip = bp_server_addr; + /* rpc_call will set d->destport */ + pkt = NULL; + rlen = rpc_call(d, + BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, + sdata.d, send_tail - (char*)sdata.d, + (void **)&rdata, &pkt); + if (rlen < 4) { + RPC_PRINTF(("bp_getfile: short reply\n")); + errno = EBADRPC; + goto done; + } + + /* + * Parse result message. + */ + + /* server name */ + sn_len = FNAME_SIZE-1; + if (xdr_string_decode(&rdata, serv_name, &sn_len)) { + RPC_PRINTF(("bp_getfile: bad server name\n")); + goto done; + } + + /* server IP address (mountd/NFS) */ + if (xdr_inaddr_decode(&rdata, serv_addr)) { + RPC_PRINTF(("bp_getfile: bad server addr\n")); + goto done; + } + + /* server pathname */ + path_len = MAXPATHLEN-1; + if (xdr_string_decode(&rdata, pathname, &path_len)) { + RPC_PRINTF(("bp_getfile: bad server path\n")); + goto done; + } + + /* success */ + rc = 0; +done: + free(pkt); + return (rc); +} + + +/* + * eXternal Data Representation routines. + * (but with non-standard args...) + */ + + +int +xdr_string_encode(char **pkt, char *str, int len) +{ + uint32_t *lenp; + char *datap; + int padlen = (len + 3) & ~3; /* padded length */ + + /* The data will be int aligned. */ + lenp = (uint32_t *) *pkt; + *pkt += sizeof(*lenp); + *lenp = htonl(len); + + datap = *pkt; + *pkt += padlen; + bcopy(str, datap, len); + + return (0); +} + +int +xdr_string_decode(char **pkt, char *str, int *len_p) +{ + uint32_t *lenp; + char *datap; + int slen; /* string length */ + int plen; /* padded length */ + + /* The data will be int aligned. */ + lenp = (uint32_t *) *pkt; + *pkt += sizeof(*lenp); + slen = ntohl(*lenp); + plen = (slen + 3) & ~3; + + if (slen > *len_p) + slen = *len_p; + datap = *pkt; + *pkt += plen; + bcopy(datap, str, slen); + + str[slen] = '\0'; + *len_p = slen; + + return (0); +} + + +int +xdr_inaddr_encode(char **pkt, struct in_addr ia) +{ + struct xdr_inaddr *xi; + u_char *cp; + int32_t *ip; + union { + n_long l; /* network order */ + u_char c[4]; + } uia; + + /* The data will be int aligned. */ + xi = (struct xdr_inaddr *) *pkt; + *pkt += sizeof(*xi); + xi->atype = htonl(1); + uia.l = ia.s_addr; + cp = uia.c; + ip = xi->addr; + /* + * Note: the htonl() calls below DO NOT + * imply that uia.l is in host order. + * In fact this needs it in net order. + */ + *ip++ = htonl((unsigned int)*cp++); + *ip++ = htonl((unsigned int)*cp++); + *ip++ = htonl((unsigned int)*cp++); + *ip++ = htonl((unsigned int)*cp++); + + return (0); +} + +int +xdr_inaddr_decode(char **pkt, struct in_addr *ia) +{ + struct xdr_inaddr *xi; + u_char *cp; + int32_t *ip; + union { + n_long l; /* network order */ + u_char c[4]; + } uia; + + /* The data will be int aligned. */ + xi = (struct xdr_inaddr *) *pkt; + *pkt += sizeof(*xi); + if (xi->atype != htonl(1)) { + RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", + ntohl(xi->atype))); + return(-1); + } + + cp = uia.c; + ip = xi->addr; + /* + * Note: the ntohl() calls below DO NOT + * imply that uia.l is in host order. + * In fact this needs it in net order. + */ + *cp++ = ntohl(*ip++); + *cp++ = ntohl(*ip++); + *cp++ = ntohl(*ip++); + *cp++ = ntohl(*ip++); + ia->s_addr = uia.l; + + return (0); +} diff --git a/stand/libsa/bootparam.h b/stand/libsa/bootparam.h new file mode 100644 index 000000000000..9c9f50ea434d --- /dev/null +++ b/stand/libsa/bootparam.h @@ -0,0 +1,6 @@ +/* $NetBSD: bootparam.h,v 1.3 1998/01/05 19:19:41 perry Exp $ */ +/* $FreeBSD$ */ + +int bp_whoami(int sock); +int bp_getfile(int sock, char *key, struct in_addr *addrp, char *path); + diff --git a/stand/libsa/bzipfs.c b/stand/libsa/bzipfs.c new file mode 100644 index 000000000000..ff1514efeed3 --- /dev/null +++ b/stand/libsa/bzipfs.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 1998 Michael Smith. + * Copyright (c) 2000 Maxim Sobolev + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifndef REGRESSION +#include "stand.h" +#else +#include <stdlib.h> +#include <sys/errno.h> +#include <sys/fcntl.h> +#include <sys/types.h> +#include <sys/unistd.h> + +struct open_file { + int f_flags; /* see F_* below */ + void *f_fsdata; /* file system specific data */ +}; +#define F_READ 0x0001 /* file opened for reading */ +#define EOFFSET (ELAST+8) /* relative seek not supported */ +static inline u_int min(u_int a, u_int b) { return(a < b ? a : b); } +#define panic(x, y) abort() +#endif + +#include <sys/stat.h> +#include <string.h> +#include <bzlib.h> + +#define BZ_BUFSIZE 2048 /* XXX larger? */ + +struct bz_file +{ + int bzf_rawfd; + bz_stream bzf_bzstream; + char bzf_buf[BZ_BUFSIZE]; + int bzf_endseen; +}; + +static int bzf_fill(struct bz_file *z); +static int bzf_open(const char *path, struct open_file *f); +static int bzf_close(struct open_file *f); +static int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t bzf_seek(struct open_file *f, off_t offset, int where); +static int bzf_stat(struct open_file *f, struct stat *sb); + +#ifndef REGRESSION +struct fs_ops bzipfs_fsops = { + "bzip", + bzf_open, + bzf_close, + bzf_read, + null_write, + bzf_seek, + bzf_stat, + null_readdir +}; +#endif + +static int +bzf_fill(struct bz_file *bzf) +{ + int result; + int req; + + req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in; + result = 0; + + /* If we need more */ + if (req > 0) { + /* move old data to bottom of buffer */ + if (req < BZ_BUFSIZE) + bcopy(bzf->bzf_buf + req, bzf->bzf_buf, BZ_BUFSIZE - req); + + /* read to fill buffer and update availibility data */ + result = read(bzf->bzf_rawfd, bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req); + bzf->bzf_bzstream.next_in = bzf->bzf_buf; + if (result >= 0) + bzf->bzf_bzstream.avail_in += result; + } + return(result); +} + +/* + * Adapted from get_byte/check_header in libz + * + * Returns 0 if the header is OK, nonzero if not. + */ +static int +get_byte(struct bz_file *bzf) +{ + if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) + return(-1); + bzf->bzf_bzstream.avail_in--; + return(*(bzf->bzf_bzstream.next_in)++); +} + +static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */ + +static int +check_header(struct bz_file *bzf) +{ + unsigned int len; + int c; + + /* Check the bzip2 magic header */ + for (len = 0; len < 3; len++) { + c = get_byte(bzf); + if (c != bz_magic[len]) { + return(1); + } + } + /* Check that the block size is valid */ + c = get_byte(bzf); + if (c < '1' || c > '9') + return(1); + + /* Put back bytes that we've took from the input stream */ + bzf->bzf_bzstream.next_in -= 4; + bzf->bzf_bzstream.avail_in += 4; + + return(0); +} + +static int +bzf_open(const char *fname, struct open_file *f) +{ + static char *bzfname; + int rawfd; + struct bz_file *bzf; + char *cp; + int error; + struct stat sb; + + /* Have to be in "just read it" mode */ + if (f->f_flags != F_READ) + return(EPERM); + + /* If the name already ends in .gz or .bz2, ignore it */ + if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz") + || !strcmp(cp, ".bz2") || !strcmp(cp, ".split"))) + return(ENOENT); + + /* Construct new name */ + bzfname = malloc(strlen(fname) + 5); + if (bzfname == NULL) + return(ENOMEM); + sprintf(bzfname, "%s.bz2", fname); + + /* Try to open the compressed datafile */ + rawfd = open(bzfname, O_RDONLY); + free(bzfname); + if (rawfd == -1) + return(ENOENT); + + if (fstat(rawfd, &sb) < 0) { + printf("bzf_open: stat failed\n"); + close(rawfd); + return(ENOENT); + } + if (!S_ISREG(sb.st_mode)) { + printf("bzf_open: not a file\n"); + close(rawfd); + return(EISDIR); /* best guess */ + } + + /* Allocate a bz_file structure, populate it */ + bzf = malloc(sizeof(struct bz_file)); + if (bzf == NULL) + return(ENOMEM); + bzero(bzf, sizeof(struct bz_file)); + bzf->bzf_rawfd = rawfd; + + /* Verify that the file is bzipped */ + if (check_header(bzf)) { + close(bzf->bzf_rawfd); + free(bzf); + return(EFTYPE); + } + + /* Initialise the inflation engine */ + if ((error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1)) != BZ_OK) { + printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error); + close(bzf->bzf_rawfd); + free(bzf); + return(EIO); + } + + /* Looks OK, we'll take it */ + f->f_fsdata = bzf; + return(0); +} + +static int +bzf_close(struct open_file *f) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + + BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); + close(bzf->bzf_rawfd); + free(bzf); + return(0); +} + +static int +bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + int error; + + bzf->bzf_bzstream.next_out = buf; /* where and how much */ + bzf->bzf_bzstream.avail_out = size; + + while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) { + if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) { + printf("bzf_read: fill error\n"); + return(EIO); + } + if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */ + printf("bzf_read: unexpected EOF\n"); + if (bzf->bzf_bzstream.avail_out == size) + return(EIO); + break; + } + + error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */ + if (error == BZ_STREAM_END) { /* EOF, all done */ + bzf->bzf_endseen = 1; + break; + } + if (error != BZ_OK) { /* argh, decompression error */ + printf("bzf_read: BZ2_bzDecompress returned %d\n", error); + return(EIO); + } + } + if (resid != NULL) + *resid = bzf->bzf_bzstream.avail_out; + return(0); +} + +static int +bzf_rewind(struct open_file *f) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + struct bz_file *bzf_tmp; + + /* + * Since bzip2 does not have an equivalent inflateReset function a crude + * one needs to be provided. The functions all called in such a way that + * at any time an error occurs a roll back can be done (effectively making + * this rewind 'atomic', either the reset occurs successfully or not at all, + * with no 'undefined' state happening). + */ + + /* Allocate a bz_file structure, populate it */ + bzf_tmp = malloc(sizeof(struct bz_file)); + if (bzf_tmp == NULL) + return(-1); + bzero(bzf_tmp, sizeof(struct bz_file)); + bzf_tmp->bzf_rawfd = bzf->bzf_rawfd; + + /* Initialise the inflation engine */ + if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) { + free(bzf_tmp); + return(-1); + } + + /* Seek back to the beginning of the file */ + if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) { + BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream)); + free(bzf_tmp); + return(-1); + } + + /* Free old bz_file data */ + BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); + free(bzf); + + /* Use the new bz_file data */ + f->f_fsdata = bzf_tmp; + + return(0); +} + +static off_t +bzf_seek(struct open_file *f, off_t offset, int where) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + off_t target; + char discard[16]; + + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = offset + bzf->bzf_bzstream.total_out_lo32; + break; + default: + errno = EINVAL; + return(-1); + } + + /* Can we get there from here? */ + if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) { + errno = EOFFSET; + return -1; + } + + /* if bzf_rewind was called then bzf has changed */ + bzf = (struct bz_file *)f->f_fsdata; + + /* skip forwards if required */ + while (target > bzf->bzf_bzstream.total_out_lo32) { + errno = bzf_read(f, discard, min(sizeof(discard), + target - bzf->bzf_bzstream.total_out_lo32), NULL); + if (errno) + return(-1); + } + /* This is where we are (be honest if we overshot) */ + return(bzf->bzf_bzstream.total_out_lo32); +} + +static int +bzf_stat(struct open_file *f, struct stat *sb) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + int result; + + /* stat as normal, but indicate that size is unknown */ + if ((result = fstat(bzf->bzf_rawfd, sb)) == 0) + sb->st_size = -1; + return(result); +} + +void +bz_internal_error(int errorcode) +{ + panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode); +} + +#ifdef REGRESSION +/* Small test case, open and decompress test.bz2 */ +int main() +{ + struct open_file f; + char buf[1024]; + size_t resid; + int err; + + memset(&f, '\0', sizeof(f)); + f.f_flags = F_READ; + err = bzf_open("test", &f); + if (err != 0) + exit(1); + do { + err = bzf_read(&f, buf, sizeof(buf), &resid); + } while (err == 0 && resid != sizeof(buf)); + + if (err != 0) + exit(2); + exit(0); +} +#endif diff --git a/stand/libsa/cd9660.c b/stand/libsa/cd9660.c new file mode 100644 index 000000000000..c5618838e4a6 --- /dev/null +++ b/stand/libsa/cd9660.c @@ -0,0 +1,600 @@ +/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ + +/* + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Stand-alone ISO9660 file reading package. + * + * Note: This doesn't support Rock Ridge extensions, extended attributes, + * blocksizes other than 2048 bytes, multi-extent files, etc. + */ +#include <sys/param.h> +#include <string.h> +#include <sys/dirent.h> +#include <isofs/cd9660/iso.h> +#include <isofs/cd9660/cd9660_rrip.h> + +#include "stand.h" + +#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 buf_read_file(struct open_file *f, char **buf_p, + size_t *size_p); +static int cd9660_open(const char *path, struct open_file *f); +static int cd9660_close(struct open_file *f); +static int cd9660_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static int cd9660_write(struct open_file *f, void *buf, size_t size, + size_t *resid); +static off_t cd9660_seek(struct open_file *f, off_t offset, int where); +static int cd9660_stat(struct open_file *f, struct stat *sb); +static int cd9660_readdir(struct open_file *f, struct dirent *d); +static int dirmatch(struct open_file *f, const char *path, + struct iso_directory_record *dp, int use_rrip, int lenskip); +static int rrip_check(struct open_file *f, struct iso_directory_record *dp, + int *lenskip); +static char *rrip_lookup_name(struct open_file *f, + struct iso_directory_record *dp, int lenskip, size_t *len); +static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, + const char *identifier, struct iso_directory_record *dp, + int lenskip); + +struct fs_ops cd9660_fsops = { + "cd9660", + cd9660_open, + cd9660_close, + cd9660_read, + cd9660_write, + cd9660_seek, + cd9660_stat, + cd9660_readdir +}; + +#define F_ISDIR 0x0001 /* Directory */ +#define F_ROOTDIR 0x0002 /* Root directory */ +#define F_RR 0x0004 /* Rock Ridge on this volume */ + +struct file { + int f_flags; /* file flags */ + off_t f_off; /* Current offset within file */ + daddr_t f_bno; /* Starting block number */ + off_t f_size; /* Size of file */ + daddr_t f_buf_blkno; /* block number of data block */ + char *f_buf; /* buffer for data block */ + int f_susp_skip; /* len_skip for SUSP records */ +}; + +struct ptable_ent { + char namlen [ISODCL( 1, 1)]; /* 711 */ + char extlen [ISODCL( 2, 2)]; /* 711 */ + char block [ISODCL( 3, 6)]; /* 732 */ + char parent [ISODCL( 7, 8)]; /* 722 */ + char name [1]; +}; +#define PTFIXSZ 8 +#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) + +#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) + +static ISO_SUSP_HEADER * +susp_lookup_record(struct open_file *f, 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; + size_t read; + + 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 = f->f_dev->dv_strategy(f->f_devdata, F_READ, + cdb2devb(isonum_733(shc->location)), + ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); + + /* Bail if it fails. */ + if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) + 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 char * +rrip_lookup_name(struct open_file *f, 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(f, 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 open_file *f, 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(f, SUSP_EXTREF, dp, 0); + if (er == NULL) + return (0); + return (1); +} + +static int +dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, + int use_rrip, int lenskip) +{ + size_t len; + char *cp; + int i, icase; + + if (use_rrip) + cp = rrip_lookup_name(f, dp, lenskip, &len); + else + cp = NULL; + if (cp == NULL) { + len = isonum_711(dp->name_len); + cp = dp->name; + icase = 1; + } else + icase = 0; + 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 int +cd9660_open(const char *path, struct open_file *f) +{ + struct file *fp = NULL; + void *buf; + struct iso_primary_descriptor *vd; + size_t buf_size, read, dsize, off; + daddr_t bno, boff; + struct iso_directory_record rec; + struct iso_directory_record *dp = NULL; + int rc, first, use_rrip, lenskip; + + /* First find the volume descriptor */ + buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); + vd = buf; + for (bno = 16;; bno++) { + twiddle(1); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), + ISO_DEFAULT_BLOCK_SIZE, buf, &read); + if (rc) + goto out; + if (read != ISO_DEFAULT_BLOCK_SIZE) { + rc = EIO; + goto out; + } + rc = EINVAL; + if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) + goto out; + if (isonum_711(vd->type) == ISO_VD_END) + goto out; + if (isonum_711(vd->type) == ISO_VD_PRIMARY) + break; + } + if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) + goto out; + + 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) { + twiddle(1); + rc = f->f_dev->dv_strategy + (f->f_devdata, F_READ, + cdb2devb(bno + boff), + ISO_DEFAULT_BLOCK_SIZE, + buf, &read); + if (rc) + goto out; + if (read != ISO_DEFAULT_BLOCK_SIZE) { + rc = EIO; + goto out; + } + boff++; + dp = (struct iso_directory_record *) buf; + } + 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(f, dp, &lenskip); + + if (dirmatch(f, 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) { + rc = ENOENT; + goto out; + } + + rec = *dp; + while (*path && *path != '/') /* look for next component */ + path++; + if (*path) path++; /* skip '/' */ + } + + /* allocate file system specific data structure */ + fp = malloc(sizeof(struct file)); + bzero(fp, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + if ((isonum_711(rec.flags) & 2) != 0) { + fp->f_flags = F_ISDIR; + } + if (first) { + fp->f_flags |= F_ROOTDIR; + + /* Check for Rock Ridge since we didn't in the loop above. */ + bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + twiddle(1); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), + ISO_DEFAULT_BLOCK_SIZE, buf, &read); + if (rc) + goto out; + if (read != ISO_DEFAULT_BLOCK_SIZE) { + rc = EIO; + goto out; + } + dp = (struct iso_directory_record *)buf; + use_rrip = rrip_check(f, dp, &lenskip); + } + if (use_rrip) { + fp->f_flags |= F_RR; + fp->f_susp_skip = lenskip; + } + fp->f_off = 0; + fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + fp->f_size = isonum_733(rec.size); + free(buf); + + return 0; + +out: + if (fp) + free(fp); + free(buf); + + return rc; +} + +static int +cd9660_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + f->f_fsdata = NULL; + free(fp); + + return 0; +} + +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + daddr_t blkno, blkoff; + int rc = 0; + size_t read; + + blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; + blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; + + if (blkno != fp->f_buf_blkno) { + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); + + twiddle(16); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, + cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, + fp->f_buf, &read); + if (rc) + return (rc); + if (read != ISO_DEFAULT_BLOCK_SIZE) + return (EIO); + + fp->f_buf_blkno = blkno; + } + + *buf_p = fp->f_buf + blkoff; + *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; + + if (*size_p > fp->f_size - fp->f_off) + *size_p = fp->f_size - fp->f_off; + return (rc); +} + +static int +cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + char *buf, *addr; + size_t buf_size, csize; + int rc = 0; + + addr = start; + while (size) { + if (fp->f_off < 0 || fp->f_off >= fp->f_size) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size > buf_size ? buf_size : size; + bcopy(buf, addr, csize); + + fp->f_off += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +static int +cd9660_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct iso_directory_record *ep; + size_t buf_size, reclen, namelen; + int error = 0; + int lenskip; + char *buf, *name; + +again: + if (fp->f_off >= fp->f_size) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + ep = (struct iso_directory_record *)buf; + + if (isonum_711(ep->length) == 0) { + daddr_t blkno; + + /* skip to next block, if any */ + blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; + fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; + goto again; + } + + if (fp->f_flags & F_RR) { + if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) + lenskip = 0; + else + lenskip = fp->f_susp_skip; + name = rrip_lookup_name(f, ep, lenskip, &namelen); + } else + name = NULL; + if (name == NULL) { + namelen = isonum_711(ep->name_len); + name = ep->name; + if (namelen == 1) { + if (ep->name[0] == 0) + name = "."; + else if (ep->name[0] == 1) { + namelen = 2; + name = ".."; + } + } + } + reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; + reclen = (reclen + 3) & ~3; + + d->d_fileno = isonum_733(ep->extent); + d->d_reclen = reclen; + if (isonum_711(ep->flags) & 2) + d->d_type = DT_DIR; + else + d->d_type = DT_REG; + d->d_namlen = namelen; + + bcopy(name, d->d_name, d->d_namlen); + d->d_name[d->d_namlen] = 0; + + fp->f_off += isonum_711(ep->length); + return (0); +} + +static int +cd9660_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused) +{ + return EROFS; +} + +static off_t +cd9660_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_off = offset; + break; + case SEEK_CUR: + fp->f_off += offset; + break; + case SEEK_END: + fp->f_off = fp->f_size - offset; + break; + default: + return -1; + } + return fp->f_off; +} + +static int +cd9660_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; + if (fp->f_flags & F_ISDIR) + sb->st_mode |= S_IFDIR; + else + sb->st_mode |= S_IFREG; + sb->st_uid = sb->st_gid = 0; + sb->st_size = fp->f_size; + return 0; +} diff --git a/stand/libsa/close.c b/stand/libsa/close.c new file mode 100644 index 000000000000..142982b88444 --- /dev/null +++ b/stand/libsa/close.c @@ -0,0 +1,98 @@ +/* $NetBSD: close.c,v 1.7 1997/01/22 00:38:09 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)close.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +int +close(int fd) +{ + struct open_file *f = &files[fd]; + int err1 = 0, err2 = 0; + + if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + if (f->f_rabuf != NULL) { + free(f->f_rabuf); + f->f_rabuf = NULL; + } + if (!(f->f_flags & F_RAW) && f->f_ops) + err1 = (f->f_ops->fo_close)(f); + if (!(f->f_flags & F_NODEV) && f->f_dev) + err2 = (f->f_dev->dv_close)(f); + if (f->f_devdata != NULL) + devclose(f); + f->f_flags = 0; + if (err1) { + errno = err1; + return (-1); + } + if (err2) { + errno = err2; + return (-1); + } + return (0); +} diff --git a/stand/libsa/closeall.c b/stand/libsa/closeall.c new file mode 100644 index 000000000000..9693130ebf9b --- /dev/null +++ b/stand/libsa/closeall.c @@ -0,0 +1,76 @@ +/* $NetBSD: closeall.c,v 1.1 1996/01/13 22:25:36 leo Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)close.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +void +closeall() +{ + int i; + + for (i = 0; i < SOPEN_MAX; i++) + if (files[i].f_flags != 0) + (void)close(i); +} diff --git a/stand/libsa/crc32.c b/stand/libsa/crc32.c new file mode 100644 index 000000000000..1a3e3a3329fe --- /dev/null +++ b/stand/libsa/crc32.c @@ -0,0 +1,108 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +#include "crc32.h" + +static const uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t +crc32(const void *buf, size_t size) +{ + const uint8_t *p = buf; + uint32_t crc; + + crc = ~0U; + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return (crc ^ ~0U); +} diff --git a/stand/libsa/crc32.h b/stand/libsa/crc32.h new file mode 100644 index 000000000000..adfd628671aa --- /dev/null +++ b/stand/libsa/crc32.h @@ -0,0 +1,13 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * $FreeBSD$ + */ + +#ifndef _CRC32_H_ +#define _CRC32_H_ + +uint32_t crc32(const void *buf, size_t size); + +#endif /* !_CRC32_H_ */ diff --git a/stand/libsa/dev.c b/stand/libsa/dev.c new file mode 100644 index 000000000000..20f3100852e7 --- /dev/null +++ b/stand/libsa/dev.c @@ -0,0 +1,61 @@ +/* $NetBSD: dev.c,v 1.4 1994/10/30 21:48:23 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)dev.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/reboot.h> + +#include "stand.h" + +int +nodev() +{ + return (ENXIO); +} + +void +nullsys() +{ +} + +/* ARGSUSED */ +int +noioctl(f, cmd, data) + struct open_file *f; + u_long cmd; + void *data; +{ + return (EINVAL); +} diff --git a/stand/libsa/dosfs.c b/stand/libsa/dosfs.c new file mode 100644 index 000000000000..68762842eaee --- /dev/null +++ b/stand/libsa/dosfs.c @@ -0,0 +1,868 @@ +/* + * Copyright (c) 1996, 1998 Robert Nordier + * 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 AUTHOR(S) ``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 AUTHOR(S) 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, + * also supports VFAT. + */ + +#include <sys/types.h> +#include <string.h> +#include <stddef.h> + +#include "stand.h" + +#include "dosfs.h" + + +static int dos_open(const char *path, struct open_file *fd); +static int dos_close(struct open_file *fd); +static int dos_read(struct open_file *fd, void *buf, size_t size, size_t *resid); +static off_t dos_seek(struct open_file *fd, off_t offset, int whence); +static int dos_stat(struct open_file *fd, struct stat *sb); +static int dos_readdir(struct open_file *fd, struct dirent *d); + +struct fs_ops dosfs_fsops = { + "dosfs", + dos_open, + dos_close, + dos_read, + null_write, + dos_seek, + dos_stat, + dos_readdir +}; + +#define SECSIZ 512 /* sector size */ +#define SSHIFT 9 /* SECSIZ shift */ +#define DEPSEC 16 /* directory entries per sector */ +#define DSHIFT 4 /* DEPSEC shift */ +#define LOCLUS 2 /* lowest cluster number */ +#define FATBLKSZ 0x20000 /* size of block in the FAT cache buffer */ + +/* DOS "BIOS Parameter Block" */ +typedef struct { + u_char secsiz[2]; /* sector size */ + u_char spc; /* sectors per cluster */ + u_char ressec[2]; /* reserved sectors */ + u_char fats; /* FATs */ + u_char dirents[2]; /* root directory entries */ + u_char secs[2]; /* total sectors */ + u_char media; /* media descriptor */ + u_char spf[2]; /* sectors per FAT */ + u_char spt[2]; /* sectors per track */ + u_char heads[2]; /* drive heads */ + u_char hidsec[4]; /* hidden sectors */ + u_char lsecs[4]; /* huge sectors */ + u_char lspf[4]; /* huge sectors per FAT */ + u_char xflg[2]; /* flags */ + u_char vers[2]; /* filesystem version */ + u_char rdcl[4]; /* root directory start cluster */ + u_char infs[2]; /* filesystem info sector */ + u_char bkbs[2]; /* backup boot sector */ +} DOS_BPB; + +/* Initial portion of DOS boot sector */ +typedef struct { + u_char jmp[3]; /* usually 80x86 'jmp' opcode */ + u_char oem[8]; /* OEM name and version */ + DOS_BPB bpb; /* BPB */ +} DOS_BS; + +/* Supply missing "." and ".." root directory entries */ +static const char *const dotstr[2] = {".", ".."}; +static DOS_DE dot[2] = { + {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}, + {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}} +}; + +/* The usual conversion macros to avoid multiplication and division */ +#define bytsec(n) ((n) >> SSHIFT) +#define secbyt(s) ((s) << SSHIFT) +#define entsec(e) ((e) >> DSHIFT) +#define bytblk(fs, n) ((n) >> (fs)->bshift) +#define blkbyt(fs, b) ((b) << (fs)->bshift) +#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT)) +#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT)) + +/* Convert cluster number to offset within filesystem */ +#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS)) + +/* Convert cluster number to logical sector number */ +#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS)) + +/* Convert cluster number to offset within FAT */ +#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \ + (sz) == 16 ? (c) << 1 : \ + (c) << 2) + +/* Does cluster number reference a valid data cluster? */ +#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) + +/* Get start cluster from directory entry */ +#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ + ((u_int)cv2((de)->dex.h_clus) << 16) | \ + cv2((de)->clus)) + +static int parsebs(DOS_FS *, DOS_BS *); +static int namede(DOS_FS *, const char *, DOS_DE **); +static int lookup(DOS_FS *, u_int, const char *, DOS_DE **); +static void cp_xdnm(u_char *, DOS_XDE *); +static void cp_sfn(u_char *, DOS_DE *); +static off_t fsize(DOS_FS *, DOS_DE *); +static int fatcnt(DOS_FS *, u_int); +static int fatget(DOS_FS *, u_int *); +static int fatend(u_int, u_int); +static int ioread(DOS_FS *, u_int, void *, size_t); +static int ioget(struct open_file *, daddr_t, void *, size_t); + +static int +dos_read_fatblk(DOS_FS *fs, struct open_file *fd, u_int blknum) +{ + int err; + size_t io_size; + daddr_t offset_in_fat, max_offset_in_fat; + + offset_in_fat = ((daddr_t)blknum) * FATBLKSZ; + max_offset_in_fat = secbyt(fs->spf); + io_size = FATBLKSZ; + if (offset_in_fat > max_offset_in_fat) + offset_in_fat = max_offset_in_fat; + if (offset_in_fat + io_size > max_offset_in_fat) + io_size = ((size_t)(max_offset_in_fat - offset_in_fat)); + + if (io_size != 0) { + err = ioget(fd, fs->lsnfat + bytsec(offset_in_fat), + fs->fatbuf, io_size); + if (err != 0) { + fs->fatbuf_blknum = ((u_int)(-1)); + return (err); + } + } + if (io_size < FATBLKSZ) + memset(fs->fatbuf + io_size, 0, FATBLKSZ - io_size); + + fs->fatbuf_blknum = blknum; + return (0); +} + +/* + * Mount DOS filesystem + */ +static int +dos_mount(DOS_FS *fs, struct open_file *fd) +{ + int err; + u_char *buf; + + bzero(fs, sizeof(DOS_FS)); + fs->fd = fd; + + if ((buf = malloc(secbyt(1))) == NULL) + return (errno); + if ((err = ioget(fs->fd, 0, buf, secbyt(1))) || + (err = parsebs(fs, (DOS_BS *)buf))) { + free(buf); + return (err); + } + free(buf); + + if ((fs->fatbuf = malloc(FATBLKSZ)) == NULL) + return (errno); + err = dos_read_fatblk(fs, fd, 0); + if (err != 0) { + free(fs->fatbuf); + return (err); + } + + fs->root = dot[0]; + fs->root.name[0] = ' '; + if (fs->fatsz == 32) { + fs->root.clus[0] = fs->rdcl & 0xff; + fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; + fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; + fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; + } + return (0); +} + +/* + * Unmount mounted filesystem + */ +static int +dos_unmount(DOS_FS *fs) +{ + if (fs->links) + return (EBUSY); + free(fs->fatbuf); + free(fs); + return (0); +} + +/* + * Open DOS file + */ +static int +dos_open(const char *path, struct open_file *fd) +{ + DOS_DE *de; + DOS_FILE *f; + DOS_FS *fs; + u_int size, clus; + int err; + + /* Allocate mount structure, associate with open */ + if ((fs = malloc(sizeof(DOS_FS))) == NULL) + return (errno); + if ((err = dos_mount(fs, fd))) { + free(fs); + return (err); + } + + if ((err = namede(fs, path, &de))) { + dos_unmount(fs); + return (err); + } + + clus = stclus(fs->fatsz, de); + size = cv4(de->size); + + if ((!(de->attr & FA_DIR) && (!clus != !size)) || + ((de->attr & FA_DIR) && size) || + (clus && !okclus(fs, clus))) { + dos_unmount(fs); + return (EINVAL); + } + if ((f = malloc(sizeof(DOS_FILE))) == NULL) { + err = errno; + dos_unmount(fs); + return (err); + } + bzero(f, sizeof(DOS_FILE)); + f->fs = fs; + fs->links++; + f->de = *de; + fd->f_fsdata = (void *)f; + return (0); +} + +/* + * Read from file + */ +static int +dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) +{ + off_t size; + u_int nb, off, clus, c, cnt, n; + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + int err = 0; + + /* + * as ioget() can be called *a lot*, use twiddle here. + * also 4 seems to be good value not to slow loading down too much: + * with 270MB file (~540k ioget() calls, twiddle can easily waste 4-5sec. + */ + twiddle(4); + nb = (u_int)nbyte; + if ((size = fsize(f->fs, &f->de)) == -1) + return (EINVAL); + if (nb > (n = size - f->offset)) + nb = n; + off = f->offset; + if ((clus = stclus(f->fs->fatsz, &f->de))) + off &= f->fs->bsize - 1; + c = f->c; + cnt = nb; + while (cnt) { + n = 0; + if (!c) { + if ((c = clus)) + n = bytblk(f->fs, f->offset); + } else if (!off) + n++; + while (n--) { + if ((err = fatget(f->fs, &c))) + goto out; + if (!okclus(f->fs, c)) { + err = EINVAL; + goto out; + } + } + if (!clus || (n = f->fs->bsize - off) > cnt) + n = cnt; + if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : + secbyt(f->fs->lsndir)) + off, buf, n))) + goto out; + f->offset += n; + f->c = c; + off = 0; + buf = (char *)buf + n; + cnt -= n; + } + out: + if (resid) + *resid = nbyte - nb + cnt; + return (err); +} + +/* + * Reposition within file + */ +static off_t +dos_seek(struct open_file *fd, off_t offset, int whence) +{ + off_t off; + u_int size; + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + + size = cv4(f->de.size); + switch (whence) { + case SEEK_SET: + off = 0; + break; + case SEEK_CUR: + off = f->offset; + break; + case SEEK_END: + off = size; + break; + default: + errno = EINVAL; + return (-1); + } + off += offset; + if (off < 0 || off > size) { + errno = EINVAL; + return (-1); + } + f->offset = (u_int)off; + f->c = 0; + return (off); +} + +/* + * Close open file + */ +static int +dos_close(struct open_file *fd) +{ + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + DOS_FS *fs = f->fs; + + f->fs->links--; + free(f); + dos_unmount(fs); + return (0); +} + +/* + * Return some stat information on a file. + */ +static int +dos_stat(struct open_file *fd, struct stat *sb) +{ + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + + /* only important stuff */ + sb->st_mode = f->de.attr & FA_DIR ? S_IFDIR | 0555 : S_IFREG | 0444; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + if ((sb->st_size = fsize(f->fs, &f->de)) == -1) + return (EINVAL); + return (0); +} + +static int +dos_checksum(char *name, char *ext) +{ + int x, i; + char buf[11]; + + bcopy(name, buf, 8); + bcopy(ext, buf+8, 3); + x = 0; + for (i = 0; i < 11; i++) { + x = ((x & 1) << 7) | (x >> 1); + x += buf[i]; + x &= 0xff; + } + return (x); +} + +static int +dos_readdir(struct open_file *fd, struct dirent *d) +{ + /* DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; */ + u_char fn[261]; + DOS_DIR dd; + size_t res; + u_int chk, x, xdn; + int err; + + x = chk = 0; + while (1) { + xdn = x; + x = 0; + err = dos_read(fd, &dd, sizeof(dd), &res); + if (err) + return (err); + if (res == sizeof(dd)) + return (ENOENT); + if (dd.de.name[0] == 0) + return (ENOENT); + + /* Skip deleted entries */ + if (dd.de.name[0] == 0xe5) + continue; + + /* Check if directory entry is volume label */ + if (dd.de.attr & FA_LABEL) { + /* + * If volume label set, check if the current entry is + * extended entry (FA_XDE) for long file names. + */ + if ((dd.de.attr & FA_MASK) == FA_XDE) { + /* + * Read through all following extended entries + * to get the long file name. 0x40 marks the + * last entry containing part of long file name. + */ + if (dd.xde.seq & 0x40) + chk = dd.xde.chk; + else if (dd.xde.seq != xdn - 1 || dd.xde.chk != chk) + continue; + x = dd.xde.seq & ~0x40; + if (x < 1 || x > 20) { + x = 0; + continue; + } + cp_xdnm(fn, &dd.xde); + } else { + /* skip only volume label entries */ + continue; + } + } else { + if (xdn == 1) { + x = dos_checksum(dd.de.name, dd.de.ext); + if (x == chk) + break; + } else { + cp_sfn(fn, &dd.de); + break; + } + x = 0; + } + } + + d->d_fileno = (dd.de.clus[1] << 8) + dd.de.clus[0]; + d->d_reclen = sizeof(*d); + d->d_type = (dd.de.attr & FA_DIR) ? DT_DIR : DT_REG; + memcpy(d->d_name, fn, sizeof(d->d_name)); + return (0); +} + +/* + * Parse DOS boot sector + */ +static int +parsebs(DOS_FS *fs, DOS_BS *bs) +{ + u_int sc; + + if ((bs->jmp[0] != 0x69 && + bs->jmp[0] != 0xe9 && + (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) || + bs->bpb.media < 0xf0) + return (EINVAL); + if (cv2(bs->bpb.secsiz) != SECSIZ) + return (EINVAL); + if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1)) + return (EINVAL); + fs->bsize = secbyt(fs->spc); + fs->bshift = ffs(fs->bsize) - 1; + if ((fs->spf = cv2(bs->bpb.spf))) { + if (bs->bpb.fats != 2) + return (EINVAL); + if (!(fs->dirents = cv2(bs->bpb.dirents))) + return (EINVAL); + } else { + if (!(fs->spf = cv4(bs->bpb.lspf))) + return (EINVAL); + if (!bs->bpb.fats || bs->bpb.fats > 16) + return (EINVAL); + if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS) + return (EINVAL); + } + if (!(fs->lsnfat = cv2(bs->bpb.ressec))) + return (EINVAL); + fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats; + fs->lsndta = fs->lsndir + entsec(fs->dirents); + if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs))) + return (EINVAL); + if (fs->lsndta > sc) + return (EINVAL); + if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS) + return (EINVAL); + fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32; + sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1; + if (fs->xclus > sc) + fs->xclus = sc; + return (0); +} + +/* + * Return directory entry from path + */ +static int +namede(DOS_FS *fs, const char *path, DOS_DE **dep) +{ + char name[256]; + DOS_DE *de; + char *s; + size_t n; + int err; + + err = 0; + de = &fs->root; + while (*path) { + while (*path == '/') + path++; + if (*path == '\0') + break; + if (!(s = strchr(path, '/'))) + s = strchr(path, 0); + if ((n = s - path) > 255) + return (ENAMETOOLONG); + memcpy(name, path, n); + name[n] = 0; + path = s; + if (!(de->attr & FA_DIR)) + return (ENOTDIR); + if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de))) + return (err); + } + *dep = de; + return (0); +} + +/* + * Lookup path segment + */ +static int +lookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep) +{ + static DOS_DIR dir[DEPSEC]; + u_char lfn[261]; + u_char sfn[13]; + u_int nsec, lsec, xdn, chk, sec, ent, x; + int err, ok; + + if (!clus) + for (ent = 0; ent < 2; ent++) + if (!strcasecmp(name, dotstr[ent])) { + *dep = dot + ent; + return (0); + } + if (!clus && fs->fatsz == 32) + clus = fs->rdcl; + nsec = !clus ? entsec(fs->dirents) : fs->spc; + lsec = 0; + xdn = chk = 0; + for (;;) { + if (!clus && !lsec) + lsec = fs->lsndir; + else if (okclus(fs, clus)) + lsec = blklsn(fs, clus); + else + return (EINVAL); + for (sec = 0; sec < nsec; sec++) { + if ((err = ioget(fs->fd, lsec + sec, dir, secbyt(1)))) + return (err); + for (ent = 0; ent < DEPSEC; ent++) { + if (!*dir[ent].de.name) + return (ENOENT); + if (*dir[ent].de.name != 0xe5) { + if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { + x = dir[ent].xde.seq; + if (x & 0x40 || (x + 1 == xdn && + dir[ent].xde.chk == chk)) { + if (x & 0x40) { + chk = dir[ent].xde.chk; + x &= ~0x40; + } + if (x >= 1 && x <= 20) { + cp_xdnm(lfn, &dir[ent].xde); + xdn = x; + continue; + } + } + } else if (!(dir[ent].de.attr & FA_LABEL)) { + if ((ok = xdn == 1)) { + x = dos_checksum(dir[ent].de.name, dir[ent].de.ext); + ok = chk == x && + !strcasecmp(name, (const char *)lfn); + } + if (!ok) { + cp_sfn(sfn, &dir[ent].de); + ok = !strcasecmp(name, (const char *)sfn); + } + if (ok) { + *dep = &dir[ent].de; + return (0); + } + } + } + xdn = 0; + } + } + if (!clus) + break; + if ((err = fatget(fs, &clus))) + return (err); + if (fatend(fs->fatsz, clus)) + break; + } + return (ENOENT); +} + +/* + * Copy name from extended directory entry + */ +static void +cp_xdnm(u_char *lfn, DOS_XDE *xde) +{ + static struct { + u_int off; + u_int dim; + } ix[3] = { + {offsetof(DOS_XDE, name1), sizeof(xde->name1) / 2}, + {offsetof(DOS_XDE, name2), sizeof(xde->name2) / 2}, + {offsetof(DOS_XDE, name3), sizeof(xde->name3) / 2} + }; + u_char *p; + u_int n, x, c; + + lfn += 13 * ((xde->seq & ~0x40) - 1); + for (n = 0; n < 3; n++) + for (p = (u_char *)xde + ix[n].off, x = ix[n].dim; x; + p += 2, x--) { + if ((c = cv2(p)) && (c < 32 || c > 127)) + c = '?'; + if (!(*lfn++ = c)) + return; + } + if (xde->seq & 0x40) + *lfn = 0; +} + +/* + * Copy short filename + */ +static void +cp_sfn(u_char *sfn, DOS_DE *de) +{ + u_char *p; + int j, i; + + p = sfn; + if (*de->name != ' ') { + for (j = 7; de->name[j] == ' '; j--); + for (i = 0; i <= j; i++) + *p++ = de->name[i]; + if (*de->ext != ' ') { + *p++ = '.'; + for (j = 2; de->ext[j] == ' '; j--); + for (i = 0; i <= j; i++) + *p++ = de->ext[i]; + } + } + *p = 0; + if (*sfn == 5) + *sfn = 0xe5; +} + +/* + * Return size of file in bytes + */ +static off_t +fsize(DOS_FS *fs, DOS_DE *de) +{ + u_long size; + u_int c; + int n; + + if (!(size = cv4(de->size)) && de->attr & FA_DIR) { + if (!(c = cv2(de->clus))) + size = fs->dirents * sizeof(DOS_DE); + else { + if ((n = fatcnt(fs, c)) == -1) + return (n); + size = blkbyt(fs, n); + } + } + return (size); +} + +/* + * Count number of clusters in chain + */ +static int +fatcnt(DOS_FS *fs, u_int c) +{ + int n; + + for (n = 0; okclus(fs, c); n++) + if (fatget(fs, &c)) + return (-1); + return (fatend(fs->fatsz, c) ? n : -1); +} + +/* + * Get next cluster in cluster chain. Use in core fat cache unless + * the number of current 128K block in FAT has changed. + */ +static int +fatget(DOS_FS *fs, u_int *c) +{ + u_int val_in, val_out, offset, blknum, nbyte; + const u_char *p_entry; + int err; + + /* check input value to prevent overflow in fatoff() */ + val_in = *c; + if (val_in & 0xf0000000) + return (EINVAL); + + /* ensure that current 128K FAT block is cached */ + offset = fatoff(fs->fatsz, val_in); + nbyte = fs->fatsz != 32 ? 2 : 4; + if (offset + nbyte > secbyt(fs->spf)) + return (EINVAL); + blknum = offset / FATBLKSZ; + offset %= FATBLKSZ; + if (offset + nbyte > FATBLKSZ) + return (EINVAL); + if (blknum != fs->fatbuf_blknum) { + err = dos_read_fatblk(fs, fs->fd, blknum); + if (err != 0) + return (err); + } + p_entry = fs->fatbuf + offset; + + /* extract cluster number from FAT entry */ + switch (fs->fatsz) { + case 32: + val_out = cv4(p_entry); + val_out &= 0x0fffffff; + break; + case 16: + val_out = cv2(p_entry); + break; + case 12: + val_out = cv2(p_entry); + if (val_in & 1) + val_out >>= 4; + else + val_out &= 0xfff; + break; + default: + return (EINVAL); + } + *c = val_out; + return (0); +} + +/* + * Is cluster an end-of-chain marker? + */ +static int +fatend(u_int sz, u_int c) +{ + return (c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7)); +} + +/* + * Offset-based I/O primitive + */ +static int +ioread(DOS_FS *fs, u_int offset, void *buf, size_t nbyte) +{ + char *s; + u_int off, n; + int err; + u_char local_buf[SECSIZ]; + + s = buf; + if ((off = offset & (SECSIZ - 1))) { + offset -= off; + if ((n = SECSIZ - off) > nbyte) + n = nbyte; + if ((err = ioget(fs->fd, bytsec(offset), local_buf, sizeof(local_buf)))) + return (err); + memcpy(s, local_buf + off, n); + offset += SECSIZ; + s += n; + nbyte -= n; + } + n = nbyte & (SECSIZ - 1); + if (nbyte -= n) { + if ((err = ioget(fs->fd, bytsec(offset), s, nbyte))) + return (err); + offset += nbyte; + s += nbyte; + } + if (n) { + if ((err = ioget(fs->fd, bytsec(offset), local_buf, sizeof(local_buf)))) + return (err); + memcpy(s, local_buf, n); + } + return (0); +} + +/* + * Sector-based I/O primitive + */ +static int +ioget(struct open_file *fd, daddr_t lsec, void *buf, size_t size) +{ + size_t rsize; + int rv; + + /* Make sure we get full read or error. */ + rsize = 0; + rv = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, + size, buf, &rsize); + if ((rv == 0) && (size != rsize)) + rv = EIO; + return (rv); +} diff --git a/stand/libsa/dosfs.h b/stand/libsa/dosfs.h new file mode 100644 index 000000000000..5b11e0fc375a --- /dev/null +++ b/stand/libsa/dosfs.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1996, 1998 Robert Nordier + * 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 AUTHOR(S) ``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 AUTHOR(S) 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$ + */ + +#ifndef DOSIO_H +#define DOSIO_H + +/* + * DOS file attributes + */ + +#define FA_RDONLY 001 /* read-only */ +#define FA_HIDDEN 002 /* hidden file */ +#define FA_SYSTEM 004 /* system file */ +#define FA_LABEL 010 /* volume label */ +#define FA_DIR 020 /* directory */ +#define FA_ARCH 040 /* archive (file modified) */ +#define FA_XDE 017 /* extended directory entry */ +#define FA_MASK 077 /* all attributes */ + +/* + * Macros to convert DOS-format 16-bit and 32-bit quantities + */ + +#define cv2(p) ((u_int16_t)(p)[0] | \ + ((u_int16_t)(p)[1] << 010)) +#define cv4(p) ((u_int32_t)(p)[0] | \ + ((u_int32_t)(p)[1] << 010) | \ + ((u_int32_t)(p)[2] << 020) | \ + ((u_int32_t)(p)[3] << 030)) + +/* + * Directory, filesystem, and file structures. + */ + +typedef struct { + u_char x_case; /* case */ + u_char c_hsec; /* created: secs/100 */ + u_char c_time[2]; /* created: time */ + u_char c_date[2]; /* created: date */ + u_char a_date[2]; /* accessed: date */ + u_char h_clus[2]; /* clus[hi] */ +} DOS_DEX; + +typedef struct { + u_char name[8]; /* name */ + u_char ext[3]; /* extension */ + u_char attr; /* attributes */ + DOS_DEX dex; /* VFAT/FAT32 only */ + u_char time[2]; /* modified: time */ + u_char date[2]; /* modified: date */ + u_char clus[2]; /* starting cluster */ + u_char size[4]; /* size */ +} DOS_DE; + +typedef struct { + u_char seq; /* flags */ + u_char name1[5][2]; /* 1st name area */ + u_char attr; /* (see fat_de) */ + u_char res; /* reserved */ + u_char chk; /* checksum */ + u_char name2[6][2]; /* 2nd name area */ + u_char clus[2]; /* (see fat_de) */ + u_char name3[2][2]; /* 3rd name area */ +} DOS_XDE; + +typedef union { + DOS_DE de; /* standard directory entry */ + DOS_XDE xde; /* extended directory entry */ +} DOS_DIR; + +typedef struct { + struct open_file *fd; /* file descriptor */ + u_char *fatbuf; /* FAT cache buffer */ + u_int fatbuf_blknum; /* number of 128K block in FAT cache buffer */ + u_int links; /* active links to structure */ + u_int spc; /* sectors per cluster */ + u_int bsize; /* cluster size in bytes */ + u_int bshift; /* cluster conversion shift */ + u_int dirents; /* root directory entries */ + u_int spf; /* sectors per fat */ + u_int rdcl; /* root directory start cluster */ + u_int lsnfat; /* start of fat */ + u_int lsndir; /* start of root dir */ + u_int lsndta; /* start of data area */ + u_int fatsz; /* FAT entry size */ + u_int xclus; /* maximum cluster number */ + DOS_DE root; +} DOS_FS; + +typedef struct { + DOS_FS *fs; /* associated filesystem */ + DOS_DE de; /* directory entry */ + u_int offset; /* current offset */ + u_int c; /* last cluster read */ +} DOS_FILE; + +#endif /* !DOSIO_H */ diff --git a/stand/libsa/environment.c b/stand/libsa/environment.c new file mode 100644 index 000000000000..291e33004430 --- /dev/null +++ b/stand/libsa/environment.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1998 Michael Smith. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Manage an environment-like space in which string variables may be stored. + * Provide support for some method-like operations for setting/retrieving + * variables in order to allow some type strength. + */ + +#include "stand.h" + +#include <string.h> + +static void env_discard(struct env_var *ev); + +struct env_var *environ = NULL; + +/* + * Look up (name) and return it's env_var structure. + */ +struct env_var * +env_getenv(const char *name) +{ + struct env_var *ev; + + for (ev = environ; ev != NULL; ev = ev->ev_next) + if (!strcmp(ev->ev_name, name)) + break; + return(ev); +} + +/* + * Some notes: + * + * If the EV_VOLATILE flag is set, a copy of the variable is made. + * If EV_DYNAMIC is set, the variable has been allocated with + * malloc and ownership transferred to the environment. + * If (value) is NULL, the variable is set but has no value. + */ +int +env_setenv(const char *name, int flags, const void *value, + ev_sethook_t sethook, ev_unsethook_t unsethook) +{ + struct env_var *ev, *curr, *last; + + if ((ev = env_getenv(name)) != NULL) { + /* + * If there's a set hook, let it do the work (unless we are working + * for one already. + */ + if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK)) + return (ev->ev_sethook(ev, flags, value)); + + /* If there is data in the variable, discard it. */ + if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0) + free(ev->ev_value); + ev->ev_value = NULL; + ev->ev_flags &= ~EV_DYNAMIC; + + } else { + + /* + * New variable; create and sort into list + */ + ev = malloc(sizeof(struct env_var)); + ev->ev_name = strdup(name); + ev->ev_value = NULL; + ev->ev_flags = 0; + /* hooks can only be set when the variable is instantiated */ + ev->ev_sethook = sethook; + ev->ev_unsethook = unsethook; + + /* Sort into list */ + ev->ev_prev = NULL; + ev->ev_next = NULL; + /* Search for the record to insert before */ + for (last = NULL, curr = environ; + curr != NULL; + last = curr, curr = curr->ev_next) { + + if (strcmp(ev->ev_name, curr->ev_name) < 0) { + if (curr->ev_prev) { + curr->ev_prev->ev_next = ev; + } else { + environ = ev; + } + ev->ev_next = curr; + ev->ev_prev = curr->ev_prev; + curr->ev_prev = ev; + break; + } + } + if (curr == NULL) { + if (last == NULL) { + environ = ev; + } else { + last->ev_next = ev; + ev->ev_prev = last; + } + } + } + + /* If we have a new value, use it */ + if (flags & EV_VOLATILE) { + ev->ev_value = strdup(value); + ev->ev_flags |= EV_DYNAMIC; + } else { + ev->ev_value = (char *)value; + ev->ev_flags |= flags & EV_DYNAMIC; + } + + return(0); +} + +char * +getenv(const char *name) +{ + struct env_var *ev; + + /* Set but no value gives empty string */ + if ((ev = env_getenv(name)) != NULL) { + if (ev->ev_value != NULL) + return(ev->ev_value); + return(""); + } + return(NULL); +} + +int +setenv(const char *name, const char *value, int overwrite) +{ + /* No guarantees about state, always assume volatile */ + if (overwrite || (env_getenv(name) == NULL)) + return(env_setenv(name, EV_VOLATILE, value, NULL, NULL)); + return(0); +} + +int +putenv(const char *string) +{ + char *value, *copy; + int result; + + copy = strdup(string); + if ((value = strchr(copy, '=')) != NULL) + *(value++) = 0; + result = setenv(copy, value, 1); + free(copy); + return(result); +} + +int +unsetenv(const char *name) +{ + struct env_var *ev; + int err; + + err = 0; + if ((ev = env_getenv(name)) == NULL) { + err = ENOENT; + } else { + if (ev->ev_unsethook != NULL) + err = ev->ev_unsethook(ev); + if (err == 0) { + env_discard(ev); + } + } + return(err); +} + +static void +env_discard(struct env_var *ev) +{ + if (ev->ev_prev) + ev->ev_prev->ev_next = ev->ev_next; + if (ev->ev_next) + ev->ev_next->ev_prev = ev->ev_prev; + if (environ == ev) + environ = ev->ev_next; + free(ev->ev_name); + if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0) + free(ev->ev_value); + free(ev); +} + +int +env_noset(struct env_var *ev __unused, int flags __unused, + const void *value __unused) +{ + return(EPERM); +} + +int +env_nounset(struct env_var *ev __unused) +{ + return(EPERM); +} diff --git a/stand/libsa/ether.c b/stand/libsa/ether.c new file mode 100644 index 000000000000..3616777e7955 --- /dev/null +++ b/stand/libsa/ether.c @@ -0,0 +1,147 @@ +/* $NetBSD: ether.c,v 1.11 1997/07/07 15:52:50 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <string.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include "stand.h" +#include "net.h" +#include "netif.h" + +/* Caller must leave room for ethernet header in front!! */ +ssize_t +sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype) +{ + ssize_t n; + struct ether_header *eh; + +#ifdef ETHER_DEBUG + if (debug) + printf("sendether: called\n"); +#endif + + eh = (struct ether_header *)pkt - 1; + len += sizeof(*eh); + + MACPY(d->myea, eh->ether_shost); /* by byte */ + MACPY(dea, eh->ether_dhost); /* by byte */ + eh->ether_type = htons(etype); + + n = netif_put(d, eh, len); + if (n == -1 || n < sizeof(*eh)) + return (-1); + + n -= sizeof(*eh); + return (n); +} + +/* + * Get a packet of any Ethernet type, with our address or + * the broadcast address. Save the Ether type in etype. + * Unless there is an error, we pass the whole packet and the unencapsulated + * data. + */ +ssize_t +readether(struct iodesc *d, void **pkt, void **payload, time_t tleft, + uint16_t *etype) +{ + ssize_t n; + struct ether_header *eh; + void *ptr; + +#ifdef ETHER_DEBUG + if (debug) + printf("readether: called\n"); +#endif + + ptr = NULL; + n = netif_get(d, &ptr, tleft); + if (n == -1 || n < sizeof(*eh)) { + free(ptr); + return (-1); + } + + eh = (struct ether_header *)((uintptr_t)ptr + ETHER_ALIGN); + /* Validate Ethernet address. */ + if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && + bcmp(bcea, eh->ether_dhost, 6) != 0) { +#ifdef ETHER_DEBUG + if (debug) + printf("readether: not ours (ea=%s)\n", + ether_sprintf(eh->ether_dhost)); +#endif + free(ptr); + return (-1); + } + + *pkt = ptr; + *payload = (void *)((uintptr_t)eh + sizeof(*eh)); + *etype = ntohs(eh->ether_type); + + n -= sizeof(*eh); + return (n); +} + +/* + * Convert Ethernet address to printable (loggable) representation. + */ +static char digits[] = "0123456789abcdef"; +char * +ether_sprintf(u_char *ap) +{ + int i; + static char etherbuf[18]; + char *cp = etherbuf; + + for (i = 0; i < 6; i++) { + *cp++ = digits[*ap >> 4]; + *cp++ = digits[*ap++ & 0xf]; + *cp++ = ':'; + } + *--cp = 0; + return (etherbuf); +} diff --git a/stand/libsa/ext2fs.c b/stand/libsa/ext2fs.c new file mode 100644 index 000000000000..348fdecc5c11 --- /dev/null +++ b/stand/libsa/ext2fs.c @@ -0,0 +1,908 @@ +/*- + * Copyright (c) 1999,2000 Jonathan Lemon <jlemon@freebsd.org> + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include "stand.h" +#include "string.h" + +static int ext2fs_open(const char *path, struct open_file *f); +static int ext2fs_close(struct open_file *f); +static int ext2fs_read(struct open_file *f, void *buf, + size_t size, size_t *resid); +static off_t ext2fs_seek(struct open_file *f, off_t offset, int where); +static int ext2fs_stat(struct open_file *f, struct stat *sb); +static int ext2fs_readdir(struct open_file *f, struct dirent *d); + +static int dtmap[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, + DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; +#define EXTFTODT(x) (x) > sizeof(dtmap) / sizeof(dtmap[0]) ? \ + DT_UNKNOWN : dtmap[x] + +struct fs_ops ext2fs_fsops = { + "ext2fs", + ext2fs_open, + ext2fs_close, + ext2fs_read, + null_write, + ext2fs_seek, + ext2fs_stat, + ext2fs_readdir +}; + +#define EXT2_SBSIZE 1024 +#define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */ +#define EXT2_MAGIC 0xef53 +#define EXT2_ROOTINO 2 + +#define EXT2_REV0 0 /* original revision of ext2 */ +#define EXT2_R0_ISIZE 128 /* inode size */ +#define EXT2_R0_FIRSTINO 11 /* first inode */ + +#define EXT2_MINBSHIFT 10 /* mininum block shift */ +#define EXT2_MINFSHIFT 10 /* mininum frag shift */ + +#define EXT2_NDADDR 12 /* # of direct blocks */ +#define EXT2_NIADDR 3 /* # of indirect blocks */ + +/* + * file system block to disk address + */ +#define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb) + +/* + * inode to block group offset + * inode to block group + * inode to disk address + * inode to block offset + */ +#define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg) +#define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg) +#define ino_to_db(fs, bg, ino) \ + fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \ + ino_to_bgo(fs, ino) / (fs)->fs_ipb)) +#define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb) + +#define nindir(fs) \ + ((fs)->fs_bsize / sizeof(u_int32_t)) +#define lblkno(fs, loc) /* loc / bsize */ \ + ((loc) >> (fs)->fs_bshift) +#define smalllblktosize(fs, blk) /* blk * bsize */ \ + ((blk) << (fs)->fs_bshift) +#define blkoff(fs, loc) /* loc % bsize */ \ + ((loc) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* roundup(size, fsize) */ \ + (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask) +#define dblksize(fs, dip, lbn) \ + (((lbn) >= EXT2_NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) + +/* + * superblock describing ext2fs + */ +struct ext2fs_disk { + u_int32_t fd_inodes; /* # of inodes */ + u_int32_t fd_blocks; /* # of blocks */ + u_int32_t fd_resblk; /* # of reserved blocks */ + u_int32_t fd_freeblk; /* # of free blocks */ + u_int32_t fd_freeino; /* # of free inodes */ + u_int32_t fd_firstblk; /* first data block */ + u_int32_t fd_bsize; /* block size */ + u_int32_t fd_fsize; /* frag size */ + u_int32_t fd_bpg; /* blocks per group */ + u_int32_t fd_fpg; /* frags per group */ + u_int32_t fd_ipg; /* inodes per group */ + u_int32_t fd_mtime; /* mount time */ + u_int32_t fd_wtime; /* write time */ + u_int16_t fd_mount; /* # of mounts */ + int16_t fd_maxmount; /* max # of mounts */ + u_int16_t fd_magic; /* magic number */ + u_int16_t fd_state; /* state */ + u_int16_t fd_eflag; /* error flags */ + u_int16_t fd_mnrrev; /* minor revision */ + u_int32_t fd_lastchk; /* last check */ + u_int32_t fd_chkintvl; /* maximum check interval */ + u_int32_t fd_os; /* os */ + u_int32_t fd_revision; /* revision */ + u_int16_t fd_uid; /* uid for reserved blocks */ + u_int16_t fd_gid; /* gid for reserved blocks */ + + u_int32_t fd_firstino; /* first non-reserved inode */ + u_int16_t fd_isize; /* inode size */ + u_int16_t fd_nblkgrp; /* block group # of superblock */ + u_int32_t fd_fcompat; /* compatible features */ + u_int32_t fd_fincompat; /* incompatible features */ + u_int32_t fd_frocompat; /* read-only compatibilties */ + u_int8_t fd_uuid[16]; /* volume uuid */ + char fd_volname[16]; /* volume name */ + char fd_fsmnt[64]; /* name last mounted on */ + u_int32_t fd_bitmap; /* compression bitmap */ + + u_int8_t fd_nblkpa; /* # of blocks to preallocate */ + u_int8_t fd_ndblkpa; /* # of dir blocks to preallocate */ +}; + +struct ext2fs_core { + int fc_bsize; /* block size */ + int fc_bshift; /* block shift amount */ + int fc_bmask; /* block mask */ + int fc_fsize; /* frag size */ + int fc_fshift; /* frag shift amount */ + int fc_fmask; /* frag mask */ + int fc_isize; /* inode size */ + int fc_imask; /* inode mask */ + int fc_firstino; /* first non-reserved inode */ + int fc_ipb; /* inodes per block */ + int fc_fsbtodb; /* fsb to ds shift */ +}; + +struct ext2fs { + struct ext2fs_disk fs_fd; + char fs_pad[EXT2_SBSIZE - sizeof(struct ext2fs_disk)]; + struct ext2fs_core fs_fc; + +#define fs_magic fs_fd.fd_magic +#define fs_revision fs_fd.fd_revision +#define fs_blocks fs_fd.fd_blocks +#define fs_firstblk fs_fd.fd_firstblk +#define fs_bpg fs_fd.fd_bpg +#define fs_ipg fs_fd.fd_ipg + +#define fs_bsize fs_fc.fc_bsize +#define fs_bshift fs_fc.fc_bshift +#define fs_bmask fs_fc.fc_bmask +#define fs_fsize fs_fc.fc_fsize +#define fs_fshift fs_fc.fc_fshift +#define fs_fmask fs_fc.fc_fmask +#define fs_isize fs_fc.fc_isize +#define fs_imask fs_fc.fc_imask +#define fs_firstino fs_fc.fc_firstino +#define fs_ipb fs_fc.fc_ipb +#define fs_fsbtodb fs_fc.fc_fsbtodb +}; + +struct ext2blkgrp { + u_int32_t bg_blkmap; /* block bitmap */ + u_int32_t bg_inomap; /* inode bitmap */ + u_int32_t bg_inotbl; /* inode table */ + u_int16_t bg_nfblk; /* # of free blocks */ + u_int16_t bg_nfino; /* # of free inodes */ + u_int16_t bg_ndirs; /* # of dirs */ + char bg_pad[14]; +}; + +struct ext2dinode { + u_int16_t di_mode; /* mode */ + u_int16_t di_uid; /* uid */ + u_int32_t di_size; /* byte size */ + u_int32_t di_atime; /* access time */ + u_int32_t di_ctime; /* creation time */ + u_int32_t di_mtime; /* modification time */ + u_int32_t di_dtime; /* deletion time */ + u_int16_t di_gid; /* gid */ + u_int16_t di_nlink; /* link count */ + u_int32_t di_nblk; /* block count */ + u_int32_t di_flags; /* file flags */ + + u_int32_t di_osdep1; /* os dependent stuff */ + + u_int32_t di_db[EXT2_NDADDR]; /* direct blocks */ + u_int32_t di_ib[EXT2_NIADDR]; /* indirect blocks */ + u_int32_t di_version; /* version */ + u_int32_t di_facl; /* file acl */ + u_int32_t di_dacl; /* dir acl */ + u_int32_t di_faddr; /* fragment addr */ + + u_int8_t di_frag; /* fragment number */ + u_int8_t di_fsize; /* fragment size */ + + char di_pad[10]; + +#define di_shortlink di_db +}; + +#define EXT2_MAXNAMLEN 255 + +struct ext2dirent { + u_int32_t d_ino; /* inode */ + u_int16_t d_reclen; /* directory entry length */ + u_int8_t d_namlen; /* name length */ + u_int8_t d_type; /* file type */ + char d_name[EXT2_MAXNAMLEN]; +}; + +struct file { + off_t f_seekp; /* seek pointer */ + struct ext2fs *f_fs; /* pointer to super-block */ + struct ext2blkgrp *f_bg; /* pointer to blkgrp map */ + struct ext2dinode f_di; /* copy of on-disk inode */ + int f_nindir[EXT2_NIADDR]; /* number of blocks mapped by + indirect block at level i */ + char *f_blk[EXT2_NIADDR]; /* buffer for indirect block + at level i */ + size_t f_blksize[EXT2_NIADDR]; /* size of buffer */ + daddr_t f_blkno[EXT2_NIADDR]; /* disk address of block in + buffer */ + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ + daddr_t f_buf_blkno; /* block number of data block */ +}; + +/* forward decls */ +static int read_inode(ino_t inumber, struct open_file *f); +static int block_map(struct open_file *f, daddr_t file_block, + daddr_t *disk_block_p); +static int buf_read_file(struct open_file *f, char **buf_p, + size_t *size_p); +static int search_directory(char *name, struct open_file *f, + ino_t *inumber_p); + +/* + * Open a file. + */ +static int +ext2fs_open(const char *upath, struct open_file *f) +{ + struct file *fp; + struct ext2fs *fs; + size_t buf_size; + ino_t inumber, parent_inumber; + int i, len, groups, bg_per_blk, blkgrps, mult; + int nlinks = 0; + int error = 0; + char *cp, *ncp, *path = NULL, *buf = NULL; + char namebuf[MAXPATHLEN+1]; + char c; + + /* allocate file system specific data structure */ + fp = malloc(sizeof(struct file)); + if (fp == NULL) + return (ENOMEM); + bzero(fp, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = (struct ext2fs *)malloc(sizeof(*fs)); + fp->f_fs = fs; + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size); + if (error) + goto out; + + if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) { + error = EINVAL; + goto out; + } + + /* + * compute in-core values for the superblock + */ + fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize; + fs->fs_bsize = 1 << fs->fs_bshift; + fs->fs_bmask = fs->fs_bsize - 1; + + fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize; + fs->fs_fsize = 1 << fs->fs_fshift; + fs->fs_fmask = fs->fs_fsize - 1; + + if (fs->fs_revision == EXT2_REV0) { + fs->fs_isize = EXT2_R0_ISIZE; + fs->fs_firstino = EXT2_R0_FIRSTINO; + } else { + fs->fs_isize = fs->fs_fd.fd_isize; + fs->fs_firstino = fs->fs_fd.fd_firstino; + } + fs->fs_imask = fs->fs_isize - 1; + fs->fs_ipb = fs->fs_bsize / fs->fs_isize; + fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1; + + /* + * we have to load in the "group descriptors" here + */ + groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg); + bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp); + blkgrps = howmany(groups, bg_per_blk); + len = blkgrps * fs->fs_bsize; + + fp->f_bg = malloc(len); + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len, + (char *)fp->f_bg, &buf_size); + if (error) + goto out; + + /* + * XXX + * validation of values? (blocksize, descriptors, etc?) + */ + + /* + * Calculate indirect block levels. + */ + mult = 1; + for (i = 0; i < EXT2_NIADDR; i++) { + mult *= nindir(fs); + fp->f_nindir[i] = mult; + } + + inumber = EXT2_ROOTINO; + if ((error = read_inode(inumber, f)) != 0) + goto out; + + path = strdup(upath); + if (path == NULL) { + error = ENOMEM; + goto out; + } + cp = path; + while (*cp) { + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if (! S_ISDIR(fp->f_di.di_mode)) { + error = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > EXT2_MAXNAMLEN) { + error = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ + parent_inumber = inumber; + error = search_directory(ncp, f, &inumber); + *cp = c; + if (error) + goto out; + + /* + * Open next component. + */ + if ((error = read_inode(inumber, f)) != 0) + goto out; + + /* + * Check for symbolic link. + */ + if (S_ISLNK(fp->f_di.di_mode)) { + int link_len = fp->f_di.di_size; + int len; + + len = strlen(cp); + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + error = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + if (fp->f_di.di_nblk == 0) { + bcopy(fp->f_di.di_shortlink, + namebuf, link_len); + } else { + /* + * Read file for symbolic link + */ + struct ext2fs *fs = fp->f_fs; + daddr_t disk_block; + size_t buf_size; + + if (! buf) + buf = malloc(fs->fs_bsize); + error = block_map(f, (daddr_t)0, &disk_block); + if (error) + goto out; + + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsb_to_db(fs, disk_block), + fs->fs_bsize, buf, &buf_size); + if (error) + goto out; + + bcopy((char *)buf, namebuf, link_len); + } + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = (ino_t)EXT2_ROOTINO; + + if ((error = read_inode(inumber, f)) != 0) + goto out; + } + } + + /* + * Found terminal component. + */ + error = 0; + fp->f_seekp = 0; +out: + if (buf) + free(buf); + if (path) + free(path); + if (error) { + if (fp->f_buf) + free(fp->f_buf); + free(fp->f_fs); + free(fp); + } + return (error); +} + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(ino_t inumber, struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2fs *fs = fp->f_fs; + struct ext2dinode *dp; + char *buf; + size_t rsize; + int level, error = 0; + + /* + * Read inode and save it. + */ + buf = malloc(fs->fs_bsize); + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize); + if (error) + goto out; + if (rsize != fs->fs_bsize) { + error = EIO; + goto out; + } + + dp = (struct ext2dinode *)buf; + fp->f_di = dp[ino_to_bo(fs, inumber)]; + + /* clear out old buffers */ + for (level = 0; level < EXT2_NIADDR; level++) + fp->f_blkno[level] = -1; + fp->f_buf_blkno = -1; + fp->f_seekp = 0; + +out: + free(buf); + return (error); +} + +/* + * Given an offset in a file, find the disk block number that + * contains that block. + */ +static int +block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2fs *fs = fp->f_fs; + daddr_t ind_block_num; + int32_t *ind_p; + int idx, level; + int error; + + /* + * Index structure of an inode: + * + * di_db[0..EXT2_NDADDR-1] hold block numbers for blocks + * 0..EXT2_NDADDR-1 + * + * di_ib[0] index block 0 is the single indirect block + * holds block numbers for blocks + * EXT2_NDADDR .. EXT2_NDADDR + NINDIR(fs)-1 + * + * di_ib[1] index block 1 is the double indirect block + * holds block numbers for INDEX blocks for blocks + * EXT2_NDADDR + NINDIR(fs) .. + * EXT2_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 + * + * di_ib[2] index block 2 is the triple indirect block + * holds block numbers for double-indirect + * blocks for blocks + * EXT2_NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. + * EXT2_NDADDR + NINDIR(fs) + NINDIR(fs)**2 + * + NINDIR(fs)**3 - 1 + */ + + if (file_block < EXT2_NDADDR) { + /* Direct block. */ + *disk_block_p = fp->f_di.di_db[file_block]; + return (0); + } + + file_block -= EXT2_NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < EXT2_NIADDR; level++) { + if (file_block < fp->f_nindir[level]) + break; + file_block -= fp->f_nindir[level]; + } + if (level == EXT2_NIADDR) { + /* Block number too high */ + return (EFBIG); + } + + ind_block_num = fp->f_di.di_ib[level]; + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *disk_block_p = 0; /* missing */ + return (0); + } + + if (fp->f_blkno[level] != ind_block_num) { + if (fp->f_blk[level] == (char *)0) + fp->f_blk[level] = + malloc(fs->fs_bsize); + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize, + fp->f_blk[level], &fp->f_blksize[level]); + if (error) + return (error); + if (fp->f_blksize[level] != fs->fs_bsize) + return (EIO); + fp->f_blkno[level] = ind_block_num; + } + + ind_p = (int32_t *)fp->f_blk[level]; + + if (level > 0) { + idx = file_block / fp->f_nindir[level - 1]; + file_block %= fp->f_nindir[level - 1]; + } else { + idx = file_block; + } + ind_block_num = ind_p[idx]; + } + + *disk_block_p = ind_block_num; + + return (0); +} + +/* + * Read a portion of a file into an internal buffer. Return + * the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2fs *fs = fp->f_fs; + long off; + daddr_t file_block; + daddr_t disk_block; + size_t block_size; + int error = 0; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = dblksize(fs, &fp->f_di, file_block); + + if (file_block != fp->f_buf_blkno) { + error = block_map(f, file_block, &disk_block); + if (error) + goto done; + + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + if (disk_block == 0) { + bzero(fp->f_buf, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(4); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsb_to_db(fs, disk_block), block_size, + fp->f_buf, &fp->f_buf_size); + if (error) + goto done; + } + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > fp->f_di.di_size - fp->f_seekp) + *size_p = fp->f_di.di_size - fp->f_seekp; +done: + return (error); +} + +/* + * Search a directory for a name and return its + * i_number. + */ +static int +search_directory(char *name, struct open_file *f, ino_t *inumber_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2dirent *dp, *edp; + char *buf; + size_t buf_size; + int namlen, length; + int error; + + length = strlen(name); + fp->f_seekp = 0; + while (fp->f_seekp < fp->f_di.di_size) { + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + dp = (struct ext2dirent *)buf; + edp = (struct ext2dirent *)(buf + buf_size); + while (dp < edp) { + if (dp->d_ino == (ino_t)0) + goto next; + namlen = dp->d_namlen; + if (namlen == length && + strncmp(name, dp->d_name, length) == 0) { + /* found entry */ + *inumber_p = dp->d_ino; + return (0); + } + next: + dp = (struct ext2dirent *)((char *)dp + dp->d_reclen); + } + fp->f_seekp += buf_size; + } + return (ENOENT); +} + +static int +ext2fs_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + int level; + + f->f_fsdata = (void *)0; + if (fp == (struct file *)0) + return (0); + + for (level = 0; level < EXT2_NIADDR; level++) { + if (fp->f_blk[level]) + free(fp->f_blk[level]); + } + if (fp->f_buf) + free(fp->f_buf); + if (fp->f_bg) + free(fp->f_bg); + free(fp->f_fs); + free(fp); + return (0); +} + +static int +ext2fs_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize, buf_size; + char *buf; + int error = 0; + + while (size != 0) { + if (fp->f_seekp >= fp->f_di.di_size) + break; + + error = buf_read_file(f, &buf, &buf_size); + if (error) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr = (char *)addr + csize; + size -= csize; + } + if (resid) + *resid = size; + return (error); +} + +static off_t +ext2fs_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = fp->f_di.di_size - offset; + break; + default: + errno = EINVAL; + return (-1); + } + return (fp->f_seekp); +} + +static int +ext2fs_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = fp->f_di.di_mode; + sb->st_uid = fp->f_di.di_uid; + sb->st_gid = fp->f_di.di_gid; + sb->st_size = fp->f_di.di_size; + return (0); +} + +static int +ext2fs_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2dirent *ed; + char *buf; + size_t buf_size; + int error; + + /* + * assume that a directory entry will not be split across blocks + */ +again: + if (fp->f_seekp >= fp->f_di.di_size) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + ed = (struct ext2dirent *)buf; + fp->f_seekp += ed->d_reclen; + if (ed->d_ino == (ino_t)0) + goto again; + d->d_type = EXTFTODT(ed->d_type); + strncpy(d->d_name, ed->d_name, ed->d_namlen); + d->d_name[ed->d_namlen] = '\0'; + return (0); +} diff --git a/stand/libsa/fstat.c b/stand/libsa/fstat.c new file mode 100644 index 000000000000..cb2df8cbf0ac --- /dev/null +++ b/stand/libsa/fstat.c @@ -0,0 +1,61 @@ +/* $NetBSD: fstat.c,v 1.1 1996/01/13 22:25:38 leo Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)stat.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +int +fstat(fd, sb) + int fd; + struct stat *sb; +{ + struct open_file *f = &files[fd]; + + if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + + /* operation not defined on raw devices */ + if (f->f_flags & F_RAW) { + errno = EOPNOTSUPP; + return (-1); + } + + errno = (f->f_ops->fo_stat)(f, sb); + if (errno) + return (-1); + return (0); +} diff --git a/stand/libsa/getopt.c b/stand/libsa/getopt.c new file mode 100644 index 000000000000..ead2ee56267c --- /dev/null +++ b/stand/libsa/getopt.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include "stand.h" +#include <string.h> + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const *nargv, const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)printf("illegal option -- %c\n", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)printf("option requires an argument -- %c\n", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/stand/libsa/gets.c b/stand/libsa/gets.c new file mode 100644 index 000000000000..9172ffc1328f --- /dev/null +++ b/stand/libsa/gets.c @@ -0,0 +1,112 @@ +/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)gets.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +/* gets() with constrained input length */ + +void +ngets(char *buf, int n) +{ + int c; + char *lp; + + for (lp = buf;;) + switch (c = getchar() & 0177) { + case '\n': + case '\r': + *lp = '\0'; + putchar('\n'); + return; + case '\b': + case '\177': + if (lp > buf) { + lp--; + putchar('\b'); + putchar(' '); + putchar('\b'); + } + break; + case 'r'&037: { + char *p; + + putchar('\n'); + for (p = buf; p < lp; ++p) + putchar(*p); + break; + } + case 'u'&037: + case 'w'&037: + lp = buf; + putchar('\n'); + break; + default: + if ((n < 1) || ((lp - buf) < n - 1)) { + *lp++ = c; + putchar(c); + } + } + /*NOTREACHED*/ +} + +int +fgetstr(char *buf, int size, int fd) +{ + char c; + int err, len; + + size--; /* leave space for terminator */ + len = 0; + while (size != 0) { + err = read(fd, &c, sizeof(c)); + if (err < 0) /* read error */ + return(-1); + if (err == 0) { /* EOF */ + if (len == 0) + return(-1); /* nothing to read */ + break; + } + if ((c == '\r') || /* line terminators */ + (c == '\n')) + break; + *buf++ = c; /* keep char */ + size--; + len++; + } + *buf = 0; + return(len); +} + diff --git a/stand/libsa/globals.c b/stand/libsa/globals.c new file mode 100644 index 000000000000..8fb56cf23e6b --- /dev/null +++ b/stand/libsa/globals.c @@ -0,0 +1,38 @@ +/* $NetBSD: globals.c,v 1.3 1995/09/18 21:19:27 pk Exp $ */ + +/* + * globals.c: + * + * global variables should be separate, so nothing else + * must be included extraneously. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include "stand.h" +#include "net.h" + +u_char bcea[6] = BA; /* broadcast ethernet address */ + +char rootpath[FNAME_SIZE] = "/"; /* root mount path */ +char bootfile[FNAME_SIZE]; /* bootp says to boot this */ +char hostname[FNAME_SIZE]; /* our hostname */ +int hostnamelen; +char domainname[FNAME_SIZE]; /* our DNS domain */ +int domainnamelen; +int netproto = NET_NONE; /* Network prototol */ +char ifname[IFNAME_SIZE]; /* name of interface (e.g. "le0") */ +struct in_addr myip; /* my ip address */ +struct in_addr nameip; /* DNS server ip address */ +struct in_addr rootip; /* root ip address */ +struct in_addr swapip; /* swap ip address */ +struct in_addr gateip; /* gateway ip address */ +n_long netmask = 0xffffff00; /* subnet or net mask */ +u_int intf_mtu; /* interface mtu from bootp/dhcp */ +int errno; /* our old friend */ + diff --git a/stand/libsa/gpt.c b/stand/libsa/gpt.c new file mode 100644 index 000000000000..7ab3fc6d04e0 --- /dev/null +++ b/stand/libsa/gpt.c @@ -0,0 +1,379 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/gpt.h> + +#ifndef LITTLE_ENDIAN +#error gpt.c works only for little endian architectures +#endif + +#include "crc32.h" +#include "drv.h" +#include "util.h" +#include "gpt.h" + +static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr; +static uint64_t hdr_primary_lba, hdr_backup_lba; +static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS]; +static struct gpt_ent *gpttable; +static int curent, bootonce; + +/* + * Buffer below 64kB passed on gptread(), which can hold at least + * one sector of data (512 bytes). + */ +static char *secbuf; + +static void +gptupdate(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + struct gpt_ent *table) +{ + int entries_per_sec, firstent; + daddr_t slba; + + /* + * We need to update the following for both primary and backup GPT: + * 1. Sector on disk that contains current partition. + * 2. Partition table checksum. + * 3. Header checksum. + * 4. Header on disk. + */ + + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + slba = curent / entries_per_sec; + firstent = slba * entries_per_sec; + bcopy(&table[firstent], secbuf, DEV_BSIZE); + slba += hdr->hdr_lba_table; + if (drvwrite(dskp, secbuf, slba, 1)) { + printf("%s: unable to update %s GPT partition table\n", + BOOTPROG, which); + return; + } + hdr->hdr_crc_table = crc32(table, hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = 0; + hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcopy(hdr, secbuf, hdr->hdr_size); + if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) { + printf("%s: unable to update %s GPT header\n", BOOTPROG, which); + return; + } +} + +int +gptfind(const uuid_t *uuid, struct dsk *dskp, int part) +{ + struct gpt_ent *ent; + int firsttry; + + if (part >= 0) { + if (part == 0 || part > gpthdr->hdr_entries) { + printf("%s: invalid partition index\n", BOOTPROG); + return (-1); + } + ent = &gpttable[part - 1]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) { + printf("%s: specified partition is not UFS\n", + BOOTPROG); + return (-1); + } + curent = part - 1; + goto found; + } + + firsttry = (curent == -1); + curent++; + if (curent >= gpthdr->hdr_entries) { + curent = gpthdr->hdr_entries; + return (-1); + } + if (bootonce) { + /* + * First look for partition with both GPT_ENT_ATTR_BOOTME and + * GPT_ENT_ATTR_BOOTONCE flags. + */ + for (; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTONCE)) + continue; + /* Ok, found one. */ + goto found; + } + bootonce = 0; + curent = 0; + } + for (; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) + continue; + if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) + continue; + /* Ok, found one. */ + goto found; + } + if (firsttry) { + /* + * No partition with BOOTME flag was found, try to boot from + * first UFS partition. + */ + for (curent = 0; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) + continue; + /* Ok, found one. */ + goto found; + } + } + return (-1); +found: + dskp->part = curent + 1; + ent = &gpttable[curent]; + dskp->start = ent->ent_lba_start; + if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) { + /* + * Clear BOOTME, but leave BOOTONCE set before trying to + * boot from this partition. + */ + if (hdr_primary_lba > 0) { + table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; + gptupdate("primary", dskp, &hdr_primary, table_primary); + } + if (hdr_backup_lba > 0) { + table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; + gptupdate("backup", dskp, &hdr_backup, table_backup); + } + } + return (0); +} + +static int +gptread_hdr(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + uint64_t hdrlba) +{ + uint32_t crc; + + if (drvread(dskp, secbuf, hdrlba, 1)) { + printf("%s: unable to read %s GPT header\n", BOOTPROG, which); + return (-1); + } + bcopy(secbuf, hdr, sizeof(*hdr)); + if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 || + hdr->hdr_lba_self != hdrlba || hdr->hdr_revision < 0x00010000 || + hdr->hdr_entsz < sizeof(struct gpt_ent) || + hdr->hdr_entries > MAXTBLENTS || DEV_BSIZE % hdr->hdr_entsz != 0) { + printf("%s: invalid %s GPT header\n", BOOTPROG, which); + return (-1); + } + crc = hdr->hdr_crc_self; + hdr->hdr_crc_self = 0; + if (crc32(hdr, hdr->hdr_size) != crc) { + printf("%s: %s GPT header checksum mismatch\n", BOOTPROG, + which); + return (-1); + } + hdr->hdr_crc_self = crc; + return (0); +} + +void +gptbootfailed(struct dsk *dskp) +{ + + if (!(gpttable[curent].ent_attr & GPT_ENT_ATTR_BOOTONCE)) + return; + + if (hdr_primary_lba > 0) { + table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + table_primary[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + gptupdate("primary", dskp, &hdr_primary, table_primary); + } + if (hdr_backup_lba > 0) { + table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + table_backup[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + gptupdate("backup", dskp, &hdr_backup, table_backup); + } +} + +static void +gptbootconv(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + struct gpt_ent *table) +{ + struct gpt_ent *ent; + daddr_t slba; + int table_updated, sector_updated; + int entries_per_sec, nent, part; + + table_updated = 0; + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + for (nent = 0, slba = hdr->hdr_lba_table; + slba < hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; + slba++, nent += entries_per_sec) { + sector_updated = 0; + for (part = 0; part < entries_per_sec; part++) { + ent = &table[nent + part]; + if ((ent->ent_attr & (GPT_ENT_ATTR_BOOTME | + GPT_ENT_ATTR_BOOTONCE | + GPT_ENT_ATTR_BOOTFAILED)) != + GPT_ENT_ATTR_BOOTONCE) { + continue; + } + ent->ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + ent->ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + table_updated = 1; + sector_updated = 1; + } + if (!sector_updated) + continue; + bcopy(&table[nent], secbuf, DEV_BSIZE); + if (drvwrite(dskp, secbuf, slba, 1)) { + printf("%s: unable to update %s GPT partition table\n", + BOOTPROG, which); + } + } + if (!table_updated) + return; + hdr->hdr_crc_table = crc32(table, hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = 0; + hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcopy(hdr, secbuf, hdr->hdr_size); + if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) + printf("%s: unable to update %s GPT header\n", BOOTPROG, which); +} + +static int +gptread_table(const char *which, const uuid_t *uuid, struct dsk *dskp, + struct gpt_hdr *hdr, struct gpt_ent *table) +{ + struct gpt_ent *ent; + int entries_per_sec; + int part, nent; + daddr_t slba; + + if (hdr->hdr_entries == 0) + return (0); + + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + slba = hdr->hdr_lba_table; + nent = 0; + for (;;) { + if (drvread(dskp, secbuf, slba, 1)) { + printf("%s: unable to read %s GPT partition table\n", + BOOTPROG, which); + return (-1); + } + ent = (struct gpt_ent *)secbuf; + for (part = 0; part < entries_per_sec; part++, ent++) { + bcopy(ent, &table[nent], sizeof(table[nent])); + if (++nent >= hdr->hdr_entries) + break; + } + if (nent >= hdr->hdr_entries) + break; + slba++; + } + if (crc32(table, nent * hdr->hdr_entsz) != hdr->hdr_crc_table) { + printf("%s: %s GPT table checksum mismatch\n", BOOTPROG, which); + return (-1); + } + return (0); +} + +int +gptread(const uuid_t *uuid, struct dsk *dskp, char *buf) +{ + uint64_t altlba; + + /* + * Read and verify both GPT headers: primary and backup. + */ + + secbuf = buf; + hdr_primary_lba = hdr_backup_lba = 0; + curent = -1; + bootonce = 1; + dskp->start = 0; + + if (gptread_hdr("primary", dskp, &hdr_primary, 1) == 0 && + gptread_table("primary", uuid, dskp, &hdr_primary, + table_primary) == 0) { + hdr_primary_lba = hdr_primary.hdr_lba_self; + gpthdr = &hdr_primary; + gpttable = table_primary; + } + + if (hdr_primary_lba > 0) { + /* + * If primary header is valid, we can get backup + * header location from there. + */ + altlba = hdr_primary.hdr_lba_alt; + } else { + altlba = drvsize(dskp); + if (altlba > 0) + altlba--; + } + if (altlba == 0) + printf("%s: unable to locate backup GPT header\n", BOOTPROG); + else if (gptread_hdr("backup", dskp, &hdr_backup, altlba) == 0 && + gptread_table("backup", uuid, dskp, &hdr_backup, + table_backup) == 0) { + hdr_backup_lba = hdr_backup.hdr_lba_self; + if (hdr_primary_lba == 0) { + gpthdr = &hdr_backup; + gpttable = table_backup; + printf("%s: using backup GPT\n", BOOTPROG); + } + } + + /* + * Convert all BOOTONCE without BOOTME flags into BOOTFAILED. + * BOOTONCE without BOOTME means that we tried to boot from it, + * but failed after leaving gptboot and machine was rebooted. + * We don't want to leave partitions marked as BOOTONCE only, + * because when we boot successfully start-up scripts should + * find at most one partition with only BOOTONCE flag and this + * will mean that we booted from that partition. + */ + if (hdr_primary_lba != 0) + gptbootconv("primary", dskp, &hdr_primary, table_primary); + if (hdr_backup_lba != 0) + gptbootconv("backup", dskp, &hdr_backup, table_backup); + + if (hdr_primary_lba == 0 && hdr_backup_lba == 0) + return (-1); + return (0); +} diff --git a/stand/libsa/gpt.h b/stand/libsa/gpt.h new file mode 100644 index 000000000000..9d48564b5ada --- /dev/null +++ b/stand/libsa/gpt.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * 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$ + */ + +#ifndef _GPT_H_ +#define _GPT_H_ + +#include <uuid.h> +#include <drv.h> + +#define MAXTBLENTS 128 + +int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf); +int gptfind(const uuid_t *uuid, struct dsk *dskp, int part); +void gptbootfailed(struct dsk *dskp); + +#endif /* !_GPT_H_ */ diff --git a/stand/libsa/gzipfs.c b/stand/libsa/gzipfs.c new file mode 100644 index 000000000000..6057c2835fec --- /dev/null +++ b/stand/libsa/gzipfs.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 1998 Michael Smith. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +#include <sys/stat.h> +#include <string.h> +#include <zlib.h> + +#define Z_BUFSIZE 2048 /* XXX larger? */ + +struct z_file +{ + int zf_rawfd; + off_t zf_dataoffset; + z_stream zf_zstream; + char zf_buf[Z_BUFSIZE]; + int zf_endseen; +}; + +static int zf_fill(struct z_file *z); +static int zf_open(const char *path, struct open_file *f); +static int zf_close(struct open_file *f); +static int zf_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t zf_seek(struct open_file *f, off_t offset, int where); +static int zf_stat(struct open_file *f, struct stat *sb); + +struct fs_ops gzipfs_fsops = { + "zip", + zf_open, + zf_close, + zf_read, + null_write, + zf_seek, + zf_stat, + null_readdir +}; + +static int +zf_fill(struct z_file *zf) +{ + int result; + int req; + + req = Z_BUFSIZE - zf->zf_zstream.avail_in; + result = 0; + + /* If we need more */ + if (req > 0) { + /* move old data to bottom of buffer */ + if (req < Z_BUFSIZE) + bcopy(zf->zf_buf + req, zf->zf_buf, Z_BUFSIZE - req); + + /* read to fill buffer and update availibility data */ + result = read(zf->zf_rawfd, zf->zf_buf + zf->zf_zstream.avail_in, req); + zf->zf_zstream.next_in = zf->zf_buf; + if (result >= 0) + zf->zf_zstream.avail_in += result; + } + return(result); +} + +/* + * Adapted from get_byte/check_header in libz + * + * Returns 0 if the header is OK, nonzero if not. + */ +static int +get_byte(struct z_file *zf, off_t *curoffp) +{ + if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) + return(-1); + zf->zf_zstream.avail_in--; + ++*curoffp; + return(*(zf->zf_zstream.next_in)++); +} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +static int +check_header(struct z_file *zf) +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + zf->zf_dataoffset = 0; + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(zf, &zf->zf_dataoffset); + if (c != gz_magic[len]) { + return(1); + } + } + method = get_byte(zf, &zf->zf_dataoffset); + flags = get_byte(zf, &zf->zf_dataoffset); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + return(1); + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(zf, &zf->zf_dataoffset); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(zf, &zf->zf_dataoffset); + len += ((uInt)get_byte(zf, &zf->zf_dataoffset))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(zf, &zf->zf_dataoffset) != -1) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) c = get_byte(zf, &zf->zf_dataoffset); + } + /* if there's data left, we're in business */ + return((c == -1) ? 1 : 0); +} + +static int +zf_open(const char *fname, struct open_file *f) +{ + static char *zfname; + int rawfd; + struct z_file *zf; + char *cp; + int error; + struct stat sb; + + /* Have to be in "just read it" mode */ + if (f->f_flags != F_READ) + return(EPERM); + + /* If the name already ends in .gz or .bz2, ignore it */ + if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz") + || !strcmp(cp, ".bz2") || !strcmp(cp, ".split"))) + return(ENOENT); + + /* Construct new name */ + zfname = malloc(strlen(fname) + 4); + if (zfname == NULL) + return(ENOMEM); + sprintf(zfname, "%s.gz", fname); + + /* Try to open the compressed datafile */ + rawfd = open(zfname, O_RDONLY); + free(zfname); + if (rawfd == -1) + return(ENOENT); + + if (fstat(rawfd, &sb) < 0) { + printf("zf_open: stat failed\n"); + close(rawfd); + return(ENOENT); + } + if (!S_ISREG(sb.st_mode)) { + printf("zf_open: not a file\n"); + close(rawfd); + return(EISDIR); /* best guess */ + } + + /* Allocate a z_file structure, populate it */ + zf = malloc(sizeof(struct z_file)); + if (zf == NULL) + return(ENOMEM); + bzero(zf, sizeof(struct z_file)); + zf->zf_rawfd = rawfd; + + /* Verify that the file is gzipped */ + if (check_header(zf)) { + close(zf->zf_rawfd); + free(zf); + return(EFTYPE); + } + + /* Initialise the inflation engine */ + if ((error = inflateInit2(&(zf->zf_zstream), -15)) != Z_OK) { + printf("zf_open: inflateInit returned %d : %s\n", error, zf->zf_zstream.msg); + close(zf->zf_rawfd); + free(zf); + return(EIO); + } + + /* Looks OK, we'll take it */ + f->f_fsdata = zf; + return(0); +} + +static int +zf_close(struct open_file *f) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + + inflateEnd(&(zf->zf_zstream)); + close(zf->zf_rawfd); + free(zf); + return(0); +} + +static int +zf_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + int error; + + zf->zf_zstream.next_out = buf; /* where and how much */ + zf->zf_zstream.avail_out = size; + + while (zf->zf_zstream.avail_out && zf->zf_endseen == 0) { + if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { + printf("zf_read: fill error\n"); + return(EIO); + } + if (zf->zf_zstream.avail_in == 0) { /* oops, unexpected EOF */ + printf("zf_read: unexpected EOF\n"); + if (zf->zf_zstream.avail_out == size) + return(EIO); + break; + } + + error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); /* decompression pass */ + if (error == Z_STREAM_END) { /* EOF, all done */ + zf->zf_endseen = 1; + break; + } + if (error != Z_OK) { /* argh, decompression error */ + printf("inflate: %s\n", zf->zf_zstream.msg); + return(EIO); + } + } + if (resid != NULL) + *resid = zf->zf_zstream.avail_out; + return(0); +} + +static int +zf_rewind(struct open_file *f) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + + if (lseek(zf->zf_rawfd, zf->zf_dataoffset, SEEK_SET) == -1) + return(-1); + zf->zf_zstream.avail_in = 0; + zf->zf_zstream.next_in = NULL; + zf->zf_endseen = 0; + (void)inflateReset(&zf->zf_zstream); + + return(0); +} + +static off_t +zf_seek(struct open_file *f, off_t offset, int where) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + off_t target; + char discard[16]; + + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = offset + zf->zf_zstream.total_out; + break; + default: + errno = EINVAL; + return(-1); + } + + /* rewind if required */ + if (target < zf->zf_zstream.total_out && zf_rewind(f) != 0) + return(-1); + + /* skip forwards if required */ + while (target > zf->zf_zstream.total_out) { + errno = zf_read(f, discard, min(sizeof(discard), + target - zf->zf_zstream.total_out), NULL); + if (errno) + return(-1); + } + /* This is where we are (be honest if we overshot) */ + return(zf->zf_zstream.total_out); +} + + +static int +zf_stat(struct open_file *f, struct stat *sb) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + int result; + + /* stat as normal, but indicate that size is unknown */ + if ((result = fstat(zf->zf_rawfd, sb)) == 0) + sb->st_size = -1; + return(result); +} + + + diff --git a/stand/libsa/i386/_setjmp.S b/stand/libsa/i386/_setjmp.S new file mode 100644 index 000000000000..95b0ea8037f5 --- /dev/null +++ b/stand/libsa/i386/_setjmp.S @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_RCS) && !defined(lint) + .text + .asciz "$FreeBSD$" +#endif /* LIBC_RCS and not lint */ + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from the last call to + * _setjmp(a) + * by restoring registers from the environment 'a'. + * The previous signal state is NOT restored. + */ + +#include <machine/asm.h> + +ENTRY(_setjmp) + movl 4(%esp),%eax + movl 0(%esp),%edx + movl %edx, 0(%eax) /* rta */ + movl %ebx, 4(%eax) + movl %esp, 8(%eax) + movl %ebp,12(%eax) + movl %esi,16(%eax) + movl %edi,20(%eax) + xorl %eax,%eax + ret +END(_setjmp) + +ENTRY(_longjmp) + movl 4(%esp),%edx + movl 8(%esp),%eax + movl 0(%edx),%ecx + movl 4(%edx),%ebx + movl 8(%edx),%esp + movl 12(%edx),%ebp + movl 16(%edx),%esi + movl 20(%edx),%edi + testl %eax,%eax + jnz 1f + incl %eax +1: movl %ecx,0(%esp) + ret +END(_longjmp) diff --git a/stand/libsa/in_cksum.c b/stand/libsa/in_cksum.c new file mode 100644 index 000000000000..97782152d71d --- /dev/null +++ b/stand/libsa/in_cksum.c @@ -0,0 +1,94 @@ +/* $NetBSD: in_cksum.c,v 1.6 2000/03/31 19:55:09 castor Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: in_cksum.c,v 1.1 92/09/11 01:15:55 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <machine/endian.h> + +#include "stand.h" + +/* + * Checksum routine for Internet Protocol family headers. + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * In particular, it should not be this one. + */ +int +in_cksum(p, len) + void *p; + int len; +{ + int sum = 0, oddbyte = 0, v = 0; + u_char *cp = p; + + /* we assume < 2^16 bytes being summed */ + while (len > 0) { + if (oddbyte) { + sum += v + *cp++; + len--; + } + if (((long)cp & 1) == 0) { + while ((len -= 2) >= 0) { + sum += *(u_short *)cp; + cp += 2; + } + } else { + while ((len -= 2) >= 0) { +#if BYTE_ORDER == BIG_ENDIAN + sum += *cp++ << 8; + sum += *cp++; +#else + sum += *cp++; + sum += *cp++ << 8; +#endif + } + } + if ((oddbyte = len & 1) != 0) +#if BYTE_ORDER == BIG_ENDIAN + v = *cp << 8; +#else + v = *cp; +#endif + } + if (oddbyte) + sum += v; + sum = (sum >> 16) + (sum & 0xffff); /* add in accumulated carries */ + sum += sum >> 16; /* add potential last carry */ + return (0xffff & ~sum); +} diff --git a/stand/libsa/inet_ntoa.c b/stand/libsa/inet_ntoa.c new file mode 100644 index 000000000000..f675a0ff7736 --- /dev/null +++ b/stand/libsa/inet_ntoa.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "stand.h" + +/* + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +char * +inet_ntoa(in) + struct in_addr in; +{ + static const char fmt[] = "%u.%u.%u.%u"; + static char ret[sizeof "255.255.255.255"]; + unsigned char *src = (unsigned char *) ∈ + + sprintf(ret, fmt, src[0], src[1], src[2], src[3]); + return (ret); +} + +/* + * Weak aliases for applications that use certain private entry points, + * and fail to include <arpa/inet.h>. + */ +#undef inet_ntoa +__weak_reference(__inet_ntoa, inet_ntoa); diff --git a/stand/libsa/ioctl.c b/stand/libsa/ioctl.c new file mode 100644 index 000000000000..807b308e5e50 --- /dev/null +++ b/stand/libsa/ioctl.c @@ -0,0 +1,88 @@ +/* $NetBSD: ioctl.c,v 1.4 1994/10/30 21:48:24 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)ioctl.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +int +ioctl(fd, cmd, arg) + int fd; + u_long cmd; + char *arg; +{ + struct open_file *f = &files[fd]; + + if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + if (f->f_flags & F_RAW) { + errno = (f->f_dev->dv_ioctl)(f, cmd, arg); + if (errno) + return (-1); + return (0); + } + errno = EIO; + return (-1); +} diff --git a/stand/libsa/iodesc.h b/stand/libsa/iodesc.h new file mode 100644 index 000000000000..37ae044af9d9 --- /dev/null +++ b/stand/libsa/iodesc.h @@ -0,0 +1,52 @@ +/* $NetBSD: iodesc.h,v 1.4 1995/09/23 03:31:50 gwr Exp $ */ + +/* + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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$ + */ + +#ifndef __SYS_LIBNETBOOT_IODESC_H +#define __SYS_LIBNETBOOT_IODESC_H + +struct iodesc { + struct in_addr destip; /* dest. ip addr, net order */ + struct in_addr myip; /* local ip addr, net order */ + u_short destport; /* dest. port, net order */ + u_short myport; /* local port, net order */ + u_long xid; /* transaction identification */ + u_char myea[6]; /* my ethernet address */ + struct netif *io_netif; +}; + +#endif /* __SYS_LIBNETBOOT_IODESC_H */ diff --git a/stand/libsa/ip.c b/stand/libsa/ip.c new file mode 100644 index 000000000000..f2293b3cd3f9 --- /dev/null +++ b/stand/libsa/ip.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/* + * The send and receive functions were originally implemented in udp.c and + * moved here. Also it is likely some more cleanup can be done, especially + * once we will implement the support for tcp. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/queue.h> + +#include <string.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> + +#include <netinet/in_pcb.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include "stand.h" +#include "net.h" + +typedef STAILQ_HEAD(ipqueue, ip_queue) ip_queue_t; +struct ip_queue { + void *ipq_pkt; + struct ip *ipq_hdr; + STAILQ_ENTRY(ip_queue) ipq_next; +}; + +/* + * Fragment re-assembly queue. + */ +struct ip_reasm { + struct in_addr ip_src; + struct in_addr ip_dst; + uint16_t ip_id; + uint8_t ip_proto; + uint8_t ip_ttl; + size_t ip_total_size; + ip_queue_t ip_queue; + void *ip_pkt; + struct ip *ip_hdr; + STAILQ_ENTRY(ip_reasm) ip_next; +}; + +STAILQ_HEAD(ire_list, ip_reasm) ire_list = STAILQ_HEAD_INITIALIZER(ire_list); + +/* Caller must leave room for ethernet and ip headers in front!! */ +ssize_t +sendip(struct iodesc *d, void *pkt, size_t len, uint8_t proto) +{ + ssize_t cc; + struct ip *ip; + u_char *ea; + +#ifdef NET_DEBUG + if (debug) { + printf("sendip: proto: %x d=%p called.\n", proto, (void *)d); + if (d) { + printf("saddr: %s:%d", + inet_ntoa(d->myip), ntohs(d->myport)); + printf(" daddr: %s:%d\n", + inet_ntoa(d->destip), ntohs(d->destport)); + } + } +#endif + + ip = (struct ip *)pkt - 1; + len += sizeof(*ip); + + bzero(ip, sizeof(*ip)); + + ip->ip_v = IPVERSION; /* half-char */ + ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ + ip->ip_len = htons(len); + ip->ip_p = proto; /* char */ + ip->ip_ttl = IPDEFTTL; /* char */ + ip->ip_src = d->myip; + ip->ip_dst = d->destip; + ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ + + if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || + netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) + ea = arpwhohas(d, ip->ip_dst); + else + ea = arpwhohas(d, gateip); + + cc = sendether(d, ip, len, ea, ETHERTYPE_IP); + if (cc == -1) + return (-1); + if (cc != len) + panic("sendip: bad write (%zd != %zd)", cc, len); + return (cc - sizeof(*ip)); +} + +static void +ip_reasm_free(struct ip_reasm *ipr) +{ + struct ip_queue *ipq; + + while ((ipq = STAILQ_FIRST(&ipr->ip_queue)) != NULL) { + STAILQ_REMOVE_HEAD(&ipr->ip_queue, ipq_next); + free(ipq->ipq_pkt); + free(ipq); + } + free(ipr->ip_pkt); + free(ipr); +} + +static int +ip_reasm_add(struct ip_reasm *ipr, void *pkt, struct ip *ip) +{ + struct ip_queue *ipq, *prev, *p; + + if ((ipq = calloc(1, sizeof (*ipq))) == NULL) + return (1); + + ipq->ipq_pkt = pkt; + ipq->ipq_hdr = ip; + + prev = NULL; + STAILQ_FOREACH(p, &ipr->ip_queue, ipq_next) { + if ((ntohs(p->ipq_hdr->ip_off) & IP_OFFMASK) < + (ntohs(ip->ip_off) & IP_OFFMASK)) { + prev = p; + continue; + } + if (prev == NULL) + break; + + STAILQ_INSERT_AFTER(&ipr->ip_queue, prev, ipq, ipq_next); + return (0); + } + STAILQ_INSERT_HEAD(&ipr->ip_queue, ipq, ipq_next); + return (0); +} + +/* + * Receive a IP packet and validate it is for us. + */ +static ssize_t +readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, + uint8_t proto) +{ + ssize_t n; + size_t hlen; + struct ether_header *eh; + struct ip *ip; + struct udphdr *uh; + uint16_t etype; /* host order */ + char *ptr; + struct ip_reasm *ipr; + struct ip_queue *ipq, *last; + +#ifdef NET_DEBUG + if (debug) + printf("readip: called\n"); +#endif + + ip = NULL; + ptr = NULL; + n = readether(d, (void **)&ptr, (void **)&ip, tleft, &etype); + if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) { + free(ptr); + return (-1); + } + + /* Ethernet address checks now in readether() */ + + /* Need to respond to ARP requests. */ + if (etype == ETHERTYPE_ARP) { + struct arphdr *ah = (void *)ip; + if (ah->ar_op == htons(ARPOP_REQUEST)) { + /* Send ARP reply */ + arp_reply(d, ah); + } + free(ptr); + errno = EAGAIN; /* Call me again. */ + return (-1); + } + + if (etype != ETHERTYPE_IP) { +#ifdef NET_DEBUG + if (debug) + printf("readip: not IP. ether_type=%x\n", etype); +#endif + free(ptr); + return (-1); + } + + /* Check ip header */ + if (ip->ip_v != IPVERSION || /* half char */ + ip->ip_p != proto) { +#ifdef NET_DEBUG + if (debug) { + printf("readip: IP version or proto. ip_v=%d ip_p=%d\n", + ip->ip_v, ip->ip_p); + } +#endif + free(ptr); + return (-1); + } + + hlen = ip->ip_hl << 2; + if (hlen < sizeof(*ip) || + in_cksum(ip, hlen) != 0) { +#ifdef NET_DEBUG + if (debug) + printf("readip: short hdr or bad cksum.\n"); +#endif + free(ptr); + return (-1); + } + if (n < ntohs(ip->ip_len)) { +#ifdef NET_DEBUG + if (debug) + printf("readip: bad length %d < %d.\n", + (int)n, ntohs(ip->ip_len)); +#endif + free(ptr); + return (-1); + } + if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { +#ifdef NET_DEBUG + if (debug) { + printf("readip: bad saddr %s != ", inet_ntoa(d->myip)); + printf("%s\n", inet_ntoa(ip->ip_dst)); + } +#endif + free(ptr); + return (-1); + } + + /* Unfragmented packet. */ + if ((ntohs(ip->ip_off) & IP_MF) == 0 && + (ntohs(ip->ip_off) & IP_OFFMASK) == 0) { + uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip)); + /* If there were ip options, make them go away */ + if (hlen != sizeof(*ip)) { + bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); + ip->ip_len = htons(sizeof(*ip)); + n -= hlen - sizeof(*ip); + } + + n = (n > (ntohs(ip->ip_len) - sizeof(*ip))) ? + ntohs(ip->ip_len) - sizeof(*ip) : n; + *pkt = ptr; + *payload = (void *)((uintptr_t)ip + sizeof(*ip)); + return (n); + } + + STAILQ_FOREACH(ipr, &ire_list, ip_next) { + if (ipr->ip_src.s_addr == ip->ip_src.s_addr && + ipr->ip_dst.s_addr == ip->ip_dst.s_addr && + ipr->ip_id == ip->ip_id && + ipr->ip_proto == ip->ip_p) + break; + } + + /* Allocate new reassembly entry */ + if (ipr == NULL) { + if ((ipr = calloc(1, sizeof (*ipr))) == NULL) { + free(ptr); + return (-1); + } + + ipr->ip_src = ip->ip_src; + ipr->ip_dst = ip->ip_dst; + ipr->ip_id = ip->ip_id; + ipr->ip_proto = ip->ip_p; + ipr->ip_ttl = MAXTTL; + STAILQ_INIT(&ipr->ip_queue); + STAILQ_INSERT_TAIL(&ire_list, ipr, ip_next); + } + + if (ip_reasm_add(ipr, ptr, ip) != 0) { + STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); + free(ipr); + free(ptr); + return (-1); + } + + if ((ntohs(ip->ip_off) & IP_MF) == 0) { + ipr->ip_total_size = (8 * (ntohs(ip->ip_off) & IP_OFFMASK)); + ipr->ip_total_size += n + sizeof (*ip); + ipr->ip_total_size += sizeof (struct ether_header); + + ipr->ip_pkt = malloc(ipr->ip_total_size + 2); + if (ipr->ip_pkt == NULL) { + STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); + ip_reasm_free(ipr); + return (-1); + } + } + + /* + * If we do not have re-assembly buffer ipr->ip_pkt, we are still + * missing fragments, so just restart the read. + */ + if (ipr->ip_pkt == NULL) { + errno = EAGAIN; + return (-1); + } + + /* + * Walk the packet list in reassembly queue, if we got all the + * fragments, build the packet. + */ + n = 0; + last = NULL; + STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { + if ((ntohs(ipq->ipq_hdr->ip_off) & IP_OFFMASK) != n / 8) { + STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); + ip_reasm_free(ipr); + return (-1); + } + + n += ntohs(ipq->ipq_hdr->ip_len) - (ipq->ipq_hdr->ip_hl << 2); + last = ipq; + } + if ((ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0) { + errno = EAGAIN; + return (-1); + } + + ipq = STAILQ_FIRST(&ipr->ip_queue); + /* Fabricate ethernet header */ + eh = (struct ether_header *)((uintptr_t)ipr->ip_pkt + 2); + bcopy((void *)((uintptr_t)ipq->ipq_pkt + 2), eh, sizeof (*eh)); + + /* Fabricate IP header */ + ipr->ip_hdr = (struct ip *)((uintptr_t)eh + sizeof (*eh)); + bcopy(ipq->ipq_hdr, ipr->ip_hdr, sizeof (*ipr->ip_hdr)); + ipr->ip_hdr->ip_hl = sizeof (*ipr->ip_hdr) >> 2; + ipr->ip_hdr->ip_len = htons(n); + ipr->ip_hdr->ip_sum = 0; + ipr->ip_hdr->ip_sum = in_cksum(ipr->ip_hdr, sizeof (*ipr->ip_hdr)); + + n = 0; + ptr = (char *)((uintptr_t)ipr->ip_hdr + sizeof (*ipr->ip_hdr)); + STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { + char *data; + size_t len; + + hlen = ipq->ipq_hdr->ip_hl << 2; + len = ntohs(ipq->ipq_hdr->ip_len) - hlen; + data = (char *)((uintptr_t)ipq->ipq_hdr + hlen); + + bcopy(data, ptr + n, len); + n += len; + } + + *pkt = ipr->ip_pkt; + ipr->ip_pkt = NULL; /* Avoid free from ip_reasm_free() */ + *payload = ptr; + + /* Clean up the reassembly list */ + while ((ipr = STAILQ_FIRST(&ire_list)) != NULL) { + STAILQ_REMOVE_HEAD(&ire_list, ip_next); + ip_reasm_free(ipr); + } + return (n); +} + +/* + * Receive a IP packet. + */ +ssize_t +readip(struct iodesc *d, void **pkt, void **payload, time_t tleft, + uint8_t proto) +{ + time_t t; + ssize_t ret = -1; + + t = getsecs(); + while ((getsecs() - t) < tleft) { + errno = 0; + ret = readipv4(d, pkt, payload, tleft, proto); + if (errno != EAGAIN) + break; + } + return (ret); +} diff --git a/stand/libsa/libstand.3 b/stand/libsa/libstand.3 new file mode 100644 index 000000000000..42289c1bce41 --- /dev/null +++ b/stand/libsa/libstand.3 @@ -0,0 +1,676 @@ +.\" Copyright (c) Michael Smith +.\" 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 AUTHOR 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 AUTHOR 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 August 6, 2004 +.Dt LIBSTAND 3 +.Os +.Sh NAME +.Nm libstand +.Nd support library for standalone executables +.Sh SYNOPSIS +.In stand.h +.Sh DESCRIPTION +The +.Nm +library provides a set of supporting functions for standalone +applications, mimicking where possible the standard +.Bx +programming +environment. +The following sections group these functions by kind. +Unless specifically described here, see the corresponding section 3 +manpages for the given functions. +.Sh STRING FUNCTIONS +String functions are available as documented in +.Xr string 3 +and +.Xr bstring 3 . +.Sh MEMORY ALLOCATION +.Bl -hang -width 10n +.It Xo +.Ft "void *" +.Fn malloc "size_t size" +.Xc +.Pp +Allocate +.Fa size +bytes of memory from the heap using a best-fit algorithm. +.It Xo +.Ft void +.Fn free "void *ptr" +.Xc +.Pp +Free the allocated object at +.Fa ptr . +.It Xo +.Ft void +.Fn setheap "void *start" "void *limit" +.Xc +.Pp +Initialise the heap. +This function must be called before calling +.Fn alloc +for the first time. +The region between +.Fa start +and +.Fa limit +will be used for the heap; attempting to allocate beyond this will result +in a panic. +.It Xo +.Ft "char *" +.Fn sbrk "int junk" +.Xc +.Pp +Provides the behaviour of +.Fn sbrk 0 , +i.e., returns the highest point that the heap has reached. +This value can +be used during testing to determine the actual heap usage. +The +.Fa junk +argument is ignored. +.El +.Sh ENVIRONMENT +A set of functions are provided for manipulating a flat variable space similar +to the traditional shell-supported environment. +Major enhancements are support +for set/unset hook functions. +.Bl -hang -width 10n +.It Xo +.Ft "char *" +.Fn getenv "const char *name" +.Xc +.It Xo +.Ft int +.Fn setenv "const char *name" "const char *value" "int overwrite" +.Xc +.It Xo +.Ft int +.Fn putenv "const char *string" +.Xc +.It Xo +.Ft int +.Fn unsetenv "const char *name" +.Xc +.Pp +These functions behave similarly to their standard library counterparts. +.It Xo +.Ft "struct env_var *" +.Fn env_getenv "const char *name" +.Xc +.Pp +Looks up a variable in the environment and returns its entire +data structure. +.It Xo +.Ft int +.Fn env_setenv "const char *name" "int flags" "const void *value" "ev_sethook_t sethook" "ev_unsethook_t unsethook" +.Xc +.Pp +Creates a new or sets an existing environment variable called +.Fa name . +If creating a new variable, the +.Fa sethook +and +.Fa unsethook +arguments may be specified. +.Pp +The set hook is invoked whenever an attempt +is made to set the variable, unless the EV_NOHOOK flag is set. +Typically +a set hook will validate the +.Fa value +argument, and then call +.Fn env_setenv +again with EV_NOHOOK set to actually save the value. +The predefined function +.Fn env_noset +may be specified to refuse all attempts to set a variable. +.Pp +The unset hook is invoked when an attempt is made to unset a variable. +If it +returns zero, the variable will be unset. +The predefined function +.Fa env_nounset +may be used to prevent a variable being unset. +.El +.Sh STANDARD LIBRARY SUPPORT +.Bl -hang -width 10n +.It Xo +.Ft int +.Fn getopt "int argc" "char * const *argv" "const char *optstring" +.Xc +.It Xo +.Ft long +.Fn strtol "const char *nptr" "char **endptr" "int base" +.Xc +.It Xo +.Ft void +.Fn srandom "unsigned long seed" +.Xc +.It Xo +.Ft "unsigned long" +.Fn random void +.Xc +.It Xo +.Ft "char *" +.Fn strerror "int error" +.Xc +.Pp +Returns error messages for the subset of errno values supported by +.Nm . +.It Fn assert expression +.Pp +Requires +.In assert.h . +.It Xo +.Ft int +.Fn setjmp "jmp_buf env" +.Xc +.It Xo +.Ft void +.Fn longjmp "jmp_buf env" "int val" +.Xc +.Pp +Defined as +.Fn _setjmp +and +.Fn _longjmp +respectively as there is no signal state to manipulate. +Requires +.In setjmp.h . +.El +.Sh CHARACTER I/O +.Bl -hang -width 10n +.It Xo +.Ft void +.Fn gets "char *buf" +.Xc +.Pp +Read characters from the console into +.Fa buf . +All of the standard cautions apply to this function. +.It Xo +.Ft void +.Fn ngets "char *buf" "int size" +.Xc +.Pp +Read at most +.Fa size +- 1 characters from the console into +.Fa buf . +If +.Fa size +is less than 1, the function's behaviour is as for +.Fn gets . +.It Xo +.Ft int +.Fn fgetstr "char *buf" "int size" "int fd" +.Xc +.Pp +Read a line of at most +.Fa size +characters into +.Fa buf . +Line terminating characters are stripped, and the buffer is always +.Dv NUL +terminated. +Returns the number of characters in +.Fa buf +if successful, or -1 if a read error occurs. +.It Xo +.Ft int +.Fn printf "const char *fmt" "..." +.Xc +.It Xo +.Ft void +.Fn vprintf "const char *fmt" "va_list ap" +.Xc +.It Xo +.Ft int +.Fn sprintf "char *buf" "const char *fmt" "..." +.Xc +.It Xo +.Ft void +.Fn vsprintf "char *buf" "const char *fmt" "va_list ap" +.Xc +.Pp +The *printf functions implement a subset of the standard +.Fn printf +family functionality and some extensions. +The following standard conversions +are supported: c,d,n,o,p,s,u,x. +The following modifiers are supported: ++,-,#,*,0,field width,precision,l. +.Pp +The +.Li b +conversion is provided to decode error registers. +Its usage is: +.Bd -ragged -offset indent +printf( +.Qq reg=%b\en , +regval, +.Qq <base><arg>* +); +.Ed +.Pp +where <base> is the output expressed as a control character, e.g.\& \e10 gives +octal, \e20 gives hex. +Each <arg> is a sequence of characters, the first of +which gives the bit number to be inspected (origin 1) and the next characters +(up to a character less than 32) give the text to be displayed if the bit is set. +Thus +.Bd -ragged -offset indent +printf( +.Qq reg=%b\en , +3, +.Qq \e10\e2BITTWO\e1BITONE +); +.Ed +.Pp +would give the output +.Bd -ragged -offset indent +reg=3<BITTWO,BITONE> +.Ed +.Pp +The +.Li D +conversion provides a hexdump facility, e.g. +.Bd -ragged -offset indent +printf( +.Qq %6D , +ptr, +.Qq \&: +); gives +.Qq XX:XX:XX:XX:XX:XX +.Ed +.Bd -ragged -offset indent +printf( +.Qq %*D , +len, +ptr, +.Qq "\ " +); gives +.Qq XX XX XX ... +.Ed +.El +.Sh CHARACTER TESTS AND CONVERSIONS +.Bl -hang -width 10n +.It Xo +.Ft int +.Fn isupper "int c" +.Xc +.It Xo +.Ft int +.Fn islower "int c" +.Xc +.It Xo +.Ft int +.Fn isspace "int c" +.Xc +.It Xo +.Ft int +.Fn isdigit "int c" +.Xc +.It Xo +.Ft int +.Fn isxdigit "int c" +.Xc +.It Xo +.Ft int +.Fn isascii "int c" +.Xc +.It Xo +.Ft int +.Fn isalpha "int c" +.Xc +.It Xo +.Ft int +.Fn toupper "int c" +.Xc +.It Xo +.Ft int +.Fn tolower "int c" +.Xc +.El +.Sh FILE I/O +.Bl -hang -width 10n +.It Xo +.Ft int +.Fn open "const char *path" "int flags" +.Xc +.Pp +Similar to the behaviour as specified in +.Xr open 2 , +except that file creation is not supported, so the mode parameter is not +required. +The +.Fa flags +argument may be one of O_RDONLY, O_WRONLY and O_RDWR (although no file systems +currently support writing). +.It Xo +.Ft int +.Fn close "int fd" +.Xc +.It Xo +.Ft void +.Fn closeall void +.Xc +.Pp +Close all open files. +.It Xo +.Ft ssize_t +.Fn read "int fd" "void *buf" "size_t len" +.Xc +.It Xo +.Ft ssize_t +.Fn write "int fd" "void *buf" "size_t len" +.Xc +.Pp +(No file systems currently support writing.) +.It Xo +.Ft off_t +.Fn lseek "int fd" "off_t offset" "int whence" +.Xc +.Pp +Files being automatically uncompressed during reading cannot seek backwards +from the current point. +.It Xo +.Ft int +.Fn stat "const char *path" "struct stat *sb" +.Xc +.It Xo +.Ft int +.Fn fstat "int fd" "struct stat *sb" +.Xc +.Pp +The +.Fn stat +and +.Fn fstat +functions only fill out the following fields in the +.Fa sb +structure: st_mode,st_nlink,st_uid,st_gid,st_size. +The +.Nm tftp +file system cannot provide meaningful values for this call, and the +.Nm cd9660 +file system always reports files having uid/gid of zero. +.El +.Sh PAGER +The +.Nm +library supplies a simple internal pager to ease reading the output of large +commands. +.Bl -hang -width 10n +.It Xo +.Ft void +.Fn pager_open +.Xc +.Pp +Initialises the pager and tells it that the next line output will be the top of the +display. +The environment variable LINES is consulted to determine the number of +lines to be displayed before pausing. +.It Xo +.Ft void +.Fn pager_close void +.Xc +.Pp +Closes the pager. +.It Xo +.Ft int +.Fn pager_output "const char *lines" +.Xc +.Pp +Sends the lines in the +.Dv NUL Ns +-terminated buffer at +.Fa lines +to the pager. +Newline characters are counted in order to determine the number +of lines being output (wrapped lines are not accounted for). +The +.Fn pager_output +function will return zero when all of the lines have been output, or nonzero +if the display was paused and the user elected to quit. +.It Xo +.Ft int +.Fn pager_file "const char *fname" +.Xc +.Pp +Attempts to open and display the file +.Fa fname . +Returns -1 on error, 0 at EOF, or 1 if the user elects to quit while reading. +.El +.Sh MISC +.Bl -hang -width 10n +.It Xo +.Ft void +.Fn twiddle void +.Xc +.Pp +Successive calls emit the characters in the sequence |,/,-,\\ followed by a +backspace in order to provide reassurance to the user. +.El +.Sh REQUIRED LOW-LEVEL SUPPORT +The following resources are consumed by +.Nm +- stack, heap, console and devices. +.Pp +The stack must be established before +.Nm +functions can be invoked. +Stack requirements vary depending on the functions +and file systems used by the consumer and the support layer functions detailed +below. +.Pp +The heap must be established before calling +.Fn alloc +or +.Fn open +by calling +.Fn setheap . +Heap usage will vary depending on the number of simultaneously open files, +as well as client behaviour. +Automatic decompression will allocate more +than 64K of data per open file. +.Pp +Console access is performed via the +.Fn getchar , +.Fn putchar +and +.Fn ischar +functions detailed below. +.Pp +Device access is initiated via +.Fn devopen +and is performed through the +.Fn dv_strategy , +.Fn dv_ioctl +and +.Fn dv_close +functions in the device switch structure that +.Fn devopen +returns. +.Pp +The consumer must provide the following support functions: +.Bl -hang -width 10n +.It Xo +.Ft int +.Fn getchar void +.Xc +.Pp +Return a character from the console, used by +.Fn gets , +.Fn ngets +and pager functions. +.It Xo +.Ft int +.Fn ischar void +.Xc +.Pp +Returns nonzero if a character is waiting from the console. +.It Xo +.Ft void +.Fn putchar int +.Xc +.Pp +Write a character to the console, used by +.Fn gets , +.Fn ngets , +.Fn *printf , +.Fn panic +and +.Fn twiddle +and thus by many other functions for debugging and informational output. +.It Xo +.Ft int +.Fn devopen "struct open_file *of" "const char *name" "const char **file" +.Xc +.Pp +Open the appropriate device for the file named in +.Fa name , +returning in +.Fa file +a pointer to the remaining body of +.Fa name +which does not refer to the device. +The +.Va f_dev +field in +.Fa of +will be set to point to the +.Vt devsw +structure for the opened device if successful. +Device identifiers must +always precede the path component, but may otherwise be arbitrarily formatted. +Used by +.Fn open +and thus for all device-related I/O. +.It Xo +.Ft int +.Fn devclose "struct open_file *of" +.Xc +.Pp +Close the device allocated for +.Fa of . +The device driver itself will already have been called for the close; this call +should clean up any allocation made by devopen only. +.It Xo +.Ft void +.Fn panic "const char *msg" "..." +.Xc +.Pp +Signal a fatal and unrecoverable error condition. +The +.Fa msg ... +arguments are as for +.Fn printf . +.El +.Sh INTERNAL FILE SYSTEMS +Internal file systems are enabled by the consumer exporting the array +.Vt struct fs_ops *file_system[] , +which should be initialised with pointers +to +.Vt struct fs_ops +structures. +The following file system handlers are supplied by +.Nm , +the consumer may supply other file systems of their own: +.Bl -hang -width ".Va cd9660_fsops" +.It Va ufs_fsops +The +.Bx +UFS. +.It Va ext2fs_fsops +Linux ext2fs file system. +.It Va tftp_fsops +File access via TFTP. +.It Va nfs_fsops +File access via NFS. +.It Va cd9660_fsops +ISO 9660 (CD-ROM) file system. +.It Va gzipfs_fsops +Stacked file system supporting gzipped files. +When trying the gzipfs file system, +.Nm +appends +.Li .gz +to the end of the filename, and then tries to locate the file using the other +file systems. +Placement of this file system in the +.Va file_system[] +array determines whether gzipped files will be opened in preference to non-gzipped +files. +It is only possible to seek a gzipped file forwards, and +.Fn stat +and +.Fn fstat +on gzipped files will report an invalid length. +.It Va bzipfs_fsops +The same as +.Va gzipfs_fsops , +but for +.Xr bzip2 1 Ns -compressed +files. +.El +.Pp +The array of +.Vt struct fs_ops +pointers should be terminated with a NULL. +.Sh DEVICES +Devices are exported by the supporting code via the array +.Vt struct devsw *devsw[] +which is a NULL terminated array of pointers to device switch structures. +.Sh HISTORY +The +.Nm +library contains contributions from many sources, including: +.Bl -bullet -compact +.It +.Nm libsa +from +.Nx +.It +.Nm libc +and +.Nm libkern +from +.Fx 3.0 . +.It +.Nm zalloc +from +.An Matthew Dillon Aq Mt dillon@backplane.com +.El +.Pp +The reorganisation and port to +.Fx 3.0 , +the environment functions and this manpage were written by +.An Mike Smith Aq Mt msmith@FreeBSD.org . +.Sh BUGS +The lack of detailed memory usage data is unhelpful. diff --git a/stand/libsa/lseek.c b/stand/libsa/lseek.c new file mode 100644 index 000000000000..df2591acd76d --- /dev/null +++ b/stand/libsa/lseek.c @@ -0,0 +1,141 @@ +/* $NetBSD: lseek.c,v 1.4 1997/01/22 00:38:10 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)lseek.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +off_t +lseek(int fd, off_t offset, int where) +{ + off_t bufpos, filepos, target; + struct open_file *f = &files[fd]; + + if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + + if (f->f_flags & F_RAW) { + /* + * On RAW devices, update internal offset. + */ + switch (where) { + case SEEK_SET: + f->f_offset = offset; + break; + case SEEK_CUR: + f->f_offset += offset; + break; + default: + errno = EOFFSET; + return (-1); + } + return (f->f_offset); + } + + /* + * If there is some unconsumed data in the readahead buffer and it + * contains the desired offset, simply adjust the buffer offset and + * length. We don't bother with SEEK_END here, since the code to + * handle it would fail in the same cases where the non-readahead + * code fails (namely, for streams which cannot seek backward and whose + * size isn't known in advance). + */ + if (f->f_ralen != 0 && where != SEEK_END) { + if ((filepos = (f->f_ops->fo_seek)(f, (off_t)0, SEEK_CUR)) == -1) + return (-1); + bufpos = filepos - f->f_ralen; + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = bufpos + offset; + break; + default: + errno = EINVAL; + return (-1); + } + if (bufpos <= target && target < filepos) { + f->f_raoffset += target - bufpos; + f->f_ralen -= target - bufpos; + return (target); + } + } + + /* + * If this is a relative seek, we need to correct the offset for + * bytes that we have already read but the caller doesn't know + * about. + */ + if (where == SEEK_CUR) + offset -= f->f_ralen; + + /* + * Invalidate the readahead buffer. + */ + f->f_ralen = 0; + + return (f->f_ops->fo_seek)(f, offset, where); +} diff --git a/stand/libsa/mips/_setjmp.S b/stand/libsa/mips/_setjmp.S new file mode 100644 index 000000000000..0289b0ec9274 --- /dev/null +++ b/stand/libsa/mips/_setjmp.S @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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$ + */ + +#include <machine/regnum.h> +#include <machine/asm.h> + +#if 0 +#if defined(LIBC_SCCS) + .text + .asciz "$OpenBSD: _setjmp.S,v 1.6 1996/09/23 21:27:53 imp Exp $" +#endif /* LIBC_SCCS */ +#endif + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from + * the last call to + * _setjmp(a) + * by restoring registers from the stack, + * The previous signal state is NOT restored. + */ + +LEAF(_setjmp) + .set noreorder + REG_LI v0, 0xACEDBADE # sigcontext magic number + REG_S ra, (2 * SZREG)(a0) # sc_pc = return address + REG_S v0, (3 * SZREG)(a0) # saved in sc_regs[0] + REG_S s0, ((S0 + 3) * SZREG)(a0) + REG_S s1, ((S1 + 3) * SZREG)(a0) + REG_S s2, ((S2 + 3) * SZREG)(a0) + REG_S s3, ((S3 + 3) * SZREG)(a0) + REG_S s4, ((S4 + 3) * SZREG)(a0) + REG_S s5, ((S5 + 3) * SZREG)(a0) + REG_S s6, ((S6 + 3) * SZREG)(a0) + REG_S s7, ((S7 + 3) * SZREG)(a0) + REG_S sp, ((SP + 3) * SZREG)(a0) + REG_S s8, ((S8 + 3) * SZREG)(a0) + j ra + move v0, zero +END(_setjmp) + +LEAF(_longjmp) +#ifdef ABICALLS + subu sp, sp, 32 + .cprestore 16 +#endif + .set noreorder + REG_L v0, (3 * SZREG)(a0) # get magic number + REG_L ra, (2 * SZREG)(a0) + bne v0, 0xACEDBADE, botch # jump if error + + addu sp, sp, 32 # does not matter, sanity + REG_L s0, ((S0 + 3) * SZREG)(a0) + REG_L s1, ((S1 + 3) * SZREG)(a0) + REG_L s2, ((S2 + 3) * SZREG)(a0) + REG_L s3, ((S3 + 3) * SZREG)(a0) + REG_L s4, ((S4 + 3) * SZREG)(a0) + REG_L s5, ((S5 + 3) * SZREG)(a0) + REG_L s6, ((S6 + 3) * SZREG)(a0) + REG_L s7, ((S7 + 3) * SZREG)(a0) + REG_L sp, ((SP + 3) * SZREG)(a0) + REG_L s8, ((S8 + 3) * SZREG)(a0) + + j ra + move v0, a1 +botch: + jal _C_LABEL(longjmperror) + nop + jal _C_LABEL(abort) + nop +END(_longjmp) diff --git a/stand/libsa/nandfs.c b/stand/libsa/nandfs.c new file mode 100644 index 000000000000..b3e72243e995 --- /dev/null +++ b/stand/libsa/nandfs.c @@ -0,0 +1,1061 @@ +/*- + * Copyright (c) 2010-2012 Semihalf. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/stdint.h> +#include <ufs/ufs/dinode.h> +#include <fs/nandfs/nandfs_fs.h> +#include "stand.h" +#include "string.h" +#include "zlib.h" + +#define DEBUG +#undef DEBUG +#ifdef DEBUG +#define NANDFS_DEBUG(fmt, args...) do { \ + printf("NANDFS_DEBUG:" fmt "\n", ##args); } while (0) +#else +#define NANDFS_DEBUG(fmt, args...) +#endif + +struct nandfs_mdt { + uint32_t entries_per_block; + uint32_t entries_per_group; + uint32_t blocks_per_group; + uint32_t groups_per_desc_block; /* desc is super group */ + uint32_t blocks_per_desc_block; /* desc is super group */ +}; + +struct bmap_buf { + LIST_ENTRY(bmap_buf) list; + nandfs_daddr_t blknr; + uint64_t *map; +}; + +struct nandfs_node { + struct nandfs_inode *inode; + LIST_HEAD(, bmap_buf) bmap_bufs; +}; +struct nandfs { + int nf_blocksize; + int nf_sectorsize; + int nf_cpno; + + struct open_file *nf_file; + struct nandfs_node *nf_opened_node; + u_int nf_offset; + uint8_t *nf_buf; + int64_t nf_buf_blknr; + + struct nandfs_fsdata *nf_fsdata; + struct nandfs_super_block *nf_sb; + struct nandfs_segment_summary nf_segsum; + struct nandfs_checkpoint nf_checkpoint; + struct nandfs_super_root nf_sroot; + struct nandfs_node nf_ifile; + struct nandfs_node nf_datfile; + struct nandfs_node nf_cpfile; + struct nandfs_mdt nf_datfile_mdt; + struct nandfs_mdt nf_ifile_mdt; + + int nf_nindir[NANDFS_NIADDR]; +}; + +static int nandfs_open(const char *, struct open_file *); +static int nandfs_close(struct open_file *); +static int nandfs_read(struct open_file *, void *, size_t, size_t *); +static off_t nandfs_seek(struct open_file *, off_t, int); +static int nandfs_stat(struct open_file *, struct stat *); +static int nandfs_readdir(struct open_file *, struct dirent *); + +static int nandfs_buf_read(struct nandfs *, void **, size_t *); +static struct nandfs_node *nandfs_lookup_path(struct nandfs *, const char *); +static int nandfs_read_inode(struct nandfs *, struct nandfs_node *, + nandfs_lbn_t, u_int, void *, int); +static int nandfs_read_blk(struct nandfs *, nandfs_daddr_t, void *, int); +static int nandfs_bmap_lookup(struct nandfs *, struct nandfs_node *, + nandfs_lbn_t, nandfs_daddr_t *, int); +static int nandfs_get_checkpoint(struct nandfs *, uint64_t, + struct nandfs_checkpoint *); +static nandfs_daddr_t nandfs_vtop(struct nandfs *, nandfs_daddr_t); +static void nandfs_calc_mdt_consts(int, struct nandfs_mdt *, int); +static void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t, + nandfs_daddr_t *, uint32_t *); +static int ioread(struct open_file *, off_t, void *, u_int); +static int nandfs_probe_sectorsize(struct open_file *); + +struct fs_ops nandfs_fsops = { + "nandfs", + nandfs_open, + nandfs_close, + nandfs_read, + null_write, + nandfs_seek, + nandfs_stat, + nandfs_readdir +}; + +#define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t)) + +/* from NetBSD's src/sys/net/if_ethersubr.c */ +static uint32_t +nandfs_crc32(uint32_t crc, const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + size_t i; + + crc = crc ^ ~0U; + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + return (crc ^ ~0U); +} + +static int +nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) +{ + uint32_t fsdata_crc, comp_crc; + + if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) + return (0); + + /* Preserve crc */ + fsdata_crc = fsdata->f_sum; + + /* Calculate */ + fsdata->f_sum = (0); + comp_crc = nandfs_crc32(0, (uint8_t *)fsdata, fsdata->f_bytes); + + /* Restore */ + fsdata->f_sum = fsdata_crc; + + /* Check CRC */ + return (fsdata_crc == comp_crc); +} + +static int +nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, + struct nandfs_super_block *super) +{ + uint32_t super_crc, comp_crc; + + /* Check super block magic */ + if (super->s_magic != NANDFS_SUPER_MAGIC) + return (0); + + /* Preserve CRC */ + super_crc = super->s_sum; + + /* Calculate */ + super->s_sum = (0); + comp_crc = nandfs_crc32(0, (uint8_t *)super, fsdata->f_sbbytes); + + /* Restore */ + super->s_sum = super_crc; + + /* Check CRC */ + return (super_crc == comp_crc); +} + +static int +nandfs_find_super_block(struct nandfs *fs, struct open_file *f) +{ + struct nandfs_super_block *sb; + int i, j, n, s; + int sectors_to_read, error; + + sb = malloc(fs->nf_sectorsize); + if (sb == NULL) + return (ENOMEM); + + memset(fs->nf_sb, 0, sizeof(*fs->nf_sb)); + + sectors_to_read = (NANDFS_NFSAREAS * fs->nf_fsdata->f_erasesize) / + fs->nf_sectorsize; + for (i = 0; i < sectors_to_read; i++) { + NANDFS_DEBUG("reading i %d offset %d\n", i, + i * fs->nf_sectorsize); + error = ioread(f, i * fs->nf_sectorsize, (char *)sb, + fs->nf_sectorsize); + if (error) { + NANDFS_DEBUG("error %d\n", error); + continue; + } + n = fs->nf_sectorsize / sizeof(struct nandfs_super_block); + s = 0; + if ((i * fs->nf_sectorsize) % fs->nf_fsdata->f_erasesize == 0) { + if (fs->nf_sectorsize == sizeof(struct nandfs_fsdata)) + continue; + else { + s += (sizeof(struct nandfs_fsdata) / + sizeof(struct nandfs_super_block)); + } + } + + for (j = s; j < n; j++) { + if (!nandfs_check_superblock_crc(fs->nf_fsdata, &sb[j])) + continue; + NANDFS_DEBUG("magic %x wtime %jd, lastcp 0x%jx\n", + sb[j].s_magic, sb[j].s_wtime, sb[j].s_last_cno); + if (sb[j].s_last_cno > fs->nf_sb->s_last_cno) + memcpy(fs->nf_sb, &sb[j], sizeof(*fs->nf_sb)); + } + } + + free(sb); + + return (fs->nf_sb->s_magic != 0 ? 0 : EINVAL); +} + +static int +nandfs_find_fsdata(struct nandfs *fs, struct open_file *f) +{ + int offset, error, i; + + NANDFS_DEBUG("starting\n"); + + offset = 0; + for (i = 0; i < 64 * NANDFS_NFSAREAS; i++) { + error = ioread(f, offset, (char *)fs->nf_fsdata, + sizeof(struct nandfs_fsdata)); + if (error) + return (error); + if (fs->nf_fsdata->f_magic == NANDFS_FSDATA_MAGIC) { + NANDFS_DEBUG("found at %x, volume %s\n", offset, + fs->nf_fsdata->f_volume_name); + if (nandfs_check_fsdata_crc(fs->nf_fsdata)) + break; + } + offset += fs->nf_sectorsize; + } + + return (error); +} + +static int +nandfs_read_structures(struct nandfs *fs, struct open_file *f) +{ + int error; + + error = nandfs_find_fsdata(fs, f); + if (error) + return (error); + + error = nandfs_find_super_block(fs, f); + + if (error == 0) + NANDFS_DEBUG("selected sb with w_time %jd last_pseg %jx\n", + fs->nf_sb->s_wtime, fs->nf_sb->s_last_pseg); + + return (error); +} + +static int +nandfs_mount(struct nandfs *fs, struct open_file *f) +{ + int err = 0, level; + uint64_t last_pseg; + + fs->nf_fsdata = malloc(sizeof(struct nandfs_fsdata)); + fs->nf_sb = malloc(sizeof(struct nandfs_super_block)); + + err = nandfs_read_structures(fs, f); + if (err) { + free(fs->nf_fsdata); + free(fs->nf_sb); + return (err); + } + + fs->nf_blocksize = 1 << (fs->nf_fsdata->f_log_block_size + 10); + + NANDFS_DEBUG("using superblock with wtime %jd\n", fs->nf_sb->s_wtime); + + fs->nf_cpno = fs->nf_sb->s_last_cno; + last_pseg = fs->nf_sb->s_last_pseg; + + /* + * Calculate indirect block levels. + */ + nandfs_daddr_t mult; + + mult = 1; + for (level = 0; level < NANDFS_NIADDR; level++) { + mult *= NINDIR(fs); + fs->nf_nindir[level] = mult; + } + + nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_datfile_mdt, + fs->nf_fsdata->f_dat_entry_size); + + nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_ifile_mdt, + fs->nf_fsdata->f_inode_size); + + err = ioread(f, last_pseg * fs->nf_blocksize, &fs->nf_segsum, + sizeof(struct nandfs_segment_summary)); + if (err) { + free(fs->nf_sb); + free(fs->nf_fsdata); + return (err); + } + + err = ioread(f, (last_pseg + fs->nf_segsum.ss_nblocks - 1) * + fs->nf_blocksize, &fs->nf_sroot, sizeof(struct nandfs_super_root)); + if (err) { + free(fs->nf_sb); + free(fs->nf_fsdata); + return (err); + } + + fs->nf_datfile.inode = &fs->nf_sroot.sr_dat; + LIST_INIT(&fs->nf_datfile.bmap_bufs); + fs->nf_cpfile.inode = &fs->nf_sroot.sr_cpfile; + LIST_INIT(&fs->nf_cpfile.bmap_bufs); + + err = nandfs_get_checkpoint(fs, fs->nf_cpno, &fs->nf_checkpoint); + if (err) { + free(fs->nf_sb); + free(fs->nf_fsdata); + return (err); + } + + NANDFS_DEBUG("checkpoint cp_cno=%lld\n", fs->nf_checkpoint.cp_cno); + NANDFS_DEBUG("checkpoint cp_inodes_count=%lld\n", + fs->nf_checkpoint.cp_inodes_count); + NANDFS_DEBUG("checkpoint cp_ifile_inode.i_blocks=%lld\n", + fs->nf_checkpoint.cp_ifile_inode.i_blocks); + + fs->nf_ifile.inode = &fs->nf_checkpoint.cp_ifile_inode; + LIST_INIT(&fs->nf_ifile.bmap_bufs); + return (0); +} + +#define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t)) + +static int +nandfs_open(const char *path, struct open_file *f) +{ + struct nandfs *fs; + struct nandfs_node *node; + int err, bsize, level; + + NANDFS_DEBUG("nandfs_open('%s', %p)\n", path, f); + + fs = malloc(sizeof(struct nandfs)); + f->f_fsdata = fs; + fs->nf_file = f; + + bsize = nandfs_probe_sectorsize(f); + if (bsize < 0) { + printf("Cannot probe medium sector size\n"); + return (EINVAL); + } + + fs->nf_sectorsize = bsize; + + /* + * Calculate indirect block levels. + */ + nandfs_daddr_t mult; + + mult = 1; + for (level = 0; level < NANDFS_NIADDR; level++) { + mult *= NINDIR(fs); + fs->nf_nindir[level] = mult; + } + + NANDFS_DEBUG("fs %p nf_sectorsize=%x\n", fs, fs->nf_sectorsize); + + err = nandfs_mount(fs, f); + if (err) { + NANDFS_DEBUG("Cannot mount nandfs: %s\n", strerror(err)); + return (err); + } + + node = nandfs_lookup_path(fs, path); + if (node == NULL) + return (EINVAL); + + fs->nf_offset = 0; + fs->nf_buf = NULL; + fs->nf_buf_blknr = -1; + fs->nf_opened_node = node; + LIST_INIT(&fs->nf_opened_node->bmap_bufs); + return (0); +} + +static void +nandfs_free_node(struct nandfs_node *node) +{ + struct bmap_buf *bmap, *tmp; + + free(node->inode); + LIST_FOREACH_SAFE(bmap, &node->bmap_bufs, list, tmp) { + LIST_REMOVE(bmap, list); + free(bmap->map); + free(bmap); + } + free(node); +} + +static int +nandfs_close(struct open_file *f) +{ + struct nandfs *fs = f->f_fsdata; + + NANDFS_DEBUG("nandfs_close(%p)\n", f); + + if (fs->nf_buf != NULL) + free(fs->nf_buf); + + nandfs_free_node(fs->nf_opened_node); + free(fs->nf_sb); + free(fs); + return (0); +} + +static int +nandfs_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + struct nandfs *fs = (struct nandfs *)f->f_fsdata; + size_t csize, buf_size; + void *buf; + int error = 0; + + NANDFS_DEBUG("nandfs_read(file=%p, addr=%p, size=%d)\n", f, addr, size); + + while (size != 0) { + if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) + break; + + error = nandfs_buf_read(fs, &buf, &buf_size); + if (error) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fs->nf_offset += csize; + addr = (char *)addr + csize; + size -= csize; + } + + if (resid) + *resid = size; + return (error); +} + +static off_t +nandfs_seek(struct open_file *f, off_t offset, int where) +{ + struct nandfs *fs = f->f_fsdata; + off_t off; + u_int size; + + NANDFS_DEBUG("nandfs_seek(file=%p, offset=%lld, where=%d)\n", f, + offset, where); + + size = fs->nf_opened_node->inode->i_size; + + switch (where) { + case SEEK_SET: + off = 0; + break; + case SEEK_CUR: + off = fs->nf_offset; + break; + case SEEK_END: + off = size; + break; + default: + errno = EINVAL; + return (-1); + } + + off += offset; + if (off < 0 || off > size) { + errno = EINVAL; + return(-1); + } + + fs->nf_offset = (u_int)off; + + return (off); +} + +static int +nandfs_stat(struct open_file *f, struct stat *sb) +{ + struct nandfs *fs = f->f_fsdata; + + NANDFS_DEBUG("nandfs_stat(file=%p, stat=%p)\n", f, sb); + + sb->st_size = fs->nf_opened_node->inode->i_size; + sb->st_mode = fs->nf_opened_node->inode->i_mode; + sb->st_uid = fs->nf_opened_node->inode->i_uid; + sb->st_gid = fs->nf_opened_node->inode->i_gid; + return (0); +} + +static int +nandfs_readdir(struct open_file *f, struct dirent *d) +{ + struct nandfs *fs = f->f_fsdata; + struct nandfs_dir_entry *dirent; + void *buf; + size_t buf_size; + + NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)\n", f, d); + + if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) { + NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) ENOENT\n", + f, d); + return (ENOENT); + } + + if (nandfs_buf_read(fs, &buf, &buf_size)) { + NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)" + "buf_read failed\n", f, d); + return (EIO); + } + + NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) moving forward\n", + f, d); + + dirent = (struct nandfs_dir_entry *)buf; + fs->nf_offset += dirent->rec_len; + strncpy(d->d_name, dirent->name, dirent->name_len); + d->d_name[dirent->name_len] = '\0'; + d->d_type = dirent->file_type; + return (0); +} + +static int +nandfs_buf_read(struct nandfs *fs, void **buf_p, size_t *size_p) +{ + nandfs_daddr_t blknr, blkoff; + + blknr = fs->nf_offset / fs->nf_blocksize; + blkoff = fs->nf_offset % fs->nf_blocksize; + + if (blknr != fs->nf_buf_blknr) { + if (fs->nf_buf == NULL) + fs->nf_buf = malloc(fs->nf_blocksize); + + if (nandfs_read_inode(fs, fs->nf_opened_node, blknr, 1, + fs->nf_buf, 0)) + return (EIO); + + fs->nf_buf_blknr = blknr; + } + + *buf_p = fs->nf_buf + blkoff; + *size_p = fs->nf_blocksize - blkoff; + + NANDFS_DEBUG("nandfs_buf_read buf_p=%p size_p=%d\n", *buf_p, *size_p); + + if (*size_p > fs->nf_opened_node->inode->i_size - fs->nf_offset) + *size_p = fs->nf_opened_node->inode->i_size - fs->nf_offset; + + return (0); +} + +static struct nandfs_node * +nandfs_lookup_node(struct nandfs *fs, uint64_t ino) +{ + uint64_t blocknr; + int entrynr; + struct nandfs_inode *buffer; + struct nandfs_node *node; + struct nandfs_inode *inode; + + NANDFS_DEBUG("nandfs_lookup_node ino=%lld\n", ino); + + if (ino == 0) { + printf("nandfs_lookup_node: invalid inode requested\n"); + return (NULL); + } + + buffer = malloc(fs->nf_blocksize); + inode = malloc(sizeof(struct nandfs_inode)); + node = malloc(sizeof(struct nandfs_node)); + + nandfs_mdt_trans(&fs->nf_ifile_mdt, ino, &blocknr, &entrynr); + + if (nandfs_read_inode(fs, &fs->nf_ifile, blocknr, 1, buffer, 0)) + return (NULL); + + memcpy(inode, &buffer[entrynr], sizeof(struct nandfs_inode)); + node->inode = inode; + free(buffer); + return (node); +} + +static struct nandfs_node * +nandfs_lookup_path(struct nandfs *fs, const char *path) +{ + struct nandfs_node *node; + struct nandfs_dir_entry *dirent; + char *namebuf; + uint64_t i, done, pinode, inode; + int nlinks = 0, counter, len, link_len, nameidx; + uint8_t *buffer, *orig; + char *strp, *lpath; + + buffer = malloc(fs->nf_blocksize); + orig = buffer; + + namebuf = malloc(2 * MAXPATHLEN + 2); + strncpy(namebuf, path, MAXPATHLEN); + namebuf[MAXPATHLEN] = '\0'; + done = nameidx = 0; + lpath = namebuf; + + /* Get the root inode */ + node = nandfs_lookup_node(fs, NANDFS_ROOT_INO); + inode = NANDFS_ROOT_INO; + + while ((strp = strsep(&lpath, "/")) != NULL) { + if (*strp == '\0') + continue; + if ((node->inode->i_mode & IFMT) != IFDIR) { + nandfs_free_node(node); + node = NULL; + goto out; + } + + len = strlen(strp); + NANDFS_DEBUG("%s: looking for %s\n", __func__, strp); + for (i = 0; i < node->inode->i_blocks; i++) { + if (nandfs_read_inode(fs, node, i, 1, orig, 0)) { + node = NULL; + goto out; + } + + buffer = orig; + done = counter = 0; + while (1) { + dirent = + (struct nandfs_dir_entry *)(void *)buffer; + NANDFS_DEBUG("%s: dirent.name = %s\n", + __func__, dirent->name); + NANDFS_DEBUG("%s: dirent.rec_len = %d\n", + __func__, dirent->rec_len); + NANDFS_DEBUG("%s: dirent.inode = %lld\n", + __func__, dirent->inode); + if (len == dirent->name_len && + (strncmp(strp, dirent->name, len) == 0) && + dirent->inode != 0) { + nandfs_free_node(node); + node = nandfs_lookup_node(fs, + dirent->inode); + pinode = inode; + inode = dirent->inode; + done = 1; + break; + } + + counter += dirent->rec_len; + buffer += dirent->rec_len; + + if (counter == fs->nf_blocksize) + break; + } + + if (done) + break; + } + + if (!done) { + node = NULL; + goto out; + } + + NANDFS_DEBUG("%s: %.*s has mode %o\n", __func__, + dirent->name_len, dirent->name, node->inode->i_mode); + + if ((node->inode->i_mode & IFMT) == IFLNK) { + NANDFS_DEBUG("%s: %.*s is symlink\n", + __func__, dirent->name_len, dirent->name); + link_len = node->inode->i_size; + + if (++nlinks > MAXSYMLINKS) { + nandfs_free_node(node); + node = NULL; + goto out; + } + + if (nandfs_read_inode(fs, node, 0, 1, orig, 0)) { + nandfs_free_node(node); + node = NULL; + goto out; + } + + NANDFS_DEBUG("%s: symlink is %.*s\n", + __func__, link_len, (char *)orig); + + nameidx = (nameidx == 0) ? MAXPATHLEN + 1 : 0; + bcopy((char *)orig, namebuf + nameidx, + (unsigned)link_len); + if (lpath != NULL) { + namebuf[nameidx + link_len++] = '/'; + strncpy(namebuf + nameidx + link_len, lpath, + MAXPATHLEN - link_len); + namebuf[nameidx + MAXPATHLEN] = '\0'; + } else + namebuf[nameidx + link_len] = '\0'; + + NANDFS_DEBUG("%s: strp=%s, lpath=%s, namebuf0=%s, " + "namebuf1=%s, idx=%d\n", __func__, strp, lpath, + namebuf + 0, namebuf + MAXPATHLEN + 1, nameidx); + + lpath = namebuf + nameidx; + + nandfs_free_node(node); + + /* + * If absolute pathname, restart at root. Otherwise + * continue with out parent inode. + */ + inode = (orig[0] == '/') ? NANDFS_ROOT_INO : pinode; + node = nandfs_lookup_node(fs, inode); + } + } + +out: + free(namebuf); + free(orig); + return (node); +} + +static int +nandfs_read_inode(struct nandfs *fs, struct nandfs_node *node, + nandfs_daddr_t blknr, u_int nblks, void *buf, int raw) +{ + uint64_t *pblks; + uint64_t *vblks; + u_int i; + int error; + + pblks = malloc(nblks * sizeof(uint64_t)); + vblks = malloc(nblks * sizeof(uint64_t)); + + NANDFS_DEBUG("nandfs_read_inode fs=%p node=%p blknr=%lld nblks=%d\n", + fs, node, blknr, nblks); + for (i = 0; i < nblks; i++) { + error = nandfs_bmap_lookup(fs, node, blknr + i, &vblks[i], raw); + if (error) { + free(pblks); + free(vblks); + return (error); + } + if (raw == 0) + pblks[i] = nandfs_vtop(fs, vblks[i]); + else + pblks[i] = vblks[i]; + } + + for (i = 0; i < nblks; i++) { + if (ioread(fs->nf_file, pblks[i] * fs->nf_blocksize, buf, + fs->nf_blocksize)) { + free(pblks); + free(vblks); + return (EIO); + } + + buf = (void *)((uintptr_t)buf + fs->nf_blocksize); + } + + free(pblks); + free(vblks); + return (0); +} + +static int +nandfs_read_blk(struct nandfs *fs, nandfs_daddr_t blknr, void *buf, int phys) +{ + uint64_t pblknr; + + pblknr = (phys ? blknr : nandfs_vtop(fs, blknr)); + + return (ioread(fs->nf_file, pblknr * fs->nf_blocksize, buf, + fs->nf_blocksize)); +} + +static int +nandfs_get_checkpoint(struct nandfs *fs, uint64_t cpno, + struct nandfs_checkpoint *cp) +{ + uint64_t blocknr; + int blockoff, cp_per_block, dlen; + uint8_t *buf; + + NANDFS_DEBUG("nandfs_get_checkpoint(fs=%p cpno=%lld)\n", fs, cpno); + + buf = malloc(fs->nf_blocksize); + + cpno += NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; + dlen = fs->nf_fsdata->f_checkpoint_size; + cp_per_block = fs->nf_blocksize / dlen; + blocknr = cpno / cp_per_block; + blockoff = (cpno % cp_per_block) * dlen; + + if (nandfs_read_inode(fs, &fs->nf_cpfile, blocknr, 1, buf, 0)) { + free(buf); + return (EINVAL); + } + + memcpy(cp, buf + blockoff, sizeof(struct nandfs_checkpoint)); + free(buf); + + return (0); +} + +static uint64_t * +nandfs_get_map(struct nandfs *fs, struct nandfs_node *node, nandfs_daddr_t blknr, + int phys) +{ + struct bmap_buf *bmap; + uint64_t *map; + + LIST_FOREACH(bmap, &node->bmap_bufs, list) { + if (bmap->blknr == blknr) + return (bmap->map); + } + + map = malloc(fs->nf_blocksize); + if (nandfs_read_blk(fs, blknr, map, phys)) { + free(map); + return (NULL); + } + + bmap = malloc(sizeof(struct bmap_buf)); + bmap->blknr = blknr; + bmap->map = map; + + LIST_INSERT_HEAD(&node->bmap_bufs, bmap, list); + + NANDFS_DEBUG("%s:(node=%p, map=%p)\n", __func__, node, map); + return (map); +} + +static int +nandfs_bmap_lookup(struct nandfs *fs, struct nandfs_node *node, + nandfs_lbn_t lblknr, nandfs_daddr_t *vblknr, int phys) +{ + struct nandfs_inode *ino; + nandfs_daddr_t ind_block_num; + uint64_t *map; + int idx; + int level; + + ino = node->inode; + + if (lblknr < NANDFS_NDADDR) { + *vblknr = ino->i_db[lblknr]; + return (0); + } + + lblknr -= NANDFS_NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < NANDFS_NIADDR; level++) { + NANDFS_DEBUG("lblknr=%jx fs->nf_nindir[%d]=%d\n", lblknr, level, fs->nf_nindir[level]); + if (lblknr < fs->nf_nindir[level]) + break; + lblknr -= fs->nf_nindir[level]; + } + + if (level == NANDFS_NIADDR) { + /* Block number too high */ + NANDFS_DEBUG("lblknr %jx too high\n", lblknr); + return (EFBIG); + } + + ind_block_num = ino->i_ib[level]; + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *vblknr = 0; /* missing */ + return (0); + } + + twiddle(1); + NANDFS_DEBUG("calling get_map with %jx\n", ind_block_num); + map = nandfs_get_map(fs, node, ind_block_num, phys); + if (map == NULL) + return (EIO); + + if (level > 0) { + idx = lblknr / fs->nf_nindir[level - 1]; + lblknr %= fs->nf_nindir[level - 1]; + } else + idx = lblknr; + + ind_block_num = ((nandfs_daddr_t *)map)[idx]; + } + + *vblknr = ind_block_num; + + return (0); +} + +static nandfs_daddr_t +nandfs_vtop(struct nandfs *fs, nandfs_daddr_t vblocknr) +{ + nandfs_lbn_t blocknr; + nandfs_daddr_t pblocknr; + int entrynr; + struct nandfs_dat_entry *dat; + + dat = malloc(fs->nf_blocksize); + nandfs_mdt_trans(&fs->nf_datfile_mdt, vblocknr, &blocknr, &entrynr); + + if (nandfs_read_inode(fs, &fs->nf_datfile, blocknr, 1, dat, 1)) { + free(dat); + return (0); + } + + NANDFS_DEBUG("nandfs_vtop entrynr=%d vblocknr=%lld pblocknr=%lld\n", + entrynr, vblocknr, dat[entrynr].de_blocknr); + + pblocknr = dat[entrynr].de_blocknr; + free(dat); + return (pblocknr); +} + +static void +nandfs_calc_mdt_consts(int blocksize, struct nandfs_mdt *mdt, int entry_size) +{ + + mdt->entries_per_group = blocksize * 8; /* bits in sector */ + mdt->entries_per_block = blocksize / entry_size; + mdt->blocks_per_group = + (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; + mdt->groups_per_desc_block = + blocksize / sizeof(struct nandfs_block_group_desc); + mdt->blocks_per_desc_block = + mdt->groups_per_desc_block * mdt->blocks_per_group + 1; +} + +static void +nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, + nandfs_daddr_t *blocknr, uint32_t *entry_in_block) +{ + nandfs_daddr_t blknr; + uint64_t group, group_offset, blocknr_in_group; + uint64_t desc_block, desc_offset; + + /* Calculate our offset in the file */ + group = index / mdt->entries_per_group; + group_offset = index % mdt->entries_per_group; + desc_block = group / mdt->groups_per_desc_block; + desc_offset = group % mdt->groups_per_desc_block; + blocknr_in_group = group_offset / mdt->entries_per_block; + + /* To descgroup offset */ + blknr = 1 + desc_block * mdt->blocks_per_desc_block; + + /* To group offset */ + blknr += desc_offset * mdt->blocks_per_group; + + /* To actual file block */ + blknr += 1 + blocknr_in_group; + + *blocknr = blknr; + *entry_in_block = group_offset % mdt->entries_per_block; +} + +static int +ioread(struct open_file *f, off_t pos, void *buf, u_int length) +{ + void *buffer; + int err; + int bsize = ((struct nandfs *)f->f_fsdata)->nf_sectorsize; + u_int off, nsec; + + off = pos % bsize; + pos /= bsize; + nsec = howmany(length, bsize); + + NANDFS_DEBUG("pos=%lld length=%d off=%d nsec=%d\n", pos, length, + off, nsec); + + buffer = malloc(nsec * bsize); + + err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, pos, + nsec * bsize, buffer, NULL); + + memcpy(buf, (void *)((uintptr_t)buffer + off), length); + free(buffer); + + return (err); +} + +static int +nandfs_probe_sectorsize(struct open_file *f) +{ + void *buffer; + int i, err; + + buffer = malloc(16 * 1024); + + NANDFS_DEBUG("probing for sector size: "); + + for (i = 512; i < (16 * 1024); i <<= 1) { + NANDFS_DEBUG("%d ", i); + err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0, i, + buffer, NULL); + + if (err == 0) { + NANDFS_DEBUG("found"); + free(buffer); + return (i); + } + } + + free(buffer); + NANDFS_DEBUG("not found\n"); + return (-1); +} diff --git a/stand/libsa/net.c b/stand/libsa/net.c new file mode 100644 index 000000000000..ae6e74511e12 --- /dev/null +++ b/stand/libsa/net.c @@ -0,0 +1,283 @@ +/* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> + +#include <string.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> + +#include <netinet/in_pcb.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include "stand.h" +#include "net.h" + +/* + * Send a packet and wait for a reply, with exponential backoff. + * + * The send routine must return the actual number of bytes written, + * or -1 on error. + * + * The receive routine can indicate success by returning the number of + * bytes read; it can return 0 to indicate EOF; it can return -1 with a + * non-zero errno to indicate failure; finally, it can return -1 with a + * zero errno to indicate it isn't done yet. + */ +ssize_t +sendrecv(struct iodesc *d, + ssize_t (*sproc)(struct iodesc *, void *, size_t), + void *sbuf, size_t ssize, + ssize_t (*rproc)(struct iodesc *, void **, void **, time_t), + void **pkt, void **payload) +{ + ssize_t cc; + time_t t, tmo, tlast; + long tleft; + +#ifdef NET_DEBUG + if (debug) + printf("sendrecv: called\n"); +#endif + + tmo = MINTMO; + tlast = 0; + tleft = 0; + t = getsecs(); + for (;;) { + if (tleft <= 0) { + if (tmo >= MAXTMO) { + errno = ETIMEDOUT; + return -1; + } + cc = (*sproc)(d, sbuf, ssize); + if (cc != -1 && cc < ssize) + panic("sendrecv: short write! (%zd < %zd)", + cc, ssize); + + tleft = tmo; + tmo += MINTMO; + if (tmo > MAXTMO) + tmo = MAXTMO; + + if (cc == -1) { + /* Error on transmit; wait before retrying */ + while ((getsecs() - t) < tmo) + ; + tleft = 0; + continue; + } + + tlast = t; + } + + /* Try to get a packet and process it. */ + cc = (*rproc)(d, pkt, payload, tleft); + /* Return on data, EOF or real error. */ + if (cc != -1 || errno != 0) + return (cc); + + /* Timed out or didn't get the packet we're waiting for */ + t = getsecs(); + tleft -= t - tlast; + tlast = t; + } +} + +/* + * Like inet_addr() in the C library, but we only accept base-10. + * Return values are in network order. + */ +n_long +inet_addr(char *cp) +{ + u_long val; + int n; + char c; + u_int parts[4]; + u_int *pp = parts; + + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; + while ((c = *cp) != '\0') { + if (c >= '0' && c <= '9') { + val = (val * 10) + (c - '0'); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16-bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xff) + goto bad; + *pp++ = val, cp++; + } else + break; + } + /* + * Check for trailing characters. + */ + if (*cp != '\0') + goto bad; + + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + goto bad; + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + goto bad; + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + goto bad; + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + + return (htonl(val)); + bad: + return (htonl(INADDR_NONE)); +} + +char * +inet_ntoa(struct in_addr ia) +{ + return (intoa(ia.s_addr)); +} + +/* Similar to inet_ntoa() */ +char * +intoa(n_long addr) +{ + char *cp; + u_int byte; + int n; + static char buf[17]; /* strlen(".255.255.255.255") + 1 */ + + addr = ntohl(addr); + cp = &buf[sizeof buf]; + *--cp = '\0'; + + n = 4; + do { + byte = addr & 0xff; + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) { + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) + *--cp = byte + '0'; + } + *--cp = '.'; + addr >>= 8; + } while (--n > 0); + + return (cp+1); +} + +static char * +number(char *s, int *n) +{ + for (*n = 0; isdigit(*s); s++) + *n = (*n * 10) + *s - '0'; + return s; +} + +n_long +ip_convertaddr(char *p) +{ +#define IP_ANYADDR 0 + n_long addr = 0, n; + + if (p == (char *)0 || *p == '\0') + return IP_ANYADDR; + p = number(p, &n); + addr |= (n << 24) & 0xff000000; + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = number(p, &n); + addr |= (n << 16) & 0xff0000; + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = number(p, &n); + addr |= (n << 8) & 0xff00; + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = number(p, &n); + addr |= n & 0xff; + if (*p != '\0') + return IP_ANYADDR; + + return htonl(addr); +} diff --git a/stand/libsa/net.h b/stand/libsa/net.h new file mode 100644 index 000000000000..cc946c15ff5c --- /dev/null +++ b/stand/libsa/net.h @@ -0,0 +1,133 @@ +/* $NetBSD: net.h,v 1.10 1995/10/20 00:46:30 cgd Exp $ */ + +/* + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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$ + */ + +#ifndef _STAND_NET_H +#define _STAND_NET_H +#ifndef _KERNEL /* XXX - see <netinet/in.h> */ +#undef __IPADDR +#define __IPADDR(x) htonl((u_int32_t)(x)) +#endif + +#include "iodesc.h" + +#define BA { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + +enum net_proto { + NET_NONE, + NET_NFS, + NET_TFTP +}; + +/* Returns true if n_long's on the same net */ +#define SAMENET(a1, a2, m) ((a1.s_addr & m) == (a2.s_addr & m)) + +#define MACPY(s, d) bcopy((char *)s, (char *)d, 6) + +#define MAXTMO 120 /* seconds */ +#define MINTMO 2 /* seconds */ + +#define FNAME_SIZE 128 +#define IFNAME_SIZE 16 +#define RECV_SIZE 1536 /* XXX delete this */ + +/* + * How much room to leave for headers: + * 14: struct ether_header + * 20: struct ip + * 8: struct udphdr + * That's 42 but let's pad it out to 48 bytes. + */ +#define ETHER_SIZE 14 +#define HEADER_SIZE 48 + +extern u_char bcea[6]; +extern char rootpath[FNAME_SIZE]; +extern char bootfile[FNAME_SIZE]; +extern char hostname[FNAME_SIZE]; +extern int hostnamelen; +extern char domainname[FNAME_SIZE]; +extern int domainnamelen; +extern int netproto; +extern char ifname[IFNAME_SIZE]; + +/* All of these are in network order. */ +extern struct in_addr myip; +extern struct in_addr rootip; +extern struct in_addr swapip; +extern struct in_addr gateip; +extern struct in_addr nameip; +extern n_long netmask; +extern u_int intf_mtu; + +extern int debug; /* defined in the machdep sources */ + +extern struct iodesc sockets[SOPEN_MAX]; + +/* ARP/RevARP functions: */ +u_char *arpwhohas(struct iodesc *, struct in_addr); +void arp_reply(struct iodesc *, void *); +int rarp_getipaddress(int); + +/* Link functions: */ +ssize_t sendether(struct iodesc *d, void *pkt, size_t len, + u_char *dea, int etype); +ssize_t readether(struct iodesc *, void **, void **, time_t, uint16_t *); + +ssize_t sendip(struct iodesc *, void *, size_t, uint8_t); +ssize_t readip(struct iodesc *, void **, void **, time_t, uint8_t); +ssize_t sendudp(struct iodesc *, void *, size_t); +ssize_t readudp(struct iodesc *, void **, void **, time_t); +ssize_t sendrecv(struct iodesc *, + ssize_t (*)(struct iodesc *, void *, size_t), + void *, size_t, + ssize_t (*)(struct iodesc *, void **, void **, time_t), + void **, void **); + +/* bootp/DHCP */ +void bootp(int); + +/* Utilities: */ +char *ether_sprintf(u_char *); +int in_cksum(void *, int); +char *inet_ntoa(struct in_addr); +char *intoa(n_long); /* similar to inet_ntoa */ +n_long inet_addr(char *); + +/* Machine-dependent functions: */ +time_t getsecs(void); +#endif /* ! _STAND_NET_H */ diff --git a/stand/libsa/netif.c b/stand/libsa/netif.c new file mode 100644 index 000000000000..105f9a31ab5d --- /dev/null +++ b/stand/libsa/netif.c @@ -0,0 +1,316 @@ +/* $NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $ */ + +/* + * Copyright (c) 1993 Adam Glass + * 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 Adam Glass. + * 4. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam Glass ``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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/mount.h> +#include <string.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include "stand.h" +#include "net.h" +#include "netif.h" + +struct iodesc sockets[SOPEN_MAX]; +#ifdef NETIF_DEBUG +int netif_debug = 0; +#endif + +/* + * netif_init: + * + * initialize the generic network interface layer + */ + +void +netif_init(void) +{ + struct netif_driver *drv; + int d, i; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_init: called\n"); +#endif + for (d = 0; netif_drivers[d]; d++) { + drv = netif_drivers[d]; + for (i = 0; i < drv->netif_nifs; i++) + drv->netif_ifs[i].dif_used = 0; + } +} + +int +netif_match(struct netif *nif, void *machdep_hint) +{ + struct netif_driver *drv = nif->nif_driver; + +#if NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_match (%d)\n", drv->netif_bname, + nif->nif_unit, nif->nif_sel); +#endif + return drv->netif_match(nif, machdep_hint); +} + +struct netif * +netif_select(void *machdep_hint) +{ + int d, u, unit_done, s; + struct netif_driver *drv; + struct netif cur_if; + static struct netif best_if; + int best_val; + int val; + + best_val = 0; + best_if.nif_driver = NULL; + + for (d = 0; netif_drivers[d] != NULL; d++) { + cur_if.nif_driver = netif_drivers[d]; + drv = cur_if.nif_driver; + + for (u = 0; u < drv->netif_nifs; u++) { + cur_if.nif_unit = u; + unit_done = 0; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("\t%s%d:", drv->netif_bname, + cur_if.nif_unit); +#endif + + for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) { + cur_if.nif_sel = s; + + if (drv->netif_ifs[u].dif_used & (1 << s)) { +#ifdef NETIF_DEBUG + if (netif_debug) + printf(" [%d used]", s); +#endif + continue; + } + + val = netif_match(&cur_if, machdep_hint); +#ifdef NETIF_DEBUG + if (netif_debug) + printf(" [%d -> %d]", s, val); +#endif + if (val > best_val) { + best_val = val; + best_if = cur_if; + } + } +#ifdef NETIF_DEBUG + if (netif_debug) + printf("\n"); +#endif + } + } + + if (best_if.nif_driver == NULL) + return NULL; + + best_if.nif_driver-> + netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel); + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_select: %s%d(%d) wins\n", + best_if.nif_driver->netif_bname, + best_if.nif_unit, best_if.nif_sel); +#endif + return &best_if; +} + +int +netif_probe(struct netif *nif, void *machdep_hint) +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit); +#endif + return drv->netif_probe(nif, machdep_hint); +} + +void +netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint) +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit); +#endif + desc->io_netif = nif; +#ifdef PARANOID + if (drv->netif_init == NULL) + panic("%s%d: no netif_init support\n", drv->netif_bname, + nif->nif_unit); +#endif + drv->netif_init(desc, machdep_hint); + bzero(drv->netif_ifs[nif->nif_unit].dif_stats, + sizeof(struct netif_stats)); +} + +void +netif_detach(struct netif *nif) +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_end == NULL) + panic("%s%d: no netif_end support\n", drv->netif_bname, + nif->nif_unit); +#endif + drv->netif_end(nif); +} + +ssize_t +netif_get(struct iodesc *desc, void **pkt, time_t timo) +{ +#ifdef NETIF_DEBUG + struct netif *nif = desc->io_netif; +#endif + struct netif_driver *drv = desc->io_netif->nif_driver; + ssize_t rv; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_get == NULL) + panic("%s%d: no netif_get support\n", drv->netif_bname, + nif->nif_unit); +#endif + rv = drv->netif_get(desc, pkt, timo); +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_get returning %d\n", drv->netif_bname, + nif->nif_unit, (int)rv); +#endif + return (rv); +} + +ssize_t +netif_put(struct iodesc *desc, void *pkt, size_t len) +{ +#ifdef NETIF_DEBUG + struct netif *nif = desc->io_netif; +#endif + struct netif_driver *drv = desc->io_netif->nif_driver; + ssize_t rv; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_put == NULL) + panic("%s%d: no netif_put support\n", drv->netif_bname, + nif->nif_unit); +#endif + rv = drv->netif_put(desc, pkt, len); +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_put returning %d\n", drv->netif_bname, + nif->nif_unit, (int)rv); +#endif + return (rv); +} + +struct iodesc * +socktodesc(int sock) +{ + if (sock >= SOPEN_MAX) { + errno = EBADF; + return (NULL); + } + return (&sockets[sock]); +} + +int +netif_open(void *machdep_hint) +{ + int fd; + struct iodesc *s; + struct netif *nif; + + /* find a free socket */ + for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++) + if (s->io_netif == (struct netif *)0) + goto fnd; + errno = EMFILE; + return (-1); + +fnd: + bzero(s, sizeof(*s)); + netif_init(); + nif = netif_select(machdep_hint); + if (!nif) + panic("netboot: no interfaces left untried"); + if (netif_probe(nif, machdep_hint)) { + printf("netboot: couldn't probe %s%d\n", + nif->nif_driver->netif_bname, nif->nif_unit); + errno = EINVAL; + return (-1); + } + netif_attach(nif, s, machdep_hint); + + return (fd); +} + +int +netif_close(int sock) +{ + if (sock >= SOPEN_MAX) { + errno = EBADF; + return (-1); + } + netif_detach(sockets[sock].io_netif); + sockets[sock].io_netif = (struct netif *)0; + + return (0); +} diff --git a/stand/libsa/netif.h b/stand/libsa/netif.h new file mode 100644 index 000000000000..44165ab0d88a --- /dev/null +++ b/stand/libsa/netif.h @@ -0,0 +1,65 @@ +/* $NetBSD: netif.h,v 1.4 1995/09/14 23:45:30 pk Exp $ */ + +/* $FreeBSD$ */ + +#ifndef __SYS_LIBNETBOOT_NETIF_H +#define __SYS_LIBNETBOOT_NETIF_H +#include "iodesc.h" + +struct netif_driver { + const char *netif_bname; + int (*netif_match)(struct netif *, void *); + int (*netif_probe)(struct netif *, void *); + void (*netif_init)(struct iodesc *, void *); + ssize_t (*netif_get)(struct iodesc *, void **, time_t); + ssize_t (*netif_put)(struct iodesc *, void *, size_t); + void (*netif_end)(struct netif *); + struct netif_dif *netif_ifs; + int netif_nifs; +}; + +struct netif_dif { + int dif_unit; + int dif_nsel; + struct netif_stats *dif_stats; + void *dif_private; + /* the following fields are used internally by the netif layer */ + u_long dif_used; +}; + +struct netif_stats { + int collisions; + int collision_error; + int missed; + int sent; + int received; + int deferred; + int overflow; +}; + +struct netif { + struct netif_driver *nif_driver; + int nif_unit; + int nif_sel; + void *nif_devdata; +}; + +extern struct netif_driver *netif_drivers[]; /* machdep */ +extern int n_netif_drivers; + +extern int netif_debug; + +void netif_init(void); +struct netif *netif_select(void *); +int netif_probe(struct netif *, void *); +void netif_attach(struct netif *, struct iodesc *, void *); +void netif_detach(struct netif *); +ssize_t netif_get(struct iodesc *, void **, time_t); +ssize_t netif_put(struct iodesc *, void *, size_t); + +int netif_open(void *); +int netif_close(int); + +struct iodesc *socktodesc(int); + +#endif /* __SYS_LIBNETBOOT_NETIF_H */ diff --git a/stand/libsa/nfs.c b/stand/libsa/nfs.c new file mode 100644 index 000000000000..7e2e1ababacc --- /dev/null +++ b/stand/libsa/nfs.c @@ -0,0 +1,860 @@ +/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ + +/*- + * Copyright (c) 1993 John Brezak + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <string.h> +#include <stddef.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include "rpcv2.h" +#include "nfsv2.h" + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" + +#define NFS_DEBUGxx + +#define NFSREAD_MIN_SIZE 1024 +#define NFSREAD_MAX_SIZE 16384 + +/* NFSv3 definitions */ +#define NFS_V3MAXFHSIZE 64 +#define NFS_VER3 3 +#define RPCMNT_VER3 3 +#define NFSPROCV3_LOOKUP 3 +#define NFSPROCV3_READLINK 5 +#define NFSPROCV3_READ 6 +#define NFSPROCV3_READDIR 16 + +typedef struct { + uint32_t val[2]; +} n_quad; + +struct nfsv3_time { + uint32_t nfs_sec; + uint32_t nfs_nsec; +}; + +struct nfsv3_fattrs { + uint32_t fa_type; + uint32_t fa_mode; + uint32_t fa_nlink; + uint32_t fa_uid; + uint32_t fa_gid; + n_quad fa_size; + n_quad fa_used; + n_quad fa_rdev; + n_quad fa_fsid; + n_quad fa_fileid; + struct nfsv3_time fa_atime; + struct nfsv3_time fa_mtime; + struct nfsv3_time fa_ctime; +}; + +/* + * For NFSv3, the file handle is variable in size, so most fixed sized + * structures for arguments won't work. For most cases, a structure + * that starts with any fixed size section is followed by an array + * that covers the maximum size required. + */ +struct nfsv3_readdir_repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t cookiev0; + uint32_t cookiev1; +}; + +struct nfsv3_readdir_entry { + uint32_t follows; + uint32_t fid0; + uint32_t fid1; + uint32_t len; + uint32_t nameplus[0]; +}; + +struct nfs_iodesc { + struct iodesc *iodesc; + off_t off; + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + struct nfsv3_fattrs fa; /* all in network order */ + uint64_t cookie; +}; + +/* + * XXX interactions with tftp? See nfswrapper.c for a confusing + * issue. + */ +int nfs_open(const char *path, struct open_file *f); +static int nfs_close(struct open_file *f); +static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t nfs_seek(struct open_file *f, off_t offset, int where); +static int nfs_stat(struct open_file *f, struct stat *sb); +static int nfs_readdir(struct open_file *f, struct dirent *d); + +struct nfs_iodesc nfs_root_node; + +struct fs_ops nfs_fsops = { + "nfs", + nfs_open, + nfs_close, + nfs_read, + nfs_write, + nfs_seek, + nfs_stat, + nfs_readdir +}; + +static int nfs_read_size = NFSREAD_MIN_SIZE; + +/* + * Improve boot performance over NFS + */ +static void +set_nfs_read_size(void) +{ + char *env, *end; + char buf[10]; + + if ((env = getenv("nfs.read_size")) != NULL) { + errno = 0; + nfs_read_size = (int)strtol(env, &end, 0); + if (errno != 0 || *env == '\0' || *end != '\0') { + printf("%s: bad value: \"%s\", defaulting to %d\n", + "nfs.read_size", env, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MIN_SIZE; + } + } + if (nfs_read_size < NFSREAD_MIN_SIZE) { + printf("%s: bad value: \"%d\", defaulting to %d\n", + "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MIN_SIZE; + } + if (nfs_read_size > NFSREAD_MAX_SIZE) { + printf("%s: bad value: \"%d\", defaulting to %d\n", + "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MAX_SIZE; + } + snprintf(buf, sizeof (buf), "%d", nfs_read_size); + setenv("nfs.read_size", buf, 1); +} + +/* + * Fetch the root file handle (call mount daemon) + * Return zero or error number. + */ +int +nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) +{ + void *pkt = NULL; + int len; + struct args { + uint32_t len; + char path[FNAME_SIZE]; + } *args; + struct repl { + uint32_t errno; + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + uint32_t authcnt; + uint32_t auth[7]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + size_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_getrootfh: %s\n", path); +#endif + + args = &sdata.d; + + bzero(args, sizeof(*args)); + len = strlen(path); + if (len > sizeof(args->path)) + len = sizeof(args->path); + args->len = htonl(len); + bcopy(path, args->path, len); + len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); + + cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, + args, len, (void **)&repl, &pkt); + if (cc == -1) { + free(pkt); + /* errno was set by rpc_call */ + return (errno); + } + if (cc < 2 * sizeof (uint32_t)) { + free(pkt); + return (EBADRPC); + } + if (repl->errno != 0) { + free(pkt); + return (ntohl(repl->errno)); + } + *fhlenp = ntohl(repl->fhsize); + bcopy(repl->fh, fhp, *fhlenp); + + set_nfs_read_size(); + free(pkt); + return (0); +} + +/* + * Lookup a file. Store handle and attributes. + * Return zero or error number. + */ +int +nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) +{ + void *pkt = NULL; + int len, rlen, pos; + struct args { + uint32_t fhsize; + uint32_t fhplusname[1 + + (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; + } *args; + struct repl { + uint32_t errno; + uint32_t fhsize; + uint32_t fhplusattr[(NFS_V3MAXFHSIZE + + 2 * (sizeof(uint32_t) + + sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + ssize_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("lookupfh: called\n"); +#endif + + args = &sdata.d; + + bzero(args, sizeof(*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fhplusname, d->fhsize); + len = strlen(name); + if (len > FNAME_SIZE) + len = FNAME_SIZE; + pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + args->fhplusname[pos++] = htonl(len); + bcopy(name, &args->fhplusname[pos], len); + len = sizeof(uint32_t) + pos * sizeof(uint32_t) + + roundup(len, sizeof(uint32_t)); + + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, + args, len, (void **)&repl, &pkt); + if (cc == -1) { + free(pkt); + return (errno); /* XXX - from rpc_call */ + } + if (cc < 2 * sizeof(uint32_t)) { + free(pkt); + return (EIO); + } + if (repl->errno != 0) { + free(pkt); + /* saerrno.h now matches NFS error numbers. */ + return (ntohl(repl->errno)); + } + newfd->fhsize = ntohl(repl->fhsize); + bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); + pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + if (repl->fhplusattr[pos++] == 0) { + free(pkt); + return (EIO); + } + bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); + free(pkt); + return (0); +} + +#ifndef NFS_NOSYMLINK +/* + * Get the destination of a symbolic link. + */ +int +nfs_readlink(struct nfs_iodesc *d, char *buf) +{ + void *pkt = NULL; + struct args { + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + } *args; + struct repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t len; + u_char path[NFS_MAXPATHLEN]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + ssize_t cc; + int rc = 0; + +#ifdef NFS_DEBUG + if (debug) + printf("readlink: called\n"); +#endif + + args = &sdata.d; + + bzero(args, sizeof(*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fh, d->fhsize); + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, + args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), + (void **)&repl, &pkt); + if (cc == -1) + return (errno); + + if (cc < 2 * sizeof(uint32_t)) { + rc = EIO; + goto done; + } + + if (repl->errno != 0) { + rc = ntohl(repl->errno); + goto done; + } + + if (repl->ok == 0) { + rc = EIO; + goto done; + } + + repl->len = ntohl(repl->len); + if (repl->len > NFS_MAXPATHLEN) { + rc = ENAMETOOLONG; + goto done; + } + + bcopy(repl->path, buf, repl->len); + buf[repl->len] = 0; +done: + free(pkt); + return (rc); +} +#endif + +/* + * Read data from a file. + * Return transfer count or -1 (and set errno) + */ +ssize_t +nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) +{ + void *pkt = NULL; + struct args { + uint32_t fhsize; + uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; + } *args; + struct repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t count; + uint32_t eof; + uint32_t len; + u_char data[NFSREAD_MAX_SIZE]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + size_t cc; + long x; + int hlen, rlen, pos; + + args = &sdata.d; + + bzero(args, sizeof(*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fhoffcnt, d->fhsize); + pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + args->fhoffcnt[pos++] = 0; + args->fhoffcnt[pos++] = htonl((uint32_t)off); + if (len > nfs_read_size) + len = nfs_read_size; + args->fhoffcnt[pos] = htonl((uint32_t)len); + hlen = offsetof(struct repl, data[0]); + + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, + args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), + (void **)&repl, &pkt); + if (cc == -1) { + /* errno was already set by rpc_call */ + return (-1); + } + if (cc < hlen) { + errno = EBADRPC; + free(pkt); + return (-1); + } + if (repl->errno != 0) { + errno = ntohl(repl->errno); + free(pkt); + return (-1); + } + rlen = cc - hlen; + x = ntohl(repl->count); + if (rlen < x) { + printf("nfsread: short packet, %d < %ld\n", rlen, x); + errno = EBADRPC; + free(pkt); + return (-1); + } + bcopy(repl->data, addr, x); + free(pkt); + return (x); +} + +/* + * Open a file. + * return zero or error number + */ +int +nfs_open(const char *upath, struct open_file *f) +{ + struct iodesc *desc; + struct nfs_iodesc *currfd; + char buf[2 * NFS_V3MAXFHSIZE + 3]; + u_char *fh; + char *cp; + int i; +#ifndef NFS_NOSYMLINK + struct nfs_iodesc *newfd; + struct nfsv3_fattrs *fa; + char *ncp; + int c; + char namebuf[NFS_MAXPATHLEN + 1]; + char linkbuf[NFS_MAXPATHLEN + 1]; + int nlinks = 0; +#endif + int error; + char *path; + + if (netproto != NET_NFS) + return (EINVAL); + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); +#endif + if (!rootpath[0]) { + printf("no rootpath, no nfs\n"); + return (ENXIO); + } + + if (f->f_dev->dv_type != DEVT_NET) + return (EINVAL); + + if (!(desc = socktodesc(*(int *)(f->f_devdata)))) + return (EINVAL); + + /* Bind to a reserved port. */ + desc->myport = htons(--rpc_port); + desc->destip = rootip; + if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, + nfs_root_node.fh))) + return (error); + nfs_root_node.fa.fa_type = htonl(NFDIR); + nfs_root_node.fa.fa_mode = htonl(0755); + nfs_root_node.fa.fa_nlink = htonl(2); + nfs_root_node.iodesc = desc; + + fh = &nfs_root_node.fh[0]; + buf[0] = 'X'; + cp = &buf[1]; + for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) + sprintf(cp, "%02x", fh[i]); + sprintf(cp, "X"); + setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); + setenv("boot.nfsroot.path", rootpath, 1); + setenv("boot.nfsroot.nfshandle", buf, 1); + sprintf(buf, "%d", nfs_root_node.fhsize); + setenv("boot.nfsroot.nfshandlelen", buf, 1); + + /* Allocate file system specific data structure */ + currfd = malloc(sizeof(*newfd)); + if (currfd == NULL) { + error = ENOMEM; + goto out; + } +#ifndef NFS_NOSYMLINK + bcopy(&nfs_root_node, currfd, sizeof(*currfd)); + newfd = NULL; + + cp = path = strdup(upath); + if (path == NULL) { + error = ENOMEM; + goto out; + } + while (*cp) { + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + + if (*cp == '\0') + break; + /* + * Check that current node is a directory. + */ + if (currfd->fa.fa_type != htonl(NFDIR)) { + error = ENOTDIR; + goto out; + } + + /* allocate file system specific data structure */ + newfd = malloc(sizeof(*newfd)); + if (newfd == NULL) { + error = ENOMEM; + goto out; + } + newfd->iodesc = currfd->iodesc; + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > NFS_MAXNAMLEN) { + error = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* lookup a file handle */ + error = nfs_lookupfh(currfd, ncp, newfd); + *cp = c; + if (error) + goto out; + + /* + * Check for symbolic link + */ + if (newfd->fa.fa_type == htonl(NFLNK)) { + int link_len, len; + + error = nfs_readlink(newfd, linkbuf); + if (error) + goto out; + + link_len = strlen(linkbuf); + len = strlen(cp); + + if (link_len + len > MAXPATHLEN + || ++nlinks > MAXSYMLINKS) { + error = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + bcopy(linkbuf, namebuf, link_len); + + /* + * If absolute pathname, restart at root. + * If relative pathname, restart at parent directory. + */ + cp = namebuf; + if (*cp == '/') + bcopy(&nfs_root_node, currfd, sizeof(*currfd)); + + free(newfd); + newfd = NULL; + + continue; + } + + free(currfd); + currfd = newfd; + newfd = NULL; + } + + error = 0; + +out: + free(newfd); + free(path); +#else + currfd->iodesc = desc; + + error = nfs_lookupfh(&nfs_root_node, upath, currfd); +#endif + if (!error) { + currfd->off = 0; + currfd->cookie = 0; + f->f_fsdata = (void *)currfd; + return (0); + } + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s lookupfh failed: %s\n", + path, strerror(error)); +#endif + free(currfd); + + return (error); +} + +int +nfs_close(struct open_file *f) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_close: fp=0x%lx\n", (u_long)fp); +#endif + + free(fp); + f->f_fsdata = NULL; + + return (0); +} + +/* + * read a portion of a file + */ +int +nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + ssize_t cc; + char *addr = buf; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: size=%lu off=%d\n", (u_long)size, + (int)fp->off); +#endif + while ((int)size > 0) { + twiddle(16); + cc = nfs_readdata(fp, fp->off, (void *)addr, size); + /* XXX maybe should retry on certain errors */ + if (cc == -1) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: read: %s", strerror(errno)); +#endif + return (errno); /* XXX - from nfs_readdata */ + } + if (cc == 0) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: hit EOF unexpectantly"); +#endif + goto ret; + } + fp->off += cc; + addr += cc; + size -= cc; + } +ret: + if (resid) + *resid = size; + + return (0); +} + +/* + * Not implemented. + */ +int +nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + return (EROFS); +} + +off_t +nfs_seek(struct open_file *f, off_t offset, int where) +{ + struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; + uint32_t size = ntohl(d->fa.fa_size.val[1]); + + switch (where) { + case SEEK_SET: + d->off = offset; + break; + case SEEK_CUR: + d->off += offset; + break; + case SEEK_END: + d->off = size - offset; + break; + default: + errno = EINVAL; + return (-1); + } + + return (d->off); +} + +/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ +int nfs_stat_types[9] = { + 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; + +int +nfs_stat(struct open_file *f, struct stat *sb) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + uint32_t ftype, mode; + + ftype = ntohl(fp->fa.fa_type); + mode = ntohl(fp->fa.fa_mode); + mode |= nfs_stat_types[ftype & 7]; + + sb->st_mode = mode; + sb->st_nlink = ntohl(fp->fa.fa_nlink); + sb->st_uid = ntohl(fp->fa.fa_uid); + sb->st_gid = ntohl(fp->fa.fa_gid); + sb->st_size = ntohl(fp->fa.fa_size.val[1]); + + return (0); +} + +static int +nfs_readdir(struct open_file *f, struct dirent *d) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + struct nfsv3_readdir_repl *repl; + struct nfsv3_readdir_entry *rent; + static void *pkt = NULL; + static char *buf; + static struct nfs_iodesc *pfp = NULL; + static uint64_t cookie = 0; + size_t cc; + int pos, rc; + + struct args { + uint32_t fhsize; + uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; + } *args; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + + if (fp != pfp || fp->off != cookie) { + pfp = NULL; + refill: + free(pkt); + pkt = NULL; + args = &sdata.d; + bzero(args, sizeof(*args)); + + args->fhsize = htonl(fp->fhsize); + bcopy(fp->fh, args->fhpluscookie, fp->fhsize); + pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + args->fhpluscookie[pos++] = htonl(fp->off >> 32); + args->fhpluscookie[pos++] = htonl(fp->off); + args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); + args->fhpluscookie[pos++] = htonl(fp->cookie); + args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); + + cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, + args, 6 * sizeof(uint32_t) + + roundup(fp->fhsize, sizeof(uint32_t)), + (void **)&buf, &pkt); + if (cc == -1) { + rc = errno; + goto err; + } + repl = (struct nfsv3_readdir_repl *)buf; + if (repl->errno != 0) { + rc = ntohl(repl->errno); + goto err; + } + pfp = fp; + cookie = fp->off; + fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | + ntohl(repl->cookiev1); + buf += sizeof (struct nfsv3_readdir_repl); + } + rent = (struct nfsv3_readdir_entry *)buf; + + if (rent->follows == 0) { + /* fid0 is actually eof */ + if (rent->fid0 != 0) { + rc = ENOENT; + goto err; + } + goto refill; + } + + d->d_namlen = ntohl(rent->len); + bcopy(rent->nameplus, d->d_name, d->d_namlen); + d->d_name[d->d_namlen] = '\0'; + + pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); + fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | + ntohl(rent->nameplus[pos + 1]); + pos += 2; + buf = (u_char *)&rent->nameplus[pos]; + return (0); + +err: + free(pkt); + pkt = NULL; + pfp = NULL; + cookie = 0; + return (rc); +} diff --git a/stand/libsa/nfsv2.h b/stand/libsa/nfsv2.h new file mode 100644 index 000000000000..09b2428b8012 --- /dev/null +++ b/stand/libsa/nfsv2.h @@ -0,0 +1,121 @@ +/* $FreeBSD$ */ +/* $NetBSD: nfsv2.h,v 1.2 1996/02/26 23:05:23 gwr Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)nfsv2.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * nfs definitions as per the version 2 specs + */ + +/* + * Constants as defined in the Sun NFS Version 2 spec. + * "NFS: Network File System Protocol Specification" RFC1094 + */ + +#define NFS_PORT 2049 +#define NFS_PROG 100003 +#define NFS_VER2 2 +#define NFS_MAXDGRAMDATA 8192 +#define NFS_MAXDATA 32768 +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_FHSIZE 32 +#define NFS_MAXPKTHDR 404 +#define NFS_MAXPACKET (NFS_MAXPKTHDR+NFS_MAXDATA) +#define NFS_MINPACKET 20 +#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ +#define NFS_READDIRSIZE 1024 + +/* Stat numbers for rpc returns */ +#define NFS_OK 0 +#define NFSERR_PERM 1 +#define NFSERR_NOENT 2 +#define NFSERR_IO 5 +#define NFSERR_NXIO 6 +#define NFSERR_ACCES 13 +#define NFSERR_EXIST 17 +#define NFSERR_NODEV 19 +#define NFSERR_NOTDIR 20 +#define NFSERR_ISDIR 21 +#define NFSERR_FBIG 27 +#define NFSERR_NOSPC 28 +#define NFSERR_ROFS 30 +#define NFSERR_NAMETOL 63 +#define NFSERR_NOTEMPTY 66 +#define NFSERR_DQUOT 69 +#define NFSERR_STALE 70 +#define NFSERR_WFLUSH 99 + +/* Sizes in bytes of various nfs rpc components */ +#define NFSX_FH 32 +#define NFSX_UNSIGNED 4 +#define NFSX_FATTR 68 +#define NFSX_SATTR 32 +#define NFSX_STATFS 20 +#define NFSX_COOKIE 4 + +/* nfs rpc procedure numbers */ +#define NFSPROC_NULL 0 +#define NFSPROC_GETATTR 1 +#define NFSPROC_SETATTR 2 +#define NFSPROC_NOOP 3 +#define NFSPROC_ROOT NFSPROC_NOOP /* Obsolete */ +#define NFSPROC_LOOKUP 4 +#define NFSPROC_READLINK 5 +#define NFSPROC_READ 6 +#define NFSPROC_WRITECACHE NFSPROC_NOOP /* Obsolete */ +#define NFSPROC_WRITE 8 +#define NFSPROC_CREATE 9 +#define NFSPROC_REMOVE 10 +#define NFSPROC_RENAME 11 +#define NFSPROC_LINK 12 +#define NFSPROC_SYMLINK 13 +#define NFSPROC_MKDIR 14 +#define NFSPROC_RMDIR 15 +#define NFSPROC_READDIR 16 +#define NFSPROC_STATFS 17 + +#define NFS_NPROCS 18 + + +/* File types */ +typedef enum { + NFNON=0, + NFREG=1, + NFDIR=2, + NFBLK=3, + NFCHR=4, + NFLNK=5 +} nfstype; diff --git a/stand/libsa/nullfs.c b/stand/libsa/nullfs.c new file mode 100644 index 000000000000..7773d16a82f6 --- /dev/null +++ b/stand/libsa/nullfs.c @@ -0,0 +1,105 @@ +/* $NetBSD: nullfs.c,v 1.1 1996/01/13 22:25:39 leo Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)open.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +/* + * Null filesystem + */ +int null_open (const char *path, struct open_file *f) +{ + return EINVAL; +} + +int null_close(struct open_file *f) +{ + return 0; +} + +int null_read (struct open_file *f, void *buf, size_t size, size_t *resid) +{ + return EIO; +} + +int null_write (struct open_file *f, void *buf, size_t size, size_t *resid) +{ + return EIO; +} + +off_t null_seek (struct open_file *f, off_t offset, int where) +{ + errno = EIO; + return -1; +} + +int null_stat (struct open_file *f, struct stat *sb) +{ + return EIO; +} + +int null_readdir(struct open_file *f, struct dirent *d) +{ + return EIO; +} diff --git a/stand/libsa/open.c b/stand/libsa/open.c new file mode 100644 index 000000000000..2ae17314bc54 --- /dev/null +++ b/stand/libsa/open.c @@ -0,0 +1,159 @@ +/* $NetBSD: open.c,v 1.16 1997/01/28 09:41:03 pk Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)open.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +struct fs_ops *exclusive_file_system; + +struct open_file files[SOPEN_MAX]; + +static int +o_gethandle(void) +{ + int fd; + + for (fd = 0; fd < SOPEN_MAX; fd++) + if (files[fd].f_flags == 0) + return(fd); + return(-1); +} + +static void +o_rainit(struct open_file *f) +{ + f->f_rabuf = malloc(SOPEN_RASIZE); + f->f_ralen = 0; + f->f_raoffset = 0; +} + +int +open(const char *fname, int mode) +{ + struct fs_ops *fs; + struct open_file *f; + int fd, i, error, besterror; + const char *file; + + if ((fd = o_gethandle()) == -1) { + errno = EMFILE; + return(-1); + } + + f = &files[fd]; + f->f_flags = mode + 1; + f->f_dev = (struct devsw *)0; + f->f_ops = (struct fs_ops *)0; + f->f_offset = 0; + f->f_devdata = NULL; + file = (char *)0; + + if (exclusive_file_system != NULL) { + fs = exclusive_file_system; + error = (fs->fo_open)(fname, f); + if (error == 0) + goto ok; + goto err; + } + + error = devopen(f, fname, &file); + if (error || + (((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0)) + goto err; + + /* see if we opened a raw device; otherwise, 'file' is the file name. */ + if (file == (char *)0 || *file == '\0') { + f->f_flags |= F_RAW; + f->f_rabuf = NULL; + return (fd); + } + + /* pass file name to the different filesystem open routines */ + besterror = ENOENT; + for (i = 0; file_system[i] != NULL; i++) { + fs = file_system[i]; + error = (fs->fo_open)(file, f); + if (error == 0) + goto ok; + if (error != EINVAL) + besterror = error; + } + error = besterror; + + fail: + if ((f->f_flags & F_NODEV) == 0 && f->f_dev != NULL) + f->f_dev->dv_close(f); + if (error) + devclose(f); + + err: + f->f_flags = 0; + errno = error; + return (-1); + + ok: + f->f_ops = fs; + o_rainit(f); + return (fd); +} diff --git a/stand/libsa/pager.c b/stand/libsa/pager.c new file mode 100644 index 000000000000..a966b0bd7992 --- /dev/null +++ b/stand/libsa/pager.c @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 AUTHOR 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 AUTHOR 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. + */ +/* + * Simple paged-output and paged-viewing functions + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" +#include <string.h> + +static int p_maxlines = -1; +static int p_freelines; + +static char *pager_prompt1 = " --more-- <space> page down <enter> line down <q> quit "; +static char *pager_blank = " "; + +/* + * 'open' the pager + */ +void +pager_open(void) +{ + int nlines; + char *cp, *lp; + + nlines = 24; /* sensible default */ + if ((cp = getenv("LINES")) != NULL) { + nlines = strtol(cp, &lp, 0); + } + + p_maxlines = nlines - 1; + if (p_maxlines < 1) + p_maxlines = 1; + p_freelines = p_maxlines; +} + +/* + * 'close' the pager + */ +void +pager_close(void) +{ + p_maxlines = -1; +} + +/* + * Emit lines to the pager; may not return until the user + * has responded to the prompt. + * + * Will return nonzero if the user enters 'q' or 'Q' at the prompt. + * + * XXX note that this watches outgoing newlines (and eats them), but + * does not handle wrap detection (req. count of columns). + */ + +int +pager_output(const char *cp) +{ + int action; + + if (cp == NULL) + return(0); + + for (;;) { + if (*cp == 0) + return(0); + + putchar(*cp); /* always emit character */ + + if (*(cp++) == '\n') { /* got a newline? */ + p_freelines--; + if (p_freelines <= 0) { + printf("%s", pager_prompt1); + action = 0; + while (action == 0) { + switch(getchar()) { + case '\r': + case '\n': + p_freelines = 1; + action = 1; + break; + case ' ': + p_freelines = p_maxlines; + action = 1; + break; + case 'q': + case 'Q': + action = 2; + break; + default: + break; + } + } + printf("\r%s\r", pager_blank); + if (action == 2) + return(1); + } + } + } +} + +/* + * Display from (fd). + */ +int +pager_file(const char *fname) +{ + char buf[80]; + size_t hmuch; + int fd; + int result; + + if ((fd = open(fname, O_RDONLY)) == -1) { + printf("can't open '%s': %s\n", fname, strerror(errno)); + return(-1); + } + + for (;;) { + hmuch = read(fd, buf, sizeof(buf) - 1); + if (hmuch == -1) { + result = -1; + break; + } + if (hmuch == 0) { + result = 0; + break; + } + buf[hmuch] = 0; + if (pager_output(buf)) { + result = 1; + break; + } + } + close(fd); + return(result); +} diff --git a/stand/libsa/panic.c b/stand/libsa/panic.c new file mode 100644 index 000000000000..6e4c76d0e031 --- /dev/null +++ b/stand/libsa/panic.c @@ -0,0 +1,59 @@ +/* + * $NetBSD: panic.c,v 1.2 1997/03/22 01:48:36 thorpej Exp $ + */ +/*- + * Copyright (c) 1996 + * Matthias Drochner. 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 for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <machine/stdarg.h> + +extern void exit(int) __dead2; + +void +panic(const char *fmt,...) +{ + va_list ap; + + printf("panic: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + + printf("--> Press a key on the console to reboot <--\n"); + getchar(); + printf("Rebooting...\n"); + exit(1); +} diff --git a/stand/libsa/pkgfs.c b/stand/libsa/pkgfs.c new file mode 100644 index 000000000000..fda7f607087d --- /dev/null +++ b/stand/libsa/pkgfs.c @@ -0,0 +1,791 @@ +/*- + * Copyright (c) 2007-2014, Juniper Networks, 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +#include <sys/stat.h> +#include <sys/stdint.h> +#include <string.h> +#include <zlib.h> + +#ifdef PKGFS_DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +static int pkg_open(const char *, struct open_file *); +static int pkg_close(struct open_file *); +static int pkg_read(struct open_file *, void *, size_t, size_t *); +static off_t pkg_seek(struct open_file *, off_t, int); +static int pkg_stat(struct open_file *, struct stat *); +static int pkg_readdir(struct open_file *, struct dirent *); + +struct fs_ops pkgfs_fsops = { + "pkg", + pkg_open, + pkg_close, + pkg_read, + null_write, + pkg_seek, + pkg_stat, + pkg_readdir +}; + +#define PKG_BUFSIZE 512 +#define PKG_MAXCACHESZ 4096 + +#define PKG_FILEEXT ".tgz" + +/* + * Layout of POSIX 'ustar' header. + */ +struct ustar_hdr { + char ut_name[100]; + char ut_mode[8]; + char ut_uid[8]; + char ut_gid[8]; + char ut_size[12]; + char ut_mtime[12]; + char ut_checksum[8]; + char ut_typeflag[1]; + char ut_linkname[100]; + char ut_magic[6]; /* For POSIX: "ustar\0" */ + char ut_version[2]; /* For POSIX: "00" */ + char ut_uname[32]; + char ut_gname[32]; + char ut_rdevmajor[8]; + char ut_rdevminor[8]; + union { + struct { + char prefix[155]; + } posix; + struct { + char atime[12]; + char ctime[12]; + char offset[12]; + char longnames[4]; + char unused[1]; + struct gnu_sparse { + char offset[12]; + char numbytes[12]; + } sparse[4]; + char isextended[1]; + char realsize[12]; + } gnu; + } u; + u_char __padding[12]; +}; + +struct package; + +struct tarfile +{ + struct package *tf_pkg; + struct tarfile *tf_next; + struct ustar_hdr tf_hdr; + off_t tf_ofs; + off_t tf_size; + off_t tf_fp; + size_t tf_cachesz; + void *tf_cache; +}; + +struct package +{ + struct package *pkg_chain; + int pkg_fd; + off_t pkg_ofs; + z_stream pkg_zs; + struct tarfile *pkg_first; + struct tarfile *pkg_last; + u_char pkg_buf[PKG_BUFSIZE]; +}; + +static struct package *package = NULL; + +static int new_package(int, struct package **); + +void +pkgfs_cleanup(void) +{ + struct package *chain; + struct tarfile *tf, *tfn; + + while (package != NULL) { + inflateEnd(&package->pkg_zs); + close(package->pkg_fd); + + tf = package->pkg_first; + while (tf != NULL) { + tfn = tf->tf_next; + if (tf->tf_cachesz > 0) + free(tf->tf_cache); + free(tf); + tf = tfn; + } + + chain = package->pkg_chain; + free(package); + package = chain; + } +} + +int +pkgfs_init(const char *pkgname, struct fs_ops *proto) +{ + struct package *pkg; + int error, fd; + + if (proto != &pkgfs_fsops) + pkgfs_cleanup(); + + exclusive_file_system = proto; + + fd = open(pkgname, O_RDONLY); + + exclusive_file_system = NULL; + + if (fd == -1) + return (errno); + + error = new_package(fd, &pkg); + if (error) { + close(fd); + return (error); + } + + if (pkg == NULL) + return (EDOOFUS); + + pkg->pkg_chain = package; + package = pkg; + exclusive_file_system = &pkgfs_fsops; + return (0); +} + +static int get_mode(struct tarfile *); +static int get_zipped(struct package *, void *, size_t); +static int new_package(int, struct package **); +static struct tarfile *scan_tarfile(struct package *, struct tarfile *); + +static int +pkg_open(const char *fn, struct open_file *f) +{ + struct tarfile *tf; + + if (fn == NULL || f == NULL) + return (EINVAL); + + if (package == NULL) + return (ENXIO); + + /* + * We can only read from a package, so reject request to open + * for write-only or read-write. + */ + if (f->f_flags != F_READ) + return (EPERM); + + /* + * Scan the file headers for the named file. We stop scanning + * at the first filename that has the .pkg extension. This is + * a package within a package. We assume we have all the files + * we need up-front and without having to dig within nested + * packages. + * + * Note that we preserve streaming properties as much as possible. + */ + while (*fn == '/') + fn++; + + /* + * Allow opening of the root directory for use by readdir() + * to support listing files in the package. + */ + if (*fn == '\0') { + f->f_fsdata = NULL; + return (0); + } + + tf = scan_tarfile(package, NULL); + while (tf != NULL) { + if (strcmp(fn, tf->tf_hdr.ut_name) == 0) { + f->f_fsdata = tf; + tf->tf_fp = 0; /* Reset the file pointer. */ + return (0); + } + tf = scan_tarfile(package, tf); + } + return (errno); +} + +static int +pkg_close(struct open_file *f) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) + return (0); + + /* + * Free up the cache if we read all of the file. + */ + if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) { + free(tf->tf_cache); + tf->tf_cachesz = 0; + } + return (0); +} + +static int +pkg_read(struct open_file *f, void *buf, size_t size, size_t *res) +{ + struct tarfile *tf; + char *p; + off_t fp; + size_t sz; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) { + if (res != NULL) + *res = size; + return (EBADF); + } + + fp = tf->tf_fp; + p = buf; + sz = 0; + while (size > 0) { + sz = tf->tf_size - fp; + if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size) + sz = tf->tf_cachesz - fp; + if (size < sz) + sz = size; + if (sz == 0) + break; + + if (fp < tf->tf_cachesz) { + /* Satisfy the request from cache. */ + memcpy(p, tf->tf_cache + fp, sz); + fp += sz; + p += sz; + size -= sz; + continue; + } + + if (get_zipped(tf->tf_pkg, p, sz) == -1) { + sz = -1; + break; + } + + fp += sz; + p += sz; + size -= sz; + + if (tf->tf_cachesz != 0) + continue; + + tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ; + tf->tf_cache = malloc(tf->tf_cachesz); + if (tf->tf_cache != NULL) + memcpy(tf->tf_cache, buf, tf->tf_cachesz); + else + tf->tf_cachesz = 0; + } + + tf->tf_fp = fp; + if (res != NULL) + *res = size; + return ((sz == -1) ? errno : 0); +} + +static off_t +pkg_seek(struct open_file *f, off_t ofs, int whence) +{ + char buf[512]; + struct tarfile *tf; + off_t delta; + size_t sz, res; + int error; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) { + errno = EBADF; + return (-1); + } + + switch (whence) { + case SEEK_SET: + delta = ofs - tf->tf_fp; + break; + case SEEK_CUR: + delta = ofs; + break; + case SEEK_END: + delta = tf->tf_size - tf->tf_fp + ofs; + break; + default: + errno = EINVAL; + return (-1); + } + + if (delta < 0) { + DBG(("%s: negative file seek (%jd)\n", __func__, + (intmax_t)delta)); + errno = ESPIPE; + return (-1); + } + + while (delta > 0 && tf->tf_fp < tf->tf_size) { + sz = (delta > sizeof(buf)) ? sizeof(buf) : delta; + error = pkg_read(f, buf, sz, &res); + if (error != 0) { + errno = error; + return (-1); + } + delta -= sz - res; + } + + return (tf->tf_fp); +} + +static int +pkg_stat(struct open_file *f, struct stat *sb) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) + return (EBADF); + memset(sb, 0, sizeof(*sb)); + sb->st_mode = get_mode(tf); + sb->st_size = tf->tf_size; + sb->st_blocks = (tf->tf_size + 511) / 512; + return (0); +} + +static int +pkg_readdir(struct open_file *f, struct dirent *d) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf != NULL) + return (EBADF); + + tf = scan_tarfile(package, NULL); + if (tf == NULL) + return (ENOENT); + + d->d_fileno = 0; + d->d_reclen = sizeof(*d); + d->d_type = DT_REG; + memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name)); + return (0); +} + +/* + * Low-level support functions. + */ + +static int +get_byte(struct package *pkg, off_t *op) +{ + int c; + + if (pkg->pkg_zs.avail_in == 0) { + c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); + if (c <= 0) + return (-1); + pkg->pkg_zs.avail_in = c; + pkg->pkg_zs.next_in = pkg->pkg_buf; + } + + c = *pkg->pkg_zs.next_in; + pkg->pkg_zs.next_in++; + pkg->pkg_zs.avail_in--; + (*op)++; + return (c); +} + +static int +get_zipped(struct package *pkg, void *buf, size_t bufsz) +{ + int c; + + pkg->pkg_zs.next_out = buf; + pkg->pkg_zs.avail_out = bufsz; + + while (pkg->pkg_zs.avail_out) { + if (pkg->pkg_zs.avail_in == 0) { + c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); + if (c <= 0) { + errno = EIO; + return (-1); + } + pkg->pkg_zs.avail_in = c; + pkg->pkg_zs.next_in = pkg->pkg_buf; + } + + c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH); + if (c != Z_OK && c != Z_STREAM_END) { + errno = EIO; + return (-1); + } + } + + pkg->pkg_ofs += bufsz; + return (0); +} + +static int +cache_data(struct tarfile *tf) +{ + struct package *pkg; + size_t sz; + + if (tf == NULL) { + DBG(("%s: no file to cache data for?\n", __func__)); + errno = EINVAL; + return (-1); + } + + pkg = tf->tf_pkg; + if (pkg == NULL) { + DBG(("%s: no package associated with file?\n", __func__)); + errno = EINVAL; + return (-1); + } + + if (tf->tf_ofs != pkg->pkg_ofs) { + DBG(("%s: caching after partial read of file %s?\n", + __func__, tf->tf_hdr.ut_name)); + errno = EINVAL; + return (-1); + } + + /* We don't cache everything... */ + if (tf->tf_size > PKG_MAXCACHESZ) { + errno = ENOMEM; + return (-1); + } + + /* All files are padded to a multiple of 512 bytes. */ + sz = (tf->tf_size + 0x1ff) & ~0x1ff; + + tf->tf_cache = malloc(sz); + if (tf->tf_cache == NULL) { + DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz)); + errno = ENOMEM; + return (-1); + } + + tf->tf_cachesz = sz; + return (get_zipped(pkg, tf->tf_cache, sz)); +} + +/* + * Note that this implementation does not (and should not!) obey + * locale settings; you cannot simply substitute strtol here, since + * it does obey locale. + */ +static off_t +pkg_atol8(const char *p, unsigned char_cnt) +{ + int64_t l, limit, last_digit_limit; + int digit, sign, base; + + base = 8; + limit = INT64_MAX / base; + last_digit_limit = INT64_MAX % base; + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '-') { + sign = -1; + p++; + } else + sign = 1; + + l = 0; + digit = *p - '0'; + while (digit >= 0 && digit < base && char_cnt-- > 0) { + if (l>limit || (l == limit && digit > last_digit_limit)) { + l = UINT64_MAX; /* Truncate on overflow. */ + break; + } + l = (l * base) + digit; + digit = *++p - '0'; + } + return (sign < 0) ? -l : l; +} + +/* + * Parse a base-256 integer. This is just a straight signed binary + * value in big-endian order, except that the high-order bit is + * ignored. Remember that "int64_t" may or may not be exactly 64 + * bits; the implementation here tries to avoid making any assumptions + * about the actual size of an int64_t. It does assume we're using + * twos-complement arithmetic, though. + */ +static int64_t +pkg_atol256(const char *_p, unsigned char_cnt) +{ + int64_t l, upper_limit, lower_limit; + const unsigned char *p = (const unsigned char *)_p; + + upper_limit = INT64_MAX / 256; + lower_limit = INT64_MIN / 256; + + /* Pad with 1 or 0 bits, depending on sign. */ + if ((0x40 & *p) == 0x40) + l = (int64_t)-1; + else + l = 0; + l = (l << 6) | (0x3f & *p++); + while (--char_cnt > 0) { + if (l > upper_limit) { + l = INT64_MAX; /* Truncate on overflow */ + break; + } else if (l < lower_limit) { + l = INT64_MIN; + break; + } + l = (l << 8) | (0xff & (int64_t)*p++); + } + return (l); +} + +static off_t +pkg_atol(const char *p, unsigned char_cnt) +{ + /* + * Technically, GNU pkg considers a field to be in base-256 + * only if the first byte is 0xff or 0x80. + */ + if (*p & 0x80) + return (pkg_atol256(p, char_cnt)); + return (pkg_atol8(p, char_cnt)); +} + +static int +get_mode(struct tarfile *tf) +{ + return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode))); +} + +/* GZip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +static int +new_package(int fd, struct package **pp) +{ + struct package *pkg; + off_t ofs; + int flags, i, error; + + pkg = malloc(sizeof(*pkg)); + if (pkg == NULL) + return (ENOMEM); + + bzero(pkg, sizeof(*pkg)); + pkg->pkg_fd = fd; + + /* + * Parse the header. + */ + error = EFTYPE; + ofs = 0; + + /* Check megic. */ + if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b) + goto fail; + /* Check method. */ + if (get_byte(pkg, &ofs) != Z_DEFLATED) + goto fail; + /* Check flags. */ + flags = get_byte(pkg, &ofs); + if (flags & RESERVED) + goto fail; + + /* Skip time, xflags and OS code. */ + for (i = 0; i < 6; i++) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + + /* Skip extra field. */ + if (flags & EXTRA_FIELD) { + i = (get_byte(pkg, &ofs) & 0xff) | + ((get_byte(pkg, &ofs) << 8) & 0xff); + while (i-- > 0) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + } + + /* Skip original file name. */ + if (flags & ORIG_NAME) { + do { + i = get_byte(pkg, &ofs); + } while (i != 0 && i != -1); + if (i == -1) + goto fail; + } + + /* Print the comment if it's there. */ + if (flags & COMMENT) { + while (1) { + i = get_byte(pkg, &ofs); + if (i == -1) + goto fail; + if (i == 0) + break; + putchar(i); + } + } + + /* Skip the CRC. */ + if (flags & HEAD_CRC) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + + /* + * Done parsing the ZIP header. Spkgt the inflation engine. + */ + error = inflateInit2(&pkg->pkg_zs, -15); + if (error != Z_OK) + goto fail; + + *pp = pkg; + return (0); + + fail: + free(pkg); + return (error); +} + +static struct tarfile * +scan_tarfile(struct package *pkg, struct tarfile *last) +{ + char buf[512]; + struct tarfile *cur; + off_t ofs; + size_t sz; + + cur = (last != NULL) ? last->tf_next : pkg->pkg_first; + if (cur == NULL) { + ofs = (last != NULL) ? last->tf_ofs + last->tf_size : + pkg->pkg_ofs; + ofs = (ofs + 0x1ff) & ~0x1ff; + + /* Check if we've reached EOF. */ + if (ofs < pkg->pkg_ofs) { + errno = ENOSPC; + return (NULL); + } + + if (ofs != pkg->pkg_ofs) { + if (last != NULL && pkg->pkg_ofs == last->tf_ofs) { + if (cache_data(last) == -1) + return (NULL); + } else { + sz = ofs - pkg->pkg_ofs; + while (sz != 0) { + if (sz > sizeof(buf)) + sz = sizeof(buf); + if (get_zipped(pkg, buf, sz) == -1) + return (NULL); + sz = ofs - pkg->pkg_ofs; + } + } + } + + cur = malloc(sizeof(*cur)); + if (cur == NULL) + return (NULL); + memset(cur, 0, sizeof(*cur)); + cur->tf_pkg = pkg; + + while (1) { + if (get_zipped(pkg, &cur->tf_hdr, + sizeof(cur->tf_hdr)) == -1) { + free(cur); + return (NULL); + } + + /* + * There are always 2 empty blocks appended to + * a PKG. It marks the end of the archive. + */ + if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) { + free(cur); + errno = ENOSPC; + return (NULL); + } + + cur->tf_ofs = pkg->pkg_ofs; + cur->tf_size = pkg_atol(cur->tf_hdr.ut_size, + sizeof(cur->tf_hdr.ut_size)); + + if (cur->tf_hdr.ut_name[0] != '+') + break; + + /* + * Skip package meta-files. + */ + ofs = cur->tf_ofs + cur->tf_size; + ofs = (ofs + 0x1ff) & ~0x1ff; + while (pkg->pkg_ofs < ofs) { + if (get_zipped(pkg, buf, sizeof(buf)) == -1) { + free(cur); + return (NULL); + } + } + } + + if (last != NULL) + last->tf_next = cur; + else + pkg->pkg_first = cur; + pkg->pkg_last = cur; + } + + return (cur); +} diff --git a/stand/libsa/powerpc/_setjmp.S b/stand/libsa/powerpc/_setjmp.S new file mode 100644 index 000000000000..7c7c24b1237c --- /dev/null +++ b/stand/libsa/powerpc/_setjmp.S @@ -0,0 +1,115 @@ +/* $FreeBSD$ */ +/* from: NetBSD: setjmp.S,v 1.1 1998/01/27 15:13:12 sakamoto Exp $ */ +/* from: OpenBSD: setjmp.S,v 1.2 1996/12/28 06:22:18 rahnds Exp */ +/* kernel version of this file, does not have signal goop */ +/* int setjmp(jmp_buf env) */ + +#include <machine/asm.h> + +#ifdef __powerpc64__ +#define LD_REG ld +#define ST_REG std +#define REGWIDTH 8 +#else +#define LD_REG lwz +#define ST_REG stw +#define REGWIDTH 4 +#endif + +#define JMP_r1 1*REGWIDTH +#define JMP_r2 2*REGWIDTH +#define JMP_r14 3*REGWIDTH +#define JMP_r15 4*REGWIDTH +#define JMP_r16 5*REGWIDTH +#define JMP_r17 6*REGWIDTH +#define JMP_r18 7*REGWIDTH +#define JMP_r19 8*REGWIDTH +#define JMP_r20 9*REGWIDTH +#define JMP_r21 10*REGWIDTH +#define JMP_r22 11*REGWIDTH +#define JMP_r23 12*REGWIDTH +#define JMP_r24 13*REGWIDTH +#define JMP_r25 14*REGWIDTH +#define JMP_r26 15*REGWIDTH +#define JMP_r27 16*REGWIDTH +#define JMP_r28 17*REGWIDTH +#define JMP_r29 18*REGWIDTH +#define JMP_r30 19*REGWIDTH +#define JMP_r31 20*REGWIDTH +#define JMP_lr 21*REGWIDTH +#define JMP_cr 22*REGWIDTH +#define JMP_ctr 23*REGWIDTH +#define JMP_xer 24*REGWIDTH +#define JMP_sig 25*REGWIDTH + +ASENTRY_NOPROF(_setjmp) + ST_REG 31, JMP_r31(3) + /* r1, r2, r14-r30 */ + ST_REG 1, JMP_r1 (3) + ST_REG 2, JMP_r2 (3) + ST_REG 14, JMP_r14(3) + ST_REG 15, JMP_r15(3) + ST_REG 16, JMP_r16(3) + ST_REG 17, JMP_r17(3) + ST_REG 18, JMP_r18(3) + ST_REG 19, JMP_r19(3) + ST_REG 20, JMP_r20(3) + ST_REG 21, JMP_r21(3) + ST_REG 22, JMP_r22(3) + ST_REG 23, JMP_r23(3) + ST_REG 24, JMP_r24(3) + ST_REG 25, JMP_r25(3) + ST_REG 26, JMP_r26(3) + ST_REG 27, JMP_r27(3) + ST_REG 28, JMP_r28(3) + ST_REG 29, JMP_r29(3) + ST_REG 30, JMP_r30(3) + /* cr, lr, ctr, xer */ + mfcr 0 + ST_REG 0, JMP_cr(3) + mflr 0 + ST_REG 0, JMP_lr(3) + mfctr 0 + ST_REG 0, JMP_ctr(3) + mfxer 0 + ST_REG 0, JMP_xer(3) + /* f14-f31, fpscr */ + li 3, 0 + blr + + +.extern sigsetmask +ASENTRY_NOPROF(_longjmp) + LD_REG 31, JMP_r31(3) + /* r1, r2, r14-r30 */ + LD_REG 1, JMP_r1 (3) + LD_REG 2, JMP_r2 (3) + LD_REG 14, JMP_r14(3) + LD_REG 15, JMP_r15(3) + LD_REG 16, JMP_r16(3) + LD_REG 17, JMP_r17(3) + LD_REG 18, JMP_r18(3) + LD_REG 19, JMP_r19(3) + LD_REG 20, JMP_r20(3) + LD_REG 21, JMP_r21(3) + LD_REG 22, JMP_r22(3) + LD_REG 23, JMP_r23(3) + LD_REG 24, JMP_r24(3) + LD_REG 25, JMP_r25(3) + LD_REG 26, JMP_r26(3) + LD_REG 27, JMP_r27(3) + LD_REG 28, JMP_r28(3) + LD_REG 29, JMP_r29(3) + LD_REG 30, JMP_r30(3) + /* cr, lr, ctr, xer */ + LD_REG 0, JMP_cr(3) + mtcr 0 + LD_REG 0, JMP_lr(3) + mtlr 0 + LD_REG 0, JMP_ctr(3) + mtctr 0 + LD_REG 0, JMP_xer(3) + mtxer 0 + /* f14-f31, fpscr */ + mr 3, 4 + blr diff --git a/stand/libsa/powerpc/syncicache.c b/stand/libsa/powerpc/syncicache.c new file mode 100644 index 000000000000..434dcec63416 --- /dev/null +++ b/stand/libsa/powerpc/syncicache.c @@ -0,0 +1,103 @@ +/*- + * Copyright (C) 1995-1997, 1999 Wolfgang Solfrank. + * Copyright (C) 1995-1997, 1999 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. + * + * $NetBSD: syncicache.c,v 1.2 1999/05/05 12:36:40 tsubai Exp $ + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#if defined(_KERNEL) || defined(_STANDALONE) +#include <sys/time.h> +#include <sys/proc.h> +#include <vm/vm.h> +#endif +#include <sys/sysctl.h> + +#include <machine/cpu.h> +#include <machine/md_var.h> + +#ifdef _STANDALONE +int cacheline_size = 32; +#endif + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include <stdlib.h> + +int cacheline_size = 0; + +static void getcachelinesize(void); + +static void +getcachelinesize() +{ + static int cachemib[] = { CTL_MACHDEP, CPU_CACHELINE }; + int clen; + + clen = sizeof(cacheline_size); + + if (sysctl(cachemib, sizeof(cachemib) / sizeof(cachemib[0]), + &cacheline_size, &clen, NULL, 0) < 0 || !cacheline_size) { + abort(); + } +} +#endif + +void +__syncicache(void *from, int len) +{ + int l, off; + char *p; + +#if !defined(_KERNEL) && !defined(_STANDALONE) + if (!cacheline_size) + getcachelinesize(); +#endif + + off = (u_int)from & (cacheline_size - 1); + l = len += off; + p = (char *)from - off; + + do { + __asm __volatile ("dcbst 0,%0" :: "r"(p)); + p += cacheline_size; + } while ((l -= cacheline_size) > 0); + __asm __volatile ("sync"); + p = (char *)from - off; + do { + __asm __volatile ("icbi 0,%0" :: "r"(p)); + p += cacheline_size; + } while ((len -= cacheline_size) > 0); + __asm __volatile ("sync; isync"); +} + diff --git a/stand/libsa/printf.c b/stand/libsa/printf.c new file mode 100644 index 000000000000..d0c409ded53c --- /dev/null +++ b/stand/libsa/printf.c @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Standaloneified version of the FreeBSD kernel printf family. + */ + +#include <sys/types.h> +#include <sys/stddef.h> +#include <sys/stdint.h> +#include <limits.h> +#include <string.h> +#include "stand.h" + +/* + * Note that stdarg.h and the ANSI style va_start macro is used for both + * ANSI and traditional C compilers. + */ +#include <machine/stdarg.h> + +#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) + +typedef void (kvprintf_fn_t)(int, void *); + +static char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); +static int kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap); + +static void +putchar_wrapper(int cc, void *arg) +{ + + putchar(cc); +} + +int +printf(const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); + va_end(ap); + return retval; +} + +void +vprintf(const char *fmt, va_list ap) +{ + + kvprintf(fmt, putchar_wrapper, NULL, 10, ap); +} + +int +sprintf(char *buf, const char *cfmt, ...) +{ + int retval; + va_list ap; + + va_start(ap, cfmt); + retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); + buf[retval] = '\0'; + va_end(ap); + return retval; +} + +struct print_buf { + char *buf; + size_t size; +}; + +static void +snprint_func(int ch, void *arg) +{ + struct print_buf *pbuf = arg; + + if (pbuf->size < 2) { + /* + * Reserve last buffer position for the terminating + * character: + */ + return; + } + *(pbuf->buf)++ = ch; + pbuf->size--; +} + +int +snprintf(char *buf, size_t size, const char *cfmt, ...) +{ + int retval; + va_list ap; + struct print_buf arg; + + arg.buf = buf; + arg.size = size; + + va_start(ap, cfmt); + retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); + va_end(ap); + + if (arg.size >= 1) + *(arg.buf)++ = 0; + return retval; +} + +void +vsprintf(char *buf, const char *cfmt, va_list ap) +{ + int retval; + + retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); + buf[retval] = '\0'; +} + +/* + * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static char * +ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) +{ + char *p, c; + + p = nbuf; + *p = '\0'; + do { + c = hex2ascii(num % base); + *++p = upper ? toupper(c) : c; + } while (num /= base); + if (lenp) + *lenp = p - nbuf; + return (p); +} + +/* + * Scaled down version of printf(3). + * + * Two additional formats: + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "<base><arg>*"); + * + * where <base> is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); + * + * would produce output: + * + * reg=3<BITTWO,BITONE> + * + * XXX: %D -- Hexdump, takes pointer and separator string: + * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + * ("%*D", len, ptr, " " -> XX XX XX XX ... + */ +static int +kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) +{ +#define PCHAR(c) {int cc=(c); if (func) (*func)(cc, arg); else *d++ = cc; retval++; } + char nbuf[MAXNBUF]; + char *d; + const char *p, *percent, *q; + uint16_t *S; + u_char *up; + int ch, n; + uintmax_t num; + int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + int cflag, hflag, jflag, tflag, zflag; + int dwidth, upper; + char padc; + int stop = 0, retval = 0; + + num = 0; + if (!func) + d = (char *) arg; + else + d = NULL; + + if (fmt == NULL) + fmt = "(fmt null)\n"; + + if (radix < 2 || radix > 36) + radix = 10; + + for (;;) { + padc = ' '; + width = 0; + while ((ch = (u_char)*fmt++) != '%' || stop) { + if (ch == '\0') + return (retval); + PCHAR(ch); + } + percent = fmt - 1; + qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; dwidth = 0; upper = 0; + cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; +reswitch: switch (ch = (u_char)*fmt++) { + case '.': + dot = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case '+': + sign = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '%': + PCHAR(ch); + break; + case '*': + if (!dot) { + width = va_arg(ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg(ap, int); + } + goto reswitch; + case '0': + if (!dot) { + padc = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n = 0;; ++fmt) { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + case 'b': + num = (u_int)va_arg(ap, int); + p = va_arg(ap, char *); + for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) + PCHAR(*q--); + + if (num == 0) + break; + + for (tmp = 0; *p;) { + n = *p++; + if (num & (1 << (n - 1))) { + PCHAR(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + PCHAR(n); + tmp = 1; + } else + for (; *p > ' '; ++p) + continue; + } + if (tmp) + PCHAR('>'); + break; + case 'c': + PCHAR(va_arg(ap, int)); + break; + case 'D': + up = va_arg(ap, u_char *); + p = va_arg(ap, char *); + if (!width) + width = 16; + while(width--) { + PCHAR(hex2ascii(*up >> 4)); + PCHAR(hex2ascii(*up & 0x0f)); + up++; + if (width) + for (q=p;*q;q++) + PCHAR(*q); + } + break; + case 'd': + case 'i': + base = 10; + sign = 1; + goto handle_sign; + case 'h': + if (hflag) { + hflag = 0; + cflag = 1; + } else + hflag = 1; + goto reswitch; + case 'j': + jflag = 1; + goto reswitch; + case 'l': + if (lflag) { + lflag = 0; + qflag = 1; + } else + lflag = 1; + goto reswitch; + case 'n': + if (jflag) + *(va_arg(ap, intmax_t *)) = retval; + else if (qflag) + *(va_arg(ap, quad_t *)) = retval; + else if (lflag) + *(va_arg(ap, long *)) = retval; + else if (zflag) + *(va_arg(ap, size_t *)) = retval; + else if (hflag) + *(va_arg(ap, short *)) = retval; + else if (cflag) + *(va_arg(ap, char *)) = retval; + else + *(va_arg(ap, int *)) = retval; + break; + case 'o': + base = 8; + goto handle_nosign; + case 'p': + base = 16; + sharpflag = (width == 0); + sign = 0; + num = (uintptr_t)va_arg(ap, void *); + goto number; + case 'q': + qflag = 1; + goto reswitch; + case 'r': + base = radix; + if (sign) + goto handle_sign; + goto handle_nosign; + case 's': + p = va_arg(ap, char *); + if (p == NULL) + p = "(null)"; + if (!dot) + n = strlen (p); + else + for (n = 0; n < dwidth && p[n]; n++) + continue; + + width -= n; + + if (!ladjust && width > 0) + while (width--) + PCHAR(padc); + while (n--) + PCHAR(*p++); + if (ladjust && width > 0) + while (width--) + PCHAR(padc); + break; + case 'S': /* Assume console can cope with wide chars */ + for (S = va_arg(ap, uint16_t *); *S != 0; S++) + PCHAR(*S); + break; + case 't': + tflag = 1; + goto reswitch; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + upper = 1; + case 'x': + base = 16; + goto handle_nosign; + case 'y': + base = 16; + sign = 1; + goto handle_sign; + case 'z': + zflag = 1; + goto reswitch; +handle_nosign: + sign = 0; + if (jflag) + num = va_arg(ap, uintmax_t); + else if (qflag) + num = va_arg(ap, u_quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, u_long); + else if (zflag) + num = va_arg(ap, size_t); + else if (hflag) + num = (u_short)va_arg(ap, int); + else if (cflag) + num = (u_char)va_arg(ap, int); + else + num = va_arg(ap, u_int); + goto number; +handle_sign: + if (jflag) + num = va_arg(ap, intmax_t); + else if (qflag) + num = va_arg(ap, quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, long); + else if (zflag) + num = va_arg(ap, ssize_t); + else if (hflag) + num = (short)va_arg(ap, int); + else if (cflag) + num = (char)va_arg(ap, int); + else + num = va_arg(ap, int); +number: + if (sign && (intmax_t)num < 0) { + neg = 1; + num = -(intmax_t)num; + } + p = ksprintn(nbuf, num, base, &n, upper); + tmp = 0; + if (sharpflag && num != 0) { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; + + if (!ladjust && padc == '0') + dwidth = width - tmp; + width -= tmp + imax(dwidth, n); + dwidth -= n; + if (!ladjust) + while (width-- > 0) + PCHAR(' '); + if (neg) + PCHAR('-'); + if (sharpflag && num != 0) { + if (base == 8) { + PCHAR('0'); + } else if (base == 16) { + PCHAR('0'); + PCHAR('x'); + } + } + while (dwidth-- > 0) + PCHAR('0'); + + while (*p) + PCHAR(*p--); + + if (ladjust) + while (width-- > 0) + PCHAR(' '); + + break; + default: + while (percent < fmt) + PCHAR(*percent++); + /* + * Since we ignore a formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; + break; + } + } +#undef PCHAR +} diff --git a/stand/libsa/qdivrem.c b/stand/libsa/qdivrem.c new file mode 100644 index 000000000000..9e7696de3853 --- /dev/null +++ b/stand/libsa/qdivrem.c @@ -0,0 +1,348 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * From: Id: qdivrem.c,v 1.7 1997/11/07 09:20:40 phk Exp + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed), + * section 4.3.1, pp. 257--259. + */ + +#include "quad.h" + +#define B (1 << HALF_BITS) /* digit base */ + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b)) + +_Static_assert(sizeof(int) / 2 == sizeof(short), + "Bitwise functions in libstand are broken on this architecture\n"); + +/* select a type for digits in base B: use unsigned short if they fit */ +typedef unsigned short digit; + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +shl(digit *p, int len, int sh) +{ + int i; + + for (i = 0; i < len; i++) + p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh)); + p[i] = LHALF(p[i] << sh); +} + +/* + * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate products + * fit within u_int. As a consequence, the maximum length dividend and + * divisor are 4 `digits' in this base (they are shorter if they have + * leading zeros). + */ +u_quad_t +__qdivrem(uq, vq, arq) + u_quad_t uq, vq, *arq; +{ + union uu tmp; + digit *u, *v, *q; + digit v1, v2; + u_int qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vq == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ul[H] = tmp.ul[L] = 1 / zero; + if (arq) + *arq = uq; + return (tmp.q); + } + if (uq < vq) { + if (arq) + *arq = uq; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.uq = uq; + u[0] = 0; + u[1] = HHALF(tmp.ul[H]); + u[2] = LHALF(tmp.ul[H]); + u[3] = HHALF(tmp.ul[L]); + u[4] = LHALF(tmp.ul[L]); + tmp.uq = vq; + v[1] = HHALF(tmp.ul[H]); + v[2] = LHALF(tmp.ul[H]); + v[3] = HHALF(tmp.ul[L]); + v[4] = LHALF(tmp.ul[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + u_int rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = u[1] / t; + rbj = COMBINE(u[1] % t, u[2]); + q2 = rbj / t; + rbj = COMBINE(rbj % t, u[3]); + q3 = rbj / t; + rbj = COMBINE(rbj % t, u[4]); + q4 = rbj / t; + if (arq) + *arq = rbj % t; + tmp.ul[H] = COMBINE(q1, q2); + tmp.ul[L] = COMBINE(q3, q4); + return (tmp.q); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + shl(&u[0], m + n, d); /* u <<= d */ + shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + u_int nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = LHALF(t); + t = HHALF(t); + } + u[j] = LHALF(u[j] + t); + } + q[j] = qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (u[i] >> d) | + LHALF(u[i - 1] << (HALF_BITS - d)); + u[i] = 0; + } + tmp.ul[H] = COMBINE(uspace[1], uspace[2]); + tmp.ul[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.q; + } + + tmp.ul[H] = COMBINE(qspace[1], qspace[2]); + tmp.ul[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.q); +} + +/* + * Divide two unsigned quads. + */ + +u_quad_t +__udivdi3(a, b) + u_quad_t a, b; +{ + + return (__qdivrem(a, b, (u_quad_t *)0)); +} + +/* + * Return remainder after dividing two unsigned quads. + */ +u_quad_t +__umoddi3(a, b) + u_quad_t a, b; +{ + u_quad_t r; + + (void)__qdivrem(a, b, &r); + return (r); +} + +/* + * Divide two signed quads. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +quad_t +__divdi3(a, b) + quad_t a, b; +{ + u_quad_t ua, ub, uq; + int neg; + + if (a < 0) + ua = -(u_quad_t)a, neg = 1; + else + ua = a, neg = 0; + if (b < 0) + ub = -(u_quad_t)b, neg ^= 1; + else + ub = b; + uq = __qdivrem(ua, ub, (u_quad_t *)0); + return (neg ? -uq : uq); +} + +/* + * Return remainder after dividing two signed quads. + * + * XXX + * If -1/2 should produce -1 on this machine, this code is wrong. + */ +quad_t +__moddi3(a, b) + quad_t a, b; +{ + u_quad_t ua, ub, ur; + int neg; + + if (a < 0) + ua = -(u_quad_t)a, neg = 1; + else + ua = a, neg = 0; + if (b < 0) + ub = -(u_quad_t)b; + else + ub = b; + (void)__qdivrem(ua, ub, &ur); + return (neg ? -ur : ur); +} diff --git a/stand/libsa/quad.h b/stand/libsa/quad.h new file mode 100644 index 000000000000..3450a7a1afe4 --- /dev/null +++ b/stand/libsa/quad.h @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)quad.h 8.1 (Berkeley) 6/4/93 + * $FreeBSD$ + */ + +/* + * Quad arithmetic. + * + * This library makes the following assumptions: + * + * - The type long long (aka quad_t) exists. + * + * - A quad variable is exactly twice as long as `long'. + * + * - The machine's arithmetic is two's complement. + * + * This library can provide 128-bit arithmetic on a machine with 128-bit + * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines + * with 48-bit longs. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <limits.h> + +_Static_assert(sizeof(quad_t) == sizeof(int) * 2, + "Bitwise function in libstand are broken on this architecture\n"); + +/* + * Depending on the desired operation, we view a `long long' (aka quad_t) in + * one or more of the following formats. + */ +union uu { + quad_t q; /* as a (signed) quad */ + quad_t uq; /* as an unsigned quad */ + int sl[2]; /* as two signed ints */ + u_int ul[2]; /* as two unsigned ints */ +}; + +/* + * Define high and low longwords. + */ +#define H _QUAD_HIGHWORD +#define L _QUAD_LOWWORD + +/* + * Total number of bits in a quad_t and in the pieces that make it up. + * These are used for shifting, and also below for halfword extraction + * and assembly. + */ +#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT) +#define HALF_BITS (sizeof(int) * CHAR_BIT / 2) + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.) + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a quad_t, shifted left + * (sizeof(long)*CHAR_BIT/2). + */ +#define HHALF(x) ((x) >> HALF_BITS) +#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1)) +#define LHUP(x) ((x) << HALF_BITS) + +quad_t __divdi3(quad_t a, quad_t b); +quad_t __moddi3(quad_t a, quad_t b); +u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem); +u_quad_t __udivdi3(u_quad_t a, u_quad_t b); +u_quad_t __umoddi3(u_quad_t a, u_quad_t b); + +/* + * XXX + * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument + * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use + * both compilers. + */ +#if __GNUC__ >= 2 +typedef unsigned int qshift_t; +#else +typedef u_quad_t qshift_t; +#endif diff --git a/stand/libsa/random.c b/stand/libsa/random.c new file mode 100644 index 000000000000..a4b4d5020642 --- /dev/null +++ b/stand/libsa/random.c @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)random.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +static u_long randseed = 1; + +void +srandom(seed) + u_long seed; +{ + randseed = seed; +} + +/* + * Pseudo-random number generator for randomizing the profiling clock, + * and whatever else we might use it for. The result is uniform on + * [0, 2^31 - 1]. + */ +u_long +random() +{ + long x, hi, lo, t; + + /* + * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1). + * From "Random number generators: good ones are hard to find", + * Park and Miller, Communications of the ACM, vol. 31, no. 10, + * October 1988, p. 1195. + */ + x = randseed; + hi = x / 127773; + lo = x % 127773; + t = 16807 * lo - 2836 * hi; + if (t <= 0) + t += 0x7fffffff; + randseed = t; + return (t); +} diff --git a/stand/libsa/rarp.c b/stand/libsa/rarp.c new file mode 100644 index 000000000000..b7e3ea486079 --- /dev/null +++ b/stand/libsa/rarp.c @@ -0,0 +1,218 @@ +/* $NetBSD: rarp.c,v 1.16 1997/07/07 15:52:52 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <netinet/in_systm.h> + +#include <string.h> + +#include "stand.h" +#include "net.h" +#include "netif.h" + + +static ssize_t rarpsend(struct iodesc *, void *, size_t); +static ssize_t rarprecv(struct iodesc *, void **, void **, time_t); + +/* + * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). + */ +int +rarp_getipaddress(int sock) +{ + struct iodesc *d; + struct ether_arp *ap; + void *pkt; + struct { + u_char header[ETHER_SIZE]; + struct { + struct ether_arp arp; + u_char pad[18]; /* 60 - sizeof(arp) */ + } data; + } wbuf; + +#ifdef RARP_DEBUG + if (debug) + printf("rarp: socket=%d\n", sock); +#endif + if (!(d = socktodesc(sock))) { + printf("rarp: bad socket. %d\n", sock); + return (-1); + } +#ifdef RARP_DEBUG + if (debug) + printf("rarp: d=%x\n", (u_int)d); +#endif + + bzero((char*)&wbuf.data, sizeof(wbuf.data)); + ap = &wbuf.data.arp; + ap->arp_hrd = htons(ARPHRD_ETHER); + ap->arp_pro = htons(ETHERTYPE_IP); + ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */ + ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */ + ap->arp_op = htons(ARPOP_REVREQUEST); + bcopy(d->myea, ap->arp_sha, 6); + bcopy(d->myea, ap->arp_tha, 6); + pkt = NULL; + + if (sendrecv(d, + rarpsend, &wbuf.data, sizeof(wbuf.data), + rarprecv, &pkt, (void *)&ap) < 0) { + printf("No response for RARP request\n"); + return (-1); + } + + bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); +#if 0 + /* XXX - Can NOT assume this is our root server! */ + bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); +#endif + free(pkt); + + /* Compute our "natural" netmask. */ + if (IN_CLASSA(myip.s_addr)) + netmask = IN_CLASSA_NET; + else if (IN_CLASSB(myip.s_addr)) + netmask = IN_CLASSB_NET; + else + netmask = IN_CLASSC_NET; + + d->myip = myip; + return (0); +} + +/* + * Broadcast a RARP request (i.e. who knows who I am) + */ +static ssize_t +rarpsend(struct iodesc *d, void *pkt, size_t len) +{ + +#ifdef RARP_DEBUG + if (debug) + printf("rarpsend: called\n"); +#endif + + return (sendether(d, pkt, len, bcea, ETHERTYPE_REVARP)); +} + +/* + * Returns 0 if this is the packet we're waiting for + * else -1 (and errno == 0) + */ +static ssize_t +rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft) +{ + ssize_t n; + struct ether_arp *ap; + void *ptr = NULL; + uint16_t etype; /* host order */ + +#ifdef RARP_DEBUG + if (debug) + printf("rarprecv: "); +#endif + + n = readether(d, &ptr, (void **)&ap, tleft, &etype); + errno = 0; /* XXX */ + if (n == -1 || n < sizeof(struct ether_arp)) { +#ifdef RARP_DEBUG + if (debug) + printf("bad len=%d\n", n); +#endif + free(ptr); + return (-1); + } + + if (etype != ETHERTYPE_REVARP) { +#ifdef RARP_DEBUG + if (debug) + printf("bad type=0x%x\n", etype); +#endif + free(ptr); + return (-1); + } + + if (ap->arp_hrd != htons(ARPHRD_ETHER) || + ap->arp_pro != htons(ETHERTYPE_IP) || + ap->arp_hln != sizeof(ap->arp_sha) || + ap->arp_pln != sizeof(ap->arp_spa) ) + { +#ifdef RARP_DEBUG + if (debug) + printf("bad hrd/pro/hln/pln\n"); +#endif + free(ptr); + return (-1); + } + + if (ap->arp_op != htons(ARPOP_REVREPLY)) { +#ifdef RARP_DEBUG + if (debug) + printf("bad op=0x%x\n", ntohs(ap->arp_op)); +#endif + free(ptr); + return (-1); + } + + /* Is the reply for our Ethernet address? */ + if (bcmp(ap->arp_tha, d->myea, 6)) { +#ifdef RARP_DEBUG + if (debug) + printf("unwanted address\n"); +#endif + free(ptr); + return (-1); + } + + /* We have our answer. */ +#ifdef RARP_DEBUG + if (debug) + printf("got it\n"); +#endif + *pkt = ptr; + *payload = ap; + return (n); +} diff --git a/stand/libsa/read.c b/stand/libsa/read.c new file mode 100644 index 000000000000..e48a4d864212 --- /dev/null +++ b/stand/libsa/read.c @@ -0,0 +1,127 @@ +/* $NetBSD: read.c,v 1.8 1997/01/22 00:38:12 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)read.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include "stand.h" + +ssize_t +read(int fd, void *dest, size_t bcount) +{ + struct open_file *f = &files[fd]; + size_t resid; + + if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + errno = EBADF; + return (-1); + } + if (f->f_flags & F_RAW) { + twiddle(4); + errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + btodb(f->f_offset), bcount, dest, &resid); + if (errno) + return (-1); + f->f_offset += resid; + return (resid); + } + + /* + * Optimise reads from regular files using a readahead buffer. + * If the request can't be satisfied from the current buffer contents, + * check to see if it should be bypassed, or refill the buffer and complete + * the request. + */ + resid = bcount; + for (;;) { + size_t ccount, cresid; + /* how much can we supply? */ + ccount = imin(f->f_ralen, resid); + if (ccount > 0) { + bcopy(f->f_rabuf + f->f_raoffset, dest, ccount); + f->f_raoffset += ccount; + f->f_ralen -= ccount; + resid -= ccount; + if (resid == 0) + return(bcount); + dest = (char *)dest + ccount; + } + + /* will filling the readahead buffer again not help? */ + if (resid >= SOPEN_RASIZE) { + /* bypass the rest of the request and leave the buffer empty */ + if ((errno = (f->f_ops->fo_read)(f, dest, resid, &cresid))) + return (-1); + return(bcount - cresid); + } + + /* fetch more data */ + if ((errno = (f->f_ops->fo_read)(f, f->f_rabuf, SOPEN_RASIZE, &cresid))) + return (-1); + f->f_raoffset = 0; + f->f_ralen = SOPEN_RASIZE - cresid; + /* no more data, return what we had */ + if (f->f_ralen == 0) + return(bcount - resid); + } +} diff --git a/stand/libsa/readdir.c b/stand/libsa/readdir.c new file mode 100644 index 000000000000..e49d93d15ed6 --- /dev/null +++ b/stand/libsa/readdir.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1999,2000 Jonathan Lemon <jlemon@freebsd.org> + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include "stand.h" + +struct dirent * +readdirfd(int fd) +{ + static struct dirent dir; /* XXX not thread safe */ + struct open_file *f = &files[fd]; + + if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + errno = EBADF; + return (NULL); + } + if (f->f_flags & F_RAW) { + errno = EIO; + return (NULL); + } + errno = (f->f_ops->fo_readdir)(f, &dir); + if (errno) + return (NULL); + return (&dir); +} diff --git a/stand/libsa/rpc.c b/stand/libsa/rpc.c new file mode 100644 index 000000000000..932fdc98b903 --- /dev/null +++ b/stand/libsa/rpc.c @@ -0,0 +1,433 @@ +/* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * RPC functions used by NFS and bootparams. + * Note that bootparams requires the ability to find out the + * address of the server from which its response has come. + * This is supported by keeping the IP/UDP headers in the + * buffer space provided by the caller. (See rpc_fromaddr) + */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include <string.h> + +#include "rpcv2.h" + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" + +struct auth_info { + int32_t authtype; /* auth type */ + u_int32_t authlen; /* auth length */ +}; + +struct auth_unix { + int32_t ua_time; + int32_t ua_hostname; /* null */ + int32_t ua_uid; + int32_t ua_gid; + int32_t ua_gidlist; /* null */ +}; + +struct rpc_call { + u_int32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (0) */ + u_int32_t rp_rpcvers; /* rpc version (2) */ + u_int32_t rp_prog; /* program */ + u_int32_t rp_vers; /* version */ + u_int32_t rp_proc; /* procedure */ +}; + +struct rpc_reply { + u_int32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (1) */ + int32_t rp_astatus; /* accept status (0: accepted) */ + union { + u_int32_t rpu_errno; + struct { + struct auth_info rok_auth; + u_int32_t rok_status; + } rpu_rok; + } rp_u; +}; + +/* Local forwards */ +static ssize_t recvrpc(struct iodesc *, void **, void **, time_t); +static int rpc_getport(struct iodesc *, n_long, n_long); + +int rpc_xid; +int rpc_port = 0x400; /* predecrement */ + +/* + * Make a rpc call; return length of answer + * Note: Caller must leave room for headers. + */ +ssize_t +rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, + void *sdata, size_t slen, void **rdata, void **pkt) +{ + ssize_t cc, rsize; + struct auth_info *auth; + struct rpc_call *call; + struct rpc_reply *reply; + char *send_head, *send_tail; + void *ptr; + n_long x; + int port; /* host order */ + +#ifdef RPC_DEBUG + if (debug) + printf("rpc_call: prog=0x%x vers=%d proc=%d\n", + prog, vers, proc); +#endif + + port = rpc_getport(d, prog, vers); + if (port == -1) + return (-1); + + d->destport = htons(port); + + /* + * Prepend authorization stuff and headers. + * Note, must prepend things in reverse order. + */ + send_head = sdata; + send_tail = (char *)sdata + slen; + + /* Auth verifier is always auth_null */ + send_head -= sizeof(*auth); + auth = (struct auth_info *)send_head; + auth->authtype = htonl(RPCAUTH_NULL); + auth->authlen = 0; + + /* Auth credentials: always auth unix (as root) */ + send_head -= sizeof(struct auth_unix); + bzero(send_head, sizeof(struct auth_unix)); + send_head -= sizeof(*auth); + auth = (struct auth_info *)send_head; + auth->authtype = htonl(RPCAUTH_UNIX); + auth->authlen = htonl(sizeof(struct auth_unix)); + + /* RPC call structure. */ + send_head -= sizeof(*call); + call = (struct rpc_call *)send_head; + rpc_xid++; + call->rp_xid = htonl(rpc_xid); + call->rp_direction = htonl(RPC_CALL); + call->rp_rpcvers = htonl(RPC_VER2); + call->rp_prog = htonl(prog); + call->rp_vers = htonl(vers); + call->rp_proc = htonl(proc); + + ptr = NULL; + cc = sendrecv(d, + sendudp, send_head, send_tail - send_head, + recvrpc, &ptr, (void **)&reply); + +#ifdef RPC_DEBUG + if (debug) + printf("callrpc: cc=%zd\n", cc); +#endif + if (cc == -1) + return (-1); + + if (cc <= sizeof(*reply)) { + errno = EBADRPC; + free(ptr); + return (-1); + } + + /* + * Check the RPC reply status. + * The xid, dir, astatus were already checked. + */ + auth = &reply->rp_u.rpu_rok.rok_auth; + x = ntohl(auth->authlen); + if (x != 0) { +#ifdef RPC_DEBUG + if (debug) + printf("callrpc: reply auth != NULL\n"); +#endif + errno = EBADRPC; + free(ptr); + return (-1); + } + x = ntohl(reply->rp_u.rpu_rok.rok_status); + if (x != 0) { + printf("callrpc: error = %ld\n", (long)x); + errno = EBADRPC; + free(ptr); + return (-1); + } + + rsize = cc - sizeof(*reply); + *rdata = (void *)((uintptr_t)reply + sizeof(*reply)); + *pkt = ptr; + return (rsize); +} + +/* + * Returns true if packet is the one we're waiting for. + * This just checks the XID, direction, acceptance. + * Remaining checks are done by callrpc + */ +static ssize_t +recvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft) +{ + void *ptr; + struct rpc_reply *reply; + ssize_t n; + int x; + + errno = 0; +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: called\n"); +#endif + + ptr = NULL; + n = readudp(d, &ptr, (void **)&reply, tleft); + if (n <= (4 * 4)) { + free(ptr); + return (-1); + } + + x = ntohl(reply->rp_xid); + if (x != rpc_xid) { +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); +#endif + free(ptr); + return (-1); + } + + x = ntohl(reply->rp_direction); + if (x != RPC_REPLY) { +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: rp_direction %d != REPLY\n", x); +#endif + free(ptr); + return (-1); + } + + x = ntohl(reply->rp_astatus); + if (x != RPC_MSGACCEPTED) { + errno = ntohl(reply->rp_u.rpu_errno); + printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); + free(ptr); + return (-1); + } + + *pkt = ptr; + *payload = reply; + /* Return data count (thus indicating success) */ + return (n); +} + +/* + * Given a pointer to a reply just received, + * dig out the IP address/port from the headers. + */ +void +rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) +{ + struct hackhdr { + /* Tail of IP header: just IP addresses */ + n_long ip_src; + n_long ip_dst; + /* UDP header: */ + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ + /* RPC reply header: */ + struct rpc_reply rpc; + } *hhdr; + + hhdr = ((struct hackhdr *)pkt) - 1; + addr->s_addr = hhdr->ip_src; + *port = hhdr->uh_sport; +} + +/* + * RPC Portmapper cache + */ +#define PMAP_NUM 8 /* need at most 5 pmap entries */ + +int rpc_pmap_num; +struct pmap_list { + struct in_addr addr; /* server, net order */ + u_int prog; /* host order */ + u_int vers; /* host order */ + int port; /* host order */ +} rpc_pmap_list[PMAP_NUM]; + +/* + * return port number in host order, or -1. + * arguments are: + * addr .. server, net order. + * prog .. host order. + * vers .. host order. + */ +int +rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) +{ + struct pmap_list *pl; + + for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { + if (pl->addr.s_addr == addr.s_addr && + pl->prog == prog && pl->vers == vers ) + { + return (pl->port); + } + } + return (-1); +} + +/* + * arguments are: + * addr .. server, net order. + * prog .. host order. + * vers .. host order. + * port .. host order. + */ +void +rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) +{ + struct pmap_list *pl; + + /* Don't overflow cache... */ + if (rpc_pmap_num >= PMAP_NUM) { + /* ... just re-use the last entry. */ + rpc_pmap_num = PMAP_NUM - 1; +#ifdef RPC_DEBUG + printf("rpc_pmap_putcache: cache overflow\n"); +#endif + } + + pl = &rpc_pmap_list[rpc_pmap_num]; + rpc_pmap_num++; + + /* Cache answer */ + pl->addr = addr; + pl->prog = prog; + pl->vers = vers; + pl->port = port; +} + + +/* + * Request a port number from the port mapper. + * Returns the port in host order. + * prog and vers are host order. + */ +int +rpc_getport(struct iodesc *d, n_long prog, n_long vers) +{ + struct args { + n_long prog; /* call program */ + n_long vers; /* call version */ + n_long proto; /* call protocol */ + n_long port; /* call port (unused) */ + } *args; + struct res { + n_long port; + } *res; + struct { + n_long h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + void *pkt; + ssize_t cc; + int port; + +#ifdef RPC_DEBUG + if (debug) + printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); +#endif + + /* This one is fixed forever. */ + if (prog == PMAPPROG) { + port = PMAPPORT; + goto out; + } + + /* Try for cached answer first */ + port = rpc_pmap_getcache(d->destip, prog, vers); + if (port != -1) + goto out; + + args = &sdata.d; + args->prog = htonl(prog); + args->vers = htonl(vers); + args->proto = htonl(IPPROTO_UDP); + args->port = 0; + pkt = NULL; + + cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, + args, sizeof(*args), (void **)&res, &pkt); + if (cc < sizeof(*res)) { + printf("getport: %s", strerror(errno)); + errno = EBADRPC; + free(pkt); + return (-1); + } + port = (int)ntohl(res->port); + free(pkt); + + rpc_pmap_putcache(d->destip, prog, vers, port); + +out: +#ifdef RPC_DEBUG + if (debug) + printf("%s: port=%u\n", __func__, port); +#endif + return (port); +} diff --git a/stand/libsa/rpc.h b/stand/libsa/rpc.h new file mode 100644 index 000000000000..5efe83210142 --- /dev/null +++ b/stand/libsa/rpc.h @@ -0,0 +1,66 @@ +/* $NetBSD: rpc.h,v 1.8 1996/09/26 23:22:03 cgd Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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$ + */ + +/* XXX defines we can't easily get from system includes */ +#define PMAPPORT 111 +#define PMAPPROG 100000 +#define PMAPVERS 2 +#define PMAPPROC_NULL 0 +#define PMAPPROC_SET 1 +#define PMAPPROC_UNSET 2 +#define PMAPPROC_GETPORT 3 +#define PMAPPROC_DUMP 4 +#define PMAPPROC_CALLIT 5 + +/* RPC functions: */ +ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long, + void *, size_t, void **, void **); +void rpc_fromaddr(void *, struct in_addr *, u_short *); +int rpc_pmap_getcache(struct in_addr, u_int, u_int); +void rpc_pmap_putcache(struct in_addr, u_int, u_int, int); + +extern int rpc_port; /* decrement before bind */ + +/* + * How much space to leave in front of RPC requests. + * In 32-bit words (alignment) we have: + * 12: Ether + IP + UDP + padding + * 6: RPC call header + * 7: Auth UNIX + * 2: Auth NULL + */ +#define RPC_HEADER_WORDS 28 diff --git a/stand/libsa/rpcv2.h b/stand/libsa/rpcv2.h new file mode 100644 index 000000000000..4f1f016333a0 --- /dev/null +++ b/stand/libsa/rpcv2.h @@ -0,0 +1,87 @@ +/* $NetBSD: rpcv2.h,v 1.1 1996/02/26 23:05:32 gwr Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93 + * + * $FreeBSD$ + */ + +/* + * Definitions for Sun RPC Version 2, from + * "RPC: Remote Procedure Call Protocol Specification" RFC1057 + */ + +/* Version # */ +#define RPC_VER2 2 + +/* Authentication */ +#define RPCAUTH_NULL 0 +#define RPCAUTH_UNIX 1 +#define RPCAUTH_SHORT 2 +#define RPCAUTH_MAXSIZ 400 +#define RPCAUTH_UNIXGIDS 16 + +/* Rpc Constants */ +#define RPC_CALL 0 +#define RPC_REPLY 1 +#define RPC_MSGACCEPTED 0 +#define RPC_MSGDENIED 1 +#define RPC_PROGUNAVAIL 1 +#define RPC_PROGMISMATCH 2 +#define RPC_PROCUNAVAIL 3 +#define RPC_GARBAGE 4 /* I like this one */ +#define RPC_MISMATCH 0 +#define RPC_AUTHERR 1 + +/* Authentication failures */ +#define AUTH_BADCRED 1 +#define AUTH_REJECTCRED 2 +#define AUTH_BADVERF 3 +#define AUTH_REJECTVERF 4 +#define AUTH_TOOWEAK 5 /* Give em wheaties */ + +/* Sizes of rpc header parts */ +#define RPC_SIZ 24 +#define RPC_REPLYSIZ 28 + +/* RPC Prog definitions */ +#define RPCPROG_MNT 100005 +#define RPCMNT_VER1 1 +#define RPCMNT_MOUNT 1 +#define RPCMNT_DUMP 2 +#define RPCMNT_UMOUNT 3 +#define RPCMNT_UMNTALL 4 +#define RPCMNT_EXPORT 5 +#define RPCMNT_NAMELEN 255 +#define RPCMNT_PATHLEN 1024 +#define RPCPROG_NFS 100003 diff --git a/stand/libsa/saioctl.h b/stand/libsa/saioctl.h new file mode 100644 index 000000000000..5124f86187c9 --- /dev/null +++ b/stand/libsa/saioctl.h @@ -0,0 +1,50 @@ +/* $NetBSD: saioctl.h,v 1.2 1994/10/26 05:45:04 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)saioctl.h 8.1 (Berkeley) 6/11/93 + * + * $FreeBSD$ + */ + +/* ioctl's -- for disks just now */ +#define SAIOHDR (('d'<<8)|1) /* next i/o includes header */ +#define SAIOCHECK (('d'<<8)|2) /* next i/o checks data */ +#define SAIOHCHECK (('d'<<8)|3) /* next i/o checks header & data */ +#define SAIONOBAD (('d'<<8)|4) /* inhibit bad sector forwarding */ +#define SAIODOBAD (('d'<<8)|5) /* enable bad sector forwarding */ +#define SAIOECCLIM (('d'<<8)|6) /* set limit to ecc correction, bits */ +#define SAIOECCUNL (('d'<<8)|7) /* use standard ecc procedures */ +#define SAIORETRIES (('d'<<8)|8) /* set retry count for unit */ +#define SAIODEVDATA (('d'<<8)|9) /* get pointer to pack label */ +#define SAIOSSI (('d'<<8)|10) /* set skip sector inhibit */ +#define SAIONOSSI (('d'<<8)|11) /* inhibit skip sector handling */ +#define SAIOSSDEV (('d'<<8)|12) /* is device skip sector type? */ +#define SAIODEBUG (('d'<<8)|13) /* enable/disable debugging */ +#define SAIOGBADINFO (('d'<<8)|14) /* get bad-sector table */ diff --git a/stand/libsa/sbrk.c b/stand/libsa/sbrk.c new file mode 100644 index 000000000000..471e78ecf6df --- /dev/null +++ b/stand/libsa/sbrk.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1998 Michael Smith + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Minimal sbrk() emulation required for malloc support. + */ + +#include <string.h> +#include "stand.h" +#include "zalloc_defs.h" + +static size_t maxheap, heapsize = 0; +static void *heapbase; + +void +setheap(void *base, void *top) +{ + /* Align start address for the malloc code. Sigh. */ + heapbase = (void *)(((uintptr_t)base + MALLOCALIGN_MASK) & + ~MALLOCALIGN_MASK); + maxheap = (char *)top - (char *)heapbase; +} + +char * +sbrk(int incr) +{ + char *ret; + + if ((heapsize + incr) <= maxheap) { + ret = (char *)heapbase + heapsize; + bzero(ret, incr); + heapsize += incr; + return(ret); + } + errno = ENOMEM; + return((char *)-1); +} + diff --git a/stand/libsa/sparc64/_setjmp.S b/stand/libsa/sparc64/_setjmp.S new file mode 100644 index 000000000000..8df29e6ba750 --- /dev/null +++ b/stand/libsa/sparc64/_setjmp.S @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * $Header: _setjmp.s,v 1.1 91/07/06 16:45:53 torek Exp + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 + .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93" +#else + RCSID("$NetBSD: _setjmp.S,v 1.4 1998/10/08 02:27:59 eeh Exp $") +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <machine/asm.h> +__FBSDID("$FreeBSD$"); + +#define _JB_FP 0x0 +#define _JB_PC 0x8 +#define _JB_SP 0x10 + + .register %g2,#ignore + .register %g3,#ignore + +/* + * C library -- setjmp, longjmp + * + * longjmp(a,v) + * will generate a "return(v?v:1)" from + * the last call to + * setjmp(a) + * by restoring the previous context. + */ + +ENTRY(_setjmp) + stx %sp, [%o0 + _JB_SP] + stx %o7, [%o0 + _JB_PC] + stx %fp, [%o0 + _JB_FP] + retl + clr %o0 +END(_setjmp) + +ENTRY(_longjmp) + mov 1, %g1 + movrnz %o1, %o1, %g1 + mov %o0, %g2 + ldx [%g2 + _JB_FP], %g3 +1: cmp %fp, %g3 + bl,a 1b + restore + be,a 2f + ldx [%g2 + _JB_SP], %o0 + +.Lbotch: + illtrap + +2: cmp %o0, %sp + bge,a 3f + mov %o0, %sp + b,a .Lbotch + nop +3: ldx [%g2 + _JB_PC], %o7 + retl + mov %g1, %o0 +END(_longjmp) diff --git a/stand/libsa/splitfs.c b/stand/libsa/splitfs.c new file mode 100644 index 000000000000..af28704bc465 --- /dev/null +++ b/stand/libsa/splitfs.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2002 Maxim Sobolev + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +#define NTRIES (3) +#define CONF_BUF (512) +#define SEEK_BUF (512) + +struct split_file +{ + char **filesv; /* Filenames */ + char **descsv; /* Descriptions */ + int filesc; /* Number of parts */ + int curfile; /* Current file number */ + int curfd; /* Current file descriptor */ + off_t tot_pos; /* Offset from the beginning of the sequence */ + off_t file_pos; /* Offset from the beginning of the slice */ +}; + +static int split_openfile(struct split_file *sf); +static int splitfs_open(const char *path, struct open_file *f); +static int splitfs_close(struct open_file *f); +static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t splitfs_seek(struct open_file *f, off_t offset, int where); +static int splitfs_stat(struct open_file *f, struct stat *sb); + +struct fs_ops splitfs_fsops = { + "split", + splitfs_open, + splitfs_close, + splitfs_read, + null_write, + splitfs_seek, + splitfs_stat, + null_readdir +}; + +static void +split_file_destroy(struct split_file *sf) +{ + int i; + + if (sf->filesc > 0) { + for (i = 0; i < sf->filesc; i++) { + free(sf->filesv[i]); + free(sf->descsv[i]); + } + free(sf->filesv); + free(sf->descsv); + } + free(sf); +} + +static int +split_openfile(struct split_file *sf) +{ + int i; + + for (i = 0;; i++) { + sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY); + if (sf->curfd >= 0) + break; + if ((sf->curfd == -1) && (errno != ENOENT)) + return (errno); + if (i == NTRIES) + return (EIO); + printf("\nInsert disk labelled %s and press any key...", + sf->descsv[sf->curfile]); + getchar(); + putchar('\n'); + } + sf->file_pos = 0; + return (0); +} + +static int +splitfs_open(const char *fname, struct open_file *f) +{ + char *buf, *confname, *cp; + int conffd; + struct split_file *sf; + struct stat sb; + + /* Have to be in "just read it" mode */ + if (f->f_flags != F_READ) + return(EPERM); + + /* If the name already ends in `.split', ignore it */ + if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split"))) + return(ENOENT); + + /* Construct new name */ + confname = malloc(strlen(fname) + 7); + sprintf(confname, "%s.split", fname); + + /* Try to open the configuration file */ + conffd = open(confname, O_RDONLY); + free(confname); + if (conffd == -1) + return(ENOENT); + + if (fstat(conffd, &sb) < 0) { + printf("splitfs_open: stat failed\n"); + close(conffd); + return(ENOENT); + } + if (!S_ISREG(sb.st_mode)) { + printf("splitfs_open: not a file\n"); + close(conffd); + return(EISDIR); /* best guess */ + } + + /* Allocate a split_file structure, populate it from the config file */ + sf = malloc(sizeof(struct split_file)); + bzero(sf, sizeof(struct split_file)); + buf = malloc(CONF_BUF); + while (fgetstr(buf, CONF_BUF, conffd) > 0) { + cp = buf; + while ((*cp != '\0') && (isspace(*cp) == 0)) + cp++; + if (*cp != '\0') { + *cp = '\0'; + cp++; + } + while ((*cp != '\0') && (isspace(*cp) != 0)) + cp++; + if (*cp == '\0') + cp = buf; + sf->filesc++; + sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc); + sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc); + sf->filesv[sf->filesc - 1] = strdup(buf); + sf->descsv[sf->filesc - 1] = strdup(cp); + } + free(buf); + close(conffd); + + if (sf->filesc == 0) { + split_file_destroy(sf); + return(ENOENT); + } + errno = split_openfile(sf); + if (errno != 0) { + split_file_destroy(sf); + return(ENOENT); + } + + /* Looks OK, we'll take it */ + f->f_fsdata = sf; + return (0); +} + +static int +splitfs_close(struct open_file *f) +{ + int fd; + struct split_file *sf; + + sf = (struct split_file *)f->f_fsdata; + fd = sf->curfd; + split_file_destroy(sf); + return(close(fd)); +} + +static int +splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + ssize_t nread; + size_t totread; + struct split_file *sf; + + sf = (struct split_file *)f->f_fsdata; + totread = 0; + do { + nread = read(sf->curfd, buf, size - totread); + + /* Error? */ + if (nread == -1) + return (errno); + + sf->tot_pos += nread; + sf->file_pos += nread; + totread += nread; + buf = (char *)buf + nread; + + if (totread < size) { /* EOF */ + if (sf->curfile == (sf->filesc - 1)) /* Last slice */ + break; + + /* Close previous slice */ + if (close(sf->curfd) != 0) + return (errno); + + sf->curfile++; + errno = split_openfile(sf); + if (errno) + return (errno); + } + } while (totread < size); + + if (resid != NULL) + *resid = size - totread; + + return (0); +} + +static off_t +splitfs_seek(struct open_file *f, off_t offset, int where) +{ + int nread; + size_t resid; + off_t new_pos, seek_by; + struct split_file *sf; + + sf = (struct split_file *)f->f_fsdata; + + seek_by = offset; + switch (where) { + case SEEK_SET: + seek_by -= sf->tot_pos; + break; + case SEEK_CUR: + break; + case SEEK_END: + panic("splitfs_seek: SEEK_END not supported"); + break; + default: + errno = EINVAL; + return (-1); + } + + if (seek_by > 0) { + /* + * Seek forward - implemented using splitfs_read(), because otherwise we'll be + * unable to detect that we have crossed slice boundary and hence + * unable to do a long seek crossing that boundary. + */ + void *tmp; + + tmp = malloc(SEEK_BUF); + if (tmp == NULL) { + errno = ENOMEM; + return (-1); + } + + nread = 0; + for (; seek_by > 0; seek_by -= nread) { + resid = 0; + errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid); + nread = min(seek_by, SEEK_BUF) - resid; + if ((errno != 0) || (nread == 0)) + /* Error or EOF */ + break; + } + free(tmp); + if (errno != 0) + return (-1); + } + + if (seek_by != 0) { + /* Seek backward or seek past the boundary of the last slice */ + if (sf->file_pos + seek_by < 0) + panic("splitfs_seek: can't seek past the beginning of the slice"); + new_pos = lseek(sf->curfd, seek_by, SEEK_CUR); + if (new_pos < 0) { + errno = EINVAL; + return (-1); + } + sf->tot_pos += new_pos - sf->file_pos; + sf->file_pos = new_pos; + } + + return (sf->tot_pos); +} + +static int +splitfs_stat(struct open_file *f, struct stat *sb) +{ + int result; + struct split_file *sf = (struct split_file *)f->f_fsdata; + + /* stat as normal, but indicate that size is unknown */ + if ((result = fstat(sf->curfd, sb)) == 0) + sb->st_size = -1; + return (result); +} diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h new file mode 100644 index 000000000000..bddfa76657d6 --- /dev/null +++ b/stand/libsa/stand.h @@ -0,0 +1,426 @@ +/* + * Copyright (c) 1998 Michael Smith. + * 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 AUTHOR 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 AUTHOR 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$ + * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ + */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)stand.h 8.1 (Berkeley) 6/11/93 + */ + +#ifndef STAND_H +#define STAND_H + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/stat.h> +#include <sys/dirent.h> + +/* this header intentionally exports NULL from <string.h> */ +#include <string.h> + +#define CHK(fmt, args...) printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args) +#define PCHK(fmt, args...) {printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args); getchar();} + +/* Avoid unwanted userlandish components */ +#define _KERNEL +#include <sys/errno.h> +#undef _KERNEL + +/* special stand error codes */ +#define EADAPT (ELAST+1) /* bad adaptor */ +#define ECTLR (ELAST+2) /* bad controller */ +#define EUNIT (ELAST+3) /* bad unit */ +#define ESLICE (ELAST+4) /* bad slice */ +#define EPART (ELAST+5) /* bad partition */ +#define ERDLAB (ELAST+6) /* can't read disk label */ +#define EUNLAB (ELAST+7) /* unlabeled disk */ +#define EOFFSET (ELAST+8) /* relative seek not supported */ +#define ESALAST (ELAST+8) /* */ + +struct open_file; + +/* + * This structure is used to define file system operations in a file system + * independent way. + * + * XXX note that filesystem providers should export a pointer to their fs_ops + * struct, so that consumers can reference this and thus include the + * filesystems that they require. + */ +struct fs_ops { + const char *fs_name; + int (*fo_open)(const char *path, struct open_file *f); + int (*fo_close)(struct open_file *f); + int (*fo_read)(struct open_file *f, void *buf, + size_t size, size_t *resid); + int (*fo_write)(struct open_file *f, void *buf, + size_t size, size_t *resid); + off_t (*fo_seek)(struct open_file *f, off_t offset, int where); + int (*fo_stat)(struct open_file *f, struct stat *sb); + int (*fo_readdir)(struct open_file *f, struct dirent *d); +}; + +/* + * libstand-supplied filesystems + */ +extern struct fs_ops ufs_fsops; +extern struct fs_ops tftp_fsops; +extern struct fs_ops nfs_fsops; +extern struct fs_ops cd9660_fsops; +extern struct fs_ops nandfs_fsops; +extern struct fs_ops gzipfs_fsops; +extern struct fs_ops bzipfs_fsops; +extern struct fs_ops dosfs_fsops; +extern struct fs_ops ext2fs_fsops; +extern struct fs_ops splitfs_fsops; +extern struct fs_ops pkgfs_fsops; + +/* where values for lseek(2) */ +#define SEEK_SET 0 /* set file offset to offset */ +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#define SEEK_END 2 /* set file offset to EOF plus offset */ + +/* + * Device switch + */ +struct devsw { + const char dv_name[8]; + int dv_type; /* opaque type constant, arch-dependant */ + int (*dv_init)(void); /* early probe call */ + int (*dv_strategy)(void *devdata, int rw, daddr_t blk, + size_t size, char *buf, size_t *rsize); + int (*dv_open)(struct open_file *f, ...); + int (*dv_close)(struct open_file *f); + int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data); + int (*dv_print)(int verbose); /* print device information */ + void (*dv_cleanup)(void); +}; + +/* + * libstand-supplied device switch + */ +extern struct devsw netdev; + +extern int errno; + +/* + * Generic device specifier; architecture-dependent + * versions may be larger, but should be allowed to + * overlap. + */ +struct devdesc +{ + struct devsw *d_dev; + int d_type; +#define DEVT_NONE 0 +#define DEVT_DISK 1 +#define DEVT_NET 2 +#define DEVT_CD 3 +#define DEVT_ZFS 4 +#define DEVT_FD 5 + int d_unit; + void *d_opendata; +}; + +struct open_file { + int f_flags; /* see F_* below */ + struct devsw *f_dev; /* pointer to device operations */ + void *f_devdata; /* device specific data */ + struct fs_ops *f_ops; /* pointer to file system operations */ + void *f_fsdata; /* file system specific data */ + off_t f_offset; /* current file offset */ + char *f_rabuf; /* readahead buffer pointer */ + size_t f_ralen; /* valid data in readahead buffer */ + off_t f_raoffset; /* consumer offset in readahead buffer */ +#define SOPEN_RASIZE 512 +}; + +#define SOPEN_MAX 64 +extern struct open_file files[]; + +/* f_flags values */ +#define F_READ 0x0001 /* file opened for reading */ +#define F_WRITE 0x0002 /* file opened for writing */ +#define F_RAW 0x0004 /* raw device open - no file system */ +#define F_NODEV 0x0008 /* network open - no device */ +#define F_MASK 0xFFFF +/* Mode modifier for strategy() */ +#define F_NORA (0x01 << 16) /* Disable Read-Ahead */ + +#define isascii(c) (((c) & ~0x7F) == 0) + +static __inline int isupper(int c) +{ + return c >= 'A' && c <= 'Z'; +} + +static __inline int islower(int c) +{ + return c >= 'a' && c <= 'z'; +} + +static __inline int isspace(int c) +{ + return c == ' ' || (c >= 0x9 && c <= 0xd); +} + +static __inline int isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +static __inline int isxdigit(int c) +{ + return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static __inline int isalpha(int c) +{ + return isupper(c) || islower(c); +} + +static __inline int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +static __inline int toupper(int c) +{ + return islower(c) ? c - 'a' + 'A' : c; +} + +static __inline int tolower(int c) +{ + return isupper(c) ? c - 'A' + 'a' : c; +} + +/* sbrk emulation */ +extern void setheap(void *base, void *top); +extern char *sbrk(int incr); + +/* Matt Dillon's zalloc/zmalloc */ +extern void *malloc(size_t bytes); +extern void free(void *ptr); +/*#define free(p) {CHK("free %p", p); free(p);} */ /* use for catching guard violations */ +extern void *calloc(size_t n1, size_t n2); +extern void *realloc(void *ptr, size_t size); +extern void *reallocf(void *ptr, size_t size); +extern void mallocstats(void); + +extern int printf(const char *fmt, ...) __printflike(1, 2); +extern void vprintf(const char *fmt, __va_list); +extern int sprintf(char *buf, const char *cfmt, ...) __printflike(2, 3); +extern int snprintf(char *buf, size_t size, const char *cfmt, ...) __printflike(3, 4); +extern void vsprintf(char *buf, const char *cfmt, __va_list); + +extern void twiddle(u_int callerdiv); +extern void twiddle_divisor(u_int globaldiv); + +extern void ngets(char *, int); +#define gets(x) ngets((x), 0) +extern int fgetstr(char *buf, int size, int fd); + +extern int open(const char *, int); +#define O_RDONLY 0x0 +#define O_WRONLY 0x1 +#define O_RDWR 0x2 +extern int close(int); +extern void closeall(void); +extern ssize_t read(int, void *, size_t); +extern ssize_t write(int, void *, size_t); +extern struct dirent *readdirfd(int); + +extern void srandom(u_long seed); +extern u_long random(void); + +/* imports from stdlib, locally modified */ +extern long strtol(const char *, char **, int); +extern unsigned long strtoul(const char *, char **, int); +extern char *optarg; /* getopt(3) external variables */ +extern int optind, opterr, optopt, optreset; +extern int getopt(int, char * const [], const char *); + +/* pager.c */ +extern void pager_open(void); +extern void pager_close(void); +extern int pager_output(const char *lines); +extern int pager_file(const char *fname); + +/* No signal state to preserve */ +#define setjmp _setjmp +#define longjmp _longjmp + +/* environment.c */ +#define EV_DYNAMIC (1<<0) /* value was dynamically allocated, free if changed/unset */ +#define EV_VOLATILE (1<<1) /* value is volatile, make a copy of it */ +#define EV_NOHOOK (1<<2) /* don't call hook when setting */ + +struct env_var; +typedef char *(ev_format_t)(struct env_var *ev); +typedef int (ev_sethook_t)(struct env_var *ev, int flags, + const void *value); +typedef int (ev_unsethook_t)(struct env_var *ev); + +struct env_var +{ + char *ev_name; + int ev_flags; + void *ev_value; + ev_sethook_t *ev_sethook; + ev_unsethook_t *ev_unsethook; + struct env_var *ev_next, *ev_prev; +}; +extern struct env_var *environ; + +extern struct env_var *env_getenv(const char *name); +extern int env_setenv(const char *name, int flags, + const void *value, ev_sethook_t sethook, + ev_unsethook_t unsethook); +extern char *getenv(const char *name); +extern int setenv(const char *name, const char *value, + int overwrite); +extern int putenv(const char *string); +extern int unsetenv(const char *name); + +extern ev_sethook_t env_noset; /* refuse set operation */ +extern ev_unsethook_t env_nounset; /* refuse unset operation */ + +/* BCD conversions (undocumented) */ +extern u_char const bcd2bin_data[]; +extern u_char const bin2bcd_data[]; +extern char const hex2ascii_data[]; + +#define bcd2bin(bcd) (bcd2bin_data[bcd]) +#define bin2bcd(bin) (bin2bcd_data[bin]) +#define hex2ascii(hex) (hex2ascii_data[hex]) + +/* min/max (undocumented) */ +static __inline int imax(int a, int b) { return (a > b ? a : b); } +static __inline int imin(int a, int b) { return (a < b ? a : b); } +static __inline long lmax(long a, long b) { return (a > b ? a : b); } +static __inline long lmin(long a, long b) { return (a < b ? a : b); } +static __inline u_int max(u_int a, u_int b) { return (a > b ? a : b); } +static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); } +static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); } +static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); } +static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); } +static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); } + + +/* null functions for device/filesystem switches (undocumented) */ +extern int nodev(void); +extern int noioctl(struct open_file *, u_long, void *); +extern void nullsys(void); + +extern int null_open(const char *path, struct open_file *f); +extern int null_close(struct open_file *f); +extern int null_read(struct open_file *f, void *buf, size_t size, size_t *resid); +extern int null_write(struct open_file *f, void *buf, size_t size, size_t *resid); +extern off_t null_seek(struct open_file *f, off_t offset, int where); +extern int null_stat(struct open_file *f, struct stat *sb); +extern int null_readdir(struct open_file *f, struct dirent *d); + + +/* + * Machine dependent functions and data, must be provided or stubbed by + * the consumer + */ +extern void exit(int); +extern int getchar(void); +extern int ischar(void); +extern void putchar(int); +extern int devopen(struct open_file *, const char *, const char **); +extern int devclose(struct open_file *f); +extern void panic(const char *, ...) __dead2 __printflike(1, 2); +extern struct fs_ops *file_system[]; +extern struct fs_ops *exclusive_file_system; +extern struct devsw *devsw[]; + +/* + * Expose byteorder(3) functions. + */ +#ifndef _BYTEORDER_PROTOTYPED +#define _BYTEORDER_PROTOTYPED +extern uint32_t htonl(uint32_t); +extern uint16_t htons(uint16_t); +extern uint32_t ntohl(uint32_t); +extern uint16_t ntohs(uint16_t); +#endif + +#ifndef _BYTEORDER_FUNC_DEFINED +#define _BYTEORDER_FUNC_DEFINED +#define htonl(x) __htonl(x) +#define htons(x) __htons(x) +#define ntohl(x) __ntohl(x) +#define ntohs(x) __ntohs(x) +#endif + +void *Malloc(size_t, const char *, int); +void *Calloc(size_t, size_t, const char *, int); +void *Realloc(void *, size_t, const char *, int); +void Free(void *, const char *, int); + +#if 1 +#define malloc(x) Malloc(x, __FILE__, __LINE__) +#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__) +#define free(x) Free(x, __FILE__, __LINE__) +#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__) +#else +#define malloc(x) Malloc(x, NULL, 0) +#define calloc(x, y) Calloc(x, y, NULL, 0) +#define free(x) Free(x, NULL, 0) +#define realloc(x, y) Realloc(x, y, NULL, 0) +#endif + +#endif /* STAND_H */ diff --git a/stand/libsa/stat.c b/stand/libsa/stat.c new file mode 100644 index 000000000000..9875372b441d --- /dev/null +++ b/stand/libsa/stat.c @@ -0,0 +1,52 @@ +/* $NetBSD: stat.c,v 1.4 1996/01/13 22:25:43 leo Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)stat.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +int +stat(str, sb) + const char *str; + struct stat *sb; +{ + int fd, rv; + + fd = open(str, O_RDONLY); + if (fd < 0) + return (-1); + rv = fstat(fd, sb); + (void)close(fd); + return (rv); +} diff --git a/stand/libsa/strcasecmp.c b/stand/libsa/strcasecmp.c new file mode 100644 index 000000000000..f8131019384c --- /dev/null +++ b/stand/libsa/strcasecmp.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/cdefs.h> +#include <string.h> +#include "stand.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +int +strcasecmp(s1, s2) + const char *s1, *s2; +{ + const u_char + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); +} + +int +strncasecmp(s1, s2, n) + const char *s1, *s2; + size_t n; +{ + if (n != 0) { + const u_char + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + do { + if (tolower(*us1) != tolower(*us2++)) + return (tolower(*us1) - tolower(*--us2)); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +} diff --git a/stand/libsa/strdup.c b/stand/libsa/strdup.c new file mode 100644 index 000000000000..de6c4def8bc6 --- /dev/null +++ b/stand/libsa/strdup.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "stand.h" +#include <stddef.h> +#include <string.h> + +char * +strdup(str) + const char *str; +{ + size_t len; + char *copy = NULL; + + if (str != NULL) { + len = strlen(str) + 1; + if ((copy = malloc(len)) == NULL) + return (NULL); + memcpy(copy, str, len); + } + return (copy); +} diff --git a/stand/libsa/strerror.c b/stand/libsa/strerror.c new file mode 100644 index 000000000000..e08ca0a7f175 --- /dev/null +++ b/stand/libsa/strerror.c @@ -0,0 +1,87 @@ +/* $NetBSD: strerror.c,v 1.12 1997/01/25 00:37:50 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +static struct +{ + int err; + char *msg; +} errtab[] = { + {0, "no error"}, + /* standard errors */ + {EPERM, "operation not permitted"}, + {ENOENT, "no such file or directory"}, + {EIO, "input/output error"}, + {ENXIO, "device not configured"}, + {ENOEXEC, "exec format error"}, + {EBADF, "bad file descriptor"}, + {ENOMEM, "cannot allocate memory"}, + {ENODEV, "operation not supported by device"}, + {ENOTDIR, "not a directory"}, + {EISDIR, "is a directory"}, + {EINVAL, "invalid argument"}, + {EMFILE, "too many open files"}, + {EFBIG, "file too large"}, + {EROFS, "read-only filesystem"}, + {EOPNOTSUPP, "operation not supported"}, + {ETIMEDOUT, "operation timed out"}, + {ESTALE, "stale NFS file handle"}, + {EBADRPC, "RPC struct is bad"}, + {EFTYPE, "inappropriate file type or format"}, + + {EADAPT, "bad adaptor number"}, + {ECTLR, "bad controller number"}, + {EUNIT, "bad unit number"}, + {ESLICE, "bad slice number"}, + {EPART, "bad partition"}, + {ERDLAB, "can't read disk label"}, + {EUNLAB, "disk unlabelled"}, + {EOFFSET, "illegal seek"}, + {0, NULL} +}; + + +char * +strerror(int err) +{ + static char msg[32]; + int i; + + for (i = 0; errtab[i].msg != NULL; i++) + if (errtab[i].err == err) + return(errtab[i].msg); + sprintf(msg, "unknown error (%d)", err); + return(msg); +} diff --git a/stand/libsa/strtol.c b/stand/libsa/strtol.c new file mode 100644 index 000000000000..e15339a60d41 --- /dev/null +++ b/stand/libsa/strtol.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "stand.h" +#include <limits.h> + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(nptr, endptr, base) + const char *nptr; + char **endptr; + int base; +{ + const char *s; + unsigned long acc; + unsigned char c; + unsigned long cutoff; + int neg = 0, any, cutlim; + + /* Be sensible about NULL strings */ + if (nptr == NULL) + nptr = ""; + s = nptr; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/stand/libsa/strtoul.c b/stand/libsa/strtoul.c new file mode 100644 index 000000000000..0c7147c2ab67 --- /dev/null +++ b/stand/libsa/strtoul.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" +#include <limits.h> + +/* + * Convert a string to an unsigned long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + const char *s; + unsigned long acc; + char c; + unsigned long cutoff; + int neg, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (isspace((unsigned char)c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULONG_MAX / base; + cutlim = ULONG_MAX % base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/stand/libsa/tftp.c b/stand/libsa/tftp.c new file mode 100644 index 000000000000..9bef4643d25f --- /dev/null +++ b/stand/libsa/tftp.c @@ -0,0 +1,785 @@ +/* $NetBSD: tftp.c,v 1.4 1997/09/17 16:57:07 drochner Exp $ */ + +/* + * Copyright (c) 1996 + * Matthias Drochner. 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 for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Simple TFTP implementation for libsa. + * Assumes: + * - socket descriptor (int) at open_file->f_devdata + * - server host IP in global servip + * Restrictions: + * - read only + * - lseek only with SEEK_SET or SEEK_CUR + * - no big time differences between transfers (<tftp timeout) + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netinet/udp.h> +#include <netinet/in_systm.h> +#include <arpa/tftp.h> + +#include <string.h> + +#include "stand.h" +#include "net.h" +#include "netif.h" + +#include "tftp.h" + +struct tftp_handle; + +static int tftp_open(const char *path, struct open_file *f); +static int tftp_close(struct open_file *f); +static int tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len); +static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t tftp_seek(struct open_file *f, off_t offset, int where); +static int tftp_set_blksize(struct tftp_handle *h, const char *str); +static int tftp_stat(struct open_file *f, struct stat *sb); +static ssize_t sendrecv_tftp(struct tftp_handle *h, + ssize_t (*sproc)(struct iodesc *, void *, size_t), + void *sbuf, size_t ssize, + ssize_t (*rproc)(struct tftp_handle *h, void **, void **, time_t, unsigned short *), + void **, void **, unsigned short *rtype); + +struct fs_ops tftp_fsops = { + "tftp", + tftp_open, + tftp_close, + tftp_read, + tftp_write, + tftp_seek, + tftp_stat, + null_readdir +}; + +extern struct in_addr servip; + +static int tftpport = 2000; +static int is_open = 0; + +/* + * The legacy TFTP_BLKSIZE value was SEGSIZE(512). + * TFTP_REQUESTED_BLKSIZE of 1428 is (Ethernet MTU, less the TFTP, UDP and + * IP header lengths). + */ +#define TFTP_REQUESTED_BLKSIZE 1428 + +/* + * Choose a blksize big enough so we can test with Ethernet + * Jumbo frames in the future. + */ +#define TFTP_MAX_BLKSIZE 9008 + +struct tftp_handle { + struct iodesc *iodesc; + int currblock; /* contents of lastdata */ + int islastblock; /* flag */ + int validsize; + int off; + char *path; /* saved for re-requests */ + unsigned int tftp_blksize; + unsigned long tftp_tsize; + void *pkt; + struct tftphdr *tftp_hdr; +}; + +#define TFTP_MAX_ERRCODE EOPTNEG +static const int tftperrors[TFTP_MAX_ERRCODE + 1] = { + 0, /* ??? */ + ENOENT, + EPERM, + ENOSPC, + EINVAL, /* ??? */ + EINVAL, /* ??? */ + EEXIST, + EINVAL, /* ??? */ + EINVAL, /* Option negotiation failed. */ +}; + +static int tftp_getnextblock(struct tftp_handle *h); + +/* send error message back. */ +static void +tftp_senderr(struct tftp_handle *h, u_short errcode, const char *msg) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + u_char space[63]; /* +1 from t */ + } __packed __aligned(4) wbuf; + char *wtail; + int len; + + len = strlen(msg); + if (len > sizeof(wbuf.space)) + len = sizeof(wbuf.space); + + wbuf.t.th_opcode = htons((u_short) ERROR); + wbuf.t.th_code = htons(errcode); + + wtail = wbuf.t.th_msg; + bcopy(msg, wtail, len); + wtail[len] = '\0'; + wtail += len + 1; + + sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); +} + +static void +tftp_sendack(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + } __packed __aligned(4) wbuf; + char *wtail; + + wbuf.t.th_opcode = htons((u_short) ACK); + wtail = (char *) &wbuf.t.th_block; + wbuf.t.th_block = htons((u_short) h->currblock); + wtail += 2; + + sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); +} + +static ssize_t +recvtftp(struct tftp_handle *h, void **pkt, void **payload, time_t tleft, + unsigned short *rtype) +{ + struct iodesc *d = h->iodesc; + struct tftphdr *t; + void *ptr = NULL; + ssize_t len; + + errno = 0; + + len = readudp(d, &ptr, (void **)&t, tleft); + + if (len < 4) { + free(ptr); + return (-1); + } + + *rtype = ntohs(t->th_opcode); + switch (ntohs(t->th_opcode)) { + case DATA: { + int got; + + if (htons(t->th_block) != (u_short) d->xid) { + /* + * Expected block? + */ + free(ptr); + return (-1); + } + if (d->xid == 1) { + /* + * First data packet from new port. + */ + struct udphdr *uh; + uh = (struct udphdr *) t - 1; + d->destport = uh->uh_sport; + } /* else check uh_sport has not changed??? */ + got = len - (t->th_data - (char *)t); + *pkt = ptr; + *payload = t; + return (got); + } + case ERROR: + if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) { + printf("illegal tftp error %d\n", ntohs(t->th_code)); + errno = EIO; + } else { +#ifdef TFTP_DEBUG + printf("tftp-error %d\n", ntohs(t->th_code)); +#endif + errno = tftperrors[ntohs(t->th_code)]; + } + free(ptr); + return (-1); + case OACK: { + struct udphdr *uh; + int tftp_oack_len; + + /* + * Unexpected OACK. TFTP transfer already in progress. + * Drop the pkt. + */ + if (d->xid != 1) { + free(ptr); + return (-1); + } + + /* + * Remember which port this OACK came from, because we need + * to send the ACK or errors back to it. + */ + uh = (struct udphdr *) t - 1; + d->destport = uh->uh_sport; + + /* Parse options ACK-ed by the server. */ + tftp_oack_len = len - sizeof(t->th_opcode); + if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) { + tftp_senderr(h, EOPTNEG, "Malformed OACK"); + errno = EIO; + free(ptr); + return (-1); + } + *pkt = ptr; + *payload = t; + return (0); + } + default: +#ifdef TFTP_DEBUG + printf("tftp type %d not handled\n", ntohs(t->th_opcode)); +#endif + free(ptr); + return (-1); + } +} + +/* send request, expect first block (or error) */ +static int +tftp_makereq(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + u_char space[FNAME_SIZE + 6]; + } __packed __aligned(4) wbuf; + char *wtail; + int l; + ssize_t res; + void *pkt; + struct tftphdr *t; + char *tftp_blksize = NULL; + int blksize_l; + unsigned short rtype = 0; + + /* + * Allow overriding default TFTP block size by setting + * a tftp.blksize environment variable. + */ + if ((tftp_blksize = getenv("tftp.blksize")) != NULL) { + tftp_set_blksize(h, tftp_blksize); + } + + wbuf.t.th_opcode = htons((u_short) RRQ); + wtail = wbuf.t.th_stuff; + l = strlen(h->path); +#ifdef TFTP_PREPEND_PATH + if (l > FNAME_SIZE - (sizeof(TFTP_PREPEND_PATH) - 1)) + return (ENAMETOOLONG); + bcopy(TFTP_PREPEND_PATH, wtail, sizeof(TFTP_PREPEND_PATH) - 1); + wtail += sizeof(TFTP_PREPEND_PATH) - 1; +#else + if (l > FNAME_SIZE) + return (ENAMETOOLONG); +#endif + bcopy(h->path, wtail, l + 1); + wtail += l + 1; + bcopy("octet", wtail, 6); + wtail += 6; + bcopy("blksize", wtail, 8); + wtail += 8; + blksize_l = sprintf(wtail, "%d", h->tftp_blksize); + wtail += blksize_l + 1; + bcopy("tsize", wtail, 6); + wtail += 6; + bcopy("0", wtail, 2); + wtail += 2; + + /* h->iodesc->myport = htons(--tftpport); */ + h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); + h->iodesc->destport = htons(IPPORT_TFTP); + h->iodesc->xid = 1; /* expected block */ + + h->currblock = 0; + h->islastblock = 0; + h->validsize = 0; + + pkt = NULL; + res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, + &recvtftp, &pkt, (void **)&t, &rtype); + if (res == -1) { + free(pkt); + return (errno); + } + + free(h->pkt); + h->pkt = pkt; + h->tftp_hdr = t; + + if (rtype == OACK) + return (tftp_getnextblock(h)); + + /* Server ignored our blksize request, revert to TFTP default. */ + h->tftp_blksize = SEGSIZE; + + switch (rtype) { + case DATA: { + h->currblock = 1; + h->validsize = res; + h->islastblock = 0; + if (res < h->tftp_blksize) { + h->islastblock = 1; /* very short file */ + tftp_sendack(h); + } + return (0); + } + case ERROR: + default: + return (errno); + } + +} + +/* ack block, expect next */ +static int +tftp_getnextblock(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + } __packed __aligned(4) wbuf; + char *wtail; + int res; + void *pkt; + struct tftphdr *t; + unsigned short rtype = 0; + wbuf.t.th_opcode = htons((u_short) ACK); + wtail = (char *) &wbuf.t.th_block; + wbuf.t.th_block = htons((u_short) h->currblock); + wtail += 2; + + h->iodesc->xid = h->currblock + 1; /* expected block */ + + pkt = NULL; + res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, + &recvtftp, &pkt, (void **)&t, &rtype); + + if (res == -1) { /* 0 is OK! */ + free(pkt); + return (errno); + } + + free(h->pkt); + h->pkt = pkt; + h->tftp_hdr = t; + h->currblock++; + h->validsize = res; + if (res < h->tftp_blksize) + h->islastblock = 1; /* EOF */ + + if (h->islastblock == 1) { + /* Send an ACK for the last block */ + wbuf.t.th_block = htons((u_short) h->currblock); + sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); + } + + return (0); +} + +static int +tftp_open(const char *path, struct open_file *f) +{ + struct tftp_handle *tftpfile; + struct iodesc *io; + int res; + size_t pathsize; + const char *extraslash; + + if (netproto != NET_TFTP) + return (EINVAL); + + if (f->f_dev->dv_type != DEVT_NET) + return (EINVAL); + + if (is_open) + return (EBUSY); + + tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile)); + if (!tftpfile) + return (ENOMEM); + + memset(tftpfile, 0, sizeof(*tftpfile)); + tftpfile->tftp_blksize = TFTP_REQUESTED_BLKSIZE; + tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); + if (io == NULL) + return (EINVAL); + + io->destip = servip; + tftpfile->off = 0; + pathsize = (strlen(rootpath) + 1 + strlen(path) + 1) * sizeof(char); + tftpfile->path = malloc(pathsize); + if (tftpfile->path == NULL) { + free(tftpfile); + return(ENOMEM); + } + if (rootpath[strlen(rootpath) - 1] == '/' || path[0] == '/') + extraslash = ""; + else + extraslash = "/"; + res = snprintf(tftpfile->path, pathsize, "%s%s%s", + rootpath, extraslash, path); + if (res < 0 || res > pathsize) { + free(tftpfile->path); + free(tftpfile); + return(ENOMEM); + } + + res = tftp_makereq(tftpfile); + + if (res) { + free(tftpfile->path); + free(tftpfile->pkt); + free(tftpfile); + return (res); + } + f->f_fsdata = (void *) tftpfile; + is_open = 1; + return (0); +} + +static int +tftp_read(struct open_file *f, void *addr, size_t size, + size_t *resid /* out */) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + + while (size > 0) { + int needblock, count; + + twiddle(32); + + needblock = tftpfile->off / tftpfile->tftp_blksize + 1; + + if (tftpfile->currblock > needblock) { /* seek backwards */ + tftp_senderr(tftpfile, 0, "No error: read aborted"); + tftp_makereq(tftpfile); /* no error check, it worked + * for open */ + } + + while (tftpfile->currblock < needblock) { + int res; + + res = tftp_getnextblock(tftpfile); + if (res) { /* no answer */ +#ifdef TFTP_DEBUG + printf("tftp: read error\n"); +#endif + return (res); + } + if (tftpfile->islastblock) + break; + } + + if (tftpfile->currblock == needblock) { + int offinblock, inbuffer; + + offinblock = tftpfile->off % tftpfile->tftp_blksize; + + inbuffer = tftpfile->validsize - offinblock; + if (inbuffer < 0) { +#ifdef TFTP_DEBUG + printf("tftp: invalid offset %d\n", + tftpfile->off); +#endif + return (EINVAL); + } + count = (size < inbuffer ? size : inbuffer); + bcopy(tftpfile->tftp_hdr->th_data + offinblock, + addr, count); + + addr = (char *)addr + count; + tftpfile->off += count; + size -= count; + + if ((tftpfile->islastblock) && (count == inbuffer)) + break; /* EOF */ + } else { +#ifdef TFTP_DEBUG + printf("tftp: block %d not found\n", needblock); +#endif + return (EINVAL); + } + + } + + if (resid) + *resid = size; + return (0); +} + +static int +tftp_close(struct open_file *f) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + + /* let it time out ... */ + + if (tftpfile) { + free(tftpfile->path); + free(tftpfile->pkt); + free(tftpfile); + } + is_open = 0; + return (0); +} + +static int +tftp_write(struct open_file *f __unused, void *start __unused, size_t size __unused, + size_t *resid __unused /* out */) +{ + return (EROFS); +} + +static int +tftp_stat(struct open_file *f, struct stat *sb) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + + sb->st_mode = 0444 | S_IFREG; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_size = (off_t) tftpfile->tftp_tsize; + return (0); +} + +static off_t +tftp_seek(struct open_file *f, off_t offset, int where) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + + switch (where) { + case SEEK_SET: + tftpfile->off = offset; + break; + case SEEK_CUR: + tftpfile->off += offset; + break; + default: + errno = EOFFSET; + return (-1); + } + return (tftpfile->off); +} + +static ssize_t +sendrecv_tftp(struct tftp_handle *h, + ssize_t (*sproc)(struct iodesc *, void *, size_t), + void *sbuf, size_t ssize, + ssize_t (*rproc)(struct tftp_handle *, void **, void **, time_t, + unsigned short *), + void **pkt, void **payload, unsigned short *rtype) +{ + struct iodesc *d = h->iodesc; + ssize_t cc; + time_t t, t1, tleft; + +#ifdef TFTP_DEBUG + if (debug) + printf("sendrecv: called\n"); +#endif + + tleft = MINTMO; + t = t1 = getsecs(); + for (;;) { + if ((getsecs() - t) > MAXTMO) { + errno = ETIMEDOUT; + return -1; + } + + cc = (*sproc)(d, sbuf, ssize); + if (cc != -1 && cc < ssize) + panic("sendrecv: short write! (%zd < %zu)", + cc, ssize); + + if (cc == -1) { + /* Error on transmit; wait before retrying */ + while ((getsecs() - t1) < tleft); + continue; + } + +recvnext: + /* Try to get a packet and process it. */ + cc = (*rproc)(h, pkt, payload, tleft, rtype); + /* Return on data, EOF or real error. */ + if (cc != -1 || errno != 0) + return (cc); + if ((getsecs() - t1) < tleft) { + goto recvnext; + } + + /* Timed out or didn't get the packet we're waiting for */ + tleft += MINTMO; + if (tleft > (2 * MINTMO)) { + tleft = (2 * MINTMO); + } + t1 = getsecs(); + } +} + +static int +tftp_set_blksize(struct tftp_handle *h, const char *str) +{ + char *endptr; + int new_blksize; + int ret = 0; + + if (h == NULL || str == NULL) + return (ret); + + new_blksize = + (unsigned int)strtol(str, &endptr, 0); + + /* + * Only accept blksize value if it is numeric. + * RFC2348 specifies that acceptable values are 8-65464. + * Let's choose a limit less than MAXRSPACE. + */ + if (*endptr == '\0' && new_blksize >= 8 + && new_blksize <= TFTP_MAX_BLKSIZE) { + h->tftp_blksize = new_blksize; + ret = 1; + } + + return (ret); +} + +/* + * In RFC2347, the TFTP Option Acknowledgement package (OACK) + * is used to acknowledge a client's option negotiation request. + * The format of an OACK packet is: + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * + * opc + * The opcode field contains a 6, for Option Acknowledgment. + * + * opt1 + * The first option acknowledgment, copied from the original + * request. + * + * value1 + * The acknowledged value associated with the first option. If + * and how this value may differ from the original request is + * detailed in the specification for the option. + * + * optN, valueN + * The final option/value acknowledgment pair. + */ +static int +tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) +{ + /* + * We parse the OACK strings into an array + * of name-value pairs. + */ + char *tftp_options[128] = { 0 }; + char *val = buf; + int i = 0; + int option_idx = 0; + int blksize_is_set = 0; + int tsize = 0; + + unsigned int orig_blksize; + + while (option_idx < 128 && i < len) { + if (buf[i] == '\0') { + if (&buf[i] > val) { + tftp_options[option_idx] = val; + val = &buf[i] + 1; + ++option_idx; + } + } + ++i; + } + + /* Save the block size we requested for sanity check later. */ + orig_blksize = h->tftp_blksize; + + /* + * Parse individual TFTP options. + * * "blksize" is specified in RFC2348. + * * "tsize" is specified in RFC2349. + */ + for (i = 0; i < option_idx; i += 2) { + if (strcasecmp(tftp_options[i], "blksize") == 0) { + if (i + 1 < option_idx) + blksize_is_set = + tftp_set_blksize(h, tftp_options[i + 1]); + } else if (strcasecmp(tftp_options[i], "tsize") == 0) { + if (i + 1 < option_idx) + tsize = strtol(tftp_options[i + 1], (char **)NULL, 10); + if (tsize != 0) + h->tftp_tsize = tsize; + } else { + /* Do not allow any options we did not expect to be ACKed. */ + printf("unexpected tftp option '%s'\n", tftp_options[i]); + return (-1); + } + } + + if (!blksize_is_set) { + /* + * If TFTP blksize was not set, try defaulting + * to the legacy TFTP blksize of SEGSIZE(512) + */ + h->tftp_blksize = SEGSIZE; + } else if (h->tftp_blksize > orig_blksize) { + /* + * Server should not be proposing block sizes that + * exceed what we said we can handle. + */ + printf("unexpected blksize %u\n", h->tftp_blksize); + return (-1); + } + +#ifdef TFTP_DEBUG + printf("tftp_blksize: %u\n", h->tftp_blksize); + printf("tftp_tsize: %lu\n", h->tftp_tsize); +#endif + return 0; +} diff --git a/stand/libsa/tftp.h b/stand/libsa/tftp.h new file mode 100644 index 000000000000..c56fb81aafaa --- /dev/null +++ b/stand/libsa/tftp.h @@ -0,0 +1,37 @@ +/* $NetBSD: tftp.h,v 1.1.1.1 1997/03/14 02:40:31 perry Exp $ */ + +/* + * Copyright (c) 1996 + * Matthias Drochner. 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 for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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$ + */ + + +#define IPPORT_TFTP 69 diff --git a/stand/libsa/twiddle.c b/stand/libsa/twiddle.c new file mode 100644 index 000000000000..31828542f7f3 --- /dev/null +++ b/stand/libsa/twiddle.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include "stand.h" + +/* Extra functions from NetBSD standalone printf.c */ + +static u_int globaldiv; + +void +twiddle(u_int callerdiv) +{ + static u_int callercnt, globalcnt, pos; + + callercnt++; + if (callerdiv > 1 && (callercnt % callerdiv) != 0) + return; + + globalcnt++; + if (globaldiv > 1 && (globalcnt % globaldiv) != 0) + return; + + putchar("|/-\\"[pos++ & 3]); + putchar('\b'); +} + +void +twiddle_divisor(u_int gdiv) +{ + + globaldiv = gdiv; +} diff --git a/stand/libsa/udp.c b/stand/libsa/udp.c new file mode 100644 index 000000000000..02ac62571fb7 --- /dev/null +++ b/stand/libsa/udp.c @@ -0,0 +1,180 @@ +/* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> + +#include <string.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> + +#include <netinet/in_pcb.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include "stand.h" +#include "net.h" + +/* Caller must leave room for ethernet, ip and udp headers in front!! */ +ssize_t +sendudp(struct iodesc *d, void *pkt, size_t len) +{ + ssize_t cc; + struct udpiphdr *ui; + struct udphdr *uh; + +#ifdef NET_DEBUG + if (debug) { + printf("sendudp: d=%lx called.\n", (long)d); + if (d) { + printf("saddr: %s:%d", + inet_ntoa(d->myip), ntohs(d->myport)); + printf(" daddr: %s:%d\n", + inet_ntoa(d->destip), ntohs(d->destport)); + } + } +#endif + + ui = (struct udpiphdr *)pkt - 1; + bzero(ui, sizeof(*ui)); + + uh = (struct udphdr *)pkt - 1; + len += sizeof(*uh); + + uh->uh_sport = d->myport; + uh->uh_dport = d->destport; + uh->uh_ulen = htons(len); + + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = uh->uh_ulen; + ui->ui_src = d->myip; + ui->ui_dst = d->destip; + +#ifndef UDP_NO_CKSUM + uh->uh_sum = in_cksum(ui, len + sizeof (struct ip)); +#endif + + cc = sendip(d, uh, len, IPPROTO_UDP); + if (cc == -1) + return (-1); + if (cc != len) + panic("sendudp: bad write (%zd != %zd)", cc, len); + return (cc - sizeof(*uh)); +} + +/* + * Receive a UDP packet and validate it is for us. + */ +ssize_t +readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft) +{ + ssize_t n; + struct udphdr *uh; + void *ptr; + +#ifdef NET_DEBUG + if (debug) + printf("readudp: called\n"); +#endif + + uh = NULL; + ptr = NULL; + n = readip(d, &ptr, (void **)&uh, tleft, IPPROTO_UDP); + if (n == -1 || n < sizeof(*uh) || n != ntohs(uh->uh_ulen)) { + free(ptr); + return (-1); + } + + if (uh->uh_dport != d->myport) { +#ifdef NET_DEBUG + if (debug) + printf("readudp: bad dport %d != %d\n", + d->myport, ntohs(uh->uh_dport)); +#endif + free(ptr); + return (-1); + } + +#ifndef UDP_NO_CKSUM + if (uh->uh_sum) { + struct udpiphdr *ui; + struct ip *ip; + struct ip tip; + + n = ntohs(uh->uh_ulen) + sizeof(*ip); + + /* Check checksum (must save and restore ip header) */ + ip = (struct ip *)uh - 1; + tip = *ip; + ui = (struct udpiphdr *)ip; + bzero(&ui->ui_x1, sizeof(ui->ui_x1)); + ui->ui_len = uh->uh_ulen; + if (in_cksum(ui, n) != 0) { +#ifdef NET_DEBUG + if (debug) + printf("readudp: bad cksum\n"); +#endif + free(ptr); + return (-1); + } + *ip = tip; + } +#endif + if (ntohs(uh->uh_ulen) < sizeof(*uh)) { +#ifdef NET_DEBUG + if (debug) + printf("readudp: bad udp len %d < %d\n", + ntohs(uh->uh_ulen), (int)sizeof(*uh)); +#endif + free(ptr); + return (-1); + } + + n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ? + ntohs(uh->uh_ulen) - sizeof(*uh) : n; + *pkt = ptr; + *payload = (void *)((uintptr_t)uh + sizeof(*uh)); + return (n); +} diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c new file mode 100644 index 000000000000..e0ceed804d9a --- /dev/null +++ b/stand/libsa/ufs.c @@ -0,0 +1,861 @@ +/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ + +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Stand-alone file reading package. + */ + +#include <sys/param.h> +#include <sys/disklabel.h> +#include <sys/time.h> +#include <ufs/ufs/dinode.h> +#include <ufs/ufs/dir.h> +#include <ufs/ffs/fs.h> +#include "stand.h" +#include "string.h" + +static int ufs_open(const char *path, struct open_file *f); +static int ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid); +static int ufs_close(struct open_file *f); +static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t ufs_seek(struct open_file *f, off_t offset, int where); +static int ufs_stat(struct open_file *f, struct stat *sb); +static int ufs_readdir(struct open_file *f, struct dirent *d); + +struct fs_ops ufs_fsops = { + "ufs", + ufs_open, + ufs_close, + ufs_read, + ufs_write, + ufs_seek, + ufs_stat, + ufs_readdir +}; + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + struct fs *f_fs; /* pointer to super-block */ + union dinode { + struct ufs1_dinode di1; + struct ufs2_dinode di2; + } f_di; /* copy of on-disk inode */ + int f_nindir[UFS_NIADDR]; + /* number of blocks mapped by + indirect block at level i */ + char *f_blk[UFS_NIADDR]; /* buffer for indirect block at + level i */ + size_t f_blksize[UFS_NIADDR]; + /* size of buffer */ + ufs2_daddr_t f_blkno[UFS_NIADDR];/* disk address of block in buffer */ + ufs2_daddr_t f_buf_blkno; /* block number of data block */ + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ +}; +#define DIP(fp, field) \ + ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ + (fp)->f_di.di1.field : (fp)->f_di.di2.field) + +static int read_inode(ino_t, struct open_file *); +static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); +static int buf_read_file(struct open_file *, char **, size_t *); +static int buf_write_file(struct open_file *, char *, size_t *); +static int search_directory(char *, struct open_file *, ino_t *); + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(inumber, f) + ino_t inumber; + struct open_file *f; +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + char *buf; + size_t rsize; + int rc; + + if (fs == NULL) + panic("fs == NULL"); + + /* + * Read inode and save it. + */ + buf = malloc(fs->fs_bsize); + twiddle(1); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, + buf, &rsize); + if (rc) + goto out; + if (rsize != fs->fs_bsize) { + rc = EIO; + goto out; + } + + if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) + fp->f_di.di1 = ((struct ufs1_dinode *)buf) + [ino_to_fsbo(fs, inumber)]; + else + fp->f_di.di2 = ((struct ufs2_dinode *)buf) + [ino_to_fsbo(fs, inumber)]; + + /* + * Clear out the old buffers + */ + { + int level; + + for (level = 0; level < UFS_NIADDR; level++) + fp->f_blkno[level] = -1; + fp->f_buf_blkno = -1; + } + fp->f_seekp = 0; +out: + free(buf); + return (rc); +} + +/* + * Given an offset in a file, find the disk block number that + * contains that block. + */ +static int +block_map(f, file_block, disk_block_p) + struct open_file *f; + ufs2_daddr_t file_block; + ufs2_daddr_t *disk_block_p; /* out */ +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + int level; + int idx; + ufs2_daddr_t ind_block_num; + int rc; + + /* + * Index structure of an inode: + * + * di_db[0..UFS_NDADDR-1] hold block numbers for blocks + * 0..UFS_NDADDR-1 + * + * di_ib[0] index block 0 is the single indirect block + * holds block numbers for blocks + * UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1 + * + * di_ib[1] index block 1 is the double indirect block + * holds block numbers for INDEX blocks for blocks + * UFS_NDADDR + NINDIR(fs) .. + * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 + * + * di_ib[2] index block 2 is the triple indirect block + * holds block numbers for double-indirect + * blocks for blocks + * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. + * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 + * + NINDIR(fs)**3 - 1 + */ + + if (file_block < UFS_NDADDR) { + /* Direct block. */ + *disk_block_p = DIP(fp, di_db[file_block]); + return (0); + } + + file_block -= UFS_NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < UFS_NIADDR; level++) { + if (file_block < fp->f_nindir[level]) + break; + file_block -= fp->f_nindir[level]; + } + if (level == UFS_NIADDR) { + /* Block number too high */ + return (EFBIG); + } + + ind_block_num = DIP(fp, di_ib[level]); + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *disk_block_p = 0; /* missing */ + return (0); + } + + if (fp->f_blkno[level] != ind_block_num) { + if (fp->f_blk[level] == (char *)0) + fp->f_blk[level] = + malloc(fs->fs_bsize); + twiddle(1); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fp->f_fs, ind_block_num), + fs->fs_bsize, + fp->f_blk[level], + &fp->f_blksize[level]); + if (rc) + return (rc); + if (fp->f_blksize[level] != fs->fs_bsize) + return (EIO); + fp->f_blkno[level] = ind_block_num; + } + + if (level > 0) { + idx = file_block / fp->f_nindir[level - 1]; + file_block %= fp->f_nindir[level - 1]; + } else + idx = file_block; + + if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) + ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; + else + ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; + } + + *disk_block_p = ind_block_num; + + return (0); +} + +/* + * Write a portion of a file from an internal buffer. + */ +static int +buf_write_file(f, buf_p, size_p) + struct open_file *f; + char *buf_p; + size_t *size_p; /* out */ +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + long off; + ufs_lbn_t file_block; + ufs2_daddr_t disk_block; + size_t block_size; + int rc; + + /* + * Calculate the starting block address and offset. + */ + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = sblksize(fs, DIP(fp, di_size), file_block); + + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (disk_block == 0) + /* Because we can't allocate space on the drive */ + return (EFBIG); + + /* + * Truncate buffer at end of file, and at the end of + * this block. + */ + if (*size_p > DIP(fp, di_size) - fp->f_seekp) + *size_p = DIP(fp, di_size) - fp->f_seekp; + if (*size_p > block_size - off) + *size_p = block_size - off; + + /* + * If we don't entirely occlude the block and it's not + * in memory already, read it in first. + */ + if (((off > 0) || (*size_p + off < block_size)) && + (file_block != fp->f_buf_blkno)) { + + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + twiddle(4); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + + fp->f_buf_blkno = file_block; + } + + /* + * Copy the user data into the cached block. + */ + bcopy(buf_p, fp->f_buf + off, *size_p); + + /* + * Write the block out to storage. + */ + + twiddle(4); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + return (rc); +} + +/* + * Read a portion of a file into an internal buffer. Return + * the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(f, buf_p, size_p) + struct open_file *f; + char **buf_p; /* out */ + size_t *size_p; /* out */ +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + long off; + ufs_lbn_t file_block; + ufs2_daddr_t disk_block; + size_t block_size; + int rc; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = sblksize(fs, DIP(fp, di_size), file_block); + + if (file_block != fp->f_buf_blkno) { + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (disk_block == 0) { + bzero(fp->f_buf, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(4); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + } + + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > DIP(fp, di_size) - fp->f_seekp) + *size_p = DIP(fp, di_size) - fp->f_seekp; + + return (0); +} + +/* + * Search a directory for a name and return its + * i_number. + */ +static int +search_directory(name, f, inumber_p) + char *name; + struct open_file *f; + ino_t *inumber_p; /* out */ +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp; + struct direct *edp; + char *buf; + size_t buf_size; + int namlen, length; + int rc; + + length = strlen(name); + + fp->f_seekp = 0; + while (fp->f_seekp < DIP(fp, di_size)) { + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + return (rc); + + dp = (struct direct *)buf; + edp = (struct direct *)(buf + buf_size); + while (dp < edp) { + if (dp->d_ino == (ino_t)0) + goto next; +#if BYTE_ORDER == LITTLE_ENDIAN + if (fp->f_fs->fs_maxsymlinklen <= 0) + namlen = dp->d_type; + else +#endif + namlen = dp->d_namlen; + if (namlen == length && + !strcmp(name, dp->d_name)) { + /* found entry */ + *inumber_p = dp->d_ino; + return (0); + } + next: + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + fp->f_seekp += buf_size; + } + return (ENOENT); +} + +static int sblock_try[] = SBLOCKSEARCH; + +/* + * Open a file. + */ +static int +ufs_open(upath, f) + const char *upath; + struct open_file *f; +{ + char *cp, *ncp; + int c; + ino_t inumber, parent_inumber; + struct file *fp; + struct fs *fs; + int i, rc; + size_t buf_size; + int nlinks = 0; + char namebuf[MAXPATHLEN+1]; + char *buf = NULL; + char *path = NULL; + + /* allocate file system specific data structure */ + fp = malloc(sizeof(struct file)); + bzero(fp, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = malloc(SBLOCKSIZE); + fp->f_fs = fs; + twiddle(1); + /* + * Try reading the superblock in each of its possible locations. + */ + for (i = 0; sblock_try[i] != -1; i++) { + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, + (char *)fs, &buf_size); + if (rc) + goto out; + if ((fs->fs_magic == FS_UFS1_MAGIC || + (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_sblockloc == sblock_try[i])) && + buf_size == SBLOCKSIZE && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= sizeof(struct fs)) + break; + } + if (sblock_try[i] == -1) { + rc = EINVAL; + goto out; + } + /* + * Calculate indirect block levels. + */ + { + ufs2_daddr_t mult; + int level; + + mult = 1; + for (level = 0; level < UFS_NIADDR; level++) { + mult *= NINDIR(fs); + fp->f_nindir[level] = mult; + } + } + + inumber = UFS_ROOTINO; + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + cp = path = strdup(upath); + if (path == NULL) { + rc = ENOMEM; + goto out; + } + while (*cp) { + + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if ((DIP(fp, di_mode) & IFMT) != IFDIR) { + rc = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > UFS_MAXNAMLEN) { + rc = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ + parent_inumber = inumber; + rc = search_directory(ncp, f, &inumber); + *cp = c; + if (rc) + goto out; + + /* + * Open next component. + */ + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + /* + * Check for symbolic link. + */ + if ((DIP(fp, di_mode) & IFMT) == IFLNK) { + int link_len = DIP(fp, di_size); + int len; + + len = strlen(cp); + + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + rc = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + + if (link_len < fs->fs_maxsymlinklen) { + if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) + cp = (caddr_t)(fp->f_di.di1.di_db); + else + cp = (caddr_t)(fp->f_di.di2.di_db); + bcopy(cp, namebuf, (unsigned) link_len); + } else { + /* + * Read file for symbolic link + */ + size_t buf_size; + ufs2_daddr_t disk_block; + struct fs *fs = fp->f_fs; + + if (!buf) + buf = malloc(fs->fs_bsize); + rc = block_map(f, (ufs2_daddr_t)0, &disk_block); + if (rc) + goto out; + + twiddle(1); + rc = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsbtodb(fs, disk_block), + fs->fs_bsize, buf, &buf_size); + if (rc) + goto out; + + bcopy((char *)buf, namebuf, (unsigned)link_len); + } + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = (ino_t)UFS_ROOTINO; + + if ((rc = read_inode(inumber, f)) != 0) + goto out; + } + } + + /* + * Found terminal component. + */ + rc = 0; + fp->f_seekp = 0; +out: + if (buf) + free(buf); + if (path) + free(path); + if (rc) { + if (fp->f_buf) + free(fp->f_buf); + free(fp->f_fs); + free(fp); + } + return (rc); +} + +static int +ufs_close(f) + struct open_file *f; +{ + struct file *fp = (struct file *)f->f_fsdata; + int level; + + f->f_fsdata = (void *)0; + if (fp == (struct file *)0) + return (0); + + for (level = 0; level < UFS_NIADDR; level++) { + if (fp->f_blk[level]) + free(fp->f_blk[level]); + } + if (fp->f_buf) + free(fp->f_buf); + free(fp->f_fs); + free(fp); + return (0); +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +static int +ufs_read(f, start, size, resid) + struct open_file *f; + void *start; + size_t size; + size_t *resid; /* out */ +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize; + char *buf; + size_t buf_size; + int rc = 0; + char *addr = start; + + while (size != 0) { + if (fp->f_seekp >= DIP(fp, di_size)) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +/* + * Write to a portion of an already allocated file. + * Cross block boundaries when necessary. Can not + * extend the file. + */ +static int +ufs_write(f, start, size, resid) + struct open_file *f; + void *start; + size_t size; + size_t *resid; /* out */ +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize; + int rc = 0; + char *addr = start; + + csize = size; + while ((size != 0) && (csize != 0)) { + if (fp->f_seekp >= DIP(fp, di_size)) + break; + + if (csize >= 512) csize = 512; /* XXX */ + + rc = buf_write_file(f, addr, &csize); + if (rc) + break; + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +static off_t +ufs_seek(f, offset, where) + struct open_file *f; + off_t offset; + int where; +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = DIP(fp, di_size) - offset; + break; + default: + errno = EINVAL; + return (-1); + } + return (fp->f_seekp); +} + +static int +ufs_stat(f, sb) + struct open_file *f; + struct stat *sb; +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = DIP(fp, di_mode); + sb->st_uid = DIP(fp, di_uid); + sb->st_gid = DIP(fp, di_gid); + sb->st_size = DIP(fp, di_size); + return (0); +} + +static int +ufs_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp; + char *buf; + size_t buf_size; + int error; + + /* + * assume that a directory entry will not be split across blocks + */ +again: + if (fp->f_seekp >= DIP(fp, di_size)) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + dp = (struct direct *)buf; + fp->f_seekp += dp->d_reclen; + if (dp->d_ino == (ino_t)0) + goto again; + d->d_type = dp->d_type; + strcpy(d->d_name, dp->d_name); + return (0); +} diff --git a/stand/libsa/ufsread.c b/stand/libsa/ufsread.c new file mode 100644 index 000000000000..bd9ad2c57103 --- /dev/null +++ b/stand/libsa/ufsread.c @@ -0,0 +1,326 @@ +/*- + * Copyright (c) 2002 McAfee, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and McAfee Research,, the Security Research Division of + * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as + * part of the DARPA CHATS research program + * + * 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 AUTHOR 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 AUTHOR 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. + */ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <ufs/ufs/dinode.h> +#include <ufs/ufs/dir.h> +#include <ufs/ffs/fs.h> + +#ifdef UFS_SMALL_CGBASE +/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase + (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can + support both UFS1 and UFS2. */ +#undef cgbase +#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) +#endif + +typedef uint32_t ufs_ino_t; + +/* + * We use 4k `virtual' blocks for filesystem data, whatever the actual + * filesystem block size. FFS blocks are always a multiple of 4k. + */ +#define VBLKSHIFT 12 +#define VBLKSIZE (1 << VBLKSHIFT) +#define VBLKMASK (VBLKSIZE - 1) +#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) +#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) +#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) +#define INO_TO_VBA(fs, ipervblk, x) \ + (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ + (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) +#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) +#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ + ((off) / VBLKSIZE) * DBPERVBLK) +#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) + +/* Buffers that must not span a 64k boundary. */ +struct dmadat { + char blkbuf[VBLKSIZE]; /* filesystem blocks */ + char indbuf[VBLKSIZE]; /* indir blocks */ + char sbbuf[SBLOCKSIZE]; /* superblock */ + char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ +}; +static struct dmadat *dmadat; + +static ufs_ino_t lookup(const char *); +static ssize_t fsread(ufs_ino_t, void *, size_t); + +static uint8_t ls, dsk_meta; +static uint32_t fs_off; + +static __inline uint8_t +fsfind(const char *name, ufs_ino_t * ino) +{ + static char buf[DEV_BSIZE]; + static struct direct d; + char *s; + ssize_t n; + + fs_off = 0; + while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) + for (s = buf; s < buf + DEV_BSIZE;) { + memcpy(&d, s, sizeof(struct direct)); + if (ls) + printf("%s ", d.d_name); + else if (!strcmp(name, d.d_name)) { + *ino = d.d_ino; + return d.d_type; + } + s += d.d_reclen; + } + if (n != -1 && ls) + printf("\n"); + return 0; +} + +static ufs_ino_t +lookup(const char *path) +{ + static char name[UFS_MAXNAMLEN + 1]; + const char *s; + ufs_ino_t ino; + ssize_t n; + uint8_t dt; + + ino = UFS_ROOTINO; + dt = DT_DIR; + for (;;) { + if (*path == '/') + path++; + if (!*path) + break; + for (s = path; *s && *s != '/'; s++); + if ((n = s - path) > UFS_MAXNAMLEN) + return 0; + ls = *path == '?' && n == 1 && !*s; + memcpy(name, path, n); + name[n] = 0; + if (dt != DT_DIR) { + printf("%s: not a directory.\n", name); + return (0); + } + if ((dt = fsfind(name, &ino)) <= 0) + break; + path = s; + } + return dt == DT_REG ? ino : 0; +} + +/* + * Possible superblock locations ordered from most to least likely. + */ +static int sblock_try[] = SBLOCKSEARCH; + +#if defined(UFS2_ONLY) +#define DIP(field) dp2.field +#elif defined(UFS1_ONLY) +#define DIP(field) dp1.field +#else +#define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field +#endif + +static ssize_t +fsread_size(ufs_ino_t inode, void *buf, size_t nbyte, size_t *fsizep) +{ +#ifndef UFS2_ONLY + static struct ufs1_dinode dp1; + ufs1_daddr_t addr1; +#endif +#ifndef UFS1_ONLY + static struct ufs2_dinode dp2; +#endif + static struct fs fs; + static ufs_ino_t inomap; + char *blkbuf; + void *indbuf; + char *s; + size_t n, nb, size, off, vboff; + ufs_lbn_t lbn; + ufs2_daddr_t addr2, vbaddr; + static ufs2_daddr_t blkmap, indmap; + u_int u; + + /* Basic parameter validation. */ + if ((buf == NULL && nbyte != 0) || dmadat == NULL) + return (-1); + + blkbuf = dmadat->blkbuf; + indbuf = dmadat->indbuf; + + /* + * Force probe if inode is zero to ensure we have a valid fs, otherwise + * when probing multiple paritions, reads from subsequent parititions + * will incorrectly succeed. + */ + if (!dsk_meta || inode == 0) { + inomap = 0; + dsk_meta = 0; + for (n = 0; sblock_try[n] != -1; n++) { + if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, + SBLOCKSIZE / DEV_BSIZE)) + return -1; + memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); + if (( +#if defined(UFS1_ONLY) + fs.fs_magic == FS_UFS1_MAGIC +#elif defined(UFS2_ONLY) + (fs.fs_magic == FS_UFS2_MAGIC && + fs.fs_sblockloc == sblock_try[n]) +#else + fs.fs_magic == FS_UFS1_MAGIC || + (fs.fs_magic == FS_UFS2_MAGIC && + fs.fs_sblockloc == sblock_try[n]) +#endif + ) && + fs.fs_bsize <= MAXBSIZE && + fs.fs_bsize >= (int32_t)sizeof(struct fs)) + break; + } + if (sblock_try[n] == -1) { + return -1; + } + dsk_meta++; + } else + memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); + if (!inode) + return 0; + if (inomap != inode) { + n = IPERVBLK(&fs); + if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) + return -1; + n = INO_TO_VBO(n, inode); +#if defined(UFS1_ONLY) + memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, + sizeof(dp1)); +#elif defined(UFS2_ONLY) + memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, + sizeof(dp2)); +#else + if (fs.fs_magic == FS_UFS1_MAGIC) + memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, + sizeof(dp1)); + else + memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, + sizeof(dp2)); +#endif + inomap = inode; + fs_off = 0; + blkmap = indmap = 0; + } + s = buf; + size = DIP(di_size); + n = size - fs_off; + if (nbyte > n) + nbyte = n; + nb = nbyte; + while (nb) { + lbn = lblkno(&fs, fs_off); + off = blkoff(&fs, fs_off); + if (lbn < UFS_NDADDR) { + addr2 = DIP(di_db[lbn]); + } else if (lbn < UFS_NDADDR + NINDIR(&fs)) { + n = INDIRPERVBLK(&fs); + addr2 = DIP(di_ib[0]); + u = (u_int)(lbn - UFS_NDADDR) / n * DBPERVBLK; + vbaddr = fsbtodb(&fs, addr2) + u; + if (indmap != vbaddr) { + if (dskread(indbuf, vbaddr, DBPERVBLK)) + return -1; + indmap = vbaddr; + } + n = (lbn - UFS_NDADDR) & (n - 1); +#if defined(UFS1_ONLY) + memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, + sizeof(ufs1_daddr_t)); + addr2 = addr1; +#elif defined(UFS2_ONLY) + memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, + sizeof(ufs2_daddr_t)); +#else + if (fs.fs_magic == FS_UFS1_MAGIC) { + memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, + sizeof(ufs1_daddr_t)); + addr2 = addr1; + } else + memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, + sizeof(ufs2_daddr_t)); +#endif + } else + return -1; + vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; + vboff = off & VBLKMASK; + n = sblksize(&fs, (off_t)size, lbn) - (off & ~VBLKMASK); + if (n > VBLKSIZE) + n = VBLKSIZE; + if (blkmap != vbaddr) { + if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) + return -1; + blkmap = vbaddr; + } + n -= vboff; + if (n > nb) + n = nb; + memcpy(s, blkbuf + vboff, n); + s += n; + fs_off += n; + nb -= n; + } + + if (fsizep != NULL) + *fsizep = size; + + return nbyte; +} + +static ssize_t +fsread(ufs_ino_t inode, void *buf, size_t nbyte) +{ + + return fsread_size(inode, buf, nbyte, NULL); +} + diff --git a/stand/libsa/util.c b/stand/libsa/util.c new file mode 100644 index 000000000000..49f42ebe2da9 --- /dev/null +++ b/stand/libsa/util.c @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <stdarg.h> + +#include "cons.h" +#include "util.h" + +void +memcpy(void *dst, const void *src, int len) +{ + const char *s = src; + char *d = dst; + + while (len--) + *d++ = *s++; +} + +void +memset(void *b, int c, size_t len) +{ + char *bp = b; + + while (len--) + *bp++ = (unsigned char)c; +} + +int +memcmp(const void *b1, const void *b2, size_t len) +{ + const unsigned char *p1, *p2; + + for (p1 = b1, p2 = b2; len > 0; len--, p1++, p2++) { + if (*p1 != *p2) + return ((*p1) - (*p2)); + } + return (0); +} + +int +strcmp(const char *s1, const char *s2) +{ + + for (; *s1 == *s2 && *s1 != '\0'; s1++, s2++) + ; + return ((unsigned char)*s1 - (unsigned char)*s2); +} + +int +strncmp(const char *s1, const char *s2, size_t len) +{ + + for (; len > 0 && *s1 == *s2 && *s1 != '\0'; len--, s1++, s2++) + ; + return (len == 0 ? 0 : (unsigned char)*s1 - (unsigned char)*s2); +} + +void +strcpy(char *dst, const char *src) +{ + + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; +} + +void +strcat(char *dst, const char *src) +{ + + while (*dst != '\0') + dst++; + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; +} + +char * +strchr(const char *s, char ch) +{ + + for (; *s != '\0'; s++) { + if (*s == ch) + return ((char *)(uintptr_t)(const void *)s); + } + return (NULL); +} + +size_t +strlen(const char *s) +{ + size_t len = 0; + + while (*s++ != '\0') + len++; + return (len); +} + +int +printf(const char *fmt, ...) +{ + va_list ap; + const char *hex = "0123456789abcdef"; + char buf[32], *s; + uint16_t *S; + unsigned long long u; + int c, l; + + va_start(ap, fmt); + while ((c = *fmt++) != '\0') { + if (c != '%') { + putchar(c); + continue; + } + l = 0; +nextfmt: + c = *fmt++; + switch (c) { + case 'l': + l++; + goto nextfmt; + case 'c': + putchar(va_arg(ap, int)); + break; + case 's': + for (s = va_arg(ap, char *); *s != '\0'; s++) + putchar(*s); + break; + case 'S': /* Assume console can cope with wide chars */ + for (S = va_arg(ap, uint16_t *); *S != 0; S++) + putchar(*S); + break; + case 'd': /* A lie, always prints unsigned */ + case 'u': + case 'x': + switch (l) { + case 2: + u = va_arg(ap, unsigned long long); + break; + case 1: + u = va_arg(ap, unsigned long); + break; + default: + u = va_arg(ap, unsigned int); + break; + } + s = buf; + if (c == 'd' || c == 'u') { + do + *s++ = '0' + (u % 10U); + while (u /= 10); + } else { + do + *s++ = hex[u & 0xfu]; + while (u >>= 4); + } + while (--s >= buf) + putchar(*s); + break; + } + } + va_end(ap); + return (0); +} diff --git a/stand/libsa/util.h b/stand/libsa/util.h new file mode 100644 index 000000000000..88a99f19f0b3 --- /dev/null +++ b/stand/libsa/util.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * 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$ + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include <sys/types.h> + +#include <stdarg.h> + +void memcpy(void *dst, const void *src, int len); +void memset(void *b, int c, size_t len); +int memcmp(const void *b1, const void *b2, size_t len); + +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bzero(buf, size) memset((buf), 0, (size)) +#define bcmp(b1, b2, len) (memcmp((b1), (b2), (len)) != 0) + +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t len); +void strcpy(char *dst, const char *src); +void strcat(char *dst, const char *src); +char *strchr(const char *s, char ch); +size_t strlen(const char *s); + +int printf(const char *fmt, ...); + +#endif /* !_UTIL_H_ */ diff --git a/stand/libsa/uuid_from_string.c b/stand/libsa/uuid_from_string.c new file mode 100644 index 000000000000..7a59b4189ead --- /dev/null +++ b/stand/libsa/uuid_from_string.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2015 M. Warner Losh + * 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 AUTHOR 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 AUTHOR 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$ + */ + +/* + * Note: some comments taken from lib/libc/uuid/uuid_from_string.c + * Copyright (c) 2002 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + */ + + +#include <stand.h> +#include <uuid.h> + +static int +hex2int(int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'a' && ch <= 'f') + return 10 + ch - 'a'; + if (ch >= 'A' && ch <= 'F') + return 10 + ch - 'A'; + return 16; +} + +static uint32_t +fromhex(const char *s, int len, int *ok) +{ + uint32_t v; + int i, h; + + if (!*ok) + return 0; + v = 0; + for (i = 0; i < len; i++) { + h = hex2int(s[i]); + if (h == 16) { + *ok = 0; + return v; + } + v = (v << 4) | h; + } + return v; +} + +/* + * uuid_from_string() - convert a string representation of an UUID into + * a binary representation. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm + * + * NOTE: The sequence field is in big-endian, while the time fields are in + * native byte order. + * + * 01234567-89ab-cdef-0123-456789abcdef + * 000000000011111111112222222222333333 + * 012345678901234567890123456789012345 + * - - - - + * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb + * + */ +void +uuid_from_string(const char *s, uuid_t *u, uint32_t *status) +{ + int ok = 1; + int n; + + if (s == NULL || *s == '\0') { + uuid_create_nil(u, status); + return; + } + + if (status != NULL) + *status = uuid_s_invalid_string_uuid; + if (strlen(s) != 36) + return; + /* Only support new format, check for all the right dashes */ + if (s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') + return; + /* native byte order */ + u->time_low = fromhex(s , 8, &ok); + u->time_mid = fromhex(s + 9, 4, &ok); + u->time_hi_and_version = fromhex(s + 14, 4, &ok); + /* Big endian, but presented as a whole number so decode as such */ + u->clock_seq_hi_and_reserved = fromhex(s + 19, 2, &ok); + u->clock_seq_low = fromhex(s + 21, 2, &ok); + u->node[0] = fromhex(s + 24, 2, &ok); + u->node[1] = fromhex(s + 26, 2, &ok); + u->node[2] = fromhex(s + 28, 2, &ok); + u->node[3] = fromhex(s + 30, 2, &ok); + u->node[4] = fromhex(s + 32, 2, &ok); + u->node[5] = fromhex(s + 34, 2, &ok); + if (!ok) + return; + + /* We have a successful scan. Check semantics... */ + n = u->clock_seq_hi_and_reserved; + if ((n & 0x80) != 0x00 && /* variant 0? */ + (n & 0xc0) != 0x80 && /* variant 1? */ + (n & 0xe0) != 0xc0) { /* variant 2? */ + if (status != NULL) + *status = uuid_s_bad_version; + } else { + if (status != NULL) + *status = uuid_s_ok; + } +} diff --git a/stand/libsa/uuid_to_string.c b/stand/libsa/uuid_to_string.c new file mode 100644 index 000000000000..d878af495aca --- /dev/null +++ b/stand/libsa/uuid_to_string.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2015 M. Warner Losh + * 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 AUTHOR 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 AUTHOR 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$ + */ + + +/* + * Note: some comments taken from lib/libc/uuid/uuid_to_string.c + * Copyright (c) 2002,2005 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + */ + +#include <stand.h> +#include <uuid.h> + +/* + * Dump len characters into *buf from val as hex and update *buf + */ +static void +tohex(char **buf, int len, uint32_t val) +{ + static const char *hexstr = "0123456789abcdef"; + char *walker = *buf; + int i; + + for (i = len - 1; i >= 0; i--) { + walker[i] = hexstr[val & 0xf]; + val >>= 4; + } + *buf = walker + len; +} + +/* + * uuid_to_string() - Convert a binary UUID into a string representation. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_to_string.htm + * + * NOTE: The references given above do not have a status code for when + * the string could not be allocated. The status code has been + * taken from the Hewlett-Packard implementation. + * + * NOTE: we don't support u == NULL for a nil UUID, sorry. + * + * NOTE: The sequence field is in big-endian, while the time fields are in + * native byte order. + * + * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb + * 01234567-89ab-cdef-0123-456789abcdef + */ +void +uuid_to_string(const uuid_t *u, char **s, uint32_t *status) +{ + uuid_t nil; + char *w; + + if (status != NULL) + *status = uuid_s_ok; + if (s == NULL) /* Regular version does this odd-ball behavior too */ + return; + w = *s = malloc(37); + if (*s == NULL) { + if (status != NULL) + *status = uuid_s_no_memory; + return; + } + if (u == NULL) { + u = &nil; + uuid_create_nil(&nil, NULL); + } + /* native */ + tohex(&w, 8, u->time_low); + *w++ = '-'; + tohex(&w, 4, u->time_mid); + *w++ = '-'; + tohex(&w, 4, u->time_hi_and_version); + *w++ = '-'; + /* Big endian, so do a byte at a time */ + tohex(&w, 2, u->clock_seq_hi_and_reserved); + tohex(&w, 2, u->clock_seq_low); + *w++ = '-'; + tohex(&w, 2, u->node[0]); + tohex(&w, 2, u->node[1]); + tohex(&w, 2, u->node[2]); + tohex(&w, 2, u->node[3]); + tohex(&w, 2, u->node[4]); + tohex(&w, 2, u->node[5]); + *w++ = '\0'; +} diff --git a/stand/libsa/write.c b/stand/libsa/write.c new file mode 100644 index 000000000000..6c65dd331245 --- /dev/null +++ b/stand/libsa/write.c @@ -0,0 +1,95 @@ +/* $NetBSD: write.c,v 1.7 1996/06/21 20:29:30 pk Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)write.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include "stand.h" + +ssize_t +write(fd, dest, bcount) + int fd; + void *dest; + size_t bcount; +{ + struct open_file *f = &files[fd]; + size_t resid; + + if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_WRITE)) { + errno = EBADF; + return (-1); + } + if (f->f_flags & F_RAW) { + twiddle(4); + errno = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, + btodb(f->f_offset), bcount, dest, &resid); + if (errno) + return (-1); + f->f_offset += resid; + return (resid); + } + resid = bcount; + if ((errno = (f->f_ops->fo_write)(f, dest, bcount, &resid))) + return (-1); + return (bcount - resid); +} diff --git a/stand/libsa/zalloc.c b/stand/libsa/zalloc.c new file mode 100644 index 000000000000..4d1ec6291210 --- /dev/null +++ b/stand/libsa/zalloc.c @@ -0,0 +1,316 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon <dillon@backplane.com> + * + * Copyright (c) 1998 The FreeBSD Project + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * LIB/MEMORY/ZALLOC.C - self contained low-overhead memory pool/allocation + * subsystem + * + * This subsystem implements memory pools and memory allocation + * routines. + * + * Pools are managed via a linked list of 'free' areas. Allocating + * memory creates holes in the freelist, freeing memory fills them. + * Since the freelist consists only of free memory areas, it is possible + * to allocate the entire pool without incuring any structural overhead. + * + * The system works best when allocating similarly-sized chunks of + * memory. Care must be taken to avoid fragmentation when + * allocating/deallocating dissimilar chunks. + * + * When a memory pool is first allocated, the entire pool is marked as + * allocated. This is done mainly because we do not want to modify any + * portion of a pool's data area until we are given permission. The + * caller must explicitly deallocate portions of the pool to make them + * available. + * + * z[n]xalloc() works like z[n]alloc() but the allocation is made from + * within the specified address range. If the segment could not be + * allocated, NULL is returned. WARNING! The address range will be + * aligned to an 8 or 16 byte boundry depending on the cpu so if you + * give an unaligned address range, unexpected results may occur. + * + * If a standard allocation fails, the reclaim function will be called + * to recover some space. This usually causes other portions of the + * same pool to be released. Memory allocations at this low level + * should not block but you can do that too in your reclaim function + * if you want. Reclaim does not function when z[n]xalloc() is used, + * only for z[n]alloc(). + * + * Allocation and frees of 0 bytes are valid operations. + */ + +#include "zalloc_defs.h" + +/* + * Objects in the pool must be aligned to at least the size of struct MemNode. + * They must also be aligned to MALLOCALIGN, which should normally be larger + * than the struct, so assert that to be so at compile time. + */ +typedef char assert_align[(sizeof(struct MemNode) <= MALLOCALIGN) ? 1 : -1]; + +#define MEMNODE_SIZE_MASK MALLOCALIGN_MASK + +/* + * znalloc() - allocate memory (without zeroing) from pool. Call reclaim + * and retry if appropriate, return NULL if unable to allocate + * memory. + */ + +void * +znalloc(MemPool *mp, uintptr_t bytes) +{ + /* + * align according to pool object size (can be 0). This is + * inclusive of the MEMNODE_SIZE_MASK minimum alignment. + * + */ + bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK; + + if (bytes == 0) + return((void *)-1); + + /* + * locate freelist entry big enough to hold the object. If all objects + * are the same size, this is a constant-time function. + */ + + if (bytes <= mp->mp_Size - mp->mp_Used) { + MemNode **pmn; + MemNode *mn; + + for (pmn = &mp->mp_First; (mn=*pmn) != NULL; pmn = &mn->mr_Next) { + if (bytes > mn->mr_Bytes) + continue; + + /* + * Cut a chunk of memory out of the beginning of this + * block and fixup the link appropriately. + */ + + { + char *ptr = (char *)mn; + + if (mn->mr_Bytes == bytes) { + *pmn = mn->mr_Next; + } else { + mn = (MemNode *)((char *)mn + bytes); + mn->mr_Next = ((MemNode *)ptr)->mr_Next; + mn->mr_Bytes = ((MemNode *)ptr)->mr_Bytes - bytes; + *pmn = mn; + } + mp->mp_Used += bytes; + return(ptr); + } + } + } + + /* + * Memory pool is full, return NULL. + */ + + return(NULL); +} + +/* + * zfree() - free previously allocated memory + */ + +void +zfree(MemPool *mp, void *ptr, uintptr_t bytes) +{ + /* + * align according to pool object size (can be 0). This is + * inclusive of the MEMNODE_SIZE_MASK minimum alignment. + */ + bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK; + + if (bytes == 0) + return; + + /* + * panic if illegal pointer + */ + + if ((char *)ptr < (char *)mp->mp_Base || + (char *)ptr + bytes > (char *)mp->mp_End || + ((uintptr_t)ptr & MEMNODE_SIZE_MASK) != 0) + panic("zfree(%p,%ju): wild pointer", ptr, (uintmax_t)bytes); + + /* + * free the segment + */ + + { + MemNode **pmn; + MemNode *mn; + + mp->mp_Used -= bytes; + + for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) { + /* + * If area between last node and current node + * - check range + * - check merge with next area + * - check merge with previous area + */ + if ((char *)ptr <= (char *)mn) { + /* + * range check + */ + if ((char *)ptr + bytes > (char *)mn) { + panic("zfree(%p,%ju): corrupt memlist1", ptr, + (uintmax_t)bytes); + } + + /* + * merge against next area or create independant area + */ + + if ((char *)ptr + bytes == (char *)mn) { + ((MemNode *)ptr)->mr_Next = mn->mr_Next; + ((MemNode *)ptr)->mr_Bytes= bytes + mn->mr_Bytes; + } else { + ((MemNode *)ptr)->mr_Next = mn; + ((MemNode *)ptr)->mr_Bytes= bytes; + } + *pmn = mn = (MemNode *)ptr; + + /* + * merge against previous area (if there is a previous + * area). + */ + + if (pmn != &mp->mp_First) { + if ((char*)pmn + ((MemNode*)pmn)->mr_Bytes == (char*)ptr) { + ((MemNode *)pmn)->mr_Next = mn->mr_Next; + ((MemNode *)pmn)->mr_Bytes += mn->mr_Bytes; + mn = (MemNode *)pmn; + } + } + return; + /* NOT REACHED */ + } + if ((char *)ptr < (char *)mn + mn->mr_Bytes) { + panic("zfree(%p,%ju): corrupt memlist2", ptr, + (uintmax_t)bytes); + } + } + /* + * We are beyond the last MemNode, append new MemNode. Merge against + * previous area if possible. + */ + if (pmn == &mp->mp_First || + (char *)pmn + ((MemNode *)pmn)->mr_Bytes != (char *)ptr + ) { + ((MemNode *)ptr)->mr_Next = NULL; + ((MemNode *)ptr)->mr_Bytes = bytes; + *pmn = (MemNode *)ptr; + mn = (MemNode *)ptr; + } else { + ((MemNode *)pmn)->mr_Bytes += bytes; + mn = (MemNode *)pmn; + } + } +} + +/* + * zextendPool() - extend memory pool to cover additional space. + * + * Note: the added memory starts out as allocated, you + * must free it to make it available to the memory subsystem. + * + * Note: mp_Size may not reflect (mp_End - mp_Base) range + * due to other parts of the system doing their own sbrk() + * calls. + */ + +void +zextendPool(MemPool *mp, void *base, uintptr_t bytes) +{ + if (mp->mp_Size == 0) { + mp->mp_Base = base; + mp->mp_Used = bytes; + mp->mp_End = (char *)base + bytes; + mp->mp_Size = bytes; + } else { + void *pend = (char *)mp->mp_Base + mp->mp_Size; + + if (base < mp->mp_Base) { + mp->mp_Size += (char *)mp->mp_Base - (char *)base; + mp->mp_Used += (char *)mp->mp_Base - (char *)base; + mp->mp_Base = base; + } + base = (char *)base + bytes; + if (base > pend) { + mp->mp_Size += (char *)base - (char *)pend; + mp->mp_Used += (char *)base - (char *)pend; + mp->mp_End = (char *)base; + } + } +} + +#ifdef ZALLOCDEBUG + +void +zallocstats(MemPool *mp) +{ + int abytes = 0; + int hbytes = 0; + int fcount = 0; + MemNode *mn; + + printf("%d bytes reserved", (int) mp->mp_Size); + + mn = mp->mp_First; + + if ((void *)mn != (void *)mp->mp_Base) { + abytes += (char *)mn - (char *)mp->mp_Base; + } + + while (mn) { + if ((char *)mn + mn->mr_Bytes != mp->mp_End) { + hbytes += mn->mr_Bytes; + ++fcount; + } + if (mn->mr_Next) + abytes += (char *)mn->mr_Next - ((char *)mn + mn->mr_Bytes); + mn = mn->mr_Next; + } + printf(" %d bytes allocated\n%d fragments (%d bytes fragmented)\n", + abytes, + fcount, + hbytes + ); +} + +#endif + diff --git a/stand/libsa/zalloc_defs.h b/stand/libsa/zalloc_defs.h new file mode 100644 index 000000000000..7f2cc1202c9b --- /dev/null +++ b/stand/libsa/zalloc_defs.h @@ -0,0 +1,78 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon <dillon@backplane.com> + * + * Copyright (c) 1998 The FreeBSD Project + * 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 AUTHOR 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 AUTHOR 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$ + */ + +/* + * DEFS.H + */ + +#define USEGUARD /* use stard/end guard bytes */ +#define USEENDGUARD +#define DMALLOCDEBUG /* add debugging code to gather stats */ +#define ZALLOCDEBUG + +#include <sys/stdint.h> +#include "stand.h" +#include "zalloc_mem.h" + +#define Library extern + +/* + * block extension for sbrk() + */ + +#define BLKEXTEND (4 * 1024) +#define BLKEXTENDMASK (BLKEXTEND - 1) + +/* + * Required malloc alignment. + * + * Embedded platforms using the u-boot API drivers require that all I/O buffers + * be on a cache line sized boundary. The worst case size for that is 64 bytes. + * For other platforms, 16 bytes works fine. The alignment also must be at + * least sizeof(struct MemNode); this is asserted in zalloc.c. + */ + +#if defined(__arm__) || defined(__mips__) || defined(__powerpc__) +#define MALLOCALIGN 64 +#else +#define MALLOCALIGN 16 +#endif +#define MALLOCALIGN_MASK (MALLOCALIGN - 1) + +typedef struct Guard { + size_t ga_Bytes; + size_t ga_Magic; /* must be at least 32 bits */ +} Guard; + +#define GAMAGIC 0x55FF44FD +#define GAFREE 0x5F54F4DF + +#include "zalloc_protos.h" diff --git a/stand/libsa/zalloc_malloc.c b/stand/libsa/zalloc_malloc.c new file mode 100644 index 000000000000..b9a295fb3850 --- /dev/null +++ b/stand/libsa/zalloc_malloc.c @@ -0,0 +1,200 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon <dillon@backplane.com> + * + * Copyright (c) 1998 The FreeBSD Project + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * MALLOC.C - malloc equivalent, runs on top of zalloc and uses sbrk + */ + +#include "zalloc_defs.h" + +static MemPool MallocPool; + +#ifdef DMALLOCDEBUG +static int MallocMax; +static int MallocCount; + +void mallocstats(void); +#endif + +#ifdef malloc +#undef malloc +#undef free +#endif + +void * +Malloc(size_t bytes, const char *file, int line) +{ + Guard *res; + +#ifdef USEENDGUARD + bytes += MALLOCALIGN + 1; +#else + bytes += MALLOCALIGN; +#endif + + while ((res = znalloc(&MallocPool, bytes)) == NULL) { + int incr = (bytes + BLKEXTENDMASK) & ~BLKEXTENDMASK; + char *base; + + if ((base = sbrk(incr)) == (char *)-1) + return(NULL); + zextendPool(&MallocPool, base, incr); + zfree(&MallocPool, base, incr); + } +#ifdef DMALLOCDEBUG + if (++MallocCount > MallocMax) + MallocMax = MallocCount; +#endif +#ifdef USEGUARD + res->ga_Magic = GAMAGIC; +#endif + res->ga_Bytes = bytes; +#ifdef USEENDGUARD + *((signed char *)res + bytes - 1) = -2; +#endif + + return((char *)res + MALLOCALIGN); +} + +void +Free(void *ptr, const char *file, int line) +{ + size_t bytes; + + if (ptr != NULL) { + Guard *res = (void *)((char *)ptr - MALLOCALIGN); + + if (file == NULL) + file = "unknown"; +#ifdef USEGUARD + if (res->ga_Magic == GAFREE) { + printf("free: duplicate free @ %p from %s:%d\n", ptr, file, line); + return; + } + if (res->ga_Magic != GAMAGIC) + panic("free: guard1 fail @ %p from %s:%d", ptr, file, line); + res->ga_Magic = GAFREE; +#endif +#ifdef USEENDGUARD + if (*((signed char *)res + res->ga_Bytes - 1) == -1) { + printf("free: duplicate2 free @ %p from %s:%d\n", ptr, file, line); + return; + } + if (*((signed char *)res + res->ga_Bytes - 1) != -2) + panic("free: guard2 fail @ %p + %zu from %s:%d", ptr, res->ga_Bytes - MALLOCALIGN, file, line); + *((signed char *)res + res->ga_Bytes - 1) = -1; +#endif + + bytes = res->ga_Bytes; + zfree(&MallocPool, res, bytes); +#ifdef DMALLOCDEBUG + --MallocCount; +#endif + } +} + + +void * +Calloc(size_t n1, size_t n2, const char *file, int line) +{ + uintptr_t bytes = (uintptr_t)n1 * (uintptr_t)n2; + void *res; + + if ((res = Malloc(bytes, file, line)) != NULL) { + bzero(res, bytes); +#ifdef DMALLOCDEBUG + if (++MallocCount > MallocMax) + MallocMax = MallocCount; +#endif + } + return(res); +} + +/* + * realloc() - I could be fancier here and free the old buffer before + * allocating the new one (saving potential fragmentation + * and potential buffer copies). But I don't bother. + */ + +void * +Realloc(void *ptr, size_t size, const char *file, int line) +{ + void *res; + size_t old; + + if ((res = Malloc(size, file, line)) != NULL) { + if (ptr) { + old = *(size_t *)((char *)ptr - MALLOCALIGN) - MALLOCALIGN; + if (old < size) + bcopy(ptr, res, old); + else + bcopy(ptr, res, size); + Free(ptr, file, line); + } else { +#ifdef DMALLOCDEBUG + if (++MallocCount > MallocMax) + MallocMax = MallocCount; +#ifdef EXITSTATS + if (DidAtExit == 0) { + DidAtExit = 1; + atexit(mallocstats); + } +#endif +#endif + } + } + return(res); +} + +void * +Reallocf(void *ptr, size_t size, const char *file, int line) +{ + void *res; + + if ((res = Realloc(ptr, size, file, line)) == NULL) + Free(ptr, file, line); + return(res); +} + +#ifdef DMALLOCDEBUG + +void +mallocstats(void) +{ + printf("Active Allocations: %d/%d\n", MallocCount, MallocMax); +#ifdef ZALLOCDEBUG + zallocstats(&MallocPool); +#endif +} + +#endif + diff --git a/stand/libsa/zalloc_mem.h b/stand/libsa/zalloc_mem.h new file mode 100644 index 000000000000..26d388dfc75e --- /dev/null +++ b/stand/libsa/zalloc_mem.h @@ -0,0 +1,53 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon <dillon@backplane.com> + * + * Copyright (c) 1998 The FreeBSD Project + * 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 AUTHOR 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 AUTHOR 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$ + */ + +/* + * H/MEM.H + * + * Basic memory pool / memory node structures. + */ + +typedef struct MemNode { + struct MemNode *mr_Next; + uintptr_t mr_Bytes; +} MemNode; + +typedef struct MemPool { + void *mp_Base; + void *mp_End; + MemNode *mp_First; + uintptr_t mp_Size; + uintptr_t mp_Used; +} MemPool; + +#define ZNOTE_FREE 0 +#define ZNOTE_REUSE 1 + diff --git a/stand/libsa/zalloc_protos.h b/stand/libsa/zalloc_protos.h new file mode 100644 index 000000000000..53a40e400dcd --- /dev/null +++ b/stand/libsa/zalloc_protos.h @@ -0,0 +1,35 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon <dillon@backplane.com> + * + * Copyright (c) 1998 The FreeBSD Project + * 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 AUTHOR 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 AUTHOR 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$ + */ + +Library void *znalloc(struct MemPool *mpool, uintptr_t bytes); +Library void zfree(struct MemPool *mpool, void *ptr, uintptr_t bytes); +Library void zextendPool(MemPool *mp, void *base, uintptr_t bytes); +Library void zallocstats(struct MemPool *mp); |