Browse Source

Plan 9 from Bell Labs 2013-09-17

David du Colombier 10 years ago
parent
commit
6c777e7232

+ 2 - 0
sys/include/libsec.h

@@ -275,6 +275,8 @@ RSApriv*	rsaprivalloc(void);
 void		rsaprivfree(RSApriv*);
 RSApub*		rsaprivtopub(RSApriv*);
 RSApub*		X509toRSApub(uchar*, int, char*, int);
+uchar*		RSApubtoasn1(RSApub*, int*);
+RSApub*		asn1toRSApub(uchar*, int);
 RSApriv*	asn1toRSApriv(uchar*, int);
 void		asn1dump(uchar *der, int len);
 uchar*		decodePEM(char *s, char *type, int *len, char **new_s);

+ 19 - 0
sys/man/2/rsa

@@ -1,6 +1,7 @@
 .TH RSA 2
 .SH NAME
 asn1dump,
+asn1toRSApub,
 asn1toRSApriv,
 decodePEM,
 rsadecrypt,
@@ -11,6 +12,7 @@ rsaprivfree,
 rsaprivtopub,
 rsapuballoc,
 rsapubfree,
+RSApubtoasn1,
 X509toRSApub,
 X509gen,
 X509verify \- RSA encryption algorithm
@@ -52,6 +54,12 @@ RSApub*	rsaprivtopub(RSApriv*)
 RSApub*	X509toRSApub(uchar *cert, int ncert, char *name, int nname)
 .PP
 .B
+RSApub*	asn1toRSApub(uchar *pub, int npub)
+.PP
+.B
+uchar* RSApubtoasn1(RSApub *pub, int *keylen)
+.PP
+.B
 RSApriv*	asn1toRSApriv(uchar *priv, int npriv)
 .PP
 .B
@@ -172,6 +180,17 @@ using the quoting conventions of
 in
 .IR getfields (2).
 .PP
+.I Asn1toRSApub
+converts an ASN1-formatted RSA public key into the corresponding
+.B RSApub
+structure.
+.PP
+.I RSApubtoasn1
+encodes an RSA public key using ASN.1 DER.  It returns a pointer
+to the encoded key; if keylen is non-nil, it sets
+.B *keylen
+to the length of the encoded key.
+.PP
 .I Asn1toRSApriv
 converts an ASN1 formatted RSA private key into the corresponding
 .B RSApriv

+ 36 - 5
sys/man/3/aoe

@@ -141,7 +141,7 @@ Number of consecutive lost jumbograms.
 .TP
 .BI if "n datamtu"
 Incorrect and unused.
-.SS Shelf-and-slot subdirectories
+.SS "Target subdirectories"
 Once configured, each AoE target is accessed via files in the directory named
 for its shelf and slot.  For example, shelf 42, slot 0 would be
 accessed through the path
@@ -154,7 +154,7 @@ The
 file contains the target's AoE configuration string.  Writing to this file
 sets the targets configuration string.
 .PP
-Reading a shelf and slot's
+Reading a target's
 .B ctl
 file returns a list of colon-separated lines
 with the following keywords and values:
@@ -209,6 +209,37 @@ they are being used.
 .I Maxbcount
 should be consulted for this purpose.
 .PP
+Writing to the
+.B ctl
+file, the following commands may be issued:
+.TF identify
+.PD
+.TP
+.B failio
+fail outstanding i/o.
+.TP
+.B identify
+send an ata
+.L "identify device"
+command to the target.
+.TP
+.BI maxbno " n"
+set the maximum number of block sent per
+packet.
+.TP
+.BI mtu  " n"
+set the maximum number of bytes (including
+header) sent per packet.
+.TP
+.B nofail
+never fail this target.  This is useful if your
+root device is on this target.
+.TP
+.BI setsize " n"
+with no arguments, reset the device size to
+the size claimed.  Otherwise, assume the
+device is the given size.
+.PP
 The
 .B data
 file may be read or written like a normal file
@@ -267,14 +298,14 @@ Unused.
 .SH SOURCE
 .B /sys/src/9/port/devaoe.c
 .SH SEE ALSO
-.\" .IR cec (1),
-.\" .IR vblade (1),
+.\" .IR cec (8),
+.\" .IR vblade (8),
 .IR sd (3),
 .IR sdaoe (3),
 .IR aoesrv (8),
 .IR snoopy (8)
 .br
-.BR http://www.coraid.com/documents/AoEr10.txt
+.BR http://support.coraid.com/documents/AoEr11.txt
 .br
 Van Jacobson and Michael J. Karels,
 .IR "``Congestion Avoidance and Control''" ,

+ 2 - 0
sys/man/4/rio

@@ -230,6 +230,8 @@ The commands are
 (restore a hidden window),
 .B current
 (make the window the recipient of keyboard and mouse input),
+.B delete
+(delete the window)
 and
 .B new
 (make a new window).

+ 1 - 0
sys/src/ape/lib/bsd/accept.c

@@ -6,6 +6,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
+#include <sys/stat.h>
 
 /* bsd extensions */
 #include <sys/uio.h>

+ 1 - 0
sys/src/ape/lib/bsd/connect.c

@@ -12,6 +12,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <sys/un.h>
+#include <sys/stat.h>
 
 #include "priv.h"
 

+ 1 - 1
sys/src/ape/lib/bsd/gethostbyname.c

@@ -26,7 +26,7 @@ enum
  *  for inet addresses only
  */
 struct hostent*
-gethostbyname(char *name)
+gethostbyname(const char *name)
 {
 	int i, t, fd, m;
 	char *p, *bp;

+ 1 - 0
sys/src/ape/lib/bsd/getpeername.c

@@ -6,6 +6,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/stat.h>
 
 /* bsd extensions */
 #include <sys/uio.h>

+ 1 - 0
sys/src/ape/lib/bsd/getsockname.c

@@ -6,6 +6,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/stat.h>
 
 /* bsd extensions */
 #include <sys/uio.h>

+ 2 - 2
sys/src/ape/lib/bsd/ntohl.c

@@ -1,5 +1,5 @@
 unsigned long
-ntohl(int x)
+ntohl(unsigned long x)
 {
 	unsigned long n;
 	unsigned char *p;
@@ -24,7 +24,7 @@ htonl(unsigned long h)
 }
 
 unsigned short
-ntohs(int x)
+ntohs(unsigned short x)
 {
 	unsigned short n;
 	unsigned char *p;

+ 6 - 5
sys/src/cmd/postscript/tr2post/readDESC.c

@@ -39,7 +39,8 @@ hash(char *s, int l) {
 }
 
 BOOLEAN
-readDESC(void) {
+readDESC(void)
+{
 	char token[MAXTOKENSIZE];
 	char *descnameformat = "%s/dev%s/DESC";
 	char *descfilename = 0;
@@ -54,7 +55,7 @@ readDESC(void) {
 	sprint(descfilename, descnameformat, FONTDIR, devname);
 	if ((bfd = Bopen(descfilename, OREAD)) == 0) {
 		error(WARNING, "cannot open file %s\n", descfilename);
-		return(0);
+		return 0;
 	}
 	Bfd = &(bfd->Biobufhdr);
 
@@ -81,7 +82,7 @@ readDESC(void) {
 			if (fontmnt <=0) {
 				if (!isdigit(*token)) {
 					error(WARNING, "readdesc: expecting number of fonts in mount table.\n");
-					return(FALSE);
+					return FALSE;
 				}
 				fontmnt = atoi(token) + 1;
 				fontmtab = galloc(fontmtab, fontmnt*sizeof(char *), "readdesc:");
@@ -101,7 +102,7 @@ readDESC(void) {
 			/* device resolution in dots per inch */
 			if (!isdigit(*token)) {
 				error(WARNING, "readdesc: expecting device resolution.\n");
-				return(FALSE);
+				return FALSE;
 			}
 			devres = atoi(token);
 			if (debug) Bprint(Bstderr, "res %d\n", devres);
@@ -136,5 +137,5 @@ readDESC(void) {
 		}
 	}
 	Bterm(Bfd);
-	return(TRUE);
+	return 0;
 }

+ 32 - 19
sys/src/games/music/juke.rc

@@ -9,12 +9,12 @@ host=''
 kb=4096
 flags=()
 sname=$user
-if (! ~ $wide 1) {
+if(! ~ $wide 1){
 	flags=($flags -t)
 	kb=1024
 }
-while(! ~ $#* 0) {
-	switch ($1) {
+while(! ~ $#* 0){
+	switch($1){
 	case -d
 		debug=$2
 		shift
@@ -22,10 +22,13 @@ while(! ~ $#* 0) {
 		tflag='-t'
 	case -h
 		host=$2
+		if(! ~ $snameset yes)
+			sname=$2
 		shift
 	case -w
-		wflags='-w'
+		wflag='-w'
 	case -s
+		snameset=yes
 		sname=$2
 		shift
 	case -*
@@ -34,27 +37,37 @@ while(! ~ $#* 0) {
 	}
 	shift
 }
-if (! test -e /mnt/playlist){
-	if (! ~ $debug '0') echo mounting playlistfs
-	if (! test -e /srv/playlist.$sname && ! ~ $host ''){
-		import -a $host /srv /srv
-	}
-	if (! mount -b /srv/playlist.$sname /mnt >/dev/null >[2]/dev/null){
-		rm -f /srv/playlist.$sname
+if(! test -e /mnt/playlist){
+	if(! ~ $debug 0) echo mounting playlistfs
+	if(~ $sname linux){
+		rm -f /srv/playlist.$sname.$user
 		if (! ~ $debug '0') echo starting playlistfs
-		games/playlistfs -s $sname -d $debug
+		games/playlistfs -s $sname.$user -d $debug
+	}
+	if not {
+		if (! test -e /srv/playlist.$sname && ! ~ $host ''){
+			if (! ~ $debug '0') echo import srv from $host
+			import -a $host /srv /srv
+		}
+		if (! ~ $debug '0') echo mount /srv/playlist.$sname
+		if (! mount -b /srv/playlist.$sname /mnt >/dev/null >[2]/dev/null){
+			rm -f /srv/playlist.$sname
+			if (! ~ $debug '0') echo starting playlistfs
+			games/playlistfs -s $sname -d $debug
+		}
 	}
 }
 if (! test -w /mnt/juke) {
-	if (! test -e /srv/jukefs.$sname && ! ~ $host ''){
+	if (! test -e /srv/jukefs.$host && ! ~ $host ''){
+		if (! ~ $debug '0') echo import srv from $host
 		import -a $host /srv /srv
 	}
-	if (! mount -b /srv/jukefs.$sname /mnt >/dev/null >[2]/dev/null){
+	if (! ~ $debug '0') echo mount /srv/jukefs.$user
+	if (! mount -b /srv/jukefs.$user /mnt >/dev/null >[2]/dev/null){
+	    if (! mount -b /srv/jukefs.$host /mnt >/dev/null >[2]/dev/null){
 		if (! ~ $debug '0') echo games/jukefs
-		games/jukefs -s $sname
+		games/jukefs -s $user
+	    }
 	}
 }
-if (~ $wflags '-w') {
-	exec games/jukebox -w -d $debug $tflag &
-}
-exec games/jukebox -d $debug $tflag
+exec games/jukebox $wflag -d $debug $tflag

+ 7 - 3
sys/src/games/music/jukebox/music.c

@@ -10,6 +10,10 @@
 #include "playlist.h"
 #include "../debug.h"
 
+enum {
+	STACKSIZE = 2048 * sizeof(void*),
+};
+
 int	debug = 0; //DBGSERVER|DBGPUMP|DBGSTATE|DBGPICKLE|DBGPLAY;
 
 char	usage[] = "Usage: %s [-d mask] [-t] [-w]\n";
@@ -1079,10 +1083,10 @@ threadmain(int argc, char *argv[]){
 	playctlfd = open(playctlfile, OWRITE);
 	if(playctlfd < 0)
 		sysfatal("%s: %r", playctlfile);
-	proccreate(playlistproc, nil, 8192);
+	proccreate(playlistproc, nil, STACKSIZE);
 	playevent = chancreate(sizeof(char *), 1);
-	proccreate(playctlproc, playevent, 8192);
-	proccreate(playvolproc, cs->ctl, 8192);
+	proccreate(playctlproc, playevent, STACKSIZE);
+	proccreate(playvolproc, cs->ctl, STACKSIZE);
 
 	work();
 

+ 4 - 0
sys/src/games/music/jukefs/object.h

@@ -1,3 +1,7 @@
+enum {
+	STACKSIZE = 2048 * sizeof(void*),
+};
+
 /* Keywords */
 
 typedef enum {

+ 4 - 4
sys/src/games/music/jukefs/parse.c

@@ -436,7 +436,7 @@ addchild(Object *parent, Object *child, char *where)
 		 */
 		for(i = 0; i < parent->nchildren; i++)
 				if(parent->children[i] == child) return;
-		parent->children = realloc(parent->children, (i+1)*4);
+		parent->children = realloc(parent->children, (i+1)*sizeof child);
 		parent->children[i] = child;
 		parent->nchildren++;
 		if(parent->type == Category && child->type == Category)
@@ -457,7 +457,7 @@ addchild(Object *parent, Object *child, char *where)
 		i = child->ncatparents;
 		if(0) fprint(2, "addcatparent %s parent %d type %d child %d type %d\n",where,
 			parent->tabno, parent->type, child->tabno, child->type);
-		child->catparents = realloc(child->catparents, (i+1)*4);
+		child->catparents = realloc(child->catparents, (i+1)*sizeof parent);
 		child->catparents[i] = parent;
 		child->ncatparents++;
 }
@@ -476,7 +476,7 @@ addcatparent(Object *parent, Object *child)
 //				if(child->catparents[i] == parent) return;
 		i = child->ncatparents;
 		fprint(2, "addcatparent parent %d child %d\n", parent->tabno, child->tabno);
-		child->catparents = realloc(child->catparents, (i+1)*4);
+		child->catparents = realloc(child->catparents, (i+1)*sizeof parent);
 		child->catparents[i] = parent;
 		child->ncatparents++;
 }
@@ -564,7 +564,7 @@ newobject(Type t, Object *parent){
 	}else{
 		if(sotab < notab+1){
 			sotab += 512;
-			otab = realloc(otab, sizeof(Object*)*sotab);
+			otab = realloc(otab, sotab * sizeof o);
 			if(otab == nil)
 				sysfatal("realloc: %r");
 		}

+ 5 - 1
sys/src/games/music/jukefs/server.c

@@ -9,6 +9,8 @@
 #include "catset.h"
 #include "../debug.h"
 
+// #include <pool.h>
+
 char		*user, *mapname, *svrname;
 int		p[2];
 int		mfd[2];
@@ -94,6 +96,8 @@ threadmain(int argc, char *argv[]) {
 	srvname = nil;
 	list = 0;
 
+	// mainmem->flags |= POOL_NOREUSE;
+
 	ARGBEGIN{
 	case 'l':
 		list = 1;
@@ -161,7 +165,7 @@ threadmain(int argc, char *argv[]) {
 	if(debug)
 		fmtinstall('F', fcallfmt);
 
-	procrfork(io, nil, 8192, RFFDG);	//RFNOTEG?
+	procrfork(io, nil, STACKSIZE, RFFDG);	//RFNOTEG?
 
 	close(p[0]);	/* don't deadlock if child fails */
 

+ 1 - 1
sys/src/games/music/mkfile

@@ -1,6 +1,6 @@
 dirs = playlistfs jukefs jukebox
 
-# DEFAULTMAP = /lib/audio/map
+DEFAULTMAP = /lib/audio/map
 ICONPATH = /lib/audio/icon
 
 ICONS = \

+ 5 - 5
sys/src/games/music/playlistfs/fs.c

@@ -718,7 +718,7 @@ allocwork(Req *r)
 	w->eventc = chancreate(sizeof(Wmsg), 1);
 	if(debug & DbgWorker)
 		fprint(2, "new worker 0x%p\n", w);/**/
-	threadcreate(worker, w, 4096);
+	threadcreate(worker, w, STACKSIZE);
 	send(w->eventc, &m);
 }
 
@@ -829,11 +829,11 @@ srv(void*)
 	close(srvfd[1]);
 
 	dispatchc = chancreate(sizeof(Req*), 1);
-	procrfork(srvio, dispatchc, 4096, RFFDG);
+	procrfork(srvio, dispatchc, STACKSIZE, RFFDG);
 
-	threadcreate(volumeupdater, nil, 4096);
-	threadcreate(playupdater, nil, 4096);
-	threadcreate(playlistsrv, nil, 4096);
+	threadcreate(volumeupdater, nil, STACKSIZE);
+	threadcreate(playupdater, nil, STACKSIZE);
+	threadcreate(playlistsrv, nil, STACKSIZE);
 
 	while(r = recvp(dispatchc))
 		allocwork(r);

+ 2 - 2
sys/src/games/music/playlistfs/main.c

@@ -76,10 +76,10 @@ threadmain(int argc, char *argv[])
 
 	if(pipe(srvfd) < 0)
 		sysfatal("pipe failed: %r");
-	procrfork(srv, nil, 8192, RFFDG);
+	procrfork(srv, nil, STACKSIZE, RFFDG);
 	close(srvfd[0]);	/* don't deadlock if child fails */
 
-	procrfork(volumeproc, nil, 8192, RFFDG);
+	procrfork(volumeproc, nil, STACKSIZE, RFFDG);
 	playinit();
 
 	if(srvpost){

+ 3 - 3
sys/src/games/music/playlistfs/player.c

@@ -140,7 +140,7 @@ startplay(ushort n)
 	pfd->filename = file;	/* mallocated already */
 	pfd->fd = fd[1];
 	pfd->cfd = fd[0];
-	procrfork(pac4dec, pfd, 4096, RFFDG);
+	procrfork(pac4dec, pfd, STACKSIZE, RFFDG);
 	close(fd[1]);	/* write fd, for pac4dec */
 	return fd[0];	/* read fd */
 }
@@ -413,8 +413,8 @@ playinit(void)
 		sendp(spare, malloc(sizeof(Pacbuf)));
 
 	playc = chancreate(sizeof(Pmsg), 1);
-	procrfork(pacproc, nil, 32*1024, RFFDG);
-	procrfork(pcmproc, nil, 32*1024, RFFDG);
+	procrfork(pacproc, nil, 8*STACKSIZE, RFFDG);
+	procrfork(pcmproc, nil, 8*STACKSIZE, RFFDG);
 }
 
 char *

+ 1 - 0
sys/src/games/music/playlistfs/playlist.h

@@ -26,6 +26,7 @@ enum {
 };
 
 enum {
+	STACKSIZE = 2048*sizeof(void*),
 	Messagesize = 8*1024+IOHDRSZ,
 	Undef = 0x80000000,
 	/* 256 buffers of 4096 bytes represents 5.9 seconds

+ 9 - 5
sys/src/liboventi/plan9-thread.c

@@ -25,6 +25,7 @@ struct VtLock {
 	int readers;		/* number writering read lock */
 	Thread *qfirst;
 	Thread *qlast;
+	uintptr	pc;
 };
 
 struct VtRendez {
@@ -170,7 +171,7 @@ vtLockAlloc(void)
 }
 
 /*
- * RSC: I think the test is backward.  Let's see who uses it. 
+ * RSC: I think the test is backward.  Let's see who uses it.
  *
 void
 vtLockInit(VtLock **p)
@@ -238,6 +239,7 @@ vtLock(VtLock *p)
 	Thread *t;
 
 	lock(&p->lk);
+	p->pc = getcallerpc(&p);
 	t = *vtRock;
 	if(p->writer == nil && p->readers == 0) {
 		p->writer = t;
@@ -316,7 +318,7 @@ vtUnlock(VtLock *p)
 	 * venti currently has code that assumes lock can be passed between threads :-)
  	 * assert(p->writer == *vtRock);
 	 */
- 	assert(p->writer != nil);   
+ 	assert(p->writer != nil);
 	assert(p->readers == 0);
 	t = p->qfirst;
 	if(t == nil) {
@@ -328,6 +330,7 @@ vtUnlock(VtLock *p)
 		p->qfirst = t->next;
 		p->writer = t;
 		unlock(&p->lk);
+
 		threadWakeup(t);
 		return;
 	}
@@ -337,6 +340,7 @@ vtUnlock(VtLock *p)
 		tt = t;
 		t = t->next;
 		p->readers++;
+
 		threadWakeup(tt);
 	}
 	p->qfirst = t;
@@ -357,7 +361,7 @@ vtRUnlock(VtLock *p)
 		return;
 	}
 	assert(t->state == QueuingW);
-	
+
 	p->qfirst = t->next;
 	p->writer = t;
 	unlock(&p->lk);
@@ -421,7 +425,7 @@ vtWakeup(VtRendez *q)
 	 * put on front so guys that have been waiting will not get starved
 	 */
 	p = q->lk;
-	lock(&p->lk);	
+	lock(&p->lk);
 	/*
 	 * venti currently has code that assumes lock can be passed between threads :-)
  	 * assert(p->writer == *vtRock);
@@ -447,7 +451,7 @@ int
 vtWakeupAll(VtRendez *q)
 {
 	int i;
-	
+
 	for(i=0; vtWakeup(q); i++)
 		;
 	return i;

+ 123 - 1
sys/src/libsec/port/x509.c

@@ -2186,6 +2186,97 @@ X509toRSApub(uchar *cert, int ncert, char *name, int nname)
 	return pk;
 }
 
+int
+getalgo(Elem *e)
+{
+	Value *v;
+	Elist *el;
+	int a;
+
+	if((a = parse_alg(e)) >= 0)
+		return a;
+	v = &e->val;
+	if(v->tag == VSeq){
+		print("Seq\n");
+		for(el = v->u.seqval; el!=nil; el = el->tl){
+			if((a = getalgo(&el->hd)) >= 0)
+				return a;
+		}
+	}
+	return -1;
+}
+
+static void edump(Elem e);
+
+RSApub*
+asn1toRSApub(uchar *der, int nder)
+{
+	Elem e;
+	Elist *el, *l;
+	int n;
+	Bits *b;
+	RSApub *key;
+	mpint *mp;
+
+	if(decode(der, nder, &e) != ASN_OK){
+		print("didn't parse\n");
+		return nil;
+	}
+	if(!is_seq(&e, &el)){
+		print("no seq");
+		return nil;
+	}
+	if((n = elistlen(el)) != 2){
+		print("bad length %d\n", n);
+		return nil;
+	}
+	if((n = getalgo(&el->hd)) < 0){
+		print("no algo\n");
+		return nil;
+	}
+	if(n != 0){
+		print("cant do algorithm %d\n", n);
+		return nil;
+	}
+	if(!is_bitstring(&el->tl->hd, &b)){
+		print("no bits\n");
+		return nil;
+	}
+	if(decode(b->data, b->len, &e) != ASN_OK){
+		print("no second decode\n");
+		return nil;
+	}
+	if(!is_seq(&e, &el)){
+		print("no second seq\n");
+		return nil;
+	}
+	if(elistlen(el) != 2){
+		print("no second length\n");
+		return nil;
+	}
+	key = rsapuballoc();
+
+	l = el;
+
+	key->n = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	el = el->tl;
+	key->ek = mp = asn1mpint(&el->hd);
+	if(mp == nil)
+		goto errret;
+
+	if(l != nil)
+		freeelist(l);
+	return key;
+errret:
+	if(l != nil)
+		freeelist(l);
+	rsapubfree(key);
+	return nil;
+}
+
 char*
 X509verify(uchar *cert, int ncert, RSApub *pk)
 {
@@ -2383,6 +2474,34 @@ mkDN(char *dn)
 	return mkseq(el);
 }
 
+uchar*
+RSApubtoasn1(RSApub *pub, int *keylen)
+{
+	Elem pubkey;
+	Bytes *pkbytes;
+	uchar *key;
+
+	key = nil;
+	pubkey = mkseq(mkel(mkbigint(pub->n),mkel(mkint(mptoi(pub->ek)),nil)));
+	if(encode(pubkey, &pkbytes) != ASN_OK)
+		goto errret;
+	freevalfields(&pubkey.val);
+	pubkey = mkseq(
+		mkel(mkalg(ALG_rsaEncryption),
+		mkel(mkbits(pkbytes->data, pkbytes->len),
+		nil)));
+	freebytes(pkbytes);
+	if(encode(pubkey, &pkbytes) != ASN_OK)
+		goto errret;
+	if(keylen)
+		*keylen = pkbytes->len;
+	key = malloc(pkbytes->len);
+	memmove(key, pkbytes->data, pkbytes->len);
+	free(pkbytes);
+errret:
+	freevalfields(&pubkey.val);
+	return key;
+}
 
 uchar*
 X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
@@ -2564,7 +2683,10 @@ edump(Elem e)
 	case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
 	case VReal: print("Real..."); break;
 	case VOther: print("Other..."); break;
-	case VBitString: print("BitString..."); break;
+	case VBitString: print("BitString");
+		for(i = 0; i<v.u.bitstringval->len; i++)
+			print(" %02x", v.u.bitstringval->data[i]);
+		break;
 	case VNull: print("Null"); break;
 	case VEOC: print("EOC..."); break;
 	case VObjId: print("ObjId");

+ 5 - 1
sys/src/libthread/id.c

@@ -83,7 +83,11 @@ threadsetname(char *fmt, ...)
 char*
 threadgetname(void)
 {
-	return _threadgetproc()->thread->cmdname;
+	Proc *p;
+
+	if((p = _threadgetproc()) && p->thread)
+		return p->thread->cmdname;
+	return nil;
 }
 
 void**