summaryrefslogtreecommitdiff
path: root/appl/cmd/install/wrap.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/install/wrap.b')
-rw-r--r--appl/cmd/install/wrap.b684
1 files changed, 684 insertions, 0 deletions
diff --git a/appl/cmd/install/wrap.b b/appl/cmd/install/wrap.b
new file mode 100644
index 00000000..1b90c765
--- /dev/null
+++ b/appl/cmd/install/wrap.b
@@ -0,0 +1,684 @@
+implement Wrap;
+
+include "sys.m";
+ sys : Sys;
+include "draw.m";
+include "bufio.m";
+ bufio : Bufio;
+ Iobuf : import bufio;
+include "keyring.m";
+ keyring : Keyring;
+include "sh.m";
+include "arch.m";
+ arch : Arch;
+include "wrap.m";
+include "archfs.m";
+
+archpid := -1;
+gzfd: ref Sys->FD;
+gzfile: string;
+
+init(bio: Bufio)
+{
+ sys = load Sys Sys->PATH;
+ if(bio == nil)
+ bufio = load Bufio Bufio->PATH;
+ else
+ bufio = bio;
+ keyring = load Keyring Keyring->PATH;
+ arch = load Arch Arch->PATH;
+ arch->init(bufio);
+}
+
+end()
+{
+ if(gzfile != nil)
+ sys->remove(gzfile);
+ if (archpid > 0){
+ fd := sys->open("#p/" + string archpid + "/ctl", sys->OWRITE);
+ if (fd != nil)
+ sys->fprint(fd, "killgrp");
+ }
+}
+
+archfs(f : string, mtpt : string, all : int, c : chan of int)
+{
+ sys->pctl(Sys->NEWPGRP, nil);
+ cmd := "/dis/install/archfs.dis";
+ m := load Archfs Archfs->PATH;
+ if(m == nil) {
+ c <-= -1;
+ return;
+ }
+ ch := chan of int;
+ if (all)
+ spawn m->initc(cmd :: "-m" :: mtpt :: f :: nil, ch);
+ else
+ spawn m->initc(cmd :: "-s" :: "-m" :: mtpt :: f :: "/wrap" :: nil, ch);
+ pid := <- ch;
+ c <-= pid;
+}
+
+mountarch(f : string, mtpt : string, all : int) : int
+{
+ c := chan of int;
+ spawn archfs(f, mtpt, all, c);
+ pid := <- c;
+ if (pid < 0) {
+ if(pid == -1)
+ sys->fprint(sys->fildes(2), "fatal: cannot run archfs\n");
+ # else probably not an archive file
+ return -1;
+ }
+ archpid = pid;
+ return 0;
+}
+
+openmount(f : string, d : string) : ref Wrapped
+{
+ if (f == nil) {
+ p := d+"/wrap";
+ f = getfirstdir(p);
+ if (f == nil)
+ return nil;
+ }
+ w := ref Wrapped;
+ w.name = f;
+ w.root = d;
+ # p := d + "/wrap/" + f;
+ p := pathcat(d, pathcat("wrap", f));
+ (w.u, w.nu, w.tfull) = openupdate(p);
+ if (w.nu < 0) {
+ closewrap(w);
+ return nil;
+ }
+ return w;
+}
+
+closewrap(w : ref Wrapped)
+{
+ w = nil;
+}
+
+openwraphdr(f : string, d : string, argl : list of string, all : int) : ref Wrapped
+{
+ argl = nil;
+ (ok, dir) := sys->stat(f);
+ if (ok < 0 || dir.mode & Sys->DMDIR)
+ return openwrap(f, d, all);
+ (nf, fd) := arch->openarchgz(f);
+ if (nf != nil) {
+ gzfile = nf;
+ f = nf;
+ gzfd = fd;
+ }
+ return openwrap(f, "/mnt/wrap", all);
+}
+
+openwrap(f : string, d : string, all : int) : ref Wrapped
+{
+ if (d == nil)
+ d = "/";
+ if((w := openmount(f, d)) != nil)
+ return w; # don't mess about if /wrap/ structure exists
+ (ok, dir) := sys->stat(f);
+ if (ok < 0)
+ return nil;
+ # accept root/ or root/wrap/pkgname
+ if (dir.mode & Sys->DMDIR) {
+ d = f;
+ if ((i := strstr(f, "/wrap/")) >= 0) {
+ f = f[i+6:];
+ d = d[0:i+6];
+ }
+ else
+ f = nil;
+ return openmount(f, d);
+ }
+ (ok, dir) = sys->stat(f);
+ if (ok < 0 || dir.mode & Sys->DMDIR)
+ return openmount(f, d); # ?
+ if (mountarch(f, d, all) < 0)
+ return nil;
+ return openmount(nil, d);
+}
+
+getfirstdir(d : string) : string
+{
+ if ((fd := sys->open(d, Sys->OREAD)) == nil)
+ return nil;
+ for(;;){
+ (n, dir) := sys->dirread(fd);
+ if(n <= 0)
+ break;
+ for(i:=0; i<n; i++)
+ if(dir[i].mode & Sys->DMDIR)
+ return dir[i].name;
+ }
+ return nil;
+}
+
+NONE : con 0;
+
+sniffdir(base : string, elem : string) : (int, int)
+{
+ # t := int elem;
+ t := string2now(elem, 0);
+ if (t == 0)
+ return (NONE, 0);
+ # buf := sys->sprint("%ud", t);
+ # if (buf != elem)
+ # return (NONE, 0);
+ rv := NONE;
+ p := base + "/" + elem + "/package";
+ (ok, nil) := sys->stat(p);
+ if (ok >= 0)
+ rv |= FULL;
+ p = base + "/" + elem + "/update";
+ (ok, nil) = sys->stat(p);
+ if (ok >= 0)
+ rv |= UPD;
+ return (rv, t);
+}
+
+openupdate(d : string) : (array of Update, int, int)
+{
+ u : array of Update;
+
+ if ((fd := sys->open(d, Sys->OREAD)) == nil)
+ return (nil, -1, 0);
+ #
+ # We are looking to find the most recent full
+ # package; anything before that is irrelevant.
+ # Also figure out the most recent package update.
+ # Non-package updates before that are irrelevant.
+ # If there are no packages installed,
+ # grab all the updates we can find.
+ #
+ tbase := -1;
+ tfull := -1;
+ nu := 0;
+ for(;;){
+ (n, dir) := sys->dirread(fd);
+ if(n <= 0)
+ break;
+ for(i := 0; i < n; i++){
+ (k, t) := sniffdir(d, dir[i].name);
+ case (k) {
+ FULL =>
+ nu++;
+ if (t > tfull)
+ tfull = t;
+ if (t > tbase)
+ tbase = t;
+ FULL|UPD =>
+ nu++;
+ if (t > tfull)
+ tfull = t;
+ UPD =>
+ nu++;
+ }
+ }
+ }
+ if (nu == 0)
+ return (nil, -1, 0);
+ u = nil;
+ nu = 0;
+ if ((fd = sys->open(d, Sys->OREAD)) == nil)
+ return (nil, -1, 0);
+ for(;;){
+ (n, dir) := sys->dirread(fd);
+ if(n <= 0)
+ break;
+ for(i := 0; i < n; i++){
+ (k, t) := sniffdir(d, dir[i].name);
+ if (k == 0)
+ continue;
+ if (t < tbase)
+ continue;
+ if (t < tfull && k == UPD)
+ continue;
+ if (nu%8 == 0) {
+ newu := array[nu+8] of Update;
+ newu[0:] = u[0:nu];
+ u = newu;
+ }
+ u[nu].typ = k;
+ if (readupdate(u, nu, d, dir[i].name) != nil)
+ nu++;
+ }
+ }
+ if (nu == 0)
+ return (nil, -1, 0);
+ qsort(u, nu);
+ return (u, nu, tfull);
+}
+
+readupdate(u : array of Update, ui : int, base : string, elem : string) : array of Update
+{
+ # u[ui].dir = base + "/" + elem;
+ u[ui].dir = pathcat(base, elem);
+ p := u[ui].dir + "/desc";
+ u[ui].desc = readfile(p);
+ # u[ui].time = int elem;
+ u[ui].time = string2now(elem, 0);
+ p = u[ui].dir + "/md5sum";
+ u[ui].bmd5 = bufio->open(p, Bufio->OREAD);
+ p = u[ui].dir + "/update";
+ q := readfile(p);
+ if (q != nil)
+ u[ui].utime = int q;
+ else
+ u[ui].utime = 0;
+ if (u[ui].bmd5 == nil)
+ return nil;
+ return u;
+}
+
+readfile(s : string) : string
+{
+ (ok, d) := sys->stat(s);
+ if (ok < 0)
+ return nil;
+ buf := array[int d.length] of byte;
+ if ((fd := sys->open(s, Sys->OREAD)) == nil || sys->read(fd, buf, int d.length) != int d.length)
+ return nil;
+ s = string buf;
+ ls := len s;
+ if (s[ls-1] == '\n')
+ s = s[0:ls-1];
+ return s;
+}
+
+hex(c : int) : int
+{
+ if (c >= '0' && c <= '9')
+ return c-'0';
+ if (c >= 'a' && c <= 'f')
+ return c-'a'+10;
+ if (c >= 'A' && c <= 'F')
+ return c-'A'+10;
+ return -1;
+}
+
+getfileinfo(w : ref Wrapped, f : string, rdigest : array of byte, wdigest : array of byte, ardigest: array of byte) : (int, int)
+{
+ p : string;
+
+ if (w == nil)
+ return (-1, 0);
+ digest := array[keyring->MD5dlen] of { * => byte 0 };
+ for (i := w.nu-1; i >= 0; i--){
+ if ((p = bsearch(w.u[i].bmd5, f)) == nil)
+ continue;
+ if (p == nil)
+ continue;
+ k := 0;
+ while (k < len p && p[k] != ' ')
+ k++;
+ if (k == len p)
+ continue;
+ q := p[k+1:];
+ if (q == nil)
+ continue;
+ if (len q != 2*Keyring->MD5dlen+1)
+ continue;
+ for (j := 0; j < Keyring->MD5dlen; j++) {
+ a := hex(q[2*j]);
+ b := hex(q[2*j+1]);
+ if (a < 0 || b < 0)
+ break;
+ digest[j] = byte ((a<<4)|b);
+ }
+ if(j != Keyring->MD5dlen)
+ continue;
+ if(rdigest == nil || memcmp(rdigest, digest, keyring->MD5dlen) == 0 || (ardigest != nil && memcmp(ardigest, digest, keyring->MD5dlen) == 0))
+ break;
+ else
+ return (-1, 0); # NEW
+ }
+ if(i < 0)
+ return (-1, 0);
+ if(wdigest != nil)
+ wdigest[0:] = rdigest;
+ return (0, w.u[i].time);
+
+
+}
+
+bsearch(b : ref Bufio->Iobuf, p : string) : string
+{
+ if (b == nil)
+ return nil;
+ lo := 0;
+ b.seek(big 0, Bufio->SEEKEND);
+ hi := int b.offset();
+ l := len p;
+ while (lo < hi) {
+ m := (lo+hi)/2;
+ b.seek(big m, Bufio->SEEKSTART);
+ b.gets('\n');
+ if (int b.offset() == hi) {
+ bgetbackc(b);
+ m = int b.offset();
+ while (m-- > lo) {
+ if (bgetbackc(b) == '\n') {
+ b.getc();
+ break;
+ }
+ }
+ }
+ s := b.gets('\n');
+ if (len s >= l+1 && s[0:l] == p && (s[l] == ' ' || s[l] == '\n'))
+ return s;
+ if (s < p)
+ lo = int b.offset();
+ else
+ hi = int b.offset()-len s;
+ }
+ return nil;
+}
+
+bgetbackc(b : ref Bufio->Iobuf) : int
+{
+ m := int b.offset();
+ b.seek(big (m-1), Bufio->SEEKSTART);
+ c := b.getc();
+ b.ungetc();
+ return c;
+}
+
+strstr(s : string, p : string) : int
+{
+ lp := len p;
+ ls := len s;
+ for (i := 0; i < ls-lp; i++)
+ if (s[i:i+lp] == p)
+ return i;
+ return -1;
+}
+
+qsort(a : array of Update, n : int)
+{
+ i, j : int;
+ t : Update;
+
+ while(n > 1) {
+ i = n>>1;
+ t = a[0]; a[0] = a[i]; a[i] = t;
+ i = 0;
+ j = n;
+ for(;;) {
+ do
+ i++;
+ while(i < n && a[i].time < a[0].time);
+ do
+ j--;
+ while(j > 0 && a[j].time > a[0].time);
+ if(j < i)
+ break;
+ t = a[i]; a[i] = a[j]; a[j] = t;
+ }
+ t = a[0]; a[0] = a[j]; a[j] = t;
+ n = n-j-1;
+ if(j >= n) {
+ qsort(a, j);
+ a = a[j+1:];
+ } else {
+ qsort(a[j+1:], n);
+ n = j;
+ }
+ }
+}
+
+md5file(file : string, digest : array of byte) : int
+{
+ (ok, d) := sys->stat(file);
+ if (ok < 0)
+ return -1;
+ if (d.mode & Sys->DMDIR)
+ return 0;
+ bio := bufio->open(file, Bufio->OREAD);
+ if (bio == nil)
+ return -1;
+ # return md5sum(bio, digest, d.length);
+ buff := array[Sys->ATOMICIO] of byte;
+ ds := keyring->md5(nil, 0, nil, nil);
+ while ((n := bio.read(buff, len buff)) > 0)
+ keyring->md5(buff, n, nil, ds);
+ keyring->md5(nil, 0, digest, ds);
+ bio = nil;
+ return 0;
+}
+
+md5sum(b : ref Iobuf, digest : array of byte, leng : int) : int
+{
+ ds := keyring->md5(nil, 0, nil, nil);
+ buff := array[Sys->ATOMICIO] of byte;
+ while (leng > 0) {
+ if (leng > len buff)
+ n := len buff;
+ else
+ n = leng;
+ if ((n = b.read(buff, n)) <= 0)
+ return -1;
+ keyring->md5(buff, n, nil, ds);
+ leng -= n;
+ }
+ keyring->md5(nil, 0, digest, ds);
+ return 0;
+}
+
+md5conv(d : array of byte) : string
+{
+ s : string = nil;
+
+ for (i := 0; i < keyring->MD5dlen; i++)
+ s += sys->sprint("%.2ux", int d[i]);
+ return s;
+}
+
+zd : Sys->Dir;
+
+newd(time : int, uid : string, gid : string) : ref Sys->Dir
+{
+ d := ref Sys->Dir;
+ *d = zd;
+ d.uid = uid;
+ d.gid = gid;
+ d.mtime = time;
+ return d;
+}
+
+putwrapfile(b : ref Iobuf, name : string, time : int, elem : string, file : string, uid : string, gid : string)
+{
+ d := newd(time, uid, gid);
+ d.mode = 8r444;
+ (ok, dir) := sys->stat(file);
+ if (ok < 0)
+ sys->fprint(sys->fildes(2), "cannot stat %s: %r", file);
+ d.length = dir.length;
+ # s := "/wrap/"+name+"/"+sys->sprint("%ud", time)+"/"+elem;
+ s := "/wrap/"+name+"/"+now2string(time, 0)+"/"+elem;
+ arch->puthdr(b, s, d);
+ arch->putfile(b, file, int d.length);
+}
+
+putwrap(b : ref Iobuf, name : string, time : int, desc : string, utime : int, pkg : int, uid : string, gid : string)
+{
+ if (!(utime || pkg))
+ sys->fprint(sys->fildes(2), "bad precondition in putwrap()");
+ d := newd(time, uid, gid);
+ d.mode = Sys->DMDIR|8r775;
+ s := "/wrap";
+ arch->puthdr(b, s, d);
+ s += "/"+name;
+ arch->puthdr(b, s, d);
+ # s += "/"+sys->sprint("%ud", time);
+ s += "/"+now2string(time, 0);
+ arch->puthdr(b, s, d);
+ d.mode = 8r444;
+ s += "/";
+ dir := s;
+ if (utime) {
+ s = dir+"update";
+ d.length = big 23;
+ arch->puthdr(b, s, d);
+ arch->putstring(b, sys->sprint("%22ud\n", utime));
+ }
+ if (pkg) {
+ s = dir+"package";
+ d.length = big 0;
+ arch->puthdr(b, s, d);
+ }
+ if (desc != nil) {
+ s = dir+"desc";
+ d.length = big (len desc+1);
+ d.mode = 8r444;
+ arch->puthdr(b, s, d);
+ arch->putstring(b, desc+"\n");
+ }
+}
+
+memcmp(b1, b2 : array of byte, n : int) : int
+{
+ for (i := 0; i < n; i++)
+ if (b1[i] < b2[i])
+ return -1;
+ else if (b1[i] > b2[i])
+ return 1;
+ return 0;
+}
+
+strprefix(s: string, pre: string): int
+{
+ return len s >= (l := len pre) && s[0:l] == pre;
+}
+
+match(s: string, pre: list of string): int
+{
+ if(pre == nil || s == "/wrap" || strprefix(s, "/wrap/"))
+ return 1;
+ for( ; pre != nil; pre = tl pre)
+ if(strprefix(s, hd pre))
+ return 1;
+ return 0;
+}
+
+notmatch(s: string, pre: list of string): int
+{
+ if(pre == nil || s == "/wrap" || strprefix(s, "/wrap/"))
+ return 1;
+ for( ; pre != nil; pre = tl pre)
+ if(strprefix(s, hd pre))
+ return 0;
+ 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;
+}
+
+md5filea(file : string, digest : array of byte) : int
+{
+ n, n0: int;
+
+ (ok, d) := sys->stat(file);
+ if (ok < 0)
+ return -1;
+ if (d.mode & Sys->DMDIR)
+ return 0;
+ bio := bufio->open(file, Bufio->OREAD);
+ if (bio == nil)
+ return -1;
+ buff := array[Sys->ATOMICIO] of byte;
+ m := len buff;
+ ds := keyring->md5(nil, 0, nil, nil);
+ r := 0;
+ while(1){
+ if(r){
+ if((n = bio.read(buff[1:], m-1)) <= 0)
+ break;
+ n++;
+ }
+ else{
+ if ((n = bio.read(buff, m)) <= 0)
+ break;
+ }
+ (n0, r) = remcr(buff, n);
+ if(r){
+ keyring->md5(buff, n0-1, nil, ds);
+ buff[0] = byte '\r';
+ }
+ else
+ keyring->md5(buff, n0, nil, ds);
+ }
+ if(r)
+ keyring->md5(buff, 1, nil, ds);
+ keyring->md5(nil, 0, digest, ds);
+ bio = nil;
+ return 0;
+}
+
+remcr(b: array of byte, n: int): (int, int)
+{
+ if(n == 0)
+ return (0, 0);
+ for(i := 0; i < n; ){
+ if(b[i] == byte '\r' && i+1 < n && b[i+1] == byte '\n')
+ b[i:] = b[i+1:n--];
+ else
+ i++;
+ }
+ return (n, b[n-1] == byte '\r');
+}
+
+TEN2EIGHT: con 100000000;
+
+now2string(n: int, flag: int): string
+{
+ if(flag == 0)
+ return sys->sprint("%ud", n);
+ if(n < 0)
+ return nil;
+ q := n/TEN2EIGHT;
+ s := "0" + string (n-TEN2EIGHT*q);
+ while(len s < 9)
+ s = "0" + s;
+ if(q <= 9)
+ s[0] = '0' + q - 0;
+ else if(q <= 21)
+ s[0] = 'A' + q - 10;
+ else
+ return nil;
+ return s;
+}
+
+string2now(s: string, flag: int): int
+{
+ if(flag == 0 && s[0] != 'A')
+ return int s;
+ if(len s != 9)
+ return 0;
+ r := int s[1: ];
+ c := s[0];
+ if(c >= '0' && c <= '9')
+ q := c - '0' + 0;
+ else if(c >= 'A' && c <= 'L')
+ q = c - 'A' + 10;
+ else
+ return 0;
+ n := TEN2EIGHT*q + r;
+ if(n < 0)
+ return 0;
+ return n;
+}