Created
March 2, 2014 20:43
-
-
Save arsv/9313535 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* See LICENSE file for copyright and license details. */ | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <errno.h> | |
#include "util.h" | |
#define ERR ((void*) -1) | |
static void sigpoweroff(void); | |
static void sigreap(void); | |
static void sigreboot(void); | |
static void spawn(char *const []); | |
char* strerror(int err); | |
static void diee(const char* msg, const char* arg); | |
static struct { | |
int sig; | |
void (*handler)(void); | |
} sigmap[] = { | |
{ SIGUSR1, sigpoweroff }, | |
{ SIGCHLD, sigreap }, | |
{ SIGINT, sigreboot }, | |
}; | |
#include "config.h" | |
static sigset_t set; | |
int | |
main(void) | |
{ | |
int sig; | |
size_t i; | |
//if (getpid() != 1) | |
// return EXIT_FAILURE; | |
//chdir("/"); | |
sigemptyset(&set); | |
for (i = 0; i < LEN(sigmap); i++) | |
sigaddset(&set, sigmap[i].sig); | |
sigprocmask(SIG_BLOCK, &set, NULL); | |
spawn(rcinitcmd); | |
while (1) { | |
sigwait(&set, &sig); | |
for (i = 0; i < LEN(sigmap); i++) | |
if (sigmap[i].sig == sig) | |
sigmap[i].handler(); | |
} | |
/* not reachable */ | |
return EXIT_SUCCESS; | |
} | |
static void | |
sigpoweroff(void) | |
{ | |
spawn(rcpoweroffcmd); | |
} | |
static void | |
sigreap(void) | |
{ | |
while (waitpid(-1, NULL, WNOHANG) > 0) | |
; | |
} | |
static void | |
sigreboot(void) | |
{ | |
spawn(rcrebootcmd); | |
} | |
static void | |
spawn(char *const argv[]) | |
{ | |
pid_t pid; | |
pid = fork(); | |
if (pid < 0) { | |
diee("fork failed", ERR); | |
} else if (pid == 0) { | |
sigprocmask(SIG_UNBLOCK, &set, NULL); | |
setsid(); | |
setpgid(0, 0); | |
execve(argv[0], argv, NULL); | |
diee("fork failed", ERR); | |
_exit(EXIT_FAILURE); | |
} | |
} | |
static void diee(const char* msg, const char* arg) | |
{ | |
char buf[256]; | |
int len = strlen(msg); | |
int max = sizeof(buf) - 2; | |
strncpy(buf, msg, max); | |
if(arg == ERR) | |
arg = strerror(errno); | |
if(arg) | |
strncpy(buf + len, arg, max - len); | |
len = strlen(buf); | |
buf[len++] = '\n'; | |
write(2, buf, len); | |
_exit(-1); | |
} | |
#define r(sym) case sym: return #sym | |
char* strerror(int err) | |
{ | |
static char buf[10]; | |
switch(err) { | |
r(ENOENT); /* open */ | |
r(ELOOP); /* open, unlikely */ | |
r(ENFILE); /* open, socket, accept */ | |
r(EPIPE); /* sendmsg */ | |
r(ENOMEM); /* mmap and a buch of other calls */ | |
r(ECONNREFUSED);/* connect in telinit */ | |
r(EINTR); /* poll; unlikely for other syscalls */ | |
r(EINVAL); /* generic, unlikely */ | |
r(EACCES); /* execve */ | |
r(EIO); /* unlikely, bad news */ | |
} | |
int i = sizeof(buf)-1; | |
buf[i--] = '\0'; | |
while(err && i >= 0) { | |
buf[i--] = err % 10; | |
err /= 10; | |
}; | |
return buf + i + 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment