1
0
Fork 0

Finished the daemon

master
LEdoian 7 years ago
parent 8b22467e34
commit 5a26e21e05

@ -0,0 +1,90 @@
/*
* async.c - functions to be called asynchronously (in signal handlers)
* also functions for non-standard operations over whole daemon
*/
#include <stdint.h>
#include <syslog.h>
#include <unistd.h>
#include "async.h"
#include "task.h"
#include "trie.h"
#include "config.h"
extern int sockfd; //in daemon.c
void async_kill(int sig) {
syslog(cfg_log_facility | LOG_INFO, "Stopping");
exit(0);
return;
}
void async_shutdown (int sig) {
async_save(sig);
close(sockfd);
if(unlink(cfg_socket) == -1){
syslog(cfg_log_facility | LOG_ERR, "async: unlink failed: %m");
}
async_kill(sig);
return;
}
void async_save(int sig) {
task_save(cfg_task_file);
trie_save(cfg_trie_file);
return;
}
void async_flush(int sig) {
task_flush();
trie_flush();
return;
}
void async_load (int sig) {
task_load(cfg_task_file);
trie_load(cfg_trie_file);
return;
}
void async_restart (int sig) {
async_save(sig);
async_flush(sig);
async_load(sig);
}
void async_run (int sig, siginfo_t *info, void *unused) {
if (info == NULL) {
syslog(cfg_log_facility | LOG_ERR, "async: someone is kidding us, we will kid them back and do nothing");
return;
}
uint64_t *p_id = (info -> si_value).sival_ptr;
if (p_id == NULL) {
syslog(cfg_log_facility | LOG_ERR, "async: someone is kidding us again, we will kid them back and do nothing");
return;
}
struct task t = task_details(*p_id);
// And now run it
// First, fork
pid_t pid = fork();
if (pid == -1) {
syslog(cfg_log_facility | LOG_ERR, "async: cannot fork: %m");
return;
}
else if (pid > 0) {
//We said in daemon.h that we don't care for children
return;
}
else if (pid == 0) {
// Reset signal handler for SIGCHLD (other signals are defined by us and will be reset during exec()
struct sigaction siga;
siga.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &siga, NULL);
// Exec
execvp(t.argv[0], t.argv);
syslog(cfg_log_facility | LOG_ERR, "async: cannot exec: %m");
return;
}
}

@ -0,0 +1,17 @@
/*
* async.h - declaration of functions in async.c
*/
#ifndef ASYNC_H
#define ASYNC_H
#include <signal.h>
void async_kill(int sig);
void async_shutdown (int sig);
void async_save(int sig);
void async_flush(int sig);
void async_load (int sig);
void async_restart (int sig);
void async_run (int sig, siginfo_t *info, void *unused);
#endif

