forsyth20121205-174063a80cc13 years agoHistory
430 lines · 9.7 KB · Brainfuck
RawDownload
implement Install; ## Determine which packages need installing and calls install/inst # to actually install each one# # usage: install/install -d -F -g -s -u -i installdir -p platform -r root -P package include "sys.m";	sys: Sys;include "draw.m";include "bufio.m";	bufio: Bufio;	Iobuf: import bufio;include "string.m";	str: String;include "arg.m";	arg: Arg;include "readdir.m";	readdir : Readdir;include "sh.m"; Install: module{	init: fn(nil: ref Draw->Context, nil: list of string);}; # required dirs, usually in the standard inferno root.# The network download doesn't include them because of# problems with versions of tar that won't create empty dirs# so we'll make sure they exist. reqdirs := array [] of {	"/mnt",	"/mnt/wrap",	"/n",	"/n/remote",	"/tmp",}; YES, NO, QUIT, ERR : con iota;INST : con "install/inst";	# actual install programMTPT : con "/n/remote";	# mount point for user's inferno root debug := 0;force := 0;exitemu := 0;uflag := 0;stderr : ref Sys->FD;installdir := "/install";platform := "Plan9";lcplatform : string;root := "/usr/inferno";local: int;global: int = 1;waitfd : ref Sys->FD; Product : adt {	name : string;	pkgs : ref Package;	nxt : ref Product;}; Package : adt {	name : string;	nxt : ref Package;}; instprods : ref Product;	# products/packages already installed # platform independent packagesxpkgs := array[] of { "inferno", "utils", "src", "ipaq", "minitel", "sds" };ypkgs: list of string;		init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	stderr = sys->fildes(2); 	# Hack for network download...	# make sure the dirs we need exist	for (dirix := 0; dirix < len reqdirs; dirix++) {		dir := reqdirs[dirix];		(exists, nil) := sys->stat(dir);		if (exists == -1) {			fd := sys->create(dir, Sys->OREAD, Sys->DMDIR + 8r7775);			if (fd == nil)				fatal(sys->sprint("cannot create directory %s: %r\n", dir));			fd = nil;		}	} 	bufio = load Bufio Bufio->PATH;	if(bufio == nil)		fatal(sys->sprint("cannot load %s: %r\n", Bufio->PATH));	readdir = load Readdir Readdir->PATH;	if(readdir == nil)		fatal(sys->sprint("cannot load %s: %r\n", Readdir->PATH));	str = load String String->PATH;	if(str == nil)		fatal(sys->sprint("cannot load %s: %r\n", String->PATH));	arg = load Arg Arg->PATH;	if(arg == nil)		fatal(sys->sprint("cannot load %s: %r\n", Arg->PATH));	arg->init(args);	while((c := arg->opt()) != 0) {		case c {			'd' =>				debug = 1;			'F' =>				force = 1;			's' =>				exitemu = 1;			'i' => 				installdir = arg->arg();				if (installdir == nil)					fatal("install directory missing");			'p' =>				platform = arg->arg();				if (platform == nil)					fatal("platform missing");			'P' =>				pkg := arg->arg();				if (pkg == nil)					fatal("package missing");				ypkgs = pkg :: ypkgs;			'r' =>				root = arg->arg();				if (root == nil)					fatal("inferno root missing");			'u' =>				uflag = 1;			'g' =>				global = 0;			'*' =>				usage();		}	}	if (arg->argv() != nil)		usage();	lcplatform = str->tolower(platform);	(ok, dir) := sys->stat(installdir);	if (ok < 0)		fatal(sys->sprint("cannot open install directory %s", installdir));	nt := lcplatform == "nt";	if (nt) {		# root os of the form ?:/.........		if (len root < 3 || root[1] != ':' || root[2] != '/')			fatal(sys->sprint("root %s not of the form ?:/.......", root));		spec := root[0:2];		root = root[2:];		if (sys->bind("#U"+spec, MTPT, Sys->MREPL|Sys->MCREATE) < 0)			fatal(sys->sprint("cannot bind to drive %s", spec));	}	else {		if (root[0] != '/')			fatal(sys->sprint("root %s must be an absolute path name", root));		if (sys->bind("#U*", MTPT, Sys->MREPL|Sys->MCREATE) < 0)			fatal("cannot bind to system root");	}	(ok, dir) = sys->stat(MTPT+root);	if (ok >= 0) {		if ((dir.mode & Sys->DMDIR) == 0)			fatal(sys->sprint("inferno root %s is not a directory", root));	}	else if (sys->create(MTPT+root, Sys->OREAD, 8r775 | Sys->DMDIR) == nil)		fatal(sys->sprint("cannot create inferno root %s: %r", root));	# need a writable tmp directory /tmp in case installing from CD	(ok, dir) = sys->stat(MTPT+root+"/tmp");	if (ok >= 0) {		if ((dir.mode & Sys->DMDIR) == 0)			fatal(sys->sprint("inferno root tmp %s is not a directory", root+"/tmp"));	}	else if (sys->create(MTPT+root+"/tmp", Sys->OREAD, 8r775 | Sys->DMDIR) == nil)		fatal(sys->sprint("cannot create inferno root tmp %s: %r", root+"/tmp"));	if (sys->bind(MTPT+root, MTPT, Sys->MREPL | Sys->MCREATE) < 0)		fatal("cannot bind inferno root");	if (sys->bind(MTPT+"/tmp", "/tmp", Sys->MREPL | Sys->MCREATE) < 0)		fatal("cannot bind inferno root tmp");	root = MTPT;		if (nt || 1)		local = 1;	else {		sys->print("You can either install software specific to %s only or\n", platform);		sys->print(" install software for all platforms that we support.\n");		sys->print("If you are unsure what to do, answer yes to the question following.\n");		sys->print(" You can install the remainder of the software at a later date if desired.\n");		sys->print("\n");		b := bufio->fopen(sys->fildes(0), Bufio->OREAD);		if (b == nil)			fatal("cannot open stdin");		for (;;) {			sys->print("Install software specific to %s only ? (yes/no/quit) ", platform);			resp := getresponse(b);			ans := answer(resp);			if (ans == QUIT)				exit;			else if (ans == ERR)				sys->print("bad response %s\n\n", resp);			else {				local = ans == YES;				break;			}		}	}	instprods = dowraps(root+"/wrap");	doprods(installdir);	if (!nt)		sys->print("installation complete\n");	if (exitemu)		shutdown();} getresponse(b : ref Iobuf) : string{	s := b.gets('\n');	while (s != nil && (s[0] == ' ' || s[0] == '\t'))		s = s[1:];	while (s != nil && ((c := s[len s - 1]) == ' ' || c == '\t' || c == '\n'))		s = s[0: len s - 1];	return s;} answer(s : string) : int{	s = str->tolower(s);	if (s == "y" || s == "yes")		return YES;	if (s == "n" || s == "no")		return NO;	if (s == "q" || s == "quit")		return QUIT;	return ERR;} usage(){	fatal("Usage: install [-d] [-F] [-s] [-u] [-i installdir ] [-p platform ] [-r root]");} fatal(s : string){	sys->fprint(stderr, "install: %s\n", s);	exit;} dowraps(d : string) : ref Product{	p : ref Product; 	# make an inventory of what is already apparently installed	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);	for (i := 0; i < n; i++) {		if (dir[i].mode & Sys->DMDIR) {			p = ref Product(str->tolower(dir[i].name), nil, p);			p.pkgs = dowrap(d + "/" + dir[i].name);		}	}	return p;} dowrap(d : string) : ref Package{	p : ref Package; 	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);	for (i := 0; i < n; i++)		p = ref Package(dir[i].name, p);	return p;}	doprods(d : string){	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);	for (i := 0; i < n; i++) {		if (dir[i].mode & Sys->DMDIR)			doprod(str->tolower(dir[i].name), d + "/" + dir[i].name);	}} doprod(pr : string, d : string){	# base package, updates and update packages have the name	# <timestamp> or <timestamp.gz>	if (!wanted(pr))		return;	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);	for (i := 0; i < n; i++) {		pk := dir[i].name;		l := len pk;		if (l >= 4 && pk[l-3:l] == ".gz")			pk = pk[0:l-3];		else if (l >= 5 && (pk[l-4:] == ".tgz" || pk[l-4:] == ".9gz"))			pk = pk[0:l-4];		dopkg(pk, pr, d+"/"+dir[i].name);			}} dopkg(pk : string, pr : string, d : string){	if (!installed(pk, pr))		install(d);} installed(pkg : string, prd : string) : int{	for (pr := instprods; pr != nil; pr = pr.nxt) {		if (pr.name == prd) {			for (pk := pr.pkgs; pk != nil; pk = pk.nxt) {				if (pk.name == pkg)					return 1;			}			return 0;		}	}	return 0;} lookup(pr : string) : int{	for (i := 0; i < len xpkgs; i++) {		if (xpkgs[i] == pr)			return i;	}	return -1;} plookup(pr: string): int{	for(ps := ypkgs; ps != nil; ps = tl ps)		if(pr == hd ps)			return 1;	return 0;} wanted(pr : string) : int{	if (!local || global)		return 1;	if(ypkgs != nil)	# overrides everything else		return plookup(pr);	found := lookup(pr);	if (found >= 0)		return 1;	return pr == lcplatform || prefix(lcplatform, pr);} install(d : string){	if (waitfd == nil)		waitfd = openwait(sys->pctl(0, nil));	sys->fprint(stderr, "installing package %s\n", d);	if (debug)		return;	c := chan of int;	args := "-t" :: "-v" :: "-r" :: root :: d :: nil;	if (uflag)		args = "-u" :: args;	if (force)		args = "-F" :: args;	spawn exec(INST, INST :: args, c);	execpid := <- c;	wait(waitfd, execpid);} exec(cmd : string, argl : list of string, ci : chan of int){	ci <-= sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: stderr.fd :: nil);	file := cmd;	if(len file<4 || file[len file-4:] !=".dis")		file += ".dis";	c := load Command file;	if(c == nil) {		err := sys->sprint("%r");		if(file[0] !='/' && file[0:2] !="./") {			c = load Command "/dis/"+file; 			if(c == nil)				err = sys->sprint("%r");		}		if(c == nil)			fatal(sys->sprint("%s: %s\n", cmd, err));	}	c->init(nil, argl);} openwait(pid : int) : ref Sys->FD{	w := sys->sprint("#p/%d/wait", pid);	fd := sys->open(w, Sys->OREAD);	if (fd == nil)		fatal("fd == nil in wait");	return fd;}	wait(wfd : ref Sys->FD, wpid : int){	n : int; 	buf := array[Sys->WAITLEN] of byte;	status := "";	for(;;) {		if ((n = sys->read(wfd, buf, len buf)) < 0)			fatal("bad read in wait");		status = string buf[0:n];		break;	}	if (int status != wpid)		fatal("bad status in wait");	if(status[len status - 1] != ':')		fatal(sys->sprint("%s\n", status));} shutdown(){	fd := sys->open("/dev/sysctl", sys->OWRITE);	if(fd == nil)		fatal("cannot shutdown emu");	if (sys->write(fd, array of byte "halt", 4) < 0)		fatal(sys->sprint("shutdown: write failed: %r\n"));} prefix(s, t : string) : int{	if (len s <= len t)		return t[0:len s] == s;	return 0;}