Add ability to override environment variables for child process
This commit is contained in:
parent
340c72f9e2
commit
38b6caa6f9
|
@ -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
|
||||||
|
*/
|
|
@ -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()
|
||||||
* Crash the program. This is better than just calling exit() because it doesn't clean up. We
|
* 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.
|
* 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 */
|
/* child -- execute new process */
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
execve(exe_path, argv, environ);
|
execve(exe_path, argv, child_environ);
|
||||||
LOG(LOG_ERR, "Could not execute `%s' (%m).", exe_path);
|
LOG(LOG_ERR, "Could not execute `%s' (%m).", exe_path);
|
||||||
crash();
|
crash();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ void usage(void)
|
||||||
" -R, --restart-interval <i> Sets the length of time between the process\n"
|
" -R, --restart-interval <i> Sets the length of time between the process\n"
|
||||||
" exiting and being restarted, in seconds (default\n"
|
" exiting and being restarted, in seconds (default\n"
|
||||||
" " DEFAULT_RESTART_INTERVAL_S "). May be 0 to restart immediately.\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);
|
"", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +52,7 @@ struct option options[] = {
|
||||||
{ "log", required_argument, 0, 'l' },
|
{ "log", required_argument, 0, 'l' },
|
||||||
{ "pidfile", required_argument, 0, 'p' },
|
{ "pidfile", required_argument, 0, 'p' },
|
||||||
{ "restart-interval", required_argument, 0, 'R' },
|
{ "restart-interval", required_argument, 0, 'R' },
|
||||||
|
{ "environment", required_argument, 0, 'E' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,7 +61,7 @@ struct option options[] = {
|
||||||
/* optstr
|
/* optstr
|
||||||
* The list of short commandline options for getopt(3). Sorted alphabetically, lowercase first.
|
* 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 'l': log_argument = optarg; break;
|
||||||
case 'p': pidfile_argument = optarg; break;
|
case 'p': pidfile_argument = optarg; break;
|
||||||
case 'R': restart_argument = optarg; break;
|
case 'R': restart_argument = optarg; break;
|
||||||
|
case 'E': set_environment_file(optarg); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts_done:
|
opts_done:
|
||||||
|
@ -120,6 +124,9 @@ int main(int argc, char* argv[])
|
||||||
log_destination_set(log_destination_file);
|
log_destination_set(log_destination_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set up environment */
|
||||||
|
if(load_child_environ()) return 1;
|
||||||
|
|
||||||
/* daemonise? */
|
/* daemonise? */
|
||||||
if(daemon) daemonise();
|
if(daemon) daemonise();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue