Browse Source

Plan 9 from Bell Labs 2003-12-16

David du Colombier 20 years ago
parent
commit
97dcff23ea

+ 12 - 10
dist/replica/plan9.db

@@ -3396,7 +3396,7 @@ sys/include/geometry.h - 664 sys sys 1014929063 2632
 sys/include/html.h - 664 sys sys 1017679304 15157
 sys/include/httpd.h - 664 sys sys 1014929064 5726
 sys/include/ip.h - 664 sys sys 1050702405 2908
-sys/include/keyboard.h - 664 sys sys 1014929064 799
+sys/include/keyboard.h - 664 sys sys 1071535972 802
 sys/include/libc.h - 664 sys sys 1067718922 19305
 sys/include/libsec.h - 664 sys sys 1068129557 8966
 sys/include/mach.h - 664 sys sys 1068478049 8194
@@ -3847,7 +3847,7 @@ sys/lib/lp - 20000000775 sys sys 954037460 0
 sys/lib/lp/bin - 20000000775 sys sys 959999531 0
 sys/lib/lp/bin/UNLOCK - 775 sys sys 954037458 25
 sys/lib/lp/bin/kill_xerox-4512 - 775 sys sys 954037458 92
-sys/lib/lp/bin/lpscratch - 775 sys sys 1063856100 908
+sys/lib/lp/bin/lpscratch - 775 sys sys 1071539623 32
 sys/lib/lp/bin/lpsend.rc - 775 sys sys 954037458 361
 sys/lib/lp/bin/true - 775 sys sys 954037458 18
 sys/lib/lp/daemon - 20000000775 sys sys 1015012112 0
@@ -3919,6 +3919,7 @@ sys/lib/lp/stat/xerox - 775 sys sys 954037459 652
 sys/lib/lp/stat/xerox-4512 - 775 sys sys 954037459 655
 sys/lib/lp/stat/xerox-4517 - 775 sys sys 954037460 658
 sys/lib/lp/stat/xerox-N32 - 775 sys sys 954037460 714
+sys/lib/lp/tmp - 20000000777 sys sys 1071536829 0
 sys/lib/man - 20000000775 sys sys 960356011 0
 sys/lib/man/checkman.awk - 664 sys sys 1017679304 6277
 sys/lib/man/colophon - 664 sys sys 956337727 545
@@ -5293,7 +5294,7 @@ sys/src/9/pc/ether83815.c - 664 sys sys 1026847640 23050
 sys/src/9/pc/ether8390.c - 664 sys sys 1071245462 17557
 sys/src/9/pc/ether8390.h - 664 sys sys 1015014517 1511
 sys/src/9/pc/etherec2t.c - 664 sys sys 1020284820 4038
-sys/src/9/pc/etherelnk3.c - 664 sys sys 1063857363 48522
+sys/src/9/pc/etherelnk3.c - 664 sys sys 1071515332 48521
 sys/src/9/pc/etherga620.c - 664 sys sys 1067723192 28788
 sys/src/9/pc/etherga620fw.h - 644 sys sys 1026847642 222295
 sys/src/9/pc/etherif.h - 664 sys sys 1045063564 961
@@ -5305,7 +5306,7 @@ sys/src/9/pc/ethersink.c - 664 sys sys 1048644103 1076
 sys/src/9/pc/ethersmc.c - 664 sys sys 1071245461 15103
 sys/src/9/pc/etherwavelan.c - 664 sys sys 1026847642 3722
 sys/src/9/pc/floppy.h - 664 sys sys 1055700609 3835
-sys/src/9/pc/fns.h - 664 sys sys 1068393346 4299
+sys/src/9/pc/fns.h - 664 sys sys 1071514801 4296
 sys/src/9/pc/hcwAMC.h - 664 sys sys 1026860163 166004
 sys/src/9/pc/i8253.c - 664 sys sys 1071245560 6251
 sys/src/9/pc/i8259.c - 664 sys sys 1015014519 4423
@@ -5313,7 +5314,7 @@ sys/src/9/pc/init9.c - 664 sys sys 1040002518 94
 sys/src/9/pc/initcode.s - 664 sys sys 1015014519 282
 sys/src/9/pc/io.h - 664 sys sys 1067722633 7991
 sys/src/9/pc/kbd.c - 664 sys sys 1039753498 9134
-sys/src/9/pc/l.s - 664 sys sys 1068394843 23295
+sys/src/9/pc/l.s - 664 sys sys 1071514801 23314
 sys/src/9/pc/main.c - 664 sys sys 1067722634 14685
 sys/src/9/pc/mem.h - 664 sys sys 1018553448 4573
 sys/src/9/pc/memory.c - 664 sys sys 1071245460 13028
@@ -6727,16 +6728,17 @@ sys/src/cmd/9nfs/9auth.c - 664 sys sys 1017337812 1454
 sys/src/cmd/9nfs/9p.c - 664 sys sys 1017337813 3291
 sys/src/cmd/9nfs/all.h - 664 sys sys 1017337813 322
 sys/src/cmd/9nfs/auth.c - 664 sys sys 1017337813 424
+sys/src/cmd/9nfs/authhostowner.c - 664 sys sys 1071498519 4190
 sys/src/cmd/9nfs/chat.c - 664 sys sys 1017337813 2096
-sys/src/cmd/9nfs/dat.h - 664 sys sys 1017337813 4445
-sys/src/cmd/9nfs/fns.h - 664 sys sys 1017337813 1879
+sys/src/cmd/9nfs/dat.h - 664 sys sys 1071498518 4406
+sys/src/cmd/9nfs/fns.h - 664 sys sys 1071498519 1908
 sys/src/cmd/9nfs/listalloc.c - 664 sys sys 1015090372 297
-sys/src/cmd/9nfs/mkfile - 664 sys sys 1050715042 621
+sys/src/cmd/9nfs/mkfile - 664 sys sys 1071498518 640
 sys/src/cmd/9nfs/mport.c - 664 sys sys 1050715069 3779
 sys/src/cmd/9nfs/nametest.c - 664 sys sys 1015090372 1723
 sys/src/cmd/9nfs/nfs.c - 664 sys sys 1017337814 9508
 sys/src/cmd/9nfs/nfs.h - 664 sys sys 1015090372 642
-sys/src/cmd/9nfs/nfsmount.c - 664 sys sys 1034737122 6538
+sys/src/cmd/9nfs/nfsmount.c - 664 sys sys 1071498520 6142
 sys/src/cmd/9nfs/nfsserver.c - 664 sys sys 1040952455 15576
 sys/src/cmd/9nfs/pcnfsd.c - 664 sys sys 1017337815 3964
 sys/src/cmd/9nfs/portmapper.c - 664 sys sys 1040952456 3179
@@ -9449,7 +9451,7 @@ sys/src/cmd/ip/imap4d/nodes.c - 664 sys sys 1015013077 3173
 sys/src/cmd/ip/imap4d/search.c - 664 sys sys 1015013077 4520
 sys/src/cmd/ip/imap4d/store.c - 664 sys sys 1066317059 1910
 sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1015013077 2481
-sys/src/cmd/ip/ipconfig.c - 664 sys sys 1060189236 29311
+sys/src/cmd/ip/ipconfig.c - 664 sys sys 1071498576 34555
 sys/src/cmd/ip/measure.c - 664 sys sys 944961011 3733
 sys/src/cmd/ip/mkfile - 664 sys sys 1063897563 1250
 sys/src/cmd/ip/ping.c - 664 sys sys 1061496964 5552

+ 12 - 0
dist/replica/plan9.log

@@ -13131,3 +13131,15 @@
 1071342042 1 c sys/man/8/ipconfig - 664 sys sys 1071340739 6037
 1071415853 0 c lib/units - 664 sys sys 1071415518 9997
 1071459058 0 c sys/src/cmd/tapefs/tarfs.c - 664 sys sys 1071458376 2672
+1071498664 0 a sys/src/cmd/9nfs/authhostowner.c - 664 sys sys 1071498519 4190
+1071498664 1 c sys/src/cmd/9nfs/dat.h - 664 sys sys 1071498518 4406
+1071498664 2 c sys/src/cmd/9nfs/fns.h - 664 sys sys 1071498519 1908
+1071498664 3 c sys/src/cmd/9nfs/mkfile - 664 sys sys 1071498518 640
+1071498664 4 c sys/src/cmd/9nfs/nfsmount.c - 664 sys sys 1071498520 6142
+1071498664 5 c sys/src/cmd/ip/ipconfig.c - 664 sys sys 1071498576 34555
+1071514866 0 c sys/src/9/pc/fns.h - 664 sys sys 1071514801 4296
+1071514866 1 c sys/src/9/pc/l.s - 664 sys sys 1071514801 23314
+1071516666 0 c sys/src/9/pc/etherelnk3.c - 664 sys sys 1071515332 48521
+1071536469 0 c sys/include/keyboard.h - 664 sys sys 1071535972 802
+1071538269 0 a sys/lib/lp/tmp - 20000000777 sys sys 1071536829 0
+1071540069 0 c sys/lib/lp/bin/lpscratch - 775 sys sys 1071539623 32

+ 1 - 1
sys/include/keyboard.h

