diff --git a/.gitignore b/.gitignore index 16205253..9bba5a87 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,9 @@ tools/mount/mount tools/mount/main.o tools/netd/main.o tools/netd/netd +tools/init/poweroff +tools/init/poweroff.o +tools/init/reboot +tools/init/reboot.o +tools/init/acpid +tools/init/acpid.o diff --git a/tools/init/Makefile b/tools/init/Makefile index 22b5aa2f..3884c4bc 100644 --- a/tools/init/Makefile +++ b/tools/init/Makefile @@ -1,13 +1,22 @@ .phony: all install CC=x86_64-astral-gcc LD=x86_64-astral-gcc -all: init + +all: init poweroff install: - cp init "$(DESTDIR)/init" + mkdir -pv "$(DESTDIR)/usr/sbin" + cp -v init "$(DESTDIR)/init" + cp -v poweroff "$(DESTDIR)/usr/sbin/poweroff" init: main.o $(LD) $(LDFLAGS) -o $@ $^ +poweroff: poweroff.o + $(LD) $(LDFLAGS) -o $@ $^ + main.o: main.c - $(CC) -c $(CFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) -o $@ $< + +poweroff.o: poweroff.c + $(CC) -c $(CFLAGS) -o $@ $< diff --git a/tools/init/common.h b/tools/init/common.h new file mode 100644 index 00000000..4897a0b3 --- /dev/null +++ b/tools/init/common.h @@ -0,0 +1,7 @@ +#ifndef _COMMON_H +#define _COMMON_H + +#define COMMAND_POWEROFF 'c' +#define COMMAND_FIFO "/tmp/.initcmd" + +#endif diff --git a/tools/init/main.c b/tools/init/main.c index 921c6121..4a1f7c63 100644 --- a/tools/init/main.c +++ b/tools/init/main.c @@ -6,6 +6,93 @@ #include #include #include +#include +#include +#include + +#include "common.h" + +static void dopoweroff(void) { + printf("init: shutting down system\n"); + //printf("init: sending SIGTERM to all processes\n"); + // TODO kill(-1, SIGTERM); + // TODO wait 5 seconds or until all children have died + //printf("init: sending SIGKILL to all processes\n"); + // TODO kill(-1, SIGKILL); + // TODO wait until all children have died + + printf("init: syncing disks\n"); + sync(); + printf("init: powering off\n"); + int acpifd = open("/dev/acpi", O_WRONLY); + if (acpifd == -1) { + perror("init: open /dev/acpi"); + goto oops; + } + + write(acpifd, "p", 1); + perror("init: write /dev/acpi"); + + oops: + printf("init: failed to send acpi power off. please manually turn the computer off.\n"); + for (;;) + sleep(1); +} + +static void handlecommands(void) { + for (;;) { + int fd = open(COMMAND_FIFO, O_RDONLY); + if (fd == -1) { + perror("init: open command fifo"); + return; + } + + char c; + int num; + for (;;) { + num = read(fd, &c, 1); + if (num == 0) + break; + + if (num == -1) { + if (errno == EINTR) + continue; + + perror("init: read"); + close(fd); + continue; + } + + switch (c) { + case COMMAND_POWEROFF: + dopoweroff(); + break; + default: + printf("init: unknown command %c\n", c); + } + } + + + close(fd); + } +} + +static void reap(int signum) { + pid_t pid; + + for (;;) { + pid = waitpid(-1, NULL, WNOHANG); + if (pid == 0) + break; + + if (pid == -1) { + if (errno == ECHILD) + break; + + perror("init: waitpid"); + } + } +} static void snatchconsole(void) { int rfd = open("/dev/console", O_RDONLY); @@ -38,55 +125,50 @@ static void dowaitpid(pid_t pid) { } static void dorootshell(void) { - // loop starting a root shell every time it exits - for (;;) { - printf("init: starting root shell\n"); + printf("init: starting root shell\n"); - pid_t pid = fork(); - if (pid == -1) { - perror("init: fork failed"); + pid_t pid = fork(); + if (pid == -1) { + perror("init: fork failed"); + exit(EXIT_FAILURE); + } + + if (pid == 0) { + // create its own process group and set is as the foreground group + if (setpgid(0, 0) == -1) { + perror("init: setpgrp failed"); exit(EXIT_FAILURE); } - if (pid == 0) { - // create its own process group and set is as the foreground group - if (setpgid(0, 0) == -1) { - perror("init: setpgrp failed"); - exit(EXIT_FAILURE); - } - - if (tcsetpgrp(0, getpid()) == -1) { - perror("init: tcsetpgrp failed"); - exit(EXIT_FAILURE); - } - - execl("/usr/bin/bash", "/usr/bin/bash", "-l", NULL); - perror("init: execl /usr/bin/bash failed"); - return exit(EXIT_FAILURE); + if (tcsetpgrp(0, getpid()) == -1) { + perror("init: tcsetpgrp failed"); + exit(EXIT_FAILURE); } - dowaitpid(pid); + execl("/usr/bin/bash", "/usr/bin/bash", "-l", NULL); + perror("init: execl /usr/bin/bash failed"); + return exit(EXIT_FAILURE); } + + handlecommands(); } static void dologinprompt(void) { - for (;;) { - pid_t pid = fork(); - if (pid == -1) { - perror("init: fork failed"); - exit(EXIT_FAILURE); - } - - if (pid == 0) { - setsid(); - snatchconsole(); - execl("/bin/login", NULL); - perror("init: exec /bin/login failed"); - exit(EXIT_FAILURE); - } - - dowaitpid(pid); + pid_t pid = fork(); + if (pid == -1) { + perror("init: fork failed"); + exit(EXIT_FAILURE); } + + if (pid == 0) { + setsid(); + snatchconsole(); + execl("/bin/login", NULL); + perror("init: exec /bin/login failed"); + exit(EXIT_FAILURE); + } + + handlecommands(); } static void dostartwm(void) { @@ -103,15 +185,23 @@ static void dostartwm(void) { exit(EXIT_FAILURE); } - dowaitpid(pid); - - // fall back to a root shell if this ever returns (it shouldn't) - dorootshell(); + handlecommands(); } int main(int argc, char *argv[]) { printf("init: Welcome to Astral!\n"); + // set up signal mask + sigset_t signals; + sigfillset(&signals); + sigprocmask(SIG_SETMASK, &signals, NULL); + + // set up signal actions + struct sigaction sa; + memset(&sa, 0, sizeof(sigaction)); + sa.sa_handler = reap; + sigaction(SIGCHLD, &sa, NULL); + // set up initial environmental variables struct passwd* pw = getpwuid(getuid()); if (pw == NULL) { @@ -180,6 +270,15 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + // unmask sigchild to reap children now + sigdelset(&signals, SIGCHLD); + + printf("init: creating %s\n", COMMAND_FIFO); + if (mkfifo(COMMAND_FIFO, 0600)) { + perror("init: mkfifo failed"); + return EXIT_FAILURE; + } + if (argc >1 && strcmp(argv[1], "withlogin") == 0) dologinprompt(); diff --git a/tools/init/poweroff.c b/tools/init/poweroff.c new file mode 100644 index 00000000..a8b06429 --- /dev/null +++ b/tools/init/poweroff.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +#include "common.h" + +int main() { + char c = COMMAND_POWEROFF; + int fd = open(COMMAND_FIFO, O_WRONLY); + + if (fd == -1) { + perror("poweroff: open"); + return EXIT_FAILURE; + } + + if (write(fd, &c, 1)) { + perror("poweroff: write"); + return EXIT_FAILURE; + } + + close(fd); + return EXIT_SUCCESS; +}