From 1fd4bc8ba5abd0c330104c4a2831e19fd6f023b8 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sun, 10 Dec 2023 18:07:49 +0100 Subject: [PATCH] Experiment with running FREEd pid1 in a VM --- etc/freed/pid1/config.ini | 2 +- etc/freed/pid1/jvm.args | 1 + sjbin/src/freed-pid1.java | 120 ++++++++++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/etc/freed/pid1/config.ini b/etc/freed/pid1/config.ini index bcdf102..3fd167d 100644 --- a/etc/freed/pid1/config.ini +++ b/etc/freed/pid1/config.ini @@ -19,7 +19,7 @@ org.argeo.cms.lib.jetty,\ org.argeo.cms.jshell,\ argeo.http.port=80 -argeo.sshd.port=22 +#argeo.sshd.port=22 argeo.osgi.sources=\ a2:///?\ diff --git a/etc/freed/pid1/jvm.args b/etc/freed/pid1/jvm.args index 572fe84..708fab1 100644 --- a/etc/freed/pid1/jvm.args +++ b/etc/freed/pid1/jvm.args @@ -2,6 +2,7 @@ #-Xshareclasses:name=pid1 #-XX:+IdleTuningGcOnIdle +-Dargeo.logging.file=/var/log/freed-pid1.log -Dlog.FreedPid1=DEBUG -Dosgi.configuration.cascaded=true diff --git a/sjbin/src/freed-pid1.java b/sjbin/src/freed-pid1.java index 31865bf..446cc0e 100644 --- a/sjbin/src/freed-pid1.java +++ b/sjbin/src/freed-pid1.java @@ -16,7 +16,10 @@ import java.net.SocketException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; +import java.util.List; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; @@ -24,11 +27,14 @@ import org.argeo.init.Service; import sun.misc.Signal; +/** A minimalistic Linux init process. */ class FreedPid1 { final static AtomicInteger runLevel = new AtomicInteger(-1); private final static Logger logger = System.getLogger(FreedPid1.class.getName()); + private final static List initDServices = Collections.synchronizedList(new ArrayList<>()); + public static void main(String... args) { try { final long pid = ProcessHandle.current().pid(); @@ -71,7 +77,7 @@ class FreedPid1 { if (runLevel.get() == 0) {// shutting down the whole system if (!isSystemInit) { logger.log(INFO, "Shutting down system..."); - new ProcessBuilder("/usr/bin/kill", "1").start(); + shutdown(false); System.exit(0); } else { logger.log(ERROR, "Cannot start at run level " + runLevel.get()); @@ -79,12 +85,8 @@ class FreedPid1 { } } else if (runLevel.get() == 6) {// reboot the whole system if (!isSystemInit) { - logger.log(INFO, "Rebooting down system..."); - Path sysrqP = Paths.get("/proc/sys/kernel/sysrq"); - Files.writeString(sysrqP, "1"); - Path sysrqTriggerP = Paths.get("/proc/sysrq-trigger"); - Files.writeString(sysrqTriggerP, "b"); - System.exit(0); + logger.log(INFO, "Rebooting the system..."); + shutdown(true); } else { logger.log(ERROR, "Cannot start at run level " + runLevel.get()); System.exit(1); @@ -93,12 +95,21 @@ class FreedPid1 { logger.log(INFO, "FREEd Init daemon starting with pid " + pid + " after " + ManagementFactory.getRuntimeMXBean().getUptime() + " ms"); + // hostname + String hostname = Files.readString(Paths.get("/etc/hostname")); + new ProcessBuilder("/usr/bin/hostname", hostname).start(); + logger.log(DEBUG, "Set hostname to " + hostname); // networking initSysctl(); startInitDService("networking", true); - if (!waitForNetwork(30 * 1000)) +// Thread.sleep(3000);// leave some time for network to start up + if (!waitForNetwork(10 * 1000)) logger.log(ERROR, "No network available"); + // OpenSSH + // TODO make it coherent with Java sshd + startInitDService("ssh", true); + // NSS services startInitDService("nslcd", false);// Note: nslcd fails to stop @@ -113,6 +124,8 @@ class FreedPid1 { } catch (Throwable e) { logger.log(ERROR, "Unexpected exception in free-pid1 init, shutting down... ", e); System.exit(1); + } finally { + stopInitDServices(); } } @@ -135,16 +148,20 @@ class FreedPid1 { Path serviceInit = Paths.get("/etc/init.d/", serviceName); if (Files.exists(serviceInit)) try { - new ProcessBuilder(serviceInit.toString(), "start").start().waitFor(); - logger.log(DEBUG, "Service " + serviceName + " started"); + int exitCode = new ProcessBuilder(serviceInit.toString(), "start").start().waitFor(); + if (exitCode != 0) + logger.log(ERROR, "Service " + serviceName + " dit not stop properly"); + else + logger.log(DEBUG, "Service " + serviceName + " started"); if (stopOnShutdown) - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - try { - new ProcessBuilder(serviceInit.toString(), "stop").start().waitFor(); - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - }, "FREEd stop service " + serviceName)); + initDServices.add(serviceName); +// Runtime.getRuntime().addShutdownHook(new Thread(() -> { +// try { +// new ProcessBuilder(serviceInit.toString(), "stop").start().waitFor(); +// } catch (IOException | InterruptedException e) { +// e.printStackTrace(); +// } +// }, "FREEd stop service " + serviceName)); } catch (IOException | InterruptedException e) { e.printStackTrace(); } @@ -170,8 +187,10 @@ class FreedPid1 { if (netInterfaces != null) { while (netInterfaces.hasMoreElements()) { NetworkInterface netInterface = netInterfaces.nextElement(); + logger.log(DEBUG, "Interface:" + netInterface); for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) { InetAddress inetAddr = addr.getAddress(); + logger.log(DEBUG, " addr: " + inetAddr); if (!inetAddr.isLoopbackAddress() && !inetAddr.isLinkLocalAddress()) { try { if (inetAddr.isReachable((int) timeout)) { @@ -191,17 +210,50 @@ class FreedPid1 { throw new IllegalStateException("No network interface has been found"); } try { - Thread.sleep(100); + Thread.sleep(1000); } catch (InterruptedException e) { // silent } } } catch (Exception e) { - logger.log(ERROR, "Cannot check whether network is avialable", e); + logger.log(ERROR, "Cannot check whether network is available", e); } return networkAvailable; } + static void shutdown(boolean reboot) { + try { + stopInitDServices(); + Path sysrqP = Paths.get("/proc/sys/kernel/sysrq"); + Files.writeString(sysrqP, "1"); + Path sysrqTriggerP = Paths.get("/proc/sysrq-trigger"); + Files.writeString(sysrqTriggerP, "e");// send SIGTERM to all processes + // Files.writeString(sysrqTriggerP, "i");// send SIGKILL to all processes + Files.writeString(sysrqTriggerP, "e");// flush data to disk + Files.writeString(sysrqTriggerP, "u");// unmount + if (reboot) + Files.writeString(sysrqTriggerP, "b"); + else + Files.writeString(sysrqTriggerP, "o"); + } catch (IOException e) { + logger.log(ERROR, "Cannot shut down system", e); + } + } + + static void stopInitDServices() { + for (int i = initDServices.size() - 1; i >= 0; i--) { + String serviceName = initDServices.get(i); + Path serviceInit = Paths.get("/etc/init.d/", serviceName); + try { + int exitCode = new ProcessBuilder(serviceInit.toString(), "stop").start().waitFor(); + if (exitCode != 0) + logger.log(ERROR, "Service " + serviceName + " dit not stop properly"); + } catch (InterruptedException | IOException e) { + logger.log(ERROR, "Cannot stop service " + serviceName, e); + } + } + } + /** A thread watching the login prompt. */ static class LoginThread extends Thread { private boolean systemShuttingDown = false; @@ -219,20 +271,26 @@ class FreedPid1 { @Override public void run() { - Console console = System.console(); - console.readLine(); // type return once to activate login prompt + boolean getty = true; prompt: while (!systemShuttingDown) { try { - console.printf("login: "); - String username = console.readLine(); - username = username.trim(); - if ("".equals(username)) - continue prompt; - ProcessBuilder pb = new ProcessBuilder("su", "--login", username); - pb.redirectError(ProcessBuilder.Redirect.INHERIT); - pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); - pb.redirectInput(ProcessBuilder.Redirect.INHERIT); - process = pb.start(); + if (getty) { + ProcessBuilder pb = new ProcessBuilder("/usr/sbin/getty", "38400", "tty2"); + process = pb.start(); + } else { + Console console = System.console(); + console.readLine(); // type return once to activate login prompt + console.printf("login: "); + String username = console.readLine(); + username = username.trim(); + if ("".equals(username)) + continue prompt; + ProcessBuilder pb = new ProcessBuilder("su", "--login", username); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); + pb.redirectInput(ProcessBuilder.Redirect.INHERIT); + process = pb.start(); + } Runtime.getRuntime().addShutdownHook(new Thread(() -> process.destroy())); try { process.waitFor(); -- 2.30.2