fiss-minit

A standalone service supervisor based on minit
Log | Files | Refs | README | LICENSE

commit c95ba8d989f2a859308ebda05f2c9cfe09377552
parent bb0cd058679ff40074ab3f384151cc8a245ed39c
Author: Friedel Schön <[email protected]>
Date:   Mon, 13 May 2024 19:56:13 +0200

removing not-domain files

Diffstat:
MMakefile | 57+++++----------------------------------------------------
Dftrigger.1 | 51---------------------------------------------------
Dftrigger.c | 169-------------------------------------------------------------------------------
Dgovernor.c | 88-------------------------------------------------------------------------------
Dhard-reboot.8 | 47-----------------------------------------------
Dhard-reboot.c | 35-----------------------------------
Dkillall5.c | 72------------------------------------------------------------------------
Dpowersave.c | 86-------------------------------------------------------------------------------
Dserdo.8 | 50--------------------------------------------------
Dserdo.c | 272-------------------------------------------------------------------------------
Dshutdown.c | 283-------------------------------------------------------------------------------
Dwaitinterface.1 | 30------------------------------
Dwaitinterface.c | 50--------------------------------------------------
Dwaitport.1 | 27---------------------------
Dwaitport.c | 153-------------------------------------------------------------------------------
Dwrite_proc.c | 17-----------------
16 files changed, 5 insertions(+), 1482 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,5 +1,4 @@ -all: minit msvc pidfilehack hard-reboot write_proc killall5 shutdown \ -minit-update serdo ftrigger waitinterface waitport powersave # governor +all: minit msvc pidfilehack minit-update #CFLAGS=-pipe -march=i386 -fomit-frame-pointer -Os -I../dietlibc/include CC=gcc @@ -10,27 +9,12 @@ CROSS= LDFLAGS=-s $(PIE) MANDIR=/usr/man -path = $(subst :, ,$(PATH)) -diet_path = $(foreach dir,$(path),$(wildcard $(dir)/diet)) -ifeq ($(strip $(diet_path)),) -ifneq ($(wildcard /opt/diet/bin/diet),) -DIET=/opt/diet/bin/diet -else -DIET= -endif -else -DIET:=$(strip $(diet_path)) -endif - ifneq ($(DEBUG),) CFLAGS+=-g LDFLAGS+=-g else CFLAGS+=-O2 -fomit-frame-pointer LDFLAGS+=-s -ifneq ($(DIET),) -DIET+=-Os -endif endif ifneq ($(MINITROOT),) @@ -49,48 +33,20 @@ endif minit: minit.o split.o openreadclose.o opendevconsole.o msvc: msvc.o -ftrigger: ftrigger.o minit-update: minit-update.o -serdo: serdo.o -waitinterface: waitinterface.o -waitport: waitport.o -powersave: powersave.o -governor: governor.o - -sepcode: - echo "int main() { return 0; }" > true.c - if $(DIET) $(CROSS)$(CC) $(CFLAGS) $(FLAGS) -Wl,-z,noseparate-code -o true true.c ; then echo -Wl,-z,noseparate-code 2>/dev/null; fi > sepcode - rm -f true true.c - -shutdown: shutdown.o split.o openreadclose.o opendevconsole.o sepcode - $(DIET) $(CROSS)$(CC) $(LDFLAGS) -o shutdown $(subst sepcode,,$^) $(shell cat sepcode) +pidfilehack: pidfilehack.o %.o: %.c - $(DIET) $(CROSS)$(CC) $(CFLAGS) -c $< + $(CROSS)$(CC) $(CFLAGS) -c $< -%: %.o sepcode - $(DIET) $(CROSS)$(CC) $(LDFLAGS) -o $@ $(subst sepcode,,$^) $(LDLIBS) $(shell cat sepcode) +%: %.o + $(CROSS)$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) clean: rm -f *.o minit msvc pidfilehack hard-reboot write_proc killall5 \ shutdown minit-update serdo ftrigger waitinterface waitport \ governor powersave sepcode -test: test.c - gcc -nostdlib -o $@ $^ -I../dietlibc/include ../dietlibc/start.o ../dietlibc/dietlibc.a - -pidfilehack: pidfilehack.c sepcode - $(DIET) $(CROSS)$(CC) $(CFLAGS) -o $@ $< $(shell cat sepcode) - -hard-reboot: hard-reboot.c sepcode - $(DIET) $(CROSS)$(CC) $(CFLAGS) -o $@ $< $(shell cat sepcode) - -write_proc: write_proc.c sepcode - $(DIET) $(CROSS)$(CC) $(CFLAGS) -o $@ $< $(shell cat sepcode) - -killall5: killall5.c sepcode - $(DIET) $(CROSS)$(CC) $(CFLAGS) -o $@ $< $(shell cat sepcode) - install-files: install -d $(DESTDIR)$(MINITROOT) $(DESTDIR)/sbin $(DESTDIR)/bin $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(MANDIR)/man1 install minit pidfilehack $(DESTDIR)/sbin @@ -114,6 +70,3 @@ tar: clean rename rename: if test $(CURNAME) != $(VERSION); then cd .. && mv $(CURNAME) $(VERSION); fi - -pie: - $(MAKE) all PIE=-fpie diff --git a/ftrigger.1 b/ftrigger.1 @@ -1,51 +0,0 @@ -.TH ftrigger 1 -.SH NAME -ftrigger \- trigger an action if a file changes -.SH SYNOPSIS -.B ftrigger [-v] @command filename [@command filename...] - -.SH DESCRIPTION -.B ftrigger -can watch a list of files and run shell commands if they change. - -.B ftrigger -uses the inotify kernel notification mechanism, so it triggers in real -time. ftrigger will trigger when the file is closed after it was opened -for writing to avoid race conditions when the file is not fully written. - -.SH EXAMPLES - -% ftrigger '@msvc -h sshd' /etc/sshd_config - -This will watch /etc/sshd_config, and if it changes, msvc will send a -SIGHUP to the sshd service. - -It is also possible to watch more than one file at a time: - -% ftrigger '@echo updated' /tmp/a /tmp/b - -And it is possible to watch multiple files with different triggers: - -% ftrigger '@echo a updated' /tmp/a '@echo b updated' /tmp/b - -.SH "RACE CONDITION" - -The inotify API has an inherent race condition. ftrigger has to watch -both the file and the directory it is in for changes. If the file is -newly created, ftrigger will receive a notification via the directory, -and will then add a watch to the newly created file, to get notified if -somebody closes the file who had it open for writing. - -If the other process closes the file before ftrigger has a chance to add -the watch on the file, ftrigger will never get notified. In practice, I -have only seen this happen with touch, where the open(3) is immediately -followed by the close(3), and there is no write(3) in the middle. - -To work around this race, ftrigger will also watch for modify events for -the file, and if there aren't any within a second, it will assume the -race happened and trigger on the file. - -.SH AUTHOR -ftrigger was written by Felix von Leitner and can be downloaded from -.I http://www.fefe.de/minit/ - diff --git a/ftrigger.c b/ftrigger.c @@ -1,169 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/inotify.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -struct trigger { - const char *filename, *command; - char * dironly, *fileonly; - struct stat ss; - int idd, idf, created; /* inotify-deskriptor */ - /* created = 1: got a create event on the dir, added a watch on the file, but no modify events on the file yet */ -}* root; -int n; - -void sighandler(int signum) { - int status; - (void) signum; - wait(&status); -} - -int v; - -int main(int argc, char* argv[]) { - int i, in; - const char* command = "make"; - struct stat ss; - char buf[2048]; - struct inotify_event* ie = (struct inotify_event*) buf; - struct pollfd p; - static struct sigaction sa; - - sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, 0); - in = inotify_init(); - root = (struct trigger*) alloca(sizeof(struct trigger) * argc); - memset(root, 0, sizeof(struct trigger) * argc); - for (i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "-v")) { - v = 1; - continue; - } - if (argv[i][0] == '@') { - command = argv[i] + 1; - ++i; - } - if (argv[i]) { - char* c; - root[n].filename = argv[i]; - root[n].command = command; - root[n].dironly = alloca(strlen(root[n].filename) + 3); - c = strrchr(root[n].filename, '/'); - if (c) { - size_t m = c - root[n].filename; - strcpy(root[n].dironly, root[n].filename); - root[n].fileonly = root[n].dironly + m + 1; - root[n].fileonly[-1] = 0; - } else { - root[n].dironly[0] = '.'; - root[n].dironly[1] = 0; - root[n].fileonly = root[n].dironly + 2; - strcpy(root[n].fileonly, root[n].filename); - } - ++n; - } - } - - for (i = 0; i < n; ++i) { - root[i].idf = -1; - if (stat(root[i].filename, &root[i].ss) != 0) - fprintf(stderr, "warning: could not stat file \"%s\": %s\n", root[i].filename, strerror(errno)); - else - root[i].idf = inotify_add_watch(in, root[i].filename, - IN_CLOSE_WRITE | IN_MOVE_SELF | IN_DELETE_SELF | IN_MODIFY); - root[i].idd = inotify_add_watch(in, root[i].dironly, - IN_MOVED_TO | IN_CREATE); - root[i].created = 0; - } - - p.fd = in; - p.events = POLLIN; - - for (;;) { - again: - switch (poll(&p, 1, 1000)) { - case -1: - if (errno == EINTR) { - int status; - wait(&status); - break; - } - return 1; - case 0: { - int foundone = 0; - for (i = 0; i < n; ++i) - if (root[i].created == 1) { - memset(&root[i].ss, 0, sizeof(root[i].ss)); - root[i].created = 0; - foundone = 1; - } - if (foundone) goto goodevent; - } - continue; - case 1: - break; - }; - if (read(in, buf, sizeof(buf)) < (ssize_t) sizeof(*ie)) { - fprintf(stderr, "error reading inotify notification: %s\n", strerror(errno)); - exit(111); - } - - - for (i = 0; i < n; ++i) { - if (root[i].idf == ie->wd) { - if (ie->mask & IN_MODIFY) { - root[i].created = 0; - root[i].idf = inotify_add_watch(in, root[i].filename, - IN_CLOSE_WRITE | IN_MOVE_SELF | IN_DELETE_SELF); - continue; - } - if (ie->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) { - inotify_rm_watch(in, ie->wd); - root[i].idf = -1; - goto again; - } - goto goodevent; - } else if (root[i].idd == ie->wd) { - if (!strcmp(ie->name, root[i].fileonly)) { - if (root[i].idf != -1) - inotify_rm_watch(in, root[i].idf); - root[i].idf = inotify_add_watch(in, root[i].filename, - IN_CLOSE_WRITE | IN_MOVE_SELF | IN_DELETE_SELF | IN_MODIFY); - root[i].created = 1; - /* if the file was created, it will be empty now, wait for - * the IN_CLOSE_WRITE event. */ - if (ie->mask & IN_CREATE) { - goto again; - } - goto goodevent; - /* if the file was moved, this is a genuine event we are - * interested in. fall through */ - } else - goto again; - } - } - goto again; - - goodevent: - for (i = 0; i < n; ++i) { - if (stat(root[i].filename, &ss) == 0 && memcmp(&ss, &root[i].ss, sizeof(ss))) { - memcpy(&root[i].ss, &ss, sizeof(ss)); - if (v) - fprintf(stderr, "file \"%s\" changed, running command \"%s\"\n", root[i].filename, root[i].command); - if (vfork() == 0) { - exit(system(root[i].command)); - } - } - } - } - return 0; -} diff --git a/governor.c b/governor.c @@ -1,88 +0,0 @@ -#include <fcntl.h> -#include <libowfat/errmsg.h> -#include <string.h> -#include <unistd.h> - -const char acstate[] = "/proc/acpi/ac_adapter/AC/state"; -const char sysacstate[] = "/sys/class/power_supply/AC/online"; -char governor[] = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"; -const char powersave[] = "powersave"; -const char performance[] = "performance"; -const char ondemand[] = "conservative"; - -int main(int argc, char* argv[]) { - char buf[1024]; - int fd, r; - const char* s; - errmsg_iam("switch_governor"); - - if (argc < 1) - s = "governor"; - else if ((s = strrchr(argv[0], '/'))) - ++s; - else - s = argv[0]; - if (!strcmp(s, "slow")) { - s = powersave; - goto writeit; - } else if (!strcmp(s, "fast")) { - s = performance; - goto writeit; - } else if (!strcmp(s, "auto")) { - s = ondemand; - goto writeit; - } - - /* first try /sys, if that fails attempt /proc */ - if ((fd = open(sysacstate, O_RDONLY)) == -1) { - if ((fd = open(acstate, O_RDONLY)) == -1) - diesys(1, "could not open ", acstate); - if ((r = read(fd, buf, sizeof(buf))) < 1) - diesys(1, "read error"); - if (r > 1000) - die(1, "too much data in ", acstate); - buf[r] = 0; - close(fd); - if (strstr(buf, "off-line")) - s = powersave; - else if (strstr(buf, "on-line")) - s = ondemand; - else - die(1, "ac adapter neither on-line nor off-line!?"); - } else { - if ((r = read(fd, buf, sizeof(buf))) < 1) - diesys(1, "read error"); - if (r > 2) - die(1, "too much data in ", sysacstate); - buf[r] = 0; - close(fd); - if (buf[0] == '0') - s = powersave; - else if (buf[0] == '1') - s = ondemand; - else - die(1, "ac adapter neither on-line nor off-line!?"); - } -writeit: { - int i; - char* x = strstr(governor, "cpu0"); - if (x) x += 3; - for (i = 0; i < 32; ++i) { - if ((fd = open(governor, O_WRONLY)) == -1) { - if (x && *x == '0') - diesys(1, "could not open ", governor); - break; - } - r = strlen(s); - if (write(fd, s, r) != r) - diesys(1, "write error"); - close(fd); - if (x) - ++(*x); - else - break; - } -} - carp("switched cpufreq governor to ", s); - return 0; -} diff --git a/hard-reboot.8 b/hard-reboot.8 @@ -1,47 +0,0 @@ -.TH hard-reboot 8 -.SH NAME -hard-reboot \- reboot your system immedeately -.SH SYNOPSIS -.B hard-reboot -.I RESTART -.br -.B hard-reboot -.I HALT -.br -.B hard-reboot -.I POWER_OFF - -.SH DESCRIPTION -.B hard-reboot -is used to reboot your system. - -It will not shut down services, unmount filesystems or notify -your users, but expects that this has already been done when it -is called. - -.SH USAGE - -To prevent accidential use of this application the parameters have to -be written in uppercase letters. -.TP 10 -.I RESTART -restart (reboot) the system -.TP -.I HALT -halt the kernel -.TP -.I POWER_OFF -power off the system if possible (supported by hardware) - -.SH AUTHOR -minit was written by Felix von Leitner and can be downloaded from -his page at -.I http://www.fefe.de/minit/ - -hard-reboot was contributed by Tommi Virtanen. - -This manpage was written by Erich Schubert <[email protected]> -for the Debian GNU/Linux operating system. - -.SH "SEE ALSO" -minit(8), msvc(8), pidfilehack(8) diff --git a/hard-reboot.c b/hard-reboot.c @@ -1,35 +0,0 @@ -#include <libowfat/str.h> -#include <stdlib.h> -#include <string.h> -#include <sys/reboot.h> -#include <unistd.h> - -#define ABORTMSG "hard-reboot: Aborted.\n" -#define USAGE "Say \"hard-reboot (RESTART|HALT|POWER_OFF)\" if you really mean it.\n" - -void usage(void) { - write(2, ABORTMSG, strlen(ABORTMSG)); - write(2, USAGE, strlen(USAGE)); - exit(1); -} - -int main(int argc, char* argv[]) { - if (argc != 2) - usage(); - - sync(); - sync(); - sync(); - if (strcmp(argv[1], "RESTART") == 0) { - reboot(RB_AUTOBOOT); - } else if (strcmp(argv[1], "HALT") == 0) { - reboot(RB_HALT_SYSTEM); - } else if (strcmp(argv[1], "POWER_OFF") == 0) { - reboot(RB_POWER_OFF); - } else { - usage(); - } - - while (1) - sleep(10); -} diff --git a/killall5.c b/killall5.c @@ -1,72 +0,0 @@ -/* - -killall5 -- send a signal to all processes. - -killall5 is the SystemV killall command. It sends a signal -to all processes except init(PID 1) and the processes in its -own session, so it won't kill the shell that is running the -script it was called from. Its primary (only) use is in the rc -scripts found in the /etc/init.d directory. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version -2 of the License, or (at your option) any later version. - -*/ - -#include <dirent.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> - -#define USAGE "Usage: killall5 SIGNAL\n" -#define NOPROC "No processes found - /proc not mounted?\n" - -int main(int argc, char** argv) { - struct dirent* dir; - DIR* dirstream; - register pid_t pid, sid, mypid, mysid; - int signal = -1; - unsigned int sig_sent = 0; - - if (argc == 2) { - if (argv[1][0] == '-') argv[1]++; - signal = atoi(argv[1]); - } - - if ((signal < 1) || (signal > 31)) { - write(2, USAGE, sizeof USAGE - 1); - return 1; - } - - - kill(-1, SIGSTOP); - - if ((dirstream = opendir("/proc"))) { - - mypid = getpid(); - mysid = getsid(0); - - while ((dir = readdir(dirstream))) { - pid = atoi(dir->d_name); - - if (pid > 1) { - sig_sent = 1; - sid = getsid(pid); - if ((pid != mypid) && - (sid != mysid)) kill(pid, signal); - } - } - } - - kill(-1, SIGCONT); - if (!sig_sent) { - write(2, NOPROC, sizeof NOPROC - 1); - return 1; - } - - return 0; -} diff --git a/powersave.c b/powersave.c @@ -1,86 +0,0 @@ -#define _GNU_SOURCE -#include <dirent.h> -#include <libowfat/open.h> -#include <linux/sockios.h> -#include <net/if.h> -#include <netinet/in.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -int write_to(const char* filename, const char* string) { - int fd = open_write(filename); - if (fd != -1) { - write(fd, string, strlen(string)); - fd = close(fd); - } - return fd; -} - -void handle(const char* s) { - size_t l = strlen(s); - char* x = alloca(l + 20); - strcpy(x, s); - strcpy(x + l, "/power/control"); - write_to(x, "auto"); -} - -void dwim(const char* name) { - DIR* D; - struct dirent* d; - if (chdir(name)) return; - if (!(D = opendir("."))) return; - while ((d = readdir(D))) { - // puts(d->d_name); - handle(d->d_name); - } - closedir(D); -} - -void pci() { - dwim("/sys/bus/pci/devices"); -} - -void usb() { - dwim("/sys/bus/usb/devices"); -} - -void wakeonlan(const char* interface) { - struct ethtool_wolinfo { - uint32_t cmd, supported, wolopts; - char sopass[6]; - } wol; - int fd = socket(PF_INET, SOCK_DGRAM, 0); - struct ifreq ifr; - if (strlen(interface) > IFNAMSIZ) - return; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); - ifr.ifr_data = (void*) &wol; - memset(&wol, 0, sizeof(wol)); - wol.cmd = 6; // ETHTOOL_SWOL - wol.wolopts = 0; - ioctl(fd, SIOCETHTOOL, &ifr); - close(fd); -} - -int main() { - write_to("/sys/class/scsi_host/host0/link_power_management_policy", "min_power"); - write_to("/sys/class/scsi_host/host1/link_power_management_policy", "min_power"); - write_to("/sys/class/scsi_host/host2/link_power_management_policy", "min_power"); - write_to("/sys/class/scsi_host/host3/link_power_management_policy", "min_power"); - write_to("/sys/class/scsi_host/host4/link_power_management_policy", "min_power"); - write_to("/sys/class/scsi_host/host5/link_power_management_policy", "min_power"); - write_to("/sys/class/scsi_host/host6/link_power_management_policy", "min_power"); - write_to("/sys/module/snd_hda_intel/parameters/power_save", "1"); - write_to("/sys/bus/usb/devices/1-3/power/control", "auto"); - write_to("/sys/bus/usb/devices/1-4/power/control", "auto"); - write_to("/proc/sys/vm/dirty_writeback_centisecs", "1500"); - pci(); - wakeonlan("eth0"); - // usb(); - return 0; -} diff --git a/serdo.8 b/serdo.8 @@ -1,50 +0,0 @@ -.TH serdo 1 -.SH NAME -serdo \- run commands serially -.SH SYNOPSIS -.B serdo -.I [-c] -.I filename - -.SH DESCRIPTION -.B serdo -will open the file given by the command line argument and serially -execute all the commands in it. If a command fails, the whole batch job -is aborted (unless -c is given as first paramter on the serdo command -line). - -serdo understands the \fBcd\fR, \fBexport\fR and \fBulimit\fR (set mode -only) sh(1) built-ins (no loops, no globbiung, no ~user expansion, no -$FOO expansion, no backticks). - -serdo is very limited by design, but it is nice to have if you just want -to run a few ifconfig, ip, route commands in sequence. serdo will -return the exit code of the last command it ran, 0 if none were given. - -If no file name is given as command line argument, but a file called -"script" exists in the current working directory, serdo will execute -that file. This saves a few inodes in a typical /etc/minit tree. - -.SH SYNTAX - -.B serdo scripts are Unix style text files with a list of commands, one -per line. Usual shell script rules do not apply. No if, while, -semicolons, no & to background jobs. - -Special commands that serdo does understand are cd, export, and ulimit. -Spaces at the beginning of each line are ignored. If a line starts with -a '#', it is considered a comment and ignored. Command line arguments -that contain spaces can be grouped using single or double quotes. -Characters can be escaped by putting a backslash ('\\') before them. - -Usually script execution is aborted if any command has a non-zero return -value. This can be overridden by putting a '-' character in front of -a command in the script file (or globally by passing the -c command line -argument to serdo). - -.SH AUTHOR -minit was written by Felix von Leitner and can be downloaded from -.I http://www.fefe.de/minit/ - -.SH "SEE ALSO" -msvc(8), sh(1) diff --git a/serdo.c b/serdo.c @@ -1,272 +0,0 @@ -#include <ctype.h> -#include <fcntl.h> -#include <libowfat/byte.h> -#include <libowfat/errmsg.h> -#include <libowfat/scan.h> -#include <libowfat/str.h> -#include <string.h> -#include <sys/resource.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <unistd.h> - -extern char** environ; - -#define MAXENV 256 -char* envp[MAXENV + 2]; -int envc; - -int continueonerror; - -int envset(char* s) { - int i, l; - if (s[l = str_chr(s, '=')] != '=') return -1; - ++l; - for (i = 0; i < envc; ++i) - if (byte_equal(envp[i], l, s)) { - envp[i] = s; - return 0; - } - if (envc < MAXENV) { - envp[envc] = s; - envp[++envc] = 0; - return 0; - } - return -1; -} - -int spawn(char** argv, int last) { - int i, ignore; - ignore = (argv[0][0] == '-'); - if (ignore) ++argv[0]; - if (str_equal(argv[0], "cd")) { - if (chdir(argv[1]) == -1) { - carpsys("chdir failed"); - failornot: - return ignore ? 0 : -1; - } - return 0; - } else if (str_equal(argv[0], "export")) { - for (i = 1; argv[i]; ++i) envset(argv[i]); - return 0; - } else if (str_equal(argv[0], "exec")) { - ++argv; - last = 1; - } else if (str_equal(argv[0], "ulimit")) { - struct rlimit rl; - for (i = 1; argv[i] && argv[i + 1]; i += 2) { - int id = -1; - if (argv[i][0] != '-') { - ulimitsyntax: - carp("ulimit syntax error: ", argv[i]); - continue; - } - switch (argv[i][1]) { - case 'c': - id = RLIMIT_CORE; - break; - case 'd': - id = RLIMIT_DATA; - break; - case 'e': - id = RLIMIT_NICE; - break; - case 'f': - id = RLIMIT_FSIZE; - break; - case 'i': - id = RLIMIT_SIGPENDING; - break; - case 'l': - id = RLIMIT_MEMLOCK; - break; - case 'm': - id = RLIMIT_RSS; - break; - case 'n': - id = RLIMIT_NOFILE; - break; - case 'r': - id = RLIMIT_RTPRIO; - break; - case 's': - id = RLIMIT_STACK; - break; - case 't': - id = RLIMIT_CPU; - break; - case 'u': - id = RLIMIT_NPROC; - break; - case 'v': - id = RLIMIT_AS; - break; - case 'x': - id = RLIMIT_LOCKS; - break; - default: - goto ulimitsyntax; - } - if (!strcmp(argv[i + 1], "unlimited")) { - rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; - } else { - unsigned long ul; - if (argv[i + 1][scan_ulong(argv[i + 1], &ul)]) - goto ulimitsyntax; - rl.rlim_cur = rl.rlim_max = ul; - } - if (setrlimit(id, &rl) == -1) { - carpsys("ulimit failed"); - goto failornot; - } - } - return 0; - } - if (!last) { - if ((i = fork()) == -1) diesys(1, "cannot fork"); - } else - i = 0; - if (!i) { - /* child */ - environ = envp; - _exit(execvp(argv[0], argv)); - } - if (waitpid(i, &i, 0) == -1) diesys(1, "waitpid failed"); - if (ignore) return 0; - if (!WIFEXITED(i)) - return -1; - return WEXITSTATUS(i); -} - -int run(char* s, int last) { - int i, spaces; - char **argv, **next; - for (i = spaces = 0; s[i]; ++i) - if (s[i] == ' ') ++spaces; - next = argv = alloca((spaces + 2) * sizeof(char*)); - - while (*s) { - while (*s && isspace(*s)) ++s; - if (*s == '"') { - ++s; - *next = s; - while (*s && (*s != '"' || s[-1] == '\\')) ++s; - if (!*s) { - --*next; - break; - } - *s = 0; - ++s; - } else if (*s == '\'') { - ++s; - *next = s; - while (*s && (*s != '\'' || s[-1] == '\\')) ++s; - if (!*s) { - --*next; - break; - } - *s = 0; - ++s; - } else { - *next = s; - while (*s && *s != ' ' && *s != '\t') ++s; - if (*s) { - *s = 0; - ++s; - } - } - ++next; - } - *next = 0; - - return spawn(argv, last); -} - -int execute(char* s, int dontexeclast) { - char* start; - int r; - r = 0; - while (*s) { - int last; - while (isspace(*s)) ++s; - if (*s == '#') { - while (*s && *s != '\n') ++s; - continue; - } - start = s; - - while (*s && *s != '\n') ++s; - /* advance to the end of the line */ - if (*s) { - /* not the last line in the file */ - char* tmp; - *s = 0; - ++s; - /* If it's the last command in the file, we do not fork+exec but - * we execve it directly. So we need to find out here if this is - * the last command in the file. For that we need to skip all the - * lines after it that are comments */ - for (tmp = s; *tmp; ++tmp) - if (!isspace(*tmp) && *tmp == '#') { - for (++tmp; *tmp && *tmp != '\n'; ++tmp) - ; - } else - break; - last = (*tmp == 0); - } else - last = 1; - if (dontexeclast) last = 0; - r = run(start, last); - if (r != 0 && !continueonerror) - break; - } - return r; -} - -int batch(char* s, int dontexeclast) { - struct stat ss; - int fd = open(s, O_RDONLY); - char* map; - if (fd == -1) diesys(1, "could not open ", s); - if (fstat(fd, &ss) == -1) diesys(1, "could not stat ", s); - if (ss.st_size > 32768) die(1, "file ", s, " is too large"); - map = alloca(ss.st_size + 1); - if (read(fd, map, ss.st_size) != (long) ss.st_size) diesys(1, "read error"); - map[ss.st_size] = 0; - close(fd); - - return execute(map, dontexeclast); -} - -int main(int argc, char* argv[], char* env[]) { - static char* fakeargv[] = { 0, "script", 0 }; - int r; - int failing = 0; - int havefail = !access("fail", O_RDONLY); - (void) argc; - if (argc < 2) { - if (!access("script", O_RDONLY)) - argv = fakeargv; - else - die(1, "usage: serdo [-c] filename"); - } - errmsg_iam("serdo"); - for (envc = 0; envc < MAXENV && env[envc]; ++envc) envp[envc] = env[envc]; - envp[envc] = 0; - if (str_equal(argv[1], "-c")) { - continueonerror = 1; - ++argv; - } - while (*++argv) { - if ((r = batch(*argv, !!argv[1] || (havefail && !failing)))) { - if (!failing && havefail) { - fakeargv[1] = "fail"; - argv = fakeargv; - failing = 1; - continue; - } - return r; - } - } - return 0; -} diff --git a/shutdown.c b/shutdown.c @@ -1,283 +0,0 @@ -/* - * Notes: - * - uncomment `#define ALLOW_SUID' below if you want users other than - * root to be able to shut down the system. - * - after compiling, install under /sbin/shutdown with chgrp adm and - * chmod 4750 for SUID root, or 0700 for root only - * - uncomment `#define USE_MINIT' below if you want to use shutdown - * with minit. If defined, shutdown will try to bring down the services - * halt (for -h or -o) or reboot (-r) before killing all other processes. - * Please make sure that you have a depends in reboot and halt that - * will bring down all respawning services. A respawning service during - * shutdown might cause you to wait for a fsck during the next boot - * - If you do not use minit shutdown will bring your system down similar - * to SysV-Inits shutdown with -n - * - * TODO: - * - add a function for wall-messages - * - cleanup - */ - -#include <fcntl.h> -#include <libowfat/str.h> -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/reboot.h> -#include <sys/types.h> -#include <sys/wait.h> - -#ifdef __dietlibc__ -# include <write12.h> -#else -# include <unistd.h> -static inline int __write1(const char* s) { return write(1, s, strlen(s)); } -static inline int __write2(const char* s) { return write(2, s, strlen(s)); } -#endif - -#define ALLOW_SUID -#define USE_MINIT - -#ifdef USE_MINIT -# include "minit.h" -#endif - -extern void opendevconsole(); - -extern char** environ; -extern int openreadclose(char* fn, char** buf, size_t* len); -extern char** split(char* buf, int c, size_t* len, size_t plus, size_t ofs); -extern char* optarg; - -void wall(char* buf) { - __write2(buf); -} - -int exec_cmd(char* cmd, ...) { - char* argv[10]; - va_list arguments; - pid_t pid; - int i; - - va_start(arguments, cmd); - for (i = 0; i < 9 && (argv[i] = va_arg(arguments, char*)) != NULL; i++) - ; - argv[i] = NULL; - va_end(arguments); - pid = fork(); - if (pid < 0) return -1; - if (pid > 0) { - wait(NULL); - } else { - execve(cmd, argv, environ); - // perror("execvp failed"); - exit(0); - } - return 0; -} - -#ifdef USE_MINIT - -static int infd, outfd; -static char buf[1500]; - -int minit_serviceDown(char* service) { - char* s = 0; - unsigned long len; - pid_t pid = 0; - - if (!service || !*service) return 0; - if (chdir(MINITROOT) || chdir(service)) return -1; - - if (!openreadclose("depends", &s, &len)) { - char** deps; - size_t depc, i; - deps = split(s, '\n', &depc, 0, 0); - for (i = 0; i < depc; i++) { - if (deps[i][0] == '#') continue; - minit_serviceDown(deps[i]); - } - } - - // get the pid - buf[0] = 'p'; - strncpy(buf + 1, service, 1400); - write(infd, buf, strlen(buf)); - len = read(outfd, buf, 1500); - if (len != 0) { - buf[len] = 0; - pid = atoi(buf); - } - - if (strcmp("reboot", service) && strcmp("halt", service) && pid > 1) { - int i; - __write2("\t--> "); - __write2(service); - buf[0] = 'r'; // we want to disable respawning first - strncpy(buf + 1, service, 1400); - buf[1400] = 0; - write(infd, buf, strlen(buf)); - if (read(outfd, buf, 1500) < 1) - __write2("\t(status read failed)"); - i = kill(pid, SIGTERM); - if (i == 0) - __write2("\t\tdone\n"); - else - __write2("\t\tfailed\n"); - } - return 0; -} - -int minit_shutdown(int level) { - int retval; - - __write2("Shutting down minit services: \n"); - infd = open(MINITROOT "/in", O_WRONLY); - outfd = open(MINITROOT "/out", O_RDONLY); - if (infd >= 0) { - while (lockf(infd, F_TLOCK, 1)) { - __write2("could not acquire lock!\n"); - sleep(1); - } - } - - retval = minit_serviceDown(level ? "halt" : "reboot"); - close(infd); - close(outfd); - return retval; -} -#endif - -void printUsage() { - __write2("usage: shutdown -[rhosmn] -[t secs]\n" - "\t -r: reboot after shutdown\n" - "\t -h: halt after shutdown\n" - "\t -o: power-off after shutdown\n" - "\t -s: single-user console after shutdown\n" - "\t -m: only shutdown the minit-part\n" - "\t -n: do not shutdown services using minit\n" - "\t -t secs: delay between SIGTERM and SIGKILL\n"); -} - -int main(int argc, char* const argv[]) { - int c; - int cfg_downlevel = 2; - /* 0: reboot - * 1: halt - * 2: power off - */ - unsigned int cfg_delay = 3; - int cfg_minitonly = 0; - int cfg_sulogin = 0; - -#ifdef ALLOW_SUID - if (setuid(geteuid()) == -1) { - __write2("setuid(geteuid()) failed.\n"); - return 111; - } -#endif - if (getuid() != 0) { - __write2("you are not root, go away!\n"); - return 1; - } - - if (argc < 2) { - printUsage(); - return 0; - } - - /* parse commandline options */ - while ((c = getopt(argc, argv, "rhosmnt:")) != EOF) { - switch (c) { - case 'r': /* do we have to reboot... */ - cfg_downlevel = 0; - break; - case 'h': /* ...halt.. */ - cfg_downlevel = 1; - break; - case 's': /* rescue system */ - cfg_sulogin = 1; - break; - case 'm': /* exit after minit down */ - cfg_minitonly = 1; - break; - case 'o': /* ..or power off? */ - cfg_downlevel = 2; - break; - case 't': /* delay between SIGTERM and SIGKILL */ - cfg_delay = atoi(optarg); - break; - default: - printUsage(); - return 1; - } - } - - opendevconsole(); - - switch (cfg_downlevel) { - case 0: - wall("system is going down for reboot NOW\n"); - break; - case 1: - wall("system is going down for system halt NOW\n"); - break; - case 2: - wall("system is going down for power-off NOW\n"); - break; - } - - /* - * catch some signals; - * getting killed after killing the controlling terminal wouldn't be - * such a great thing... - */ - signal(SIGQUIT, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - signal(SIGHUP, SIG_IGN); - signal(SIGTSTP, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - -// real shutdown? then lets rock.. -#ifdef USE_MINIT - minit_shutdown(cfg_downlevel); - if (cfg_minitonly) return 0; -#endif - - /* kill all processes still left */ - __write2("sending all processes the TERM signal...\n"); - kill(-1, SIGTERM); - sleep(cfg_delay); - - __write2("sending all processes the KILL signal...\n"); - kill(-1, SIGKILL); - - if (cfg_sulogin) { - char* suargs[] = { "sulogin", 0 }; - execve("/sbin/sulogin", suargs, 0); - __write2("execve() /sbin/sulogin failed\n"); - return 1; - } - - /* sync buffers */ - sync(); - - exec_cmd("/sbin/swapoff", "swapoff", "-a", (char*) 0); - exec_cmd("/bin/umount", "umount", "-a", (char*) 0); - exec_cmd("/bin/mount", "mount", "-o", "remount,ro", "/", (char*) 0); - - sync(); - - /* and finally reboot, halt or power-off the system */ - if (cfg_downlevel == 0) { - reboot(RB_AUTOBOOT); - } else if (cfg_downlevel == 1) { - reboot(RB_HALT_SYSTEM); - } else { - reboot(RB_POWER_OFF); - } - return 0; -} diff --git a/waitinterface.1 b/waitinterface.1 @@ -1,30 +0,0 @@ -.TH waitinterface 1 -.SH NAME -waitinterface \- wait for a network interface to show up -.SH SYNOPSIS -.B waitinterface ifname command ... - -.B waitinterfaceup ifname command ... -.SH DESCRIPTION -.B waitinterface -will wait for /sys/class/net/ifname to show up (it will try for a few -seconds, then abort and fail if nothing shows up). - -If it is called under the name waitinterfaceup (make a symbolic or hard -link at installation!), it will also wait for the interface to go up. If -that does not happen within a few seconds, it will abort and fail. - -If execution gets this far, the rest of the command line is run (using -execve, so you have to pass in the full path to the command). - -This program is meant for use when one command loads a network driver -into the kernel, and the next program wants to initialize it. There is a -race condition between the kernel module creating the network interface -and the initialization functions attempting to initialize that -interface. In this case you can use waitinterface to delay the -initialization until the interface is actually there. - -.SH AUTHOR -waitinterface was written by Felix von Leitner and can be downloaded from -.I http://www.fefe.de/minit/ - diff --git a/waitinterface.c b/waitinterface.c @@ -1,50 +0,0 @@ -#include <libowfat/errmsg.h> -#include <libowfat/fmt.h> -#include <net/if.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <time.h> -#include <unistd.h> - -int main(int argc, char* argv[], char* envp[]) { - unsigned int i; - struct timespec req, rem; - struct stat ss; - char* sys; - int found; - errmsg_iam("waitinterface"); - if (argc < 2) - die(0, "usage: waitinterface wlan0 /usr/sbin/dhcpcd wlan0\n\twaits for wlan0 to show up and then executes the rest of the command line"); - sys = fmt_strm_alloca("/sys/class/net/", argv[1]); - req.tv_sec = 0; - req.tv_nsec = 100000000; - for (i = 0; i < 100; ++i) { - if ((found = lstat(sys, &ss)) == 0) break; - nanosleep(&req, &rem); - } - if (found == -1) - die(1, "interface not showing up"); - if (strstr(argv[0], "up")) { - /* they want the interface to be up, too */ - int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); - struct ifreq ifr; - if (s == -1) s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - if (s == -1) diesys(1, "socket"); - strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); - for (i = 0; i < 100; ++i) { - if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0 && (ifr.ifr_flags & IFF_UP)) break; - nanosleep(&req, &rem); - } - close(s); - if (!(ifr.ifr_flags & IFF_UP)) - die(1, "interface not up"); - } - if (argv[2]) { - execve(argv[2], argv + 2, envp); - diesys(1, "execve"); - } - return 0; -} diff --git a/waitport.1 b/waitport.1 @@ -1,27 +0,0 @@ -.TH waitport 1 -.SH NAME -waitport \- wait for a local TCP service to show up -.SH SYNOPSIS -.B waitport port command ... - -.B waitport ip/port command ... - -.SH DESCRIPTION -.B waitport -will repeatedly do what netstat does (go through /proc/net/tcp and -/proc/net/tcp6) and look for a specific TCP port in LISTEN state to show -up. When that happens, it will run the rest of the command line. - -There is a timeout after 1000 tries (10 tries per second). If the port -does not show up by then, waitport will abort with a non-zero exit code. - -This program is meant for use with minit, when one service starts a -service, and another program should only be started once the first -service has bound to the port (i.e. is accepting connections). - -Use waitport to resolve race conditions in dependency chains in minit. - -.SH AUTHOR -waitport was written by Felix von Leitner and can be downloaded from -.I http://www.fefe.de/minit/ - diff --git a/waitport.c b/waitport.c @@ -1,153 +0,0 @@ -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <libowfat/buffer.h> -#include <libowfat/fmt.h> -#include <libowfat/ip4.h> -#include <libowfat/ip6.h> -#include <libowfat/scan.h> -#include <libowfat/stralloc.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -static int netstat(const char* addr, unsigned int wantedport) { - /* see linux/Documentation/networking/proc_net_tcp.txt */ - int fd = -1; - char rbuf[4096]; /* since these files can become arbitrarily large, we'll use a real buffer to read from them */ - const char* filenames[] = { "/proc/net/tcp6", "/proc/net/tcp" }; - buffer b; - unsigned int fn; - stralloc line; - - for (fn = 0; fn < sizeof(filenames) / sizeof(filenames[0]); ++fn) { - const char* filename = filenames[fn]; - - fd = open(filename, O_RDONLY | O_CLOEXEC); - if (fd == -1) - continue; - buffer_init(&b, read, fd, rbuf, sizeof(rbuf)); /* can't fail */ - for (;;) { - int r; - char* c; - char* local; - int v6; - stralloc_zero(&line); - if ((r = buffer_getline_sa(&b, &line)) == -1) { - close(fd); - fprintf(stderr, "read error from %s\n", filename); - exit(1); - } - if (r == 0) break; - if (line.len < 1 || line.s[line.len - 1] != '\n') { - parseerror: - close(fd); - fprintf(stderr, "parse error from %s\n", filename); - exit(1); - } - line.s[line.len - 1] = 0; /* string is now null terminated */ - - /* First token is something like "917:", skip */ - for (c = line.s; *c && *c != ':'; ++c) - ; - if (*c != ':') continue; /* first line is boilerplate text and has no :-token, skip it */ - ++c; - for (; *c == ' '; ++c) - ; - /* Next token is something like "00000000:1770" or "00000000000000000000000000000000:0016" */ - local = c; - for (; isxdigit(*c); ++c) - ; - if (c - local != 8 && c - local != 32) /* we only support ipv4 and ipv6; this is neither */ - continue; - v6 = (c - local == 32); - if (*c != ':') goto parseerror; - for (r = 1; r < 5; ++r) { - if (!isxdigit(c[r])) goto parseerror; - } - if (c[5] != ' ') goto parseerror; - c[5] = 0; - c += 6; - /* Next token is the same thing, but we don't really need it, so - * just skip till next whitespace */ - for (; *c && *c != ' '; ++c) - ; - if (*c != ' ') goto parseerror; - ++c; - /* Next is the state; if we are looking at tcp, 0A means LISTEN */ - if (filename[10] == 't' && c[0] == '0' && c[1] == 'A') { - /* TCP LISTEN */ - size_t n; - union { - char ip[16]; - uint32_t ints[4]; - } omgwtfbbq; - char ipstring[FMT_IP6]; - unsigned short port; - unsigned long temp; - - /* we can only be here if the hex string is 8 or 32 bytes long, see above */ - for (n = 0; n < (unsigned int) v6 * 3 + 1; ++n) { - scan_xlongn(local + n * 8, 8, &temp); - omgwtfbbq.ints[n] = temp; - } - - if (scan_xshort(local + (((unsigned int) v6 * 3 + 1) * 8) + 1, &port) != 4) /* can't happen, we validated with isxdigit */ - goto parseerror; - - ipstring[v6 ? fmt_ip6c(ipstring, omgwtfbbq.ip) : fmt_ip4(ipstring, omgwtfbbq.ip)] = 0; - - if (!strcmp(ipstring, addr ? addr : (v6 ? "::" : "0.0.0.0")) && port == wantedport) { - close(fd); - return 1; - } - } - } - close(fd); - fd = -1; - } - - return 0; -} - -int main(int argc, char* argv[], char* envp[]) { - unsigned short port; - - unsigned int i; - struct timespec req, rem; - - char* s = argv[1]; - char* t = strchr(s, '/'); - - if (argc < 2) - usage: - printf("usage: waitport ::/111 some.rpcd\n\twaits for a service to bind to TCP port 111 on ::, then executes the rest of the command line\n"); - exit(0); - { - if (t) { - *t = 0; - if (scan_ushort(t + 1, &port) == 0) goto usage; - } else { - if (scan_ushort(s, &port) == 0) goto usage; - s = 0; - } - } - - req.tv_sec = 0; - req.tv_nsec = 100000000; - for (i = 0; i < 1000; ++i) { - if (netstat(s, port)) { - if (argv[2]) { - execve(argv[2], argv + 2, envp); - fprintf(stderr, "execve: %s\n", strerror(errno)); - exit(1); - } - return 0; - } - nanosleep(&req, &rem); - } - fprintf(stderr, "service on port not showing up"); - exit(1); -} diff --git a/write_proc.c b/write_proc.c @@ -1,17 +0,0 @@ -#include <fcntl.h> -#include <string.h> -#include <unistd.h> - -#define USAGE "write_proc <value> <path_to_proc_file>\n" - -int main(int argc, char* argv[]) { - int fd; - if (argc != 3) goto usage; - if ((fd = open(argv[2], O_WRONLY)) == -1) goto usage; - write(fd, argv[1], strlen(argv[1])); - close(fd); - return 0; -usage: - write(2, USAGE, strlen(USAGE)); - return 1; -}