@ -0,0 +1,31 @@
/*
* config.h: compilation config file
* Edit as needed.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <stdint.h>
#include <signal.h>
#include <time.h>
#include <syslog.h>
const int cfg_log_facility = LOG_CRON;
const char cfg_log_ident[] = "kairos";
const int cfg_log_opt = LOG_PID | LOG_NDELAY;
const char cfg_trie_file[] = "/home/ledoian/.kairos/trie";
const char cfg_task_file[] = "/home/ledoian/.kairos/tasks";
const char cfg_socket[] = "/tmp/kairos.sock";
const uint32_t cfg_sock_maxclients = 16;
const uint64_t cfg_var_name_max_len = 16;
const clockid_t cfg_clockid = CLOCK_REALTIME; // select CLOCK_REALTIME_ALARM
// for waking system from suspend;
// requires CAP_WAKE_ALARM
const char cfg_safe_string[] = "Sure";
#endif

@ -7,16 +7,21 @@
#define CONFIG_H #define CONFIG_H
#include <stdint.h> #include <stdint.h>
#include <time.h>
const int cfg_log_facility = LOG_CRON; extern const int cfg_log_facility;
const char cfg_log_ident[] = "kairos"; extern const char cfg_log_ident[];
const int cfg_log_opt = LOG_PID | LOG_NDELAY; extern const int cfg_log_opt;
const char cfg_trie_file[] = "/home/ledoian/.kairos/trie"; extern const char cfg_trie_file[];
const char cfg_task_file[] = "/home/ledoian/.kairos/tasks"; extern const char cfg_task_file[];
const char cfg_socket[] = "/tmp/kairos.sock"; extern const char cfg_socket[];
const uint32_t cfg_sock_maxclients = 16; extern const uint32_t cfg_sock_maxclients;
const uint64_t cfg_var_name_max_len = 16; extern const uint64_t cfg_var_name_max_len;
extern const clockid_t cfg_clockid;
extern const char cfg_safe_string[];
#endif #endif

@ -15,11 +15,16 @@
#include "trie.h" #include "trie.h"
#include "task.h" #include "task.h"
#include "daemonize.h" #include "daemonize.h"
#include "async.h"
void term_handle(int sigval); enum resp {
SUCCESS, FAIL
};
void reg_sig_handlers(void);
bool process(int fd); bool process(int fd);
static int sockfd; int sockfd; //async.h has to be able to use it, and I would hate to write a getter for that
int main (void) { int main (void) {
openlog(cfg_log_ident, cfg_log_opt, cfg_log_facility); //I will probably close its fd a moment later, FIXME openlog(cfg_log_ident, cfg_log_opt, cfg_log_facility); //I will probably close its fd a moment later, FIXME
@ -27,30 +32,17 @@ int main (void) {
daemonize(0); daemonize(0);
// Load saved state -- variable values and tasks // Load saved state -- variable values and tasks
trie_load(cfg_trie_file); async_load(0);
task_load(cfg_task_file);
// Set basic signal handlers // Set basic signal handlers
sigset_t empty; reg_sig_handlers();
sigemptyset(&empty); // Shall not fail
struct sigaction *term_sigh = (struct sigaction *) malloc(sizeof(struct sigaction));
term_sigh -> sa_handler = &term_handle;
term_sigh -> sa_mask = empty;
term_sigh -> sa_flags = 0;
sigaction(SIGTERM, term_sigh, NULL);
struct sigaction *chld_sigh = (struct sigaction *) malloc(sizeof(struct sigaction));
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);
// Setup a socket to listen on // Setup a socket to listen on
sockfd = socket(AF_UNIX, SOCK_STREAM, 0); sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr; struct sockaddr_un addr;
socklen_t addrsize = sizeof(struct sockaddr_un); socklen_t addrsize = sizeof(struct sockaddr_un);
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
memcpy(&addr.sun_path, cfg_socket, strlen(cfg_socket)); memcpy(&addr.sun_path, cfg_socket, strlen(cfg_socket)+1);
bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)); bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
listen(sockfd, cfg_sock_maxclients); listen(sockfd, cfg_sock_maxclients);
@ -67,13 +59,284 @@ int main (void) {
return 5; return 5;
} }
void term_handle (int signum) { uint64_t read_uint64(int fd) {
trie_save(cfg_trie_file); char buf[8];
task_save(cfg_task_file); read(fd, buf, 8);
close(sockfd); uint64_t num = *(uint64_t *)buf;
unlink(cfg_socket); return num;
exit(0); }
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[1];
struct grow *tmp = grow_init(true);
do {
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");
return NULL;
}
for (uint64_t j = 0; j < tmp -> elems; j++) {
str[j] = *(char *)(tmp->arr[j]);
}
grow_drop(tmp);
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; return;
} }
bool process(int fd) {} 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 = read_string(fd);
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 = read_string(fd);
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 = read_string(fd);
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);
}

291
task.c

@ -5,16 +5,40 @@
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include "task.h" #include "task.h"
#include "grow.h" #include "grow.h"
#include "async.h" #include "config.h"
#include "rpn.h"
static struct grow *tasks = NULL; static struct grow *tasks = NULL;
static struct itimerspec task_update_times(struct itimerspec times) {
times.it_interval.tv_nsec = times.it_value.tv_nsec = 0; // We are only precise to a second
struct timespec cur_time;
if(clock_gettime(cfg_clockid, &cur_time) == -1) {
syslog(cfg_log_facility | LOG_WARNING, "task: clock_gettime failed: %m");
syslog(cfg_log_facility | LOG_NOTICE, "task: not updating time, weird things may happen");
} else {
time_t modulo = times.it_value.tv_sec % times.it_interval.tv_sec;
if (cur_time.tv_nsec >= 500000000) cur_time.tv_sec++; //round
time_t current_modulo = cur_time.tv_sec % times.it_interval.tv_sec;
if (modulo < current_modulo) modulo += times.it_interval.tv_sec;
times.it_value.tv_sec = cur_time.tv_sec + (modulo - current_modulo); //Nearest future moment of running
}
return times;
}
bool task_add(struct task t) { bool task_add(struct task t) {
// struct task t = task_convert(ts);
bool retval = true; bool retval = true;
t.times = task_update_times(t.times);
struct task *p_t = malloc(sizeof(struct task)); struct task *p_t = malloc(sizeof(struct task));
if(p_t == NULL) { if(p_t == NULL) {
syslog(cfg_log_facility | LOG_ERR, "task: could not allocate space for task: %m"); syslog(cfg_log_facility | LOG_ERR, "task: could not allocate space for task: %m");
@ -22,26 +46,267 @@ bool task_add(struct task t) {
} }
*p_t = t; *p_t = t;
if (tasks == NULL) { if (tasks == NULL) {
tasks = grow_init(true); tasks = grow_init(false); //We will have to clear for ourself, cannot do automatically without mem leak.
if (tasks == NULL) { if (tasks == NULL) {
return false; return false;
} }
// Task number 0 is reserved (for errors)
retval &= grow_push(NULL, tasks);
}
t.id = tasks -> elems; // This relies on implementation detail of our growing array.
if (t.when == VARCHG) {
t.run = rpn_eval_assoc(t.formula, t.id);
} }
uint64_t id = tasks -> elems; // This relies on implementation detail of our growing array.
retval &= grow_push(p_t, tasks); retval &= grow_push(p_t, tasks);
// Create a timer for the task // Create a timer for the task
// store timerid in ((struct task *)(tasks -> arr[id])) -> timerid // store timerid in ((struct task *)(tasks -> arr[t.id])) -> timerid
struct sigevent evp;
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGALRM;
evp.sigev_value.sival_ptr = tasks -> arr[t.id];
if(timer_create(cfg_clockid, &evp, &(((struct task *)(tasks -> arr[t.id])) -> timerid)) == -1){
syslog(cfg_log_facility | LOG_ERR, "task: could not create timer for task %ld: %m", t.id);
return false;
}
// Arm the timer
if (t.enabled) {
if (timer_settime(t.timerid, TIMER_ABSTIME, &t.times, NULL) == -1) {
syslog(cfg_log_facility | LOG_ERR, "task: could not arm timer for task %ld: %m", t.id);
return false;
}
}
return retval;
} }
bool task_disable(uint64_t id); bool task_disable(uint64_t id) {
bool task_enable(uint64_t id); if (id >= tasks->elems) {
bool task_delete(uint64_t id); syslog(cfg_log_facility | LOG_WARNING, "task: attempt to disable non-existent task: %ld", id);
return false;
}
struct task *t =(struct task *) tasks->arr[id];
if (t == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to disable non-existent task: %ld", id);
return false;
}
t -> enabled = false;
return true;
}
bool task_enable(uint64_t id) {
if (id >= tasks->elems) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to enable non-existent task: %ld", id);
return false;
}
struct task *t =(struct task *) tasks->arr[id];
if (t == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to enable non-existent task: %ld", id);
return false;
}
t -> enabled = true;
return true;
}
struct grow *task_list(void); bool task_delete(uint64_t id) {
struct task task_details(uint64_t id); if (id >= tasks->elems) {
void task_recalc(uint64_t id); syslog(cfg_log_facility | LOG_NOTICE, "task: attempt to delete non-existent task: %ld", id);
return true;
}
struct task *t =(struct task *) tasks->arr[id];
if (t == NULL) {
syslog(cfg_log_facility | LOG_NOTICE, "task: attempt to delete non-existent task: %ld", id);
return true;
}
//disarm
timer_delete(t->timerid); //if it fails, it means the timer didn't exist
//.argv**
for (int i = 0; t->argv[i] != NULL; i++){
free(t->argv[i]);
}
free(t->argv);
// unassociate
if (t->when == VARCHG) {
rpn_eval_unassoc(t->formula, t->id);
}
//.formula
free(t->formula);
//task
free(t);
// delete from list
tasks -> active_elems--;
tasks -> arr[id] = NULL;
return true;
}
struct grow *task_list(void) {
return tasks;
}
struct task task_details(uint64_t id) {
if (id >= tasks -> elems) {
struct task t;
t.id = 0; //error task
return t;
}
if (tasks->arr[id] != NULL) {
return *(struct task *)(tasks -> arr[id]);
} else {
struct task t;
t.id = 0; //error task
return t;
}
}
bool task_load(void); bool task_recalc(uint64_t id) {
bool task_save(void); if (id >= tasks -> elems) {
void task_flush(void); syslog(cfg_log_facility | LOG_WARNING, "task: attempt to recalculate non-existent task: %ld", id);
return false;
}
if (tasks -> arr[id] == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to recalculate non-existent task: %ld", id);
return false;
}
if (((struct task *)(tasks -> arr[id])) -> when != VARCHG) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to recalculate task which is not precalculated: %ld", id);
return false;
}
((struct task *)(tasks -> arr[id])) -> run = rpn_eval(((struct task *)(tasks -> arr[id])) -> formula);
return true;
}
bool task_write(struct task t, int fd) {
bool retval = true;
if(write(fd, &t, sizeof(struct task)) == -1) {
syslog(cfg_log_facility | LOG_ERR, "task: could not write() task: %m");
return false;
}
for (int i = 0; i < t.argc; i++) {
if (t.argv[i] == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to write malformed task");
char emptystring = '\0';
write(fd, &emptystring, 1); //If there actually was some logic to it.
retval = false;
} else {
int len = strlen(t.argv[i]) + 1;
if(write(fd, t.argv[i], len) == -1) {
syslog(cfg_log_facility | LOG_ERR, "task: write() failed: %m");
retval = false;
}
}
}
if (t.formula == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "task: attempt to write malformed formula");
char emptystring = '\0';
write(fd, &emptystring, 1); //If there actually was some logic to it.
retval = false;
} else {
int len = strlen(t.formula) + 1;
if(write(fd, t.formula, len) == -1) {
syslog(cfg_log_facility | LOG_ERR, "task: write() failed: %m");
retval = false;
}
}
return retval;
}
struct task *task_read(int fd) {
struct task *t = malloc(sizeof(struct task));
if (t == NULL) {
syslog(cfg_log_facility | LOG_ERR, "task: cannot malloc memory for a task: %m");
return NULL;
}
errno = 0;
ssize_t readbytes;
readbytes = read(fd, t, sizeof(struct task));
if (readbytes < (ssize_t)sizeof(struct task)) {
syslog(cfg_log_facility | LOG_ERR, "task: unexpected EOF when reading task (or error: %m)");
return NULL;
}
t->argv = malloc((t->argc + 1) * sizeof(char *));
if (t->argv == NULL) {
syslog(cfg_log_facility | LOG_ERR, "task: cannot malloc memory for task arguments: %m");
return NULL;
}
t->argv[t->argc+1] = NULL; //for execvp()
for (int i = 0; i < t->argc; i++) {
// This should be done in some more clever way
char buf[1];
struct grow *tmp = grow_init(true);
do {
read(fd, buf, 1);
grow_push(buf, tmp);
} while (buf[0] != '\0');
t->argv[i] = malloc(tmp->elems * sizeof(char));
if (t->argv[i] == NULL) {
syslog(cfg_log_facility | LOG_ERR, "task: cannot malloc memory for task argument: %m");
return NULL;
}
for (uint64_t j = 0; j < tmp -> elems; j++) {
t->argv[i][j] = *(char *)(tmp->arr[j]);
}
grow_drop(tmp);
}
// and one more time for the formula
char buf[1];
struct grow *tmp = grow_init(true);
do {
read(fd, buf, 1);
grow_push(buf, tmp);
} while (buf[0] != '\0');
t->formula = malloc(tmp->elems * sizeof(char));
if (t->formula == NULL) {
syslog(cfg_log_facility | LOG_ERR, "task: cannot malloc memory for task formula: %m");
return NULL;
}
for (uint64_t j = 0; j < tmp -> elems; j++) {
t->formula[j] = *(char *)(tmp->arr[j]);
}
grow_drop(tmp);
return t;
}
bool task_load(const char fn[]) {
bool retval = true;
int fd = open(fn, O_RDONLY);
if (fd == -1) {
syslog(cfg_log_facility | LOG_WARNING, "task: could not load tasks from file: %m");
return false;
}
struct task *t;
while ((t = task_read(fd)) != NULL) {
task_add(*t);
}
close(fd);
return retval;
}
bool task_save(const char fn[]) {
bool retval = true;
int fd = open(fn, O_CREAT | O_WRONLY | O_TRUNC);
if (fd == -1) {
syslog(cfg_log_facility | LOG_WARNING, "trie: could not save tasks to file: %m");
return false;
}
for (uint64_t i = 0; i < tasks -> elems; i++) {
if (tasks -> arr[i] == NULL) continue;
struct task t = *(struct task *)(tasks->arr[i]);
retval &= task_write(t, fd);
}
close(fd);
return retval;
}
void task_flush(void) {
for (uint64_t i = 0; i < tasks->elems; i++) {
free(((struct task *)(tasks->arr[i]))->formula);
for (int j = 0; ((struct task *)(tasks->arr[i]))->argv[j] != NULL; j++) {
free(((struct task *)(tasks->arr[i]))->argv[j]);
}
free(((struct task *)(tasks->arr[i]))->argv);
free(tasks->arr[i]);
}
grow_drop(tasks);
tasks = NULL;
return;
}

@ -15,17 +15,20 @@ enum task_check { // whether to check formula in signal handler or when variable
}; };
struct task { struct task {
uint64_t id;
// Time info // Time info
struct itimerspec times; struct itimerspec times;
timer_t timerid; timer_t timerid;
// Command to run // Command to run
int argc; // count of elements in argv 'true' has 1, 'echo Lorem Ipsum' has 3, 'echo Lorem\ ipsum' has 2.
char **argv; //NULL terminated list of NUL terminated strings char **argv; //NULL terminated list of NUL terminated strings
// Formula to be checked when running // Formula to be checked when running
char *formula; // in RPN, NUL terminated char *formula; // in RPN, NUL terminated
enum task_check when; enum task_check when;
bool run; // dynamic programming bool run; // whether to run task in case of when == VARCHG
// Disabling/enabling // Disabling/enabling
bool enabled; bool enabled;
@ -38,10 +41,13 @@ bool task_delete(uint64_t id);
struct grow *task_list(void); struct grow *task_list(void);
struct task task_details(uint64_t id); struct task task_details(uint64_t id);
void task_recalc(uint64_t id); bool task_recalc(uint64_t id);
bool task_write(struct task t, int fd);
struct task *task_read(int fd);
bool task_load(void); bool task_load(const char fn[]);
bool task_save(void); bool task_save(const char fn[]);
void task_flush(void); void task_flush(void);
#endif #endif

@ -125,6 +125,7 @@ struct trie_retval trie_lookup(char string[]) {
} }
bool trie_load(const char fn[]) { bool trie_load(const char fn[]) {
bool retval;
FILE *f = fopen(fn, "r"); FILE *f = fopen(fn, "r");
if (f == NULL) { if (f == NULL) {
syslog(cfg_log_facility | LOG_WARNING, "trie: could not load trie from file: %m"); syslog(cfg_log_facility | LOG_WARNING, "trie: could not load trie from file: %m");
@ -138,13 +139,15 @@ bool trie_load(const char fn[]) {
while ((status = fscanf(f, "%s %ld\n", name, &val)) != EOF) { while ((status = fscanf(f, "%s %ld\n", name, &val)) != EOF) {
if (status != 2) { if (status != 2) {
syslog(cfg_log_facility | LOG_ERR, "trie: fscanf matched bad number of items: %d", status); syslog(cfg_log_facility | LOG_ERR, "trie: fscanf matched bad number of items: %d", status);
return false; retval = false;
} }
if(trie_set(name, val) == false) { if(trie_set(name, val) == false) {
syslog(cfg_log_facility | LOG_WARNING, "trie: setting a variable failed: %s = %ld", name, val); syslog(cfg_log_facility | LOG_WARNING, "trie: setting a variable failed: %s = %ld", name, val);
retval = false;
} }
} }
return true; fclose(f);
return retval;
} }
static bool trie_dfs(char prefix[], uint64_t prefixlen, struct grow *list, struct trie *vertex, enum dfs_list style) { static bool trie_dfs(char prefix[], uint64_t prefixlen, struct grow *list, struct trie *vertex, enum dfs_list style) {
@ -204,6 +207,7 @@ bool trie_save(const char fn[]) {
fprintf(f, "%s %ld\n", l.name, l.val); fprintf(f, "%s %ld\n", l.name, l.val);
} }
grow_drop(list); grow_drop(list);
fclose(f);
return true; return true;
} }
@ -265,7 +269,7 @@ bool trie_unassoc(char var[], uint64_t task) {
} }
} }
void trie_drop (void) { void trie_flush (void) {
struct grow *list = grow_init(true); struct grow *list = grow_init(true);
trie_dfs("", 0, list, trie_base, VERTICES); trie_dfs("", 0, list, trie_base, VERTICES);
grow_drop(list); grow_drop(list);

@ -32,7 +32,7 @@ struct trie_list {
struct trie_retval trie_lookup(char string[]); struct trie_retval trie_lookup(char string[]);
bool trie_set (char string[], int64_t val); bool trie_set (char string[], int64_t val);
bool trie_un (char string[]); bool trie_unset (char string[]);
struct grow *trie_list(void); struct grow *trie_list(void);
bool trie_assoc(char var[], uint64_t task); bool trie_assoc(char var[], uint64_t task);

Loading…
Cancel
Save