diff options
author | Leah Neukirchen <leah@vuxu.org> | 2024-01-06 22:36:15 +0100 |
---|---|---|
committer | Leah Neukirchen <leah@vuxu.org> | 2024-01-06 22:36:15 +0100 |
commit | 0d9adeb9e70a0af0e4570d0a384a42b0256cffc5 (patch) | |
tree | cc0fe6eab30b1dfcb966ef04938b2aa8b6a9fa0f | |
parent | 59ff3a7c520c14e329d6acabeabf093174065145 (diff) | |
download | nitro-0d9adeb9e70a0af0e4570d0a384a42b0256cffc5.tar.gz nitro-0d9adeb9e70a0af0e4570d0a384a42b0256cffc5.tar.xz nitro-0d9adeb9e70a0af0e4570d0a384a42b0256cffc5.zip |
nitroctl: can be used as drop-in for init, halt, reboot, poweroff.
-rw-r--r-- | nitroctl.c | 139 |
1 files changed, 130 insertions, 9 deletions
diff --git a/nitroctl.c b/nitroctl.c index 09497c7..485a2d6 100644 --- a/nitroctl.c +++ b/nitroctl.c @@ -1,8 +1,17 @@ +#ifdef __linux__ +#define INIT_SYSTEM +#endif + #include <sys/socket.h> #include <sys/un.h> +#include <sys/utsname.h> +#ifdef INIT_SYSTEM +#include <sys/reboot.h> +#endif #include <ctype.h> #include <errno.h> +#include <fcntl.h> #include <libgen.h> #include <limits.h> #include <signal.h> @@ -11,6 +20,7 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <utmp.h> int connfd; const char *sockpath; @@ -155,10 +165,91 @@ normalize(char *service) return end + 1; } +#ifdef INIT_SYSTEM + +#ifndef OUR_WTMP +#define OUR_WTMP "/var/log/wtmp" +#endif + +#ifndef OUR_UTMP +#define OUR_UTMP "/run/utmp" +#endif + +void write_wtmp(int boot) { + int fd; + + if ((fd = open(OUR_WTMP, O_WRONLY|O_APPEND)) < 0) + return; + + struct utmp utmp = {0}; + struct utsname uname_buf; + struct timeval tv; + + gettimeofday(&tv, 0); + utmp.ut_tv.tv_sec = tv.tv_sec; + utmp.ut_tv.tv_usec = tv.tv_usec; + + utmp.ut_type = boot ? BOOT_TIME : RUN_LVL; + + strncpy(utmp.ut_name, boot ? "reboot" : "shutdown", sizeof utmp.ut_name); + strncpy(utmp.ut_id , "~~", sizeof utmp.ut_id); + strncpy(utmp.ut_line, boot ? "~" : "~~", sizeof utmp.ut_line); + if (uname(&uname_buf) == 0) + strncpy(utmp.ut_host, uname_buf.release, sizeof utmp.ut_host); + + write(fd, (char *)&utmp, sizeof utmp); + close(fd); + + if (boot) { + if ((fd = open(OUR_UTMP, O_WRONLY|O_APPEND)) < 0) + return; + write(fd, (char *)&utmp, sizeof utmp); + close(fd); + } +} + +#endif + +int +suffix(const char *str, const char *suff) +{ + size_t a = strlen(str); + size_t b = strlen(suff); + return b <= a && strcmp(str + a - b, suff) == 0; +} int main(int argc, char *argv[]) { +#ifdef INIT_SYSTEM + if (getpid() == 1) { + execvp("nitro", argv); + dprintf(2, "nitroctl: exec init failed: %s\n", strerror(errno)); + exit(111); + } +#endif + char cmd; + +#ifdef INIT_SYSTEM + if (suffix(argv[0], "init")) { + if (argv[1] && strcmp(argv[1], "0") == 0) { + cmd = 'S'; + } else if (argv[1] && strcmp(argv[1], "6") == 0) { + cmd = 'R'; + } else if (argv[1] && strcmp(argv[1], "q") == 0) { + cmd = 's'; + } else { + dprintf(2, "usage: init [0|6|q]\n"); + exit(2); + } + } else if (suffix(argv[0], "halt")) { + cmd = 'S'; + } else if (suffix(argv[0], "poweroff")) { + cmd = 'S'; + } else if (suffix(argv[0], "reboot")) { + cmd = 'R'; + } else +#endif if (argc < 2 || ( strcmp(argv[1], "l") != 0 && strcmp(argv[1], "list") != 0 && strcmp(argv[1], "d") != 0 && strcmp(argv[1], "down") != 0 && @@ -176,13 +267,42 @@ main(int argc, char *argv[]) strcmp(argv[1], "check") != 0 && strcmp(argv[1], "start") != 0 && strcmp(argv[1], "r") != 0 && strcmp(argv[1], "restart") != 0 && + strcmp(argv[1], "s") != 0 && strcmp(argv[1], "scan") != 0 && strcmp(argv[1], "stop") != 0 && strcmp(argv[1], "Reboot") != 0 && strcmp(argv[1], "Shutdown") != 0)) { dprintf(2, "usage: nitroctl COMMAND [SERVICE]\n"); exit(2); + } else { + cmd = argv[1][0]; } +#ifdef INIT_SYSTEM + if ((cmd == 'R' || cmd == 'S') && argv[1]) { + if (strcmp(argv[1], "-f") == 0) { + if (cmd == 'R') { + reboot(RB_AUTOBOOT); + dprintf(2, "nitroctl: force reboot failed: %s\n", strerror(errno)); + exit(111); + } else if (cmd == 'S') { + reboot(RB_POWER_OFF); + dprintf(2, "nitroctl: force shutdown failed: %s\n", strerror(errno)); + exit(111); + } + } + + if (strcmp(argv[1], "-B") == 0) { + write_wtmp(1); + return 0; + } + + if (strcmp(argv[1], "-w") == 0) { + write_wtmp(0); + return 0; + } + } +#endif + static const char default_sock[] = "/run/nitro/nitro.sock"; sockpath = getenv("NITRO_SOCK"); if (!sockpath || !*sockpath) @@ -194,17 +314,18 @@ main(int argc, char *argv[]) exit(111); } - char cmd = argv[1][0]; char *service = normalize(argv[2]); - if (strcmp(argv[1], "start") == 0 && service) - return send_and_wait('u', service); - else if (strcmp(argv[1], "stop") == 0 && service) - return send_and_wait('d', service); - else if (strcmp(argv[1], "restart") == 0 && service) - return send_and_wait('r', service); - else if (strcmp(argv[1], "check") == 0 && service) - cmd = '?'; + if (argv[1]) { + if (strcmp(argv[1], "start") == 0 && service) + return send_and_wait('u', service); + else if (strcmp(argv[1], "stop") == 0 && service) + return send_and_wait('d', service); + else if (strcmp(argv[1], "restart") == 0 && service) + return send_and_wait('r', service); + else if (strcmp(argv[1], "check") == 0 && service) + cmd = '?'; + } notifysock(""); |