Skip to content

Instantly share code, notes, and snippets.

@maxisoft
Created May 7, 2013 06:43
Show Gist options
  • Save maxisoft/5530670 to your computer and use it in GitHub Desktop.
Save maxisoft/5530670 to your computer and use it in GitHub Desktop.
If in preprocessor close after dup 2
#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