summaryrefslogtreecommitdiff
path: root/appl/cmd/install/create.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/install/create.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/install/create.b')
-rw-r--r--appl/cmd/install/create.b445
1 files changed, 445 insertions, 0 deletions
diff --git a/appl/cmd/install/create.b b/appl/cmd/install/create.b
new file mode 100644
index 00000000..848fdc6b
--- /dev/null
+++ b/appl/cmd/install/create.b
@@ -0,0 +1,445 @@
+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 archive
+protof: 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); # NEW
+remfile: 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;
+}