shithub: mc

ref: 349fb0a3a44d80d9655037eb660af844bc5a3244
dir: /lib/std/syswrap+plan9.myr/

View raw version
use sys

use "option"
use "types"
use "errno"
use "result"
use "cstrconv"
use "strfind"
use "syswrap-ss"

pkg std =
	type fd		= sys.fd
	type pid	= sys.pid
	type fdopt	= sys.fdopt
	type whence = int64

	type sysinfo = struct
		system	: byte[:]
		version	: byte[:]
		release	: byte[:]
		arch	: byte[:]
	;;

	const Seekset	: whence = 0
	const Seekcur	: whence = 1
	const Seekend	: whence = 2

	const Failmem	: byte#	= (-1 : byte#)

	const Oread  	: fdopt = (sys.Oread	: fdopt)
	const Owrite  	: fdopt = (sys.Owrite	: fdopt)
	const Ordwr    	: fdopt = (sys.Ordwr	: fdopt)
	const Otrunc   	: fdopt = (sys.Otrunc	: fdopt)
	const Ocexec	: fdopt = (sys.Ocexec	: 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 -> result(fd, errno))
	const openmode	: (path : byte[:], opts : fdopt, mode : int64 -> result(fd, errno))
	const close	: (fd : fd -> errno)
	const read	: (fd : fd, buf : byte[:] -> result(size, errno))
	const pread	: (fd : fd, buf : byte[:], off : off -> result(size, errno))
	const write	: (fd : fd, buf : byte[:] -> result(size, errno))
	const pwrite	: (fd : fd, buf : byte[:], off : off -> result(size, errno))
	const seek	: (fd : fd, delta : off, whence : whence -> result(off, errno))
	const pipe	: (fds : fd[2]# -> errno)
	const dup2	: (ofd : fd, nfd : fd -> result(fd, errno))
	const nopipe	: (-> void)

	/* useful/portable bits of stat */
	const fmtime	: (f : byte[:]	-> result(time, errno))
	const fsize	: (f : byte[:]	-> result(off, errno))
	const fexists	: (f : byte[:]	-> bool)
	const fisdir	: (f : byte[:]	-> bool)
	const fisreg	: (f : byte[:]	-> bool)

	/* the important bits that uname provides */
	const getsysinfo	: (si : sysinfo# -> void)

	/* path manipulation */
	const mkdir	: (path : byte[:], mode : int64 -> errno)
	const chdir	: (path : byte[:] -> bool)
	const remove	: (path : byte[:] -> bool)

	/* process stuff */
	const getpid	: ( -> pid)
	$noret const suicide	: ( -> void)
	const fork	: (-> pid)
	const execv	: (cmd : byte[:], args : byte[:][:] -> errno)
	const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno)

	pkglocal const Canunmap	: bool = true
	pkglocal const getmem	: (sz : size -> byte#)
	pkglocal const freemem	: (p : byte#, sz : size -> void)
	pkglocal const curtime	: (-> time)
	pkglocal const p9errstr	: (buf : byte[:] -> byte[:])

	/* statbuf offsets */
	pkglocal const Sizeoff	: int64 = 0
	pkglocal const Sizesz	: int64 = 2
	pkglocal const Typeoff	: int64 = Sizeoff + Sizesz
	pkglocal const Typesz	: int64 = 2
	pkglocal const Devoff	: int64 = Typeoff + Typesz
	pkglocal const Devsz	: int64 = 4
	pkglocal const Qidtypeoff	: int64 = Devoff + Devsz
	pkglocal const Qidtypesz	: int64 = 1
	pkglocal const Qidversoff	: int64 = Qidtypeoff + Qidtypesz
	pkglocal const Qidverssz	: int64	= 4
	pkglocal const Qidpathoff	: int64 = Qidversoff + Qidverssz
	pkglocal const Qidpathsz	: int64 = 8
	pkglocal const Modeoff	: int64 = Qidpathoff + Qidpathsz
	pkglocal const Modesz	: int64 = 4
	pkglocal const Atimeoff	: int64 = Modeoff + Modesz
	pkglocal const Atimesz	: int64 = 4
	pkglocal const Mtimeoff	: int64 = Atimeoff + Atimesz
	pkglocal const Mtimesz	: int64 = 4
	pkglocal const Lengthoff	: int64 = Mtimeoff + Mtimesz
	pkglocal const Lengthsz	: int64 = 8
	pkglocal const Stringsoff	: int64 = Lengthoff + Lengthsz
;;

/* UGLY: circular dependency breaking... */
extern const getenvv : (name : byte[:], default : byte[:] -> byte[:])

/* fd stuff */
const open	= {path, opts;	-> check(sys.open(path, (opts : sys.fdopt)))}
const openmode	= {path, opts, mode;
	var fd


	if opts & Ocreat != 0
		opts &= ~Ocreat
		fd = sys.create(path, (opts : sys.fdopt), (mode : int))
	else
		fd = sys.open(path, (opts : sys.fdopt))
	;;
	if opts & Oappend != 0
		sys.seek(fd, 0, 2)
	;;
	-> check(fd)
}

const nopipe = {
}

/* useful/portable bits of stat */
const fexists = {path
	var buf : byte[4]	/* big enough for size, nothing else. */

	-> sys.stat(path, buf[:]) >= 0
}

const fmtime = {path
	var buf	: byte[Stringsoff + 512]	/* enough space for some strings */

	if sys.stat(path, buf[:]) < Stringsoff
		-> `Err Emisc
	;;
	-> `Ok ((_getle32(buf[Mtimeoff:Mtimeoff + 8]) : time)*1_000_000)
}

const fsize = {path
	var buf	: byte[Stringsoff + 512]	/* enough space for some strings */

	if sys.stat(path, buf[:]) < Stringsoff
		-> `Err Emisc
	;;
	-> `Ok (_getle64(buf[Lengthoff:Lengthoff + 8]) : off)
}

extern const put : (fmt : byte[:], args : ... -> int64)
const fisdir = {path
	var buf	: byte[Stringsoff + 39]	/* enough space for qid type */

	if sys.stat(path, buf[:]) < Stringsoff
		-> false
	;;
	-> (_getle32(buf[Modeoff:Modeoff + 4]) & sys.Dmdir) != 0
}

const fisreg = {path
	var buf	: byte[Stringsoff + 512]	/* enough space for some strings */
	var ty

	if sys.stat(path, buf[:]) < Stringsoff
		-> false
	;;

	ty = _getle16(buf[Typeoff:Typeoff + 2])
	if (_getle32(buf[Modeoff:Modeoff + 4]) & sys.Dmdir) != 0
		-> false
	/* ugh. maybe this call should just be '!fisdir()' */
	elif ty == '|' || ty == 's' || ty == 'm'
		-> false
	else
		-> true
	;;
}

const getsysinfo = {si
	si.system = getenvv("osname", "Plan9")
	si.release = "4"
	si.version = "0"
	si.arch = getenvv("objtype", "amd64")
}

const close	= {fd;		-> (sys.close((fd : sys.fd)) : errno)}
const read	= {fd, buf;	-> check(sys.pread((fd : sys.fd), buf, -1))}
const pread	= {fd, buf,off;	-> check(sys.pread((fd : sys.fd), buf, (off : sys.off)))}
const write	= {fd, buf;	-> check(sys.pwrite((fd : sys.fd), buf, -1))}
const pwrite	= {fd, buf,off;	-> check(sys.pwrite((fd : sys.fd), buf, (off : sys.off)))}
const seek	= {fd, off, whence; 	-> check(sys.seek((fd : sys.fd), (off : sys.off), (whence : int64)))}
const pipe	= {fds;		-> (sys.pipe((fds : sys.fd[2]#)) : errno)}
const dup2	= {ofd, nfd;	-> check(sys.dup((ofd : sys.fd), (nfd : sys.fd)))}

/* path manipulation */
const remove	= {path;	-> sys.remove(path) == 0}
const chdir	= {path;	-> sys.chdir(path) == 0}
const mkdir	= {path, mode;
	var fd

	fd = sys.create(path, sys.Oread, sys.Dmdir | (mode : int))
	if fd < 0
		-> lasterr()
	;;
	sys.close(fd)
	-> 0
}

/* process stuff */
const getpid	= {;	-> (sys.tosptr.pid : pid)}
const suicide	= {;	(0 : byte#)#}	/* let's happy segfault!! t */
const fork	= {;		-> (sys.rfork(sys.Rffdg | sys.Rfrend | sys.Rfproc) : pid)}
const execv	= {cmd, args;
	sys.exec(cmd, args)
	-> lasterr()
}

const execve	= {cmd, args, env;
	sys.exec(cmd, args)
	-> lasterr()
}



/* memory stuff */
const getmem	= {sz
	var endp, oldp

	oldp = sys.curbrk
	endp = (sys.curbrk : intptr) + (sz : intptr)
	endp = (endp + 4095) & ~4095
	if sys.brk_((endp : byte#)) < 0
		-> Failmem
	;;
	sys.curbrk = (endp : byte#)
	-> oldp
}
	
const freemem = {p, sz
	/* FIXME: we leak address space */
	sys.segfree(p, (sz : sys.size))
}

const curtime = {
	-> (sys.nsec()/1000 : time)
}

const p9errstr = {errbuf
	var i

	sys.errstr(errbuf)
	for i = 0; errbuf[i] != 0 && i < errbuf.len; i++
		continue
	;;
	-> errbuf[:i]
}

/* FIXME: will be needed when we resize stat bufs when statting.
const statsz = {buf
	-> (buf[0] : int64)) | ((buf[1] << 8 : int64))
}
*/

generic check = {e : @a -> result(@b, errno) :: integral, numeric @a
	if e < 0
		-> `Err lasterr()
	else
		-> `Ok (e : @b)
	;;
}

/* duplicated code to break dependency cycle */
generic _getle16 = {buf -> @a :: numeric,integral @a
	-> ((buf[0] : @a) << 0) | \
		((buf[1] : @a) << 8)
}

generic _getle32 = {buf -> @a :: numeric,integral @a
	-> ((buf[0] : @a) << 0) | \
		((buf[1] : @a) << 8) | \
		((buf[2] : @a) << 16) | \
		((buf[3] : @a) << 24)
}

generic _getle64 = {buf -> @a :: numeric,integral @a
	-> ((buf[0] : @a)  << 0) | \
		((buf[1] : @a)  << 8) | \
		((buf[2] : @a)  << 16) | \
		((buf[3] : @a)  << 24) | \
		((buf[4] : @a)  << 32) | \
		((buf[5] : @a)  << 40) | \
		((buf[6] : @a)  << 48) | \
		((buf[7] : @a)  << 56)
}