package org.freertr.user; import java.io.File; import java.util.ArrayList; import java.util.List; import org.freertr.cry.cryHashGeneric; import org.freertr.cry.cryHashSha2256; import org.freertr.cry.cryUtils; import org.freertr.pipe.pipeShell; import org.freertr.pipe.pipeSide; import org.freertr.tab.tabGen; import org.freertr.util.bits; import org.freertr.util.cmds; /** * process image creation * * @author matecsaba */ public class userImage { /** * create instance */ public userImage() { } private pipeSide pip; private String tempDir = "../binDsk"; private String downDir = "../binDwn"; private String imgName = "../binImg/rtr"; private String found = ""; private int downMode = 1; private int hashMode = 3; private long regeTim = bits.getTime() - Integer.MAX_VALUE; private String miro = "http://deb.debian.org/debian/"; private String qemu = "x86_64"; private String arch = "amd64"; private String boot = "x86_64-efi"; private String kern = "cloud-amd64"; private String unam = "x86_64"; private String comp = "clang"; private String cabi = "gnu"; private String ctrg = "x86_64"; private String carc = "little-endian"; private String grub = "efi-amd64-bin"; private String uefi = "bootx64.efi"; private String xtra = ""; private boolean depends = true; private tabGen catalogs = new tabGen(); private tabGen allPkgs = new tabGen(); private tabGen allPrvs = new tabGen(); private tabGen missing = new tabGen(); private tabGen selected = new tabGen(); private tabGen forbidden = new tabGen(); private tabGen discarded = new tabGen(); private userImagePkg matchReg(tabGen lst, String a) { for (int i = 0; i < lst.size(); i++) { userImagePkg pkg = lst.get(i); if (a.matches(pkg.name)) { return pkg; } } return null; } private void filterCat(tabGen trg, userImageCat cat, tabGen src) { trg.clear(); for (int i = 0; i < src.size(); i++) { userImagePkg cur = src.get(i); if (cur.cat != cat) { continue; } trg.add(cur); } } private String dumpList(tabGen lst, boolean done, boolean detail) { String s = ""; long o = 0; int p = 0; for (int i = 0; i < lst.size(); i++) { userImagePkg pkg = lst.get(i); if (done != pkg.done) { continue; } o += pkg.size; p++; if (!detail) { continue; } s += " " + pkg.name; } if (detail) { s += " -"; } s += " " + (o / 1024) + " kb in " + p + " packages"; return s; } private String getPackageName(userImagePkg pkg) { return downDir + "/" + arch + "-" + pkg.name + ".deb"; } private int execCmd(String s) { pip.linePut("!" + s + "."); pipeShell sh = pipeShell.exec(pip, "sh -c", s, false, true, false, true); sh.waitFor(); return sh.resultNum(); } private boolean delFiles(String s) { return execCmd("rm -rf " + s) != 0; } private boolean downloadFile(String url, String fil, int siz) { File f = new File(fil); switch (downMode) { case 3: if (!f.exists()) { break; } if (siz < 0) { if (f.lastModified() < regeTim) { break; } return false; } if (f.length() == siz) { return false; } break; case 2: if (f.exists()) { return false; } break; case 1: break; case 0: return false; } userFlash.delete(fil + ".tmp"); if (execCmd("wget -O " + fil + ".tmp " + url) != 0) { pip.linePut("error downloading " + fil); return true; } userFlash.rename(fil, fil + ".bak", true, true); userFlash.rename(fil + ".tmp", fil, true, true); return false; } private boolean verifyPackage(String fil, String sum) { cryHashGeneric h = new cryHashSha2256(); h.init(); if (cryUtils.hashFile(h, new File(fil))) { pip.linePut("error reading " + fil); return true; } if (!sum.equals(cryUtils.hash2hex(h))) { pip.linePut("checksum mismatch on " + fil); return true; } pip.linePut(fil + " verified"); return false; } private boolean readUpCatalog(userImageCat cat, List res) { if (res == null) { return true; } userImagePkg pkg = new userImagePkg(""); for (int cnt = 0; cnt < res.size(); cnt++) { String a = res.get(cnt).trim(); int i = a.indexOf(":"); if (i < 1) { continue; } String b = a.substring(i + 1, a.length()).trim(); a = a.substring(0, i).trim().toLowerCase(); if (a.equals("package")) { pkg.cat = cat; allPkgs.put(pkg); pkg = new userImagePkg(b); continue; } if (a.equals("provides")) { List r = new ArrayList(); userImagePkg.listPackages(b, r); for (i = 0; i < r.size(); i++) { a = r.get(i); userImagePrv p = new userImagePrv(a); p.who = pkg; allPrvs.put(p); } continue; } if (a.equals("depends")) { pkg.addDepends(b); continue; } if (a.equals("pre-depends")) { pkg.addDepends(b); continue; } if (a.equals("sha256")) { pkg.sum = b; continue; } if (a.equals("filename")) { pkg.file = b; continue; } if (a.equals("version")) { pkg.vers = b; continue; } if (a.equals("size")) { pkg.size = bits.str2num(b); continue; } } return false; } private boolean readUpCatalog(cmds cmd) { String name = cmd.word(); String comp = cmd.word(); String mirr = cmd.word(); String dist = cmd.word(); for (;;) { String pool = cmd.word(); if (pool.length() < 1) { break; } userImageCat cat = new userImageCat(name + "-" + pool); cat.url = mirr; cat.arch = arch; catalogs.add(cat); cmd.error("reading " + name + " " + pool + " list"); String cat1 = tempDir + "/" + name + "-" + pool + ".txt"; String cat2 = downDir + "/" + arch + "--" + name + "-" + pool + "." + comp; userFlash.delete(cat1); if (downloadFile(mirr + "dists/" + dist + "/" + pool + "/binary-" + arch + "/Packages." + comp, cat2, -1)) { return true; } if (comp.equals("xz")) { execCmd("cp " + cat2 + " " + cat1 + ".xz"); execCmd("xz -d " + cat1 + ".xz"); } if (comp.equals("gz")) { execCmd("cp " + cat2 + " " + cat1 + ".gz"); execCmd("gzip -d " + cat1 + ".gz"); } List res = bits.txt2buf(cat1); userFlash.delete(cat1); if (readUpCatalog(cat, res)) { cmd.error("parse failed"); return true; } } return false; } private boolean selectOnePackage(int level, String nam, String by) { nam = nam.trim(); if (nam.length() < 1) { return false; } userImagePkg pkt = new userImagePkg(nam); pkt = allPkgs.find(pkt); if (pkt == null) { userImagePrv prv = new userImagePrv(nam); prv = allPrvs.find(prv); if (prv == null) { missing.add(new userImagePkg(nam)); return false; } pkt = prv.who; } pkt.added = by; if (matchReg(forbidden, nam) != null) { discarded.add(pkt); return false; } if (selected.add(pkt) != null) { return true; } if (!depends) { return true; } for (int i = 0; i < pkt.depend.size(); i++) { selectOnePackage(level + 1, pkt.depend.get(i), nam); } return true; } /** * download one image * * @param pkg package to download * @return true on error, false on success */ private boolean downOneFile(userImagePkg pkg) { String name = getPackageName(pkg); if (pkg.done) { return false; } for (int i = 0; i < hashMode; i++) { if (downloadFile(pkg.cat.url + pkg.file, name, pkg.size)) { return true; } boolean vrfy = verifyPackage(name, pkg.sum); if (!vrfy) { return false; } userFlash.rename(name, name + ".bak", true, true); } return true; } private boolean downAllFiles() { for (int i = 0; i < selected.size(); i++) { userImagePkg pkg = selected.get(i); if (downOneFile(pkg)) { return true; } } return false; } private boolean instOneFile(String name) { return execCmd("dpkg-deb --fsys-tarfile " + name + " | tar -x --keep-directory-symlink -C " + tempDir + "/") != 0; } private boolean instOneFile(userImagePkg pkg) { String name = getPackageName(pkg); if (pkg.done) { pip.linePut("skipping " + name); return false; } pkg.done = true; return instOneFile(name); } private boolean instXtraFiles() { cmds cmd = new cmds("pkg", xtra); for (;;) { String a = cmd.word(); if (a.length() < 1) { break; } if (instOneFile(downDir + "/" + arch + "-" + a)) { return true; } } return false; } private boolean instAllFiles() { for (int i = 0; i < selected.size(); i++) { userImagePkg pkg = selected.get(i); if (instOneFile(pkg)) { return true; } } return false; } private boolean doIncludeAll(cmds c) { boolean res = false; for (;;) { String s = c.word(); if (s.length() < 1) { break; } cmds cmd = getCmd(s); res |= doIncludeOne(cmd); } return res; } private boolean doIncludeOne(cmds c) { String s = c.getRemaining(); c.error("including " + s); List lst = bits.txt2buf(s); if (lst == null) { c.error("no such file " + s); return true; } return doOneFile(lst); } private cmds getCmd(String s) { cmds c = new cmds("img", s); c.pipe = pip; return c; } private boolean doOneFile(List res) { for (int cnt = 0; cnt < res.size(); cnt++) { String s = res.get(cnt); s = s.replaceAll("%tmp%", tempDir); s = s.replaceAll("%dwn%", downDir); s = s.replaceAll("%img%", imgName); s = s.replaceAll("%mirr%", miro); s = s.replaceAll("%qemu%", qemu); s = s.replaceAll("%arch%", arch); s = s.replaceAll("%boot%", boot); s = s.replaceAll("%kern%", kern); s = s.replaceAll("%unam%", unam); s = s.replaceAll("%comp%", comp); s = s.replaceAll("%cabi%", cabi); s = s.replaceAll("%ctrg%", ctrg); s = s.replaceAll("%carc%", carc); s = s.replaceAll("%grub%", grub); s = s.replaceAll("%uefi%", uefi); s = s.replaceAll("%find%", found); s = s.replaceAll("%%", "%"); s += "#"; int i = s.indexOf("#"); s = s.substring(0, i).trim(); s += " "; i = s.indexOf(" "); String a = s.substring(0, i).trim().toLowerCase(); s = s.substring(i, s.length()).trim(); if (a.length() < 1) { continue; } pip.linePut("--> " + a + " " + s + " <--"); if (a.equals("exec")) { execCmd(s); continue; } cmds cmd = getCmd(a + " " + s); cmd.word(); if (a.equals("include")) { if (doIncludeOne(cmd)) { return true; } continue; } if (a.equals("inclall")) { if (doIncludeAll(cmd)) { return true; } continue; } if (a.equals("reget-time")) { regeTim = bits.getTime() - (bits.str2num(s) * 3600 * 1000); continue; } if (a.equals("download")) { downMode = bits.str2num(s); continue; } if (a.equals("hashdown")) { hashMode = bits.str2num(s); continue; } if (a.equals("mirr")) { miro = s; continue; } if (a.equals("qemu")) { qemu = s; continue; } if (a.equals("arch")) { arch = s; continue; } if (a.equals("boot")) { boot = s; continue; } if (a.equals("kern")) { kern = s; continue; } if (a.equals("unam")) { unam = s; continue; } if (a.equals("comp")) { comp = s; continue; } if (a.equals("cabi")) { cabi = s; continue; } if (a.equals("ctrg")) { ctrg = s; continue; } if (a.equals("carc")) { carc = s; continue; } if (a.equals("grub")) { grub = s; continue; } if (a.equals("uefi")) { uefi = s; continue; } if (a.equals("xtra")) { xtra = s; continue; } if (a.equals("temp")) { tempDir = s; continue; } if (a.equals("down")) { downDir = s; continue; } if (a.equals("image")) { imgName = s; continue; } if (a.equals("exit")) { break; } if (a.equals("find-clear")) { found = ""; continue; } if (a.equals("find-result")) { cmd.error("result='" + found + "'"); continue; } if (a.equals("find-file")) { i = s.indexOf(" "); a = s.substring(0, i); s = s.substring(i + 1, s.length()); File[] fl = userFlash.dirList(a); if (fl == null) { cmd.error("error getting list"); continue; } for (i = 0; i < fl.length; i++) { a = fl[i].getName(); if (!a.matches(s)) { continue; } found = a; break; } continue; } if (a.equals("catalog-sum")) { tabGen lst = new tabGen(); for (i = 0; i < catalogs.size(); i++) { userImageCat cat = catalogs.get(i); filterCat(lst, cat, selected); cmd.error(""); cmd.error("catalog " + cat + ":" + dumpList(lst, false, true)); } cmd.error(""); continue; } if (a.equals("catalog-read")) { cmds c = getCmd(s); if (readUpCatalog(c)) { return true; } continue; } if (a.equals("catalog-save")) { a = downDir + "/" + arch + "--" + cmd.word() + ".lst"; List don = new ArrayList(); for (i = 0; i < selected.size(); i++) { userImagePkg pkg = selected.get(i); if (!pkg.done) { continue; } don.add(getPackageName(pkg)); } List old = bits.txt2buf(a); bits.buf2txt(true, don, a); if (old == null) { continue; } for (i = 0; i < old.size(); i++) { a = old.get(i); if (a.length() < 1) { continue; } if (don.indexOf(a) >= 0) { continue; } cmd.error("renaming legacy " + a); userFlash.rename(a, a + ".bak", true, true); } continue; } if (a.equals("select-one")) { selectOnePackage(0, s, s); continue; } if (a.equals("select-all")) { for (;;) { a = cmd.word(); if (a.length() < 1) { break; } selectOnePackage(0, a, a); } continue; } if (a.equals("select-any")) { for (;;) { a = cmd.word(); if (a.length() < 1) { break; } if (selectOnePackage(0, a, a)) { break; } } continue; } if (a.equals("select-dep")) { depends = cmd.word().equals("yes"); continue; } if (a.equals("select-dis")) { forbidden.add(new userImagePkg(s)); continue; } if (a.equals("select-del")) { selected.del(new userImagePkg(s)); continue; } if (a.equals("select-lst")) { for (i = 0; i < selected.size(); i++) { userImagePkg ntry = selected.get(i); if (ntry.done) { continue; } cmd.error("" + ntry); } continue; } if (a.equals("select-clr")) { selected.clear(); forbidden.clear(); discarded.clear(); missing.clear(); continue; } if (a.equals("select-sum")) { cmd.error(""); cmd.error("available:" + dumpList(allPkgs, false, false)); cmd.error(""); cmd.error("forbidden:" + dumpList(forbidden, false, true)); cmd.error(""); cmd.error("discarded:" + dumpList(discarded, false, true)); cmd.error(""); cmd.error("selected:" + dumpList(selected, false, true)); cmd.error(""); cmd.error("already:" + dumpList(selected, true, true)); cmd.error(""); cmd.error("missing:" + dumpList(missing, false, true)); cmd.error(""); continue; } if (a.equals("package-down")) { if (downAllFiles()) { return true; } continue; } if (a.equals("package-inst")) { if (instAllFiles()) { return true; } continue; } if (a.equals("package-xtra")) { if (instXtraFiles()) { return true; } continue; } if (a.equals("del-ifdn")) { if (downMode == 1) { delFiles(s); } continue; } if (a.equals("del-alw")) { delFiles(s); continue; } cmd.error("unknown command: " + a + " " + s); return true; } return false; } /** * do the work * * @param cmd command to do * @return true on error, false on success */ public boolean doer(cmds cmd) { pip = cmd.pipe; return doIncludeAll(cmd); } } class userImageCat implements Comparable { public final String name; public String url; public String arch; public userImageCat(String n) { name = n.trim(); } public int compareTo(userImageCat o) { return name.compareTo(o.name); } public String toString() { return name; } } class userImagePrv implements Comparable { public final String name; public userImagePkg who; public userImagePrv(String n) { name = n.trim(); } public int compareTo(userImagePrv o) { return name.compareTo(o.name); } } class userImagePkg implements Comparable { public final String name; public boolean done; public userImageCat cat; public String added = ""; public String sum = ""; public String file = ""; public String vers = ""; public int size = 0; public List depend = new ArrayList(); public int level; public userImagePkg(String n) { name = n.trim(); } public int compareTo(userImagePkg o) { return name.compareTo(o.name); } public String toString() { String s = name + " " + cat + " " + vers + " " + added + " " + file + " " + size; for (int i = 0; i < depend.size(); i++) { s += " " + depend.get(i); } return s; } public static void listPackages(String s, List res) { s += ","; for (;;) { int i = s.indexOf(","); int o = s.indexOf("|"); if (i < 0) { break; } if ((o >= 0) && (o < i)) { i = o; } String a = s.substring(0, i).trim(); s = s.substring(i + 1, s.length()); i = a.indexOf("("); if (i >= 0) { a = a.substring(0, i); } res.add(a.trim()); } } public void addDepends(String s) { listPackages(s, depend); } }