From: Shamus Hammons Date: Mon, 3 Apr 2017 14:05:29 +0000 (-0500) Subject: Rewrite of Ruby script into C. To my eye, it's much cleaner. :-) X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=init-ng;a=commitdiff_plain;h=9f23f04c3792ce4c64fec9f1b8116e0586f50ce0 Rewrite of Ruby script into C. To my eye, it's much cleaner. :-) There are still a few things that need to be added, like status of monitored processes, and reading/parsing of inittab to make it a true drop in replacement for SysV init, but this is pretty close as it is. --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..561f3c3 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +# Doesn't need to be more complex than this + +init-ng: init-ng.c + gcc -std=c99 -g init-ng.c -o init-ng + diff --git a/README b/README index be745eb..7f5e224 100644 --- a/README +++ b/README @@ -32,6 +32,11 @@ HOW TO INSTALL/USE IT Once you have rebooted successfully and logged in as root, typing 'init' on the command line will display the commands that init-ng understands. +It is also possible to leave the existing init in place without renaming it; in +this case you would rename the new init to something else, such as init-ng. +Then, on your kernel boot command line, you would add "init=/sbin/init-ng" +(without the quotes) to have the kernel use it instead of your current init. + CREDITS ------- diff --git a/init-ng b/init-ng new file mode 100755 index 0000000..dcd7ff3 Binary files /dev/null and b/init-ng differ diff --git a/init-ng.c b/init-ng.c new file mode 100644 index 0000000..3b969be --- /dev/null +++ b/init-ng.c @@ -0,0 +1,387 @@ +// +// Init-NG +// +// A minimal, drop-in replacement for SysV init. +// This leverages OpenRC to do most of the heavy lifting, and does the minimum +// amount that it should--unlike other so-called inits, that have world + +// kitchen sink thrown in, seemingly to enlarge the attack surface. ;-) +// +// by James Hammons +// (C) 2017 Underground Software +// + +#define _GNU_SOURCE // Without this, functions in unistd.h go missing +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char socketPath[] = "/run/initctl"; +static int shuttingDown = 0; +static int verbose = 0; // N.B.: There is no mechanism to set this ATM +static struct sigaction action; +static int freeProcessSlot = 0; +static pid_t processPID[1024]; +static char * processCmd[1024]; +static char * processName[1024]; +static char * args[256]; // 256 arguments ought to be enough for anybody ;-) + + +// +// Find a process in the monitored process list (MPL) by PID. Returns the index +// of the entry in the MPL. +// +int FindMonitoredPID(pid_t pid) +{ + for(int i=0; i 1) + { + if ((strcmp(argv[1], "poweroff") == 0) + || (strcmp(argv[1], "restart") == 0) + || (strcmp(argv[1], "halt") == 0) + || (strcmp(argv[1], "status") == 0)) + { + DoCmd(argv[1]); + } + else if (strcmp(argv[1], "test") == 0) + { + ShutDown(LINUX_REBOOT_CMD_POWER_OFF); + } + else + printf("Invalid command\n"); + } + else + printf("Usage: poweroff, restart, halt, status, test\n"); + + return 1; + } + + // We are PID EINS, so start the system using OpenRC... + Init(); + + // Launch TTYs... + // N.B.: To be a drop in replacement for SysV init, we really should read + // and parse the entries in /etc/inittab; at least the c entries... + for(int i=1; i<=6; i++) + { + sprintf(buf, "agetty%i", i); + sprintf(buf2, "/sbin/agetty tty%i --noclear", i); + Launch(buf, buf2, 1); + } + + // Install SIGCHLD signal handler to do process monitoring + memset(&action, 0, sizeof(action)); + action.sa_sigaction = HandleSIGCHLD; + action.sa_flags = SA_SIGINFO; + sigaction(SIGCHLD, &action, NULL); + + // Create socket to listen on for commands... + struct sockaddr_un local, remote; + unsigned int s = socket(AF_UNIX, SOCK_STREAM, 0); + + if (s == -1) + { + perror("socket"); + printf("init-ng: socket() failed!\n"); + } + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, socketPath); + unlink(local.sun_path); + int len = strlen(local.sun_path) + sizeof(local.sun_family); + + if (bind(s, (struct sockaddr *)&local, len) == -1) + { + perror("bind"); + printf("init-ng: bind() failed!\n"); + } + + // Queue size of 20 ought to be enough for anybody ;-) + if (listen(s, 20) == -1) + { + perror("listen"); + printf("init-ng: listen() failed!\n"); + } + + // Main loop for PID 1. All commands are received and acted upon from here. + while (1) + { + int t = sizeof(remote); + unsigned int s2 = accept(s, (struct sockaddr *)&remote, &t); + + if (s2 == -1) + { + // Check to see if the signal handler blew things up on us + if (errno == EINTR) + continue; + + // An unanticipated error occurred, handle it + perror("accept"); + printf("init-ng: accept() failed!\n"); + } + + // Get the message from the socket + int n = recv(s2, buf, 2048, 0); + buf[n] = 0; + + if (verbose) + printf("PID1: Received \"%s\" from socket...\n", buf); + + // Now do something with it... + if (strcmp(buf, "poweroff") == 0) + { + ShutDown(LINUX_REBOOT_CMD_POWER_OFF); + } + else if (strcmp(buf, "restart") == 0) + { + ShutDown(LINUX_REBOOT_CMD_RESTART); + } + else if (strcmp(buf, "halt") == 0) + { + ShutDown(LINUX_REBOOT_CMD_HALT); + } + else if (strcmp(buf, "status") == 0) + { + printf("[Status placeholder]\n"); + } + + close(s2); + } + + // We should never get here... + return 0; +} + diff --git a/init b/init-ng.rb similarity index 100% rename from init rename to init-ng.rb