forsyth20121205-174063a80cc13 years agoHistory
500 lines · 10.1 KB · Brainfuck
RawDownload
implement Inst; include "sys.m";	sys: Sys;	Dir, sprint, fprint: import sys;include "draw.m";include "bufio.m";	bufio: Bufio;	Iobuf: import bufio;include "string.m";	str: String;include "arg.m";	arg: Arg;include "keyring.m";	keyring : Keyring;include "arch.m";	arch : Arch;include "wrap.m";	wrap : Wrap; Inst: module{	init:	fn(nil: ref Draw->Context, nil: list of string);}; LEN: con Sys->ATOMICIO; tflag := 0;uflag := 0;hflag := 0;vflag := 0;fflag := 1;stderr: ref Sys->FD;bout: ref Iobuf;argv0 := "inst";oldw, w : ref Wrap->Wrapped;root := "/";force := 0;stoponerr := 1; # membogus(argv: list of string)# {## } init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	stderr = sys->fildes(2);	bufio = load Bufio Bufio->PATH;	if(bufio == nil)		error(sys->sprint("cannot load %s: %r\n", Bufio->PATH)); 	str = load String String->PATH;	if(str == nil)		error(sys->sprint("cannot load %s: %r\n", String->PATH)); 	arg = load Arg Arg->PATH;	if(arg == nil)		error(sys->sprint("cannot load %s: %r\n", Arg->PATH));	keyring = load Keyring Keyring->PATH;	if(keyring == nil)		error(sys->sprint("cannot load %s: %r\n", Keyring->PATH));	arch = load Arch Arch->PATH;	if(arch == nil)		error(sys->sprint("cannot load %s: %r\n", Arch->PATH));	arch->init(bufio);	wrap = load Wrap Wrap->PATH;	if(wrap == nil)		error(sys->sprint("cannot load %s: %r\n", Wrap->PATH));	wrap->init(bufio);	arg->init(args);	while((c := arg->opt()) != 0)		case c {		'f' =>			fflag = 0;		'h' =>			hflag = 1;			bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);			if(bout == nil)				error(sys->sprint("can't access standard output: %r"));		't' =>			tflag = 1;		'u' =>			uflag = 1;		'v' =>			vflag = 1;		'r' =>			root = arg->arg();			if (root == nil)				fatal("root missing");		'F' =>			force = 1;		'c' =>			stoponerr = 0;		* =>			usage();		}	args = arg->argv();	if (args == nil)		usage();	ar := arch->openarch(hd args);	if(ar == nil || ar.b == nil)		error(sys->sprint("can't access %s: %r", hd args));	w = wrap->openwraphdr(hd args, root, nil, 0);	if (w == nil)		fatal("no such package found");	if(w.nu != 1)		fatal("strange package: more than one piece");	if (force == 0)		oldw = wrap->openwrap(w.name, root, 0);	if (force == 0 && w.u[0].utime && (oldw == nil || oldw.tfull < w.u[0].utime)){		tfull: int;		if(oldw == nil)			tfull = -1;		else			tfull = oldw.tfull;		fatal(sys->sprint("need %s version of %s already installed (pkg %d)", wrap->now2string(w.u[0].utime, 0), w.name, tfull));	}	args = tl args;	digest := array[Keyring->MD5dlen] of byte;	digest0 := array[Keyring->MD5dlen] of byte;	digest1 := array[Keyring->MD5dlen] of byte; 	while ((a := arch->gethdr(ar)) != nil) {		why := "";		docopy := 0;		if(force)			docopy = 1;		else if(a.d.mode & Sys->DMDIR)			docopy = 1;		else if(wrap->md5file(root+a.name, digest) < 0)			docopy = 1;		else{			wrap->md5filea(root+a.name, digest1);			(ok, t) := wrap->getfileinfo(oldw, a.name, digest, nil, digest1);			if (ok >= 0) {				if(t > w.u[0].time){					docopy = 0;					why = "version from newer package exists";				}				else					docopy = 1;			}			else {				(ok, t) = wrap->getfileinfo(oldw, a.name, nil, nil, nil);				if(ok >= 0){					docopy = 0;					why = "locally modified";				}				else{					docopy = 0;					why = "locally created";				}			}		}		if(!docopy){			wrap->md5sum(ar.b, digest0, int a.d.length);			if(wrap->memcmp(digest, digest0, Keyring->MD5dlen))				skipfile(a.name, why);			continue;		}		if(args != nil){			if(!selected(a.name, args)){				arch->drain(ar, int a.d.length);				continue;			}			if (!hflag)				mkdirs(root, a.name);		}		name := pathcat(root, a.name);		if(hflag){			bout.puts(sys->sprint("%s %uo %s %s %ud %d\n",				name, a.d.mode, a.d.uid, a.d.gid, a.d.mtime, int a.d.length));			arch->drain(ar, int a.d.length);			continue;		}		if(a.d.mode & Sys->DMDIR)			mkdir(name, a.d);		else			extract(ar, name, a.d);	}	arch->closearch(ar);	if(ar.err == nil){		# fprint(stderr, "done\n");		quit(nil);	}	else {		fprint(stderr, "%s\n", ar.err);		quit("eof");	}} skipfile(f : string, why : string){	sys->fprint(stderr, "skipping %s: %s\n", f, why);} skiprmfile(f: string, why: string){	sys->fprint(stderr, "not removing %s: %s\n", f, why);} doremove(s : string){	p := pathcat(root, s);	digest := array[Keyring->MD5dlen] of { * => byte 0 };	digest1 := array[Keyring->MD5dlen] of { * => byte 0 };	if(wrap->md5file(p, digest) < 0)		;	else{		wrap->md5filea(p, digest1);		(ok, nil) := wrap->getfileinfo(oldw, s, digest, nil, digest1);		if(force == 0 && ok < 0)			skiprmfile(p, "locally modified");		else{			if (vflag)				sys->print("rm %s\n", p);			remove(p);		}	}} quit(s: string){	if (s == nil) {		p := w.u[0].dir + "/remove";		if ((b := bufio->open(p, Bufio->OREAD)) != nil) {			while ((t := b.gets('\n')) != nil) {				lt := len t;				if (t[lt-1] == '\n')					t = t[0:lt-1];				doremove(t);			}		}	}	if(bout != nil)		bout.flush();	if(wrap != nil)		wrap->end();	if(s != nil)		raise "fail: "+s;	else		fprint(stderr, "done\n");	exit;} fileprefix(prefix, s: string): int{	n := len prefix;	m := len s;	if(n > m || !str->prefix(prefix, s))		return 0;	if(m > n && s[n] != '/')		return 0;	return 1;} selected(s: string, args: list of string): int{	for(; args != nil; args = tl args)		if(fileprefix(hd args, s))			return 1;	return 0;} mkdirs(basedir, name: string){	(nil, names) := sys->tokenize(name, "/");	while(names != nil) {		create(basedir, Sys->OREAD, 8r775|Sys->DMDIR);		if(tl names == nil)			break;		basedir = basedir + "/" + hd names;		names = tl names;	}} mkdir(name: string, dir : ref Sys->Dir){	d: Dir;	i: int; 	if(vflag) {		MTPT : con "/n/remote";		s := name;		if (len name >= len MTPT && name[0:len MTPT] == MTPT)			s = name[len MTPT:];		sys->print("installing directory %s\n", s);	}	fd := create(name, Sys->OREAD, dir.mode);	if(fd == nil) {		err := sys->sprint("%r");		(i, d) = sys->stat(name);		if(i < 0 || !(d.mode & Sys->DMDIR)){			werr(sys->sprint("can't make directory %s: %s", name, err));			return;		}	}	else {		(i, d) = sys->fstat(fd);		if(i < 0)			warn(sys->sprint("can't stat %s: %r", name));		fd = nil;	}	d = sys->nulldir;	(nil, p) := str->splitr(name, "/");	if(p == nil)		p = name;	d.name = p;	d.mode = dir.mode;	if(tflag || uflag)		d.mtime = dir.mtime;	if(uflag){		d.uid = dir.uid;		d.gid = dir.gid;	}	fd = nil;	if(sys->wstat(name, d) < 0){		e := sys->sprint("%r");		if(wstat(name, d) < 0)			warn(sys->sprint("can't set modes for %s: %s", name, e));	}	if(uflag){		(i, d) = sys->stat(name);		if(i < 0)			warn(sys->sprint("can't reread modes for %s: %r", name));		if(dir.uid != d.uid)			warn(sys->sprint("%s: uid mismatch %s %s", name, dir.uid, d.uid));		if(dir.gid != d.gid)			warn(sys->sprint("%s: gid mismatch %s %s", name, dir.gid, d.gid));	}} extract(ar : ref Arch->Archive, name: string, dir : ref Sys->Dir){	sfd := create(name, Sys->OWRITE, dir.mode);	if(sfd == nil) {		if(!fflag || remove(name) == -1 ||		    (sfd = create(name, Sys->OWRITE, dir.mode)) == nil) {			werr(sys->sprint("can't make file %s: %r", name));			arch->drain(ar, int dir.length);			return;		}	}	b := bufio->fopen(sfd, Bufio->OWRITE);	if (b == nil) {		warn(sys->sprint("can't open file %s for bufio : %r", name));		arch->drain(ar, int dir.length);		return;	}	err := arch->getfile(ar, b, int dir.length);	if (err != nil) {		if (len err >= 9 && err[0:9] == "premature")			fatal(err);		else			warn(err);	}	(i, d) := sys->fstat(b.fd);	if(i < 0)		warn(sys->sprint("can't stat %s: %r", name));	d = sys->nulldir;	(nil, p) := str->splitr(name, "/");	if(p == nil)		p = name;	d.name = p;	d.mode = dir.mode;	if(tflag || uflag)		d.mtime = dir.mtime;	if(uflag){		d.uid = dir.uid;		d.gid = dir.gid;	}	if(b.flush() == Bufio->ERROR)		werr(sys->sprint("error writing %s: %r", name));	b.close();	sfd = nil;	if(sys->wstat(name, d) < 0){		e := sys->sprint("%r");		if(wstat(name, d) < 0)			warn(sys->sprint("can't set modes for %s: %s", name, e));	}	if(uflag){		(i, d) = sys->stat(name);		if(i < 0)			warn(sys->sprint("can't reread modes for %s: %r", name));		if(d.uid != dir.uid)			warn(sys->sprint("%s: uid mismatch %s %s", name, dir.uid, d.uid));		if(d.gid != dir.gid)			warn(sys->sprint("%s: gid mismatch %s %s", name, dir.gid, d.gid));	}} error(s: string){	fprint(stderr, "%s: %s\n", argv0, s);	quit("error");} werr(s: string){	fprint(stderr, "%s: %s\n", argv0, s);	if(stoponerr)		quit("werr");}	warn(s: string){	fprint(stderr, "%s: %s\n", argv0, s);} usage(){	fprint(stderr, "Usage: inst [-h] [-u] [-v] [-f] [-c] [-F] [-r dest-root] [file ...]\n");	raise "fail: usage";} fatal(s : string){	sys->fprint(stderr, "inst: %s\n", s);	if(wrap != nil)		wrap->end();	exit;} parent(name : string) : string{	slash := -1;	for (i := 0; i < len name; i++)		if (name[i] == '/')			slash = i;	if (slash > 0)		return name[0:slash];	return "/";} create(name : string, rw : int, mode : int) : ref Sys->FD{	fd := sys->create(name, rw, mode);	if (fd == nil) {		p := parent(name);		(ok, d) := sys->stat(p);		if (ok < 0)			return nil;		omode := d.mode;		d = sys->nulldir;		d.mode = omode | 8r222;	# ensure parent is writable		sys->wstat(p, d);		fd = sys->create(name, rw, mode);		d.mode = omode;		sys->wstat(p, d);	}	return fd;} remove(name : string) : int{	if (sys->remove(name) < 0) {		(ok, d) := sys->stat(name);		if (ok < 0)			return -1;		omode := d.mode;		d.mode |= 8r222;		sys->wstat(name, d);		if (sys->remove(name) >= 0)			return 0;		d.mode = omode;		sys->wstat(name, d);		return -1;	}	return 0;} wstat(name : string, d : Dir) : int{	(ok, dir) := sys->stat(name);	if (ok < 0)		return -1;	omode := dir.mode;	dir.mode |= 8r222;	sys->wstat(name, dir);	if (sys->wstat(name, d) >= 0)		return 0;	dir.mode = omode;	sys->wstat(name, dir);	return -1;} pathcat(s : string, t : string) : string{	if (s == nil) return t;	if (t == nil) return s;	slashs := s[len s - 1] == '/';	slasht := t[0] == '/';	if (slashs && slasht)		return s + t[1:];	if (!slashs && !slasht)		return s + "/" + t;	return s + t;}