shithub: mc

Download patch

ref: 8c15f1cba546350fd109d676f86c4267bd733b6f
parent: 3324a15b63cd10f880308623cfc27c69b3ed3c59
author: Ori Bernstein <[email protected]>
date: Thu Dec 25 10:59:01 EST 2014

Libstd now builds on plan9.

    It's missing a load of functions, of course, but it buillds.

--- /dev/null
+++ b/libstd/dial+posixy.myr
@@ -1,0 +1,142 @@
+use "alloc.use"
+use "chartype.use"
+use "die.use"
+use "endian.use"
+use "fmt.use"
+use "hasprefix.use"
+use "intparse.use"
+use "ipparse.use"
+use "option.use"
+use "resolve.use"
+use "result.use"
+use "sleq.use"
+use "strfind.use"
+use "sys.use"
+use "syswrap.use"
+use "utf.use"
+
+pkg std =
+	const dial	: (dialstr : byte[:] -> result(fd, byte[:]))
+;;
+
+/*
+ a map from service name to a list of (port,proto)
+ pairs in order of preference
+*/
+/* FIXME: implement
+var services : htab(byte[:], [int, byte[:]][:])#
+var inited = false
+*/
+
+/* takes a plan 9 style dial string */
+const dial = {str
+	var proto, host, port
+	var sa : sys.sockaddr_in	/* we only support inet sockets right now.. ugh. */
+	var sock
+
+	match parsedial(str)
+	| `Ok val:	(proto, host, port) = val
+	| `Fail m:	-> `Fail m
+	;;
+
+	match getaddr(host)
+	| `Ipv4 bits:
+		sa.fam = sys.Afinet
+		sa.addr = bits
+		sa.port = hosttonet(port)
+	| `Ipv6 bits:
+		-> `Fail "ipv6 not yet supported"
+	;;
+
+	sock = sys.socket(sa.fam, proto, 0)
+	if sock < 0
+		-> `Fail "failed to connect to socket"
+	;;
+	var err
+	err = sys.connect(sock, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in))
+	if err < 0
+		put("Errno %i\n", -err)
+		sys.close(sock)
+		-> `Fail "Failed to bind socket"
+	;;
+
+	-> `Ok (sock castto(fd))
+}
+
+const parsedial = {str
+	var proto, host, port
+	var socktype, portnum
+
+	(proto, str) = nameseg(str)
+	(host, str) = nameseg(str)
+	(port, str) = nameseg(str)
+
+	if proto.len == 0
+		-> `Fail "missing proto"
+	elif host.len == 0
+		-> `Fail "missing host"
+	elif port.len == 0
+		-> `Fail "missing port"
+	;;
+
+	if sleq(proto, "net")
+		-> `Fail "net wildcard proto not yet supported\n"
+	elif sleq(proto, "unix")
+		-> `Fail "net unix proto not yet supported\n"
+	elif sleq(proto, "tcp")
+		socktype = sys.Sockstream
+	elif sleq(proto, "udp")
+		socktype = sys.Sockdgram
+	;;
+
+	match parseport(port)
+	| `Some n:	portnum = n
+	| `None:	-> `Fail "bad port"
+	;;
+
+	-> `Ok (socktype, host, portnum)
+}
+
+const parseport = {port
+	match intparse(port)
+	| `Some n:	-> `Some n
+	| `None:
+		/* a small number of hardcoded ports */
+		if sleq(port, "http")
+			-> `Some 80
+		elif sleq(port, "https")
+			-> `Some 443
+		elif sleq(port, "ircd")
+			-> `Some 6667
+		elif sleq(port, "dns")
+			-> `Some 53
+		;;
+	;;
+	-> `None
+}
+
+const getaddr = {addr
+	var ip
+
+	match ipparse(addr)
+	| `Some a:	ip = a
+	| `None:
+		match resolve(addr)
+		| `Ok hi:
+			ip = hi[0].addr
+			slfree(hi)
+		| `Fail m:
+		;;
+	;;
+	-> ip
+}
+
+const nameseg = {str
+	match strfind(str, "!")
+	| `Some idx:
+		-> (str[:idx], str[idx+1:])
+	| `None:
+		-> (str, "")
+	;;
+}
+
--- a/libstd/dial.myr
+++ b/libstd/dial.myr
@@ -1,142 +1,0 @@
-use "alloc.use"
-use "chartype.use"
-use "die.use"
-use "endian.use"
-use "fmt.use"
-use "hasprefix.use"
-use "intparse.use"
-use "ipparse.use"
-use "option.use"
-use "resolve.use"
-use "result.use"
-use "sleq.use"
-use "strfind.use"
-use "sys.use"
-use "syswrap.use"
-use "utf.use"
-
-pkg std =
-	const dial	: (dialstr : byte[:] -> result(fd, byte[:]))
-;;
-
-/*
- a map from service name to a list of (port,proto)
- pairs in order of preference
-*/
-/* FIXME: implement
-var services : htab(byte[:], [int, byte[:]][:])#
-var inited = false
-*/
-
-/* takes a plan 9 style dial string */
-const dial = {str
-	var proto, host, port
-	var sa : sys.sockaddr_in	/* we only support inet sockets right now.. ugh. */
-	var sock
-
-	match parsedial(str)
-	| `Ok val:	(proto, host, port) = val
-	| `Fail m:	-> `Fail m
-	;;
-
-	match getaddr(host)
-	| `Ipv4 bits:
-		sa.fam = sys.Afinet
-		sa.addr = bits
-		sa.port = hosttonet(port)
-	| `Ipv6 bits:
-		-> `Fail "ipv6 not yet supported"
-	;;
-
-	sock = sys.socket(sa.fam, proto, 0)
-	if sock < 0
-		-> `Fail "failed to connect to socket"
-	;;
-	var err
-	err = sys.connect(sock, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in))
-	if err < 0
-		put("Errno %i\n", -err)
-		sys.close(sock)
-		-> `Fail "Failed to bind socket"
-	;;
-
-	-> `Ok (sock castto(fd))
-}
-
-const parsedial = {str
-	var proto, host, port
-	var socktype, portnum
-
-	(proto, str) = nameseg(str)
-	(host, str) = nameseg(str)
-	(port, str) = nameseg(str)
-
-	if proto.len == 0
-		-> `Fail "missing proto"
-	elif host.len == 0
-		-> `Fail "missing host"
-	elif port.len == 0
-		-> `Fail "missing port"
-	;;
-
-	if sleq(proto, "net")
-		-> `Fail "net wildcard proto not yet supported\n"
-	elif sleq(proto, "unix")
-		-> `Fail "net unix proto not yet supported\n"
-	elif sleq(proto, "tcp")
-		socktype = sys.Sockstream
-	elif sleq(proto, "udp")
-		socktype = sys.Sockdgram
-	;;
-
-	match parseport(port)
-	| `Some n:	portnum = n
-	| `None:	-> `Fail "bad port"
-	;;
-
-	-> `Ok (socktype, host, portnum)
-}
-
-const parseport = {port
-	match intparse(port)
-	| `Some n:	-> `Some n
-	| `None:
-		/* a small number of hardcoded ports */
-		if sleq(port, "http")
-			-> `Some 80
-		elif sleq(port, "https")
-			-> `Some 443
-		elif sleq(port, "ircd")
-			-> `Some 6667
-		elif sleq(port, "dns")
-			-> `Some 53
-		;;
-	;;
-	-> `None
-}
-
-const getaddr = {addr
-	var ip
-
-	match ipparse(addr)
-	| `Some a:	ip = a
-	| `None:
-		match resolve(addr)
-		| `Ok hi:
-			ip = hi[0].addr
-			slfree(hi)
-		| `Fail m:
-		;;
-	;;
-	-> ip
-}
-
-const nameseg = {str
-	match strfind(str, "!")
-	| `Some idx:
-		-> (str[:idx], str[idx+1:])
-	| `None:
-		-> (str, "")
-	;;
-}
-
--- /dev/null
+++ b/libstd/env+plan9.myr
@@ -1,0 +1,18 @@
+use sys
+
+use "extremum.use"
+use "option.use"
+use "sleq.use"
+
+pkg std =
+	const getenv :	(name : byte[:] -> option(byte[:]))
+	const getenvv :	(name : byte[:], default : byte[:] -> byte[:])
+;;
+
+const getenv = {name
+	-> `None
+}
+
+const getenvv = {name, default
+	-> default
+}
--- /dev/null
+++ b/libstd/env+posixy.myr
@@ -1,0 +1,28 @@
+use sys
+
+use "extremum.use"
+use "option.use"
+use "sleq.use"
+
+pkg std =
+	const getenv :	(name : byte[:] -> option(byte[:]))
+	const getenvv :	(name : byte[:], default : byte[:] -> byte[:])
+;;
+
+const getenv = {name
+	var n
+	for env in sys.__environment
+		n = min(name.len, env.len)
+		if sleq(name, env[:n]) && sleq(env[n:n+1], "=")
+			-> `Some env[n+1:]
+		;;
+	;;
+	-> `None
+}
+
+const getenvv = {name, default
+	match getenv(name)
+	| `Some v:	-> v
+	| `None:	-> default
+	;;
+}
--- a/libstd/env.myr
+++ b/libstd/env.myr
@@ -10,19 +10,9 @@
 ;;
 
 const getenv = {name
-	var n
-	for env in sys.__environment
-		n = min(name.len, env.len)
-		if sleq(name, env[:n]) && sleq(env[n:n+1], "=")
-			-> `Some env[n+1:]
-		;;
-	;;
 	-> `None
 }
 
 const getenvv = {name, default
-	match getenv(name)
-	| `Some v:	-> v
-	| `None:	-> default
-	;;
+	-> default
 }
--- a/libstd/mkfile
+++ b/libstd/mkfile
@@ -67,7 +67,7 @@
 	varargs.myr \
 	waitstatus.myr \
 
-all: lib$STDLIB.a lib$SYSLIB.a
+all:V: lib$STDLIB.a lib$SYSLIB.a
 
 lib$STDLIB.a: $STDSRC $ASMSRC lib$SYSLIB.a
 	../myrbuild/$O.out -I. -C../6/$O.out -M../muse/$O.out -l $STDLIB $STDSRC $STDASMSRC
--- a/libstd/now.myr
+++ b/libstd/now.myr
@@ -1,7 +1,5 @@
-use sys
-
 use "types.use"
-use "fmt.use"
+use "syswrap.use"
 
 pkg std =
 	const now	: (-> time)
@@ -9,15 +7,5 @@
 
 /* microseconds since epoch */
 const now = {
-	var tm
-	var sec
-	var nsec
-
-	if sys.clock_gettime(`sys.Clockrealtime, &tm) == 0
-		sec = tm.sec
-		nsec = tm.nsec castto(uint64)
-		-> (sec*1_000_000 + nsec/1000) castto(time)
-	else
-		-> -1
-	;;
+	-> curtime()
 }
