unix/fiss

renaming src/exec -> src/bin (3333c196e2dd892a6300495091a98b3e32253dc6)
Repositories | LICENSE

commit 3333c196e2dd892a6300495091a98b3e32253dc6
parent fc767b2459193cbc4f5fd6ee07d9953afa93ad5b
Author: Friedel Schön <[email protected]>
Date:   Wed, 31 May 2023 00:08:51 +0200

renaming src/exec -> src/bin

Diffstat:
MMakefile2+-
Mdocs/chpst.8.html2+-
Mdocs/index.html2+-
Mman/chpst.82+-
Mman/fsvc.82+-
Mman/fsvs.82+-
Mman/halt.82+-
Mman/modules-load.82+-
Mman/shutdown.82+-
Mman/sigremap.82+-
Mman/vlogger.12+-
Mman/zzz.82+-
Dsrc/exec/chpst.c129-------------------------------------------------------------------------------
Dsrc/exec/finit.c129-------------------------------------------------------------------------------
Dsrc/exec/fsvc.c320-------------------------------------------------------------------------------
Dsrc/exec/fsvs.c58----------------------------------------------------------
Dsrc/exec/halt.c79-------------------------------------------------------------------------------
Dsrc/exec/init.lnk2--
Dsrc/exec/modules-load.c136-------------------------------------------------------------------------------
Dsrc/exec/poweroff.lnk2--
Dsrc/exec/reboot.lnk2--
Dsrc/exec/seedrng.c468-------------------------------------------------------------------------------
Dsrc/exec/shutdown.sh69---------------------------------------------------------------------
Dsrc/exec/sigremap.c277-------------------------------------------------------------------------------
Dsrc/exec/vlogger.c193-------------------------------------------------------------------------------
Dsrc/exec/zzz.c120-------------------------------------------------------------------------------
26 files changed, 12 insertions(+), 1996 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,7 @@ SRC_DIR := src BUILD_DIR := build INCLUDE_DIR := include BIN_DIR := bin -EXEC_DIR := src/exec +EXEC_DIR := src/bin MAN_DIR := src/man TEMPL_DIR := src/docs ROFF_DIR := man diff --git a/docs/chpst.8.html b/docs/chpst.8.html @@ -11,7 +11,7 @@ <body> <div id=wrapper> -<span class=header><a class=title id=top href=#top>chpst(8) 0.3.2</a><span class=right><span id=toggle_dark onclick=toggle_dark()> turn the lights on </span> <a href=https://github.com/friedelschoen/fiss><img id=github alt=GitHub src=assets/github-mark.svg /></a></span></span> +<span class=header><a class=title id=top href=#top>chpst(8) 0.3.3</a><span class=right><span id=toggle_dark onclick=toggle_dark()> turn the lights on </span> <a href=https://github.com/friedelschoen/fiss><img id=github alt=GitHub src=assets/github-mark.svg /></a></span></span> ================================================================================ <a class=title id=name href=#name>Name</a> diff --git a/docs/index.html b/docs/index.html @@ -11,7 +11,7 @@ <body> <div id=wrapper> -<span class=header><a class=title id=top href=#top>fiss 0.3.2</a><span class=right><span id=toggle_dark onclick=toggle_dark()> turn the lights on </span> <a href=https://github.com/friedelschoen/fiss><img id=github alt=GitHub src=assets/github-mark.svg /></a></span></span> +<span class=header><a class=title id=top href=#top>fiss 0.3.3</a><span class=right><span id=toggle_dark onclick=toggle_dark()> turn the lights on </span> <a href=https://github.com/friedelschoen/fiss><img id=github alt=GitHub src=assets/github-mark.svg /></a></span></span> ================================================================================ Aloha! You somehow landed on the website of <b>fiss</b> (_Friedel's Initialization and Service Supervision_). <b>fiss</b> is a supervision suite for Unix and Unix-like systems with the power off system initialization. This project is based on <b>runit</b> and other <b>daemontools</b>-based utilities. diff --git a/man/chpst.8 b/man/chpst.8 @@ -1,4 +1,4 @@ -.TH chpst 8 "MAY 2023" "0.3.2" "fiss man page" +.TH chpst 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/fsvc.8 b/man/fsvc.8 @@ -1,4 +1,4 @@ -.TH fsvc 8 "MAY 2023" "0.3.2" "fiss man page" +.TH fsvc 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/fsvs.8 b/man/fsvs.8 @@ -1,4 +1,4 @@ -.TH fsvs 8 "MAY 2023" "0.3.2" "fiss man page" +.TH fsvs 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/halt.8 b/man/halt.8 @@ -1,4 +1,4 @@ -.TH halt 8 "MAY 2023" "0.3.2" "fiss man page" +.TH halt 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/modules-load.8 b/man/modules-load.8 @@ -1,4 +1,4 @@ -.TH modules-load 8 "MAY 2023" "0.3.2" "fiss man page" +.TH modules-load 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/shutdown.8 b/man/shutdown.8 @@ -1,4 +1,4 @@ -.TH shutdown 8 "MAY 2023" "0.3.2" "fiss man page" +.TH shutdown 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/sigremap.8 b/man/sigremap.8 @@ -1,4 +1,4 @@ -.TH sigremap 8 "MAY 2023" "0.3.2" "fiss man page" +.TH sigremap 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/vlogger.1 b/man/vlogger.1 @@ -1,4 +1,4 @@ -.TH vlogger 1 "MAY 2023" "0.3.2" "fiss man page" +.TH vlogger 1 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/man/zzz.8 b/man/zzz.8 @@ -1,4 +1,4 @@ -.TH zzz 8 "MAY 2023" "0.3.2" "fiss man page" +.TH zzz 8 "MAY 2023" "0.3.3" "fiss man page" .PP .SH NAME diff --git a/src/exec/chpst.c b/src/exec/chpst.c @@ -1,129 +0,0 @@ -#include "parse.h" -#include "util.h" - -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <sys/file.h> - - -int main(int argc, char** argv) { - int opt, lockfd, lockflags, gid_len = 0; - char *arg0 = NULL, *root = NULL, *cd = NULL, *lock = NULL, *exec = NULL; - uid_t uid = 0; - gid_t gid[61]; - long nicelevel = 0; - bool ssid = false; - bool closestd[3] = { false, false, false }; - - while ((opt = getopt(argc, argv, "+u:U:b:e:m:d:o:p:f:c:r:t:/:C:n:l:L:vP012V")) != -1) { - switch (opt) { - case 'u': - case 'U': - gid_len = parse_ugid(optarg, &uid, gid); - break; - case 'b': - arg0 = optarg; - break; - case '/': - root = optarg; - break; - case 'C': - cd = optarg; - break; - case 'n': - nicelevel = parse_long(optarg, "nice-level"); - break; - case 'l': - lock = optarg; - lockflags = LOCK_EX | LOCK_NB; - break; - case 'L': - lock = optarg; - lockflags = LOCK_EX; - break; - case 'v': // ignored - break; - case 'P': - ssid = true; - break; - case '0': - case '1': - case '2': - closestd[opt - '0'] = true; - break; - case 'e': - case 'd': - case 'o': - case 'p': - case 'f': - case 'c': - case 'r': - case 't': - case 'm': // ignored - fprintf(stderr, "warning: '-%c' are ignored\n", optopt); - break; - case '?': - fprintf(stderr, "usage\n"); - return 1; - } - } - argv += optind, argc -= optind; - - if (argc == 0) { - fprintf(stderr, "command required\n"); - return 1; - } - - if (ssid) { - setsid(); - } - - if (uid) { - setgroups(gid_len, gid); - setgid(gid[0]); - setuid(uid); - // $EUID - } - - if (root) { - if (chroot(root) == -1) - print_error("unable to change root directory: %s\n"); - - // chdir to '/', otherwise the next command will complain 'directory not found' - chdir("/"); - } - - if (cd) { - chdir(cd); - } - - if (nicelevel != 0) { - if (nice(nicelevel) == -1) - print_error("unable to set nice level: %s\n"); - } - - if (lock) { - if ((lockfd = open(lock, O_WRONLY | O_APPEND)) == -1) - print_error("unable to open lock: %s\n"); - - if (flock(lockfd, lockflags) == -1) - print_error("unable to lock: %s\n"); - } - - if (closestd[0] && close(0) == -1) - print_error("unable to close stdin: %s\n"); - if (closestd[1] && close(1) == -1) - print_error("unable to close stdout: %s\n"); - if (closestd[2] && close(2) == -1) - print_error("unable to close stderr: %s\n"); - - exec = argv[0]; - if (arg0) - argv[0] = arg0; - - execvp(exec, argv); - print_error("cannot execute: %s\n"); -} diff --git a/src/exec/finit.c b/src/exec/finit.c @@ -1,129 +0,0 @@ -#include "config.h" -#include "message.h" -#include "service.h" -#include "util.h" - -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdio.h> -#include <string.h> -#include <sys/reboot.h> -#include <sys/wait.h> -#include <unistd.h> - - -static bool do_reboot; - -static int handle_initctl(int argc, const char** argv) { - int sig; - - if (argc != 2 || argv[1][1] != '\0' || (argv[1][0] != '0' && argv[1][0] != '6')) { - print_usage_exit(PROG_FINIT, 1); - } - if (getuid() != 0) { - fprintf(stderr, "error: can only be run as root...\n"); - return 1; - } - sig = argv[1][0] == '0' ? SIGTERM : SIGINT; - if (kill(1, sig) == -1) { - print_error("error: unable to kill init: %s\n"); - return 1; - } - return 0; -} - -static void signal_interrupt(int signum) { - daemon_running = false; - do_reboot = signum == SIGINT; -} - - -int main(int argc, const char** argv) { - sigset_t ss; - pid_t pid; - - if (getpid() != 1) { - return handle_initctl(argc, argv); - } - setsid(); - - sigblock_all(false); - - reclaim_console(); - - // disable ctrl-alt-delete - reboot(0); - - printf("booting...\n"); - - // stage 1 - service_stage(0); - - - // stage 2 - if (daemon_running) { // stage1 succeed - struct sigaction sigact = { 0 }; - - sigblock_all(true); - - sigact.sa_handler = signal_interrupt; - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGINT, &sigact, NULL); - - service_supervise(SV_SERVICE_DIR, SV_RUNLEVEL_DEFAULT); - sigblock_all(false); - } - - // stage 3 - service_stage(2); - -#ifdef RB_AUTOBOOT - /* fallthrough stage 3 */ - printf("sending KILL signal to all processes...\n"); - kill(-1, SIGKILL); - - if ((pid = fork()) <= 0) { - if (do_reboot) { - printf("system reboot\n"); - sync(); - reboot(RB_AUTOBOOT); - } else { -# if defined(RB_POWER_OFF) - printf("system power off\n"); - sync(); - reboot(RB_POWER_OFF); - sleep(2); -# elif defined(RB_HALT_SYSTEM) - printf("system halt\n"); - sync(); - reboot(RB_HALT_SYSTEM); -# elif define(RB_HALT) - printf("system halt\n"); - sync(); - reboot(RB_HALT); -# else - printf("system reboot\n"); - sync(); - reboot(RB_AUTOBOOT); -# endif - } - if (pid == 0) - _exit(0); - } else { - sigemptyset(&ss); - sigaddset(&ss, SIGCHLD); - sigprocmask(SIG_UNBLOCK, &ss, NULL); - - while (waitpid(pid, NULL, 0) != -1) {} - } -#endif - - sigfillset(&ss); - for (;;) - sigsuspend(&ss); - - /* not reached */ - printf("exit.\n"); - return 0; -} diff --git a/src/exec/fsvc.c b/src/exec/fsvc.c @@ -1,320 +0,0 @@ -#include "config.h" -#include "message.h" -#include "service.h" -#include "signame.h" -#include "util.h" - -#include <fcntl.h> -#include <getopt.h> -#include <limits.h> -#include <stdbool.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - - -struct ident { - const char* name; - const char* command; - bool runit; -}; - -static struct ident command_names[] = { - { "up", "u", true }, // starts the services, pin as started - { "down", "d", true }, // stops the service, pin as stopped - { "xup", "U", true }, // stops the service, don't pin as stopped - { "xdown", "D", true }, // stops the service, don't pin as stopped - { "once", "o", true }, // same as xup - { "term", "t", true }, // same as down - { "kill", "k", true }, // sends kill, pin as stopped - { "pause", "p", true }, // pauses the service - { "cont", "c", true }, // resumes the service - { "reset", "r", true }, // resets the service - { "alarm", "a", true }, // sends alarm - { "hup", "h", true }, // sends hup - { "int", "i", true }, // sends interrupt - { "quit", "q", true }, // sends quit - { "1", "1", true }, // sends usr1 - { "2", "2", true }, // sends usr2 - { "exit", "x", true }, // does nothing - { "+up", "U0", false }, // starts the service, don't modify pin - { "+down", "D0", false }, // stops the service, don't modify pin - { "restart", "!D0U0", false }, // restarts the service, don't modify pin - { "start", "!u", true }, // start the service, pin as started, print status - { "stop", "!d", true }, // stop the service, pin as stopped, print status - { "status", "!", true }, // print status - { "check", "!", true }, // print status - { "enable", "!.e", false }, // enable service - { "disable", "!.d", false }, // disable service - { "enable-once", "!.e", false }, // enable service once - { "disable-once", "!.d", false }, // disable service once - { 0, 0, 0 } -}; - -static const struct option long_options[] = { - { "version", no_argument, NULL, 'V' }, - { "wait", no_argument, NULL, 'w' }, - { 0 } -}; - -static int check_service(int dir, char* runlevel) { - int fd; - ssize_t size; - - if ((fd = openat(dir, "supervise/ok", O_WRONLY | O_NONBLOCK)) == -1) - return -1; - close(fd); - - if ((fd = openat(dir, "supervise/runlevel", O_RDONLY)) == -1) - return -1; - - if ((size = read(fd, runlevel, NAME_MAX)) == -1) { - close(fd); - return -1; - } - runlevel[size] = '\0'; - close(fd); - - return 0; -} - -static time_t get_mtime(int dir) { - struct stat st; - if (fstatat(dir, "supervise/status", &st, 0) == -1) - return -1; - return st.st_mtim.tv_sec; -} - -static int handle_command(int dir, char command, const char* runlevel) { - int fd; - - char up_file[SV_NAME_MAX] = "up-"; - char once_file[SV_NAME_MAX] = "once-"; - - strcat(up_file, runlevel); - strcat(once_file, runlevel); - - switch (command) { - case 'e': // enable - if ((fd = openat(dir, up_file, O_WRONLY | O_TRUNC | O_CREAT, 0644)) != -1) - close(fd); - break; - case 'd': - unlinkat(dir, up_file, 0); - break; - case 'E': // enable - if ((fd = openat(dir, once_file, O_WRONLY | O_TRUNC | O_CREAT, 0644)) != -1) - close(fd); - break; - case 'D': - unlinkat(dir, once_file, 0); - break; - default: - return -1; - } - return 0; -} - -static int send_command(int dir, const char* command, const char* runlevel) { - int fd; - if ((fd = openat(dir, "supervise/control", O_WRONLY | O_NONBLOCK)) == -1) - return -1; - - for (const char* c = command; *c != '\0'; c++) { - if (*c == '.') { - c++; - if (handle_command(dir, *c, runlevel) == -1) - return -1; - } else { - if (write(fd, c, 1) == -1) - break; - } - } - close(fd); - - return 0; -} - -int status(int dir) { - int fd; - time_t timeval; - const char* timeunit = "sec"; - - if ((fd = openat(dir, "supervise/status", O_RDONLY | O_NONBLOCK)) == -1) - return -1; - - service_serial_t buffer; - service_t s; - - if (read(fd, &buffer, sizeof(buffer)) == -1) { - close(fd); - return -1; - } - - close(fd); - - service_decode(&s, &buffer); - - timeval = time(NULL) - s.status_change; - - if (timeval >= 60) { - timeval /= 60; - timeunit = "min"; - if (timeval >= 60) { - timeval /= 60; - timeunit = "h"; - if (timeval >= 24) { - timeval /= 24; - timeunit = "d"; - } - } - } - - switch (s.state) { - case STATE_SETUP: - printf("setting up"); - break; - case STATE_STARTING: - printf("starting as %d", s.pid); - break; - case STATE_ACTIVE_FOREGROUND: - printf("active as %d", s.pid); - break; - case STATE_ACTIVE_BACKGROUND: - case STATE_ACTIVE_DUMMY: - printf("active"); - break; - case STATE_FINISHING: - printf("finishing as %d", s.pid); - break; - case STATE_STOPPING: - printf("stopping as %d", s.pid); - break; - case STATE_INACTIVE: - printf("inactive"); - break; - case STATE_DEAD: - printf("dead"); - break; - } - - if (s.paused) - printf(" & paused"); - - printf(" since %lu%s", timeval, timeunit); - - if (s.restart_final) - printf(", restarts on exit"); - - if (s.return_code > 0 && s.last_exit == EXIT_NORMAL) - printf(", exited with %d", s.return_code); - - if (s.return_code > 0 && s.last_exit == EXIT_SIGNALED) - printf(", signaled with SIG%s", sigabbr(s.return_code)); - - if (s.fail_count > 0) - printf(", failed %d times", s.fail_count); - - printf("\n"); - - return 0; -} - -int main(int argc, char** argv) { - int opt, dir, - timeout = SV_STATUS_WAIT; - time_t mod, start; - - const char* command = NULL; - char runlevel[SV_NAME_MAX]; - - while ((opt = getopt_long(argc, argv, ":Vw:", long_options, NULL)) != -1) { - switch (opt) { - case 'V': - // version - break; - case 'w': - timeout = parse_long(optarg, "seconds"); - break; - default: - case '?': - if (optopt) - fprintf(stderr, "error: invalid option -%c\n", optopt); - else - fprintf(stderr, "error: invalid option %s\n", argv[optind - 1]); - print_usage_exit(PROG_FSVC, 1); - } - } - - argc -= optind, argv += optind; - - if (argc == 0) { - fprintf(stderr, "error: command omitted\n"); - print_usage_exit(PROG_FSVC, 1); - } - for (struct ident* ident = command_names; ident->name != NULL; ident++) { - if (streq(ident->name, argv[0])) { - command = ident->command; - break; - } - } - if (command == NULL) { - fprintf(stderr, "error: unknown command '%s'\n", argv[0]); - print_usage_exit(PROG_FSVC, 1); - } - - argc--, argv++; - - if (argc == 0) { - fprintf(stderr, "error: at least one service must be specified\n"); - print_usage_exit(PROG_FSVC, 1); - } - - chdir(SV_SERVICE_DIR); - - bool print_status; - if ((print_status = command[0] == '!')) { - command++; - } - - for (int i = 0; i < argc; i++) { - if ((dir = open(argv[i], O_DIRECTORY)) == -1) { - fprintf(stderr, "warning: '%s' is not a valid directory\n", argv[i]); - continue; - } - - - if (check_service(dir, runlevel) == -1) { - fprintf(stderr, "warning: '%s' is not a valid service\n", argv[i]); - continue; - } - - if ((mod = get_mtime(dir)) == -1) { - fprintf(stderr, "warning: cannot get modify-time of '%s'\n", argv[i]); - continue; - } - - if (command[0] != '\0') { - if (send_command(dir, command, runlevel) == -1) { - fprintf(stderr, "warning: unable to send command to '%s'\n", argv[i]); - continue; - } - } else { - mod++; // avoid modtime timeout - } - - start = time(NULL); - if (print_status) { - while (get_mtime(dir) == mod && time(NULL) - start < timeout) - usleep(500); // sleep half a secound - - if (get_mtime(dir) == mod) - printf("timeout: "); - - printf("%s: ", progname(argv[i])); - - if (status(dir) == -1) - printf("unable to access supervise/status\n"); - } - } -} diff --git a/src/exec/fsvs.c b/src/exec/fsvs.c @@ -1,58 +0,0 @@ -// daemon manager - -#include "config.h" -#include "message.h" -#include "service.h" -#include "util.h" - -#include <getopt.h> -#include <stdio.h> -#include <sys/wait.h> -#include <unistd.h> - - -static const struct option long_options[] = { - { "version", no_argument, 0, 'V' }, - { 0 } -}; - -static void signal_interrupt(int signum) { - (void) signum; - - daemon_running = false; -} - -int main(int argc, char** argv) { - int c; - while ((c = getopt_long(argc, argv, ":V", long_options, NULL)) > 0) { - switch (c) { - case 'V': - print_version_exit(); - default: - case '?': - if (optopt) - fprintf(stderr, "error: invalid option -%c\n", optopt); - else - fprintf(stderr, "error: invalid option %s\n", argv[optind - 1]); - print_usage_exit(PROG_FSVS, 1); - } - } - - argv += optind; - argc -= optind; - if (argc == 0) { - fprintf(stderr, "error: missing <service-dir>\n"); - print_usage_exit(PROG_FSVS, 1); - } else if (argc == 1) { - fprintf(stderr, "error: missing <runlevel>\n"); - print_usage_exit(PROG_FSVS, 1); - } else if (argc > 2) { - fprintf(stderr, "error: too many arguments\n"); - print_usage_exit(PROG_FSVS, 1); - } - - signal(SIGINT, signal_interrupt); - signal(SIGCONT, signal_interrupt); - - return service_supervise(argv[0], argv[1]); -} diff --git a/src/exec/halt.c b/src/exec/halt.c @@ -1,79 +0,0 @@ -#include "util.h" -#include "wtmp.h" - -#include <errno.h> -#include <stdbool.h> -#include <string.h> -#include <sys/reboot.h> -#include <unistd.h> - - -int main(int argc, char* argv[]) { - bool do_sync = true, - do_force = false, - do_wtmp = true, - noop = false; - int opt; - int rebootnum; - const char* initarg; - - char* prog = progname(argv[0]); - - if (streq(prog, "halt")) { - rebootnum = RB_HALT_SYSTEM; - initarg = "0"; - } else if (streq(prog, "poweroff")) { - rebootnum = RB_POWER_OFF; - initarg = "0"; - } else if (streq(prog, "reboot")) { - rebootnum = RB_AUTOBOOT; - initarg = "6"; - } else { - fprintf(stderr, "invalid mode: %s\n", prog); - return 1; - } - - while ((opt = getopt(argc, argv, "dfhinwB")) != -1) - switch (opt) { - case 'n': - do_sync = 0; - break; - case 'w': - noop = 1; - do_sync = 0; - break; - case 'd': - do_wtmp = 0; - break; - case 'h': - case 'i': - /* silently ignored. */ - break; - case 'f': - do_force = 1; - break; - case 'B': - write_wtmp(1); - return 0; - default: - fprintf(stderr, "Usage: %s [-n] [-f] [-d] [-w] [-B]", prog); - return 1; - } - - if (do_wtmp) - write_wtmp(0); - - if (do_sync) - sync(); - - if (!noop) { - if (do_force) { - reboot(rebootnum); - } else { - execl("/sbin/finit", "init", initarg, NULL); - } - print_error("reboot failed: %s\n"); - } - - return 0; -} diff --git a/src/exec/init.lnk b/src/exec/init.lnk @@ -1 +0,0 @@ -finit -\ No newline at end of file diff --git a/src/exec/modules-load.c b/src/exec/modules-load.c @@ -1,136 +0,0 @@ -#include "util.h" - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <regex.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define MAX_CMDLINE_SIZE 4096 -#define MAX_MODULE_SIZE 256 -#define MAX_MODULE_COUNT 64 - - -static char kernel_cmdline[MAX_CMDLINE_SIZE]; -static char modules[MAX_MODULE_COUNT][MAX_MODULE_SIZE]; -static int modules_size = 0; - -static void read_cmdline(void) { - int fd; - int size; - char *end, *match, *com; - - if ((fd = open("/proc/cmdline", O_RDONLY)) == -1) - return; - - if ((size = read(fd, kernel_cmdline, sizeof(kernel_cmdline))) == -1) { - print_error("cannot read /proc/cmdline: %s\n"); - close(fd); - return; - } - kernel_cmdline[size] = '\0'; - - end = kernel_cmdline; - - while (end < kernel_cmdline + size && (match = strstr(end, "modules-load=")) != NULL) { - if (match != end && match[-1] != '.' && match[-1] != ' ') { - end += sizeof("modules-load=") - 1; // -1 because of implicit '\0' - continue; - } - - match += sizeof("modules-load=") - 1; // -1 because of implicit '\0' - if ((end = strchr(match, ' ')) == NULL) - end = kernel_cmdline + size; - *end = '\0'; - - while ((com = strchr(match, ',')) != NULL) { - *com = '\0'; - strcpy(modules[modules_size++], match); - match = com + 1; - } - if (match[0] != '\0') - strcpy(modules[modules_size++], match); - } -} - -static void read_file(const char* path) { - int fd; - char line[MAX_MODULE_SIZE]; - char* comment; - - if ((fd = open(path, O_RDONLY)) == -1) { - print_error("unable to open %s: %s\n", path); - return; - } - - while (dgetline(fd, line, sizeof(line)) > 0) { - if ((comment = strchr(line, '#')) != NULL) { - *comment = '\0'; - } - if ((comment = strchr(line, ';')) != NULL) { - *comment = '\0'; - } - - if (line[0] != '\0') - strcpy(modules[modules_size++], line); - } -} - -static void read_dir(const char* path) { - DIR* dir; - struct dirent* de; - - if ((dir = opendir(path)) == NULL) { - return; - } - - char filepath[1024]; - while ((de = readdir(dir)) != NULL) { - if (de->d_name[0] == '.') - continue; - - strcpy(filepath, path); - strcat(filepath, de->d_name); - - read_file(filepath); - } - - closedir(dir); -} - -int main(int argc, char** argv) { - read_cmdline(); - - read_dir("/etc/modules-load.d/"); - read_dir("/run/modules-load.d/"); - read_dir("/usr/lib/modules-load.d/"); - - for (int i = 0; i < modules_size; i++) { - printf("%s\n", modules[i]); - } - - char* args[modules_size + argc - 1 + 2 + 1]; - int argi = 0; - - args[argi++] = "modprobe"; - args[argi++] = "-ab"; - - for (int i = 1; i < argc; i++) { - args[argi++] = argv[i]; - } - - for (int i = 0; i < modules_size; i++) { - args[argi++] = modules[i]; - } - - args[argi++] = NULL; - - execvp("modprobe", args); - - print_error("cannot exec modprobe: %s"); - return 1; -} diff --git a/src/exec/poweroff.lnk b/src/exec/poweroff.lnk @@ -1 +0,0 @@ -halt -\ No newline at end of file diff --git a/src/exec/reboot.lnk b/src/exec/reboot.lnk @@ -1 +0,0 @@ -halt -\ No newline at end of file diff --git a/src/exec/seedrng.c b/src/exec/seedrng.c @@ -1,468 +0,0 @@ -/* Based on code from <https://git.zx2c4.com/seedrng/about/>. */ - -#include <endian.h> -#include <errno.h> -#include <fcntl.h> -#include <linux/random.h> -#include <poll.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/file.h> -#include <sys/ioctl.h> -#include <sys/random.h> -#include <sys/stat.h> -#include <time.h> -#include <unistd.h> - - -#ifndef LOCALSTATEDIR -# define LOCALSTATEDIR "/var/lib" -#endif - -#define SEED_DIR LOCALSTATEDIR "/seedrng" -#define CREDITABLE_SEED "seed.credit" -#define NON_CREDITABLE_SEED "seed.no-credit" - -enum blake2s_lengths { - BLAKE2S_BLOCK_LEN = 64, - BLAKE2S_HASH_LEN = 32, - BLAKE2S_KEY_LEN = 32 -}; - -enum seedrng_lengths { - MAX_SEED_LEN = 512, - MIN_SEED_LEN = BLAKE2S_HASH_LEN -}; - -struct blake2s_state { - uint32_t h[8]; - uint32_t t[2]; - uint32_t f[2]; - uint8_t buf[BLAKE2S_BLOCK_LEN]; - unsigned int buflen; - unsigned int outlen; -}; - -#define le32_to_cpup(a) le32toh(*(a)) -#define cpu_to_le32(a) htole32(a) -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif -#ifndef DIV_ROUND_UP -# define DIV_ROUND_UP(n, d) (((n) + (d) -1) / (d)) -#endif - -static inline void cpu_to_le32_array(uint32_t* buf, unsigned int words) { - while (words--) { - *buf = cpu_to_le32(*buf); - ++buf; - } -} - -static inline void le32_to_cpu_array(uint32_t* buf, unsigned int words) { - while (words--) { - *buf = le32_to_cpup(buf); - ++buf; - } -} - -static inline uint32_t ror32(uint32_t word, unsigned int shift) { - return (word >> (shift & 31)) | (word << ((-shift) & 31)); -} - -static const uint32_t blake2s_iv[8] = { - 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, - 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL -}; - -static const uint8_t blake2s_sigma[10][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, -}; - -static void blake2s_set_lastblock(struct blake2s_state* state) { - state->f[0] = -1; -} - -static void blake2s_increment_counter(struct blake2s_state* state, const uint32_t inc) { - state->t[0] += inc; - state->t[1] += (state->t[0] < inc); -} - -static void blake2s_init_param(struct blake2s_state* state, const uint32_t param) { - int i; - - memset(state, 0, sizeof(*state)); - for (i = 0; i < 8; ++i) - state->h[i] = blake2s_iv[i]; - state->h[0] ^= param; -} - -static void blake2s_init(struct blake2s_state* state, const size_t outlen) { - blake2s_init_param(state, 0x01010000 | outlen); - state->outlen = outlen; -} - -static void blake2s_compress(struct blake2s_state* state, const uint8_t* block, size_t nblocks, const uint32_t inc) { - uint32_t m[16]; - uint32_t v[16]; - int i; - - while (nblocks > 0) { - blake2s_increment_counter(state, inc); - memcpy(m, block, BLAKE2S_BLOCK_LEN); - le32_to_cpu_array(m, ARRAY_SIZE(m)); - memcpy(v, state->h, 32); - v[8] = blake2s_iv[0]; - v[9] = blake2s_iv[1]; - v[10] = blake2s_iv[2]; - v[11] = blake2s_iv[3]; - v[12] = blake2s_iv[4] ^ state->t[0]; - v[13] = blake2s_iv[5] ^ state->t[1]; - v[14] = blake2s_iv[6] ^ state->f[0]; - v[15] = blake2s_iv[7] ^ state->f[1]; - -#define G(r, i, a, b, c, d) \ - do { \ - a += b + m[blake2s_sigma[r][2 * i + 0]]; \ - d = ror32(d ^ a, 16); \ - c += d; \ - b = ror32(b ^ c, 12); \ - a += b + m[blake2s_sigma[r][2 * i + 1]]; \ - d = ror32(d ^ a, 8); \ - c += d; \ - b = ror32(b ^ c, 7); \ - } while (0) - -#define ROUND(r) \ - do { \ - G(r, 0, v[0], v[4], v[8], v[12]); \ - G(r, 1, v[1], v[5], v[9], v[13]); \ - G(r, 2, v[2], v[6], v[10], v[14]); \ - G(r, 3, v[3], v[7], v[11], v[15]); \ - G(r, 4, v[0], v[5], v[10], v[15]); \ - G(r, 5, v[1], v[6], v[11], v[12]); \ - G(r, 6, v[2], v[7], v[8], v[13]); \ - G(r, 7, v[3], v[4], v[9], v[14]); \ - } while (0) - ROUND(0); - ROUND(1); - ROUND(2); - ROUND(3); - ROUND(4); - ROUND(5); - ROUND(6); - ROUND(7); - ROUND(8); - ROUND(9); - -#undef G -#undef ROUND - - for (i = 0; i < 8; ++i) - state->h[i] ^= v[i] ^ v[i + 8]; - - block += BLAKE2S_BLOCK_LEN; - --nblocks; - } -} - -static void blake2s_update(struct blake2s_state* state, const void* inp, size_t inlen) { - const size_t fill = BLAKE2S_BLOCK_LEN - state->buflen; - const uint8_t* in = inp; - - if (!inlen) - return; - if (inlen > fill) { - memcpy(state->buf + state->buflen, in, fill); - blake2s_compress(state, state->buf, 1, BLAKE2S_BLOCK_LEN); - state->buflen = 0; - in += fill; - inlen -= fill; - } - if (inlen > BLAKE2S_BLOCK_LEN) { - const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_LEN); - blake2s_compress(state, in, nblocks - 1, BLAKE2S_BLOCK_LEN); - in += BLAKE2S_BLOCK_LEN * (nblocks - 1); - inlen -= BLAKE2S_BLOCK_LEN * (nblocks - 1); - } - memcpy(state->buf + state->buflen, in, inlen); - state->buflen += inlen; -} - -static void blake2s_final(struct blake2s_state* state, uint8_t* out) { - blake2s_set_lastblock(state); - memset(state->buf + state->buflen, 0, BLAKE2S_BLOCK_LEN - state->buflen); - blake2s_compress(state, state->buf, 1, state->buflen); - cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); - memcpy(out, state->h, state->outlen); -} - -static ssize_t getrandom_full(void* buf, size_t count, unsigned int flags) { - ssize_t ret, total = 0; - uint8_t* p = buf; - - do { - ret = getrandom(p, count, flags); - if (ret < 0 && errno == EINTR) - continue; - else if (ret < 0) - return ret; - total += ret; - p += ret; - count -= ret; - } while (count); - return total; -} - -static ssize_t read_full(int fd, void* buf, size_t count) { - ssize_t ret, total = 0; - uint8_t* p = buf; - - do { - ret = read(fd, p, count); - if (ret < 0 && errno == EINTR) - continue; - else if (ret < 0) - return ret; - else if (ret == 0) - break; - total += ret; - p += ret; - count -= ret; - } while (count); - return total; -} - -static ssize_t write_full(int fd, const void* buf, size_t count) { - ssize_t ret, total = 0; - const uint8_t* p = buf; - - do { - ret = write(fd, p, count); - if (ret < 0 && errno == EINTR) - continue; - else if (ret < 0) - return ret; - total += ret; - p += ret; - count -= ret; - } while (count); - return total; -} - -static size_t determine_optimal_seed_len(void) { - size_t ret = 0; - char poolsize_str[11] = { 0 }; - int fd = open("/proc/sys/kernel/random/poolsize", O_RDONLY); - - if (fd < 0 || read_full(fd, poolsize_str, sizeof(poolsize_str) - 1) < 0) { - perror("Unable to determine pool size, falling back to 256 bits"); - ret = MIN_SEED_LEN; - } else - ret = DIV_ROUND_UP(strtoul(poolsize_str, NULL, 10), 8); - if (fd >= 0) - close(fd); - if (ret < MIN_SEED_LEN) - ret = MIN_SEED_LEN; - else if (ret > MAX_SEED_LEN) - ret = MAX_SEED_LEN; - return ret; -} - -static int read_new_seed(uint8_t* seed, size_t len, bool* is_creditable) { - ssize_t ret; - int urandom_fd; - - *is_creditable = false; - ret = getrandom_full(seed, len, GRND_NONBLOCK); - if (ret == (ssize_t) len) { - *is_creditable = true; - return 0; - } else if (ret < 0 && errno == ENOSYS) { - struct pollfd random_fd = { - .fd = open("/dev/random", O_RDONLY), - .events = POLLIN - }; - if (random_fd.fd < 0) - return -errno; - *is_creditable = poll(&random_fd, 1, 0) == 1; - close(random_fd.fd); - } else if (getrandom_full(seed, len, GRND_INSECURE) == (ssize_t) len) - return 0; - urandom_fd = open("/dev/urandom", O_RDONLY); - if (urandom_fd < 0) - return -1; - ret = read_full(urandom_fd, seed, len); - if (ret == (ssize_t) len) - ret = 0; - else - ret = -errno ? -errno : -EIO; - close(urandom_fd); - errno = -ret; - return ret ? -1 : 0; -} - -static int seed_rng(uint8_t* seed, size_t len, bool credit) { - struct { - int entropy_count; - int buf_size; - uint8_t buffer[MAX_SEED_LEN]; - } req = { - .entropy_count = credit ? len * 8 : 0, - .buf_size = len - }; - int random_fd, ret; - - if (len > sizeof(req.buffer)) { - errno = EFBIG; - return -1; - } - memcpy(req.buffer, seed, len); - - random_fd = open("/dev/urandom", O_RDONLY); - if (random_fd < 0) - return -1; - ret = ioctl(random_fd, RNDADDENTROPY, &req); - if (ret) - ret = -errno ? -errno : -EIO; - close(random_fd); - errno = -ret; - return ret ? -1 : 0; -} - -static int seed_from_file_if_exists(const char* filename, int dfd, bool credit, struct blake2s_state* hash) { - uint8_t seed[MAX_SEED_LEN]; - ssize_t seed_len; - int fd = -1, ret = 0; - - fd = openat(dfd, filename, O_RDONLY); - if (fd < 0 && errno == ENOENT) - return 0; - else if (fd < 0) { - ret = -errno; - perror("Unable to open seed file"); - goto out; - } - seed_len = read_full(fd, seed, sizeof(seed)); - if (seed_len < 0) { - ret = -errno; - perror("Unable to read seed file"); - goto out; - } - if ((unlinkat(dfd, filename, 0) < 0 || fsync(dfd) < 0) && seed_len) { - ret = -errno; - perror("Unable to remove seed after reading, so not seeding"); - goto out; - } - if (!seed_len) - goto out; - - blake2s_update(hash, &seed_len, sizeof(seed_len)); - blake2s_update(hash, seed, seed_len); - - printf("Seeding %zd bits %s crediting\n", seed_len * 8, credit ? "and" : "without"); - if (seed_rng(seed, seed_len, credit) < 0) { - ret = -errno; - perror("Unable to seed"); - } - -out: - if (fd >= 0) - close(fd); - errno = -ret; - return ret ? -1 : 0; -} - -static bool skip_credit(void) { - const char* skip = getenv("SEEDRNG_SKIP_CREDIT"); - return skip && (!strcmp(skip, "1") || !strcasecmp(skip, "true") || - !strcasecmp(skip, "yes") || !strcasecmp(skip, "y")); -} - -int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused))) { - static const char seedrng_prefix[] = "SeedRNG v1 Old+New Prefix"; - static const char seedrng_failure[] = "SeedRNG v1 No New Seed Failure"; - int fd = -1, dfd = -1, program_ret = 0; - uint8_t new_seed[MAX_SEED_LEN]; - size_t new_seed_len; - bool new_seed_creditable; - struct timespec realtime = { 0 }, boottime = { 0 }; - struct blake2s_state hash; - - umask(0077); - if (getuid()) { - errno = EACCES; - perror("This program requires root"); - return 1; - } - - blake2s_init(&hash, BLAKE2S_HASH_LEN); - blake2s_update(&hash, seedrng_prefix, strlen(seedrng_prefix)); - clock_gettime(CLOCK_REALTIME, &realtime); - clock_gettime(CLOCK_BOOTTIME, &boottime); - blake2s_update(&hash, &realtime, sizeof(realtime)); - blake2s_update(&hash, &boottime, sizeof(boottime)); - - if (mkdir(SEED_DIR, 0700) < 0 && errno != EEXIST) { - perror("Unable to create seed directory"); - return 1; - } - - dfd = open(SEED_DIR, O_DIRECTORY); - if (dfd < 0 || flock(dfd, LOCK_EX) < 0) { - perror("Unable to lock seed directory"); - program_ret = 1; - goto out; - } - - if (seed_from_file_if_exists(NON_CREDITABLE_SEED, dfd, false, &hash) < 0) - program_ret |= 1 << 1; - if (seed_from_file_if_exists(CREDITABLE_SEED, dfd, !skip_credit(), &hash) < 0) - program_ret |= 1 << 2; - - new_seed_len = determine_optimal_seed_len(); - if (read_new_seed(new_seed, new_seed_len, &new_seed_creditable) < 0) { - perror("Unable to read new seed"); - new_seed_len = BLAKE2S_HASH_LEN; - strncpy((char*) new_seed, seedrng_failure, new_seed_len); - program_ret |= 1 << 3; - } - blake2s_update(&hash, &new_seed_len, sizeof(new_seed_len)); - blake2s_update(&hash, new_seed, new_seed_len); - blake2s_final(&hash, new_seed + new_seed_len - BLAKE2S_HASH_LEN); - - printf("Saving %zu bits of %s seed for next boot\n", new_seed_len * 8, new_seed_creditable ? "creditable" : "non-creditable"); - fd = openat(dfd, NON_CREDITABLE_SEED, O_WRONLY | O_CREAT | O_TRUNC, 0400); - if (fd < 0) { - perror("Unable to open seed file for writing"); - program_ret |= 1 << 4; - goto out; - } - if (write_full(fd, new_seed, new_seed_len) != (ssize_t) new_seed_len || fsync(fd) < 0) { - perror("Unable to write seed file"); - program_ret |= 1 << 5; - goto out; - } - if (new_seed_creditable && renameat(dfd, NON_CREDITABLE_SEED, dfd, CREDITABLE_SEED) < 0) { - perror("Unable to make new seed creditable"); - program_ret |= 1 << 6; - } -out: - if (fd >= 0) - close(fd); - if (dfd >= 0) - close(dfd); - return program_ret; -} diff --git a/src/exec/shutdown.sh b/src/exec/shutdown.sh @@ -1,69 +0,0 @@ -#!/bin/sh -# shutdown - shutdown(8) lookalike for fiss - -abort() { - printf '%s\n' "$1" >&2 - exit 1 -} - -usage() { - abort "Usage: ${0##*/} [-fF] [-kchPr] time [warning message]" -} - -action=: - -while getopts akrhPHfFnct: opt; do - case "$opt" in - a|n|H) abort "'-$opt' is not implemented";; - t) ;; - f) touch /fastboot;; - F) touch /forcefsck;; - k) action=true;; - c) action=cancel;; - h|P) action=halt;; - r) action=reboot;; - [?]) usage;; - esac -done -shift $((OPTIND - 1)) - -[ $# -eq 0 ] && usage - -time=$1; shift -message="${*:-system is going down}" - -if [ "$action" = "cancel" ]; then - kill "$(cat /run/fiss/shutdown.pid)" - if [ -e /etc/nologin ] && ! [ -s /etc/nologin ]; then - rm /etc/nologin - fi - echo "${*:-shutdown cancelled}" | wall - exit -fi - -touch /run/fiss/shutdown.pid 2>/dev/null || abort "Not enough permissions to execute ${0#*/}" -echo $$ >/run/fiss/shutdown.pid - -case "$time" in - now) time=0;; - +*) time=${time#+};; - *:*) abort "absolute time is not implemented";; - *) abort "invalid time";; -esac - -for break in 5 0; do - [ "$time" -gt "$break" ] || continue - [ "$break" = 0 ] && touch /etc/nologin - - printf '%s in %s minutes\n' "$message" "$time" | wall - printf 'shutdown: sleeping for %s minutes... ' "$(( time - break ))" - sleep $(( (time - break) * 60 )) - time="$break" - printf '\n' - - [ "$break" = 0 ] && rm /etc/nologin -done - -printf '%s NOW\n' "$message" | wall - -$action diff --git a/src/exec/sigremap.c b/src/exec/sigremap.c @@ -1,277 +0,0 @@ -/* Copyright (c) 2015 Yelp, Inc. - With modification 2023 Friedel Schon - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - - -#include "message.h" -#include "signame.h" -#include "util.h" - -#include <assert.h> -#include <errno.h> -#include <getopt.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#include <unistd.h> - -#define DEBUG(...) \ - do { \ - if (debug) \ - fprintf(stderr, __VA_ARGS__); \ - } while (0) - -#define set_signal_undefined(old, new) \ - if (signal_remap[old] == -1) \ - signal_remap[old] = new; - - -// Signals we care about are numbered from 1 to 31, inclusive. -// (32 and above are real-time signals.) -// TODO: this is likely not portable outside of Linux, or on strange architectures -#define MAXSIG 31 - -// Indices are one-indexed (signal 1 is at index 1). Index zero is unused. -// User-specified signal rewriting. -static int signal_remap[MAXSIG + 1]; -// One-time ignores due to TTY quirks. 0 = no skip, 1 = skip the next-received signal. -static bool signal_temporary_ignores[MAXSIG + 1]; - -static int child_pid = -1; -static bool debug = false; -static bool use_setsid = true; - - -/* - * The sigremap signal handler. - * - * The main job of this signal handler is to forward signals along to our child - * process(es). In setsid mode, this means signaling the entire process group - * rooted at our child. In non-setsid mode, this is just signaling the primary - * child. - * - * In most cases, simply proxying the received signal is sufficient. If we - * receive a job control signal, however, we should not only forward it, but - * also sleep sigremap itself. - * - * This allows users to run foreground processes using sigremap and to - * control them using normal shell job control features (e.g. Ctrl-Z to - * generate a SIGTSTP and suspend the process). - * - * The libc manual is useful: - * https://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html - * - */ -static void handle_signal(int signum) { - DEBUG("Received signal %d.\n", signum); - - if (signal_temporary_ignores[signum] == 1) { - DEBUG("Ignoring tty hand-off signal %d.\n", signum); - signal_temporary_ignores[signum] = 0; - } else if (signum == SIGCHLD) { - int status, exit_status; - int killed_pid; - while ((killed_pid = waitpid(-1, &status, WNOHANG)) > 0) { - if (WIFEXITED(status)) { - exit_status = WEXITSTATUS(status); - DEBUG("A child with PID %d exited with exit status %d.\n", killed_pid, exit_status); - } else { - assert(WIFSIGNALED(status)); - exit_status = 128 + WTERMSIG(status); - DEBUG("A child with PID %d was terminated by signal %d.\n", killed_pid, exit_status - 128); - } - - if (killed_pid == child_pid) { - kill(use_setsid ? -child_pid : child_pid, SIGTERM); // send SIGTERM to any remaining children - DEBUG("Child exited with status %d. Goodbye.\n", exit_status); - exit(exit_status); - } - } - } else { - if (signum <= MAXSIG && signal_remap[signum] != -1) { - DEBUG("Translating signal %d to %d.\n", signum, signal_remap[signum]); - signum = signal_remap[signum]; - } - - kill(use_setsid ? -child_pid : child_pid, signum); - DEBUG("Forwarded signal %d to children.\n", signum); - - if (signum == SIGTSTP || signum == SIGTTOU || signum == SIGTTIN) { - DEBUG("Suspending self due to TTY signal.\n"); - kill(getpid(), SIGSTOP); - } - } -} - -static char** parse_command(int argc, char* argv[]) { - int opt; - struct option long_options[] = { - { "single", no_argument, NULL, 's' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 }, - }; - char *old, *new; - int oldsig, newsig; - - while ((opt = getopt_long(argc, argv, "+:hvVs", long_options, NULL)) != -1) { - switch (opt) { - case 'v': - debug = true; - break; - case 'V': - print_version_exit(); - case 'c': - use_setsid = false; - break; - default: - print_usage_exit(PROG_SIGREMAP, 1); - } - } - - argc -= optind, argv += optind; - - while (argc > 0) { - if ((new = strchr(argv[0], '=')) == NULL) - break; - - old = argv[0]; - *new = '\0'; - new ++; - - if ((oldsig = signame(old)) == -1) { - fprintf(stderr, "error: invalid old signal '%s'\n", old); - exit(1); - } - if ((newsig = signame(new)) == -1) { - fprintf(stderr, "error: invalid new signal '%s'\n", new); - exit(1); - } - signal_remap[oldsig] = newsig; - - argc--, argv++; - } - - if (argc < 1) { - print_usage_exit(PROG_SIGREMAP, 1); - } - - if (use_setsid) { - set_signal_undefined(SIGTSTP, SIGSTOP); - set_signal_undefined(SIGTSTP, SIGTTOU); - set_signal_undefined(SIGTSTP, SIGTTIN); - } - - return &argv[optind]; -} - -// A dummy signal handler used for signals we care about. -// On the FreeBSD kernel, ignored signals cannot be waited on by `sigwait` (but -// they can be on Linux). We must provide a dummy handler. -// https://lists.freebsd.org/pipermail/freebsd-ports/2009-October/057340.html -static void dummy(int signum) { - (void) signum; -} - -int main(int argc, char* argv[]) { - char** cmd = parse_command(argc, argv); - sigset_t all_signals; - int signum; - - sigfillset(&all_signals); - sigprocmask(SIG_BLOCK, &all_signals, NULL); - - for (int i = 1; i <= MAXSIG; i++) { - signal_remap[i] = -1; - signal_temporary_ignores[i] = false; - - signal(i, dummy); - } - - /* - * Detach sigremap from controlling tty, so that the child's session can - * attach to it instead. - * - * We want the child to be able to be the session leader of the TTY so that - * it can do normal job control. - */ - if (use_setsid) { - if (ioctl(STDIN_FILENO, TIOCNOTTY) == -1) { - DEBUG( - "Unable to detach from controlling tty (errno=%d %s).\n", - errno, - strerror(errno)); - } else { - /* - * When the session leader detaches from its controlling tty via - * TIOCNOTTY, the kernel sends SIGHUP and SIGCONT to the process - * group. We need to be careful not to forward these on to the - * sigremap child so that it doesn't receive a SIGHUP and - * terminate itself (#136). - */ - if (getsid(0) == getpid()) { - DEBUG("Detached from controlling tty, ignoring the first SIGHUP and SIGCONT we receive.\n"); - signal_temporary_ignores[SIGHUP] = 1; - signal_temporary_ignores[SIGCONT] = 1; - } else { - DEBUG("Detached from controlling tty, but was not session leader.\n"); - } - } - } - - child_pid = fork(); - if (child_pid < 0) { - print_error("error: unable to fork: %s\n"); - return 1; - } else if (child_pid == 0) { - /* child */ - sigprocmask(SIG_UNBLOCK, &all_signals, NULL); - if (use_setsid) { - if (setsid() == -1) { - print_error("error: unable to setsid: %s\n"); - exit(1); - } - - if (ioctl(STDIN_FILENO, TIOCSCTTY, 0) == -1) { - DEBUG( - "Unable to attach to controlling tty (errno=%d %s).\n", - errno, - strerror(errno)); - } - DEBUG("setsid complete.\n"); - } - execvp(cmd[0], cmd); - - // if this point is reached, exec failed, so we should exit nonzero - print_error("error: unable to execute %s: %s\n", cmd[0]); - _exit(2); - } - - /* parent */ - DEBUG("Child spawned with PID %d.\n", child_pid); - for (;;) { - sigwait(&all_signals, &signum); - handle_signal(signum); - } -} diff --git a/src/exec/vlogger.c b/src/exec/vlogger.c @@ -1,193 +0,0 @@ -#include "config.h" -#include "message.h" -#include "util.h" - -#include <errno.h> -#include <libgen.h> -#include <limits.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <sys/syslog.h> -#include <unistd.h> - -static char pwd[PATH_MAX]; - -typedef struct ident { - const char* name; - int value; -} ident_t; - -ident_t prioritynames[] = { - { "alert", LOG_ALERT }, - { "crit", LOG_CRIT }, - { "debug", LOG_DEBUG }, - { "emerg", LOG_EMERG }, - { "err", LOG_ERR }, - { "error", LOG_ERR }, - { "info", LOG_INFO }, - { "notice", LOG_NOTICE }, - { "panic", LOG_EMERG }, - { "warn", LOG_WARNING }, - { "warning", LOG_WARNING }, - { 0, -1 } -}; - -ident_t facilitynames[] = { - { "auth", LOG_AUTH }, - { "authpriv", LOG_AUTHPRIV }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "security", LOG_AUTH }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { 0, -1 } -}; - -static void strpriority(char* facil_str, int* facility, int* level) { - char* prio_str = NULL; - ident_t* ident; - - if ((prio_str = strchr(facil_str, '.'))) { - *prio_str = '\0'; - prio_str++; - for (ident = prioritynames; ident->name; ident++) { - if (streq(ident->name, prio_str)) - *level = ident->value; - } - } - if (*facil_str) { - for (ident = facilitynames; ident->name; ident++) { - if (streq(ident->name, facil_str)) - *facility = ident->value; - } - } -} - -int main(int argc, char* argv[]) { - char buf[SV_VLOGGER_BUFFER]; - char *p, *e, *argv0; - char* tag = NULL; - int c; - bool Sflag = false; - int logflags = 0; - int facility = LOG_USER; - int level = LOG_NOTICE; - - argv0 = *argv; - - if (streq(argv0, "./run")) { - // if running as a service, update facility and tag - p = getcwd(pwd, sizeof(pwd)); - if (p != NULL && *pwd == '/') { - if (*(p = pwd + (strlen(pwd) - 1)) == '/') - *p = '\0'; - if ((p = strrchr(pwd, '/')) && strncmp(p + 1, "log", 3) == 0 && - (*p = '\0', (p = strrchr(pwd, '/'))) && (*(p + 1) != '\0')) { - tag = p + 1; - facility = LOG_DAEMON; - level = LOG_NOTICE; - } - } - } else if (streq(basename(argv0), "logger")) { - /* behave just like logger(1) and only use syslog */ - Sflag = true; - } - - while ((c = getopt(argc, argv, "f:ip:Sst:")) != -1) - switch (c) { - case 'f': - if (freopen(optarg, "r", stdin) == NULL) { - print_error("error: unable to reopen %s: %s\n", optarg); - return 1; - } - break; - case 'i': - logflags |= LOG_PID; - break; - case 'p': - strpriority(optarg, &facility, &level); - break; - case 'S': - Sflag = true; - break; - case 's': - logflags |= LOG_PERROR; - break; - case 't': - tag = optarg; - break; - default: - print_usage_exit(PROG_VLOGGER, 1); - } - argc -= optind; - argv += optind; - - if (argc > 0) - Sflag = true; - - if (!Sflag && access("/etc/vlogger", X_OK) != -1) { - ident_t* ident; - const char *sfacility = "", *slevel = ""; - for (ident = prioritynames; ident->name; ident++) { - if (ident->value == level) - slevel = ident->name; - } - for (ident = facilitynames; ident->name; ident++) { - if (ident->value == facility) - sfacility = ident->name; - } - execl("/etc/vlogger", argv0, tag ? tag : "", slevel, sfacility, NULL); - print_error("error: unable to exec /etc/vlogger: %s\n"); - exit(1); - } - - openlog(tag ? tag : getlogin(), logflags, facility); - - if (argc > 0) { - size_t len; - p = buf; - *p = '\0'; - e = buf + sizeof(buf) - 2; - while (*argv) { - len = strlen(*argv); - if (p + len > e && p > buf) { - syslog(level | facility, "%s", buf); - p = buf; - *p = '\0'; - } - if (len > sizeof(buf) - 1) { - syslog(level | facility, "%s", *argv++); - } else { - if (p != buf) { - *p++ = ' '; - *p = '\0'; - } - strncat(p, *argv++, e - p); - p += len; - } - } - if (p != buf) - syslog(level | facility, "%s", buf); - return 0; - } - - while (fgets(buf, sizeof(buf), stdin) != NULL) - syslog(level | facility, "%s", buf); - - return 0; -} diff --git a/src/exec/zzz.c b/src/exec/zzz.c @@ -1,120 +0,0 @@ -#include "config.h" -#include "util.h" - -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <unistd.h> - - -static int open_write(const char* path, const char* string) { - int fd; - - if ((fd = open(path, O_WRONLY | O_TRUNC)) == -1) { - print_error("cannot open %s: %s\n", path); - return -1; - } - if (write(fd, string, strlen(string)) == -1) { - print_error("error writing to %s: %s\n", path); - close(fd); - return -1; - } - return close(fd); -} - - -int main(int argc, char** argv) { - int opt; - pid_t pid; - struct stat st; - const char *new_state = "mem", - *new_disk = NULL; - - struct option long_options[] = { - { "noop", no_argument, 0, 'n' }, - { "freeze", no_argument, 0, 'S' }, - { "suspend", no_argument, 0, 'z' }, - { "hibernate", no_argument, 0, 'Z' }, - { "reboot", no_argument, 0, 'R' }, - { "hybrid", no_argument, 0, 'H' }, - { 0 }, - }; - - while ((opt = getopt_long(argc, argv, "nSzZRH", long_options, NULL)) != -1) { - switch (opt) { - case 'n': - new_state = NULL; - new_disk = NULL; - break; - case 's': - new_state = "suspend"; - new_disk = NULL; - break; - case 'S': - new_state = "freeze"; - new_disk = NULL; - break; - case 'z': - new_state = "mem"; - new_disk = NULL; - break; - case 'Z': - new_state = "disk"; - new_disk = "platform"; - break; - case 'R': - new_state = "disk"; - new_disk = "reboot"; - break; - case 'H': - new_state = "disk"; - new_disk = "suspend"; - break; - default: - printf("zzz [-n] [-S] [-z] [-Z] [-R] [-H]\n"); - return 1; - } - } - - argc -= optind, argv += optind; - - - if (stat(SV_SUSPEND_EXEC, &st) == 0 && st.st_mode & S_IXUSR) { - if ((pid = fork()) == -1) { - print_error("failed to fork for " SV_SUSPEND_EXEC ": %s\n"); - return 1; - } else if (pid == 0) { // child - execl(SV_SUSPEND_EXEC, SV_SUSPEND_EXEC, NULL); - print_error("failed to execute " SV_SUSPEND_EXEC ": %s\n"); - _exit(1); - } - - wait(NULL); - } - - if (new_disk) { - open_write("/sys/power/disk", new_disk); - } - - if (new_state) { - open_write("/sys/power/state", new_state); - } else { - sleep(5); - } - - if (stat(SV_RESUME_EXEC, &st) == 0 && st.st_mode & S_IXUSR) { - if ((pid = fork()) == -1) { - print_error("failed to fork for " SV_RESUME_EXEC ": %s\n"); - return 1; - } else if (pid == 0) { // child - execl(SV_RESUME_EXEC, SV_RESUME_EXEC, NULL); - print_error("failed to execute " SV_RESUME_EXEC ": %s\n"); - _exit(1); - } - - wait(NULL); - } -}