/** * * Created : Feb 19, 2012 * * @author pquiring */ import java.util.*; import java.io.*; import jfparted.*; import javaforce.*; import javaforce.linux.*; public class Install extends IPanel implements ShellProcessListener { /** * Creates new form Install */ public Install() { initComponents(); Data.getDevices(); Data.getPartitions(); Installer.disableButtons(); //create a Thread Worker worker = new Worker(); worker.start(); } private class Optional extends Exception { public Optional(String msg) { super(msg); } }; /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); log = new javax.swing.JTextArea(); progress = new javax.swing.JProgressBar(); log.setColumns(20); log.setEditable(false); log.setRows(5); jScrollPane1.setViewportView(log); progress.setToolTipText(""); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) .addComponent(progress, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) ); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextArea log; private javax.swing.JProgressBar progress; // End of variables declaration//GEN-END:variables private int totalFilesCopied = 0, filesToCopy = 0; private boolean calcFilesToCopy = false; private boolean fedoraMount = false; public class Worker extends Thread { public void run() { ShellProcess sp; ArrayList<String> cmd; String output; //disable all swaps (can prevent deleting old parts) sp = new ShellProcess(); cmd = new ArrayList<String>(); cmd.add("sudo"); cmd.add("swapoff"); cmd.add("-a"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to exec swapoff"); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } //umount any parts that startsWith(Data.root.device.dev) sp = new ShellProcess(); cmd = new ArrayList<String>(); cmd.add("mount"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to exec mount"); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } String lns[] = output.split("\n"); for(int a=0;a<lns.length;a++) { if (lns[a].startsWith(Data.root.device.dev)) { int idx = lns[a].indexOf(" "); if (!Data.umount(lns[a].substring(0, idx))) { addLog("Error:Failed to exec umount"); abort(); return; } } } if (Linux.distro == Linux.DistroTypes.Fedora) { //need to mount CD under /mnt/src Data.mount("/dev/mapper/live-osimg-min", "/mnt/src"); fedoraMount = true; } //do guided part stuff if (Data.guidedTarget != null) { //perform ops1 (removes) addLog("Partitioning device..."); sp = new ShellProcess(); cmd = new ArrayList<String>(); cmd.add("sudo"); cmd.add("parted"); for(int a=0;a<Data.ops1.size();a++) sp.addResponse("(parted) ", Data.ops1.get(a), false); output = sp.run(cmd, false); if ((output == null) || (output.indexOf("Error:") != -1) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to remove old partitions.\nAre they mounted?"); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } //perform ops2 (mkpart's) sp = new ShellProcess(); cmd = new ArrayList<String>(); cmd.add("sudo"); cmd.add("parted"); for(int a=0;a<Data.ops2.size();a++) sp.addResponse("(parted) ", Data.ops2.get(a), false); output = sp.run(cmd, false); if ((output == null) || (output.indexOf("Error:") != -1) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to create new partitions."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } //format / and swap addLog("Formatting new partitions..."); Data.root.label = "OS"; if (!Data.format(Data.root)) { addLog("Error:Failed to format root partition"); abort(); return; } addLog("...swap..."); Data.swap.label = "SWAP"; if (!Data.format(Data.swap)) { addLog("Error:Failed to format swap partition"); abort(); return; } } //refresh partition lists Data.getDevices(); Data.getPartitions(); // confirm Data.root == ext4 & Data.swap == swap String rootdev = Data.root.device.dev + Data.root.number; String swapdev = ""; if (Data.swap != null) swapdev = Data.swap.device.dev + Data.swap.number; boolean rootOk = false; boolean swapOk = false; if (Data.swap == null) swapOk = true; for(int d=0;d<Data.devices.size();d++) { Data.Device device = Data.devices.get(d); for (int p=0;p<device.parts.size();p++) { Data.Partition part = device.parts.get(p); if (part.number == -1) continue; String partdev = part.device.dev + part.number; if (partdev.equals(rootdev)) { if (part.filesys.startsWith("ext")) { rootOk = true; } } if ((Data.swap != null) && (partdev.equals(swapdev))) { if (part.filesys.equals("swap")) { swapOk = true; } } } } if (!rootOk) { addLog("Error:Unable to find root partition."); abort(); return; } if (!swapOk) { addLog("Error:Unable to find swap partition."); abort(); return; } // mount Data.root if (!Data.mount(Data.root, "/mnt/install")) { addLog("Error:Failed to mount root partition."); abort(); return; } //load filesToCopy from /etc/.live try { Properties props = new Properties(); FileInputStream etclive = new FileInputStream("/etc/.live"); props.load(etclive); etclive.close(); filesToCopy = JF.atoi(props.getProperty("filesToCopy")); } catch (Exception e) { JFLog.log(e); } if (filesToCopy <= 0) { addLog("Calculating files to copy..."); sp = new ShellProcess(); cmd = new ArrayList<String>(); cmd.add("sudo"); cmd.add("rsync"); cmd.add("-aHAXvn"); //archive + H A X + verbose + dry run if (Linux.distro == Linux.DistroTypes.Ubuntu) cmd.add("/rofs/."); else cmd.add("/mnt/src/."); cmd.add("/mnt/install"); sp.addListener(Install.this); sp.log = false; //too much sp.keepOutput(false); calcFilesToCopy = true; output = sp.run(cmd, false); calcFilesToCopy = false; sp.log = true; if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to calculate files to copy."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } // addLog("filesToCopy=" + filesToCopy); System.out.println("filesToCopy=" + filesToCopy); } sp = new ShellProcess(); cmd = new ArrayList<String>(); addLog("Copying files..."); cmd.add("sudo"); cmd.add("rsync"); cmd.add("-aHAXv"); //archive + H A X + verbose if (Linux.distro == Linux.DistroTypes.Ubuntu) cmd.add("/rofs/."); else cmd.add("/mnt/src/."); cmd.add("/mnt/install"); sp.addListener(Install.this); sp.log = false; //too much sp.keepOutput(false); output = sp.run(cmd, false); sp.log = true; sp.addListener(null); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to copy files."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } ShellProcess.log = true; //modify new installation // : create skipped folders /* Data.mkdir("/mnt/install/dev"); Data.mkdir("/mnt/install/proc"); Data.mkdir("/mnt/install/tmp"); Data.chmod("/mnt/install/tmp", "1777"); Data.mkdir("/mnt/install/sys"); Data.mkdir("/mnt/install/run"); Data.mkdir("/mnt/install/run/lock"); Data.chmod("/mnt/install/run/lock", "1777");*/ // : fstab addLog("Generating fstab..."); try { FileOutputStream fos = new FileOutputStream("/tmp/fstab"); fos.write("#fstab generated by jfinstall\n".getBytes()); for(int a=0;a<Data.fstab.size();a++) { fos.write((Data.fstab.get(a) + "\n").getBytes()); } fos.close(); sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("cp"); cmd.add("/tmp/fstab"); cmd.add("/mnt/install/etc/fstab"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to setup fstab."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("fstab creation failed"); abort(); return; } addLog("Creating new user..."); // : add new user try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("chroot"); cmd.add("/mnt/install"); cmd.add("useradd"); cmd.add("-s"); cmd.add("/bin/bash"); cmd.add("-m"); cmd.add("-G"); switch (Linux.distro) { case Ubuntu: cmd.add("sudo"); break; //allows sudo (Ubuntu 12.04) // cmd.add("admin"); //allows sudo (Ubuntu 11.10) case Fedora: cmd.add("wheel"); break; //allows sudo (Fedora) } cmd.add("-c"); cmd.add("\"" + Data.fullName + "\""); cmd.add(Data.loginName); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to create new user."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to create new user."); abort(); return; } // : set new user passwd try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("chroot"); cmd.add("/mnt/install"); cmd.add("passwd"); cmd.add(Data.loginName); //ubuntu??? sp.addResponse("Enter new UNIX password:", Data.passwd + "\n", true); sp.addResponse("Retype new UNIX password:", Data.passwd + "\n", true); //fedora (f19) sp.addResponse("New password:", Data.passwd + "\n", true); sp.addResponse("Retype new password:", Data.passwd + "\n", true); output = sp.run(cmd, true); //NOTE : prompts are sent to stderr if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to create new user passwd."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to create new user passwd."); abort(); return; } // : delete /etc/.live try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("rm"); cmd.add("/mnt/install/etc/.live"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to delete /etc/.live"); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to delete /etc/.live"); abort(); return; } // : assign hostname & domain addLog("Assign computer name & domain..."); try { File tmpFile1 = File.createTempFile("hostname", ".tmp"); FileOutputStream fos1 = new FileOutputStream(tmpFile1); fos1.write(Data.localhost.getBytes()); fos1.close(); File tmpFile2 = File.createTempFile("hosts", ".tmp"); FileOutputStream fos2 = new FileOutputStream(tmpFile2); FileInputStream fis2 = new FileInputStream("/mnt/install/etc/hosts"); BufferedReader br = new BufferedReader(new InputStreamReader(fis2)); String ln; while ((ln = br.readLine()) != null) { if (ln.startsWith("127.0.0.1")) { ln = "127.0.0.1\tlocalhost " + Data.localhost; } fos2.write((ln + "\n").getBytes()); } fos2.close(); fis2.close(); if (!Linux.runScript(new String[] { "cp " + tmpFile1.getAbsolutePath() + " /mnt/install/etc/hostname", "cp " + tmpFile2.getAbsolutePath() + " /mnt/install/etc/hosts", })) { tmpFile1.delete(); throw new Exception("file io error"); } tmpFile1.delete(); } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to set hostname."); abort(); return; } try { File tmpFile = File.createTempFile("network", ".xml"); FileOutputStream fos = new FileOutputStream(tmpFile); fos.write(("<network>\n <hostname>" + Data.localhost + "</hostname>\n <domain>" + Data.localdomain + "</domain>\n</network>\n").getBytes()); fos.close(); if (!Linux.copyFile(tmpFile.getAbsolutePath(), "/mnt/install/etc/jconfig.d/network.xml")) { throw new Exception("file io error"); } tmpFile.delete(); } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to save network config."); abort(); return; } //set timezone try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("chroot"); cmd.add("/mnt/install"); cmd.add("rm"); cmd.add("/etc/localtime"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to delete current timezone."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to delete current timezone."); abort(); return; } try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("chroot"); cmd.add("/mnt/install"); cmd.add("ln"); cmd.add("-s"); cmd.add("/usr/share/zoneinfo/" + Data.timezone); cmd.add("/etc/localtime"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to assign timezone."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to assign timezone."); abort(); return; } try { File file = new File("/tmp/timezone"); FileOutputStream fos = new FileOutputStream(file); fos.write(Data.timezone.getBytes()); fos.close(); sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("cp"); cmd.add("/tmp/timezone"); cmd.add("/mnt/install/etc/timezone"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to assign timezone."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } file.delete(); } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to assign timezone."); abort(); return; } // : set root part bootable (parted : set $Data.root.number boot on) addLog("Setting boot partition..."); try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("parted"); sp.addResponse("(parted) ", "select " + Data.root.device.dev + "\n", false); sp.addResponse("(parted) ", "set " + Data.root.number + " boot on\n", false); sp.addResponse("(parted) ", "quit\n", false); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to set bootable partition."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to set bootable partition."); abort(); return; } // : install grub addLog("Installing boot loader..."); try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); if (new File("/usr/sbin/grub2-install").exists()) cmd.add("grub2-install"); else if (new File("/usr/sbin/grub-install").exists()) cmd.add("grub-install"); else throw new Exception("grub tools not found"); cmd.add(Data.root.device.dev); cmd.add("--boot-directory=/mnt/install/boot"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to exec " + cmd.get(1)); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("grub install failed"); abort(); return; } //get `uname -r` sp = new ShellProcess(); //create initramfs try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("jfinstall-chroot.sh"); cmd.add("/mnt/install"); if (Linux.distro == Linux.DistroTypes.Fedora) { //fedora way cmd.add("dracut"); } else { //ubuntu way String uname = sp.run(new String[] {"uname", "-r"}, false).replaceAll("\n", ""); cmd.add("mkinitramfs"); cmd.add("-o"); cmd.add("/boot/initrd.img-" + uname); } output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to exec " + cmd.get(3)); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("create initramfs failed"); abort(); return; } //grub mkconfig try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("jfinstall-chroot.sh"); cmd.add("/mnt/install"); if (new File("/usr/sbin/grub2-mkconfig").exists()) { cmd.add("grub2-mkconfig"); cmd.add("--output=/boot/grub2/grub.cfg"); } else if (new File("/usr/sbin/grub-mkconfig").exists()) { cmd.add("grub-mkconfig"); cmd.add("--output=/boot/grub/grub.cfg"); } else { throw new Exception("grub tools not found"); } output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to exec " + cmd.get(3) ); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("grub mkconfig failed"); abort(); return; } //grub mkdevicemap (optional) try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("jfinstall-chroot.sh"); cmd.add("/mnt/install"); if (new File("/usr/sbin/grub2-mkdevicemap").exists()) cmd.add("grub2-mkdevicemap"); else if (new File("/usr/sbin/grub-mkdevicemap").exists()) cmd.add("grub-mkdevicemap"); else throw new Optional("device.map will not be created"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to exec " + cmd.get(3)); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Optional e) { JFLog.log(e.toString()); } catch (Exception e) { JFLog.log(e); addLog("grub mkdevicemap failed"); abort(); return; } addLog("Removing unneeded packages..."); // : remove unneeded packages try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("chroot"); cmd.add("/mnt/install"); switch (Linux.distro) { case Ubuntu: cmd.add("apt-get"); cmd.add("--yes"); break; case Fedora: cmd.add("yum"); cmd.add("-y"); break; } cmd.add("remove"); switch (Linux.distro) { case Ubuntu: cmd.add("casper"); cmd.add("lupin-casper"); break; } cmd.add("jfinstall"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Error:Failed to remove unneeded packages."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); abort(); return; } } catch (Exception e) { JFLog.log(e); addLog("Error:Failed to remove unneeded packages."); abort(); return; } /* addLog("Installing 'extra' packages..."); //install restricted packages (ffmpeg, chrome) try { sp = new ShellProcess(); cmd.clear(); cmd.add("sudo"); cmd.add("chroot"); cmd.add("/mnt/install"); switch (Linux.distro) { case Ubuntu: cmd.add("apt-get"); cmd.add("--yes"); break; case Fedora: cmd.add("yum"); cmd.add("-y"); break; } cmd.add("install"); switch (Linux.distro) { case Ubuntu: cmd.add("libav-tools"); break; case Fedora: cmd.add("ffmpeg"); break; } cmd.add("google-chrome-stable"); output = sp.run(cmd, false); if ((output == null) || (sp.getErrorLevel() != 0)) { addLog("Warning:Failed to install extra packages."); JFLog.log("ErrorLevel=" + sp.getErrorLevel()); } } catch (Exception e) { JFLog.log(e); addLog("Warning:Failed to install extra packages."); } */ //delete some fedora live files /* //even Fedora installers don't touch this stuff if (Linux.distro == Linux.DistroTypes.Fedora) { try { new File("/etc/rc.d/init.d/livesys").delete(); new File("/etc/rc.d/init.d/livesys-late").delete(); new File("/sbin/halt.local").delete(); } catch (Exception e) { JFLog.log(e); } } */ //unmount root part Data.umount(Data.root.device.dev + Data.root.number); if (Linux.distro == Linux.DistroTypes.Fedora) { if (fedoraMount) { Data.umount("/mnt/src"); fedoraMount = false; } } //done! addLog("Installation complete"); progress.setValue(100); Installer.enableFinish(); } } private void addLog(String msg) { log.setText(log.getText() + msg + "\n"); JFLog.log(msg); } private void abort() { addLog("Installation aborted"); addLog("Please view /tmp/install.log for details"); if (Data.root != null) Data.umount(Data.root.device.dev + Data.root.number); if (Linux.distro == Linux.DistroTypes.Fedora) { if (fedoraMount) { Data.umount("/mnt/src"); fedoraMount = false; } } Installer.enableFinish(); } public void shellProcessOutput(String str) { int newFilesCopied = str.split("\n").length - 1; if (calcFilesToCopy) { filesToCopy += newFilesCopied; } else { totalFilesCopied += newFilesCopied; progress.setValue(totalFilesCopied * 100 / filesToCopy); } } public IPanel next() {return null;} public IPanel prev() {return null;} public IPanel getThis() {return this;} }