forsyth20121205-174063a80cc13 years agoHistory
445 lines · 9.9 KB · Brainfuck
RawDownload
implement Create; 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 "daytime.m";include "keyring.m";	keyring : Keyring;include "sh.m";include "wrap.m";	wrap : Wrap;include "arch.m";	arch : Arch;include "proto.m";	proto : Proto;include "protocaller.m";	protocaller : Protocaller; WARN, ERROR, FATAL : import Protocaller; Create: module{	init:	fn(nil: ref Draw->Context, nil: list of string);	protofile: fn(new : string, old : string, d : ref Sys->Dir);	protoerr: fn(lev : int, line : int, err : string);}; bout: ref Iobuf;			# stdout when writing archiveprotof: string;notesf: string;oldroot: string;buf: array of byte;buflen := 1024-8;verb: int;xflag: int;stderr: ref Sys->FD;uid, gid : string;desc : string;pass : int;update : int;md5s : ref Keyring->DigestState;w : ref Wrap->Wrapped;root := "/";prefix, notprefix: list of string;onlist: list of (string, string);	# NEWremfile: string; n2o(n: string): string{	for(onl := onlist; onl != nil; onl = tl onl)		if((hd onl).t1 == n)			return (hd onl).t0;	return n;} init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	str = load String String->PATH;	arg = load Arg Arg->PATH;	wrap = load Wrap Wrap->PATH;	wrap->init(bufio);	arch = load Arch Arch->PATH;	arch->init(bufio);	daytime := load Daytime Daytime->PATH;	now := daytime->now();	# {	#	for(i := 0; i < 21; i++){	#		n := now+(i-9)*100000000;	#		sys->print("%d	->	%s\n", n, wrap->now2string(n));	#		if(wrap->string2now(wrap->now2string(n)) != n)	#			sys->print("%d wrong\n", n);	#	}	# }	daytime = nil;	proto = load Proto Proto->PATH;	protocaller = load Protocaller "$self"; 	sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->FORKFD, nil);	stderr = sys->fildes(2);	if(arg == nil)		error(sys->sprint("can't load %s: %r", Arg->PATH));	name := "";	desc = "inferno";	tostdout := 0;	not := 0;	arg->init(args);	while((c := arg->opt()) != 0)		case c {		'n' =>			not = 1;		'o' =>			tostdout = 1;		'p' =>			protof = reqarg("proto file (-p)");		'r' => 			root = reqarg("root directory (-r)");		's' =>			oldroot = reqarg("source directory (-d)");		'u' =>			update = 1;		'v' =>			verb = 1;		'x' =>			xflag = 1;		'N' =>			uid = reqarg("user name (-U)");		'G' =>			gid = reqarg("group name (-G)");		'd' or 'D' =>			desc = reqarg("product description (-D)");		't' =>			rt := reqarg("package time (-t)");			now = int rt;		'i' =>			notesf = reqarg("file (-i)");		'R' =>			remfile = reqarg("remove file (-R)");		'P' =>			arch->addperms(0);		* =>			usage();		} 	args = arg->argv();	if(args == nil)		usage();	if (tostdout || xflag) {		bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);		if(bout == nil)			error(sys->sprint("can't open standard output for archive: %r"));	}	else {		# ar := sys->sprint("%ud", now);		ar := wrap->now2string(now, 0);		bout = bufio->create(ar, Sys->OWRITE, 8r664);		if(bout == nil)			error(sys->sprint("can't create %s for archive: %r", ar));		sys->print("archiving package %s to %s\n", hd args, ar);	}	buf = array [buflen] of byte;	name = hd args;	if(update){		if(not)			notprefix = tl args;		else			prefix = tl args;	}	else if (tl args != nil)		fatal("only one name allowed");	if (!xflag)		digest := wrapinit(name, now);	fprint(stderr, "processing %s\n", protof);	proto->rdproto(protof, oldroot, protocaller);	if (!xflag)		wrapend(digest);	if (!xflag)		fprint(stderr, "file system made\n");	arch->putend(bout);	exits();} protofile(new : string, old : string, d : ref Sys->Dir){	if(xflag && bout != nil){		bout.puts(sys->sprint("%s\t%d\t%bd\n", new, d.mtime, d.length));		return;	}	d.uid = uid;	d.gid = gid;	if (!(d.mode & Sys->DMDIR)) {		# if(verb)		#	fprint(stderr, "%s\n", new);		f := sys->open(old, Sys->OREAD);		if(f == nil){			warn(sys->sprint("can't open %s: %r", old));			return;		}	}	mkarch(new, old, d);} protoerr(lev : int, line : int, err : string){	s := "line " + string line + " : " + err;	case lev {		WARN => warn(s);		ERROR => error(s);		FATAL => fatal(s);	}} quit(){	if(bout != nil)		bout.flush();	exits();} reqarg(what: string): string{	if((o := arg->arg()) == nil){		sys->fprint(stderr, "missing %s\n", what);		exits();	}	return o;} puthdr(f : string, d: ref Dir){	if (d.mode & Sys->DMDIR)		d.length = big 0;	arch->puthdr(bout, f, d);} error(s: string){	fprint(stderr, "%s: %s\n", protof, s);	quit();} fatal(s: string){	fprint(stderr, "fatal: %s\n", s);	exits();} warn(s: string){	fprint(stderr, "%s: %s\n", protof, s);}	usage(){	fprint(stderr, "usage: install/create [-ovx] [-N uid] [-G gid] [-r root] [-d desc] [-s src-fs] [-p proto] name\n");	fprint(stderr, "or install/create -u [-ovx] [-N uid] [-G gid] [-r root] [-d desc] [-s src-fs] [-p proto] old-package [prefix ...]\n");	exits();} wrapinit(name : string, t : int) : array of byte{	rmfile : string;	rmfd: ref Sys->FD; 	if (uid == nil)		uid = "inferno";	if (gid == nil)		gid = "inferno";	if (update) {		w = wrap->openwraphdr(name, root, nil, 0);		if (w == nil)			fatal("no such package found");		# ignore any updates - NEW commented out		# while (w.nu > 0 && w.u[w.nu-1].typ == wrap->UPD)		#	w.nu--; 		# w.nu = 1;	NEW commented out		if (protof == nil)			protof = w.u[0].dir + "/proto";		name = w.name;	}	else {		if (protof == nil)			fatal("proto file missing");	}	(md5file, md5fd) := opentemp("wrap.md5", t);	if (md5fd == nil)		fatal(sys->sprint("cannot create %s", md5file));	keyring = load Keyring Keyring->PATH;	md5s = keyring->md5(nil, 0, nil, nil);	md5b := bufio->fopen(md5fd, Bufio->OWRITE);	if (md5b == nil)		fatal(sys->sprint("cannot open %s", md5file));	fprint(stderr, "wrap pass %s\n", protof);	obout := bout;	bout = md5b;	pass = 0;	proto->rdproto(protof, oldroot, protocaller);	bout.flush();	bout = md5b = nil;	digest := array[keyring->MD5dlen] of { * => byte 0 };	keyring->md5(nil, 0, digest, md5s);	md5s = nil;	(md5sort, md5sfd) := opentemp("wrap.md5s", t);	if (md5sfd == nil)		fatal(sys->sprint("cannot create %s", md5sort));	endc := chan of int;	md5fd = nil;	# close md5file	spawn fsort(md5sfd, md5file, endc);	md5sfd = nil;	res := <- endc;	if (res < 0)		fatal("sort failed");	if (update) {		(rmfile, rmfd) = opentemp("wrap.rm", t);		if (rmfd == nil)			fatal(sys->sprint("cannot create %s", rmfile));		rmed: list of string;		for(i := w.nu-1; i >= 0; i--){	# NEW does loop			w.u[i].bmd5.seek(big 0, Bufio->SEEKSTART);			while ((p := w.u[i].bmd5.gets('\n')) != nil) {				if(prefix != nil && !wrap->match(p, prefix))					continue;				if(notprefix != nil && !wrap->notmatch(p, notprefix))					continue;				(q, nil) := str->splitl(p, " ");				q = pathcat(root, q);				(ok, nil) := sys->stat(q);				if(ok < 0)					(ok, nil) = sys->stat(n2o(q));				if (len q >= 7 && q[len q - 7:] == "emu.new")	# quick hack for now					continue;				if (ok < 0){					for(r := rmed; r != nil; r = tl r)	# NEW to avoid duplication						if(hd r == q)							break;					if(r == nil){						# sys->fprint(rmfd, "%s\n", q);						rmed = q :: rmed;					}				}			}		}		for(r := rmed; r != nil; r = tl r)			sys->fprint(rmfd, "%s\n", hd r);		if(remfile != nil){			rfd := sys->open(remfile, Sys->OREAD);			rbuf := array[128] of byte;			for(;;){				n := sys->read(rfd, rbuf, 128);				if(n <= 0)					break;				sys->write(rmfd, rbuf, n);			}		}		rmfd = nil;		rmed = nil;	}	bout = obout;	if (update)		wrap->putwrap(bout, name, t, desc, w.tfull, prefix == nil && notprefix == nil, uid, gid);	else		wrap->putwrap(bout, name, t, desc, 0, 1, uid, gid);	wrap->putwrapfile(bout, name, t, "proto", protof, uid, gid);	wrap->putwrapfile(bout, name, t, "md5sum", md5sort, uid, gid);	if (update)		wrap->putwrapfile(bout, name, t, "remove", rmfile, uid, gid);	if(notesf != nil)		wrap->putwrapfile(bout, name, t, "notes", notesf, uid, gid);	md5s = keyring->md5(nil, 0, nil, nil);	pass = 1;	return digest;} wrapend(digest : array of byte){	digest0 := array[keyring->MD5dlen] of { * => byte 0 };	keyring->md5(nil, 0, digest0, md5s);	md5s = nil;	if (wrap->memcmp(digest, digest0, keyring->MD5dlen) != 0)		warn(sys->sprint("files changed underfoot %s %s", wrap->md5conv(digest), wrap->md5conv(digest0)));} mkarch(new : string, old : string, d : ref Dir){	if(pass == 0 && old != new)		onlist = (old, new) :: onlist;	if(prefix != nil && !wrap->match(new, prefix))		return;	if(notprefix != nil && !wrap->notmatch(new, notprefix))		return;	digest := array[keyring->MD5dlen] of { * => byte 0 };	wrap->md5file(old, digest);	(ok, nil) := wrap->getfileinfo(w, new, digest, nil, nil);	if (ok >= 0)		return;	n := array of byte new;	keyring->md5(n, len n, nil, md5s);	if (pass == 0) {		bout.puts(sys->sprint("%s %s\n", new, wrap->md5conv(digest)));		return;	}	if(verb)		fprint(stderr, "%s\n", new);	puthdr(new, d);	if(!(d.mode & Sys->DMDIR)) {		err := arch->putfile(bout, old, int d.length);		if (err != nil)			warn(err);	}} fsort(fd : ref Sys->FD, file : string, c : chan of int){	sys->pctl(Sys->FORKFD, nil);	sys->dup(fd.fd, 1);	cmd := "/dis/sort.dis";	m := load Command cmd;	if(m == nil) {		c <-= -1;		return;	}	m->init(nil, cmd :: file :: nil);	c <-= 0;} tmpfiles: list of string; opentemp(prefix: string, t: int): (string, ref Sys->FD){	name := sys->sprint("/tmp/%s.%ud.%d", prefix, t, sys->pctl(0, nil));	fd := sys->create(name, Sys->ORDWR, 8r666);	# fd := sys->create(name, Sys->ORDWR | Sys->ORCLOSE, 8r666); not on Nt	tmpfiles = name :: tmpfiles;	return (name, fd);} exits(){	wrap->end();	for( ; tmpfiles != nil; tmpfiles = tl tmpfiles)		sys->remove(hd tmpfiles);	exit;} 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;}