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