diff options
Diffstat (limited to 'appl/cmd/install/wrap.b')
| -rw-r--r-- | appl/cmd/install/wrap.b | 684 |
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; +} |
