diff options
60 files changed, 11408 insertions, 0 deletions
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile new file mode 100644 index 000000000000..04c980458c39 --- /dev/null +++ b/lib/libstand/Makefile @@ -0,0 +1,116 @@ +# $Id$ +# +# 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. +# + +LIB=		stand +NOPROFILE=	YES +NOPIC=		YES + +# Mostly OK, some of the libc imports are a bit noisy +CFLAGS+=	-Wall + +# i386 apps are loaded by an a.out only loader +.if ${MACHINE_ARCH} == "i386" +OBJFORMAT=	aout +.endif + +.if ${MACHINE_ARCH} == "alpha" +CFLAGS+=	-mno-fp-regs +.endif + +# standalone components and stuff we have modified locally +SRCS+=	__main.c alloc.c bcd.c bswap.c environment.c getopt.c gets.c \ +	globals.c pager.c printf.c strdup.c strerror.c strtol.c random.c \ +	twiddle.c + +# string functions from libc +.PATH:	${.CURDIR}/../libc/string +.if ${MACHINE_ARCH} == "i386" +SRCS+=	bcmp.c bcopy.c bzero.c ffs.c index.c memccpy.c memchr.c memcmp.c \ +        memcpy.c memmove.c memset.c rindex.c strcasecmp.c strcat.c strchr.c \ +        strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c \ +	strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c +.endif +.if ${MACHINE_ARCH} == "alpha" +.PATH: ${.CURDIR}/../libc/alpha/string +SRCS+=	bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \ +	memcpy.S memmove.S memset.c rindex.c strcasecmp.c strcat.c strchr.c \ +	strcmp.c strcpy.c strcspn.c strlen.c \ +	strncat.c strncmp.c strncpy.c strpbrk.c strrchr.c strsep.c \ +	strspn.c strstr.c strtok.c swab.c + +.PATH: ${.CURDIR}/../libc/alpha/net +SRCS+= htons.S ntohs.S htonl.S ntohl.S + +SRCS+= __divqu.S __divq.S __divlu.S __divl.S +SRCS+= __remqu.S __remq.S __remlu.S __reml.S + +CLEANFILES+=   __divqu.S __divq.S __divlu.S __divl.S +CLEANFILES+=   __remqu.S __remq.S __remlu.S __reml.S + + +__divqu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__divqu -DOP=div -DS=false -DWORDSIZE=64 \ +		${.ALLSRC} > ${.TARGET} + +__divq.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__divq -DOP=div -DS=true -DWORDSIZE=64 \ +		${.ALLSRC} > ${.TARGET} + +__divlu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__divlu -DOP=div -DS=false -DWORDSIZE=32 \ +		${.ALLSRC} > ${.TARGET} + +__divl.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__divl -DOP=div -DS=true -DWORDSIZE=32 \ +		${.ALLSRC} > ${.TARGET} + +__remqu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__remqu -DOP=rem -DS=false -DWORDSIZE=64 \ +		${.ALLSRC} > ${.TARGET} + +__remq.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__remq -DOP=rem -DS=true -DWORDSIZE=64 \ +		${.ALLSRC} > ${.TARGET} + +__remlu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__remlu -DOP=rem -DS=false -DWORDSIZE=32 \ +		${.ALLSRC} > ${.TARGET} + +__reml.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4 +	m4 -DNAME=__reml -DOP=rem -DS=true -DWORDSIZE=32 \ +		${.ALLSRC} > ${.TARGET} +.endif + +# network support from libc +.PATH:	${.CURDIR}/../libc/net +SRCS+=	inet_ntoa.c inet_addr.c + +# decompression functionality from libz +.PATH:	${.CURDIR}/../libz +CFLAGS+=-DHAVE_MEMCPY +SRCS+=	adler32.c crc32.c infblock.c infcodes.c inffast.c inflate.c \ +	inftrees.c infutil.c zutil.c  + +# 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 + +# network routines +SRCS+=	arp.c ether.c in_cksum.c net.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 zipfs.c +SRCS+=	netif.c nfs.c +# needs "open directory" support +#SRCS+=	dosfs.c + +.include <bsd.lib.mk> diff --git a/lib/libstand/__main.c b/lib/libstand/__main.c new file mode 100644 index 000000000000..be23105b64b2 --- /dev/null +++ b/lib/libstand/__main.c @@ -0,0 +1,40 @@ +/*	$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/types.h> + +void __main(void); + +void +__main() +{ +} diff --git a/lib/libstand/alloc.c b/lib/libstand/alloc.c new file mode 100644 index 000000000000..7fc63c18c687 --- /dev/null +++ b/lib/libstand/alloc.c @@ -0,0 +1,244 @@ +/*	$NetBSD: alloc.c,v 1.11 1997/09/17 16:24:00 drochner Exp $	*/ + +/* + * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved. + * Copyright (c) 1996 + *	Matthias Drochner.  All rights reserved. + * 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. + * + *	@(#)alloc.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. + */ + +/* + * Dynamic memory allocator. + * + * Compile options: + * + *	ALLOC_TRACE	enable tracing of allocations/deallocations + + *	ALLOC_FIRST_FIT	use a first-fit allocation algorithm, rather than + *			the default best-fit algorithm. + * + *	HEAP_LIMIT	heap limit address (defaults to "no limit"). + * + *	HEAP_START	start address of heap (defaults to '&end'). + * + *	DEBUG		enable debugging sanity checks. + */ + +#include <sys/param.h> +#include "stand.h" + +/* Default to variable heap operation */ +#define HEAP_VARIABLE +#define DEBUG + +/* + * Each block actually has ALIGN(size_t) + ALIGN(size) bytes allocated + * to it, as follows: + * + * 0 ... (sizeof(size_t) - 1) + *	allocated or unallocated: holds size of user-data part of block. + * + * sizeof(size_t) ... (ALIGN(sizeof(size_t)) - 1) + *	allocated: unused + *	unallocated: depends on packing of struct fl + * + * ALIGN(sizeof(size_t)) ... (ALIGN(sizeof(size_t)) + ALIGN(data size) - 1) + *	allocated: user data + *	unallocated: depends on packing of struct fl + * + * 'next' is only used when the block is unallocated (i.e. on the free list). + * However, note that ALIGN(sizeof(size_t)) + ALIGN(data size) must + * be at least 'sizeof(struct fl)', so that blocks can be used as structures + * when on the free list. + */ +struct fl { +	size_t		size; +	struct fl	*next; +} *freelist = (struct fl *)0; + +#ifdef HEAP_VARIABLE +static char *top, *heapstart, *heaplimit; +void setheap(start, limit) +void *start, *limit; +{ +    heapstart = top = start; +    heaplimit = limit; +} +#define HEAP_START heapstart +#define HEAP_LIMIT heaplimit +#else /* !HEAP_VARIABLE */ +#ifndef HEAP_START +extern char end[]; +#define HEAP_START end +#endif +static char *top = (char*)HEAP_START; +#endif /* HEAP_VARIABLE */ + +void * +malloc(size) +	size_t size; +{ +	register struct fl **f = &freelist, **bestf = NULL; +	size_t bestsize = 0xffffffff;	/* greater than any real size */ +	char *help; +	int failed; + +#ifdef ALLOC_TRACE +	printf("alloc(%u)", size); +#endif + +#ifdef ALLOC_FIRST_FIT +	while (*f != (struct fl *)0 && (*f)->size < size) +		f = &((*f)->next); +	bestf = f; +	failed = (*bestf == (struct fl *)0); +#else +	/* scan freelist */ +	while (*f) { +		if ((*f)->size >= size) { +			if ((*f)->size == size) /* exact match */ +				goto found; + +			if ((*f)->size < bestsize) { +				/* keep best fit */ +	                        bestf = f; +	                        bestsize = (*f)->size; +	                } +	        } +	        f = &((*f)->next); +	} + +	/* no match in freelist if bestsize unchanged */ +	failed = (bestsize == 0xffffffff); +#endif + +	if (failed) { /* nothing found */ +	        /* +		 * allocate from heap, keep chunk len in +		 * first word +		 */ +	        help = top; + +		/* make _sure_ the region can hold a struct fl. */ +		if (size < ALIGN(sizeof (struct fl *))) +			size = ALIGN(sizeof (struct fl *)); +		top += ALIGN(sizeof(size_t)) + ALIGN(size); +#ifdef HEAP_LIMIT +		if (top > (char*)HEAP_LIMIT) +		        panic("heap full (0x%lx+%u)", help, size); +#endif +		*(size_t *)help = ALIGN(size); +#ifdef ALLOC_TRACE +		printf("=%lx\n", (u_long)help + ALIGN(sizeof(size_t))); +		getchar(); +#endif +		return(help + ALIGN(sizeof(size_t))); +	} + +	/* we take the best fit */ +	f = bestf; + +found: +        /* remove from freelist */ +        help = (char*)*f; +	*f = (*f)->next; +#ifdef ALLOC_TRACE +	printf("=%lx (origsize %u)\n", (u_long)help + ALIGN(sizeof(size_t)), +	    *(size_t *)help); +	getchar(); +#endif +	return(help + ALIGN(sizeof(size_t))); +} + +void +free(ptr) +	void *ptr; +{ +	register struct fl *f = +	    (struct fl *)((char*)ptr - ALIGN(sizeof(size_t))); +#ifdef ALLOC_TRACE +	printf("free(%lx, %u) (origsize %u)\n", (u_long)ptr, size, f->size); +	getchar(); +#endif +#ifdef DEBUG +	if (ptr < (void *)HEAP_START) +		printf("free: %lx before start of heap.\n", (u_long)ptr); + +#ifdef HEAP_LIMIT +	if (ptr > (void *)HEAP_LIMIT) +		printf("free: %lx beyond end of heap.\n", (u_long)ptr); +#endif +#endif /* DEBUG */ +	/* put into freelist */ +	f->next = freelist; +	freelist = f; +} + +/* + * Emulate sbrk(0) behaviour + */ +char * +sbrk(int junk) +{ +    return((char *)top); +} diff --git a/lib/libstand/arp.c b/lib/libstand/arp.c new file mode 100644 index 000000000000..4736b516d08c --- /dev/null +++ b/lib/libstand/arp.c @@ -0,0 +1,310 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp  (LBL) + */ + +#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 *, size_t, time_t); + +/* Broadcast an ARP packet, asking who has addr on interface d */ +u_char * +arpwhohas(d, addr) +	register struct iodesc *d; +	struct in_addr addr; +{ +	register int i; +	register struct ether_arp *ah; +	register struct arp_list *al; +	struct { +		struct ether_header eh; +		struct { +			struct ether_arp arp; +			u_char pad[18]; 	/* 60 - sizeof(...) */ +		} data; +	} wbuf; +	struct { +		struct ether_header eh; +		struct { +			struct ether_arp arp; +			u_char pad[24]; 	/* extra space */ +		} data; +	} rbuf; + +	/* 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; + +	i = sendrecv(d, +	    arpsend, &wbuf.data, sizeof(wbuf.data), +	    arprecv, &rbuf.data, sizeof(rbuf.data)); +	if (i == -1) { +		panic("arp: no response for %s\n", +			  inet_ntoa(addr)); +	} + +	/* Store ethernet address in cache */ +	ah = &rbuf.data.arp; +#ifdef ARP_DEBUG + 	if (debug) { +		printf("arp: response from %s\n", +		    ether_sprintf(rbuf.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; + +	return (al->ea); +} + +static ssize_t +arpsend(d, pkt, len) +	register struct iodesc *d; +	register void *pkt; +	register 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(d, pkt, len, tleft) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +	time_t tleft; +{ +	register ssize_t n; +	register struct ether_arp *ah; +	u_int16_t etype;	/* host order */ + +#ifdef ARP_DEBUG + 	if (debug) +		printf("arprecv: "); +#endif + +	n = readether(d, pkt, len, 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 +		return (-1); +	} + +	if (etype != ETHERTYPE_ARP) { +#ifdef ARP_DEBUG +		if (debug) +			printf("not arp type=%d\n", etype); +#endif +		return (-1); +	} + +	/* Ethernet address now checked in readether() */ + +	ah = (struct ether_arp *)pkt; +	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 +		return (-1); +	} + +	if (ah->arp_op == htons(ARPOP_REQUEST)) { +#ifdef ARP_DEBUG +		if (debug) +			printf("is request\n"); +#endif +		arp_reply(d, ah); +		return (-1); +	} + +	if (ah->arp_op != htons(ARPOP_REPLY)) { +#ifdef ARP_DEBUG +		if (debug) +			printf("not ARP reply\n"); +#endif +		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 +		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 +	return (n); +} + +/* + * Convert an ARP request into a reply and send it. + * Notes:  Re-uses buffer.  Pad to length = 46. + */ +void +arp_reply(d, pkt) +	register struct iodesc *d; +	register void *pkt;		/* the request */ +{ +	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/lib/libstand/bcd.c b/lib/libstand/bcd.c new file mode 100644 index 000000000000..540ed5f61f66 --- /dev/null +++ b/lib/libstand/bcd.c @@ -0,0 +1,35 @@ +/* + * Some data-tables that are often used. + * Cannot be copyrighted. + */ + +#include <sys/libkern.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/lib/libstand/bootp.c b/lib/libstand/bootp.c new file mode 100644 index 000000000000..35ccf7a74400 --- /dev/null +++ b/lib/libstand/bootp.c @@ -0,0 +1,396 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp  (LBL) + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include <string.h> + +#define BOOTP_DEBUGxx +#define SUPPORT_DHCP + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "bootp.h" + + +struct in_addr servip; + +static n_long	nmask, smask; + +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 *, size_t, time_t); +static	int vend_rfc1048(u_char *, u_int); +#ifdef BOOTP_VEND_CMU +static	void vend_cmu(u_char *); +#endif + +#ifdef SUPPORT_DHCP +static char expected_dhcpmsgtype = -1, dhcp_ok; +struct in_addr dhcp_serverip; +#endif + +/* Fetch required bootp infomation */ +void +bootp(sock) +	int sock; +{ +	struct iodesc *d; +	register struct bootp *bp; +	struct { +		u_char header[HEADER_SIZE]; +		struct bootp wbootp; +	} wbuf; +	struct { +		u_char header[HEADER_SIZE]; +		struct bootp rbootp; +	} rbuf; + +#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; +	bp->bp_vend[7] = TAG_END; +#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, &rbuf.rbootp, sizeof(rbuf.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(&rbuf.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); +		bp->bp_vend[25] = TAG_END; + +		expected_dhcpmsgtype = DHCPACK; + +		if(sendrecv(d, +			    bootpsend, bp, sizeof(*bp), +			    bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) +		   == -1) { +			printf("DHCPREQUEST failed\n"); +			return; +		} +	} +#endif + +	myip = d->myip = rbuf.rbootp.bp_yiaddr; +	servip = rbuf.rbootp.bp_siaddr; +	if(rootip.s_addr == INADDR_ANY) rootip = servip; +	bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); +	bootfile[sizeof(bootfile) - 1] = '\0'; + +	if (IN_CLASSA(myip.s_addr)) +		nmask = htonl(IN_CLASSA_NET); +	else if (IN_CLASSB(myip.s_addr)) +		nmask = htonl(IN_CLASSB_NET); +	else +		nmask = htonl(IN_CLASSC_NET); +#ifdef BOOTP_DEBUG +	if (debug) +		printf("'native netmask' is %s\n", intoa(nmask)); +#endif + +	/* Check subnet mask against net mask; toss if bogus */ +	if ((nmask & smask) != nmask) { +#ifdef BOOTP_DEBUG +		if (debug) +			printf("subnet mask (%s) bad\n", intoa(smask)); +#endif +		smask = 0; +	} + +	/* Get subnet (or natural net) mask */ +	netmask = nmask; +	if (smask) +		netmask = smask; +#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; +} + +/* Transmit a bootp request */ +static ssize_t +bootpsend(d, pkt, len) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +{ +	register 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(d, pkt, len, tleft) +register struct iodesc *d; +register void *pkt; +register size_t len; +time_t tleft; +{ +	register ssize_t n; +	register struct bootp *bp; + +#ifdef BOOTP_DEBUGx +	if (debug) +		printf("bootp_recvoffer: called\n"); +#endif + +	n = readudp(d, pkt, len, tleft); +	if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) +		goto bad; + +	bp = (struct bootp *)pkt; +	 +#ifdef BOOTP_DEBUG +	if (debug) +		printf("bootprecv: checked.  bp = 0x%lx, n = %d\n", +		    (long)bp, (int)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) { +		if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0) +		    goto bad; +	} +#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); + +	return(n); +bad: +	errno = 0; +	return (-1); +} + +static int +vend_rfc1048(cp, len) +	register u_char *cp; +	u_int len; +{ +	register u_char *ep; +	register int size; +	register u_char tag; + +#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); + +	while (cp < ep) { +		tag = *cp++; +		size = *cp++; +		if (tag == TAG_END) +			break; + +		if (tag == TAG_SUBNET_MASK) { +			bcopy(cp, &smask, sizeof(smask)); +		} +		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(swapip.s_addr)); +		} +		if (tag == TAG_ROOTPATH) { +			strncpy(rootpath, (char *)cp, sizeof(rootpath)); +			rootpath[size] = '\0'; +		} +		if (tag == TAG_HOSTNAME) { +			strncpy(hostname, (char *)cp, sizeof(hostname)); +			hostname[size] = '\0'; +		} +#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(cp) +	u_char *cp; +{ +	register 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) { +		smask = vp->v_smask.s_addr; +	} +	if (vp->v_dgate.s_addr != 0) { +		gateip = vp->v_dgate; +	} +} +#endif diff --git a/lib/libstand/bootp.h b/lib/libstand/bootp.h new file mode 100644 index 000000000000..7435e3cdbbb0 --- /dev/null +++ b/lib/libstand/bootp.h @@ -0,0 +1,137 @@ +/*	$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. + */ + + +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) + +#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) +#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 */ diff --git a/lib/libstand/bootparam.c b/lib/libstand/bootparam.c new file mode 100644 index 000000000000..6d64e7a87d2e --- /dev/null +++ b/lib/libstand/bootparam.c @@ -0,0 +1,449 @@ +/*	$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. + */ + +/* + * 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(sockfd) +	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; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct repl d; +	} rdata; +	char *send_tail, *recv_head; +	struct iodesc *d; +	int len, x; + +	RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); + +	if (!(d = socktodesc(sockfd))) { +		RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); +		return (-1); +	} +	args = &sdata.d; +	repl = &rdata.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 (-1); + +	/* RPC: portmap/callit */ +	d->myport = htons(--rpc_port); +	d->destip.s_addr = INADDR_BROADCAST;	/* XXX: subnet bcast? */ +	/* rpc_call will set d->destport */ + +	len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, +				  args, send_tail - (char*)args, +				  repl, sizeof(*repl)); +	if (len < 8) { +		printf("bootparamd: 'whoami' call failed\n"); +		return (-1); +	} + +	/* 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); +		return (-1); +	} +	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")); +		return (-1); +	} + +	/* domain name */ +	domainnamelen = MAXHOSTNAMELEN-1; +	if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { +		RPC_PRINTF(("bp_whoami: bad domainname\n")); +		return (-1); +	} + +	/* gateway address */ +	if (xdr_inaddr_decode(&recv_head, &gateip)) { +		RPC_PRINTF(("bp_whoami: bad gateway\n")); +		return (-1); +	} + +	/* success */ +	return(0); +} + + +/* + * RPC: bootparam/getfile + * Given client name and file "key", get: + *	server name + *	server IP address + *	server pathname + */ +int +bp_getfile(sockfd, key, serv_addr, pathname) +	int sockfd; +	char *key; +	char *pathname; +	struct in_addr *serv_addr; +{ +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		n_long  d[64]; +	} sdata; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		n_long  d[128]; +	} rdata; +	char serv_name[FNAME_SIZE]; +	char *send_tail, *recv_head; +	/* misc... */ +	struct iodesc *d; +	int 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; +	recv_head = (char*) rdata.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 */ + +	rlen = rpc_call(d, +		BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, +		sdata.d, send_tail - (char*)sdata.d, +		rdata.d, sizeof(rdata.d)); +	if (rlen < 4) { +		RPC_PRINTF(("bp_getfile: short reply\n")); +		errno = EBADRPC; +		return (-1); +	} +	recv_head = (char*) rdata.d; + +	/* +	 * Parse result message. +	 */ + +	/* server name */ +	sn_len = FNAME_SIZE-1; +	if (xdr_string_decode(&recv_head, serv_name, &sn_len)) { +		RPC_PRINTF(("bp_getfile: bad server name\n")); +		return (-1); +	} + +	/* server IP address (mountd/NFS) */ +	if (xdr_inaddr_decode(&recv_head, serv_addr)) { +		RPC_PRINTF(("bp_getfile: bad server addr\n")); +		return (-1); +	} + +	/* server pathname */ +	path_len = MAXPATHLEN-1; +	if (xdr_string_decode(&recv_head, pathname, &path_len)) { +		RPC_PRINTF(("bp_getfile: bad server path\n")); +		return (-1); +	} + +	/* success */ +	return(0); +} + + +/* + * eXternal Data Representation routines. + * (but with non-standard args...) + */ + + +int +xdr_string_encode(pkt, str, len) +	char **pkt; +	char *str; +	int len; +{ +	u_int32_t *lenp; +	char *datap; +	int padlen = (len + 3) & ~3;	/* padded length */ + +	/* The data will be int aligned. */ +	lenp = (u_int32_t*) *pkt; +	*pkt += sizeof(*lenp); +	*lenp = htonl(len); + +	datap = *pkt; +	*pkt += padlen; +	bcopy(str, datap, len); + +	return (0); +} + +int +xdr_string_decode(pkt, str, len_p) +	char **pkt; +	char *str; +	int *len_p;		/* bufsize - 1 */ +{ +	u_int32_t *lenp; +	char *datap; +	int slen;	/* string length */ +	int plen;	/* padded length */ + +	/* The data will be int aligned. */ +	lenp = (u_int32_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(pkt, ia) +	char **pkt; +	struct in_addr ia;		/* network order */ +{ +	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(pkt, ia) +	char **pkt; +	struct in_addr *ia;		/* network order */ +{ +	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/lib/libstand/bootparam.h b/lib/libstand/bootparam.h new file mode 100644 index 000000000000..6f0c773a0759 --- /dev/null +++ b/lib/libstand/bootparam.h @@ -0,0 +1,5 @@ +/*	$NetBSD: bootparam.h,v 1.3 1998/01/05 19:19:41 perry Exp $	*/ + +int bp_whoami(int sock); +int bp_getfile(int sock, char *key, struct in_addr *addrp, char *path); + diff --git a/lib/libstand/bswap.c b/lib/libstand/bswap.c new file mode 100644 index 000000000000..1951509df93f --- /dev/null +++ b/lib/libstand/bswap.c @@ -0,0 +1,37 @@ +/* + * Written by Manuel Bouyer <bouyer@netbsd.org>. + * Public domain. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$NetBSD: bswap32.c,v 1.1 1997/10/09 15:42:33 bouyer Exp $"; +static char *rcsid = "$NetBSD: bswap64.c,v 1.1 1997/10/09 15:42:33 bouyer Exp $"; +#endif + +#include <sys/types.h> + +#undef bswap32 +#undef bswap64 + +u_int32_t +bswap32(x) +    u_int32_t x; +{ +	return  ((x << 24) & 0xff000000 ) | +			((x <<  8) & 0x00ff0000 ) | +			((x >>  8) & 0x0000ff00 ) | +			((x >> 24) & 0x000000ff ); +} + +u_int64_t +bswap64(x) +    u_int64_t x; +{   +	u_int32_t *p = (u_int32_t*)&x; +	u_int32_t t; +	t = bswap32(p[0]); +	p[0] = bswap32(p[1]); +	p[1] = t; +	return x; +}    + diff --git a/lib/libstand/cd9660.c b/lib/libstand/cd9660.c new file mode 100644 index 000000000000..5d3d85acc844 --- /dev/null +++ b/lib/libstand/cd9660.c @@ -0,0 +1,401 @@ +/*	$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. + */ + +/* + * 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 <isofs/cd9660/iso.h> + +#include "stand.h" + +static int	cd9660_open(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); + +struct fs_ops cd9660_fsops = { +	"cd9660", cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, cd9660_stat +}; + +struct file { +	off_t off;			/* Current offset within file */ +	daddr_t bno;			/* Starting block number  */ +	off_t size;			/* Size of file */ +}; + +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) + +/* XXX these should be in the system headers */ +static __inline int +isonum_722(p) +	u_char *p; +{ +	return (*p << 8)|p[1]; +} + +static __inline int +isonum_732(p) +	u_char *p; +{ +	return (*p << 24)|(p[1] << 16)|(p[2] << 8)|p[3]; +} + + + +static int +pnmatch(path, pp) +	char *path; +	struct ptable_ent *pp; +{ +	char *cp; +	int i; +	 +	cp = pp->name; +	for (i = isonum_711(pp->namlen); --i >= 0; path++, cp++) { +		if (toupper(*path) == *cp) +			continue; +		return 0; +	} +	if (*path != '/') +		return 0; +	return 1; +} + +static int +dirmatch(path, dp) +	char *path; +	struct iso_directory_record *dp; +{ +	char *cp; +	int i; + +	/* This needs to be a regular file */ +	if (dp->flags[0] & 6) +		return 0; + +	cp = dp->name; +	for (i = isonum_711(dp->name_len); --i >= 0; path++, cp++) { +		if (!*path) +			break; +		if (toupper(*path) == *cp) +			continue; +		return 0; +	} +	if (*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(path, f) +	char *path; +	struct open_file *f; +{ +	struct file *fp = 0; +	void *buf; +	struct iso_primary_descriptor *vd; +	size_t buf_size, read, psize, dsize; +	daddr_t bno; +	int parent, ent; +	struct ptable_ent *pp; +	struct iso_directory_record *dp = 0; +	int rc; +	 +	/* First find the volume descriptor */ +	buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); +	vd = buf; +	for (bno = 16;; bno++) { +		twiddle(); +		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; +	 +	/* Now get the path table and lookup the directory of the file */ +	bno = isonum_732(vd->type_m_path_table); +	psize = isonum_733(vd->path_table_size); +	 +	if (psize > ISO_DEFAULT_BLOCK_SIZE) { +		free(buf); +		buf = malloc(buf_size = roundup(psize, ISO_DEFAULT_BLOCK_SIZE)); +	} + +	twiddle(); +	rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), +				   buf_size, buf, &read); +	if (rc) +		goto out; +	if (read != buf_size) { +		rc = EIO; +		goto out; +	} +	 +	parent = 1; +	pp = (struct ptable_ent *)buf; +	ent = 1; +	bno = isonum_732(pp->block) + isonum_711(pp->extlen); +	 +	rc = ENOENT; +	while (*path) { +		if ((void *)pp >= buf + psize) +			break; +		if (isonum_722(pp->parent) != parent) +			break; +		if (!pnmatch(path, pp)) { +			pp = (struct ptable_ent *)((void *)pp + PTSIZE(pp)); +			ent++; +			continue; +		} +		path += isonum_711(pp->namlen) + 1; +		parent = ent; +		bno = isonum_732(pp->block) + isonum_711(pp->extlen); +		while ((void *)pp < buf + psize) { +			if (isonum_722(pp->parent) == parent) +				break; +			pp = (struct ptable_ent *)((void *)pp + PTSIZE(pp)); +			ent++; +		} +	} + +	/* Now bno has the start of the directory that supposedly contains the file */ +	bno--; +	dsize = 1;		/* Something stupid, but > 0			XXX */ +	for (psize = 0; psize < dsize;) { +		if (!(psize % ISO_DEFAULT_BLOCK_SIZE)) { +			bno++; +			twiddle(); +			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; +		} +		if (!isonum_711(dp->length)) { +			if ((void *)dp == buf) +				psize += ISO_DEFAULT_BLOCK_SIZE; +			else +				psize = roundup(psize, ISO_DEFAULT_BLOCK_SIZE); +			continue; +		} +		if (dsize == 1) +			dsize = isonum_733(dp->size); +		if (dirmatch(path, dp)) +			break; +		psize += isonum_711(dp->length); +		dp = (struct iso_directory_record *)((void *)dp + isonum_711(dp->length)); +	} + +	if (psize >= dsize) { +		rc = ENOENT; +		goto out; +	} +	 +	/* allocate file system specific data structure */ +	fp = malloc(sizeof(struct file)); +	bzero(fp, sizeof(struct file)); +	f->f_fsdata = (void *)fp; + +	fp->off = 0; +	fp->bno = isonum_733(dp->extent); +	fp->size = isonum_733(dp->size); +	free(buf); +	 +	return 0; +	 +out: +	if (fp) +		free(fp); +	free(buf); +	 +	return rc; +} + +static int +cd9660_close(f) +	struct open_file *f; +{ +	struct file *fp = (struct file *)f->f_fsdata; +	 +	f->f_fsdata = 0; +	free(fp); +	 +	return 0; +} + +static int +cd9660_read(f, start, size, resid) +	struct open_file *f; +	void *start; +	size_t size; +	size_t *resid; +{ +	struct file *fp = (struct file *)f->f_fsdata; +	int rc = 0; +	daddr_t bno; +	char buf[ISO_DEFAULT_BLOCK_SIZE]; +	char *dp; +	size_t read, off; +	 +	while (size) { +		if (fp->off < 0 || fp->off >= fp->size) +			break; +		bno = fp->off / ISO_DEFAULT_BLOCK_SIZE + fp->bno; +		if (fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1) +		    || size < ISO_DEFAULT_BLOCK_SIZE) +			dp = buf; +		else +			dp = start; +		twiddle();	 +		rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), +					   ISO_DEFAULT_BLOCK_SIZE, dp, &read); +		if (rc) +			return rc; +		if (read != ISO_DEFAULT_BLOCK_SIZE) +			return EIO; +		if (dp == buf) { +			off = fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1); +			if (read > off + size) +				read = off + size; +			read -= off; +			bcopy(buf + off, start, read); +			start += read; +			fp->off += read; +			size -= read; +		} else { +			start += ISO_DEFAULT_BLOCK_SIZE; +			fp->off += ISO_DEFAULT_BLOCK_SIZE; +			size -= ISO_DEFAULT_BLOCK_SIZE; +		} +	} +	if (resid) +		*resid = size; +	return rc; +} + +static int +cd9660_write(f, start, size, resid) +	struct open_file *f; +	void *start; +	size_t size; +	size_t *resid; +{ +	return EROFS; +} + +static off_t +cd9660_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->off = offset; +		break; +	case SEEK_CUR: +		fp->off += offset; +		break; +	case SEEK_END: +		fp->off = fp->size - offset; +		break; +	default: +		return -1; +	} +	return fp->off; +} + +static int +cd9660_stat(f, sb) +	struct open_file *f; +	struct stat *sb; +{ +	struct file *fp = (struct file *)f->f_fsdata; +	 +	/* only importatn stuff */ +	sb->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; +	sb->st_uid = sb->st_gid = 0; +	sb->st_size = fp->size; +	return 0; +} diff --git a/lib/libstand/close.c b/lib/libstand/close.c new file mode 100644 index 000000000000..aca6a656fb23 --- /dev/null +++ b/lib/libstand/close.c @@ -0,0 +1,96 @@ +/*	$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. 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. + * + *	@(#)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 "stand.h" + +int +close(fd) +	int fd; +{ +	register 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_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/lib/libstand/closeall.c b/lib/libstand/closeall.c new file mode 100644 index 000000000000..8da450a00ae9 --- /dev/null +++ b/lib/libstand/closeall.c @@ -0,0 +1,77 @@ +/*	$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. 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. + * + *	@(#)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 "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/lib/libstand/dev.c b/lib/libstand/dev.c new file mode 100644 index 000000000000..c5b9c2780495 --- /dev/null +++ b/lib/libstand/dev.c @@ -0,0 +1,62 @@ +/*	$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. 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. + * + *	@(#)dev.c	8.1 (Berkeley) 6/11/93 + */ + +#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/lib/libstand/dev_net.c b/lib/libstand/dev_net.c new file mode 100644 index 000000000000..8d09e4f7c084 --- /dev/null +++ b/lib/libstand/dev_net.c @@ -0,0 +1,255 @@ +/*	$NetBSD: dev_net.c,v 1.12 1997/12/10 20:38:37 gwr Exp $	*/ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross. + * + * 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 NetBSD + *        Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * This module implements a "raw device" interface suitable for + * use by the stand-alone I/O library NFS code.  This interface + * does not support any "block" access, and exists only for the + * purpose of initializing the network interface, getting boot + * parameters, and performing the NFS mount. + * + * At open time, this does: + * + * find interface      - netif_open() + * RARP for IP address - rarp_getipaddress() + * RPC/bootparams      - callrpc(d, RPC_BOOTPARAMS, ...) + * RPC/mountd          - nfs_mount(sock, ip, path) + * + * the root file handle from mountd is saved in a global + * for use by the NFS open code (NFS/lookup). + */ + +#include <machine/stdarg.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "nfs.h" +#include "bootparam.h" +#include "dev_net.h" + +static int netdev_sock = -1; +static int netdev_opens; + +static int net_getparams(int sock); + +struct devsw netdev = { +    "net",  +    DEVT_NET,  +    net_init, +    net_strategy,  +    net_open,  +    net_close,  +    noioctl +}; + +/* + * Called by devopen after it sets f->f_dev to our devsw entry. + * This opens the low-level device and sets f->f_devdata. + * This is declared with variable arguments... + */ +int +net_open(struct open_file *f, void *vdev) +{ +	char *devname;		/* Device part of file name (or NULL). */ +	int error = 0; + +	devname = vdev; + +#ifdef	NETIF_DEBUG +	if (debug) +		printf("net_open: %s\n", devname); +#endif + +	/* On first open, do netif open, mount, etc. */ +	if (netdev_opens == 0) { +		/* Find network interface. */ +		if (netdev_sock < 0) { +			netdev_sock = netif_open(devname); +			if (netdev_sock < 0) { +				printf("net_open: netif_open() failed\n"); +				return (ENXIO); +			} +			if (debug) +				printf("net_open: netif_open() succeeded\n"); +		} +		if (rootip.s_addr == 0) { +			/* Get root IP address, and path, etc. */ +			error = net_getparams(netdev_sock); +			if (error) { +				/* getparams makes its own noise */ +				netif_close(netdev_sock); +				netdev_sock = -1; +				return (error); +			} +		} +	} +	netdev_opens++; +	return (error); +} + +int +net_close(f) +	struct open_file *f; +{ + +#ifdef	NETIF_DEBUG +	if (debug) +		printf("net_close: opens=%d\n", netdev_opens); +#endif + +	/* On last close, do netif close, etc. */ +	f->f_devdata = NULL; +	/* Extra close call? */ +	if (netdev_opens <= 0) +		return (0); +	netdev_opens--; +	/* Not last close? */ +	if (netdev_opens > 0) +		return(0); +	rootip.s_addr = 0; +	if (netdev_sock >= 0) { +		if (debug) +			printf("net_close: calling netif_close()\n"); +		netif_close(netdev_sock); +		netdev_sock = -1; +	} +	return (0); +} + +int +net_ioctl() +{ +	return EIO; +} + +int +net_strategy() +{ +	return EIO; +} + + +/* + * Get info for NFS boot: our IP address, our hostname, + * server IP address, and our root path on the server. + * There are two ways to do this:  The old, Sun way, + * and the more modern, BOOTP way. (RFC951, RFC1048) + * + * The default is to use the Sun bootparams RPC + * (because that is what the kernel will do). + * MD code can make try_bootp initialied data, + * which will override this common definition. + */ +#ifdef	SUPPORT_BOOTP +int try_bootp; +int bootp(int sock); +#endif + +static int +net_getparams(sock) +	int sock; +{ +	char buf[MAXHOSTNAMELEN]; +	n_long smask; + +#ifdef	SUPPORT_BOOTP +	/* +	 * Try to get boot info using BOOTP.  If we succeed, then +	 * the server IP address, gateway, and root path will all +	 * be initialized.  If any remain uninitialized, we will +	 * use RARP and RPC/bootparam (the Sun way) to get them. +	 */ +	if (try_bootp) +		bootp(sock); +	if (myip.s_addr != 0) +		return (0); +	if (debug) +		printf("net_open: BOOTP failed, trying RARP/RPC...\n"); +#endif + +	/* +	 * Use RARP to get our IP address.  This also sets our +	 * netmask to the "natural" default for our address. +	 */ +	if (rarp_getipaddress(sock)) { +		printf("net_open: RARP failed\n"); +		return (EIO); +	} +	printf("net_open: client addr: %s\n", inet_ntoa(myip)); + +	/* Get our hostname, server IP address, gateway. */ +	if (bp_whoami(sock)) { +		printf("net_open: bootparam/whoami RPC failed\n"); +		return (EIO); +	} +	printf("net_open: client name: %s\n", hostname); + +	/* +	 * Ignore the gateway from whoami (unreliable). +	 * Use the "gateway" parameter instead. +	 */ +	smask = 0; +	gateip.s_addr = 0; +	if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { +		/* Got it!  Parse the netmask. */ +		smask = ip_convertaddr(buf); +	} +	if (smask) { +		netmask = smask; +		printf("net_open: subnet mask: %s\n", intoa(netmask)); +	} +	if (gateip.s_addr) +		printf("net_open: net gateway: %s\n", inet_ntoa(gateip)); + +	/* Get the root server and pathname. */ +	if (bp_getfile(sock, "root", &rootip, rootpath)) { +		printf("net_open: bootparam/getfile RPC failed\n"); +		return (EIO); +	} + +	printf("net_open: server addr: %s\n", inet_ntoa(rootip)); +	printf("net_open: server path: %s\n", rootpath); + +	return (0); +} diff --git a/lib/libstand/dev_net.h b/lib/libstand/dev_net.h new file mode 100644 index 000000000000..f728c4f9b470 --- /dev/null +++ b/lib/libstand/dev_net.h @@ -0,0 +1,7 @@ +/*	$NetBSD: dev_net.h,v 1.3 1997/03/15 18:12:14 is Exp $	*/ + +int	net_open(struct open_file *, ...); +int	net_close(struct open_file *); +int	net_ioctl(); +int	net_strategy(); + diff --git a/lib/libstand/dosfs.c b/lib/libstand/dosfs.c new file mode 100644 index 000000000000..90aa728ad202 --- /dev/null +++ b/lib/libstand/dosfs.c @@ -0,0 +1,660 @@ +/* + * 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. + */ + +/* + * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, + * also supports VFAT. + */ + +#include <sys/types.h> +#include <string.h> +#include <stddef.h> + +#include "stand.h" + +#if 0 +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#endif + +#include "dosfs.h" + + +static int	dos_open(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); + +struct fs_ops dos_fsops = { +    "dosfs", dos_open, dos_close, dos_read, null_write, dos_seek, dos_stat +}; + +#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 */ + +/* 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 dosunmount(DOS_FS *); +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 int fatget(DOS_FS *, u_int *); +static int fatend(u_int, u_int); +static int ioread(DOS_FS *, u_int, void *, u_int); +static int iobuf(DOS_FS *, u_int); +static int ioget(struct open_file *, u_int, void *, u_int); + +/* + * Mount DOS filesystem + */ +static int +dos_mount(DOS_FS *fs, struct open_file *fd) +{ +    int err; + +    bzero(fs, sizeof(DOS_FS)); +    fs->fd = fd; +    if ((err = !(fs->buf = alloc(SECSIZ)) ? errno : 0) || +        (err = ioget(fs->fd, 0, fs->buf, 1)) || +        (err = parsebs(fs, (DOS_BS *)fs->buf))) { +        (void)dosunmount(fs); +        return(err); +    } +    return 0; +} + +/* + * Unmount mounted filesystem + */ +static int +dos_unmount(DOS_FS *fs) +{ +    int err; + +    if (fs->links) +        return(EBUSY); +    if ((err = dosunmount(fs))) +        return(err); +    return 0; +} + +/* + * Common code shared by dos_mount() and dos_unmount() + */ +static int +dosunmount(DOS_FS *fs) +{ +    if (fs->buf) +        free(fs->buf, 0); +    free(fs, 0); +    return(0); +} + +/* + * Open DOS file + */ +static int +dos_open(char *path, struct open_file *fd) +{ +    DOS_DE *de; +    DOS_FILE *f; +    DOS_FS *fs; +    u_int size, clus; +    int err = 0; + +    /* Allocate mount structure, associate with open */ +    fs = alloc(sizeof(DOS_FS)); +     +    if ((err = dos_mount(fs, fd))) +	goto out; + +    if ((err = namede(fs, path, &de))) +	goto out; + +    /* XXX we need to be able to open directories */ +    if (de->attr & FA_DIR) { +        err = EISDIR; +	goto out; +    } +    clus = stclus(fs->fatsz, de); +    size = cv4(de->size); +    if (!clus ^ !size || (clus && !okclus(fs, clus))) { +        err = EINVAL; +	goto out; +    } +    f = alloc(sizeof(DOS_FILE)); +    bzero(f, sizeof(DOS_FILE)); +    f->fs = fs; +    fs->links++; +    f->de = *de; +    fd->f_fsdata = (void *)f; + + out: +    return(err); +} + +/* + * Read from file + */ +static int +dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) +{ +    u_int nb, off, clus, c, cnt, n; +    DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; +    int err = 0; + +    nb = (u_int)nbyte; +    if (nb > (n = cv4(f->de.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, blkoff(f->fs, c) + off, buf, n))) +	    goto out; +        f->offset += n; +        f->c = c; +        off = 0; +        buf += n; +        cnt -= n; +    } + out: +    if (resid) +	*resid = 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: +	return(-1); +    } +    off += offset; +    if (off < 0 || off > size) +        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, 0); +    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 = 0444; +    sb->st_nlink = 1; +    sb->st_uid = 0; +    sb->st_gid = 0; +    sb->st_size = cv4(f->de.size); +    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 = dot; +    if (*path == '/') +        path++; +    while (*path) { +        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; +        if (*path == '/') +            path++; +    } +    *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, i; + +    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, 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)) { +                            for (x = 0, i = 0; i < 11; i++) +                                x = ((((x & 1) << 7) | (x >> 1)) + +                                     dir[ent].de.name[i]) & 0xff; +                            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; +} + +/* + * Get next cluster in cluster chain + */ +static int +fatget(DOS_FS *fs, u_int *c) +{ +    u_char buf[4]; +    u_int x; +    int err; + +    err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, +                 fs->fatsz != 32 ? 2 : 4); +    if (err) +        return err; +    x = fs->fatsz != 32 ? cv2(buf) : cv4(buf); +    *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x; +    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, u_int nbyte) +{ +    char *s; +    u_int off, n; +    int err; + +    s = buf; +    if ((off = offset & (SECSIZ - 1))) { +        offset -= off; +        if ((err = iobuf(fs, bytsec(offset)))) +            return err; +        offset += SECSIZ; +        if ((n = SECSIZ - off) > nbyte) +            n = nbyte; +        memcpy(s, fs->buf + off, n); +        s += n; +        nbyte -= n; +    } +    n = nbyte & (SECSIZ - 1); +    if (nbyte -= n) { +        if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte)))) +            return err; +        offset += nbyte; +        s += nbyte; +    } +    if (n) { +        if ((err = iobuf(fs, bytsec(offset)))) +            return err; +        memcpy(s, fs->buf, n); +    } +    return 0; +} + +/* + * Buffered sector-based I/O primitive + */ +static int +iobuf(DOS_FS *fs, u_int lsec) +{ +    int err; + +    if (fs->bufsec != lsec) { +        if ((err = ioget(fs->fd, lsec, fs->buf, 1))) +            return err; +        fs->bufsec = lsec; +    } +    return 0; +} + +/* + * Sector-based I/O primitive + */ +static int +ioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec) +{ +    int	err; +     +    if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec,  +					secbyt(nsec), buf, NULL))) +	return(err); +    return(0); +} diff --git a/lib/libstand/dosfs.h b/lib/libstand/dosfs.h new file mode 100644 index 000000000000..e44b6b51f288 --- /dev/null +++ b/lib/libstand/dosfs.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#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 *buf;                /* buffer */ +    u_int bufsec;               /* buffered sector */ +    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_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/lib/libstand/environment.c b/lib/libstand/environment.c new file mode 100644 index 000000000000..007b6a2dc87b --- /dev/null +++ b/lib/libstand/environment.c @@ -0,0 +1,212 @@ +/*  + * 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. + * + *	$Id$ + * + */ + +/* + * 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 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, 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)); +    } else { +	ev = malloc(sizeof(struct env_var)); +	ev->ev_name = strdup(name); +	ev->ev_value = NULL; +	/* hooks can only be set when the variable is instantiated */ +	ev->ev_sethook = sethook; +	ev->ev_unsethook = unsethook; +    } +     +    /* If there is data in the variable, discard it */ +    if (ev->ev_value != NULL) +	free(ev->ev_value); + +    /* If we have a new value, use it */ +    if (flags & EV_VOLATILE) { +	ev->ev_value = strdup(value); +    } else { +	ev->ev_value = value; +    } + +    /* Keep the flag components that are relevant */ +    ev->ev_flags = flags & (EV_DYNAMIC); + +    /* 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; +	} +    } +    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, 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; + +    if ((value = strchr(string, '=')) != NULL) +	*(value++) = 0; +    return(setenv(string, value, 1)); +} + +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_flags & EV_DYNAMIC) +	free(ev->ev_value); +    free(ev); +} + +int +env_noset(struct env_var *ev, int flags, void *value) +{ +    return(EPERM); +} + +int +env_nounset(struct env_var *ev) +{ +    return(EPERM); +} diff --git a/lib/libstand/ether.c b/lib/libstand/ether.c new file mode 100644 index 000000000000..d95f50469d57 --- /dev/null +++ b/lib/libstand/ether.c @@ -0,0 +1,151 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL) + */ + +#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(d, pkt, len, dea, etype) +	struct iodesc *d; +	void *pkt; +	size_t len; +	u_char *dea; +	int etype; +{ +	register ssize_t n; +	register 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 arg 5. + * NOTE: Caller must leave room for the Ether header. + */ +ssize_t +readether(d, pkt, len, tleft, etype) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +	time_t tleft; +	register u_int16_t *etype; +{ +	register ssize_t n; +	register struct ether_header *eh; + +#ifdef ETHER_DEBUG + 	if (debug) +		printf("readether: called\n"); +#endif + +	eh = (struct ether_header *)pkt - 1; +	len += sizeof(*eh); + +	n = netif_get(d, eh, len, tleft); +	if (n == -1 || n < sizeof(*eh)) +		return (-1); + +	/* 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 +		return (-1); +	} +	*etype = ntohs(eh->ether_type); + +	n -= sizeof(*eh); +	return (n); +} + +/* + * Convert Ethernet address to printable (loggable) representation. + */ +static char digits[] = "0123456789abcdef"; +char * +ether_sprintf(ap) +        register u_char *ap; +{ +	register i; +	static char etherbuf[18]; +	register 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/lib/libstand/fstat.c b/lib/libstand/fstat.c new file mode 100644 index 000000000000..aa8b89826fd0 --- /dev/null +++ b/lib/libstand/fstat.c @@ -0,0 +1,60 @@ +/*	$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. 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. + * + *	@(#)stat.c	8.1 (Berkeley) 6/11/93 + */ + +#include "stand.h" + +int +fstat(fd, sb) +	int fd; +	struct stat *sb; +{ +	register 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); +	return (0); +} diff --git a/lib/libstand/getopt.c b/lib/libstand/getopt.c new file mode 100644 index 000000000000..f788fe0fd946 --- /dev/null +++ b/lib/libstand/getopt.c @@ -0,0 +1,112 @@ +/* + * 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. 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. + */ + +#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(nargc, nargv, ostr) +	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/lib/libstand/gets.c b/lib/libstand/gets.c new file mode 100644 index 000000000000..3fbe9b4047a3 --- /dev/null +++ b/lib/libstand/gets.c @@ -0,0 +1,110 @@ +/*	$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. 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. + * + *	@(#)gets.c	8.1 (Berkeley) 6/11/93 + */ + +#include "stand.h" + +/* gets() with constrained input length */ + +void +ngets(char *buf, int n) +{ +    register int c; +    register 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: { +	    register 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)) { +		*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 */ +	    break; +	if ((c == '\r') ||	/* line terminators */ +	    (c == '\n')) +	    break; +	*buf++ = c;		/* keep char */ +	size--; +	len++; +    } +    *buf = 0; +    return(len); +} + diff --git a/lib/libstand/globals.c b/lib/libstand/globals.c new file mode 100644 index 000000000000..c35021c9e277 --- /dev/null +++ b/lib/libstand/globals.c @@ -0,0 +1,33 @@ +/*	$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/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; +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;			/* swap ip address */ +n_long	netmask = 0xffffff00;		/* subnet or net mask */ +int	errno;				/* our old friend */ + diff --git a/lib/libstand/gzipfs.c b/lib/libstand/gzipfs.c new file mode 100644 index 000000000000..90589078d465 --- /dev/null +++ b/lib/libstand/gzipfs.c @@ -0,0 +1,316 @@ +/*  + * 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. + * + *	$Id$ + * + */ + +#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; +    z_stream		zf_zstream; +    char		zf_buf[Z_BUFSIZE]; +}; + +static int	zf_fill(struct z_file *z); +static int	zf_open(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 zipfs_fsops = { +    "zip", +    zf_open,  +    zf_close,  +    zf_read, +    null_write, +    zf_seek, +    zf_stat +}; + +void * +calloc(int items, size_t size) +{ +    return(malloc(items * size)); +} + +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) +{ +    if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) +	return(-1); +    zf->zf_zstream.avail_in--; +    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; + +    /* Check the gzip magic header */ +    for (len = 0; len < 2; len++) { +	c = get_byte(zf); +	if (c != gz_magic[len]) { +	    return(1); +	} +    } +    method = get_byte(zf); +    flags = get_byte(zf); +    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); + +    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ +	len  =  (uInt)get_byte(zf); +	len += ((uInt)get_byte(zf))<<8; +	/* len is garbage if EOF but the loop below will quit anyway */ +	while (len-- != 0 && get_byte(zf) != -1) ; +    } +    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ +	while ((c = get_byte(zf)) != 0 && c != -1) ; +    } +    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */ +	while ((c = get_byte(zf)) != 0 && c != -1) ; +    } +    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */ +	for (len = 0; len < 2; len++) c = get_byte(zf); +    } +    /* if there's data left, we're in business */ +    return((c == -1) ? 1 : 0); +} +	 +static int +zf_open(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, ignore it */ +    if ((cp = strrchr(fname, '.')) && !strcmp(cp, ".gz")) +	return(ENOENT); + +    /* Construct new name */ +    zfname = malloc(strlen(fname) + 3); +    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)); +    bzero(zf, sizeof(struct z_file)); +    zf->zf_rawfd = rawfd; + +    /* Verify that the file is gzipped (XXX why do this afterwards?) */ +    if (check_header(zf)) { +	close(zf->zf_rawfd); +	inflateEnd(&(zf->zf_zstream)); +	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) { +	if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { +	    printf("zf_read: fill error\n"); +	    return(-1); +	} +	if (zf->zf_zstream.avail_in == 0) {		/* oops, unexpected EOF */ +	    printf("zf_read: unexpected EOF\n"); +	    break; +	} + +	error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH);	/* decompression pass */ +	if (error == Z_STREAM_END) {			/* EOF, all done */ +	    break; +	} +	if (error != Z_OK) {				/* argh, decompression error */ +	    printf("inflate: %s\n", zf->zf_zstream.msg); +	    errno = EIO; +	    return(-1); +	} +    } +    if (resid != NULL) +	*resid = zf->zf_zstream.avail_out; +    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: +	target = -1; +    } + +    /* Can we get there from here? */ +    if (target < zf->zf_zstream.total_out) { +	errno = EOFFSET; +	return -1; +    }  + +    /* skip forwards if required */ +    while (target > zf->zf_zstream.total_out) { +	if (zf_read(f, discard, min(sizeof(discard), target - zf->zf_zstream.total_out), NULL) == -1) +	    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/lib/libstand/if_ether.h b/lib/libstand/if_ether.h new file mode 100644 index 000000000000..a9bc89191bb4 --- /dev/null +++ b/lib/libstand/if_ether.h @@ -0,0 +1,263 @@ +/*	$NetBSD: if_ether.h,v 1.25 1997/01/17 17:06:06 mikel Exp $	*/ + +/* + * Copyright (c) 1982, 1986, 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. 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. + * + *	@(#)if_ether.h	8.1 (Berkeley) 6/10/93 + */ + +/* + * Ethernet address - 6 octets + * this is only used by the ethers(3) functions. + */ +struct ether_addr { +	u_int8_t ether_addr_octet[6]; +}; + +/* + * Structure of a 10Mb/s Ethernet header. + */ +#define	ETHER_ADDR_LEN	6 + +struct	ether_header { +	u_int8_t  ether_dhost[ETHER_ADDR_LEN]; +	u_int8_t  ether_shost[ETHER_ADDR_LEN]; +	u_int16_t ether_type; +}; + +#define	ETHERTYPE_PUP		0x0200	/* PUP protocol */ +#define	ETHERTYPE_IP		0x0800	/* IP protocol */ +#define	ETHERTYPE_ARP		0x0806	/* address resolution protocol */ +#define	ETHERTYPE_REVARP	0x8035	/* reverse addr resolution protocol */ + +/* + * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have + * (type-ETHERTYPE_TRAIL)*512 bytes of data followed + * by an ETHER type (as given above) and then the (variable-length) header. + */ +#define	ETHERTYPE_TRAIL		0x1000		/* Trailer packet */ +#define	ETHERTYPE_NTRAILER	16 + +#define	ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#define	ETHERMTU	1500 +#define	ETHERMIN	(60-14) + +#ifdef _KERNEL +/* + * Macro to map an IP multicast address to an Ethernet multicast address. + * The high-order 25 bits of the Ethernet address are statically assigned, + * and the low-order 23 bits are taken from the low end of the IP address. + */ +#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr)				\ +	/* struct in_addr *ipaddr; */					\ +	/* u_int8_t enaddr[ETHER_ADDR_LEN]; */				\ +{									\ +	(enaddr)[0] = 0x01;						\ +	(enaddr)[1] = 0x00;						\ +	(enaddr)[2] = 0x5e;						\ +	(enaddr)[3] = ((u_int8_t *)ipaddr)[1] & 0x7f;			\ +	(enaddr)[4] = ((u_int8_t *)ipaddr)[2];				\ +	(enaddr)[5] = ((u_int8_t *)ipaddr)[3];				\ +} +#endif + +/* + * Ethernet Address Resolution Protocol. + * + * See RFC 826 for protocol description.  Structure below is adapted + * to resolving internet addresses.  Field names used correspond to  + * RFC 826. + */ +struct	ether_arp { +	struct	 arphdr ea_hdr;			/* fixed-size header */ +	u_int8_t arp_sha[ETHER_ADDR_LEN];	/* sender hardware address */ +	u_int8_t arp_spa[4];			/* sender protocol address */ +	u_int8_t arp_tha[ETHER_ADDR_LEN];	/* target hardware address */ +	u_int8_t arp_tpa[4];			/* target protocol address */ +}; +#define	arp_hrd	ea_hdr.ar_hrd +#define	arp_pro	ea_hdr.ar_pro +#define	arp_hln	ea_hdr.ar_hln +#define	arp_pln	ea_hdr.ar_pln +#define	arp_op	ea_hdr.ar_op + +/* + * Structure shared between the ethernet driver modules and + * the address resolution code.  For example, each ec_softc or il_softc + * begins with this structure. + */ +struct	arpcom { +	struct	 ifnet ac_if;			/* network-visible interface */ +	u_int8_t ac_enaddr[ETHER_ADDR_LEN];	/* ethernet hardware address */ +	char	 ac__pad[2];			/* be nice to m68k ports */ +	LIST_HEAD(, ether_multi) ac_multiaddrs;	/* list of ether multicast addrs */ +	int	 ac_multicnt;			/* length of ac_multiaddrs list */ +}; + +struct llinfo_arp { +	LIST_ENTRY(llinfo_arp) la_list; +	struct	rtentry *la_rt; +	struct	mbuf *la_hold;		/* last packet until resolved/timeout */ +	long	la_asked;		/* last time we QUERIED for this addr */ +#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */ +}; + +struct sockaddr_inarp { +	u_int8_t  sin_len; +	u_int8_t  sin_family; +	u_int16_t sin_port; +	struct	  in_addr sin_addr; +	struct	  in_addr sin_srcaddr; +	u_int16_t sin_tos; +	u_int16_t sin_other; +#define SIN_PROXY 1 +}; + +/* + * IP and ethernet specific routing flags + */ +#define	RTF_USETRAILERS	RTF_PROTO1	/* use trailers */ +#define	RTF_ANNOUNCE	RTF_PROTO2	/* announce new arp entry */ + +#ifdef	_KERNEL +u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN]; +u_int8_t ether_ipmulticast_min[ETHER_ADDR_LEN]; +u_int8_t ether_ipmulticast_max[ETHER_ADDR_LEN]; +struct	ifqueue arpintrq; + +void	arpwhohas(struct arpcom *, struct in_addr *); +void	arpintr(void); +int	arpresolve(struct arpcom *, +	    struct rtentry *, struct mbuf *, struct sockaddr *, u_char *); +void	arp_ifinit(struct arpcom *, struct ifaddr *); +void	arp_rtrequest(int, struct rtentry *, struct sockaddr *); + +int	ether_addmulti(struct ifreq *, struct arpcom *); +int	ether_delmulti(struct ifreq *, struct arpcom *); +#endif /* _KERNEL */ + +/* + * Ethernet multicast address structure.  There is one of these for each + * multicast address or range of multicast addresses that we are supposed + * to listen to on a particular interface.  They are kept in a linked list, + * rooted in the interface's arpcom structure.  (This really has nothing to + * do with ARP, or with the Internet address family, but this appears to be + * the minimally-disrupting place to put it.) + */ +struct ether_multi { +	u_int8_t enm_addrlo[ETHER_ADDR_LEN]; /* low  or only address of range */ +	u_int8_t enm_addrhi[ETHER_ADDR_LEN]; /* high or only address of range */ +	struct	 arpcom *enm_ac;	/* back pointer to arpcom */ +	u_int	 enm_refcount;		/* no. claims to this addr/range */ +	LIST_ENTRY(ether_multi) enm_list; +}; + +/* + * Structure used by macros below to remember position when stepping through + * all of the ether_multi records. + */ +struct ether_multistep { +	struct ether_multi  *e_enm; +}; + +/* + * Macro for looking up the ether_multi record for a given range of Ethernet + * multicast addresses connected to a given arpcom structure.  If no matching + * record is found, "enm" returns NULL. + */ +#define ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm)			\ +	/* u_int8_t addrlo[ETHER_ADDR_LEN]; */				\ +	/* u_int8_t addrhi[ETHER_ADDR_LEN]; */				\ +	/* struct arpcom *ac; */					\ +	/* struct ether_multi *enm; */					\ +{									\ +	for ((enm) = (ac)->ac_multiaddrs.lh_first;			\ +	    (enm) != NULL &&						\ +	    (bcmp((enm)->enm_addrlo, (addrlo), ETHER_ADDR_LEN) != 0 ||	\ +	     bcmp((enm)->enm_addrhi, (addrhi), ETHER_ADDR_LEN) != 0);	\ +		(enm) = (enm)->enm_list.le_next);			\ +} + +/* + * Macro to step through all of the ether_multi records, one at a time. + * The current position is remembered in "step", which the caller must + * provide.  ETHER_FIRST_MULTI(), below, must be called to initialize "step" + * and get the first record.  Both macros return a NULL "enm" when there + * are no remaining records. + */ +#define ETHER_NEXT_MULTI(step, enm) \ +	/* struct ether_multistep step; */  \ +	/* struct ether_multi *enm; */  \ +{ \ +	if (((enm) = (step).e_enm) != NULL) \ +		(step).e_enm = (enm)->enm_list.le_next; \ +} + +#define ETHER_FIRST_MULTI(step, ac, enm) \ +	/* struct ether_multistep step; */ \ +	/* struct arpcom *ac; */ \ +	/* struct ether_multi *enm; */ \ +{ \ +	(step).e_enm = (ac)->ac_multiaddrs.lh_first; \ +	ETHER_NEXT_MULTI((step), (enm)); \ +} + +#ifdef _KERNEL +void arp_rtrequest(int, struct rtentry *, struct sockaddr *); +int arpresolve(struct arpcom *, struct rtentry *, struct mbuf *, +		    struct sockaddr *, u_char *); +void arpintr(void); +int arpioctl(u_long, caddr_t); +void arp_ifinit(struct arpcom *, struct ifaddr *); +void revarpinput(struct mbuf *); +void in_revarpinput(struct mbuf *); +void revarprequest(struct ifnet *); +int revarpwhoarewe(struct ifnet *, struct in_addr *, struct in_addr *); +int revarpwhoami(struct in_addr *, struct ifnet *); +int db_show_arptab(void); +#endif + +/* + * Prototype ethers(3) functions. + */ +#ifndef _KERNEL +#include <sys/cdefs.h> +__BEGIN_DECLS +char *	ether_ntoa(struct ether_addr *); +struct ether_addr * +	ether_aton(char *); +int	ether_ntohost(char *, struct ether_addr *); +int	ether_hostton(char *, struct ether_addr *); +int	ether_line(char *, struct ether_addr *, char *); +__END_DECLS +#endif diff --git a/lib/libstand/in_cksum.c b/lib/libstand/in_cksum.c new file mode 100644 index 000000000000..d9b8964c62c3 --- /dev/null +++ b/lib/libstand/in_cksum.c @@ -0,0 +1,83 @@ +/*	$NetBSD: in_cksum.c,v 1.3 1995/04/22 13:53:48 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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: in_cksum.c,v 1.1 92/09/11 01:15:55 leres Exp  (LBL) + */ + +#include <sys/types.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) +	register void *p; +	register int len; +{ +	register int sum = 0, oddbyte = 0, v = 0; +	register 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) { +				sum += *cp++ << 8; +				sum += *cp++; +			} +		} +		if ((oddbyte = len & 1) != 0) +			v = *cp << 8; +	} +	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/lib/libstand/ioctl.c b/lib/libstand/ioctl.c new file mode 100644 index 000000000000..1b0f353f8996 --- /dev/null +++ b/lib/libstand/ioctl.c @@ -0,0 +1,89 @@ +/*	$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. 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. + * + *	@(#)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 "stand.h" + +int +ioctl(fd, cmd, arg) +	int fd; +	u_long cmd; +	char *arg; +{ +	register 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/lib/libstand/iodesc.h b/lib/libstand/iodesc.h new file mode 100644 index 000000000000..690c65bae18d --- /dev/null +++ b/lib/libstand/iodesc.h @@ -0,0 +1,54 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + */ + +#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/lib/libstand/libstand.3 b/lib/libstand/libstand.3 new file mode 100644 index 000000000000..4d4b287b3583 --- /dev/null +++ b/lib/libstand/libstand.3 @@ -0,0 +1,456 @@ +.\" 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 Ohttp://wafu.netgate.net/tama/unix/indexe.htmlTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\"	$Id$ +.\" +.Dd June 22, 1998 +.Dt LIBSTAND 3 +.Os FreeBSD 3.0 +.Sh NAME +.Nm libstand +.Nd support library for standalone executables +.Sh SYNOPSIS +.Fd #include <stand.h> +.Sh DESCRIPTION +.Nm +provides a set of supporting functions for standalone +applications, mimicking where possible the standard BSD 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 Fn "void *malloc" "size_t size" +.Pp +Allocate +.Fa size +bytes of memory from the heap using a best-fit algorithm. +.It Fn "void free" "void *ptr" +.Pp +Free the allocated object at +.Fa ptr . +.It Fn "void setheap" "void *start" "void *limit" +.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 Fn "char *sbrk" "int junk" +.Pp +Provides the behaviour of +.Fn sbrk 0 , +ie. 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 evironment.  Major enhancements are support +for set/unset hook functions. +.Bl -hang -width 10n +.It Fn "char *getenv" "const char *name" +.It Fn "int setenv" "const char *name" "char *value" "int overwrite" +.It Fn "int putenv" "const char *string" +.It Fn "int unsetenv" "const char *name" +.Pp +These functions behave similarly to their standard library counterparts. +.It Fn "struct env_var *env_getenv" "const char *name" +.Pp +Looks up a variable in the environment and returns its entire  +data structure. +.It Fn "int env_setenv" "const char *name" "int flags" "char *value" "ev_sethook_t sethook" "ev_unsethook_t unsethook" +.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 Fn "int getopt" "int argc" "char * const *argv" "cont char *optstring" +.It Fn "long strtol" "const char *nptr" "char **endptr" "int base" +.It Fn "void srandom" "unsigned long seed" +.It Fn "unsigned long random" "void" +.It Fn "char *strerror" "int error" +.Pp +Returns error messages for the subset of errno values supported by +.Nm No . +.El +.Sh CHARACTER I/O +.Bl -hang -width 10n +.It Fn "void gets" "char *buf" +.Pp +Read characters from the console into +.Fa buf . +All of the standard cautions apply to this function. +.It Fn "void ngets" "char *buf" "size_t size" +.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 Fn "int fgetstr" "char *buf" "int size" "int fd" +.Pp +Read a line of at most +.Fa size +characters into +.Fa buf . +Line terminating characters are stripped, and the buffer is always nul +terminated.  Returns the number of characters in +.Fa buf +if successful, or -1 if a read error occurs. +.It Fn "int printf" "const char *fmt" "..." +.It Fn "void vprintf" "const char *fmt" "va_list ap" +.It Fn "int sprintf" "char *buf" "const char *fmt" "..." +.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: +.Pp +.Bd -offset indent +printf(  +.Qq reg=%b\en ,  +regval,  +.Qq <base><arg>* +); +.Ed + +where <base> is the output expressed as a control character, eg. \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 +.Pp +.Bd -offset indent +printf( +.Qq reg=%b\en +3 +.Qq \e10\e2BITTWO\e1BITONE\en +); +.Ed + +would give the output +.Pp +.Bd -offset indent +reg=3<BITTWO,BITONE> +.Ed +.Pp +The +.Li D +conversion provides a hexdump facility, eg. +.Pp +.Bd -offset indent -literal +printf( +.Qq %6D , +ptr, +.Qq \: +);  gives   +.Qq XX:XX:XX:XX:XX:XX +.Ed +.Bd -offset indent -literal +printf( +.Qq %*D , +len, +ptr, +.Qq "\ " +);  gives   +.Qq XX XX XX ... +.Ed +.El +.Sh CHARACTER TESTS AND CONVERSIONS +.Bl -hang -width 10n +.It Fn "int isupper" "int c" +.It Fn "int islower" "int c" +.It Fn "int isspace" "int c" +.It Fn "int isdigit" "int c" +.It Fn "int isxdigit" "int c" +.It Fn "int isascii" "int c" +.It Fn "int isalpha" "int c" +.It Fn "int toupper" "int c" +.It Fn "int tolower" "int c" +.El +.Sh FILE I/O +.Bl -hang -width 10n +.It Fn "int open" "const char *path" "int flags" +.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 filesystems +currently support writing). +.It Fn "int close" "int fd" +.It Fn "void closeall" "void" +.Pp +Close all open files. +.It Fn "ssize_t read" "int fd" "void *buf" "size_t len" +.It Fn "ssize_t write" "int fd" "void *buf" "size_t len" +.Pp +(No filesystems currently support writing.) +.It Fn "off_t lseek" "int fd" "off_t offset" "int whence" +.Pp +Files being automatically uncompressed during reading cannot seek backwards +from the current point. +.It Fn "int stat" "const char *path" "struct stat *sb" +.It Fn "int fstat" "int fd" "struct stat *sb" +.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 +filesystem cannot provide meaningful values for this call, and the  +.Nm cd9660 +filesystem always reports files having uid/gid of zero. +.El +.Sh PAGER +.Nm +supplies a simple internal pager to ease reading the output of large commands. +.Bl -hang -width 10n +.It Fn "void pager_open" +.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 Fn "void pager_close" "void" +.Pp +Closes the pager. +.It Fn "void pager_output" "char *lines" +.Pp +Sends the lines in the nul-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). +.Fn pager_output +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 Fn "int pager_file" "char *fname" +.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 Fn "void twiddle" "void" +.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 filesystems 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 Fn "int getchar" "void" +.Pp +Return a character from the console, used by +.Fn gets , +.Fn ngets +and pager functions. +.It Fn "int ischar" "void" +.Pp +Returns nonzero if a character is waiting from the console. +.It Fn "void putchar" "int" +.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 Fn "int devopen" "struct open_file *of" "const char *name" "char **file" +.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 +.Dv 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 Fn "int devclose" "struct open_file *of" +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 Fn "void panic" "const char *msg" "..." +.Pp +Signal a fatal and unrecoverable error condition.  The +.Fa msg ... +arguments are as for +.Fn printf . +.El +.Sh INTERNAL FILESYSTEMS +Internal filesystems are enabled by the consumer exporting the array +.Dv struct fs_ops *file_system[], which should be initialised with pointers +to +.Dv struct fs_ops +structures.  The following filesystem handlers are supplied by +.Nm No , +the consumer may supply other filesystems of their own: +.Bl -hang -width "cd9660_fsops " +.It ufs_fsops +The BSD UFS. +.It tftp_fsops +File access via TFTP. +.It nfs_fsops +File access via NFS. +.It cd9660_fsops +ISO 9660 (CD-ROM) filesystem. +.It zipfs_fsops +Stacked filesystem supporting gzipped files. When trying the zipfs filesystem, +.Nm +appends +.Li .gz +to the end of the filename, and then tries to locate the file using the other +filesystems.  Placement of this filesystem in the +.Dv 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. +.El +.Pp +The array of +.Dv struct fs_ops +pointers should be terminated with a NULL. +.Sh DEVICES +Devices are exported by the supporting code via the array +.Dv struct devsw *devsw[] +which is a NULL terminated array of pointers to device switch structures. +.Sh BUGS +.Pp +The lack of detailed memory usage data is unhelpful. +.Sh HISTORY +.Nm +contains contributions from many sources, including: +.Bl -bullet -compact +.It  +.Nm libsa +from +.Nx +.It +.Nm libc +and +.Nm libkern +from +.Fx 3.0 . +.El +.Pp +The reorganisation and port to +.Fx 3.0 , +the environment functions and this manpage were written by +.An Mike Smith Aq msmith@freebsd.org . diff --git a/lib/libstand/lseek.c b/lib/libstand/lseek.c new file mode 100644 index 000000000000..089491292756 --- /dev/null +++ b/lib/libstand/lseek.c @@ -0,0 +1,102 @@ +/*	$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. 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. + * + *	@(#)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 "stand.h" + +off_t +lseek(fd, offset, where) +	int fd; +	off_t offset; +	int where; +{ +	register 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; +		case SEEK_END: +		default: +			errno = EOFFSET; +			return (-1); +		} +		return (f->f_offset); +	} + +	return (f->f_ops->fo_seek)(f, offset, where); +} diff --git a/lib/libstand/net.c b/lib/libstand/net.c new file mode 100644 index 000000000000..978bd703e272 --- /dev/null +++ b/lib/libstand/net.c @@ -0,0 +1,503 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL) + */ + +#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 <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(d, pkt, len) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +{ +	register ssize_t cc; +	register struct ip *ip; +	register struct udphdr *uh; +	register u_char *ea; + +#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 + +	uh = (struct udphdr *)pkt - 1; +	ip = (struct ip *)uh - 1; +	len += sizeof(*ip) + sizeof(*uh); + +	bzero(ip, sizeof(*ip) + sizeof(*uh)); + +	ip->ip_v = IPVERSION;			/* half-char */ +	ip->ip_hl = sizeof(*ip) >> 2;		/* half-char */ +	ip->ip_len = htons(len); +	ip->ip_p = IPPROTO_UDP;			/* char */ +	ip->ip_ttl = IP_TTL;			/* char */ +	ip->ip_src = d->myip; +	ip->ip_dst = d->destip; +	ip->ip_sum = in_cksum(ip, sizeof(*ip));	 /* short, but special */ + +	uh->uh_sport = d->myport; +	uh->uh_dport = d->destport; +	uh->uh_ulen = htons(len - sizeof(*ip)); + +#ifndef UDP_NO_CKSUM +	{ +		register struct udpiphdr *ui; +		struct ip tip; + +		/* Calculate checksum (must save and restore ip header) */ +		tip = *ip; +		ui = (struct udpiphdr *)ip; +		bzero(&ui->ui_x1, sizeof(ui->ui_x1)); +		ui->ui_len = uh->uh_ulen; +		uh->uh_sum = in_cksum(ui, len); +		*ip = tip; +	} +#endif + +	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("sendudp: bad write (%d != %d)", cc, len); +	return (cc - (sizeof(*ip) + sizeof(*uh))); +} + +/* + * Receive a UDP packet and validate it is for us. + * Caller leaves room for the headers (Ether, IP, UDP) + */ +ssize_t +readudp(d, pkt, len, tleft) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +	time_t tleft; +{ +	register ssize_t n; +	register size_t hlen; +	register struct ip *ip; +	register struct udphdr *uh; +	u_int16_t etype;	/* host order */ + +#ifdef NET_DEBUG +	if (debug) +		printf("readudp: called\n"); +#endif + +	uh = (struct udphdr *)pkt - 1; +	ip = (struct ip *)uh - 1; + +	n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype); +	if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) +		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); +		} +		return -1; +	} + +	if (etype != ETHERTYPE_IP) { +#ifdef NET_DEBUG +		if (debug) +			printf("readudp: not IP. ether_type=%x\n", etype); +#endif +		return -1; +	} + +	/* Check ip header */ +	if (ip->ip_v != IPVERSION || +	    ip->ip_p != IPPROTO_UDP) {	/* half char */ +#ifdef NET_DEBUG +		if (debug) +			printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); +#endif +		return -1; +	} + +	hlen = ip->ip_hl << 2; +	if (hlen < sizeof(*ip) || +	    in_cksum(ip, hlen) != 0) { +#ifdef NET_DEBUG +		if (debug) +			printf("readudp: short hdr or bad cksum.\n"); +#endif +		return -1; +	} +	if (n < ntohs(ip->ip_len)) { +#ifdef NET_DEBUG +		if (debug) +			printf("readudp: bad length %d < %d.\n", +			       (int)n, ntohs(ip->ip_len)); +#endif +		return -1; +	} +	if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { +#ifdef NET_DEBUG +		if (debug) { +			printf("readudp: bad saddr %s != ", inet_ntoa(d->myip)); +			printf("%s\n", inet_ntoa(ip->ip_dst)); +		} +#endif +		return -1; +	} + +	/* If there were ip options, make them go away */ +	if (hlen != sizeof(*ip)) { +		bcopy(((u_char *)ip) + hlen, uh, len - hlen); +		ip->ip_len = htons(sizeof(*ip)); +		n -= hlen - sizeof(*ip); +	} +	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 +		return -1; +	} + +#ifndef UDP_NO_CKSUM +	if (uh->uh_sum) { +		register struct udpiphdr *ui; +		struct ip tip; + +		n = ntohs(uh->uh_ulen) + sizeof(*ip); +		if (n > RECV_SIZE - ETHER_SIZE) { +			printf("readudp: huge packet, udp len %d\n", (int)n); +			return -1; +		} + +		/* Check checksum (must save and restore ip header) */ +		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 +			*ip = tip; +			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 +		return -1; +	} + +	n -= sizeof(*ip) + sizeof(*uh); +	return (n); +} + +/* + * 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(d, sproc, sbuf, ssize, rproc, rbuf, rsize) +	register struct iodesc *d; +	register ssize_t (*sproc)(struct iodesc *, void *, size_t); +	register void *sbuf; +	register size_t ssize; +	register ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t); +	register void *rbuf; +	register size_t rsize; +{ +	register ssize_t cc; +	register time_t t, tmo, tlast; +	long tleft; + +#ifdef NET_DEBUG +	if (debug) +		printf("sendrecv: called\n"); +#endif + +	tmo = MINTMO; +	tlast = 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! (%d < %d)", +				    cc, ssize); + +			tleft = tmo; +			tmo <<= 1; +			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, rbuf, rsize, 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(cp) +	char *cp; +{ +	register u_long val; +	register int n; +	register char c; +	u_int parts[4]; +	register 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(ia) +	struct in_addr ia; +{ +	return (intoa(ia.s_addr)); +} + +/* Similar to inet_ntoa() */ +char * +intoa(addr) +	register n_long addr; +{ +	register char *cp; +	register u_int byte; +	register int n; +	static char buf[17];	/* strlen(".255.255.255.255") + 1 */ + +	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(s, n) +	char *s; +	int *n; +{ +	for (*n = 0; isdigit(*s); s++) +		*n = (*n * 10) + *s - '0'; +	return s; +} + +n_long +ip_convertaddr(p) +	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/lib/libstand/net.h b/lib/libstand/net.h new file mode 100644 index 000000000000..6f6d4435e657 --- /dev/null +++ b/lib/libstand/net.h @@ -0,0 +1,122 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + */ + +#define NETIF_DEBUG 1 + +#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 } + +/* 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 20	/* 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	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	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 *d, void *pkt, size_t len, +			time_t tleft, u_int16_t *etype); + +ssize_t	sendudp(struct iodesc *, void *, size_t); +ssize_t	readudp(struct iodesc *, void *, size_t, time_t); +ssize_t	sendrecv(struct iodesc *, +		      ssize_t (*)(struct iodesc *, void *, size_t), +			void *, size_t, +		        ssize_t (*)(struct iodesc *, void *, size_t, time_t), +			void *, size_t); + +/* 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); diff --git a/lib/libstand/netif.c b/lib/libstand/netif.c new file mode 100644 index 000000000000..bc1b7bd1f556 --- /dev/null +++ b/lib/libstand/netif.c @@ -0,0 +1,332 @@ +/*	$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/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() +{ +	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(nif, machdep_hint) +	struct netif *nif; +	void *machdep_hint; +{ +	struct netif_driver *drv = nif->nif_driver; + +#if 0 +	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(machdep_hint) +	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(nif, machdep_hint) +	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(nif, desc, machdep_hint) +	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(nif) +	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(desc, pkt, len, timo) +	struct iodesc *desc; +	void *pkt; +	size_t len; +	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, len, 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(desc, pkt, len) +	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(sock) +	int sock; +{ +	if (sock >= SOPEN_MAX) { +		errno = EBADF; +		return (NULL); +	} +	return (&sockets[sock]); +} + +int +netif_open(machdep_hint) +	void *machdep_hint; +{ +	int fd; +	register 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(sock) +	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/lib/libstand/netif.h b/lib/libstand/netif.h new file mode 100644 index 000000000000..06093103fa05 --- /dev/null +++ b/lib/libstand/netif.h @@ -0,0 +1,65 @@ +/*	$NetBSD: netif.h,v 1.4 1995/09/14 23:45:30 pk Exp $	*/ + +#ifndef __SYS_LIBNETBOOT_NETIF_H +#define __SYS_LIBNETBOOT_NETIF_H +#include "iodesc.h" + +#define NENTS(x)	sizeof(x)/sizeof(x[0]) + +struct netif_driver { +	char	*netif_bname; +	int	(*netif_match)(struct netif *, void *); +	int	(*netif_probe)(struct netif *, void *); +	void	(*netif_init)(struct iodesc *, void *); +	int	(*netif_get)(struct iodesc *, void *, size_t, time_t); +	int	(*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 *, size_t, 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/lib/libstand/nfs.c b/lib/libstand/nfs.c new file mode 100644 index 000000000000..46e27fab6548 --- /dev/null +++ b/lib/libstand/nfs.c @@ -0,0 +1,653 @@ +/*	$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/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <string.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 "nfs.h" +#include "rpc.h" + +#define NFS_DEBUGxx + +/* Define our own NFS attributes without NQNFS stuff. */ +struct nfsv2_fattrs { +	n_long	fa_type; +	n_long	fa_mode; +	n_long	fa_nlink; +	n_long	fa_uid; +	n_long	fa_gid; +	n_long	fa_size; +	n_long	fa_blocksize; +	n_long	fa_rdev; +	n_long	fa_blocks; +	n_long	fa_fsid; +	n_long	fa_fileid; +	struct nfsv2_time fa_atime; +	struct nfsv2_time fa_mtime; +	struct nfsv2_time fa_ctime; +}; + + +struct nfs_read_args { +	u_char	fh[NFS_FHSIZE]; +	n_long	off; +	n_long	len; +	n_long	xxx;			/* XXX what's this for? */ +}; + +/* Data part of nfs rpc reply (also the largest thing we receive) */ +#define NFSREAD_SIZE 1024 +struct nfs_read_repl { +	n_long	errno; +	struct	nfsv2_fattrs fa; +	n_long	count; +	u_char	data[NFSREAD_SIZE]; +}; + +#ifndef NFS_NOSYMLINK +struct nfs_readlnk_repl { +	n_long	errno; +	n_long	len; +	char	path[NFS_MAXPATHLEN]; +}; +#endif + +struct nfs_iodesc { +	struct	iodesc	*iodesc; +	off_t	off; +	u_char	fh[NFS_FHSIZE]; +	struct nfsv2_fattrs fa;	/* all in network order */ +}; + +/* + * XXX interactions with tftp? See nfswrapper.c for a confusing + *     issue. + */ +int		nfs_open(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); + +struct fs_ops nfs_fsops = { +	"nfs", nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat +}; + + +/* + * Fetch the root file handle (call mount daemon) + * Return zero or error number. + */ +int +nfs_getrootfh(d, path, fhp) +	register struct iodesc *d; +	char *path; +	u_char *fhp; +{ +	register int len; +	struct args { +		n_long	len; +		char	path[FNAME_SIZE]; +	} *args; +	struct repl { +		n_long	errno; +		u_char	fh[NFS_FHSIZE]; +	} *repl; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct args d; +	} sdata; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct repl d; +	} rdata; +	size_t cc; +	 +#ifdef NFS_DEBUG +	if (debug) +		printf("nfs_getrootfh: %s\n", path); +#endif + +	args = &sdata.d; +	repl = &rdata.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 = 4 + roundup(len, 4); + +	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, +	    args, len, repl, sizeof(*repl)); +	if (cc == -1) { +		/* errno was set by rpc_call */ +		return (errno); +	} +	if (cc < 4) +		return (EBADRPC); +	if (repl->errno) +		return (ntohl(repl->errno)); +	bcopy(repl->fh, fhp, sizeof(repl->fh)); +	return (0); +} + +/* + * Lookup a file.  Store handle and attributes. + * Return zero or error number. + */ +int +nfs_lookupfh(d, name, newfd) +	struct nfs_iodesc *d; +	char *name; +	struct nfs_iodesc *newfd; +{ +	register int len, rlen; +	struct args { +		u_char	fh[NFS_FHSIZE]; +		n_long	len; +		char	name[FNAME_SIZE]; +	} *args; +	struct repl { +		n_long	errno; +		u_char	fh[NFS_FHSIZE]; +		struct	nfsv2_fattrs fa; +	} *repl; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct args d; +	} sdata; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct repl d; +	} rdata; +	ssize_t cc; +	 +#ifdef NFS_DEBUG +	if (debug) +		printf("lookupfh: called\n"); +#endif + +	args = &sdata.d; +	repl = &rdata.d; + +	bzero(args, sizeof(*args)); +	bcopy(d->fh, args->fh, sizeof(args->fh)); +	len = strlen(name); +	if (len > sizeof(args->name)) +		len = sizeof(args->name); +	bcopy(name, args->name, len); +	args->len = htonl(len); +	len = 4 + roundup(len, 4); +	len += NFS_FHSIZE; + +	rlen = sizeof(*repl); + +	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, +	    args, len, repl, rlen); +	if (cc == -1) +		return (errno);		/* XXX - from rpc_call */ +	if (cc < 4) +		return (EIO); +	if (repl->errno) { +		/* saerrno.h now matches NFS error numbers. */ +		return (ntohl(repl->errno)); +	} +	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); +	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); +	return (0); +} + +#ifndef NFS_NOSYMLINK +/* + * Get the destination of a symbolic link. + */ +int +nfs_readlink(d, buf) +	struct nfs_iodesc *d; +	char *buf; +{ +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		u_char fh[NFS_FHSIZE]; +	} sdata; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct nfs_readlnk_repl d; +	} rdata; +	ssize_t cc; + +#ifdef NFS_DEBUG +	if (debug) +		printf("readlink: called\n"); +#endif + +	bcopy(d->fh, sdata.fh, NFS_FHSIZE); +	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, +		      sdata.fh, NFS_FHSIZE, +		      &rdata.d, sizeof(rdata.d)); +	if (cc == -1) +		return (errno); + +	if (cc < 4) +		return (EIO); +	 +	if (rdata.d.errno) +		return (ntohl(rdata.d.errno)); + +	rdata.d.len = ntohl(rdata.d.len); +	if (rdata.d.len > NFS_MAXPATHLEN) +		return (ENAMETOOLONG); + +	bcopy(rdata.d.path, buf, rdata.d.len); +	buf[rdata.d.len] = 0; +	return (0); +} +#endif + +/* + * Read data from a file. + * Return transfer count or -1 (and set errno) + */ +ssize_t +nfs_readdata(d, off, addr, len) +	struct nfs_iodesc *d; +	off_t off; +	void *addr; +	size_t len; +{ +	struct nfs_read_args *args; +	struct nfs_read_repl *repl; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct nfs_read_args d; +	} sdata; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct nfs_read_repl d; +	} rdata; +	size_t cc; +	long x; +	int hlen, rlen; + +	args = &sdata.d; +	repl = &rdata.d; + +	bcopy(d->fh, args->fh, NFS_FHSIZE); +	args->off = htonl((n_long)off); +	if (len > NFSREAD_SIZE) +		len = NFSREAD_SIZE; +	args->len = htonl((n_long)len); +	args->xxx = htonl((n_long)0); +	hlen = sizeof(*repl) - NFSREAD_SIZE; + +	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, +	    args, sizeof(*args), +	    repl, sizeof(*repl)); +	if (cc == -1) { +		/* errno was already set by rpc_call */ +		return (-1); +	} +	if (cc < hlen) { +		errno = EBADRPC; +		return (-1); +	} +	if (repl->errno) { +		errno = ntohl(repl->errno); +		return (-1); +	} +	rlen = cc - hlen; +	x = ntohl(repl->count); +	if (rlen < x) { +		printf("nfsread: short packet, %d < %ld\n", rlen, x); +		errno = EBADRPC; +		return(-1); +	} +	bcopy(repl->data, addr, x); +	return (x); +} + +/* + * Open a file. + * return zero or error number + */ +int +nfs_open(path, f) +	char *path; +	struct open_file *f; +{ +	static struct nfs_iodesc nfs_root_node; +	struct iodesc *desc; +	struct nfs_iodesc *currfd; +#ifndef NFS_NOSYMLINK +	struct nfs_iodesc *newfd; +	struct nfsv2_fattrs *fa; +	register char *cp, *ncp; +	register int c; +	char namebuf[NFS_MAXPATHLEN + 1]; +	char linkbuf[NFS_MAXPATHLEN + 1]; +	int nlinks = 0; +#endif +	int error; + +#ifdef NFS_DEBUG + 	if (debug) + 	    printf("nfs_open: %s (rootpath=%s)\n", path, rootpath); +#endif +	if (!rootpath[0]) { +		printf("no rootpath, no nfs\n"); +		return (ENXIO); +	} + +	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.fh))) +		return (error); +	nfs_root_node.iodesc = desc; + +#ifndef NFS_NOSYMLINK +	/* Fake up attributes for the root dir. */ +	fa = &nfs_root_node.fa; +	fa->fa_type  = htonl(NFDIR); +	fa->fa_mode  = htonl(0755); +	fa->fa_nlink = htonl(2); + +	currfd = &nfs_root_node; +	newfd = 0; + +	cp = path; +	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)); +		newfd->iodesc = currfd->iodesc; +		newfd->off = 0; +	 +		/* +		 * Get next component of path name. +		 */ +		{ +			register 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 == '/') { +				if (currfd != &nfs_root_node) +					free(currfd); +				currfd = &nfs_root_node; +			} + +			free(newfd); +			newfd = 0; +			 +			continue; +		} +		 +		if (currfd != &nfs_root_node) +			free(currfd); +		currfd = newfd; +		newfd = 0; +	} + +	error = 0; + +out: +	if (newfd) +		free(newfd); +#else +        /* allocate file system specific data structure */ +        currfd = malloc(sizeof(*currfd)); +        currfd->iodesc = desc; +        currfd->off = 0; + +        error = nfs_lookupfh(&nfs_root_node, path, currfd); +#endif +	if (!error) { +		f->f_fsdata = (void *)currfd; +		return (0); +	} +		 +#ifdef NFS_DEBUG +	if (debug) +		printf("nfs_open: %s lookupfh failed: %s\n", +		    path, strerror(error)); +#endif +#ifndef NFS_NOSYMLINK +	if (currfd != &nfs_root_node) +#endif +		free(currfd); + +	return (error); +} + +int +nfs_close(f) +	struct open_file *f; +{ +	register 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 + +	if (fp) +		free(fp); +	f->f_fsdata = (void *)0; +	 +	return (0); +} + +/* + * read a portion of a file + */ +int +nfs_read(f, buf, size, resid) +	struct open_file *f; +	void *buf; +	size_t size; +	size_t *resid;	/* out */ +{ +	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; +	register ssize_t cc; +	register 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(); +		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(f, buf, size, resid) +	struct open_file *f; +	void *buf; +	size_t size; +	size_t *resid;	/* out */ +{ +	return (EROFS); +} + +off_t +nfs_seek(f, offset, where) +	struct open_file *f; +	off_t offset; +	int where; +{ +	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; +	n_long size = ntohl(d->fa.fa_size); + +	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: +		return (-1); +	} + +	return (d->off); +} + +/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ +int nfs_stat_types[8] = { +	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; + +int +nfs_stat(f, sb) +	struct open_file *f; +	struct stat *sb; +{ +	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; +	register n_long 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); + +	return (0); +} diff --git a/lib/libstand/nfs.h b/lib/libstand/nfs.h new file mode 100644 index 000000000000..667e93e32134 --- /dev/null +++ b/lib/libstand/nfs.h @@ -0,0 +1,37 @@ +/*	$NetBSD: nfs.h,v 1.5 1996/07/10 18:32:33 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. 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. + */ + +extern int	nfs_open(char *path, struct open_file *f);	/* XXX for nfswrapper */ + diff --git a/lib/libstand/nfsv2.h b/lib/libstand/nfsv2.h new file mode 100644 index 000000000000..1d7d9d4c8f91 --- /dev/null +++ b/lib/libstand/nfsv2.h @@ -0,0 +1,166 @@ +/*	$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. 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. + * + *	@(#)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 */ + +/* 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; + +/* Structs for common parts of the rpc's */ +struct nfsv2_time { +	n_long	nfs_sec; +	n_long	nfs_usec; +}; + +/* + * File attributes and setable attributes. + */ +struct nfsv2_fattr { +	n_long	fa_type; +	n_long	fa_mode; +	n_long	fa_nlink; +	n_long	fa_uid; +	n_long	fa_gid; +	n_long	fa_size; +	n_long	fa_blocksize; +	n_long	fa_rdev; +	n_long	fa_blocks; +	n_long	fa_fsid; +	n_long	fa_fileid; +	struct nfsv2_time fa_atime; +	struct nfsv2_time fa_mtime; +	struct nfsv2_time fa_ctime; +}; + +struct nfsv2_sattr { +	n_long	sa_mode; +	n_long	sa_uid; +	n_long	sa_gid; +	n_long	sa_size; +	struct nfsv2_time sa_atime; +	struct nfsv2_time sa_mtime; +}; + +struct nfsv2_statfs { +	n_long	sf_tsize; +	n_long	sf_bsize; +	n_long	sf_blocks; +	n_long	sf_bfree; +	n_long	sf_bavail; +}; diff --git a/lib/libstand/nullfs.c b/lib/libstand/nullfs.c new file mode 100644 index 000000000000..dff6e15ba871 --- /dev/null +++ b/lib/libstand/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. 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. + * + *	@(#)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 "stand.h" + +/* + * Null filesystem + */ +int	null_open (char *path, struct open_file *f) +{ +	errno  = EIO; +	return -1; +} + +int	null_close(struct open_file *f) +{ +	return 0; +} + +ssize_t	null_read (struct open_file *f, void *buf, size_t size, size_t *resid) +{ +	errno = EIO; +	return -1; +} + +ssize_t	null_write (struct open_file *f, void *buf, size_t size, size_t *resid) +{ +	errno = EIO; +	return -1; +} + +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) +{ +	errno = EIO; +	return -1; +} diff --git a/lib/libstand/open.c b/lib/libstand/open.c new file mode 100644 index 000000000000..a3df60a02c51 --- /dev/null +++ b/lib/libstand/open.c @@ -0,0 +1,137 @@ +/*	$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. 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. + * + *	@(#)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 "stand.h" + +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); +} + + +int +open(const char *fname, int mode) +{ +    struct open_file	*f; +    int			fd, i, error, besterror; +    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; +    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; +	return (fd); +    } + +    /* pass file name to the different filesystem open routines */ +    besterror = ENOENT; +    for (i = 0; file_system[i] != NULL; i++) { + +	error = ((*file_system[i]).fo_open)(file, f); +	if (error == 0) { +	     +	    f->f_ops = file_system[i]; +	    return (fd); +	} +	if (error != EINVAL) +	    besterror = error; +    } +    error = besterror; + +    if ((f->f_flags & F_NODEV) == 0) +	f->f_dev->dv_close(f); +    if (error) +	devclose(f); + + err: +    f->f_flags = 0; +    errno = error; +    return (-1); +} diff --git a/lib/libstand/pager.c b/lib/libstand/pager.c new file mode 100644 index 000000000000..773a82eb95c7 --- /dev/null +++ b/lib/libstand/pager.c @@ -0,0 +1,162 @@ +/*- + * 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. + * + *	$Id$ + */ +/* + * Simple paged-output and paged-viewing functions + */ + +#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(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(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); +    } + +    pager_open(); +    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; +	} +    } +    pager_close(); +    close(fd); +    return(result); +} diff --git a/lib/libstand/printf.c b/lib/libstand/printf.c new file mode 100644 index 000000000000..8c7b38477a7e --- /dev/null +++ b/lib/libstand/printf.c @@ -0,0 +1,355 @@ +/*- + * 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. 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. + * + *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94 + * $Id: subr_prf.c,v 1.46 1998/05/28 09:30:20 phk Exp $ + */ + +/* + * Standaloneified version of the FreeBSD kernel printf family. + */ + +#include <sys/types.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> + +static char	*ksprintn (u_long num, int base, int *len); +static int	kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); + +int +printf(const char *fmt, ...) +{ +	va_list ap; +	int retval; + +	va_start(ap, fmt); +	retval = kvprintf(fmt, putchar, NULL, 10, ap); +	va_end(ap); +	return retval; +} + +void +vprintf(const char *fmt, va_list ap) +{ + +	kvprintf(fmt, putchar, NULL, 10, ap); +} + +/* + * Scaled down version of sprintf(3). + */ +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; +} + +/* + * Put a number (base <= 16) in a buffer in reverse order; return an + * optional length and a pointer to the NULL terminated (preceded?) + * buffer. + */ +static char * +ksprintn(ul, base, lenp) +	register u_long ul; +	register int base, *lenp; +{					/* A long in base 8, plus NULL. */ +	static char buf[sizeof(long) * NBBY / 3 + 2]; +	register char *p; + +	p = buf; +	do { +		*++p = hex2ascii(ul % base); +	} while (ul /= base); +	if (lenp) +		*lenp = p - buf; +	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\n"); + * + * 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, void (*func)(int), void *arg, int radix, va_list ap) +{ +#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } +	char *p, *q, *d; +	u_char *up; +	int ch, n; +	u_long ul; +	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; +	int dwidth; +	char padc; +	int retval = 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++) != '%') { +			if (ch == '\0')  +				return retval; +			PCHAR(ch); +		} +		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; +		sign = 0; dot = 0; dwidth = 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': +			ul = va_arg(ap, int); +			p = va_arg(ap, char *); +			for (q = ksprintn(ul, *p++, NULL); *q;) +				PCHAR(*q--); + +			if (!ul) +				break; + +			for (tmp = 0; *p;) { +				n = *p++; +				if (ul & (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': +			ul = lflag ? va_arg(ap, long) : va_arg(ap, int); +			sign = 1; +			base = 10; +			goto number; +		case 'l': +			lflag = 1; +			goto reswitch; +		case 'n': +			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); +			base = radix; +			goto number; +		case 'o': +			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); +			base = 8; +			goto number; +		case 'p': +			ul = (u_long)va_arg(ap, void *); +			base = 16; +			sharpflag = 1; +			goto number; +		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 'u': +			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); +			base = 10; +			goto number; +		case 'x': +			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); +			base = 16; +number:			if (sign && (long)ul < 0L) { +				neg = 1; +				ul = -(long)ul; +			} +			p = ksprintn(ul, base, &tmp); +			if (sharpflag && ul != 0) { +				if (base == 8) +					tmp++; +				else if (base == 16) +					tmp += 2; +			} +			if (neg) +				tmp++; + +			if (!ladjust && width && (width -= tmp) > 0) +				while (width--) +					PCHAR(padc); +			if (neg) +				PCHAR('-'); +			if (sharpflag && ul != 0) { +				if (base == 8) { +					PCHAR('0'); +				} else if (base == 16) { +					PCHAR('0'); +					PCHAR('x'); +				} +			} + +			while (*p) +				PCHAR(*p--); + +			if (ladjust && width && (width -= tmp) > 0) +				while (width--) +					PCHAR(padc); + +			break; +		default: +			PCHAR('%'); +			if (lflag) +				PCHAR('l'); +			PCHAR(ch); +			break; +		} +	} +#undef PCHAR +} + diff --git a/lib/libstand/random.c b/lib/libstand/random.c new file mode 100644 index 000000000000..617398af142c --- /dev/null +++ b/lib/libstand/random.c @@ -0,0 +1,72 @@ +/*- + * 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. 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. + * + *	@(#)random.c	8.1 (Berkeley) 6/10/93 + * $Id: random.c,v 1.6 1997/02/22 09:39:59 peter Exp $ + */ + +#include <sys/libkern.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() +{ +	register 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/lib/libstand/rarp.c b/lib/libstand/rarp.c new file mode 100644 index 000000000000..898e4756aeda --- /dev/null +++ b/lib/libstand/rarp.c @@ -0,0 +1,225 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp  (LBL) + */ +#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 *, size_t, time_t); + +/* + * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). + */ +int +rarp_getipaddress(sock) +	int sock; +{ +	struct iodesc *d; +	register struct ether_arp *ap; +	struct { +		u_char header[ETHER_SIZE]; +		struct { +			struct ether_arp arp; +			u_char pad[18]; 	/* 60 - sizeof(arp) */ +		} data; +	} wbuf; +	struct { +		u_char header[ETHER_SIZE]; +		struct { +			struct ether_arp arp; +			u_char pad[24]; 	/* extra space */ +		} data; +	} rbuf; + +#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); + +	if (sendrecv(d, +	    rarpsend, &wbuf.data, sizeof(wbuf.data), +	    rarprecv, &rbuf.data, sizeof(rbuf.data)) < 0) +	{ +		printf("No response for RARP request\n"); +		return (-1); +	} + +	ap = &rbuf.data.arp; +	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 + +	/* 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(d, pkt, len) +	register struct iodesc *d; +	register void *pkt; +	register 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(d, pkt, len, tleft) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +	time_t tleft; +{ +	register ssize_t n; +	register struct ether_arp *ap; +	u_int16_t etype;	/* host order */ + +#ifdef RARP_DEBUG + 	if (debug) +		printf("rarprecv: "); +#endif + +	n = readether(d, pkt, len, 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 +		return (-1); +	} + +	if (etype != ETHERTYPE_REVARP) { +#ifdef RARP_DEBUG +		if (debug) +			printf("bad type=0x%x\n", etype); +#endif +		return (-1); +	} + +	ap = (struct ether_arp *)pkt; +	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 +		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 +		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 +		return (-1); +	} + +	/* We have our answer. */ +#ifdef RARP_DEBUG + 	if (debug) +		printf("got it\n"); +#endif +	return (n); +} diff --git a/lib/libstand/read.c b/lib/libstand/read.c new file mode 100644 index 000000000000..5b14a75f8339 --- /dev/null +++ b/lib/libstand/read.c @@ -0,0 +1,96 @@ +/*	$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. 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. + * + *	@(#)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/param.h> +#include "stand.h" + +ssize_t +read(fd, dest, bcount) +	int fd; +	void *dest; +	size_t bcount; +{ +	register 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(); +		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); +	} +	resid = bcount; +	if ((errno = (f->f_ops->fo_read)(f, dest, bcount, &resid))) +		return (-1); +	return (ssize_t)(bcount - resid); +} diff --git a/lib/libstand/rpc.c b/lib/libstand/rpc.c new file mode 100644 index 000000000000..9f0fa32764e4 --- /dev/null +++ b/lib/libstand/rpc.c @@ -0,0 +1,440 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + * + * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL) + */ + +/* + * 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 *, size_t, 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(d, prog, vers, proc, sdata, slen, rdata, rlen) +	register struct iodesc *d; +	register n_long prog, vers, proc; +	register void *sdata; +	register size_t slen; +	register void *rdata; +	register size_t rlen; +{ +	register ssize_t cc; +	struct auth_info *auth; +	struct rpc_call *call; +	struct rpc_reply *reply; +	char *send_head, *send_tail; +	char *recv_head, *recv_tail; +	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; + +#if 1 +	/* 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)); +#else +	/* Auth credentials: always auth_null (XXX OK?) */ +	send_head -= sizeof(*auth); +	auth = send_head; +	auth->authtype = htonl(RPCAUTH_NULL); +	auth->authlen = 0; +#endif + +	/* 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); + +	/* Make room for the rpc_reply header. */ +	recv_head = rdata; +	recv_tail = (char *)rdata + rlen; +	recv_head -= sizeof(*reply); + +	cc = sendrecv(d, +	    sendudp, send_head, send_tail - send_head, +	    recvrpc, recv_head, recv_tail - recv_head); + +#ifdef RPC_DEBUG +	if (debug) +		printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); +#endif +	if (cc == -1) +		return (-1); + +	if (cc <= sizeof(*reply)) { +		errno = EBADRPC; +		return (-1); +	} + +	recv_tail = recv_head + cc; + +	/* +	 * Check the RPC reply status. +	 * The xid, dir, astatus were already checked. +	 */ +	reply = (struct rpc_reply *)recv_head; +	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; +		return(-1); +	} +	x = ntohl(reply->rp_u.rpu_rok.rok_status); +	if (x != 0) { +		printf("callrpc: error = %ld\n", (long)x); +		errno = EBADRPC; +		return(-1); +	} +	recv_head += sizeof(*reply); + +	return (ssize_t)(recv_tail - recv_head); +} + +/* + * 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(d, pkt, len, tleft) +	register struct iodesc *d; +	register void *pkt; +	register size_t len; +	time_t tleft; +{ +	register struct rpc_reply *reply; +	ssize_t	n; +	int	x; + +	errno = 0; +#ifdef RPC_DEBUG +	if (debug) +		printf("recvrpc: called len=%lu\n", (u_long)len); +#endif + +	n = readudp(d, pkt, len, tleft); +	if (n <= (4 * 4)) +		return -1; + +	reply = (struct rpc_reply *)pkt; + +	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 +		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 +		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); +		return -1; +	} + +	/* 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(pkt, addr, port) +	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 */ +int +rpc_pmap_getcache(addr, prog, vers) +	struct in_addr	addr;	/* server, net order */ +	u_int		prog;	/* host order */ +	u_int		vers;	/* host order */ +{ +	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); +} + +void +rpc_pmap_putcache(addr, prog, vers, port) +	struct in_addr	addr;	/* server, net order */ +	u_int		prog;	/* host order */ +	u_int		vers;	/* host order */ +	int 		port;	/* host order */ +{ +	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. + */ +int +rpc_getport(d, prog, vers) +	register struct iodesc *d; +	n_long prog;	/* host order */ +	n_long vers;	/* host order */ +{ +	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; +	struct { +		n_long	h[RPC_HEADER_WORDS]; +		struct res d; +		n_long  pad; +	} rdata; +	ssize_t cc; +	int port; + +#ifdef RPC_DEBUG +	if (debug) +		printf("getport: prog=0x%x vers=%d\n", prog, vers); +#endif + +	/* This one is fixed forever. */ +	if (prog == PMAPPROG) +		return (PMAPPORT); + +	/* Try for cached answer first */ +	port = rpc_pmap_getcache(d->destip, prog, vers); +	if (port != -1) +		return (port); + +	args = &sdata.d; +	args->prog = htonl(prog); +	args->vers = htonl(vers); +	args->proto = htonl(IPPROTO_UDP); +	args->port = 0; +	res = &rdata.d; + +	cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, +		args, sizeof(*args), res, sizeof(*res)); +	if (cc < sizeof(*res)) { +		printf("getport: %s", strerror(errno)); +		errno = EBADRPC; +		return (-1); +	} +	port = (int)ntohl(res->port); + +	rpc_pmap_putcache(d->destip, prog, vers, port); + +	return (port); +} diff --git a/lib/libstand/rpc.h b/lib/libstand/rpc.h new file mode 100644 index 000000000000..1b6c60d34f26 --- /dev/null +++ b/lib/libstand/rpc.h @@ -0,0 +1,68 @@ +/*	$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. 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, Lawrence Berkeley Laboratory 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. + */ + +/* 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 *, size_t); +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/lib/libstand/rpcv2.h b/lib/libstand/rpcv2.h new file mode 100644 index 000000000000..e4d2dbeb6285 --- /dev/null +++ b/lib/libstand/rpcv2.h @@ -0,0 +1,89 @@ +/*	$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. 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. + * + *	@(#)rpcv2.h	8.1 (Berkeley) 6/10/93 + */ + +/* + * 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/lib/libstand/saioctl.h b/lib/libstand/saioctl.h new file mode 100644 index 000000000000..bf7df4cdac17 --- /dev/null +++ b/lib/libstand/saioctl.h @@ -0,0 +1,52 @@ +/*	$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. 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. + * + *	@(#)saioctl.h	8.1 (Berkeley) 6/11/93 + */ + +/* 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/lib/libstand/stand.h b/lib/libstand/stand.h new file mode 100644 index 000000000000..40c4e70a869f --- /dev/null +++ b/lib/libstand/stand.h @@ -0,0 +1,305 @@ +/* + * 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. + * + *	$Id$ + * 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. 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. + * + *	@(#)stand.h	8.1 (Berkeley) 6/11/93 + */ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/stat.h> + +#ifndef NULL +#define	NULL	0 +#endif + +/* 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 { +    char	*fs_name; +    int		(*fo_open)(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); +}; + +/* + * 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 zipfs_fsops; +#ifdef notyet +extern struct fs_ops dosfs_fsops; +#endif + +/* 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 { +    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, void *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); +}; + +extern int errno; + +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 (F_RAW) */ +}; + +#define	SOPEN_MAX	8 +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 isupper(c)	((c) >= 'A' && (c) <= 'Z') +#define islower(c)	((c) >= 'a' && (c) <= 'z') +#define isspace(c)	((c) == ' ' || (c) == '\t') +#define isdigit(c)	((c) >= '0' && (c) <= '9') +#define isxdigit(c)	(isdigit(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#define isascii(c)	((c) >= 0 || (c <= 0x7f)) +#define isalpha(c)	(isupper(c) || (islower(c))) +#define toupper(c)	((c) - 'a' + 'A') +#define tolower(c)	((c) - 'A' + 'a') + +extern void	setheap(void *, void *); +extern void	*malloc(size_t); +extern void	free(void *); +extern char	*sbrk(int junk); + +/* disklabel support (undocumented, may be junk) */ +struct		disklabel; +extern char	*getdisklabel(const char *, struct disklabel *); +extern int	dkcksum(struct disklabel *); + +extern int	printf(const char *fmt, ...); +extern void	vprintf(const char *fmt, _BSD_VA_LIST_); +extern int	sprintf(char *buf, const char *cfmt, ...); + +extern void	twiddle(void); + +extern void	ngets(char *, int); +#define gets(x)	ngets((x), 0) +extern int	fgetstr(char *buf, int size, int fd); + +extern char	*strerror(int); + +extern int	open(const char *, int); +#define	O_RDONLY	0x0 +#define O_WRONLY	0x1			/* writing not (yet?) supported */ +#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 off_t	lseek(int, off_t, int); +extern int	stat(const char *, struct stat *); + +extern void	srandom(u_long seed); +extern u_long	random(void); +     +/* imports from stdlib, locally modified */ +extern long	strtol(const char *, char **, int); +extern char	*optarg;			/* getopt(3) external variables */ +extern int	optind, opterr, optopt; +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(char *fname); + +/* 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, 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, void *value,  +				   ev_sethook_t sethook, ev_unsethook_t unsethook); +extern char		*getenv(const char *name); +extern int		setenv(const char *name, 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); } + +/* swaps (undocumented, useful?) */ +#ifdef __i386__ +extern u_int32_t	bswap32(u_int32_t x); +extern u_int64_t	bswap64(u_int32_t x); +#endif + +/* 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(char *path, struct open_file *f); +extern int	null_close(struct open_file *f); +extern ssize_t	null_read(struct open_file *f, void *buf, size_t size, size_t *resid); +extern ssize_t	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); + +/* stuff should be in bootstrap (undocumented) */ +extern int	getfile(char *prompt, int mode); + +/*  + * Machine dependent functions and data, must be provided or stubbed by  + * the consumer  + */ +extern int		getchar(void); +extern int		ischar(void); +extern void		putchar(int); +extern int		devopen(struct open_file *, const char *, char **); +extern int		devclose(struct open_file *f); +extern __dead void	panic(const char *, ...) __attribute__((noreturn)); +extern struct fs_ops	*file_system[]; +extern struct devsw	*devsw[]; + diff --git a/lib/libstand/stat.c b/lib/libstand/stat.c new file mode 100644 index 000000000000..bdc97d571ca9 --- /dev/null +++ b/lib/libstand/stat.c @@ -0,0 +1,53 @@ +/*	$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. 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. + * + *	@(#)stat.c	8.1 (Berkeley) 6/11/93 + */ + +#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/lib/libstand/strdup.c b/lib/libstand/strdup.c new file mode 100644 index 000000000000..ee46e7d1670b --- /dev/null +++ b/lib/libstand/strdup.c @@ -0,0 +1,56 @@ +/* + * 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. 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. + */ + +#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/lib/libstand/strerror.c b/lib/libstand/strerror.c new file mode 100644 index 000000000000..e84a4d4275b3 --- /dev/null +++ b/lib/libstand/strerror.c @@ -0,0 +1,88 @@ +/*	$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. 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. + */ + +#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/lib/libstand/strtol.c b/lib/libstand/strtol.c new file mode 100644 index 000000000000..02c59200a18c --- /dev/null +++ b/lib/libstand/strtol.c @@ -0,0 +1,133 @@ +/*- + * 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. 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. + */ + +#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; +	register int base; +{ +	register const char *s; +	register unsigned long acc; +	register unsigned char c; +	register unsigned long cutoff; +	register 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 != 0) +		*endptr = (char *)(any ? s - 1 : nptr); +	return (acc); +} diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c new file mode 100644 index 000000000000..db796b3b0f09 --- /dev/null +++ b/lib/libstand/tftp.c @@ -0,0 +1,400 @@ +/*	$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. + * + */ + +/* + * 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" + +static int	tftp_open(char *path, struct open_file *f); +static int	tftp_close(struct open_file *f); +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_stat(struct open_file *f, struct stat *sb); + +struct fs_ops tftp_fsops = { +	"tftp", tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek, tftp_stat +}; + +extern struct in_addr servip; + +static int      tftpport = 2000; + +#define RSPACE 520		/* max data packet, rounded up */ + +struct tftp_handle { +	struct iodesc  *iodesc; +	int             currblock;	/* contents of lastdata */ +	int             islastblock;	/* flag */ +	int             validsize; +	int             off; +	char           *path;	/* saved for re-requests */ +	struct { +		u_char header[HEADER_SIZE]; +		struct tftphdr t; +		u_char space[RSPACE]; +	} lastdata; +}; + +static int tftperrors[8] = { +	0,			/* ??? */ +	ENOENT, +	EPERM, +	ENOSPC, +	EINVAL,			/* ??? */ +	EINVAL,			/* ??? */ +	EEXIST, +	EINVAL			/* ??? */ +}; + +static ssize_t  +recvtftp(d, pkt, len, tleft) +	register struct iodesc *d; +	register void  *pkt; +	register ssize_t len; +	time_t          tleft; +{ +	struct tftphdr *t; + +	len = readudp(d, pkt, len, tleft); + +	if (len < 8) +		return (-1); + +	t = (struct tftphdr *) pkt; +	switch (ntohs(t->th_opcode)) { +	case DATA: { +		int got; + +		if (htons(t->th_block) != d->xid) { +			/* +			 * Expected block? +			 */ +			return (-1); +		} +		if (d->xid == 1) { +			/* +			 * First data packet from new port. +			 */ +			register struct udphdr *uh; +			uh = (struct udphdr *) pkt - 1; +			d->destport = uh->uh_sport; +		} /* else check uh_sport has not changed??? */ +		got = len - (t->th_data - (char *) t); +		return got; +	} +	case ERROR: +		if ((unsigned) ntohs(t->th_code) >= 8) { +			printf("illegal tftp error %d\n", ntohs(t->th_code)); +			errno = EIO; +		} else { +#ifdef DEBUG +			printf("tftp-error %d\n", ntohs(t->th_code)); +#endif +			errno = tftperrors[ntohs(t->th_code)]; +		} +		return (-1); +	default: +#ifdef DEBUG +		printf("tftp type %d not handled\n", ntohs(t->th_opcode)); +#endif +		return (-1); +	} +} + +/* send request, expect first block (or error) */ +static int  +tftp_makereq(h) +	struct tftp_handle *h; +{ +	struct { +		u_char header[HEADER_SIZE]; +		struct tftphdr  t; +		u_char space[FNAME_SIZE + 6]; +	} wbuf; +	char           *wtail; +	int             l; +	ssize_t         res; +	struct tftphdr *t; + +	wbuf.t.th_opcode = htons((u_short) RRQ); +	wtail = wbuf.t.th_stuff; +	l = strlen(h->path); +	bcopy(h->path, wtail, l + 1); +	wtail += l + 1; +	bcopy("octet", wtail, 6); +	wtail += 6; + +	t = &h->lastdata.t; + +	/* h->iodesc->myport = htons(--tftpport); */ +	h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); +	h->iodesc->destport = htons(IPPORT_TFTP); +	h->iodesc->xid = 1;	/* expected block */ + +	res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, +		       recvtftp, t, sizeof(*t) + RSPACE); + +	if (res == -1) +		return (errno); + +	h->currblock = 1; +	h->validsize = res; +	h->islastblock = 0; +	if (res < SEGSIZE) +		h->islastblock = 1;	/* very short file */ +	return (0); +} + +/* ack block, expect next */ +static int  +tftp_getnextblock(h) +	struct tftp_handle *h; +{ +	struct { +		u_char header[HEADER_SIZE]; +		struct tftphdr t; +	} wbuf; +	char           *wtail; +	int             res; +	struct tftphdr *t; + +	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; + +	t = &h->lastdata.t; + +	h->iodesc->xid = h->currblock + 1;	/* expected block */ + +	res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, +		       recvtftp, t, sizeof(*t) + RSPACE); + +	if (res == -1)		/* 0 is OK! */ +		return (errno); + +	h->currblock++; +	h->validsize = res; +	if (res < SEGSIZE) +		h->islastblock = 1;	/* EOF */ +	return (0); +} + +static int  +tftp_open(path, f) +	char           *path; +	struct open_file *f; +{ +	struct tftp_handle *tftpfile; +	struct iodesc  *io; +	int             res; + +	tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile)); +	if (!tftpfile) +		return (ENOMEM); + +	tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); +	io->destip = servip; +	tftpfile->off = 0; +	tftpfile->path = path;	/* XXXXXXX we hope it's static */ + +	res = tftp_makereq(tftpfile, path); + +	if (res) { +		free(tftpfile); +		return (res); +	} +	f->f_fsdata = (void *) tftpfile; +	return (0); +} + +static int  +tftp_read(f, addr, size, resid) +	struct open_file *f; +	void           *addr; +	size_t          size; +	size_t         *resid;	/* out */ +{ +	struct tftp_handle *tftpfile; +	static int      tc = 0; +	tftpfile = (struct tftp_handle *) f->f_fsdata; + +	while (size > 0) { +		int needblock, count; + +		if (!(tc++ % 16)) +			twiddle(); + +		needblock = tftpfile->off / SEGSIZE + 1; + +		if (tftpfile->currblock > needblock)	/* seek backwards */ +			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 DEBUG +				printf("tftp: read error\n"); +#endif +				return (res); +			} +			if (tftpfile->islastblock) +				break; +		} + +		if (tftpfile->currblock == needblock) { +			int offinblock, inbuffer; + +			offinblock = tftpfile->off % SEGSIZE; + +			inbuffer = tftpfile->validsize - offinblock; +			if (inbuffer < 0) { +#ifdef DEBUG +				printf("tftp: invalid offset %d\n", +				    tftpfile->off); +#endif +				return (EINVAL); +			} +			count = (size < inbuffer ? size : inbuffer); +			bcopy(tftpfile->lastdata.t.th_data + offinblock, +			    addr, count); + +			addr += count; +			tftpfile->off += count; +			size -= count; + +			if ((tftpfile->islastblock) && (count == inbuffer)) +				break;	/* EOF */ +		} else { +#ifdef DEBUG +			printf("tftp: block %d not found\n", needblock); +#endif +			return (EINVAL); +		} + +	} + +	if (resid) +		*resid = size; +	return (0); +} + +static int  +tftp_close(f) +	struct open_file *f; +{ +	struct tftp_handle *tftpfile; +	tftpfile = (struct tftp_handle *) f->f_fsdata; + +	/* let it time out ... */ + +	if (tftpfile) +		free(tftpfile); +	return (0); +} + +static int  +tftp_write(f, start, size, resid) +	struct open_file *f; +	void           *start; +	size_t          size; +	size_t         *resid;	/* out */ +{ +	return (EROFS); +} + +static int  +tftp_stat(f, sb) +	struct open_file *f; +	struct stat    *sb; +{ +	struct tftp_handle *tftpfile; +	tftpfile = (struct tftp_handle *) f->f_fsdata; + +	sb->st_mode = 0444; +	sb->st_nlink = 1; +	sb->st_uid = 0; +	sb->st_gid = 0; +	sb->st_size = -1; +	return (0); +} + +static off_t  +tftp_seek(f, offset, where) +	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); +} diff --git a/lib/libstand/tftp.h b/lib/libstand/tftp.h new file mode 100644 index 000000000000..cbbbbd782129 --- /dev/null +++ b/lib/libstand/tftp.h @@ -0,0 +1,36 @@ +/*	$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. + * + */ + + +#define IPPORT_TFTP 69 diff --git a/lib/libstand/twiddle.c b/lib/libstand/twiddle.c new file mode 100644 index 000000000000..c74c06b53596 --- /dev/null +++ b/lib/libstand/twiddle.c @@ -0,0 +1,54 @@ +/*- + * 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. 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. + * + *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94 + * $Id: subr_prf.c,v 1.46 1998/05/28 09:30:20 phk Exp $ + */ + +#include <sys/types.h> +#include "stand.h" + +/* Extra functions from NetBSD standalone printf.c */ + +void +twiddle() +{ +	static int pos; + +	putchar("|/-\\"[pos++ & 3]); +	putchar('\b'); +} diff --git a/lib/libstand/ufs.c b/lib/libstand/ufs.c new file mode 100644 index 000000000000..2a2c56a90bda --- /dev/null +++ b/lib/libstand/ufs.c @@ -0,0 +1,704 @@ +/*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross 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. 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. + */ + +/* + *	Stand-alone file reading package. + */ + +#include <sys/param.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(char *path, struct open_file *f); +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); + +struct fs_ops ufs_fsops = { +	"ufs", ufs_open, ufs_close, ufs_read, null_write, ufs_seek, ufs_stat +}; + + +/* + * In-core open file. + */ +struct file { +	off_t		f_seekp;	/* seek pointer */ +	struct fs	*f_fs;		/* pointer to super-block */ +	struct dinode	f_di;		/* copy of on-disk inode */ +	int		f_nindir[NIADDR]; +					/* number of blocks mapped by +					   indirect block at level i */ +	char		*f_blk[NIADDR];	/* buffer for indirect block at +					   level i */ +	size_t		f_blksize[NIADDR]; +					/* size of buffer */ +	daddr_t		f_blkno[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 */ +}; + +static int	read_inode(ino_t, struct open_file *); +static int	block_map(struct open_file *, daddr_t, daddr_t *); +static int	buf_read_file(struct open_file *, char **, size_t *); +static int	search_directory(char *, struct open_file *, ino_t *); +#ifdef COMPAT_UFS +static void	ffs_oldfscompat(struct fs *); +#endif + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(inumber, f) +	ino_t inumber; +	struct open_file *f; +{ +	register struct file *fp = (struct file *)f->f_fsdata; +	register struct fs *fs = fp->f_fs; +	char *buf; +	size_t rsize; +	int rc; + +	/* +	 * Read inode and save it. +	 */ +	buf = malloc(fs->fs_bsize); +	twiddle(); +	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; +	} + +	{ +		register struct dinode *dp; + +		dp = (struct dinode *)buf; +		fp->f_di = dp[ino_to_fsbo(fs, inumber)]; +	} + +	/* +	 * Clear out the old buffers +	 */ +	{ +		register int level; + +		for (level = 0; level < NIADDR; level++) +			fp->f_blkno[level] = -1; +		fp->f_buf_blkno = -1; +	} +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; +	daddr_t file_block; +	daddr_t *disk_block_p;	/* out */ +{ +	register struct file *fp = (struct file *)f->f_fsdata; +	register struct fs *fs = fp->f_fs; +	int level; +	int idx; +	daddr_t ind_block_num; +	daddr_t *ind_p; +	int rc; + +	/* +	 * Index structure of an inode: +	 * +	 * di_db[0..NDADDR-1]	hold block numbers for blocks +	 *			0..NDADDR-1 +	 * +	 * di_ib[0]		index block 0 is the single indirect block +	 *			holds block numbers for blocks +	 *			NDADDR .. NDADDR + NINDIR(fs)-1 +	 * +	 * di_ib[1]		index block 1 is the double indirect block +	 *			holds block numbers for INDEX blocks for blocks +	 *			NDADDR + NINDIR(fs) .. +	 *			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 +	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. +	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 +	 *				+ NINDIR(fs)**3 - 1 +	 */ + +	if (file_block < NDADDR) { +		/* Direct block. */ +		*disk_block_p = fp->f_di.di_db[file_block]; +		return (0); +	} + +	file_block -= NDADDR; + +	/* +	 * nindir[0] = NINDIR +	 * nindir[1] = NINDIR**2 +	 * nindir[2] = NINDIR**3 +	 *	etc +	 */ +	for (level = 0; level < NIADDR; level++) { +		if (file_block < fp->f_nindir[level]) +			break; +		file_block -= fp->f_nindir[level]; +	} +	if (level == 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(); +			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; +		} + +		ind_p = (daddr_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(f, buf_p, size_p) +	struct open_file *f; +	char **buf_p;		/* out */ +	size_t *size_p;		/* out */ +{ +	register struct file *fp = (struct file *)f->f_fsdata; +	register struct fs *fs = fp->f_fs; +	long off; +	register daddr_t file_block; +	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 = dblksize(fs, &fp->f_di, file_block); + +	if (file_block != fp->f_buf_blkno) { +		rc = block_map(f, file_block, &disk_block); +		if (rc) +			return (rc); + +		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(); +			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 > fp->f_di.di_size - fp->f_seekp) +		*size_p = fp->f_di.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 */ +{ +	register struct file *fp = (struct file *)f->f_fsdata; +	register 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 < fp->f_di.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); +} + +/* + * Open a file. + */ +static int +ufs_open(path, f) +	char *path; +	struct open_file *f; +{ +	register char *cp, *ncp; +	register int c; +	ino_t inumber, parent_inumber; +	struct file *fp; +	struct fs *fs; +	int rc; +	size_t buf_size; +	int nlinks = 0; +	char namebuf[MAXPATHLEN+1]; +	char *buf = 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(SBSIZE); +	fp->f_fs = fs; +	twiddle(); +	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, +		SBLOCK, SBSIZE, (char *)fs, &buf_size); +	if (rc) +		goto out; + +	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || +	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { +		rc = EINVAL; +		goto out; +	} +#ifdef COMPAT_UFS +	ffs_oldfscompat(fs); +#endif + +	/* +	 * Calculate indirect block levels. +	 */ +	{ +		register int mult; +		register int level; + +		mult = 1; +		for (level = 0; level < NIADDR; level++) { +			mult *= NINDIR(fs); +			fp->f_nindir[level] = mult; +		} +	} + +	inumber = ROOTINO; +	if ((rc = read_inode(inumber, f)) != 0) +		goto out; + +	cp = path; +	while (*cp) { + +		/* +		 * Remove extra separators +		 */ +		while (*cp == '/') +			cp++; +		if (*cp == '\0') +			break; + +		/* +		 * Check that current node is a directory. +		 */ +		if ((fp->f_di.di_mode & IFMT) != IFDIR) { +			rc = ENOTDIR; +			goto out; +		} + +		/* +		 * Get next component of path name. +		 */ +		{ +			register int len = 0; + +			ncp = cp; +			while ((c = *cp) != '\0' && c != '/') { +				if (++len > 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 ((fp->f_di.di_mode & IFMT) == IFLNK) { +			int link_len = fp->f_di.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) { +				bcopy(fp->f_di.di_shortlink, namebuf, +				      (unsigned) link_len); +			} else { +				/* +				 * Read file for symbolic link +				 */ +				size_t buf_size; +				daddr_t	disk_block; +				register struct fs *fs = fp->f_fs; + +				if (!buf) +					buf = malloc(fs->fs_bsize); +				rc = block_map(f, (daddr_t)0, &disk_block); +				if (rc) +					goto out; +				 +				twiddle(); +				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)ROOTINO; + +			if ((rc = read_inode(inumber, f)) != 0) +				goto out; +		} +	} + +	/* +	 * Found terminal component. +	 */ +	rc = 0; +out: +	if (buf) +		free(buf); +	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; +{ +	register 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 < 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 */ +{ +	register struct file *fp = (struct file *)f->f_fsdata; +	register size_t csize; +	char *buf; +	size_t buf_size; +	int rc = 0; +	register char *addr = start; + +	while (size != 0) { +		if (fp->f_seekp >= fp->f_di.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); +} + +static off_t +ufs_seek(f, offset, where) +	struct open_file *f; +	off_t offset; +	int where; +{ +	register 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: +		return (-1); +	} +	return (fp->f_seekp); +} + +static int +ufs_stat(f, sb) +	struct open_file *f; +	struct stat *sb; +{ +	register 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); +} + +#ifdef COMPAT_UFS +/* + * Sanity checks for old file systems. + * + * XXX - goes away some day. + */ +static void +ffs_oldfscompat(fs) +	struct fs *fs; +{ +	int i; + +	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */ +	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */ +	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */ +		fs->fs_nrpos = 8;				/* XXX */ +	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */ +		quad_t sizepb = fs->fs_bsize;			/* XXX */ +								/* XXX */ +		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */ +		for (i = 0; i < NIADDR; i++) {			/* XXX */ +			sizepb *= NINDIR(fs);			/* XXX */ +			fs->fs_maxfilesize += sizepb;		/* XXX */ +		}						/* XXX */ +		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */ +		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */ +	}							/* XXX */ +} +#endif diff --git a/lib/libstand/write.c b/lib/libstand/write.c new file mode 100644 index 000000000000..7c30926313f1 --- /dev/null +++ b/lib/libstand/write.c @@ -0,0 +1,96 @@ +/*	$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. 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. + * + *	@(#)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/param.h> +#include "stand.h" + +ssize_t +write(fd, dest, bcount) +	int fd; +	void *dest; +	size_t bcount; +{ +	register 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(); +		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 (0); +} diff --git a/lib/libstand/zipfs.c b/lib/libstand/zipfs.c new file mode 100644 index 000000000000..90589078d465 --- /dev/null +++ b/lib/libstand/zipfs.c @@ -0,0 +1,316 @@ +/*  + * 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. + * + *	$Id$ + * + */ + +#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; +    z_stream		zf_zstream; +    char		zf_buf[Z_BUFSIZE]; +}; + +static int	zf_fill(struct z_file *z); +static int	zf_open(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 zipfs_fsops = { +    "zip", +    zf_open,  +    zf_close,  +    zf_read, +    null_write, +    zf_seek, +    zf_stat +}; + +void * +calloc(int items, size_t size) +{ +    return(malloc(items * size)); +} + +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) +{ +    if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) +	return(-1); +    zf->zf_zstream.avail_in--; +    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; + +    /* Check the gzip magic header */ +    for (len = 0; len < 2; len++) { +	c = get_byte(zf); +	if (c != gz_magic[len]) { +	    return(1); +	} +    } +    method = get_byte(zf); +    flags = get_byte(zf); +    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); + +    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ +	len  =  (uInt)get_byte(zf); +	len += ((uInt)get_byte(zf))<<8; +	/* len is garbage if EOF but the loop below will quit anyway */ +	while (len-- != 0 && get_byte(zf) != -1) ; +    } +    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ +	while ((c = get_byte(zf)) != 0 && c != -1) ; +    } +    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */ +	while ((c = get_byte(zf)) != 0 && c != -1) ; +    } +    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */ +	for (len = 0; len < 2; len++) c = get_byte(zf); +    } +    /* if there's data left, we're in business */ +    return((c == -1) ? 1 : 0); +} +	 +static int +zf_open(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, ignore it */ +    if ((cp = strrchr(fname, '.')) && !strcmp(cp, ".gz")) +	return(ENOENT); + +    /* Construct new name */ +    zfname = malloc(strlen(fname) + 3); +    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)); +    bzero(zf, sizeof(struct z_file)); +    zf->zf_rawfd = rawfd; + +    /* Verify that the file is gzipped (XXX why do this afterwards?) */ +    if (check_header(zf)) { +	close(zf->zf_rawfd); +	inflateEnd(&(zf->zf_zstream)); +	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) { +	if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { +	    printf("zf_read: fill error\n"); +	    return(-1); +	} +	if (zf->zf_zstream.avail_in == 0) {		/* oops, unexpected EOF */ +	    printf("zf_read: unexpected EOF\n"); +	    break; +	} + +	error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH);	/* decompression pass */ +	if (error == Z_STREAM_END) {			/* EOF, all done */ +	    break; +	} +	if (error != Z_OK) {				/* argh, decompression error */ +	    printf("inflate: %s\n", zf->zf_zstream.msg); +	    errno = EIO; +	    return(-1); +	} +    } +    if (resid != NULL) +	*resid = zf->zf_zstream.avail_out; +    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: +	target = -1; +    } + +    /* Can we get there from here? */ +    if (target < zf->zf_zstream.total_out) { +	errno = EOFFSET; +	return -1; +    }  + +    /* skip forwards if required */ +    while (target > zf->zf_zstream.total_out) { +	if (zf_read(f, discard, min(sizeof(discard), target - zf->zf_zstream.total_out), NULL) == -1) +	    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); +} + + +  | 
