Created
May 7, 2013 06:43
-
-
Save maxisoft/5530670 to your computer and use it in GitHub Desktop.
If in preprocessor
close after dup 2
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
#define forever for(;;) | |
#define THREAD_SLEEP_TIME 100000 //0.1 sec | |
#define THREAD_MUTEX_WAIT_TIME 10000 //0.01 sec | |
#define LOG_UNCATCHED_SIGNAL 1 // 1 => crée un fichier period.signals.log et log les signaux qui ne sont pas dans CATCHED_SIGNAL | |
#define LOCK_FILE_STR "/tmp/period.lock" | |
#if LOG_UNCATCHED_SIGNAL | |
#define SIGNAL_LOG_FILE_STR "/tmp/period.signals.log" | |
#endif | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <sys/file.h> | |
#include <fcntl.h> | |
#include <signal.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <pthread.h> | |
#include <stdint.h> | |
#include "message.h" | |
#include "cmdstruct.h" | |
#include "bool.h" | |
#include "utils.h" | |
static unsigned char CATCHED_SIGNAL[] = {SIGUSR1, SIGINT, SIGTERM, SIGSTOP, SIGCONT}; | |
static int FIFO_IN = -1; | |
static int LOCK_FILE; | |
static FILE *SIGNAL_LOG_FILE = NULL; | |
static sigset_t MASK; | |
static struct list TABLE = {NULL, NULL}; | |
static size_t LAST_ID = 0; | |
static pthread_t UPDATE_TABLE_THREAD; | |
static bool THREAD_CONTINUE = true; | |
static pthread_mutex_t MUTEX = PTHREAD_MUTEX_INITIALIZER; | |
static bool IN_PAUSE = false; | |
static struct flock FILE_LOCK; | |
/** | |
* Convert an argv (2d array) into cmd_t. | |
* @param argv the 2d chars array | |
* @return parsed cmd_t | |
*/ | |
cmd_t argv_as_cmd(char **argv) { | |
cmd_t ret; | |
ret.start = atol(argv[0]); | |
ret.period = atoi(argv[1]); | |
ret.cmd = argv[2]; | |
ret.args = argv + 3; | |
ret.issetcmd = 0; | |
ret.disable = 0; | |
return ret; | |
} | |
free_argv(char **ptr) { | |
size_t i = 0; | |
char *curr; | |
while (curr = ptr[i++]) { | |
free(curr); | |
} | |
free(ptr); | |
} | |
/** | |
* Atexit fct callback. | |
*/ | |
void exitfct() { | |
THREAD_CONTINUE = 0; //call thread stop | |
pthread_join(UPDATE_TABLE_THREAD, NULL); //wait thread | |
fflush(stdout); //flush output | |
fflush(stderr); //flush output | |
close(LOCK_FILE); //close file before deleting | |
unlink(LOCK_FILE_STR); //delete file. | |
} | |
void action_add(char **recived, siginfo_t *Info) { | |
cmd_t c = argv_as_cmd(recived + 1); //parse it | |
c.id = (++LAST_ID); //set id | |
while (pthread_mutex_lock(&MUTEX) != 0) {//lock unsucess | |
//TODO with pthread cond | |
usleep(THREAD_MUTEX_WAIT_TIME); //wait 0.01 sec | |
} | |
list_insert(&TABLE, c); //insert (autosort) | |
pthread_mutex_unlock(&MUTEX); //unlock | |
//NOTE on ne free pas recived tout de suite mais quant la commande sera parsé par l'autre thread. | |
} | |
void action_get(char **recived, siginfo_t *Info) { | |
while (pthread_mutex_lock(&MUTEX) != 0) {//lock unsuccess | |
//TODO with pthread cond | |
usleep(THREAD_MUTEX_WAIT_TIME); //wait 0.01 sec | |
} | |
char *fifoout = getFifoOut_FileName(Info->si_pid); //open a file containing the process sender's pid. | |
if (access(fifoout, F_OK) == -1) {// file doesn't exist | |
pthread_mutex_unlock(&MUTEX); //unlock | |
fputs("Error, no fifo pipe :\"", stderr); | |
fputs(fifoout, stderr); | |
fputs("\".\n", stderr); | |
fflush(stderr); | |
return; | |
} | |
int fdout = assert_open(fifoout, O_WRONLY | O_NONBLOCK, 0); //No blocking pipe. | |
char *tmp = list_str(&TABLE); | |
send_string(fdout, tmp); | |
pthread_mutex_unlock(&MUTEX); //unlock | |
close(fdout); | |
free_argv(recived); | |
free(tmp); | |
} | |
void action_remove(char **recived, siginfo_t *Info) { | |
size_t id = atoi(recived[1]); | |
while (pthread_mutex_lock(&MUTEX) != 0) {//lock unsucess | |
//TODO with pthread cond | |
usleep(THREAD_MUTEX_WAIT_TIME); //wait 0.01 sec | |
} | |
list_remove(&TABLE, id); | |
pthread_mutex_unlock(&MUTEX); //unlock | |
free_argv(recived); | |
} | |
/** | |
* The sig handler function. | |
* @param signal | |
* @param Info | |
* @param uselessstuff | |
*/ | |
void sig_handler(int signal, siginfo_t *Info, void *uselessstuff) { | |
if (signal == SIGTERM || signal == SIGINT) { | |
exit(0); // auto call exitfct | |
} | |
if (signal == SIGSTOP) { | |
IN_PAUSE = true; | |
return; | |
} | |
if (signal == SIGCONT) { | |
IN_PAUSE = false; | |
return; | |
} | |
if (signal == SIGUSR1) { | |
if (FIFO_IN < 0) { //Global not set | |
FIFO_IN = assert_open(getFifoIn_FileName(), O_RDONLY, 0); | |
} | |
char **recived = recv_argv(FIFO_IN); | |
if (!recived || !recived[0]) { | |
fprintf(stderr, "Strange thing append, Got NO Cmd.\n"); | |
fflush(stderr); | |
return; | |
} | |
if (strcmp(recived[0], "get") == 0) { //catch retrieve cmd | |
action_get(recived, Info); | |
return; | |
} else if (strcmp(recived[0], "add") == 0) {//catch add cmd | |
action_add(recived, Info); | |
return; | |
} else if (strcmp(recived[0], "remove") == 0) { //catch remove cmd | |
action_remove(recived, Info); | |
return; | |
} | |
//else | |
fprintf(stderr, "Strange thing append, Got Unexpected Cmd : \"%s\".\n", recived[0]); | |
fflush(stderr); | |
return; | |
} | |
//else | |
fprintf(stderr, "Unexpected Signal : \"%i\".\n", signal); | |
fflush(stderr); | |
} | |
void defaut_sig_handler(int signal, siginfo_t *Info, void *uselessstuff) { | |
fprintf(SIGNAL_LOG_FILE, "Got Signal : \"%i\".\n\tDescription : %s\n\tSender's pid: %i\n", signal, strsignal(signal), Info->si_pid); | |
fflush(SIGNAL_LOG_FILE); | |
} | |
/** | |
* Write current Process pid to a file. | |
*/ | |
void write_PID() { | |
FILE *f = fopen(getPidDaemon_FileName(), "w+"); | |
fprintf(f, "%i", getpid()); | |
fclose(f); | |
} | |
/** | |
* This fonction will run in a thread. | |
* @param data | |
* @return | |
*/ | |
void* thread_fct(void* data) { | |
cmd_t curr = {0, 0, NULL, NULL}; | |
char *tmp = NULL; | |
while (THREAD_CONTINUE) { | |
if (!IN_PAUSE && TABLE.head && pthread_mutex_lock(&MUTEX) == 0) {//lock sucess and there is somethg in Table and not in pause. | |
curr = list_pop(&TABLE); | |
if (curr.start <= now()) { | |
if (!curr.issetcmd) { | |
tmp = cmd_to_strcmd(curr); | |
free_argv(curr.args - 4); | |
curr.args = NULL; | |
curr.cmd = tmp; | |
curr.issetcmd = 1; | |
} | |
if (!(curr.disable)) { | |
system(curr.cmd); | |
} | |
if (!(curr.disable) && curr.period) {//repeat | |
curr.start = now() + curr.period; | |
list_insert(&TABLE, curr); //reinsert (autosort) | |
} else { | |
free(curr.cmd); //delete | |
} | |
} else { | |
list_insert(&TABLE, curr); //reinsert (autosort) | |
} | |
} | |
fflush(stdout); | |
fflush(stderr); | |
pthread_mutex_unlock(&MUTEX); //unlock | |
usleep(THREAD_SLEEP_TIME); //0.1 sec | |
} | |
return NULL; | |
} | |
void lock_period() { | |
FILE_LOCK.l_type = F_WRLCK; | |
FILE_LOCK.l_whence = SEEK_SET; | |
FILE_LOCK.l_start = 0; | |
FILE_LOCK.l_len = 0; | |
FILE_LOCK.l_pid = getpid(); | |
LOCK_FILE = assert_open(LOCK_FILE_STR, O_CREAT | O_RDWR, 0777); | |
if (LOCK_FILE == -1) { | |
fputs("Error can't create lock file\n", stderr); | |
fflush(stderr); | |
exit(-3); | |
} | |
if (fcntl(LOCK_FILE, F_SETLK, &FILE_LOCK) == -1) { | |
fputs("Daemon already running.\n", stderr); | |
fflush(stderr); | |
exit(-5); | |
} | |
} | |
void daemonize() { | |
pid_t pid, sid; | |
// Fork | |
pid = fork(); | |
if (pid < 0) { | |
exit(EXIT_FAILURE); | |
} | |
// exit the parent process. | |
if (pid > 0) { | |
exit(EXIT_SUCCESS); | |
} | |
// file mode mask | |
umask(0); | |
// Create a new SID | |
sid = setsid(); | |
if (sid < 0) { | |
exit(EXIT_FAILURE); | |
} | |
// current working directory | |
if ((chdir("/")) < 0) { | |
exit(EXIT_FAILURE); | |
} | |
//relock with new pid | |
sleep(1); // pour les systeme lent ... comme les debians 6.0 :) (sinon le fichier est toujour lock par le processus initial qui n'existe plus ...) | |
FILE_LOCK.l_pid = getpid(); | |
if (fcntl(LOCK_FILE, F_SETLK, &FILE_LOCK) == -1) { | |
fputs("Daemon already running.\n", stderr); | |
fflush(stderr); | |
exit(-5); | |
} | |
} | |
void init() { | |
atexit(exitfct); | |
list_init(&TABLE); | |
chdir(get_tmp_dir()); | |
//open files | |
int out = assert_open("period.out", O_APPEND | O_WRONLY | O_CREAT, 0644); | |
int err = assert_open("period.err", O_APPEND | O_WRONLY | O_CREAT, 0644); | |
//redirect standards outputs | |
dup2(out, 1) && close(out); | |
dup2(err, 2) && close(err); | |
//close stdin | |
close(0); | |
write_PID(); | |
char * tmp = getFifoIn_FileName(); | |
if (access(tmp, F_OK) == -1) {// file doesn't exist | |
mkfifo(tmp, 0666); | |
} | |
//create dir | |
mkdir("./period", 0777); | |
pthread_create(&UPDATE_TABLE_THREAD, NULL, thread_fct, NULL); | |
size_t i; | |
size_t len = sizeof (CATCHED_SIGNAL); | |
sigset_t othermask; | |
sigfillset(&othermask); | |
sigemptyset(&MASK); | |
//sigaction handler | |
struct sigaction sa; | |
sa.sa_handler = (void (*)) (&sig_handler); //cast to prevent warning | |
sa.sa_flags = SA_SIGINFO; | |
struct sigaction othersa; | |
othersa.sa_handler = (void (*)) (&defaut_sig_handler); //cast to prevent warning | |
othersa.sa_flags = SA_SIGINFO; | |
for (i = 0; i < len; ++i) { | |
sigaddset(&MASK, CATCHED_SIGNAL[i]); | |
sigdelset(&othermask, CATCHED_SIGNAL[i]); | |
sigaction(CATCHED_SIGNAL[i], &sa, NULL); | |
} | |
sigprocmask(SIG_BLOCK, &MASK, NULL); | |
sigprocmask(SIG_BLOCK, &othermask, NULL); | |
#if LOG_UNCATCHED_SIGNAL | |
SIGNAL_LOG_FILE = fopen(SIGNAL_LOG_FILE_STR, "a+"); | |
if (!SIGNAL_LOG_FILE) { | |
fprintf(stderr, "Can't open file \"%s\".\n", SIGNAL_LOG_FILE_STR); | |
} else { | |
for (i = 1; i <= SIGRTMAX; ++i) { | |
if (sigismember(&othermask, i)) { | |
sigaction(i, &othersa, NULL); | |
} | |
} | |
} | |
#endif | |
//pthread_sigmask(SIG_BLOCK, &mask, NULL); | |
fflush(stdout); | |
} | |
int main(int argc, char** argv) { | |
lock_period(); | |
daemonize(); | |
init(); | |
forever{ | |
//attente de Signal | |
sigsuspend(&MASK); | |
} | |
return (EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment