From 38b6caa6f9235c1de4cf2c286ed0b64971c3dd9c Mon Sep 17 00:00:00 2001 From: Laurence Withers Date: Sat, 26 Jul 2008 18:10:04 +0000 Subject: [PATCH] Add ability to override environment variables for child process --- src/daemonitor/500_env.c | 155 +++++++++++++++++++++++++++++++ src/daemonitor/600_run_program.c | 10 +- src/daemonitor/999_main.c | 9 +- 3 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 src/daemonitor/500_env.c diff --git a/src/daemonitor/500_env.c b/src/daemonitor/500_env.c new file mode 100644 index 0000000..a0b0f1e --- /dev/null +++ b/src/daemonitor/500_env.c @@ -0,0 +1,155 @@ +/* daemonitor/src/daemonitor/500_env.c + * + * (c)2007, Laurence Withers, . + * Released under the GNU GPLv3. See file COPYING or + * http://www.gnu.org/copyleft/gpl.html for details. +*/ + + + +/* ENVIRONMENT HANDLING *************************************************************************** + * + * This file contains routines for modifying the environment of the child process. + */ + + + +/* PUBLIC API ************************************************************************************/ + + + +/* set_environment_file() + * Stores a pointer to a filename from which the environment is loaded. A pointer to the string + * is stored; the string itself is not copied. + */ +void set_environment_file(const char* filename); + + + +/* child_environ + * Set by load_child_environ(), this is the list of enviroment vairables loaded from the file + * specified by set_environment_file(), in a format suitable for execve(2). + */ +extern char** child_environ; + + + +/* load_child_environ() + * Opens and parses the environment file whose name is provided by set_environment_file(), storing + * the results in `child_environ' (which is cleared first if necessary). On error, logs the + * reason, and returns -1. Returns 0 on success. If no environment file has been set, child_environ + * is instead set to point at `environ' and 0 is returned. + */ +int load_child_environ(void); + + + +/* IMPLEMENTATION ********************************************************************************/ + + + +/* environ_filename, set_environment_file() + * The filename of the environment file. If 0, then no file has been specified. The function + * simply stores the pointer. + */ +const char* environ_filename = 0; +void set_environment_file(const char* filename) +{ + environ_filename = filename; +} + + + +/* environ + * As per environ(7), this variable must be declared by the user program. It is used to specify + * the environment for our child process. + */ +extern char **environ; + + + +/* child_environ et al. + * Dynamic array of allocated strings. + */ +char** child_environ = 0; +int child_environ_num = 0, child_environ_size = 0; + + + +/* add_child_environ_entry() + * Add a pointer `p' into the dynamic array `child_environ'. + */ +void add_child_environ_entry(char* p) +{ + char** n; + + if(child_environ_num == child_environ_size) { + child_environ_size = child_environ_size ? (child_environ_size << 1) : 16; + n = realloc(child_environ, child_environ_size * sizeof(char*)); + if(!n) { + LOG(LOG_WARNING, "Out of memory (%d environment variables).", child_environ_size); + return; + } + child_environ = n; + } + + child_environ[child_environ_num++] = p; +} + + + +/* load_child_environ() + * If `environ_filename' is 0, simply point `child_environ' at libc's `environ' and return with + * success. Otherwise, load the file, storing its lines into the dynamic array `child_environ'. + */ +int load_child_environ(void) +{ + int i; + FILE* fp; + char* line; + size_t line_sz; + ssize_t ret; + + /* don't override */ + if(!environ_filename) { + child_environ = environ; + return 0; + } + + /* clear old array entries */ + for(i = 0; i < child_environ_num; ++i) { + free(child_environ[i]); + } + child_environ_num = 0; + + /* open file */ + fp = fopen(environ_filename, "r"); + if(!fp) { + LOG(LOG_ERR, "Could not open environment file `%s' (%m).", environ_filename); + return -1; + } + + /* store each line */ + while(1) { + line = 0; + line_sz = 0; + ret = getline(&line, &line_sz, fp); + if(ret == -1) break; /* EOF */ + if(ret < 2) continue; /* skip blank lines */ + + if(line[ret - 1] == '\n') line[ret - 1] = 0; /* strip `\n' */ + add_child_environ_entry(line); + } + + /* clean up */ + fclose(fp); + add_child_environ_entry(0); + return 0; +} + + + +/* options for text editors +kate: replace-trailing-space-save true; space-indent true; tab-width 4; +vim: expandtab:ts=4:sw=4 +*/ diff --git a/src/daemonitor/600_run_program.c b/src/daemonitor/600_run_program.c index 0325bf0..a5c7630 100644 --- a/src/daemonitor/600_run_program.c +++ b/src/daemonitor/600_run_program.c @@ -40,14 +40,6 @@ void close_file_descriptors(void); -/* environ - * As per environ(7), this variable must be declared by the user program. It is used to specify - * the environment for our child process. - */ -extern char **environ; - - - /* 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. @@ -81,7 +73,7 @@ void run_program(const char* exe_path, char** argv) /* child -- execute new process */ if(pid == 0) { - execve(exe_path, argv, environ); + execve(exe_path, argv, child_environ); LOG(LOG_ERR, "Could not execute `%s' (%m).", exe_path); crash(); } diff --git a/src/daemonitor/999_main.c b/src/daemonitor/999_main.c index ad4ca26..9bfffda 100644 --- a/src/daemonitor/999_main.c +++ b/src/daemonitor/999_main.c @@ -35,6 +35,8 @@ void usage(void) " -R, --restart-interval Sets the length of time between the process\n" " exiting and being restarted, in seconds (default\n" " " DEFAULT_RESTART_INTERVAL_S "). May be 0 to restart immediately.\n" + " -E, --environment Name of file containing environment variables for\n" + " child process, one NAME=VALUE entry per line.\n" "", stderr); } @@ -50,6 +52,7 @@ struct option options[] = { { "log", required_argument, 0, 'l' }, { "pidfile", required_argument, 0, 'p' }, { "restart-interval", required_argument, 0, 'R' }, + { "environment", required_argument, 0, 'E' }, { 0, 0, 0, 0 } }; @@ -58,7 +61,7 @@ struct option options[] = { /* optstr * The list of short commandline options for getopt(3). Sorted alphabetically, lowercase first. */ -const char* optstr = "dhl:p:R:V"; +const char* optstr = "dhl:p:E:R:V"; @@ -86,6 +89,7 @@ int main(int argc, char* argv[]) 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; } } opts_done: @@ -120,6 +124,9 @@ int main(int argc, char* argv[]) log_destination_set(log_destination_file); } + /* set up environment */ + if(load_child_environ()) return 1; + /* daemonise? */ if(daemon) daemonise();