X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fscript.c;h=1ce59ea0d8001a50a6b52d348912b5af515c4912;hp=6389cb4b19ca0559a9c74373e0c83f7d30b598e8;hb=add75303e918af5e94ff545d969872799fac5cef;hpb=53036a58790168e18f524bd923f9a7d34691ba2d diff --git a/src/script.c b/src/script.c index 6389cb4b..1ce59ea0 100644 --- a/src/script.c +++ b/src/script.c @@ -1,7 +1,7 @@ /* script.c -- call an external script Copyright (C) 1999-2005 Ivo Timmermans, - 2000-2013 Guus Sliepen + 2000-2017 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,26 +21,116 @@ #include "system.h" #include "conf.h" +#include "device.h" #include "logger.h" #include "names.h" #include "script.h" #include "xalloc.h" -bool execute_script(const char *name, char **envp) { -#ifdef HAVE_SYSTEM - char *scriptname; +#ifdef HAVE_PUTENV +static void unputenv(const char *p) { + const char *e = strchr(p, '='); + if(!e) + return; + int len = e - p; +#ifndef HAVE_UNSETENV +#ifdef HAVE_MINGW + // Windows requires putenv("FOO=") to unset %FOO% + len++; +#endif +#endif + char var[len + 1]; + strncpy(var, p, len); + var[len] = 0; +#ifdef HAVE_UNSETENV + unsetenv(var); +#else + // We must keep what we putenv() around in memory. + // To do this without memory leaks, keep things in a list and reuse if possible. + static list_t list = {}; + for list_each(char, data, &list) { + if(!strcmp(data, var)) { + putenv(data); + return; + } + } + char *data = xstrdup(var); + list_insert_tail(&list, data); + putenv(data); +#endif +} +#else +static void putenv(const char *p) {} +static void unputenv(const char *p) {} +#endif + +static const int min_env_size; + +int environment_add(environment_t *env, const char *format, ...) { + if(env->n >= env->size) { + env->size = env->n ? env->n * 2 : min_env_size; + env->entries = xrealloc(env->entries, env->size * sizeof *env->entries); + } + + if(format) { + va_list ap; + va_start(ap, format); + vasprintf(&env->entries[env->n], format, ap); + va_end(ap); + } else { + env->entries[env->n] = NULL; + } + + return env->n++; +} + +void environment_update(environment_t *env, int pos, const char *format, ...) { + free(env->entries[pos]); + va_list ap; + va_start(ap, format); + vasprintf(&env->entries[pos], format, ap); + va_end(ap); +} + +void environment_init(environment_t *env) { + env->n = 0; + env->size = min_env_size; + env->entries = 0; //xzalloc(env->size * sizeof *env->entries); + + if(netname) + environment_add(env, "NETNAME=%s", netname); + if(myname) + environment_add(env, "NAME=%s", myname); + if(device) + environment_add(env, "DEVICE=%s", device); + if(iface) + environment_add(env, "INTERFACE=%s", iface); + if(debug_level >= 0) + environment_add(env, "DEBUG=%d", debug_level); +} + +void environment_exit(environment_t *env) { + for(int i = 0; i < env->n; i++) + free(env->entries[i]); + free(env->entries); +} + +bool execute_script(const char *name, environment_t *env) { + char scriptname[PATH_MAX]; char *command; - xasprintf(&scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension); + snprintf(scriptname, sizeof scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension); /* First check if there is a script */ #ifdef HAVE_MINGW if(!*scriptextension) { const char *pathext = getenv("PATHEXT") ?: ".COM;.EXE;.BAT;.CMD"; - char fullname[strlen(scriptname) + strlen(pathext)]; - char *ext = fullname + strlen(scriptname); - strcpy(fullname, scriptname); + size_t pathlen = strlen(pathext); + size_t scriptlen = strlen(scriptname); + char fullname[scriptlen + pathlen + 1]; + char *ext = fullname + scriptlen; + strncpy(fullname, scriptname, sizeof fullname); const char *p = pathext; bool found = false; @@ -51,32 +141,26 @@ bool execute_script(const char *name, char **envp) { ext[q - p] = 0; q++; } else { - strcpy(ext, p); + strncpy(ext, p, pathlen + 1); } if((found = !access(fullname, F_OK))) break; p = q; } - if(!found) { - free(scriptname); + if(!found) return true; - } } else #endif - if(access(scriptname, F_OK)) { - free(scriptname); + if(access(scriptname, F_OK)) return true; - } logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name); -#ifdef HAVE_PUTENV /* Set environment */ - for(int i = 0; envp[i]; i++) - putenv(envp[i]); -#endif + for(int i = 0; i < env->n; i++) + putenv(env->entries[i]); if(scriptinterpreter) xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname); @@ -86,19 +170,11 @@ bool execute_script(const char *name, char **envp) { int status = system(command); free(command); - free(scriptname); /* Unset environment */ - for(int i = 0; envp[i]; i++) { - char *e = strchr(envp[i], '='); - if(e) { - char p[e - envp[i] + 1]; - strncpy(p, envp[i], e - envp[i]); - p[e - envp[i]] = '\0'; - putenv(p); - } - } + for(int i = 0; i < env->n; i++) + unputenv(env->entries[i]); if(status != -1) { #ifdef WEXITSTATUS @@ -121,6 +197,6 @@ bool execute_script(const char *name, char **envp) { logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno)); return false; } -#endif + return true; }