Add ability to override environment variables for child process

This commit is contained in:
Laurence Withers 2008-07-26 18:10:04 +00:00
parent 340c72f9e2
commit 38b6caa6f9
3 changed files with 164 additions and 10 deletions

155
src/daemonitor/500_env.c Normal file
View File

@ -0,0 +1,155 @@
/* daemonitor/src/daemonitor/500_env.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.
*/
/* 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
*/

View File

@ -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();
}

View File

@ -35,6 +35,8 @@ void usage(void)
" -R, --restart-interval <i> 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 <path> 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();