Use PATHEXT when checking for the presence of scripts on Windows.
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 23 Aug 2013 17:24:36 +0000 (19:24 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 23 Aug 2013 19:23:46 +0000 (21:23 +0200)
It seems like a lot of overhead to call access() for every possible extension
defined in PATHEXT, but apparently this is what Windows does itself too. At
least this avoids calling system() when the script one is looking for does not
exist at all.

Since the tinc utility also needs to call scripts, execute_script() is now
split off into its own source file.

13 files changed:
src/Makefile.am
src/graph.c
src/invitation.c
src/net.c
src/net_packet.c
src/net_setup.c
src/process.c
src/process.h
src/protocol_auth.c
src/script.c [new file with mode: 0644]
src/script.h [new file with mode: 0644]
src/subnet.c
src/tincctl.c

index 2738008be028bd26b175c112203477d579a52ba9..96643524d7d80d891240e22ae07de1d2283f4249 100644 (file)
@@ -55,6 +55,7 @@ tincd_SOURCES = \
        route.c route.h \
        rsa.h \
        rsagen.h \
+       script.c script.h \
        splay_tree.c splay_tree.h \
        sptps.c sptps.h \
        subnet.c subnet.h \
@@ -73,6 +74,7 @@ tinc_SOURCES = \
        list.c list.h \
        names.c names.h \
        netutl.c netutl.h \
+       script.c script.h \
        sptps.c sptps.h \
        subnet_parse.c subnet.h \
        tincctl.c tincctl.h \
index b4c01bb5ef8b2ec36e660ffd05ec0428c82c18fc..396e35a3e68d2e9373a6dde4a753402ad7d4228f 100644 (file)
@@ -53,8 +53,8 @@
 #include "names.h"
 #include "netutl.h"
 #include "node.h"
-#include "process.h"
 #include "protocol.h"
+#include "script.h"
 #include "subnet.h"
 #include "utils.h"
 #include "xalloc.h"
index e6567bae4960b779841ff1d676576d6aed439d4b..188ea2dbdb75dd1ddf628d507be8a7de428f9141 100644 (file)
@@ -27,6 +27,7 @@
 #include "names.h"
 #include "netutl.h"
 #include "rsagen.h"
+#include "script.h"
 #include "sptps.h"
 #include "tincctl.h"
 #include "utils.h"
@@ -395,17 +396,15 @@ int cmd_invite(int argc, char *argv[]) {
        xasprintf(&url, "%s/%s%s", address, hash, cookie);
 
        // Call the inviation-created script
-       setenv("NAME", myname, true);
-       setenv("NETNAME", netname, true);
-       setenv("NODE", argv[1], true);
-       setenv("INVITATION_FILE", filename, true);
-       setenv("INVITATION_URL", url, true);
-       char *scriptname;
-       xasprintf(&scriptname, "\"%s" SLASH "invitation-created\"", confbase);
-       system(scriptname);
-       free(scriptname);
-       unsetenv("NODE");
-       unsetenv("INVITATION");
+       char *envp[6] = {};
+       xasprintf(&envp[0], "NAME=%s", myname);
+       xasprintf(&envp[1], "NETNAME=%s", netname);
+       xasprintf(&envp[2], "NODE=%s", argv[1]);
+       xasprintf(&envp[3], "INVITATION_FILE=%s", filename);
+       xasprintf(&envp[4], "INVITATION_URL=%s", url);
+       execute_script("invitation-created", envp);
+       for(int i = 0; i < 6 && envp[i]; i++)
+               free(envp[i]);
 
        puts(url);
        free(url);
index bf6cfcf177d58a18572a4947e62a45e11f73c617..286f15763e2f6cbd4e7bf632f91c550106d718f7 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -32,7 +32,6 @@
 #include "names.h"
 #include "net.h"
 #include "netutl.h"
-#include "process.h"
 #include "protocol.h"
 #include "subnet.h"
 #include "xalloc.h"
index f79c9a75ac7e6795a70a1abe64fc42eb2886b870..1159231205f8bbbb25a22e091d83a15ac9db0846 100644 (file)
@@ -42,7 +42,6 @@
 #include "net.h"
 #include "netutl.h"
 #include "protocol.h"
-#include "process.h"
 #include "route.h"
 #include "utils.h"
 #include "xalloc.h"
index 35cd3f7948ab9945653f8a3d08e284b3ee76dab3..b9c5df7a8209bce0521bd9724543ee0f54419c03 100644 (file)
@@ -38,6 +38,7 @@
 #include "protocol.h"
 #include "route.h"
 #include "rsa.h"
+#include "script.h"
 #include "subnet.h"
 #include "utils.h"
 #include "xalloc.h"
index cbb190a5a9abea30241af0dce8769b602a02d37a..c1038bcd62165728a026742ab1034b44c40ca7ec 100644 (file)
@@ -214,72 +214,4 @@ bool detach(void) {
        return true;
 }
 
-bool execute_script(const char *name, char **envp) {
-#ifdef HAVE_SYSTEM
-       char *scriptname;
-       char *command;
 
-       xasprintf(&scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension);
-
-       /* First check if there is a script */
-
-       if(access(scriptname, F_OK)) {
-               free(scriptname);
-               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
-
-       if(scriptinterpreter)
-               xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
-       else
-               xasprintf(&command, "\"%s\"", scriptname);
-
-       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);
-               }
-       }
-
-       if(status != -1) {
-#ifdef WEXITSTATUS
-               if(WIFEXITED(status)) {          /* Child exited by itself */
-                       if(WEXITSTATUS(status)) {
-                               logger(DEBUG_ALWAYS, LOG_ERR, "Script %s exited with non-zero status %d",
-                                          name, WEXITSTATUS(status));
-                               return false;
-                       }
-               } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
-                       logger(DEBUG_ALWAYS, LOG_ERR, "Script %s was killed by signal %d (%s)",
-                                  name, WTERMSIG(status), strsignal(WTERMSIG(status)));
-                       return false;
-               } else {                         /* Something strange happened */
-                       logger(DEBUG_ALWAYS, LOG_ERR, "Script %s terminated abnormally", name);
-                       return false;
-               }
-#endif
-       } else {
-               logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
-               return false;
-       }
-#endif
-       return true;
-}
index 0b296dbe343b4c5000e5d3d7c68df451f131a340..4cdf711bba0b5fa08161ce8066a0a92974e96160 100644 (file)
@@ -1,7 +1,7 @@
 /*
     process.h -- header file for process.c
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
 
     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
@@ -25,7 +25,6 @@ extern bool do_detach;
 extern bool sigalrm;
 
 extern void setup_signals(void);
-extern bool execute_script(const char *, char **);
 extern bool detach(void);
 extern bool kill_other(int);
 
index f309a40d8d6f94d066943e68cd1dd1256102210a..147c3b485b75393156ab74ac77f1fbff1637fba5 100644 (file)
@@ -38,9 +38,9 @@
 #include "netutl.h"
 #include "node.h"
 #include "prf.h"
-#include "process.h"
 #include "protocol.h"
 #include "rsa.h"
+#include "script.h"
 #include "sptps.h"
 #include "utils.h"
 #include "xalloc.h"
diff --git a/src/script.c b/src/script.c
new file mode 100644 (file)
index 0000000..9a43d53
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+    script.c -- call an external script
+    Copyright (C) 1999-2005 Ivo Timmermans,
+                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+
+    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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include "conf.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;
+       char *command;
+
+       xasprintf(&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);
+
+               const char *p = pathext;
+               bool found = false;
+               while(p && *p) {
+                       const char *q = strchr(p, ';');
+                       if(q) {
+                               memcpy(ext, p, q - p);
+                               ext[q - p] = 0;
+                               *q++;
+                       } else {
+                               strcpy(ext, p);
+                       }
+                       if((found = !access(fullname, F_OK)))
+                               break;
+                       p = q;
+               }
+               if(!found) {
+                       free(scriptname);
+                       return true;
+               }
+       } else
+#endif
+
+       if(access(scriptname, F_OK)) {
+               free(scriptname);
+               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
+
+       if(scriptinterpreter)
+               xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
+       else
+               xasprintf(&command, "\"%s\"", scriptname);
+
+       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);
+               }
+       }
+
+       if(status != -1) {
+#ifdef WEXITSTATUS
+               if(WIFEXITED(status)) {          /* Child exited by itself */
+                       if(WEXITSTATUS(status)) {
+                               logger(DEBUG_ALWAYS, LOG_ERR, "Script %s exited with non-zero status %d",
+                                          name, WEXITSTATUS(status));
+                               return false;
+                       }
+               } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
+                       logger(DEBUG_ALWAYS, LOG_ERR, "Script %s was killed by signal %d (%s)",
+                                  name, WTERMSIG(status), strsignal(WTERMSIG(status)));
+                       return false;
+               } else {                         /* Something strange happened */
+                       logger(DEBUG_ALWAYS, LOG_ERR, "Script %s terminated abnormally", name);
+                       return false;
+               }
+#endif
+       } else {
+               logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
+               return false;
+       }
+#endif
+       return true;
+}
diff --git a/src/script.h b/src/script.h
new file mode 100644 (file)
index 0000000..446a3b9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+    script.h -- header file for script.c
+    Copyright (C) 1999-2005 Ivo Timmermans,
+                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+
+    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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef __TINC_SCRIPT_H__
+#define __TINC_SCRIPT_H__
+
+extern bool execute_script(const char *, char **);
+
+#endif /* __TINC_SCRIPT_H__ */
index 3b980303e88509f67b610da486d279c60fa3efa5..7ff8f7aab518d27372fd74436eb5198546e72aa2 100644 (file)
@@ -29,7 +29,7 @@
 #include "net.h"
 #include "netutl.h"
 #include "node.h"
-#include "process.h"
+#include "script.h"
 #include "subnet.h"
 #include "utils.h"
 #include "xalloc.h"
index f133e2def81086456033a59ea74cb1f28b47ccc7..956771f7a4d0909cb580bc4d2c5ce2b9c39e042e 100644 (file)
@@ -65,6 +65,8 @@ static bool force = false;
 bool tty = true;
 bool confbasegiven = false;
 bool netnamegiven = false;
+char *scriptinterpreter = NULL;
+char *scriptextension = "";
 
 #ifdef HAVE_MINGW
 static struct WSAData wsa_state;