@@ -32,7 +32,7 @@ enum {
 	Kview=	0x80,
 	Kpgdown=	KF|0x13,
 	Kins=	KF|0x14,
-	Kend=	'\r',	/* [sic] */
+	Kend=	KF|0x18,	/* [sic] */
 
 	Kalt=		KF|0x15,
 	Kshift=	KF|0x16,

+ 1 - 36
sys/lib/lp/bin/lpscratch

@@ -1,37 +1,2 @@
 #!/bin/rc
-
-#
-# set up scratch area that is on disk that is not backed-up
-#
-# file server of scratch file system
-LPLIB=/sys/lib/lp		# lp scripts directories and configuration file are here
-
-if (~ $#fileserver 0)
-	SCRATCHFILESERVER=emelie
-if not
-	SCRATCHFILESERVER=$fileserver
-# scratch file system name
-switch($SCRATCHFILESERVER){
-case kfs
-	SCRATCHFILESYSTEM=''
-case fossil
-	SCRATCHFILESYSTEM=''
-case *
-	SCRATCHFILESYSTEM=other
-}
-SCRATCH=/n/^$SCRATCHFILESERVER^$SCRATCHFILESYSTEM
-# lp subdirectory where log, prob, queue and tmp reside
-LPSCRATCH=$SCRATCH/lp
-
-if (! test -d $SCRATCH/lp) {
-	if (! test -r /srv/$SCRATCHFILESERVER) srv $SCRATCHFILESERVER
-	if (! mount -c /srv/$SCRATCHFILESERVER $SCRATCH $SCRATCHFILESYSTEM) {
-		echo 'cannot mount '$SCRATCH' filesystem' >[1=2]
-		exit 'LP mount'
-	}
-}
-if (! bind -a $LPSCRATCH $LPLIB) {
-	echo 'cannot bind '$LPSCRATCH' onto '$LPLIB >[1=2]
-	exit 'LP bind'
-}
-exit ''
+LPSCRATCH=/sys/lib/lp

+ 1 - 2
sys/src/9/pc/etherelnk3.c

@@ -1521,6 +1521,7 @@ tcm5XXpcmcia(Ether* ether)
 		ctlr->active = 1;
 		return ctlr;
 	}
+
 	return nil;
 }
 
@@ -2044,7 +2045,6 @@ etherelnk3reset(Ether* ether)
 	 * Allocate any receive buffers.
 	 */
 	switch(ctlr->busmaster){
-
 	case 2:
 		ctlr->dnenabled = 1;
 
@@ -2074,7 +2074,6 @@ etherelnk3reset(Ether* ether)
 		}
 		outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
 		break;
-
 	default:
 		ctlr->rbp = rbpalloc(iallocb);
 		if(ctlr->rbp == nil)

+ 2 - 2
sys/src/9/pc/fns.h

@@ -80,6 +80,8 @@ void	links(void);
 void	ltr(ulong);
 void	mach0init(void);
 void	mathinit(void);
+void	mb386(void);
+void	mb586(void);
 void	meminit(void);
 #define mmuflushtlb(pdb) putcr3(pdb)
 void	mmuinit(void);
@@ -145,8 +147,6 @@ void	upafree(ulong, int);
 #define	userureg(ur) (((ur)->cs & 0xFFFF) == UESEL)
 void	vectortable(void);
 void	wrmsr(int, vlong);
-void	wbflush(void);
-void	wbinvd(void);
 int	xchgw(ushort*, int);
 
 #define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))

+ 9 - 7
sys/src/9/pc/l.s

@@ -12,7 +12,6 @@
 #define WRMSR		BYTE $0x0F; BYTE $0x30	/* WRMSR, argument in AX/DX (lo/hi) */
 #define RDTSC 		BYTE $0x0F; BYTE $0x31	/* RDTSC, result in AX/DX (lo/hi) */
 #define RDMSR		BYTE $0x0F; BYTE $0x32	/* RDMSR, result in AX/DX (lo/hi) */
-#define WBINVD		BYTE $0x0F; BYTE $0x09
 #define HLT		BYTE $0xF4
 
 /*
@@ -352,10 +351,6 @@ TEXT wrmsr(SB), $0
 	WRMSR
 	RET
 
-TEXT wbinvd(SB), $0
-	WBINVD
-	RET
-
 /*
  * Try to determine the CPU type which requires fiddling with EFLAGS.
  * If the Id bit can be toggled then the CPUID instruciton can be used
@@ -542,7 +537,15 @@ _xdeclt:
 	DECL	AX
 	RET
 
-TEXT wbflush(SB), $0
+TEXT mb386(SB), $0
+	POPL	AX			/* return PC */
+	PUSHFL
+	PUSHL	CS
+	PUSHL	AX
+	IRETL
+
+TEXT mb586(SB), $0
+	XORL	AX, AX
 	CPUID
 	RET
 
@@ -930,4 +933,3 @@ TEXT vectortable(SB), $0
 	CALL _strayintr(SB); BYTE $0xFD
 	CALL _strayintr(SB); BYTE $0xFE
 	CALL _strayintr(SB); BYTE $0xFF
-

+ 239 - 0
sys/src/cmd/9nfs/authhostowner.c

@@ -0,0 +1,239 @@
+#include "all.h"
+
+enum { 
+	ARgiveup = 100,
+};
+
+static uchar*
+gstring(uchar *p, uchar *ep, char **s)
+{
+	uint n;
+
+	if(p == nil)
+		return nil;
+	if(p+BIT16SZ > ep)
+		return nil;
+	n = GBIT16(p);
+	p += BIT16SZ;
+	if(p+n > ep)
+		return nil;
+	*s = malloc(n+1);
+	memmove((*s), p, n);
+	(*s)[n] = '\0';
+	p += n;
+	return p;
+}
+
+static uchar*
+gcarray(uchar *p, uchar *ep, uchar **s, int *np)
+{
+	uint n;
+
+	if(p == nil)
+		return nil;
+	if(p+BIT16SZ > ep)
+		return nil;
+	n = GBIT16(p);
+	p += BIT16SZ;
+	if(p+n > ep)
+		return nil;
+	*s = malloc(n);
+	if(*s == nil)
+		return nil;
+	memmove((*s), p, n);
+	*np = n;
+	p += n;
+	return p;
+}
+
+static uchar*
+convM2AI(uchar *p, int n, AuthInfo **aip)
+{
+	uchar *e = p+n;
+	AuthInfo *ai;
+
+	ai = mallocz(sizeof(*ai), 1);
+	if(ai == nil)
+		return nil;
+
+	p = gstring(p, e, &ai->cuid);
+	p = gstring(p, e, &ai->suid);
+	p = gstring(p, e, &ai->cap);
+	p = gcarray(p, e, &ai->secret, &ai->nsecret);
+	if(p == nil)
+		auth_freeAI(ai);
+	else
+		*aip = ai;
+	return p;
+}
+
+static int
+dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey)
+{
+	int ret;
+
+	for(;;){
+		if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey)
+			return ret;
+		if(getkey == nil)
+			return ARgiveup;	/* don't know how */
+		if((*getkey)(rpc->arg) < 0)
+			return ARgiveup;	/* user punted */
+	}
+}
+
+static int
+doread(Session *s, Fid *f, void *buf, int n)
+{
+	s->f.fid = f - s->fids;
+	s->f.offset = 0;
+	s->f.count = n;
+	if(xmesg(s, Tread) < 0)
+		return -1;
+	n = s->f.count;
+	memmove(buf, s->f.data, n);
+	return n;
+}
+
+static int
+dowrite(Session *s, Fid *f, void *buf, int n)
+{
+	s->f.fid = f - s->fids;
+	s->f.offset = 0;
+	s->f.count = n;
+	s->f.data = (char *)buf;
+	if(xmesg(s, Twrite) < 0)
+		return -1;
+	return n;
+}
+
+/*
+ *  this just proxies what the factotum tells it to.
+ */
+AuthInfo*
+authproto(Session *s, Fid *f, AuthRpc *rpc, AuthGetkey *getkey, char *params)
+{
+	char *buf;
+	int m, n, ret;
+	AuthInfo *a;
+	char oerr[ERRMAX];
+
+	rerrstr(oerr, sizeof oerr);
+	werrstr("UNKNOWN AUTH ERROR");
+
+	if(dorpc(rpc, "start", params, strlen(params), getkey) != ARok){
+		werrstr("fauth_proxy start: %r");
+		return nil;
+	}
+
+	buf = malloc(AuthRpcMax);
+	if(buf == nil)
+		return nil;
+	for(;;){
+		switch(dorpc(rpc, "read", nil, 0, getkey)){
+		case ARdone:
+			free(buf);
+			a = auth_getinfo(rpc);
+			errstr(oerr, sizeof oerr);	/* no error, restore whatever was there */
+			return a;
+		case ARok:
+			if(dowrite(s, f, rpc->arg, rpc->narg) != rpc->narg){
+				werrstr("auth_proxy write fd: %r");
+				goto Error;
+			}
+			break;
+		case ARphase:
+			n = 0;
+			memset(buf, 0, AuthRpcMax);
+			while((ret = dorpc(rpc, "write", buf, n, getkey)) == ARtoosmall){
+				if(atoi(rpc->arg) > AuthRpcMax)
+					break;
+				m = doread(s, f, buf+n, atoi(rpc->arg)-n);
+				if(m <= 0){
+					if(m == 0)
+						werrstr("auth_proxy short read: %s", buf);
+					goto Error;
+				}
+				n += m;
+			}
+			if(ret != ARok){
+				werrstr("auth_proxy rpc write: %s: %r", buf);
+				goto Error;
+			}
+			break;
+		default:
+			werrstr("auth_proxy rpc: %r");
+			goto Error;
+		}
+	}
+Error:
+	free(buf);
+	return nil;
+}
+
+/* returns 0 if auth succeeded (or unneeded), -1 otherwise */
+int
+authhostowner(Session *s)
+{
+	Fid *af, *f;
+	int rv = -1;
+	int afd;
+	AuthInfo *ai;
+	AuthRpc *rpc;
+
+	/* get a fid to authenticate over */
+	f = nil;
+	af = newfid(s);
+	s->f.afid = af - s->fids;
+	s->f.uname = getuser();
+	s->f.aname = s->spec;
+	if(xmesg(s, Tauth)){
+		/* not needed */
+		rv = 0;
+		goto out;
+	}
+
+	quotefmtinstall();	/* just in case */
+
+	afd = open("/mnt/factotum/rpc", ORDWR);
+	if(afd < 0){
+		werrstr("opening /mnt/factotum/rpc: %r");
+		goto out;
+	}
+
+	rpc = auth_allocrpc(afd);
+	if(rpc == nil)
+		goto out;
+
+	ai = authproto(s, af, rpc, auth_getkey, "proto=p9any role=client");
+	if(ai != nil){
+		rv = 0;
+		auth_freeAI(ai);
+	}
+	auth_freerpc(rpc);
+	close(afd);
+
+	/* try attaching with the afid */
+	chat("attaching as hostowner...");
+	f = newfid(s);
+	s->f.fid = f - s->fids;
+	s->f.afid = af - s->fids;;
+	s->f.uname = getuser();
+	s->f.aname = s->spec;
+	if(xmesg(s, Tattach) == 0)
+		rv = 0;
+out:
+	if(af != nil){
+		putfid(s, af);
+		s->f.fid = af - s->fids;
+		xmesg(s, Tclunk);
+	}
+	if(f != nil){
+		putfid(s, f);
+		s->f.fid = f - s->fids;
+		xmesg(s, Tclunk);
+	}
+
+	return rv;
+}
+

+ 0 - 1
sys/src/cmd/9nfs/dat.h

@@ -238,7 +238,6 @@ struct Session
 	char	schal[CHALLEN];		/* server challenge */
 	char	authid[ANAMELEN];	/* server encryption uid */
 	char	authdom[DOMLEN];	/* server encryption domain */
-	int	count;			/* number of attaches */
 	char *	spec;			/* for attach */
 	Xfile *	root;			/* to answer mount rpc */
 	ushort	tag;

+ 1 - 0
sys/src/cmd/9nfs/fns.h

@@ -1,4 +1,5 @@
 int	auth2unix(Auth*, Authunix*);
+int	authhostowner(Session*);
 int	canlock(Lock*);
 void	chat(char*, ...);
 void	chatsrv(char*);

+ 1 - 0
sys/src/cmd/9nfs/mkfile

@@ -21,6 +21,7 @@ OFILES=chat.$O\
 
 NFSSERVER=9p.$O\
 	auth.$O\
+	authhostowner.$O\
 	nfs.$O\
 	nfsmount.$O\
 	xfile.$O

+ 6 - 23
sys/src/cmd/9nfs/nfsmount.c

@@ -123,31 +123,15 @@ srvinit(int fd, char *file, char *addr)
 	messagesize = IOHDRSZ+s->f.msize;
 	chat("version spec %s size %d\n", s->f.version, s->f.msize);
 
-/*
-	chat("session...");
-	s->tag = NOTAG-1;
-	srand(starttime);
-	for(i = 0; i < CHALLEN; i++)
-		s->cchal[i] = nrand(256);
-	memmove(s->f.chal, s->cchal, CHALLEN);
-	if(xmesg(s, Tsession)){
-		clog("session failed\n");
+	s->tag = 0;
+
+	chat("authenticate...");
+	if(authhostowner(s) < 0){
+		clog("auth failed %r\n");
 		goto error;
 	}
-	memmove(s->schal, s->f.chal, CHALLEN);
-	memmove(s->authid, s->f.authid, NAMELEN);
-	memmove(s->authdom, s->f.authdom, DOMLEN);
 
-	for(i = 0; i < CHALLEN; i++)
-		if(s->schal[i])
-			break;
-	if(i >= CHALLEN || noauth){
-		chat("no schal...");
-		++s->noauth;
-	}
-*/
-	chat("attach...");
-	s->tag = 0;
+	chat("attach as none...");
 	f = newfid(s);
 	s->f.fid = f - s->fids;
 	s->f.afid = ~0x0UL;
@@ -157,7 +141,6 @@ srvinit(int fd, char *file, char *addr)
 		clog("attach failed\n");
 		goto error;
 	}
-	s->count = 1;
 
 	xp = xfile(&s->f.qid, s, 1);
 	s->root = xp;

+ 254 - 38
sys/src/cmd/ip/ipconfig.c

@@ -16,6 +16,8 @@ int	nodhcpwatch;
 int	sendhostname;
 int	dondbconfig = 0;
 
+char	*ndboptions;
+
 Ipifc	*ifc;
 
 // possible verbs
@@ -69,46 +71,154 @@ struct {
 	ulong	timeout;		/* time to timeout - seconds */
 } conf;
 
+enum
+{
+	Taddr,
+	Taddrs,
+	Tstr,
+	Tbyte,
+	Tulong,
+	Tvec,
+};
+
+typedef struct Option Option;
+struct Option
+{
+	char	*name;
+	int	type;
+};
+
+// I was too lazy to look up the types for each of these
+// options.  If someone feels like it, please mail me a
+// corrected array -- presotto
+Option option[256] =
+{
+[OBmask]		{ "ipmask",		Taddr },
+[OBtimeoff]		{ "timeoff",		Tulong },
+[OBrouter]		{ "ipgw",		Taddrs },
+[OBtimeserver]		{ "time",		Taddrs },
+[OBnameserver]		{ "name",		Taddrs },
+[OBdnserver]		{ "dns",		Taddrs },
+[OBlogserver]		{ "log",		Taddrs },
+[OBcookieserver]	{ "cookie",		Taddrs },
+[OBlprserver]		{ "lpr",		Taddrs },
+[OBimpressserver]	{ "impress",		Taddrs },
+[OBrlserver]		{ "rl",			Taddrs },
+[OBhostname]		{ "sys",		Tstr },
+[OBbflen]		{ "bflen",		Tulong },
+[OBdumpfile]		{ "dumpfile",		Tstr },
+[OBdomainname]		{ "dom",		Tstr },
+[OBswapserver]		{ "swap",		Taddrs },
+[OBrootpath]		{ "rootpath",		Tstr },
+[OBextpath]		{ "extpath",		Tstr },
+[OBipforward]		{ "ipforward",		Taddrs },
+[OBnonlocal]		{ "nonlocal",		Taddrs },
+[OBpolicyfilter]	{ "policyfilter",	Taddrs },
+[OBmaxdatagram]		{ "maxdatagram",	Tulong },
+[OBttl]			{ "ttl",		Tulong },
+[OBpathtimeout]		{ "pathtimeout",	Taddrs },
+[OBpathplateau]		{ "pathplateau",	Taddrs },
+[OBmtu]			{ "mtu",		Tulong },
+[OBsubnetslocal]	{ "subnetslocal",	Taddrs },
+[OBbaddr]		{ "baddr",		Taddrs },
+[OBdiscovermask]	{ "discovermask",	Taddrs },
+[OBsupplymask]		{ "supplymask",		Taddrs },
+[OBdiscoverrouter]	{ "discoverrouter",	Taddrs },
+[OBrsserver]		{ "rs",			Taddrs },
+[OBstaticroutes]	{ "staticroutes",	Taddrs },
+[OBtrailerencap]	{ "trailerencap",	Taddrs },
+[OBarptimeout]		{ "arptimeout",		Tulong },
+[OBetherencap]		{ "etherencap",		Taddrs },
+[OBtcpttl]		{ "tcpttl",		Tulong },
+[OBtcpka]		{ "tcpka",		Tulong },
+[OBtcpkag]		{ "tcpkag",		Tulong },
+[OBnisdomain]		{ "nisdomain",		Tstr },
+[OBniserver]		{ "ni",			Taddrs },
+[OBntpserver]		{ "ntp",		Taddrs },
+[OBnetbiosns]		{ "netbiosns",		Taddrs },
+[OBnetbiosdds]		{ "netbiosdds",		Taddrs },
+[OBnetbiostype]		{ "netbiostype",	Taddrs },
+[OBnetbiosscope]	{ "netbiosscope",	Taddrs },
+[OBxfontserver]		{ "xfont",		Taddrs },
+[OBxdispmanager]	{ "xdispmanager",	Taddrs },
+[OBnisplusdomain]	{ "nisplusdomain",	Tstr },
+[OBnisplusserver]	{ "nisplus",		Taddrs },
+[OBhomeagent]		{ "homeagent",		Taddrs },
+[OBsmtpserver]		{ "smtp",		Taddrs },
+[OBpop3server]		{ "pop3",		Taddrs },
+[OBnntpserver]		{ "nntp",		Taddrs },
+[OBwwwserver]		{ "www",		Taddrs },
+[OBfingerserver]	{ "finger",		Taddrs },
+[OBircserver]		{ "irc",		Taddrs },
+[OBstserver]		{ "st",			Taddrs },
+[OBstdaserver]		{ "stdar",		Taddrs },
+
+[ODipaddr]		{ "ipaddr",		Taddr },
+[ODlease]		{ "lease",		Tulong },
+[ODoverload]		{ "overload",		Taddr },
+[ODtype]		{ "type",		Tbyte },
+[ODserverid]		{ "serverid",		Taddr },
+[ODparams]		{ "params",		Tvec },
+[ODmessage]		{ "message",		Tstr },
+[ODmaxmsg]		{ "maxmsg",		Tulong },
+[ODrenewaltime]		{ "renewaltime",	Tulong },
+[ODrebindingtime]	{ "rebindingtime",	Tulong },
+[ODvendorclass]		{ "vendorclass",	Tvec },
+[ODclientid]		{ "clientid",		Tvec },
+[ODtftpserver]		{ "tftp",		Taddr },
+[ODbootfile]		{ "bootfile",		Tstr },
+};
+
+uchar defrequested[] = {
+	OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver,
+};
+
+uchar requested[256];
+int nrequested;
+
 void	adddefroute(char*, uchar*);
+int	addoption(char*);
 void	binddevice(void);
-void	controldevice(void);
 void	bootprequest(void);
+void	controldevice(void);
+void	dhcpquery(int, int);
 void	dhcprecv(void);
 void	dhcpsend(int);
 int	dhcptimer(void);
-void	dhcpquery(int, int);
 void	dhcpwatch(int);
+void	doadd(int);
+void	doremove(void);
+void	dounbind(void);
 int	getndb(void);
+void	getoptions(uchar*);
 int	ipconfig(void);
 void	lookforip(char*);
-uchar	*optadd(uchar*, int, void*, int);
-uchar	*optaddbyte(uchar*, int, int);
-uchar	*optaddulong(uchar*, int, ulong);
-uchar	*optaddaddr(uchar*, int, uchar*);
-uchar	*optaddstr(uchar*, int, char*);
-uchar	*optaddvec(uchar*, int, uchar*, int);
-uchar	*optget(uchar*, int, int*);
-int	optgetbyte(uchar*, int);
-ulong	optgetulong(uchar*, int);
+void	mkclientid(void);
+void	ndbconfig(void);
+int	nipifcs(char*);
+int	openlisten(void);
+uchar*	optadd(uchar*, int, void*, int);
+uchar*	optaddaddr(uchar*, int, uchar*);
+uchar*	optaddbyte(uchar*, int, int);
+uchar*	optaddstr(uchar*, int, char*);
+uchar*	optaddulong(uchar*, int, ulong);
+uchar*	optaddvec(uchar*, int, uchar*, int);
+uchar*	optget(uchar*, int, int*);
 int	optgetaddr(uchar*, int, uchar*);
 int	optgetaddrs(uchar*, int, uchar*, int);
