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 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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue