1
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
8.7 KiB
C

/*
* main.c: the daemon itself
*/
#include <unistd.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include "config.h"
#include "trie.h"
#include "task.h"
#include "daemonize.h"
#include "async.h"
enum resp {
SUCCESS, FAIL
};
void reg_sig_handlers(void);
bool process(int fd);
int sockfd; //async.h has to be able to use it, and I would hate to write a getter for that
int main (void) {
openlog(cfg_log_ident, cfg_log_opt, cfg_log_facility); //I will probably close its fd a moment later, FIXME
syslog(cfg_log_facility | LOG_INFO, "Starting");
// No arguments, if you want something, go change source, according to documentation.
// daemonize(0);
// Load saved state -- variable values and tasks
async_load(0);
// Set basic signal handlers
reg_sig_handlers();
// Setup a socket to listen on
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
socklen_t addrsize = sizeof(struct sockaddr_un);
addr.sun_family = AF_UNIX;
memcpy(&addr.sun_path, cfg_socket, strlen(cfg_socket)+1);
if(bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) {
syslog(cfg_log_facility | LOG_ERR, "daemon: bind failed: %m");
}
if(listen(sockfd, cfg_sock_maxclients) == -1) {
syslog(cfg_log_facility | LOG_ERR, "daemon: listen failed: %m");
}
// Everything prepared
syslog(cfg_log_facility | LOG_INFO, "Started");
// Main loop: (everything else is handled by process() and signal handlers).
while (true) {
int fd = accept(sockfd, (struct sockaddr *) &addr, &addrsize);
if (fd == -1) {
syslog(cfg_log_facility | LOG_ERR, "daemon: accept failed: %m");
while(1);
break;
} else {
syslog(cfg_log_facility | LOG_INFO, "daemon: accepted new connection");
process(fd);
}
}
syslog(cfg_log_facility | LOG_CRIT, "Escaped infinite loop!");
return 5;
}
uint64_t read_uint64(int fd) {
char buf[8];
read(fd, buf, 8);
uint64_t num = *(uint64_t *)buf;
return num;
}
bool write_uint64(uint64_t num, int fd) {
char *buf = &num;
write(fd, buf, 8);
return true; //TODO: error handling
}
char *read_string(int fd) {
char *buf;
struct grow *tmp = grow_init(true);
do {
buf = malloc(1);
if(buf == NULL) {
syslog(cfg_log_facility | LOG_ERR, "cannot malloc memory for a letter: %m");
grow_drop(tmp);
return NULL;
}
read(fd, buf, 1);
grow_push(buf, tmp);
} while (buf[0] != '\0');
char *str = malloc(tmp->elems * sizeof(char));
if (str == NULL) {
syslog(cfg_log_facility | LOG_ERR, "cannot malloc memory for string: %m");
grow_drop(tmp);
return NULL;
}
for (uint64_t j = 0; j < tmp -> elems; j++) {
str[j] = *(char *)(tmp->arr[j]);
}
grow_drop(tmp);
syslog(cfg_log_facility | LOG_DEBUG, "daemon: read_string: returning '%s'", str);
return str;
}
bool write_string (char *str, int fd) {
int len = strlen(str)+1;
write(fd, str, len);
return true; // TODO: error handling
}
void response(enum resp r, int fd) {
if (r==SUCCESS) {
char str[] = "OK";
write(fd, str, 2);
} else {
char str[] = "KO";
write(fd, str, 2);
}
return;
}
bool process(int fd) {
char cmd[5];
read(fd, cmd, 4);
cmd[4] = '\0';
if (0){ //alignment
return true;
} else if (strcmp(cmd, "TADD") == 0) {
struct task *t = task_read(fd);
if (t == NULL) { // We do not handle errors here, they are already logged
response(FAIL,fd);
return false;
}
if(task_add(*t)) {
response(SUCCESS,fd);
return true;
} else {
response(FAIL,fd);
return false;
}
} else if (strcmp(cmd, "TDEL") == 0) {
uint64_t id = read_uint64(fd);
if(task_delete(id)) {
response(SUCCESS,fd);
return true;
} else {
response(FAIL,fd);
return false;
}
} else if (strcmp(cmd, "TENA") == 0) {
uint64_t id = read_uint64(fd);
if(task_enable(id)) {
response(SUCCESS,fd);
return true;
} else {
response(FAIL,fd);
return false;
}
} else if (strcmp(cmd, "TDIS") == 0) {
uint64_t id = read_uint64(fd);
if(task_disable(id)) {
response(SUCCESS,fd);
return true;
} else {
response(FAIL,fd);
return false;
}
} else if (strcmp(cmd, "TDET") == 0) {
uint64_t id = read_uint64(fd);
struct task t = task_details(id);
response(SUCCESS, fd);
return task_write(t, fd);
} else if (strcmp(cmd, "TLST") == 0) {
bool retval = true;
struct grow *lst = task_list();
if (lst == NULL) {
response(SUCCESS, fd);
retval &= write_uint64(0, fd);
} else {
response(SUCCESS,fd);
retval &= write_uint64(lst->active_elems, fd);
for (uint64_t i = 0; i < lst->elems; i++) {
if (lst->arr[i] == NULL) {
continue;
} else {
struct task t = *(struct task *)lst->arr[i];
retval &= task_write(t, fd);
}
}
}
return retval;
} else if (strcmp(cmd, "VADD") == 0) {
int64_t val = (int64_t) read_uint64(fd);
char *str = read_string(fd);
if(trie_set(str, val)) {
response(SUCCESS, fd);
return true;
} else {
response(FAIL, fd);
return false;
}
} else if (strcmp(cmd, "VSET") == 0) {
int64_t val = (int64_t) read_uint64(fd);
char *str = read_string(fd);
if(trie_set(str, val)) {
response(SUCCESS, fd);
return true;
} else {
response(FAIL, fd);
return false;
}
} else if (strcmp(cmd, "VDEL") == 0) {
char *str = read_string(fd);
if(trie_unset(str)) {
response(SUCCESS, fd);
return true;
} else {
response(FAIL, fd);
return false;
}
} else if (strcmp(cmd, "VLST") == 0) {
bool retval = true;
struct grow *lst = trie_list();
if (lst == NULL) {
response(SUCCESS, fd);
retval &= write_uint64(0, fd);
return retval;
}
response(SUCCESS, fd);
retval &= write_uint64(lst->elems, fd);
for (uint64_t i = 0; i < lst->elems; i++) {
struct trie_list item = *(struct trie_list *)lst->arr[i];
retval &= write_uint64(item.val, fd);
retval &= write_string(item.name, fd);
}
return retval;
} else if (strcmp(cmd, "VDET") == 0) {
char *name = read_string(fd);
if (name == NULL) {
response(FAIL, fd);
return false;
}
struct trie_retval var = trie_lookup(name);
response(SUCCESS, fd);
write(fd, &var, sizeof(struct trie_retval));
if (var.tasks == NULL) {
write_uint64(0, fd);
return true;
}
write_uint64(var.tasks->active_elems, fd);
for(uint64_t i = 0; i< var.tasks->elems; i++) {
if(var.tasks->arr[i] == NULL) {
continue;
} else {
uint64_t task = *(uint64_t *)var.tasks->arr[i];
write_uint64(task, fd);
}
}
return true; // TODO: error handling!!
} else if (strcmp(cmd, "QUIT") == 0) {
response(SUCCESS, fd);
async_shutdown(0);
return true;
} else if (strcmp(cmd, "REST") == 0) {
response(SUCCESS, fd);
async_restart(0);
return true;
} else if (strcmp(cmd, "SAVE") == 0) {
response(SUCCESS, fd);
async_save(0);
return true;
} else if (strcmp(cmd, "FLSH") == 0) {
char *safe = calloc(1+strlen(cfg_safe_string), sizeof(char));
read(fd, safe, strlen(cfg_safe_string));
if (strcmp(safe, cfg_safe_string) == 0) {
response(SUCCESS, fd);
async_flush(0);
return true;
} else {
response(FAIL, fd);
return false;
}
} else if (strcmp(cmd, "LOAD") == 0) {
char *safe = calloc(1+strlen(cfg_safe_string), sizeof(char));
read(fd, safe, strlen(cfg_safe_string));
if (strcmp(safe, cfg_safe_string) == 0) {
response(SUCCESS, fd);
async_load(0);
return true;
} else {
response(FAIL, fd);
return false;
}
} else if (strcmp(cmd, "KILL") == 0) {
char *safe = calloc(1+strlen(cfg_safe_string), sizeof(char));
read(fd, safe, strlen(cfg_safe_string));
if (strcmp(safe, cfg_safe_string) == 0) {
response(SUCCESS, fd);
async_kill(0);
return true;
} else {
response(FAIL, fd);
return false;
}
} else {
syslog(cfg_log_facility | LOG_NOTICE, "Unknown command: %s (0x%02X%02X%02X%02X)", cmd, cmd[0], cmd[1], cmd[2], cmd[3]);
char str[] = "KO";
write(fd, str, 2);
response(FAIL,fd);
return false;
}
}
void reg_sig_handlers(void) {
sigset_t empty;
sigemptyset(&empty); // Shall not fail
//SIGTERM
struct sigaction term_sigh;
term_sigh.sa_handler = &async_shutdown;
term_sigh.sa_mask = empty;
term_sigh.sa_flags = 0;
sigaction(SIGTERM, &term_sigh, NULL);
//SIGCHLD
struct sigaction chld_sigh;
chld_sigh.sa_handler = SIG_IGN; // We don't care for children
chld_sigh.sa_mask = empty;
chld_sigh.sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD, &chld_sigh, NULL);
//SIGHUP
struct sigaction hup_sigh;
hup_sigh.sa_handler = &async_restart;
hup_sigh.sa_mask = empty;
hup_sigh.sa_flags = 0;
sigaction(SIGHUP, &hup_sigh, NULL);
//SIGINT
struct sigaction int_sigh;
int_sigh.sa_handler = &async_save;
int_sigh.sa_mask = empty;
int_sigh.sa_flags = 0;
sigaction(SIGINT, &int_sigh, NULL);
//SIGALRM
struct sigaction alrm_sigh;
alrm_sigh.sa_sigaction = &async_run;
alrm_sigh.sa_mask = empty;
alrm_sigh.sa_flags = SA_SIGINFO;
sigaction(SIGALRM, &alrm_sigh, NULL);
}