+int	optgetbyte(uchar*, int);
 int	optgetstr(uchar*, int, char*, int);
+ulong	optgetulong(uchar*, int);
 int	optgetvec(uchar*, int, uchar*, int);
-void	mkclientid(void);
-int	nipifcs(char*);
-int	openlisten(void);
+char*	optgetx(uchar*, uchar);
+Bootp*	parsebootp(uchar*, int);
 int	parseoptions(uchar *p, int n);
-Bootp	*parsebootp(uchar*, int);
+int	parseverb(char*);
 void	putndb(void);
 void	tweakservers(void);
-void	writendb(char*, int, int);
 void	usage(void);
 int	validip(uchar*);
-int	parseverb(char*);
-void	doadd(int);
-void	doremove(void);
-void	dounbind(void);
-void	ndbconfig(void);
+void	writendb(char*, int, int);
 
 char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
 
@@ -150,6 +260,10 @@ main(int argc, char **argv)
 	retry = 0;
 	ctll = &firstctl;
 
+	// init set of requested parameters with the default
+	nrequested = sizeof(defrequested);
+	memcpy(requested, defrequested, nrequested);
+
 	ARGBEGIN {
 	case 'D':
 		debug = 1;
@@ -220,6 +334,10 @@ main(int argc, char **argv)
 	case 'X':
 		nodhcpwatch = 1;
 		break;
+	case 'o':
+		if(addoption(ARGF()) < 0)
+			usage();
+		break;
 	} ARGEND;
 
 	// default to any host name we already have
@@ -764,10 +882,6 @@ err:
 	return -1;
 }
 
-uchar requested[] = {
-	OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver,
-};
-
 void
 dhcpsend(int type)
 {
@@ -804,7 +918,7 @@ dhcpsend(int type)
 			n = snprint((char*)vendor, sizeof(vendor), "plan9_%s", conf.cputype);
 			p = optaddvec(p, ODvendorclass, vendor, n);
 		}
-		p = optaddvec(p, ODparams, requested, sizeof(requested));
+		p = optaddvec(p, ODparams, requested, nrequested);
 		if(validip(conf.laddr))
 			p = optaddaddr(p, ODipaddr, conf.laddr);
 		break;
@@ -829,7 +943,7 @@ dhcpsend(int type)
 			n = snprint((char*)vendor, sizeof(vendor), "plan9_%s", conf.cputype);
 			p = optaddvec(p, ODvendorclass, vendor, n);
 		}
-		p = optaddvec(p, ODparams, requested, sizeof(requested));
+		p = optaddvec(p, ODparams, requested, nrequested);
 		if(*conf.hostname && sendhostname)
 			p = optaddstr(p, OBhostname, conf.hostname);
 		break;	
@@ -906,7 +1020,7 @@ dhcprecv(void)
 			fprint(2, "%s: Offer with %lud lease, using %d\n", argv0, lease, MinLease);
 			lease = MinLease;
 		}
-		DEBUG("lease %lud ", lease);
+		DEBUG("lease=%lud ", lease);
 		if(!optgetaddr(bp->optdata, ODserverid, conf.server)) {
 			fprint(2, "%s: Offer from server with invalid serverid\n", argv0);
 			break;
@@ -915,7 +1029,7 @@ dhcprecv(void)
 		v4tov6(conf.laddr, bp->yiaddr);
 		memmove(conf.sname, bp->sname, sizeof(conf.sname));
 		conf.sname[sizeof(conf.sname)-1] = 0;
-		DEBUG("server %I %s\n", conf.server, conf.sname);
+		DEBUG("server=%I sname=%s\n", conf.server, conf.sname);
 		conf.offered = lease;
 		conf.state = Srequesting;
 		dhcpsend(Request);
@@ -939,22 +1053,22 @@ dhcprecv(void)
 			fprint(2, "%s: Ack with %lud lease, using %d\n", argv0, lease, MinLease);
 			lease = MinLease;
 		}
-		DEBUG("lease %lud ", lease);
+		DEBUG("lease=%lud ", lease);
 
 		// address and mask
 		v4tov6(conf.laddr, bp->yiaddr);
 		if(!optgetaddr(bp->optdata, OBmask, conf.mask))
 			ipmove(conf.mask, IPnoaddr);
-		DEBUG("addr %I mask %M ", conf.laddr, conf.mask);
+		DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask);
 
 		// get a router address either from the router option
 		// or from the router that forwarded the dhcp packet
 		if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){
-			DEBUG("router %I ", conf.gaddr);
+			DEBUG("ipgw=%I ", conf.gaddr);
 		} else {
 			if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen) != 0){
 				v4tov6(conf.gaddr, bp->giaddr);
-				DEBUG("giaddr %I ", conf.gaddr);
+				DEBUG("giaddr=%I ", conf.gaddr);
 			}
 		}
 
@@ -963,34 +1077,38 @@ dhcprecv(void)
 		n = optgetaddrs(bp->optdata, OBdnserver, conf.dns,
 				sizeof(conf.dns)/IPaddrlen);
 		for(i = 0; i < n; i++)
-			DEBUG("dns %I ", conf.dns+i*IPaddrlen);
+			DEBUG("dns=%I ", conf.dns+i*IPaddrlen);
 
 		// get ntp servers
 		memset(conf.ntp, 0, sizeof(conf.ntp));
 		n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp,
 				sizeof(conf.ntp)/IPaddrlen);
 		for(i = 0; i < n; i++)
-			DEBUG("ntp %I ", conf.ntp+i*IPaddrlen);
+			DEBUG("ntp=%I ", conf.ntp+i*IPaddrlen);
 
 		// get names
 		optgetstr(bp->optdata, OBhostname, conf.hostname, sizeof(conf.hostname));
 		optgetstr(bp->optdata, OBdomainname, conf.domainname, sizeof(conf.domainname));
 
+		// get anything else we asked for
+		getoptions(bp->optdata);
+
 		// get plan9 specific options
 		n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof(vopts)-1);
 		if(n > 0){
 			if(parseoptions(vopts, n) == 0){
 				n = optgetaddrs(vopts, OP9fs, conf.fs, 2);
 				for(i = 0; i < n; i++)
-					DEBUG("fs %I ", conf.fs+i*IPaddrlen);
+					DEBUG("fs=%I ", conf.fs+i*IPaddrlen);
 				n = optgetaddrs(vopts, OP9auth, conf.auth, 2);
 				for(i = 0; i < n; i++)
-					DEBUG("auth %I ", conf.auth+i*IPaddrlen);
+					DEBUG("auth=%I ", conf.auth+i*IPaddrlen);
 			}
 		}
+
 		conf.lease = lease;
 		conf.state = Sbound;
-		DEBUG("server %I %s\n", conf.server, conf.sname);
+		DEBUG("server=%I sname=%s\n", conf.server, conf.sname);
 		break;
 	case Nak:
 		conf.state = Sinit;
@@ -1355,6 +1473,8 @@ putndb(void)
 		p = putaddrs(p, e, "\tdns", conf.dns, sizeof(conf.dns));
 	if(validip(conf.ntp))
 		p = putaddrs(p, e, "\tntp", conf.ntp, sizeof(conf.ntp));
+	if(ndboptions)
+		p = seprint(p, e, "%s\n", ndboptions);
 	if(p > buf)
 		writendb(buf, p-buf, append);
 }
@@ -1513,3 +1633,99 @@ ndbconfig(void)
 	if(!validip(conf.laddr))
 		sysfatal("address not found in ndb");
 }
+
+int
+addoption(char *opt)
+{
+	Option *o;
+
+	if(opt == nil)
+		return -1;
+	for(o = option; o < &option[nelem(option)]; o++){
+		if(o->name == nil)
+			continue;
+		if(strcmp(opt, o->name) == 0){
+			if(!memchr(requested, (int)opt, nrequested))
+				if(nrequested < nelem(requested))
+					requested[nrequested++] = o-option;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+char*
+optgetx(uchar *p, uchar opt)
+{
+	Option *o;
+	int i, n;
+	ulong x;
+	char *s, *ns;
+	uchar ip[IPaddrlen];
+	uchar ips[16*IPaddrlen];
+	char str[256];
+	uchar vec[256];
+
+	o = &option[opt];
+	if(o->name == nil)
+		return nil;
+
+	s = nil;
+	switch(o->type){
+	case Taddr:
+		if(optgetaddr(p, opt, ip))
+			s = smprint("%s=%I", o->name, ip);
+		break;
+	case Taddrs:
+		n = optgetaddrs(p, opt, ips, 16);
+		if(n > 0)
+			s = smprint("%s=%I", o->name, ips);
+		for(i = 1; i < n; i++){
+			ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]);
+			free(s);
+			s = ns;
+		}
+		break;
+	case Tulong:
+		x = optgetulong(p, opt);
+		if(x != 0)
+			s = smprint("%s=%lud", o->name, x);
+		break;
+	case Tbyte:
+		x = optgetbyte(p, opt);
+		if(x != 0)
+			s = smprint("%s=%lud", o->name, x);
+		break;
+	case Tstr:
+		if(optgetstr(p, opt, str, sizeof(str)))
+			s = smprint("%s=%s", o->name, str);
+		break;
+	case Tvec:
+		n = optgetvec(p, opt, vec, sizeof(vec));
+		if(n > 0)
+			s = smprint("%s=%.*H", o->name, n, vec);
+		break;
+	}
+	return s;
+}
+
+void
+getoptions(uchar *p)
+{
+	int i;
+	char *s, *t;
+
+	for(i = nelem(defrequested); i < nrequested; i++){
+		s = optgetx(p, requested[i]);
+		if(s != nil)
+			DEBUG("%s ", s);
+		if(ndboptions == nil)
+			ndboptions = smprint("\t%s", s);
+		else{
+			t = ndboptions;
+			ndboptions = smprint("\t%s%s", s, ndboptions);
+			free(t);
+		}
+		free(s);
+	}
+}