Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1186 → Rev 1187

/rebootd/trunk/Makefile
4,13 → 4,14
OUTDIR= output
PROG= $(OUTDIR)/$(PROJ)
SRCDIR= src
SRCS= $(SRCDIR)/rebootd.c
HEADERS= $(SRCDIR)/rebootd.h $(SRCDIR)/config.h $(SRCDIR)/signals.h $(SRCDIR)/network.h
SRCS= $(SRCDIR)/rebootd.c $(SRCDIR)/config.c $(SRCDIR)/signals.c $(SRCDIR)/network.c
 
VER_MAJOR= 1
VER_MINOR= 0
VER_REVISION!= svnversion .
 
$(PROG): $(SRCS)
$(PROG): $(HEADERS) $(SRCS)
cc -pedantic-errors -Wall -o $(PROG) \
-DVER_MAJOR=\"$(VER_MAJOR)\" -DVER_MINOR=\"$(VER_MINOR)\" -DVER_REVISION=\"$(VER_REVISION)\" \
$(SRCS)
20,8 → 21,7
pedantic:
lint -x -s -p -n -h -e -c -b -aa \
-DVER_MAJOR=\"$(VER_MAJOR)\" -DVER_MINOR=\"$(VER_MINOR)\" -DVER_REVISION=\"$(VER_REVISION)\" \
$(SRCS) \
| grep -E '^$(PROJ)'
$(SRCS)
cc -Wnested-externs -Wredundant-decls -Wmissing-declarations \
-Wmissing-prototypes -Wstrict-prototypes -Waggregate-return \
-Wwrite-strings -Wcast-align -Wcast-qual -Wpointer-arith \
/rebootd/trunk/TODO
3,5 → 3,5
 
- split code to several files
- man page
- FreeBSD port, Debian package
- Debian package
 
/rebootd/trunk/src/config.c
0,0 → 1,477
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <ctype.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#include "common.h"
#include "config.h"
 
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[]);
static int parse_config_file(struct config *cfg, const char *config_name);
 
static uint min(uint a, uint b)
{
return (a < b) ? a : b;
}
 
static void print_version(void)
{
printf("%s %s.%s.%s\n", APP_NAME, VER_MAJOR, VER_MINOR, VER_REVISION);
}
 
static void pring_usage(int argc, const char* argv[])
{
print_version();
printf("\nA daemon which waits on specified UDP port for special");
printf(" string (password) and reboots the computer.\n\n");
printf("Usage: %s [--debug] [--interface IP] [--port PORT]\n", argv[0]);
printf(" [--config CONFIG_FILE] [--pid FILE]\n");
printf(" or: %s --version\n", argv[0]);
printf(" or: %s --help\n\n", argv[0]);
printf("Defaults are port 19, all interfaces, config /etc/rebootd.conf and no PID file.\n");
printf("In debug mode do not reboot, just write to log.\n\n");
printf("Config file looks like:\n--------------------------\n");
printf("interface=192.168.0.1\nport=19\npassword=\"some password\"\n");
printf("pid=/var/run/rebootd.pid\n--------------------------\n\n");
printf("Then run from any other host:\necho -n \"some password\" | nc -uo host_to_rebot 19\n");
}
 
static int print_error(const char *msg, const char *value)
{
if(daemonized) {
syslog(LOG_ERR, "%s", msg);
if(value) syslog(LOG_ERR, " - %s\n", value);
syslog(LOG_ERR, "\n");
}
else {
fprintf(stderr, "%s", msg);
if(value) fprintf(stderr, " - %s\n", value);
fprintf(stderr, "\n");
}
 
return RESULT_ERROR;
}
 
static int print_cmd_error(int argc, const char* argv[], const char *msg, const char *value)
{
fprintf(stderr, "%s", msg);
if(value) fprintf(stderr, " - %s\n", value);
fprintf(stderr, "\n");
 
pring_usage(argc, argv);
 
return RESULT_ERROR;
}
 
static int print_config_error(const char *config_name, int line, const char *msg, const char *value)
{
if(daemonized) {
syslog(LOG_ERR, "Error in %s, line %d: %s", config_name, line, msg);
if(value) syslog(LOG_ERR, " - %s", value);
syslog(LOG_ERR, "\n");
}
else {
fprintf(stderr, "Error in %s, line %d: %s", config_name, line, msg);
if(value) fprintf(stderr, " - %s", value);
fprintf(stderr, "\n");
}
 
return RESULT_ERROR;
}
 
static int check_abs_path(const char *file_name)
{
if(file_name && file_name[0] != '\0' && file_name[0] != '/') {
return print_error("File must have an absolute path", file_name);
}
 
return RESULT_OK;
}
 
static int parse_interface(const char *s, char **end, struct in_addr *ip)
{
char buf[MAX_CONFIG_LINE];
int count;
const char *c;
 
c = s;
count = 0;
while(c[0] != '\0' && !isspace(c[0])) c++, count++;
if(count > MAX_CONFIG_LINE) return RESULT_ERROR;
strncpy(buf, s, count);
buf[count] = '\0';
c++;
 
if(end) *end = (char *)c;
 
if(inet_aton(buf, ip) == 1)
return RESULT_OK;
else
return RESULT_ERROR;
}
 
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[])
{
char *end;
int i;
long port;
 
memset(cfg, 0, sizeof(struct config));
 
for(i = 1; i < argc; i++) {
if(0 == strcmp(argv[i], PARAM_INTERFACE)) {
if(cfg->interface.s_addr)
return print_cmd_error(argc, argv, "Interface is already set", NULL);
 
if(++i < argc) {
if(parse_interface(argv[i], (char **)NULL, &cfg->interface) != RESULT_OK)
return print_cmd_error(argc, argv,
"Cannot parse interface", argv[i]);
}
else {
return print_cmd_error(argc, argv, "Interface expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_PORT)) {
if(cfg->port)
return print_cmd_error(argc, argv, "Port is already set", NULL);
 
if(++i < argc) {
port = strtol(argv[i], &end, 10);
if(*end != '\0' || port < PORT_MIN || port > PORT_MAX)
return print_cmd_error(argc, argv,
"Port number must be integer between 1 and 65535", NULL);
cfg->port = (ushort)port;
}
else {
return print_cmd_error(argc, argv, "Port number expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_CONFIG)) {
if(cfg->config_file[0] != '\0')
return print_cmd_error(argc, argv, "Config file name is already set", NULL);
 
if(++i < argc) {
strncpy(cfg->config_file, argv[i], FILENAME_MAX);
if(cfg->config_file[FILENAME_MAX - 1] != '\0')
return print_cmd_error(argc, argv,
"Config file name is too long", NULL);
}
else {
return print_cmd_error(argc, argv, "Config file name expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_PID_FILE)) {
if(cfg->pid_file[0] != '\0')
return print_cmd_error(argc, argv, "PID file name is already set", NULL);
 
if(++i < argc) {
strncpy(cfg->pid_file, argv[i], FILENAME_MAX);
if(cfg->pid_file[FILENAME_MAX - 1] != '\0')
return print_cmd_error(argc, argv,
"PID file name is too long", NULL);
}
else {
return print_cmd_error(argc, argv, "PID file name expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_DEBUG)) {
cfg->debug_mode = 1;
}
else if(0 == strcmp(argv[i], PARAM_VERSION)) {
print_version();
return RESULT_EXIT;
}
else if(0 == strcmp(argv[i], PARAM_HELP_1) || 0 == strcmp(argv[i], PARAM_HELP_2)) {
pring_usage(argc, argv);
return RESULT_EXIT;
}
else {
return print_cmd_error(argc, argv, "Unknown parameter", argv[i]);
}
}
 
return RESULT_OK;
}
 
static int validate_equal_sign(const char *config_name, const int count, const char *line,
uint name_len, char **subline)
{
const char *c;
 
c = line + name_len - 1;
if('=' != c[0] && !isspace(c[0]))
return print_config_error(config_name, count, "Unknown config parameter", line);
while(c[0] != '\0' && isspace(c[0])) c++;
if('=' != c[0])
return print_config_error(config_name, count, "Equal sign expected", NULL);
c++;
 
if(subline) *subline = (char *)c;
 
return RESULT_OK;
}
 
static int validate_eol(const char *config_name, const int count, const char *line)
{
while(line[0] != '\0' && isspace(line[0])) line++;
if('\0' != line[0] && '#' != line[0])
return print_config_error(config_name, count, "End of line expected", NULL);
 
return RESULT_OK;
}
 
static int extract_string_value(const char *config_name, const int count, char **subline, int must_quot,
char *string, uint len)
{
uint cur_len;
int quot;
 
while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
if('"' == *subline[0]) {
quot = 1;
(*subline)++;
}
else {
if(must_quot) {
return print_config_error(config_name, count, "Open quot expected", NULL);
}
else {
quot = 0;
/* skip spaces if not quoted */
while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
}
}
 
cur_len = 0;
while(*subline[0] != '\0')
{
if(cur_len >= len) return print_config_error(config_name, count, "Value too long", NULL);
if(quot && *subline[0] == '"') break;
if(!quot && isspace(*subline[0])) break;
 
string[0] = *subline[0];
string++;
(*subline)++;
cur_len++;
}
 
string[0] = '\0';
if(quot) {
if('"' != *subline[0])
return print_config_error(config_name, count, "Close quot expected", NULL);
(*subline)++;
}
 
return RESULT_OK;
}
 
static int parse_config_file(struct config *cfg, const char *config_name)
{
FILE *config_file;
char buf[MAX_CONFIG_LINE];
char *line;
char *subline;
int count;
uint len;
long port;
int res;
 
memset(cfg, 0, sizeof(struct config));
 
config_file = fopen(config_name, "r");
if(!config_file)
return print_error("Can not open config file", strerror(errno));
 
count = 0;
while(fgets(buf, sizeof(buf), config_file)) {
count++;
line = buf;
 
/* skip end spaces */
len = strlen(line);
if(len == MAX_CONFIG_LINE-1)
return print_config_error(config_name, count, "Line is too long", NULL);
while(len && isspace(line[len-1])) --len;
if(!len) continue;
line[len] = '\0';
 
/* skip begin spaces */
while(line[0] != '\0' && isspace(line[0])) line++;
 
if('#' == line[0]) { /* skip comment lines */
continue;
}
else if(strncmp(line, CONFIG_INTERFACE, min(sizeof(CONFIG_INTERFACE) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_INTERFACE), &subline)) != RESULT_OK) return res;
 
if(parse_interface(subline, &subline, &cfg->interface) != RESULT_OK)
return print_config_error(config_name, count,
"Cannot parse interface", NULL);
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else if(strncmp(line, CONFIG_PORT, min(sizeof(CONFIG_PORT) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line, sizeof(CONFIG_PORT),
&subline)) != RESULT_OK) return res;
 
port = strtol(subline, &subline, 10);
if(port < PORT_MIN || port > PORT_MAX)
return print_config_error(config_name, count,
"Port number must be integer between 1 and 65535", NULL);
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
cfg->port = (ushort)port;
}
else if(strncmp(line, CONFIG_PASSWORD, min(sizeof(CONFIG_PASSWORD) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_PASSWORD), &subline)) != RESULT_OK) return res;
 
if((res = extract_string_value(config_name, count, &subline, 1,
cfg->password, sizeof(cfg->password))) != RESULT_OK) return res;
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else if(strncmp(line, CONFIG_PID_FILE, min(sizeof(CONFIG_PID_FILE) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_PID_FILE), &subline)) != RESULT_OK) return res;
 
if((res = extract_string_value(config_name, count, &subline, 0,
cfg->pid_file, sizeof(cfg->pid_file))) != RESULT_OK) return res;
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else {
return print_config_error(config_name, count, "Unknown config parameter", line);
}
}
if(ferror(config_file)) {
print_error("Config file reading failed", strerror(errno));
}
 
if(fclose(config_file) != 0)
return print_error("Can not close config file", strerror(errno));
 
return RESULT_OK;
}
 
int read_config(struct config *cfg, int argc, const char* argv[])
{
int res_cmd_line;
int res_config_file;
struct config cmd_cfg;
struct config file_cfg;
 
memset(cfg, 0, sizeof(struct config));
res_cmd_line = parse_cmd_line(&cmd_cfg, argc, argv);
if(res_cmd_line != RESULT_OK) return res_cmd_line;
if(check_abs_path(cmd_cfg.config_file) != RESULT_OK) return RESULT_ERROR;
 
res_config_file = parse_config_file(&file_cfg,
cmd_cfg.config_file[0] != '\0' ? cmd_cfg.config_file : DEFAULT_CFG_FILE);
if(res_config_file != RESULT_OK) return res_config_file;
 
if(file_cfg.password[0] == '\0')
return print_error("Password is not set", NULL);
 
/* save parsed values to general config */
if(cmd_cfg.config_file[0] != '\0') {
strncpy(cfg->config_file, cmd_cfg.config_file, sizeof(cfg->config_file));
cfg->config_file_prio = CFG_PRIO_CMD;
}
else {
strncpy(cfg->config_file, DEFAULT_CFG_FILE, sizeof(cfg->config_file));
cfg->config_file_prio = CFG_PRIO_DEFAULT;
}
 
if(cmd_cfg.interface.s_addr) {
cfg->interface = cmd_cfg.interface;
cfg->interface_prio = CFG_PRIO_CMD;
}
else if(file_cfg.interface.s_addr) {
cfg->interface = file_cfg.interface;
cfg->interface_prio = CFG_PRIO_CONFIG;
}
else {
cfg->interface_prio = CFG_PRIO_DEFAULT;
}
 
if(cmd_cfg.port) {
cfg->port = cmd_cfg.port;
cfg->port_prio = CFG_PRIO_CMD;
}
else if(file_cfg.port) {
cfg->port = file_cfg.port;
cfg->port_prio = CFG_PRIO_CONFIG;
}
else {
cfg->port = DEFAULT_PORT;
cfg->port_prio = CFG_PRIO_DEFAULT;
}
 
if(cmd_cfg.pid_file[0] != '\0') {
strncpy(cfg->pid_file, cmd_cfg.pid_file, sizeof(cfg->pid_file));
cfg->pid_file_prio = CFG_PRIO_CMD;
}
else if(file_cfg.pid_file[0] != '\0') {
strncpy(cfg->pid_file, file_cfg.pid_file, sizeof(cfg->pid_file));
cfg->pid_file_prio = CFG_PRIO_CONFIG;
}
else {
cfg->pid_file_prio = CFG_PRIO_DEFAULT;
}
if(check_abs_path(cfg->config_file) != RESULT_OK) return RESULT_ERROR;
 
strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
cfg->password_prio = CFG_PRIO_CONFIG;
 
cfg->debug_mode = cmd_cfg.debug_mode;
 
return RESULT_OK;
}
 
int reread_config(struct config *cfg, int *reinit_needed)
{
int res_config_file;
struct config file_cfg;
 
*reinit_needed = 0;
 
res_config_file = parse_config_file(&file_cfg, cfg->config_file);
if(res_config_file != RESULT_OK) return res_config_file;
 
if(file_cfg.password[0] == '\0')
return print_error("Password is not set", NULL);
 
/* save parsed values to general config */
if(cfg->interface_prio >= CFG_PRIO_CONFIG && cfg->interface.s_addr != file_cfg.interface.s_addr)
{
*reinit_needed = 1;
cfg->interface = file_cfg.interface;
cfg->interface_prio = CFG_PRIO_CONFIG;
}
 
if(cfg->port_prio >= CFG_PRIO_CONFIG && cfg->port != file_cfg.port && file_cfg.port) {
*reinit_needed = 1;
cfg->port = file_cfg.port;
cfg->port_prio = CFG_PRIO_CONFIG;
}
 
if(check_abs_path(cfg->config_file) != RESULT_OK) return RESULT_ERROR;
 
strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
cfg->password_prio = CFG_PRIO_CONFIG;
 
return RESULT_OK;
}
 
/rebootd/trunk/src/signals.h
0,0 → 1,11
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#ifndef _REBOOTD_SIGNALS_H_
#define _REBOOTD_SIGNALS_H_
 
int init_signals(void);
 
#endif /* !_REBOOTD_SIGNALS_H_ */
 
/rebootd/trunk/src/network.c
0,0 → 1,68
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#include "common.h"
#include "rebootd.h"
#include "network.h"
 
int establish(const struct config *cfg)
{
int s;
struct sockaddr_in sa;
 
memset(&sa, 0, sizeof(struct sockaddr_in));
 
sa.sin_family = AF_INET;
sa.sin_port = htons(cfg->port);
sa.sin_addr.s_addr = (cfg->interface.s_addr ? cfg->interface.s_addr : INADDR_ANY);
 
if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
return -1;
 
if(bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
close(s);
return -1;
}
 
return s;
}
 
void listen_socket(const struct config *cfg, int soc)
{
char buf[BUFSIZE];
int br;
struct sockaddr_storage ss;
socklen_t ss_size;
 
for(;;) {
ss_size = sizeof(ss);
br = recvfrom(soc, buf, sizeof(buf)-1, 0, (struct sockaddr *)&ss, &ss_size);
 
if(br < 0) {
if(errno == EINTR) {
if(reconfig_required || quit_required) break;
}
else {
syslog(LOG_INFO, "cannot receive: %s", strerror(errno));
}
 
continue;
}
 
buf[br] = '\0';
sleep(1);
syslog(LOG_INFO, "got command");
handle_command(cfg, buf, sizeof(buf));
}
}
 
/rebootd/trunk/src/config.h
0,0 → 1,14
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#ifndef _REBOOTD_CONFIG_H_
#define _REBOOTD_CONFIG_H_
 
#include "common.h"
 
int read_config(struct config *cfg, int argc, const char* argv[]);
int reread_config(struct config *cfg, int *reinit_needed);
 
#endif /* !_REBOOTD_CONFIG_H_ */
 
/rebootd/trunk/src/Makefile
2,13 → 2,15
 
PROJ= rebootd
PROG= $(PROJ)
SRCS= rebootd.c
 
HEADERS= rebootd.h config.h signals.h network.h
SRCS= rebootd.c config.c signals.c network.c
 
VER_MAJOR= %VER_MAJOR%
VER_MINOR= %VER_MINOR%
VER_REVISION= %VER_REVISION%
 
$(PROG): $(SRCS)
$(PROG): $(HEADERS) $(SRCS)
cc -o $(PROG) \
-DVER_MAJOR=\"$(VER_MAJOR)\" -DVER_MINOR=\"$(VER_MINOR)\" -DVER_REVISION=\"$(VER_REVISION)\" \
$(SRCS)
/rebootd/trunk/src/common.h
0,0 → 1,71
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#ifndef _REBOOTD_H_
#define _REBOOTD_H_
 
#include <stdio.h>
#include <netinet/in.h>
 
/* project name */
#define APP_NAME "rebootd"
 
#define DEFAULT_PORT 19
#define DEFAULT_CFG_FILE "/etc/rebootd.conf"
#define CMDSIZE 4096
#define BUFSIZE 4096
#define MAX_CONFIG_LINE 4096
#define PORT_MIN 1
#define PORT_MAX 65535
 
/* return values of functions */
#define RESULT_OK 0
#define RESULT_EXIT 1
#define RESULT_ERROR 2
#define RESULT_UNEXPECTED 3
 
/* return values for the whole program */
#define EXIT_OK 0
#define EXIT_USER_ERROR 1
#define EXIT_UNEXPECTED 2
 
/* command line and config file parameters */
#define PARAM_HELP_1 "-h"
#define PARAM_HELP_2 "--help"
#define PARAM_VERSION "--version"
#define PARAM_INTERFACE "--interface"
#define PARAM_PORT "--port"
#define PARAM_CONFIG "--config"
#define PARAM_PID_FILE "--pid"
#define PARAM_DEBUG "--debug"
#define CONFIG_INTERFACE "interface"
#define CONFIG_PORT "port"
#define CONFIG_PASSWORD "password"
#define CONFIG_PID_FILE "pid"
 
/* priority of defferent sources of options */
#define CFG_PRIO_CMD 1
#define CFG_PRIO_CONFIG 2
#define CFG_PRIO_DEFAULT 3
 
struct config {
char config_file[FILENAME_MAX];
char config_file_prio;
struct in_addr interface;
char interface_prio;
ushort port;
char port_prio;
char password[MAX_CONFIG_LINE];
char password_prio;
char pid_file[FILENAME_MAX];
char pid_file_prio;
char debug_mode;
};
 
extern int daemonized; /* we are already a daemon */
extern volatile int reconfig_required; /* we have to stop socket listening and reread config */
extern volatile int quit_required; /* we have to stop socket listening and exit */
 
#endif /* !_REBOOTD_H_ */
 
/rebootd/trunk/src/rebootd.c
13,607 → 13,39
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>
#include <netdb.h>
#include <syslog.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/reboot.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
/* name version number */
#define APP_NAME "rebootd"
#include "common.h"
#include "rebootd.h"
#include "config.h"
#include "signals.h"
#include "network.h"
 
#define DEFAULT_PORT 19
#define DEFAULT_CFG_FILE "/etc/rebootd.conf"
#define CMDSIZE 4096
#define BUFSIZE 4096
#define MAX_CONFIG_LINE 4096
#define PORT_MIN 1
#define PORT_MAX 65535
int daemonized = 0; /* we are already a daemon */
volatile int reconfig_required = 0; /* we have to stop socket listening and reread config */
volatile int quit_required = 0; /* we have to stop socket listening and exit */
 
/* return values of functions */
#define RESULT_OK 0
#define RESULT_EXIT 1
#define RESULT_ERROR 2
#define RESULT_UNEXPECTED 3
 
/* return values for the whole program */
#define EXIT_OK 0
#define EXIT_USER_ERROR 1
#define EXIT_UNEXPECTED 2
 
/* command line and config file parameters */
#define PARAM_HELP_1 "-h"
#define PARAM_HELP_2 "--help"
#define PARAM_VERSION "--version"
#define PARAM_INTERFACE "--interface"
#define PARAM_PORT "--port"
#define PARAM_CONFIG "--config"
#define PARAM_PID_FILE "--pid"
#define PARAM_DEBUG "--debug"
#define CONFIG_INTERFACE "interface"
#define CONFIG_PORT "port"
#define CONFIG_PASSWORD "password"
#define CONFIG_PID_FILE "pid"
 
/* priority of defferent sources of options */
#define CFG_PRIO_CMD 1
#define CFG_PRIO_CONFIG 2
#define CFG_PRIO_DEFAULT 3
 
struct config {
char config_file[FILENAME_MAX];
char config_file_prio;
struct in_addr interface;
char interface_prio;
ushort port;
char port_prio;
char password[MAX_CONFIG_LINE];
char password_prio;
char pid_file[FILENAME_MAX];
char pid_file_prio;
char debug_mode;
};
static struct config global_cfg;
static int daemonized = 0; /* we are already a daemon */
volatile static int reconfig_required = 0; /* we have to stop socket listening and reread config */
volatile static int quit_required = 0; /* we have to stop socket listening and exit */
 
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[]);
static int parse_config_file(struct config *cfg, const char *config_name);
static void check_return(int res);
 
static uint min(uint a, uint b)
void handle_command(const struct config *cfg, const char *cmd, const int cmd_len)
{
return (a < b) ? a : b;
}
if(0 != strncmp(cmd, cfg->password, cmd_len)) return; /* wrong password */
 
static int establish(const struct config *cfg)
{
int s;
struct sockaddr_in sa;
 
memset(&sa, 0, sizeof(struct sockaddr_in));
 
sa.sin_family = AF_INET;
sa.sin_port = htons(cfg->port);
sa.sin_addr.s_addr = (cfg->interface.s_addr ? cfg->interface.s_addr : INADDR_ANY);
 
if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
return -1;
 
if(bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
close(s);
return -1;
if(cfg->debug_mode) {
syslog(LOG_INFO, "REBOOT, debug mode");
}
 
return s;
}
 
static void listen_socket(const struct config *cfg, int soc)
{
char buf[BUFSIZE];
int br;
struct sockaddr_storage ss;
socklen_t ss_size;
 
for(;;) {
ss_size = sizeof(ss);
br = recvfrom(soc, buf, sizeof(buf)-1, 0, (struct sockaddr *)&ss, &ss_size);
 
if(br < 0) {
if(errno == EINTR) {
if(reconfig_required || quit_required) break;
}
else {
syslog(LOG_INFO, "cannot receive: %s", strerror(errno));
}
 
continue;
}
 
buf[br] = '\0';
sleep(1);
syslog(LOG_INFO, "got command");
if(0 == strncmp(buf, cfg->password, sizeof(buf))) {
if(cfg->debug_mode) {
syslog(LOG_INFO, "REBOOT, debug mode");
}
else {
syslog(LOG_EMERG, "REBOOT");
sleep(5);
if(reboot(RB_AUTOBOOT) < 0) {
syslog(LOG_ERR, "cannot reboot, %s", strerror(errno));
}
}
}
}
}
 
static void print_version(void)
{
printf("%s %s.%s.%s\n", APP_NAME, VER_MAJOR, VER_MINOR, VER_REVISION);
}
 
static void pring_usage(int argc, const char* argv[])
{
print_version();
printf("\nA daemon which waits on specified UDP port for special");
printf(" string (password) and reboots the computer.\n\n");
printf("Usage: %s [--debug] [--interface IP] [--port PORT]\n", argv[0]);
printf(" [--config CONFIG_FILE] [--pid FILE]\n");
printf(" or: %s --version\n", argv[0]);
printf(" or: %s --help\n\n", argv[0]);
printf("Defaults are port 19, all interfaces, config /etc/rebootd.conf and no PID file.\n");
printf("In debug mode do not reboot, just write to log.\n\n");
printf("Config file looks like:\n--------------------------\n");
printf("interface=192.168.0.1\nport=19\npassword=\"some password\"\n");
printf("pid=/var/run/rebootd.pid\n--------------------------\n\n");
printf("Then run from any other host:\necho -n \"some password\" | nc -uo host_to_rebot 19\n");
}
 
static int print_error(const char *msg, const char *value)
{
if(daemonized) {
syslog(LOG_ERR, "%s", msg);
if(value) syslog(LOG_ERR, " - %s\n", value);
syslog(LOG_ERR, "\n");
}
else {
fprintf(stderr, "%s", msg);
if(value) fprintf(stderr, " - %s\n", value);
fprintf(stderr, "\n");
}
 
return RESULT_ERROR;
}
 
static int print_cmd_error(int argc, const char* argv[], const char *msg, const char *value)
{
fprintf(stderr, "%s", msg);
if(value) fprintf(stderr, " - %s\n", value);
fprintf(stderr, "\n");
 
pring_usage(argc, argv);
 
return RESULT_ERROR;
}
 
static int print_config_error(const char *config_name, int line, const char *msg, const char *value)
{
if(daemonized) {
syslog(LOG_ERR, "Error in %s, line %d: %s", config_name, line, msg);
if(value) syslog(LOG_ERR, " - %s", value);
syslog(LOG_ERR, "\n");
}
else {
fprintf(stderr, "Error in %s, line %d: %s", config_name, line, msg);
if(value) fprintf(stderr, " - %s", value);
fprintf(stderr, "\n");
}
 
return RESULT_ERROR;
}
 
static int check_abs_path(const char *file_name)
{
if(file_name && file_name[0] != '\0' && file_name[0] != '/') {
return print_error("File must have an absolute path", file_name);
}
 
return RESULT_OK;
}
 
static int read_config(struct config *cfg, int argc, const char* argv[])
{
int res_cmd_line;
int res_config_file;
struct config cmd_cfg;
struct config file_cfg;
 
memset(cfg, 0, sizeof(struct config));
res_cmd_line = parse_cmd_line(&cmd_cfg, argc, argv);
if(res_cmd_line != RESULT_OK) return res_cmd_line;
if(check_abs_path(cmd_cfg.config_file) != RESULT_OK) return RESULT_ERROR;
 
res_config_file = parse_config_file(&file_cfg,
cmd_cfg.config_file[0] != '\0' ? cmd_cfg.config_file : DEFAULT_CFG_FILE);
if(res_config_file != RESULT_OK) return res_config_file;
 
if(file_cfg.password[0] == '\0')
return print_error("Password is not set", NULL);
 
/* save parsed values to general config */
if(cmd_cfg.config_file[0] != '\0') {
strncpy(cfg->config_file, cmd_cfg.config_file, sizeof(cfg->config_file));
cfg->config_file_prio = CFG_PRIO_CMD;
}
else {
strncpy(cfg->config_file, DEFAULT_CFG_FILE, sizeof(cfg->config_file));
cfg->config_file_prio = CFG_PRIO_DEFAULT;
}
 
if(cmd_cfg.interface.s_addr) {
cfg->interface = cmd_cfg.interface;
cfg->interface_prio = CFG_PRIO_CMD;
}
else if(file_cfg.interface.s_addr) {
cfg->interface = file_cfg.interface;
cfg->interface_prio = CFG_PRIO_CONFIG;
}
else {
cfg->interface_prio = CFG_PRIO_DEFAULT;
}
 
if(cmd_cfg.port) {
cfg->port = cmd_cfg.port;
cfg->port_prio = CFG_PRIO_CMD;
}
else if(file_cfg.port) {
cfg->port = file_cfg.port;
cfg->port_prio = CFG_PRIO_CONFIG;
}
else {
cfg->port = DEFAULT_PORT;
cfg->port_prio = CFG_PRIO_DEFAULT;
}
 
if(cmd_cfg.pid_file[0] != '\0') {
strncpy(cfg->pid_file, cmd_cfg.pid_file, sizeof(cfg->pid_file));
cfg->pid_file_prio = CFG_PRIO_CMD;
}
else if(file_cfg.pid_file[0] != '\0') {
strncpy(cfg->pid_file, file_cfg.pid_file, sizeof(cfg->pid_file));
cfg->pid_file_prio = CFG_PRIO_CONFIG;
}
else {
cfg->pid_file_prio = CFG_PRIO_DEFAULT;
}
if(check_abs_path(cfg->config_file) != RESULT_OK) return RESULT_ERROR;
 
strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
cfg->password_prio = CFG_PRIO_CONFIG;
 
cfg->debug_mode = cmd_cfg.debug_mode;
 
return RESULT_OK;
}
 
static int reread_config(struct config *cfg, int *reinit_needed)
{
int res_config_file;
struct config file_cfg;
 
*reinit_needed = 0;
 
res_config_file = parse_config_file(&file_cfg, cfg->config_file);
if(res_config_file != RESULT_OK) return res_config_file;
 
if(file_cfg.password[0] == '\0')
return print_error("Password is not set", NULL);
 
/* save parsed values to general config */
if(cfg->interface_prio >= CFG_PRIO_CONFIG && cfg->interface.s_addr != file_cfg.interface.s_addr)
{
*reinit_needed = 1;
cfg->interface = file_cfg.interface;
cfg->interface_prio = CFG_PRIO_CONFIG;
}
 
if(cfg->port_prio >= CFG_PRIO_CONFIG && cfg->port != file_cfg.port && file_cfg.port) {
*reinit_needed = 1;
cfg->port = file_cfg.port;
cfg->port_prio = CFG_PRIO_CONFIG;
}
 
if(check_abs_path(cfg->config_file) != RESULT_OK) return RESULT_ERROR;
 
strncpy(cfg->password, file_cfg.password, sizeof(cfg->password));
cfg->password_prio = CFG_PRIO_CONFIG;
 
return RESULT_OK;
}
 
static int parse_interface(const char *s, char **end, struct in_addr *ip)
{
char buf[MAX_CONFIG_LINE];
int count;
const char *c;
 
c = s;
count = 0;
while(c[0] != '\0' && !isspace(c[0])) c++, count++;
if(count > MAX_CONFIG_LINE) return RESULT_ERROR;
strncpy(buf, s, count);
buf[count] = '\0';
c++;
 
if(end) *end = (char *)c;
 
if(inet_aton(buf, ip) == 1)
return RESULT_OK;
else
return RESULT_ERROR;
}
 
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[])
{
char *end;
int i;
long port;
 
memset(cfg, 0, sizeof(struct config));
 
for(i = 1; i < argc; i++) {
if(0 == strcmp(argv[i], PARAM_INTERFACE)) {
if(cfg->interface.s_addr)
return print_cmd_error(argc, argv, "Interface is already set", NULL);
 
if(++i < argc) {
if(parse_interface(argv[i], (char **)NULL, &cfg->interface) != RESULT_OK)
return print_cmd_error(argc, argv,
"Cannot parse interface", argv[i]);
}
else {
return print_cmd_error(argc, argv, "Interface expected", NULL);
}
syslog(LOG_EMERG, "REBOOT");
sleep(5);
if(reboot(RB_AUTOBOOT) < 0) {
syslog(LOG_ERR, "cannot reboot, %s", strerror(errno));
}
else if(0 == strcmp(argv[i], PARAM_PORT)) {
if(cfg->port)
return print_cmd_error(argc, argv, "Port is already set", NULL);
 
if(++i < argc) {
port = strtol(argv[i], &end, 10);
if(*end != '\0' || port < PORT_MIN || port > PORT_MAX)
return print_cmd_error(argc, argv,
"Port number must be integer between 1 and 65535", NULL);
cfg->port = (ushort)port;
}
else {
return print_cmd_error(argc, argv, "Port number expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_CONFIG)) {
if(cfg->config_file[0] != '\0')
return print_cmd_error(argc, argv, "Config file name is already set", NULL);
 
if(++i < argc) {
strncpy(cfg->config_file, argv[i], FILENAME_MAX);
if(cfg->config_file[FILENAME_MAX - 1] != '\0')
return print_cmd_error(argc, argv,
"Config file name is too long", NULL);
}
else {
return print_cmd_error(argc, argv, "Config file name expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_PID_FILE)) {
if(cfg->pid_file[0] != '\0')
return print_cmd_error(argc, argv, "PID file name is already set", NULL);
 
if(++i < argc) {
strncpy(cfg->pid_file, argv[i], FILENAME_MAX);
if(cfg->pid_file[FILENAME_MAX - 1] != '\0')
return print_cmd_error(argc, argv,
"PID file name is too long", NULL);
}
else {
return print_cmd_error(argc, argv, "PID file name expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_DEBUG)) {
cfg->debug_mode = 1;
}
else if(0 == strcmp(argv[i], PARAM_VERSION)) {
print_version();
return RESULT_EXIT;
}
else if(0 == strcmp(argv[i], PARAM_HELP_1) || 0 == strcmp(argv[i], PARAM_HELP_2)) {
pring_usage(argc, argv);
return RESULT_EXIT;
}
else {
return print_cmd_error(argc, argv, "Unknown parameter", argv[i]);
}
}
 
return RESULT_OK;
}
 
static int validate_equal_sign(const char *config_name, const int count, const char *line,
uint name_len, char **subline)
{
const char *c;
 
c = line + name_len - 1;
if('=' != c[0] && !isspace(c[0]))
return print_config_error(config_name, count, "Unknown config parameter", line);
while(c[0] != '\0' && isspace(c[0])) c++;
if('=' != c[0])
return print_config_error(config_name, count, "Equal sign expected", NULL);
c++;
 
if(subline) *subline = (char *)c;
 
return RESULT_OK;
}
 
static int validate_eol(const char *config_name, const int count, const char *line)
{
while(line[0] != '\0' && isspace(line[0])) line++;
if('\0' != line[0] && '#' != line[0])
return print_config_error(config_name, count, "End of line expected", NULL);
 
return RESULT_OK;
}
 
static int extract_string_value(const char *config_name, const int count, char **subline, int must_quot,
char *string, uint len)
{
uint cur_len;
int quot;
 
while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
if('"' == *subline[0]) {
quot = 1;
(*subline)++;
}
else {
if(must_quot) {
return print_config_error(config_name, count, "Open quot expected", NULL);
}
else {
quot = 0;
/* skip spaces if not quoted */
while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
}
}
 
cur_len = 0;
while(*subline[0] != '\0')
{
if(cur_len >= len) return print_config_error(config_name, count, "Value too long", NULL);
if(quot && *subline[0] == '"') break;
if(!quot && isspace(*subline[0])) break;
 
string[0] = *subline[0];
string++;
(*subline)++;
cur_len++;
}
 
string[0] = '\0';
if(quot) {
if('"' != *subline[0])
return print_config_error(config_name, count, "Close quot expected", NULL);
(*subline)++;
}
 
return RESULT_OK;
}
 
static int parse_config_file(struct config *cfg, const char *config_name)
{
FILE *config_file;
char buf[MAX_CONFIG_LINE];
char *line;
char *subline;
int count;
uint len;
long port;
int res;
 
memset(cfg, 0, sizeof(struct config));
 
config_file = fopen(config_name, "r");
if(!config_file)
return print_error("Can not open config file", strerror(errno));
 
count = 0;
while(fgets(buf, sizeof(buf), config_file)) {
count++;
line = buf;
 
/* skip end spaces */
len = strlen(line);
if(len == MAX_CONFIG_LINE-1)
return print_config_error(config_name, count, "Line is too long", NULL);
while(len && isspace(line[len-1])) --len;
if(!len) continue;
line[len] = '\0';
 
/* skip begin spaces */
while(line[0] != '\0' && isspace(line[0])) line++;
 
if('#' == line[0]) { /* skip comment lines */
continue;
}
else if(strncmp(line, CONFIG_INTERFACE, min(sizeof(CONFIG_INTERFACE) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_INTERFACE), &subline)) != RESULT_OK) return res;
 
if(parse_interface(subline, &subline, &cfg->interface) != RESULT_OK)
return print_config_error(config_name, count,
"Cannot parse interface", NULL);
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else if(strncmp(line, CONFIG_PORT, min(sizeof(CONFIG_PORT) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line, sizeof(CONFIG_PORT),
&subline)) != RESULT_OK) return res;
 
port = strtol(subline, &subline, 10);
if(port < PORT_MIN || port > PORT_MAX)
return print_config_error(config_name, count,
"Port number must be integer between 1 and 65535", NULL);
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
cfg->port = (ushort)port;
}
else if(strncmp(line, CONFIG_PASSWORD, min(sizeof(CONFIG_PASSWORD) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_PASSWORD), &subline)) != RESULT_OK) return res;
 
if((res = extract_string_value(config_name, count, &subline, 1,
cfg->password, sizeof(cfg->password))) != RESULT_OK) return res;
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else if(strncmp(line, CONFIG_PID_FILE, min(sizeof(CONFIG_PID_FILE) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_PID_FILE), &subline)) != RESULT_OK) return res;
 
if((res = extract_string_value(config_name, count, &subline, 0,
cfg->pid_file, sizeof(cfg->pid_file))) != RESULT_OK) return res;
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else {
return print_config_error(config_name, count, "Unknown config parameter", line);
}
}
if(ferror(config_file)) {
print_error("Config file reading failed", strerror(errno));
}
 
if(fclose(config_file) != 0)
return print_error("Can not close config file", strerror(errno));
 
return RESULT_OK;
}
 
static int save_pid(const char *pid_file, const pid_t pid)
{
int fd;
679,77 → 111,19
return RESULT_OK;
}
 
static void delete_pid_file(void)
static void delete_pid_file(const char *pid_file)
{
if(global_cfg.pid_file && global_cfg.pid_file[0] != '\0') {
if(unlink(global_cfg.pid_file) != 0) {
syslog(LOG_ERR, "Cannot delete PID file %s: %s\n",
global_cfg.pid_file, strerror(errno));
if(pid_file && pid_file[0] != '\0') {
if(unlink(pid_file) != 0) {
syslog(LOG_ERR, "Cannot delete PID file %s: %s\n", pid_file, strerror(errno));
}
}
}
 
static void reconfig_signal(void)
static void check_return(int res, const struct config *cfg)
{
syslog(LOG_INFO, "reconfig");
reconfig_required = 1;
}
 
static void quit_signal(void)
{
syslog(LOG_WARNING, "quit");
quit_required = 1;
}
 
static void signal_handler(int sig)
{
int saved_errno = errno;
 
switch(sig) {
case SIGHUP:
reconfig_signal();
break;
 
case SIGINT:
case SIGTERM:
case SIGQUIT:
quit_signal();
break;
}
 
errno = saved_errno;
}
 
static int init_signal_handler(int sig)
{
struct sigaction sa;
 
sa.sa_flags = 0;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
 
if(sigaction(sig, &sa, (struct sigaction *)NULL) != 0) {
syslog(LOG_ERR, "Cannot register handler for signal %d: %s\n", sig, strerror(errno));
return RESULT_UNEXPECTED;
}
 
return RESULT_OK;
}
 
static int init_signals(void)
{
if(init_signal_handler(SIGHUP) != RESULT_OK) return RESULT_UNEXPECTED;
if(init_signal_handler(SIGINT) != RESULT_OK) return RESULT_UNEXPECTED;
if(init_signal_handler(SIGTERM) != RESULT_OK) return RESULT_UNEXPECTED;
if(init_signal_handler(SIGQUIT) != RESULT_OK) return RESULT_UNEXPECTED;
 
return RESULT_OK;
}
 
static void check_return(int res)
{
if(daemonized && res != RESULT_OK) {
delete_pid_file();
delete_pid_file(cfg->pid_file);
syslog(LOG_WARNING, "quit");
}
 
762,20 → 136,21
 
int main(int argc, const char* argv[])
{
int soc;
int reinit_needed;
int soc;
int reinit_needed;
struct config cfg;
 
/* get config */
check_return(read_config(&global_cfg, argc, argv));
check_return(read_config(&cfg, argc, argv), &cfg);
 
/* try to listen the port */
if((soc = establish(&global_cfg)) < 0) {
fprintf(stderr, "Cannot listen to port %i\n", global_cfg.port);
if((soc = establish(&cfg)) < 0) {
fprintf(stderr, "Cannot listen to port %i\n", cfg.port);
return EXIT_USER_ERROR;
}
 
/* fork and release the console */
check_return(create_child(soc));
check_return(create_child(soc), &cfg);
 
/* continue as first child */
if(setsid() == -1) {
784,7 → 159,7
}
 
/* fork the second time */
check_return(create_child(soc));
check_return(create_child(soc), &cfg);
 
/* continue as final child */
if(init_signals() != RESULT_OK) return EXIT_UNEXPECTED;
794,7 → 169,7
return EXIT_UNEXPECTED;
}
umask(0);
check_return(save_pid(global_cfg.pid_file, getpid()));
check_return(save_pid(cfg.pid_file, getpid()), &cfg);
daemonized = 1;
 
/* from now do not use console for error output */
803,8 → 178,8
if(close_descr(2) != RESULT_OK) return EXIT_UNEXPECTED;
 
for(;;) {
syslog(LOG_INFO, "listen on %d", global_cfg.port);
listen_socket(&global_cfg, soc);
syslog(LOG_INFO, "listen on %d", cfg.port);
listen_socket(&cfg, soc);
 
if(quit_required) {
break;
811,19 → 186,19
}
else if(reconfig_required) {
reconfig_required = 0;
check_return(reread_config(&global_cfg, &reinit_needed));
check_return(reread_config(&cfg, &reinit_needed), &cfg);
if(reinit_needed) {
close(soc);
 
if((soc = establish(&global_cfg)) < 0) {
syslog(LOG_ERR, "Cannot listen to port %i\n", global_cfg.port);
check_return(RESULT_ERROR);
if((soc = establish(&cfg)) < 0) {
syslog(LOG_ERR, "Cannot listen to port %i\n", cfg.port);
check_return(RESULT_ERROR, &cfg);
}
}
}
}
 
delete_pid_file();
delete_pid_file(cfg.pid_file);
return EXIT_OK;
}
 
/rebootd/trunk/src/network.h
0,0 → 1,14
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#ifndef _REBOOTD_NETWORK_H_
#define _REBOOTD_NETWORK_H_
 
#include "config.h"
 
int establish(const struct config *cfg);
void listen_socket(const struct config *cfg, int soc);
 
#endif /* !_REBOOTD_NETWORK_H_ */
 
/rebootd/trunk/src/signals.c
0,0 → 1,80
/******************************************************************
* rebootd.
*
* A daemon which waits on specified UDP port for special string
* (password) and reboots the computer.
*
* Run "./rebootd --help" to see options and parameters.
*
* Copyleft 2005 Anatoli Klassen
*
******************************************************************/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <syslog.h>
 
#include "common.h"
#include "signals.h"
 
static void reconfig_signal(void)
{
syslog(LOG_INFO, "reconfig");
reconfig_required = 1;
}
 
static void quit_signal(void)
{
syslog(LOG_WARNING, "quit");
quit_required = 1;
}
 
static void signal_handler(int sig)
{
int saved_errno = errno;
 
switch(sig) {
case SIGHUP:
reconfig_signal();
break;
 
case SIGINT:
case SIGTERM:
case SIGQUIT:
quit_signal();
break;
}
 
errno = saved_errno;
}
 
static int init_signal_handler(int sig)
{
struct sigaction sa;
 
sa.sa_flags = 0;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
 
if(sigaction(sig, &sa, (struct sigaction *)NULL) != 0) {
syslog(LOG_ERR, "Cannot register handler for signal %d: %s\n", sig, strerror(errno));
return RESULT_UNEXPECTED;
}
 
return RESULT_OK;
}
 
int init_signals(void)
{
if(init_signal_handler(SIGHUP) != RESULT_OK) return RESULT_UNEXPECTED;
if(init_signal_handler(SIGINT) != RESULT_OK) return RESULT_UNEXPECTED;
if(init_signal_handler(SIGTERM) != RESULT_OK) return RESULT_UNEXPECTED;
if(init_signal_handler(SIGQUIT) != RESULT_OK) return RESULT_UNEXPECTED;
 
return RESULT_OK;
}
 
/rebootd/trunk/src/rebootd.h
0,0 → 1,13
/******************************************************************
* rebootd. Copyleft 2005 Anatoli Klassen
******************************************************************/
 
#ifndef _REBOOTD_MAIN_H_
#define _REBOOTD_MAIN_H_
 
#include "common.h"
 
void handle_command(const struct config *cfg, const char *cmd, const int cmd_len);
 
#endif /* !_REBOOTD_MAIN_H_ */