Compare commits
	
		
			8 Commits
		
	
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | b2aadf503b | |
|  | 639944b905 | |
|  | c55693ce1c | |
|  | b17eed9466 | |
|  | b26bd15791 | |
|  | f611c2acf7 | |
|  Laurence Withers | 4a50315f12 | |
|  Laurence Withers | 45bbf6bf1c | 
							
								
								
									
										10
									
								
								README
								
								
								
								
							
							
						
						
									
										10
									
								
								README
								
								
								
								
							|  | @ -1,8 +1,10 @@ | |||
| daemonitor | ||||
| ============================================================================== | ||||
| (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| Released under the GNU GPLv3. See file COPYING or  | ||||
| http://www.gnu.org/copyleft/gpl.html for details. | ||||
| ======================================================================== | ||||
| Copyright: ©2007–2012, Güralp Systems Limited | ||||
| Author: Laurence Withers <lwithers@guralp.com> | ||||
| License: GPLv3 | ||||
| 
 | ||||
| See file COPYING for detail license information. | ||||
| 
 | ||||
| Really Quick Instructions | ||||
| ------------------------- | ||||
|  |  | |||
							
								
								
									
										7
									
								
								config
								
								
								
								
							
							
						
						
									
										7
									
								
								config
								
								
								
								
							|  | @ -1,10 +1,9 @@ | |||
| # daemonitor/config | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: syntax=sh:expandtab:ts=4:sw=4 | ||||
| # | ||||
| #  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| #  Released under the GNU GPLv3. See file COPYING or | ||||
| #  http://www.gnu.org/copyleft/gpl.html for details. | ||||
| #  Copyright: ©2007–2012, Güralp Systems Limited | ||||
| #  Author: Laurence Withers <lwithers@guralp.com> | ||||
| #  License: GPLv3 | ||||
| # | ||||
| # This file contains options used to build daemonitor. | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										15
									
								
								make.sh
								
								
								
								
							
							
						
						
									
										15
									
								
								make.sh
								
								
								
								
							|  | @ -1,9 +1,9 @@ | |||
| #!/bin/sh | ||||
| #!/bin/bash | ||||
| # daemonitor/make.sh | ||||
| #  | ||||
| #  (c)2006-2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| #  Released under the GNU GPLv3. See file COPYING or | ||||
| #  http://www.gnu.org/copyleft/gpl.html for details. | ||||
| #  Copyright: ©2007–2012, Güralp Systems Limited | ||||
| #  Author: Laurence Withers <lwithers@guralp.com> | ||||
| #  License: GPLv3 | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
|  | @ -15,19 +15,19 @@ then | |||
|     echo "Configuration file not found???" | ||||
|     exit 1 | ||||
| fi | ||||
| source "config" # don't fail on error, since last command in config might return false | ||||
| source "./config" # don't fail on error, since last command in config might return false | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # Get version information | ||||
| source version || exit 1 | ||||
| source "./version" || exit 1 | ||||
| VERSION="${VERMAJOR}.${VERMINOR}.${VERMICRO}" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # Get standard functions | ||||
| [ -z "${VERBOSE}" ] && VERBOSE="0" | ||||
| source scripts/functions.sh || exit 1 | ||||
| source "./scripts/functions.sh" || exit 1 | ||||
| 
 | ||||
| 
 | ||||
| # List of directories which will be emptied by clean. | ||||
|  | @ -292,5 +292,4 @@ done | |||
| 
 | ||||
| exit 0 | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: expandtab:ts=4:sw=4 | ||||
|  |  | |||
							
								
								
									
										25
									
								
								run-test.sh
								
								
								
								
							
							
						
						
									
										25
									
								
								run-test.sh
								
								
								
								
							|  | @ -1,9 +1,9 @@ | |||
| #!/bin/sh | ||||
| #!/bin/bash | ||||
| # daemonitor/test.sh | ||||
| #  | ||||
| #  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| #  Released under the GNU GPLv3. See file COPYING or | ||||
| #  http://www.gnu.org/copyleft/gpl.html for details. | ||||
| #  Copyright: ©2007–2012, Güralp Systems Limited | ||||
| #  Author: Laurence Withers <lwithers@guralp.com> | ||||
| #  License: GPLv3 | ||||
| # | ||||
| 
 | ||||
| # Running this script on its own will display a summary of all the | ||||
|  | @ -21,12 +21,7 @@ run_test() { | |||
|         return 1 | ||||
|     fi | ||||
| 
 | ||||
|     if [ $# -eq 0 ] | ||||
|     then | ||||
|         LD_LIBRARY_PATH="obj" ${EXE} || return 1 | ||||
|     else | ||||
|         LD_LIBRARY_PATH="obj" ${EXE} "$*" || return 1 | ||||
|     fi | ||||
|     LD_LIBRARY_PATH="obj:${LD_LIBRARY_PATH}" "${EXE}" "$@" || return 1 | ||||
|     return 0 | ||||
| } | ||||
| 
 | ||||
|  | @ -38,14 +33,15 @@ print_tests() { | |||
|     echo "---------------------------------------------------------------------" | ||||
|     for EXE in obj/tests/* | ||||
|     do | ||||
|         [ -x ${EXE} ] || continue | ||||
|         NAME=$(echo ${EXE} | sed 's,obj/tests/,,') | ||||
|         [ -x "${EXE}" ] || continue | ||||
|         NAME="$(echo "${EXE}" | sed 's,obj/tests/,,')" | ||||
|         echo -ne "${NAME}\t" | ||||
|         LD_LIBRARY_PATH="obj" ${EXE} --print-summary | ||||
|         LD_LIBRARY_PATH="obj:${LD_LIBRARY_PATH}" "${EXE}" --print-summary | ||||
|     done | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # Main script | ||||
| if [ $# -eq 0 ] | ||||
| then | ||||
|  | @ -53,7 +49,6 @@ then | |||
|     exit 0 | ||||
| fi | ||||
| 
 | ||||
| run_test $* | ||||
| run_test "$@" | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: expandtab:ts=4:sw=4 | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ build.docs.none | |||
| build.files.none | ||||
| build.firmware.gpasm | ||||
| build.firmware.sdcc | ||||
| build.header.c | ||||
| build.lib.c | ||||
| build.lib.c++ | ||||
| build.make.none | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # daemonitor/scripts/functions.sh | ||||
| # | ||||
| #  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| #  Released under the GNU GPLv3. See file COPYING or | ||||
| #  http://www.gnu.org/copyleft/gpl.html for details. | ||||
| #  Copyright: ©2007–2012, Güralp Systems Limited | ||||
| #  Author: Laurence Withers, <lwithers@guralp.com> | ||||
| #  License: GPLv3 | ||||
| # | ||||
| 
 | ||||
| # Common functions | ||||
|  | @ -63,5 +63,4 @@ do_cmd_redir() { | |||
|     fi | ||||
| } | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: expandtab:ts=4:sw=4 | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # daemonitor/scripts/paths | ||||
| # | ||||
| #  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| #  Released under the GNU GPLv3. See file COPYING or | ||||
| #  http://www.gnu.org/copyleft/gpl.html for details. | ||||
| #  Copyright: ©2007–2012, Güralp Systems Limited | ||||
| #  Author: Laurence Withers, <lwithers@guralp.com> | ||||
| #  License: GPLv3 | ||||
| # | ||||
| #  Default path setup. Not meant for editing; use environment variables  | ||||
| #  to override values if needed. | ||||
|  | @ -60,5 +60,4 @@ fi | |||
| [ -z "${WEBDIR}" ] && WEBDIR="${SRVDIR}/http" | ||||
| [ -z "${CGIDIR}" ] && CGIDIR="${WEBDIR}/cgi-bin" | ||||
|   | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: syntax=sh:expandtab:ts=4:sw=4 | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| /* daemonitor/src/daemonitor/200_log.c
 | ||||
|  * | ||||
|  *  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
|  *  Released under the GNU GPLv3. See file COPYING or | ||||
|  *  http://www.gnu.org/copyleft/gpl.html for details.
 | ||||
| */ | ||||
|  *  Copyright: ©2007–2012, Laurence Withers. | ||||
|  *  Author: Laurence Withers <l@lwithers.me.uk> | ||||
|  *  License: GPLv3 | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -170,16 +170,25 @@ void log_func_syslog(int level, const char* fmt, ...) | |||
| /* log_destination_set()
 | ||||
|  *  Set `log_func' function pointer. | ||||
|  */ | ||||
| void log_destination_set(enum log_destination_t dest) | ||||
| void | ||||
| log_destination_set(enum log_destination_t dest) | ||||
| { | ||||
|     switch(dest) { | ||||
|     case log_destination_stdout: | ||||
|         log_func_fd = STDOUT_FILENO; | ||||
|         log_func_fd = dup(STDOUT_FILENO); | ||||
|         if(log_func_fd == -1) { | ||||
|             printf("dup() failed: %m."); | ||||
|             exit(1); | ||||
|         } | ||||
|         log_func = log_func_file; | ||||
|         break; | ||||
| 
 | ||||
|     case log_destination_stderr: | ||||
|         log_func_fd = STDERR_FILENO; | ||||
|         log_func_fd = dup(STDERR_FILENO); | ||||
|         if(log_func_fd == -1) { | ||||
|             fprintf(stderr, "dup() failed: %m."); | ||||
|             exit(1); | ||||
|         } | ||||
|         log_func = log_func_file; | ||||
|         break; | ||||
| 
 | ||||
|  | @ -210,6 +219,5 @@ int log_destination_set_file(const char* filename) | |||
| 
 | ||||
| 
 | ||||
| /* options for text editors
 | ||||
| kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| vim: expandtab:ts=4:sw=4 | ||||
| */ | ||||
|  |  | |||
|  | @ -1,160 +0,0 @@ | |||
| /* daemonitor/src/daemonitor/400_daemon.c
 | ||||
|  * | ||||
|  *  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
|  *  Released under the GNU GPLv3. See file COPYING or | ||||
|  *  http://www.gnu.org/copyleft/gpl.html for details.
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* DAEMON ROUTINES ********************************************************************************
 | ||||
|  * | ||||
|  *  This file provides the daemonise() routine, which makes the process a daemon (fork() + setsid() | ||||
|  *  so that the process lives in the background, also opens /dev/console). It also provides the | ||||
|  *  close_file_descriptors() routine, which clears all file descriptors but 0, 1 and 2. | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* PUBLIC API ************************************************************************************/ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* daemonise()
 | ||||
|  *  Performs a fork() and setsid() so that the process lives in the background. It closes stdin, | ||||
|  *  stdout and stderr and opens /dev/null and/or /dev/console instead, as appropriate. On error, | ||||
|  *  this function exits the program. | ||||
|  */ | ||||
| void daemonise(void); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* close_file_descriptors()
 | ||||
|  *  Closes all file descriptors but stdin, stdout and stderr. Should be called whether we are | ||||
|  *  daemonising or not. | ||||
|  */ | ||||
| void close_file_descriptors(void); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* IMPLEMENTATION ********************************************************************************/ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void daemonise(void) | ||||
| { | ||||
|     int fd; | ||||
|     pid_t pid; | ||||
| 
 | ||||
|     /* close stdin and reopen it as /dev/null */ | ||||
|     TEMP_FAILURE_RETRY( close(STDIN_FILENO) ); | ||||
|     fd = open("/dev/null", O_RDONLY); | ||||
|     switch(fd) { | ||||
|     case -1: | ||||
|         LOG(LOG_CRIT, "Could not open `/dev/null' (%m)."); | ||||
|         exit(1); | ||||
| 
 | ||||
|     case STDIN_FILENO: | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         LOG(LOG_CRIT, "Opened `/dev/null' for stdin, but got file descriptor %d instead.", fd); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     /* close stdout and reopen it as /dev/console if possible, or /dev/null if not */ | ||||
|     TEMP_FAILURE_RETRY( close(STDOUT_FILENO) ); | ||||
|     fd = open("/dev/console", O_WRONLY | O_NOCTTY); | ||||
|     if(fd == -1) { | ||||
|         LOG(LOG_WARNING, "Could not open `/dev/console' for stdout (%m)."); | ||||
|         fd = open("/dev/null", O_WRONLY); | ||||
|     } | ||||
|     switch(fd) { | ||||
|     case -1: | ||||
|         LOG(LOG_CRIT, "Could not open `/dev/null' (%m)."); | ||||
|         exit(1); | ||||
| 
 | ||||
|     case STDOUT_FILENO: | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         LOG(LOG_CRIT, "Opened `/dev/null' for stdout, but got file descriptor %d instead.", fd); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     /* close stderr and reopen it as /dev/console if possible, or /dev/null if not */ | ||||
|     TEMP_FAILURE_RETRY( close(STDERR_FILENO) ); | ||||
|     fd = open("/dev/console", O_WRONLY | O_NOCTTY); | ||||
|     if(fd == -1) { | ||||
|         LOG(LOG_WARNING, "Could not open `/dev/console' for stderr (%m)."); | ||||
|         /* force fd closed again, in case glibc kindly connected it to syslog for us */ | ||||
|         TEMP_FAILURE_RETRY( close(STDERR_FILENO) ); | ||||
|         fd = open("/dev/null", O_WRONLY); | ||||
|     } | ||||
|     switch(fd) { | ||||
|     case -1: | ||||
|         LOG(LOG_CRIT, "Could not open `/dev/null' (%m)."); | ||||
|         exit(1); | ||||
| 
 | ||||
|     case STDERR_FILENO: | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         LOG(LOG_CRIT, "Opened `/dev/null' for stderr, but got file descriptor %d instead.", fd); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     /* daemonise */ | ||||
|     pid = fork(); | ||||
|     if(pid == (pid_t)-1) { | ||||
|         LOG(LOG_CRIT, "Could not fork daemonised process (%m)."); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     if(pid) { | ||||
|         /* parent */ | ||||
|         _exit(0); /* don't call atexit() et al. in parent */ | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     setsid(); | ||||
|     LOG(LOG_NOTICE, "Daemonised, PID %lu.", (unsigned long)getpid()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* close_file_descriptors()
 | ||||
|  *  Adapted from libgslutil (GPL-3). | ||||
|  */ | ||||
| void close_file_descriptors(void) | ||||
| { | ||||
|     DIR* d; | ||||
|     struct dirent* de; | ||||
|     int i, end, dfd; | ||||
| 
 | ||||
|     d = opendir("/proc/self/fd"); | ||||
|     if(!d) { | ||||
|         /* backup method */ | ||||
|         for(i = STDERR_FILENO + 1, end = getdtablesize(); i < end; ++i) { | ||||
|             close(i); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|     dfd = dirfd(d); | ||||
| 
 | ||||
|     while( (de = readdir(d)) ) { | ||||
|         if(de->d_name[0] == '.') continue; | ||||
|         i = strtol(de->d_name, 0, 10); | ||||
|         if(i == dfd) continue; /* skip file descriptor associated with `DIR* d' */ | ||||
|         if(i <= STDERR_FILENO) continue; /* leave stdin, stdout, stderr alone */ | ||||
|         TEMP_FAILURE_RETRY( close(i) ); | ||||
|     } | ||||
|     closedir(d); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* options for text editors
 | ||||
| kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| vim: expandtab:ts=4:sw=4 | ||||
| */ | ||||
|  | @ -1,9 +1,9 @@ | |||
| /* daemonitor/src/daemonitor/600_run_program.c
 | ||||
|  * | ||||
|  *  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
|  *  Released under the GNU GPLv3. See file COPYING or | ||||
|  *  http://www.gnu.org/copyleft/gpl.html for details.
 | ||||
| */ | ||||
|  *  Copyright: ©2007–2012, Laurence Withers. | ||||
|  *  Author: Laurence Withers <l@lwithers.me.uk> | ||||
|  *  License: GPLv3 | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -45,8 +45,8 @@ volatile int sigterm_received = 0; | |||
| 
 | ||||
| 
 | ||||
| /* close_file_descriptors()
 | ||||
|  *  Closes all file descriptors but stdin, stdout and stderr. Should be called whether we are | ||||
|  *  daemonising or not. | ||||
|  *  Closes all file descriptors but stdin, stdout and stderr (which it leaves | ||||
|  *  unchanged). | ||||
|  */ | ||||
| void close_file_descriptors(void); | ||||
| 
 | ||||
|  | @ -56,6 +56,38 @@ void close_file_descriptors(void); | |||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* close_file_descriptors()
 | ||||
|  *  Adapted from libgslutil (GPL-3). | ||||
|  */ | ||||
| void | ||||
| close_file_descriptors(void) | ||||
| { | ||||
|     DIR* d; | ||||
|     struct dirent* de; | ||||
|     int i, end, dfd; | ||||
| 
 | ||||
|     d = opendir("/proc/self/fd"); | ||||
|     if(!d) { | ||||
|         /* backup method */ | ||||
|         for(i = STDERR_FILENO + 1, end = getdtablesize(); i < end; ++i) { | ||||
|             close(i); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|     dfd = dirfd(d); | ||||
| 
 | ||||
|     while( (de = readdir(d)) ) { | ||||
|         if(de->d_name[0] == '.') continue; | ||||
|         i = strtol(de->d_name, 0, 10); | ||||
|         if(i == dfd) continue; /* skip file descriptor associated with `DIR* d' */ | ||||
|         if(i <= STDERR_FILENO) continue; /* leave stdin, stdout, stderr alone */ | ||||
|         TEMP_FAILURE_RETRY( close(i) ); | ||||
|     } | ||||
|     closedir(d); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* crash()
 | ||||
|  *  Crash the program. This is better than just calling exit() because it doesn't clean up. We | ||||
|  *  should leave our PID file lying around to look like we crashed. This function is paranoid. | ||||
|  | @ -113,6 +145,8 @@ void run_program(const char* exe_path, char** argv) | |||
| 
 | ||||
|     /* child -- execute new process */ | ||||
|     if(pid == 0) { | ||||
|         close_file_descriptors(); | ||||
| 
 | ||||
|         /* clear the child's signal mask */ | ||||
|         sigemptyset(&ss); | ||||
|         sigprocmask(SIG_SETMASK, &ss, 0); | ||||
|  | @ -203,6 +237,5 @@ void run_program(const char* exe_path, char** argv) | |||
| 
 | ||||
| 
 | ||||
| /* options for text editors
 | ||||
| kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| vim: expandtab:ts=4:sw=4 | ||||
| */ | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| /* daemonitor/src/daemonitor/700_signal.c
 | ||||
|  * | ||||
|  *  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
|  *  Released under the GNU GPLv3. See file COPYING or | ||||
|  *  http://www.gnu.org/copyleft/gpl.html for details.
 | ||||
| */ | ||||
|  *  Copyright: ©2007–2012, Laurence Withers. | ||||
|  *  Author: Laurence Withers <l@lwithers.me.uk> | ||||
|  *  License: GPLv3 | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -45,7 +45,7 @@ void sigterm_handler(int signum __attribute__((unused))) | |||
|     /* uck -- we can't call exit() because it's not async-signal-safe, so we must call _exit() and
 | ||||
|      * clean up manually, with no logging */ | ||||
|     unlink(pidfile_filename); | ||||
|     exit(0); | ||||
|     _exit(0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -72,8 +72,9 @@ void signal_setup(void) | |||
|     sigdelset(&ss, SIGSEGV); | ||||
|     sigdelset(&ss, SIGBUS); | ||||
| 
 | ||||
|     /* we'd like to deal with SIGTERM specially */ | ||||
|     /* we'd like to deal with SIGTERM/SIGINT specially */ | ||||
|     sigdelset(&ss, SIGTERM); | ||||
|     sigdelset(&ss, SIGINT); | ||||
| 
 | ||||
|     /* don't block SIGCHLD or wait(2) won't work */ | ||||
|     sigdelset(&ss, SIGCHLD); | ||||
|  | @ -90,9 +91,10 @@ void signal_setup(void) | |||
|     sigaction(SIGBUS, &sa, 0); | ||||
|     sigaction(SIGCHLD, &sa, 0); | ||||
| 
 | ||||
|     /* install our own handler for SIGTERM */ | ||||
|     /* install our own handler for SIGTERM/SIGINT */ | ||||
|     sa.sa_handler = sigterm_handler; | ||||
|     sigaction(SIGTERM, &sa, 0); | ||||
|     sigaction(SIGINT, &sa, 0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,186 @@ | |||
| /* daemonitor/src/daemonitor/800_checks.c
 | ||||
|  * | ||||
|  *  Copyright: ©2012, Laurence Withers. | ||||
|  *  Author: Laurence Withers <l@lwithers.me.uk> | ||||
|  *  License: GPLv3 | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* RESPAWN CHECKS **************************************************************
 | ||||
|  * | ||||
|  *  This file implements functionality for various checks that may be carried | ||||
|  *  out whenever the child process needs to be respawned. An arbitrary number of | ||||
|  *  checks may be registered; if any single check fails, the entire test counts | ||||
|  *  as failing. The result of the checks is found by calling run_checks(). | ||||
|  * | ||||
|  *  A failed check will log details at LOG_NOTICE (or above). | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* PUBLIC API *****************************************************************/ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* check_command_register()
 | ||||
|  *  cmd: A command (passed to system(3)) to run. If it exits with code 0, the | ||||
|  *       check passes. | ||||
|  */ | ||||
| void check_command_register(const char* cmd); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* check_file_register()
 | ||||
|  *  path: A file to test. If it exists, the check passes. | ||||
|  */ | ||||
| void check_file_register(const char* cmd); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* run_checks()
 | ||||
|  *  Returns 0 if all checks succeeded (including when none are registered) and | ||||
|  *  non-0 if any check failed. | ||||
|  */ | ||||
| int run_checks(void); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* IMPLEMENTATION *************************************************************/ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| enum check_type { | ||||
|     check_type_command, | ||||
|     check_type_file, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* struct check
 | ||||
|  * check_head | ||||
|  *  A linked list of the checks that are to be run. | ||||
|  */ | ||||
| struct check { | ||||
|     enum check_type type; | ||||
| 
 | ||||
|     /* can be the argument for system(3) or the path to check for a file */ | ||||
|     const char* arg; | ||||
| 
 | ||||
|     /* linked list structure */ | ||||
|     struct check* next; | ||||
| }; | ||||
| 
 | ||||
| struct check* check_head = 0; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* check_generic_register()
 | ||||
|  *  Instantiates a ‘struct check’ and adds it to the list at ‘check_head’. | ||||
|  */ | ||||
| void | ||||
| check_generic_register(enum check_type type, const char* arg) | ||||
| { | ||||
|     struct check* c; | ||||
| 
 | ||||
|     c = malloc(sizeof(*c)); | ||||
|     c->type = type; | ||||
|     c->arg = arg; | ||||
|     c->next = check_head; | ||||
|     check_head = c; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| check_command_register(const char* cmd) | ||||
| { | ||||
|     check_generic_register(check_type_command, cmd); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| check_command_run(const struct check* iter) | ||||
| { | ||||
|     int ret; | ||||
| 
 | ||||
|     ret = system(iter->arg); | ||||
|     if(ret == -1) { | ||||
|         LOG(LOG_ERR, "Unable to run check command \"%s\": %m.", iter->arg); | ||||
|         return 0; /* don't exit just because system(3) failed */ | ||||
|     } | ||||
| 
 | ||||
|     if(WIFSIGNALED(ret)) { | ||||
|         LOG(LOG_WARNING, "Check command \"%s\" killed by signal (%s). Exiting.", | ||||
|             iter->arg, strsignal(WTERMSIG(ret))); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if(!WIFEXITED(ret)) { | ||||
|         LOG(LOG_WARNING, "Unrecognised exit code 0x%X from check command " | ||||
|             "\"%s\".", ret, iter->arg); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     if(WEXITSTATUS(ret)) { | ||||
|         LOG(LOG_NOTICE, "Check command \"%s\" signalled failure (exit code " | ||||
|             "%d). Exiting.", iter->arg, WEXITSTATUS(ret)); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| check_file_register(const char* path) | ||||
| { | ||||
|     check_generic_register(check_type_file, path); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| check_file_run(const struct check* iter) | ||||
| { | ||||
|     int ret; | ||||
| 
 | ||||
|     ret = access(iter->arg, F_OK); | ||||
|     if(ret) { | ||||
|         LOG(LOG_NOTICE, "Check file \"%s\" does not exist. Exiting.", | ||||
|             iter->arg); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| run_checks(void) | ||||
| { | ||||
|     const struct check* iter; | ||||
| 
 | ||||
|     for(iter = check_head; iter; iter = iter->next) { | ||||
|         switch(iter->type) { | ||||
|         case check_type_command: | ||||
|             if(check_command_run(iter)) return -1; | ||||
|             break; | ||||
| 
 | ||||
|         case check_type_file: | ||||
|             if(check_file_run(iter)) return -1; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* options for text editors
 | ||||
| vim: expandtab:ts=4:sw=4 | ||||
| */ | ||||
|  | @ -1,9 +1,9 @@ | |||
| /* daemonitor/src/daemonitor/999_main.c
 | ||||
|  * | ||||
|  *  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
|  *  Released under the GNU GPLv3. See file COPYING or | ||||
|  *  http://www.gnu.org/copyleft/gpl.html for details.
 | ||||
| */ | ||||
|  *  Copyright: ©2007–2012, Laurence Withers. | ||||
|  *  Author: Laurence Withers <l@lwithers.me.uk> | ||||
|  *  License: GPLv3 | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -37,6 +37,10 @@ void usage(void) | |||
|         "                              " DEFAULT_RESTART_INTERVAL_S "). May be 0 to restart immediately.\n" | ||||
|         " -E, --environment <path>  Name of file containing environment variables for\n" | ||||
|         "                           child process, one NAME=VALUE entry per line.\n" | ||||
|         " -C, --check-command <cmd> Runs <cmd> via /bin/sh before restarting a service\n" | ||||
|         "                           that has exited. Stops if <cmd> fails.\n" | ||||
|         " -F, --check-file <path>   Checks that <path> exists before restarting a service\n" | ||||
|         "                           that has exited. Stops if it does not exist.\n" | ||||
|     "", stderr); | ||||
| } | ||||
| 
 | ||||
|  | @ -53,6 +57,8 @@ struct option options[] = { | |||
|     { "pidfile", required_argument, 0, 'p' }, | ||||
|     { "restart-interval", required_argument, 0, 'R' }, | ||||
|     { "environment", required_argument, 0, 'E' }, | ||||
|     { "check-command", required_argument, 0, 'C' }, | ||||
|     { "check-file", required_argument, 0, 'F' }, | ||||
|     { 0, 0, 0, 0 } | ||||
| }; | ||||
| 
 | ||||
|  | @ -61,7 +67,7 @@ struct option options[] = { | |||
| /* optstr
 | ||||
|  *  The list of short commandline options for getopt(3). Sorted alphabetically, lowercase first. | ||||
|  */ | ||||
| const char* optstr = "dhl:p:E:R:V"; | ||||
| const char* optstr = "dhl:p:C:E:F:R:V"; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -73,7 +79,7 @@ int main(int argc, char* argv[]) | |||
| { | ||||
|     char* endp; | ||||
|     const char* log_argument = 0, * pidfile_argument = 0, * restart_argument = 0; | ||||
|     int daemon = 0, restart_interval = DEFAULT_RESTART_INTERVAL; | ||||
|     int do_daemon = 0, restart_interval = DEFAULT_RESTART_INTERVAL; | ||||
| 
 | ||||
|     /* safety */ | ||||
|     close_file_descriptors(); /* leaves stdout etc. open */ | ||||
|  | @ -85,11 +91,13 @@ int main(int argc, char* argv[]) | |||
|         case '?': LOG_ANYWHERE("Invalid commandline options."); return 1; | ||||
|         case 'h': usage(); return 1; | ||||
|         case 'V': fputs("daemonitor " VERSION "\n", stderr); return 1; | ||||
|         case 'd': ++daemon; break; | ||||
|         case 'd': ++do_daemon; break; | ||||
|         case 'l': log_argument = optarg; break; | ||||
|         case 'p': pidfile_argument = optarg; break; | ||||
|         case 'R': restart_argument = optarg; break; | ||||
|         case 'E': set_environment_file(optarg); break; | ||||
|         case 'C': check_command_register(optarg); break; | ||||
|         case 'F': check_file_register(optarg); break; | ||||
|         } | ||||
|     } | ||||
|   opts_done: | ||||
|  | @ -128,7 +136,12 @@ int main(int argc, char* argv[]) | |||
|     if(load_child_environ()) return 1; | ||||
| 
 | ||||
|     /* daemonise? */ | ||||
|     if(daemon) daemonise(); | ||||
|     if(do_daemon) { | ||||
|         if(daemon(0, 0)) { | ||||
|             LOG(LOG_CRIT, "daemon() failed: %m."); | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* write a PID file */ | ||||
|     if(pidfile_argument) { | ||||
|  | @ -150,6 +163,8 @@ int main(int argc, char* argv[]) | |||
|             LOG(LOG_NOTICE, "Sleeping for %d seconds.", restart_interval); | ||||
|             safe_sleep_fixed(restart_interval, 0); | ||||
|         } | ||||
| 
 | ||||
|         if(run_checks()) return 0; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
|  | @ -158,6 +173,5 @@ int main(int argc, char* argv[]) | |||
| 
 | ||||
| 
 | ||||
| /* options for text editors
 | ||||
| kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| vim: expandtab:ts=4:sw=4 | ||||
| */ | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
| if [ -z ${daemonitor_BUILT} ] | ||||
| then | ||||
|     daemonitor="obj/daemonitor" | ||||
|     EXTRAS="-D_GNU_SOURCE" | ||||
|     EXTRAS="-std=gnu99 -D_GNU_SOURCE -DAPP_NAME=\"daemonitor\"" | ||||
| 
 | ||||
|     echo "Building application ${daemonitor}..." | ||||
| 
 | ||||
|  | @ -37,5 +37,4 @@ then | |||
| 
 | ||||
| fi | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: syntax=sh:expandtab:ts=4:sw=4 | ||||
|  |  | |||
|  | @ -8,5 +8,4 @@ echo "Installing binaries into '${SBINDIR}'" | |||
| install_file "${daemonitor}" "${SBINDIR}" 0755 || return 1 | ||||
| print_success "Done" | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: syntax=sh:expandtab:ts=4:sw=4 | ||||
|  |  | |||
|  | @ -14,5 +14,4 @@ then | |||
|     MONOLITHIC_DOC="${MONOLITHIC_DOC} ${SRC}" | ||||
| fi | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: syntax=sh:expandtab:ts=4:sw=4 | ||||
|  |  | |||
							
								
								
									
										9
									
								
								version
								
								
								
								
							
							
						
						
									
										9
									
								
								version
								
								
								
								
							|  | @ -1,8 +1,8 @@ | |||
| # daemonitor/version | ||||
| #  | ||||
| #  (c)2007, Laurence Withers, <l@lwithers.me.uk>. | ||||
| #  Released under the GNU GPLv3. See file COPYING or | ||||
| #  http://www.gnu.org/copyleft/gpl.html for details. | ||||
| #  Copyright: ©2007–2012, Güralp Systems Limited | ||||
| #  Author: Laurence Withers <lwithers@guralp.com> | ||||
| #  License: GPLv3 | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
|  | @ -11,7 +11,6 @@ | |||
| # expected to be in 'major.minor.micro' format. | ||||
| VERMAJOR=1 | ||||
| VERMINOR=0 | ||||
| VERMICRO=1 | ||||
| VERMICRO=3 | ||||
| 
 | ||||
| # kate: replace-trailing-space-save true; space-indent true; tab-width 4; | ||||
| # vim: expandtab:ts=4:sw=4:syntax=sh | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue