Experiment with running FREEd pid1 in a VM
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 10 Dec 2023 17:07:49 +0000 (18:07 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 10 Dec 2023 17:07:49 +0000 (18:07 +0100)
etc/freed/pid1/config.ini
etc/freed/pid1/jvm.args
sjbin/src/freed-pid1.java

index bcdf102d4995393004770e77aa907daa4568869d..3fd167d67f8d7d899b1344ab1e8a431112a6443e 100644 (file)
@@ -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:///?\
index 572fe84c70162e31591225ca1da838f5f5f3060b..708fab1079c9fa713419990c81a7c28e96d38dd1 100644 (file)
@@ -2,6 +2,7 @@
 #-Xshareclasses:name=pid1
 #-XX:+IdleTuningGcOnIdle
 
+-Dargeo.logging.file=/var/log/freed-pid1.log
 -Dlog.FreedPid1=DEBUG
 
 -Dosgi.configuration.cascaded=true
index 31865bfa03596aac108781d94b378d86f6469001..446cc0edc33a865c49a1da01c83268178d83f574 100644 (file)
@@ -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<String> 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();