/* daemon.c */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _UTILS_C_ #define _UTILS_C_ #endif #include "utils.h" #include "config.h" #define MAXCFGLINE 265 #define DEBUGFILE "/var/log/gpioctrld.log" /* _var = local _var_ = global */ bool _daemon_ = false; //bool _debuglog_ = false; bool _debug2file_ = false; /* * This function reports the error and * exits back to the shell: */ void displayLastSystemError (const char *on_what) { fputs (strerror (errno), stderr); fputs (": ", stderr); fputs (on_what, stderr); fputc ('\n', stderr); if (_daemon_ == true) { logMessage (LOG_ERR, "%d : %s", errno, on_what); closelog (); } } /* From -- syslog.h -- #define LOG_EMERG 0 // system is unusable #define LOG_ALERT 1 // action must be taken immediately #define LOG_CRIT 2 // critical conditions #define LOG_ERR 3 // error conditions #define LOG_WARNING 4 // warning conditions #define LOG_NOTICE 5 // normal but significant condition #define LOG_INFO 6 // informational #define LOG_DEBUG 7 // debug-level messages */ char *elevel2text(int level) { switch(level) { case LOG_ERR: return "Error:"; break; case LOG_DEBUG: return "Debug:"; break; case LOG_NOTICE: return "Notice:"; break; case LOG_INFO: return "Info:"; break; case LOG_WARNING: default: return "Warning:"; break; } return ""; } int text2elevel(char* level) { if (strcmp(level, "DEBUG") == 0) { return LOG_DEBUG; } else if (strcmp(level, "INFO") == 0) { return LOG_INFO; } else if (strcmp(level, "NOTICE") == 0) { return LOG_NOTICE; } else if (strcmp(level, "WARNING") == 0) { return LOG_WARNING; } else if (strcmp(level, "ERROR") == 0) { return LOG_ERR; } return LOG_ERR; } #define MXPRNT 512 void logMessage(int level, char *format, ...) { //if (_debuglog_ == false && level == LOG_DEBUG) // return; char buffer[MXPRNT]; va_list args; va_start(args, format); strncpy(buffer, " ", 8); int size = vsnprintf (&buffer[8], MXPRNT-10, format, args); va_end(args); //if (_sdconfig_.log_level < LOG_ERR || _sdconfig_.log_level > LOG_DEBUG) { if (_sdconfig_.log_level == -1) { fprintf (stderr, buffer); syslog (level, "%s", &buffer[8]); closelog (); } else if (level > _sdconfig_.log_level) { return; } if (size >= MXPRNT-10 ) { buffer[MXPRNT-0] = '\0'; buffer[MXPRNT-1] = '\n'; buffer[MXPRNT-2] = '.'; buffer[MXPRNT-3] = '.'; buffer[MXPRNT-4] = '.'; buffer[MXPRNT-5] = '.'; } if (_daemon_ == true) { syslog (level, "%s", &buffer[8]); closelog (); } if (_daemon_ != true || level == LOG_ERR || _debug2file_ == true) { char *strLevel = elevel2text(level); strncpy(buffer, strLevel, strlen(strLevel)); if ( buffer[strlen(buffer)-1] != '\n') { buffer[strlen(buffer)+1] = '\0'; buffer[strlen(buffer)] = '\n'; } if (_debug2file_ == true) { int fp = open(DEBUGFILE, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (fp != -1) { write(fp, buffer, strlen(buffer)+1 ); close(fp); } else { fprintf (stderr, "Can't open debug log\n %s", buffer); } } else if (level != LOG_ERR) { printf ("%s", buffer); } if (level == LOG_ERR) fprintf (stderr, "%s", buffer); } } void daemonise (char *pidFile, void (*main_function) (void)) { FILE *fp = NULL; pid_t process_id = 0; pid_t sid = 0; _daemon_ = true; /* Check we are root */ if (getuid() != 0) { logMessage(LOG_ERR,"Can only be run as root\n"); exit(EXIT_FAILURE); } int pid_file = open (pidFile, O_CREAT | O_RDWR, 0666); int rc = flock (pid_file, LOCK_EX | LOCK_NB); if (rc) { if (EWOULDBLOCK == errno) ; // another instance is running //fputs ("\nAnother instance is already running\n", stderr); logMessage(LOG_ERR,"\nAnother instance is already running\n"); exit (EXIT_FAILURE); } process_id = fork (); // Indication of fork() failure if (process_id < 0) { displayLastSystemError ("fork failed!"); // Return failure in exit status exit (EXIT_FAILURE); } // PARENT PROCESS. Need to kill it. if (process_id > 0) { fp = fopen (pidFile, "w"); if (fp == NULL) logMessage(LOG_ERR,"can't write to PID file %s",pidFile); else fprintf(fp, "%d", process_id); fclose (fp); logMessage (LOG_DEBUG, "process_id of child process %d \n", process_id); // return success in exit status exit (EXIT_SUCCESS); } //unmask the file mode umask (0); //set new session sid = setsid (); if (sid < 0) { // Return failure displayLastSystemError("Failed to fork process"); exit (EXIT_FAILURE); } // Change the current working directory to root. chdir ("/"); // Close stdin. stdout and stderr close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO); // this is the first instance (*main_function) (); return; } int count_characters(const char *str, char character) { const char *p = str; int count = 0; do { if (*p == character) count++; } while (*(p++)); return count; } char * replace(char const * const original, char const * const pattern, char const * const replacement) { size_t const replen = strlen(replacement); size_t const patlen = strlen(pattern); size_t const orilen = strlen(original); size_t patcnt = 0; const char * oriptr; const char * patloc; // find how many times the pattern occurs in the original string for ( (oriptr = original); (patloc = strstr(oriptr, pattern)); (oriptr = patloc + patlen)) { patcnt++; } { // allocate memory for the new string size_t const retlen = orilen + patcnt * (replen - patlen); char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) ); if (returned != NULL) { // copy the original string, // replacing all the instances of the pattern char * retptr = returned; for ( (oriptr = original); (patloc = strstr(oriptr, pattern)); (oriptr = patloc + patlen)) { size_t const skplen = patloc - oriptr; // copy the section until the occurence of the pattern strncpy(retptr, oriptr, skplen); retptr += skplen; // copy the replacement strncpy(retptr, replacement, replen); retptr += replen; } // copy the rest of the string. strcpy(retptr, oriptr); } return returned; } } void run_external(char *command, int state) { char *cmd = replace(command, "%STATE%", (state==1?"1":"0")); system(cmd); logMessage (LOG_DEBUG, "Ran command '%s'\n", cmd); free(cmd); return; } int str2int(const char* str, int len) { int i; int ret = 0; for(i = 0; i < len; ++i) { if (isdigit(str[i])) ret = ret * 10 + (str[i] - '0'); else break; } return ret; } void run_external_OLD(char *command, int state) { //int status; // By calling fork(), a child process will be created as a exact duplicate of the calling process. // Search for fork() (maybe "man fork" on Linux) for more information. if(fork() == 0){ // Child process will return 0 from fork() //printf("I'm the child process.\n"); char *cmd = replace(command, "%STATE%", (state==1?"1":"0")); system(cmd); logMessage (LOG_DEBUG, "Ran command '%s'\n", cmd); free(cmd); exit(0); }else{ // Parent process will return a non-zero value from fork() //printf("I'm the parent.\n"); } return; } /* void readCfg (char *cfgFile) { FILE * fp ; char bufr[MAXCFGLINE]; const char delim[2] = ";"; char *token; int line = 1; if( (fp = fopen(cfgFile, "r")) != NULL){ while(! feof(fp)){ if (fgets(bufr, MAXCFGLINE, fp) != NULL) { if (bufr[0] != '#' && bufr[0] != ' ' && bufr[0] != '\n') { token = strtok(bufr, delim); while( token != NULL ) { if ( token[(strlen(token)-1)] == '\n') { token[(strlen(token)-1)] = '\0'; } printf( "Line %d - Token %s\n", line, token ); token = strtok(NULL, delim); } line++; } } } fclose(fp); } else { displayLastSystemError(cfgFile); exit (EXIT_FAILURE); } } */