--- /dev/null
+++ b/libstd/resolve+posixy.myr
@@ -1,0 +1,446 @@
+use sys
+use "alloc.use"
+use "chartype.use"
+use "die.use"
+use "endian.use"
+use "result.use"
+use "extremum.use"
+use "fmt.use"
+use "hashfuncs.use"
+use "htab.use"
+use "ipparse.use"
+use "option.use"
+use "slcp.use"
+use "sleq.use"
+use "slpush.use"
+use "slurp.use"
+use "strfind.use"
+use "strsplit.use"
+use "strstrip.use"
+use "types.use"
+use "utf.use"
+
+pkg std =
+	type rectype = uint16
+
+	const DnsA	: rectype = 1  /* host address */
+	const DnsNS	: rectype = 2  /* authoritative name server */
+	const DnsMD	: rectype = 3  /* mail destination (Obsolete - use MX) */
+	const DnsMF	: rectype = 4  /* mail forwarder (Obsolete - use MX) */
+	const DnsCNAME	: rectype = 5  /* canonical name for an alias */
+	const DnsSOA	: rectype = 6  /* marks the start of a zone of authority */
+	const DnsMB	: rectype = 7  /* mailbox domain name (EXPERIMENTAL) */
+	const DnsMG	: rectype = 8  /* mail group member (EXPERIMENTAL) */
+	const DnsMR	: rectype = 9  /* mail rename domain name (EXPERIMENTAL) */
+	const DnsNULL	: rectype = 10 /* null RR (EXPERIMENTAL) */
+	const DnsWKS	: rectype = 11 /* well known service description */
+	const DnsPTR	: rectype = 12 /* domain name pointer */
+	const DnsHINFO	: rectype = 13 /* host information */
+	const DnsMINFO	: rectype = 14 /* mailbox or mail list information */
+	const DnsMX	: rectype = 15 /* mail exchange */
+	const DnsTXT	: rectype = 16 /* text strings */
+	const DnsAAAA	: rectype = 28 /* ipv6 host address */
+
+
+	type resolveerr = union
+		`Badhost
+		`Badsrv
+		`Badquery
+		`Badresp
+	;;
+
+	type hostinfo = struct
+		fam	: sys.sockfam
+		stype	: sys.socktype
+		ttl	: uint32
+		addr	: netaddr
+	/*
+		flags	: uint32
+		addr	: sockaddr[:]
+		canon	: byte[:]
+	*/
+	;;
+
+	const resolve	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+	const resolvemx	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+	const resolverec	: (host : byte[:], t : rectype	-> result(hostinfo[:], resolveerr))
+;;
+
+const Hostfile = "/etc/hosts"
+const Resolvfile = "/etc/resolv.conf"
+
+var hostmap	: htab(byte[:], hostinfo)#
+var search	: byte[:][:]
+var nameservers	: netaddr[:]
+var inited	: bool = false
+
+
+const resolve = {host
+	-> resolverec(host, DnsA)
+}
+
+const resolvemx = {host
+	-> resolverec(host, DnsMX)
+}
+
+const resolverec = {host, t
+	match hostfind(host)
+	| `Some hinf:
+		-> `Ok slpush([][:], hinf)
+	| `None:
+		-> dnsresolve(host, DnsA)
+	;;
+}
+
+const hostfind = {host
+	if !inited
+		hostmap = mkht(strhash, streq)
+		loadhosts()
+		loadresolv()
+		inited = true
+	;;
+	-> htget(hostmap, host)
+}
+
+const loadhosts = {
+	var h
+	var lines
+
+	match slurp(Hostfile)
+	| `Ok d:	h = d
+	| `Fail m:	->
+	;;
+
+	lines = strsplit(h, "\n")
+	for l in lines
+		/* trim comment */
+		match strfind(l, "#")
+		| `Some idx:	l = l[:idx]
+		| `None:	/* whole line */
+		;;
+
+		match word(l)
+		| `Some (ip, rest):
+			match ipparse(ip)
+			| `Some addr:
+				addhosts(addr, ip, rest)
+			| `None:
+				/*
+				invalid addresses are ignored: we don't want to break stuff
+				with invalid or unsupported addresses
+				*/
+				
+			;;
+		| `None:
+		;;
+	;;
+	slfree(lines)
+}
+
+const addhosts = {addr, as, str
+	var hinf
+	var fam
+
+	match addr
+	| `Ipv4 _:	fam = sys.Afinet
+	| `Ipv6 _:	fam = sys.Afinet6
+	;;
+	while true
+		match word(str)
+		| `Some (name, rest):
+			if hthas(hostmap, name)
+				continue
+			;;
+			hinf = [
+				.fam=fam,
+				.stype = 0,
+				.ttl = 0,
+				.addr = addr
+			]
+			htput(hostmap, name, hinf)
+			str = rest
+		| `None:
+			->
+		;;
+	;;
+}
+
+const loadresolv = {
+	var h
+	var lines
+
+	match slurp(Resolvfile)
+	| `Ok d:	h = d
+	| `Fail m:	->
+	;;
+
+	lines = strsplit(h, "\n")
+	for l in lines
+		match strfind(l, "#")
+		| `Some _idx: l = l[:_idx]
+		| `None:
+		;;
+
+		match word(l)
+		| `Some ("nameserver", srv):
+			addns(srv)
+		| `Some (_, rest):
+			/* invalid or unrecognized commands */
+		| `None:
+			/* unrecognized lines */
+		;;
+	;;
+	slfree(lines)
+}
+
+const addns = {rest
+	match word(rest)
+	| `Some (name, _):
+		match ipparse(name)
+		| `Some addr: 
+			nameservers = slpush(nameservers, addr)
+		| `None:
+			/* nothing */
+		;;
+	| `None:
+		/* nothing */
+	;;
+}
+
+const word = {s
+	var c, len
+
+	len = 0
+	s = strfstrip(s)
+	for c = decode(s[len:]); c != Badchar && !isblank(c); c = decode(s[len:])
+		len += charlen(c)
+	;;
+	if len == 0
+		-> `None
+	else
+		-> `Some (s[:len], s[len:])
+	;;
+}
+
+
+const dnsresolve = {host, t
+	var nsrv
+
+	if !valid(host)
+		-> `Fail (`Badhost)
+	;;
+	for ns in nameservers
+		nsrv = dnsconnect(ns)
+		if nsrv >= 0
+			-> dnsquery(nsrv, host, t)
+		;;
+	;;
+	-> `Fail (`Badsrv)
+}
+
+const dnsconnect = {ns
+	match ns
+	| `Ipv4 addr:	-> dnsconnectv4(addr)
+	| `Ipv6 addr:	die("don't support ipv6 yet\n")
+	;;
+}
+
+const dnsconnectv4 = {addr
+	var sa : sys.sockaddr_in
+	var s
+	var status
+
+	s = sys.socket(sys.Afinet, sys.Sockdgram, 0)
+	if s < 0
+		-> -1
+	;;
+	sa.fam = sys.Afinet
+	sa.port = hosttonet(53)
+	sa.addr = addr
+	status = sys.connect(s, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in))
+	if status < 0
+		-> -1
+	;;
+	-> s
+}
+
+const dnsquery = {srv, host, t
+	var id
+	var r
+
+	id = tquery(srv, host, t)
+	r = rquery(srv, id)
+	-> r
+}
+
+const Qr : uint16 = 1 << 0
+const Aa : uint16 = 1 << 5
+const Tc : uint16 = 1 << 6
+const Rd : uint16 = 1 << 7
+const Ra : uint16 = 1 << 8
+
+var nextid : uint16 = 42
+const tquery = {srv, host, t
+	var pkt : byte[512] /* big enough */
+	var off : size
+
+	/* header */
+	off = 0
+	off += pack16(pkt[:], off, nextid)	/* id */
+	off += pack16(pkt[:], off, Ra)	/* flags */
+	off += pack16(pkt[:], off, 1)	/* qdcount */
+	off += pack16(pkt[:], off, 0)	/* ancount */
+	off += pack16(pkt[:], off, 0)	/* nscount */
+	off += pack16(pkt[:], off, 0)	/* arcount */
+
+	/* query */
+	off += packname(pkt[:], off, host)	/* host */
+	off += pack16(pkt[:], off, t castto(uint16)) /* qtype: a record */
+	off += pack16(pkt[:], off, 0x1) /* qclass: inet4 */
+
+	sys.write(srv, pkt[:off])
+	-> nextid++
+}
+
+const rquery = {srv, id
+	var pktbuf : byte[1024]
+	var pkt
+	var n
+
+	n = sys.read(srv, pktbuf[:])
+	if n < 0
+	;;
+	pkt = pktbuf[:n]
+	-> hosts(pkt, id)
+}
+
+const hosts = {pkt, id : uint16
+	var off
+	var v, q, a
+	var i
+	var hinf : hostinfo[:]
+
+	off = 0
+	/* parse header */
+	(v, off) = unpack16(pkt, off)	/* id */
+	if v != id
+		-> `Fail (`Badresp)
+	;;
+	(v, off) = unpack16(pkt, off)	/* flags */
+	(q, off) = unpack16(pkt, off)	/* qdcount */
+	(a, off) = unpack16(pkt, off)	/* ancount */
+	(v, off) = unpack16(pkt, off)	/* nscount */
+	(v, off) = unpack16(pkt, off)	/* arcount */
+
+	/* skip past query records */
+	for i = 0; i < q; i++
+		off = skipname(pkt, off)	/* name */
+		(v, off) = unpack16(pkt, off)	/* type */
+		(v, off) = unpack16(pkt, off)	/* class */
+	;;
+
+	/* parse answer records */
+	hinf = slalloc(a castto(size))
+	for i = 0; i < a; i++
+		off = skipname(pkt, off)	/* name */
+		(v, off) = unpack16(pkt, off)	/* type */
+		(v, off) = unpack16(pkt, off)	/* class */
+		(hinf[i].ttl, off) = unpack32(pkt, off)	/* ttl */
+		(v, off) = unpack16(pkt, off)	/* rdatalen */
+		/* the thing we're interested in: our IP address */
+		hinf[i].addr = `Ipv4 [pkt[off], pkt[off+1], pkt[off+2], pkt[off+3]]
+		off += 4;
+	;;
+	-> `Ok hinf
+}
+
+
+const skipname = {pkt, off
+	var sz
+
+	for sz = pkt[off] castto(size); sz != 0; sz = pkt[off] castto(size)
+		/* ptr is 2 bytes */
+		if sz & 0xC0 == 0xC0
+			-> off + 2
+		else
+			off += sz + 1
+		;;
+	;;
+	-> off + 1
+}
+
+
+const pack16 = {buf, off, v
+	buf[off]	= (v & 0xff00) >> 8 castto(byte)
+	buf[off+1]	= (v & 0x00ff) castto(byte)
+	-> sizeof(uint16) /* we always write one uint16 */
+}
+
+const unpack16 = {buf, off
+	var v
+
+	v = (buf[off] castto(uint16)) << 8
+	v |= (buf[off + 1] castto(uint16))
+	-> (v, off+sizeof(uint16))
+}
+
+const unpack32 = {buf, off
+	var v
+
+	v = (buf[off] castto(uint32)) << 24
+	v |= (buf[off+1] castto(uint32)) << 32
+	v |= (buf[off+2] castto(uint32)) << 8
+	v |= (buf[off+3] castto(uint32))
+	-> (v, off+sizeof(uint32))
+}
+
+const packname = {buf, off : size, host
+	var i
+	var start
+	var last
+
+	start = off
+	last = 0
+	for i = 0; i < host.len; i++
+		if host[i] == ('.' castto(byte))
+			off += addseg(buf, off, host[last:i])
+			last = i + 1
+		;;
+	;;
+	if host[host.len - 1] != ('.' castto(byte))
+		off += addseg(buf, off, host[last:])
+	;;
+	off += addseg(buf, off, "") /* null terminating segment */
+	-> off - start
+}
+
+const addseg = {buf, off, str
+	buf[off] = str.len castto(byte)
+	slcp(buf[off + 1 : off + str.len + 1], str)
+	-> str.len + 1
+}
+
+const valid = {host : byte[:]
+	var i
+	var seglen
+
+	/* maximum length: 255 chars */
+	if host.len > 255
+		-> false
+	;;
+
+	seglen = 0
+	for i = 0; i < host.len; i++
+		if host[i] == ('.' castto(byte))
+			seglen = 0
+		;;
+		if seglen > 63
+			-> false
+		;;
+		if host[i] & 0x80 != 0
+			-> false
+		;;
+	;;
+
+	-> true
+}
--- a/libstd/resolve.myr
+++ b/libstd/resolve.myr
@@ -1,446 +1,0 @@
-use sys
-use "alloc.use"
-use "chartype.use"
-use "die.use"
-use "endian.use"
-use "result.use"
-use "extremum.use"
-use "fmt.use"
-use "hashfuncs.use"
-use "htab.use"
-use "ipparse.use"
-use "option.use"
-use "slcp.use"
-use "sleq.use"
-use "slpush.use"
-use "slurp.use"
-use "strfind.use"
-use "strsplit.use"
-use "strstrip.use"
-use "types.use"
-use "utf.use"
-
-pkg std =
-	type rectype = uint16
-
-	const DnsA	: rectype = 1  /* host address */
-	const DnsNS	: rectype = 2  /* authoritative name server */
-	const DnsMD	: rectype = 3  /* mail destination (Obsolete - use MX) */
-	const DnsMF	: rectype = 4  /* mail forwarder (Obsolete - use MX) */
-	const DnsCNAME	: rectype = 5  /* canonical name for an alias */
-	const DnsSOA	: rectype = 6  /* marks the start of a zone of authority */
-	const DnsMB	: rectype = 7  /* mailbox domain name (EXPERIMENTAL) */
-	const DnsMG	: rectype = 8  /* mail group member (EXPERIMENTAL) */
-	const DnsMR	: rectype = 9  /* mail rename domain name (EXPERIMENTAL) */
-	const DnsNULL	: rectype = 10 /* null RR (EXPERIMENTAL) */
-	const DnsWKS	: rectype = 11 /* well known service description */
-	const DnsPTR	: rectype = 12 /* domain name pointer */
-	const DnsHINFO	: rectype = 13 /* host information */
-	const DnsMINFO	: rectype = 14 /* mailbox or mail list information */
-	const DnsMX	: rectype = 15 /* mail exchange */
-	const DnsTXT	: rectype = 16 /* text strings */
-	const DnsAAAA	: rectype = 28 /* ipv6 host address */
-
-
-	type resolveerr = union
-		`Badhost
-		`Badsrv
-		`Badquery
-		`Badresp
-	;;
-
-	type hostinfo = struct
-		fam	: sys.sockfam
-		stype	: sys.socktype
-		ttl	: uint32
-		addr	: netaddr
-	/*
-		flags	: uint32
-		addr	: sockaddr[:]
-		canon	: byte[:]
-	*/
-	;;
-
-	const resolve	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
-	const resolvemx	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
-	const resolverec	: (host : byte[:], t : rectype	-> result(hostinfo[:], resolveerr))
-;;
-
-const Hostfile = "/etc/hosts"
-const Resolvfile = "/etc/resolv.conf"
-
-var hostmap	: htab(byte[:], hostinfo)#
-var search	: byte[:][:]
-var nameservers	: netaddr[:]
-var inited	: bool = false
-
-
-const resolve = {host
-	-> resolverec(host, DnsA)
-}
-
-const resolvemx = {host
-	-> resolverec(host, DnsMX)
-}
-
-const resolverec = {host, t
-	match hostfind(host)
-	| `Some hinf:
-		-> `Ok slpush([][:], hinf)
-	| `None:
-		-> dnsresolve(host, DnsA)
-	;;
-}
-
-const hostfind = {host
-	if !inited
-		hostmap = mkht(strhash, streq)
-		loadhosts()
-		loadresolv()
-		inited = true
-	;;
-	-> htget(hostmap, host)
-}
-
-const loadhosts = {
-	var h
-	var lines
-
-	match slurp(Hostfile)
-	| `Ok d:	h = d
-	| `Fail m:	->
-	;;
-
-	lines = strsplit(h, "\n")
-	for l in lines
-		/* trim comment */
-		match strfind(l, "#")
-		| `Some idx:	l = l[:idx]
-		| `None:	/* whole line */
-		;;
-
-		match word(l)
-		| `Some (ip, rest):
-			match ipparse(ip)
-			| `Some addr:
-				addhosts(addr, ip, rest)
-			| `None:
-				/*
-				invalid addresses are ignored: we don't want to break stuff
-				with invalid or unsupported addresses
-				*/
-				
-			;;
-		| `None:
-		;;
-	;;
-	slfree(lines)
-}
-
-const addhosts = {addr, as, str
-	var hinf
-	var fam
-
-	match addr
-	| `Ipv4 _:	fam = sys.Afinet
-	| `Ipv6 _:	fam = sys.Afinet6
-	;;
-	while true
-		match word(str)
-		| `Some (name, rest):
-			if hthas(hostmap, name)
-				continue
-			;;
-			hinf = [
-				.fam=fam,
-				.stype = 0,
-				.ttl = 0,
-				.addr = addr
-			]
-			htput(hostmap, name, hinf)
-			str = rest
-		| `None:
-			->
-		;;
-	;;
-}
-
-const loadresolv = {
-	var h
-	var lines
-
-	match slurp(Resolvfile)
-	| `Ok d:	h = d
-	| `Fail m:	->
-	;;
-
-	lines = strsplit(h, "\n")
-	for l in lines
-		match strfind(l, "#")
-		| `Some _idx: l = l[:_idx]
-		| `None:
-		;;
-
-		match word(l)
-		| `Some ("nameserver", srv):
-			addns(srv)
-		| `Some (_, rest):
-			/* invalid or unrecognized commands */
-		| `None:
-			/* unrecognized lines */
-		;;
-	;;
-	slfree(lines)
-}
-
-const addns = {rest
-	match word(rest)
-	| `Some (name, _):
-		match ipparse(name)
-		| `Some addr: 
-			nameservers = slpush(nameservers, addr)
-		| `None:
-			/* nothing */
-		;;
-	| `None:
-		/* nothing */
-	;;
-}
-
-const word = {s
-	var c, len
-
-	len = 0
-	s = strfstrip(s)
-	for c = decode(s[len:]); c != Badchar && !isblank(c); c = decode(s[len:])
-		len += charlen(c)
-	;;
-	if len == 0
-		-> `None
-	else
-		-> `Some (s[:len], s[len:])
-	;;
-}
-
-
-const dnsresolve = {host, t
-	var nsrv
-
-	if !valid(host)
-		-> `Fail (`Badhost)
-	;;
-	for ns in nameservers
-		nsrv = dnsconnect(ns)
-		if nsrv >= 0
-			-> dnsquery(nsrv, host, t)
-		;;
-	;;
-	-> `Fail (`Badsrv)
-}
-
-const dnsconnect = {ns
-	match ns
-	| `Ipv4 addr:	-> dnsconnectv4(addr)
-	| `Ipv6 addr:	die("don't support ipv6 yet\n")
-	;;
-}
-
-const dnsconnectv4 = {addr
-	var sa : sys.sockaddr_in
-	var s
-	var status
-
-	s = sys.socket(sys.Afinet, sys.Sockdgram, 0)
-	if s < 0
-		-> -1
-	;;
-	sa.fam = sys.Afinet
-	sa.port = hosttonet(53)
-	sa.addr = addr
-	status = sys.connect(s, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in))
-	if status < 0
-		-> -1
-	;;
-	-> s
-}
-
-const dnsquery = {srv, host, t
-	var id
-	var r
-
-	id = tquery(srv, host, t)
-	r = rquery(srv, id)
-	-> r
-}
-
-const Qr : uint16 = 1 << 0
-const Aa : uint16 = 1 << 5
-const Tc : uint16 = 1 << 6
-const Rd : uint16 = 1 << 7
-const Ra : uint16 = 1 << 8
-
-var nextid : uint16 = 42
-const tquery = {srv, host, t
-	var pkt : byte[512] /* big enough */
-	var off : size
-
-	/* header */
-	off = 0
-	off += pack16(pkt[:], off, nextid)	/* id */
-	off += pack16(pkt[:], off, Ra)	/* flags */
-	off += pack16(pkt[:], off, 1)	/* qdcount */
-	off += pack16(pkt[:], off, 0)	/* ancount */
-	off += pack16(pkt[:], off, 0)	/* nscount */
-	off += pack16(pkt[:], off, 0)	/* arcount */
-
-	/* query */
-	off += packname(pkt[:], off, host)	/* host */
-	off += pack16(pkt[:], off, t castto(uint16)) /* qtype: a record */
-	off += pack16(pkt[:], off, 0x1) /* qclass: inet4 */
-
-	sys.write(srv, pkt[:off])
-	-> nextid++
-}
-
-const rquery = {srv, id
-	var pktbuf : byte[1024]
-	var pkt
-	var n
-
-	n = sys.read(srv, pktbuf[:])
-	if n < 0
-	;;
-	pkt = pktbuf[:n]
-	-> hosts(pkt, id)
-}
-
-const hosts = {pkt, id : uint16
-	var off
-	var v, q, a
-	var i
-	var hinf : hostinfo[:]
-
-	off = 0
-	/* parse header */
-	(v, off) = unpack16(pkt, off)	/* id */
-	if v != id
-		-> `Fail (`Badresp)
-	;;
-	(v, off) = unpack16(pkt, off)	/* flags */
-	(q, off) = unpack16(pkt, off)	/* qdcount */
-	(a, off) = unpack16(pkt, off)	/* ancount */
-	(v, off) = unpack16(pkt, off)	/* nscount */
-	(v, off) = unpack16(pkt, off)	/* arcount */
-
-	/* skip past query records */
-	for i = 0; i < q; i++
-		off = skipname(pkt, off)	/* name */
-		(v, off) = unpack16(pkt, off)	/* type */
-		(v, off) = unpack16(pkt, off)	/* class */
-	;;
-
-	/* parse answer records */
-	hinf = slalloc(a castto(size))
-	for i = 0; i < a; i++
-		off = skipname(pkt, off)	/* name */
-		(v, off) = unpack16(pkt, off)	/* type */
-		(v, off) = unpack16(pkt, off)	/* class */
-		(hinf[i].ttl, off) = unpack32(pkt, off)	/* ttl */
-		(v, off) = unpack16(pkt, off)	/* rdatalen */
-		/* the thing we're interested in: our IP address */
-		hinf[i].addr = `Ipv4 [pkt[off], pkt[off+1], pkt[off+2], pkt[off+3]]
-		off += 4;
-	;;
-	-> `Ok hinf
-}
-
-
-const skipname = {pkt, off
-	var sz
-
-	for sz = pkt[off] castto(size); sz != 0; sz = pkt[off] castto(size)
-		/* ptr is 2 bytes */
-		if sz & 0xC0 == 0xC0
-			-> off + 2
-		else
-			off += sz + 1
-		;;
-	;;
-	-> off + 1
-}
-
-
-const pack16 = {buf, off, v
-	buf[off]	= (v & 0xff00) >> 8 castto(byte)
-	buf[off+1]	= (v & 0x00ff) castto(byte)
-	-> sizeof(uint16) /* we always write one uint16 */
-}
-
-const unpack16 = {buf, off
-	var v
-
-	v = (buf[off] castto(uint16)) << 8
-	v |= (buf[off + 1] castto(uint16))
-	-> (v, off+sizeof(uint16))
-}
-
-const unpack32 = {buf, off
-	var v
-
-	v = (buf[off] castto(uint32)) << 24
-	v |= (buf[off+1] castto(uint32)) << 32
-	v |= (buf[off+2] castto(uint32)) << 8
-	v |= (buf[off+3] castto(uint32))
-	-> (v, off+sizeof(uint32))
-}
-
-const packname = {buf, off : size, host
-	var i
-	var start
-	var last
-
-	start = off
-	last = 0
-	for i = 0; i < host.len; i++
-		if host[i] == ('.' castto(byte))
-			off += addseg(buf, off, host[last:i])
-			last = i + 1
-		;;
-	;;
-	if host[host.len - 1] != ('.' castto(byte))
-		off += addseg(buf, off, host[last:])
-	;;
-	off += addseg(buf, off, "") /* null terminating segment */
-	-> off - start
-}
-
-const addseg = {buf, off, str
-	buf[off] = str.len castto(byte)
-	slcp(buf[off + 1 : off + str.len + 1], str)
-	-> str.len + 1
-}
-
-const valid = {host : byte[:]
-	var i
-	var seglen
-
-	/* maximum length: 255 chars */
-	if host.len > 255
-		-> false
-	;;
-
-	seglen = 0
-	for i = 0; i < host.len; i++
-		if host[i] == ('.' castto(byte))
-			seglen = 0
-		;;
-		if seglen > 63
-			-> false
-		;;
-		if host[i] & 0x80 != 0
-			-> false
-		;;
-	;;
-
-	-> true
-}
--- a/libstd/spork.myr
+++ b/libstd/spork.myr
@@ -1,5 +1,3 @@
-use sys
-
 use "die.use"
 use "execvp.use"
 use "fmt.use"
@@ -46,10 +44,10 @@
 	/* child */
 	elif pid == 0
 		/* stdin/stdout for our communication. */
-		if sys.dup2(infd castto(sys.fd), 0) != 0
+		if dup2(infd castto(fd), 0) != 0
 			fatal(1, "unable to set stdin\n")
 		;;
-		if sys.dup2(outfd castto(sys.fd), 1) != 1
+		if dup2(outfd castto(fd), 1) != 1
 			fatal(1, "unable to set stdout\n")
 		;;
 		close(infd)
--- a/libstd/sys+plan9-x64.myr
+++ b/libstd/sys+plan9-x64.myr
@@ -121,41 +121,42 @@
 	const Sys_nsec		: scno = 53
 
 
-	const sysr1	: (->int)
-	const bind	: (nm : byte[:], old : byte[:] -> int)
-	const chdir	: (dir : byte[:] -> int)
-	const close	: (fd : fd -> int)
+	const sysr1	: (-> int64)
+	const bind	: (nm : byte[:], old : byte[:] -> int64)
+	const chdir	: (dir : byte[:] -> int64)
+	const close	: (fd : fd -> int64)
 	const dup	: (old : fd, new : fd -> fd)
-	const alarm	: (msec : uint32 -> int)
-	const exits	: (msg : byte[:] -> int)
-	const fauth	: (fd : fd, name : byte[:] -> int)
-	const segbrk	: (saddr : void#, addr : void# -> int)
+	const alarm	: (msec : uint32 -> int64)
+	const exits	: (msg : byte[:] -> int64)
+	const fauth	: (fd : fd, name : byte[:] -> int64)
+	const segbrk	: (saddr : void#, addr : void# -> int64)
 	const open	: (path : byte[:], opt : fdopt -> fd)
-	const sleep	: (msec : uint32 -> int)
+	const sleep	: (msec : uint32 -> int64)
 	const rfork	: (rflags : rflags -> pid)
-	const pipe	: (fds : fd[2]# -> int)
+	const pipe	: (fds : fd[2]# -> int64)
 	const create	: (path : byte[:], opt : fdopt, perm : int -> fd)
-	const fd2path	: (fd : fd, path : byte[:] -> int)
-	const remove	: (path : byte[:] -> int)
-	const notify	: (fn : (a : void#, c : char# -> int) -> int)
-	const noted	: (v : int32 -> int)
-	const segattach	: (attr : int32, class : byte[:], va : void#, len : uint32 -> int)
-	const segdetach	: (va : void# -> int)
-	const segfree	: (va : void#, len : uint32 -> int)
-	const segflush	: (va : void#, len : uint32 -> int)
-	const unmount	: (name : byte[:], old : byte[:] -> int)
-	const errstr	: (buf : byte[:] -> int)
-	const stat	: (name : byte[:], edir : byte[:] -> int)
-	const fstat	: (fd : fd, edir : byte[:] -> int)
-	const wstat	: (name : byte[:], edir : byte[:] -> int)
-	const fwstat	: (fd : byte[:],  edir : byte[:] -> int)
+	const fd2path	: (fd : fd, path : byte[:] -> int64)
+	const remove	: (path : byte[:] -> int64)
+	const notify	: (fn : (a : void#, c : char# -> int64) -> int64)
+	const noted	: (v : int32 -> int64)
+	const segattach	: (attr : int32, class : byte[:], va : void#, len : uint32 -> int64)
+	const segdetach	: (va : void# -> int64)
+	const segfree	: (va : void#, len : uint32 -> int64)
+	const segflush	: (va : void#, len : uint32 -> int64)
+	const unmount	: (name : byte[:], old : byte[:] -> int64)
+	const errstr	: (buf : byte[:] -> int64)
+	const stat	: (name : byte[:], edir : byte[:] -> int64)
+	const fstat	: (fd : fd, edir : byte[:] -> int64)
+	const wstat	: (name : byte[:], edir : byte[:] -> int64)
+	const fwstat	: (fd : byte[:],  edir : byte[:] -> int64)
 	const seek	: (fd : fd, len : off, ty : int -> off)
-	const mount	: (fd : fd, afd : fd, old : byte[:], flag : int32, aname : byte[:] -> int)
-	const await	: (buf : byte[:] -> int)
+	const mount	: (fd : fd, afd : fd, old : byte[:], flag : int32, aname : byte[:] -> int64)
+	const await	: (buf : byte[:] -> int64)
 	const pread	: (fd : fd, buf : byte[:], off : off -> size)
 	const pwrite	: (fd : fd, buf : byte[:], off : off -> size)
-	const exec	: (bin : byte[:], args : byte[:][:] -> int)
-	const brk_	: (endp : byte# -> int)
+	const exec	: (bin : byte[:], args : byte[:][:] -> int64)
+	const brk_	: (endp : byte# -> int64)
+	const nsec	: (-> uint64)
 
 	extern var tosptr	: tos#
 	extern var curbrk	: byte#
@@ -162,10 +163,10 @@
 ;;
 
 /* asm stub from syscall.s */
-extern const syscall : (scno : scno, args : ... -> int)
+extern const syscall : (scno : scno, args : ... -> int64)
 /* asm stubs from util+plan9.s */
 extern const cstring	: (str : byte[:] -> byte#)
-extern const alloca	: (sz : size	-> int)
+extern const alloca	: (sz : size	-> byte#)
 
 
 /*
@@ -210,6 +211,7 @@
 const pwrite	= {fd, buf, off;	-> syscall(Syspwrite, a(fd), p(buf), a(buf.len), s(off)) castto(size)}
 const await	= {buf;	-> syscall(Sysawait, p(buf), a(buf.len))}
 const brk_	= {endp;	-> syscall(Sysbrk_, p(endp))}
+const nsec	= {;	-> syscall(Sys_nsec) castto(uint64)}
 const seek	= {fd, n, ty
 	var ret : off
 	syscall(Sysseek, a(&ret), a(fd), a(n), a(ty))
--- /dev/null
+++ b/libstd/syswrap+plan9-x6.myr
@@ -1,0 +1,104 @@
+use sys
+use "types.use"
+
+pkg std =
+	type fd		= sys.fd
+	type pid	= sys.pid
+	type fdopt	= sys.fdopt
+
+	const Failmem	: byte#	= -1 castto(byte#)
+
+	const Ordonly  	: fdopt = sys.Ordonly	castto(fdopt)
+	const Owronly  	: fdopt = sys.Owronly	castto(fdopt)
+	const Ordwr    	: fdopt = sys.Ordwr	castto(fdopt)
+	const Otrunc   	: fdopt = sys.Otrunc	castto(fdopt)
+	const Ocreat   	: fdopt = 0x1000000	/* emulated by redirecting to creat(). */
+	const Oappend  	: fdopt = 0x2000000	/* emulated by seeking to EOF */
+	const Odir	: fdopt = 0x0	/* no-op on plan9 */
+
+	/* fd stuff */
+	const open	: (path : byte[:], opts : fdopt -> fd)
+	const openmode	: (path : byte[:], opts : fdopt, mode : int64 -> fd)
+	const close	: (fd : fd -> int64)
+	const creat	: (path : byte[:], mode : int64 -> fd)
+	const read	: (fd : fd, buf : byte[:] -> size)
+	const write	: (fd : fd, buf : byte[:] -> size)
+	const pipe	: (fds : fd[2]# -> int64)
+
+	/* path manipulation */
+	const mkdir	: (path : byte[:], mode : int64 -> int64)
+	const unlink	: (path : byte[:] -> int)
+
+	/* process stuff */
+	const getpid	: ( -> pid)
+	const suicide	: ( -> void)
+	const fork	: (-> pid)
+	const execv	: (cmd : byte[:], args : byte[:][:] -> int64)
+	const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+	const exit	: (status:int -> void)
+	const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
+	const getmem	: (sz : size -> byte#)
+	const freemem	: (p : byte#, sz : size -> void)
+;;
+
+/* fd stuff */
+const open	= {path, opts;	-> sys.open(path, opts castto(sys.fdopt)) castto(fd)}
+const openmode	= {path, opts, mode;
+	var fd
+
+
+	if opts & Ocreat != 0
+		fd = sys.create(path, opts castto(sys.fdopt), mode castto(int))
+	else
+		fd = sys.open(path, opts castto(sys.fdopt))
+	;;
+	if opts & Oappend != 0
+		sys.seek(fd, 0, 2)
+	;;
+	-> fd castto(fd)
+}
+
+const close	= {fd;		-> sys.close(fd castto(sys.fd)) castto(int64)}
+const read	= {fd, buf;	-> sys.pread(fd castto(sys.fd), buf, -1) castto(size)}
+const write	= {fd, buf;	-> sys.pwrite(fd castto(sys.fd), buf, -1) castto(size)}
+const pipe	= {fds;		-> sys.pipe(fds castto(sys.fd[2]#)) castto(int64)}
+
+/* path manipulation */
+const unlink	= {path;	-> sys.remove(path)}
+const mkdir	= {path, mode;
+	var fd
+
+	fd = sys.create(path, sys.Ordonly, sys.Dmdir | (mode castto(int)))
+	if fd < 0
+		-> -1
+	;;
+	sys.close(fd)
+	-> 0
+}
+
+/* process stuff */
+const getpid	= {;	-> sys.gettos().pid castto(pid)}
+const suicide	= {;	(0 castto(byte#))#}	/* let's happy segfault!! t */
+const fork	= {;		-> sys.rfork(sys.Rffdg | sys.Rfrend | sys.Rfproc) castto(pid)}
+const execv	= {cmd, args;	-> sys.exec(cmd, args) castto(int64)}
+const execve	= {cmd, args, env;	-> sys.exec(cmd, args) castto(int64)}
+const exit	= {status;
+	if status == 0
+		sys.exits("")
+	else
+		sys.exits("failure")
+	;;
+}
+
+/* FIXME: horribly broken. We wait for a pid to exit, and lie about which one. */
+const waitpid	= {pid, loc, opt;
+	var buf : byte[512]
+	var n
+
+	n = sys.await(buf[:])
+	-> pid
+}
+
+/* memory stuff */
+const getmem	= {sz;		-> sys.mmap(0 castto(byte#), sz castto(sys.size), sys.Mprotrw, sys.Mpriv | sys.Manon, -1, 0)}
+const freemem	= {p, sz;	sys.munmap(p, sz castto(sys.size))}
--- a/libstd/syswrap+plan9-x64.myr
+++ b/libstd/syswrap+plan9-x64.myr
@@ -24,10 +24,11 @@
 	const read	: (fd : fd, buf : byte[:] -> size)
 	const write	: (fd : fd, buf : byte[:] -> size)
 	const pipe	: (fds : fd[2]# -> int64)
+	const dup2	: (ofd : fd, nfd : fd -> fd)
 
 	/* path manipulation */
 	const mkdir	: (path : byte[:], mode : int64 -> int64)
-	const unlink	: (path : byte[:] -> int)
+	const unlink	: (path : byte[:] -> int64)
 
 	/* process stuff */
 	const getpid	: ( -> pid)
@@ -37,8 +38,10 @@
 	const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
 	const exit	: (status:int -> void)
 	const waitpid	: (pid:pid, loc:int32#, opt : int64	-> pid)
-	const getmem	: (sz : size -> byte#)
-	const freemem	: (p : byte#, sz : size -> void)
+
+	pkglocal const getmem	: (sz : size -> byte#)
+	pkglocal const freemem	: (p : byte#, sz : size -> void)
+	pkglocal const curtime	: (-> time)
 ;;
 
 /* fd stuff */
@@ -62,6 +65,7 @@
 const read	= {fd, buf;	-> sys.pread(fd castto(sys.fd), buf, -1) castto(size)}
 const write	= {fd, buf;	-> sys.pwrite(fd castto(sys.fd), buf, -1) castto(size)}
 const pipe	= {fds;		-> sys.pipe(fds castto(sys.fd[2]#)) castto(int64)}
+const dup2	= {ofd, nfd;	-> sys.dup(ofd castto(sys.fd), nfd castto(sys.fd)) castto(fd)}
 
 /* path manipulation */
 const unlink	= {path;	-> sys.remove(path)}
@@ -112,6 +116,10 @@
 	-> sys.curbrk
 }
 	
-const freemem	= {p, sz
+const freemem = {p, sz
 	/* FIXME: don't leak */
+}
+
+const curtime = {
+	-> sys.nsec()/1000 castto(time)
 }
--- a/libstd/syswrap+posixy.myr
+++ b/libstd/syswrap+posixy.myr
@@ -39,6 +39,7 @@
 	const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
 	const getmem	: (sz : size -> byte#)
 	const freemem	: (p : byte#, sz : size -> void)
+	const curtime	: (-> uint64)
 ;;
 
 /* fd stuff */
@@ -66,3 +67,14 @@
 /* memory stuff */
 const getmem	= {sz;		-> sys.mmap(0 castto(byte#), sz castto(sys.size), sys.Mprotrw, sys.Mpriv | sys.Manon, -1, 0)}
 const freemem	= {p, sz;	sys.munmap(p, sz castto(sys.size))}
+const curtime = {
+	var tm, sec, nsec
+
+	if sys.clock_gettime(`sys.Clockrealtime, &tm) == 0
+		sec = tm.sec
+		nsec = tm.nsec castto(uint64)
+		-> (sec*1_000_000 + nsec/1000) castto(time)
+	else
+		-> -1
+	;;
+}
\ No newline at end of file