From b22499668a7aa63c619cb8fa8535282a38841ce9 Mon Sep 17 00:00:00 2001 From: Etienne Dechamps Date: Sat, 12 Jul 2014 18:37:56 +0100 Subject: [PATCH 1/2] Fix "tinc start" on Windows when the path contains spaces. When invoking "tinc start" with spaces in the path, the following happens: > "c:\Program Files (x86)\tinc\tinc.exe" start c:\Program: unrecognized argument 'Files' Try `c:\Program --help' for more information. This is caused by inconsistent handling of command line strings between execvp() and the spawned process' CRT, as documented on MSDN: http://msdn.microsoft.com/library/431x4c1w.aspx --- src/tincctl.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/tincctl.c b/src/tincctl.c index 6227750c..12cffebc 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -810,7 +810,19 @@ static int cmd_start(int argc, char *argv[]) { int nargc = 0; char **nargv = xzalloc((optind + argc) * sizeof *nargv); - nargv[nargc++] = c; + char *arg0 = c; +#ifdef HAVE_MINGW + /* + Windows has no real concept of an "argv array". A command line is just one string. + The CRT of the new process will decode the command line string to generate argv before calling main(), and (by convention) + it uses quotes to handle spaces in arguments. + Therefore we need to quote all arguments that might contain spaces. No, execvp() won't do that for us (see MSDN). + If we don't do that, then execvp() will run fine but any spaces in the filename contained in arg0 will bleed + into the next arguments when the spawned process' CRT parses its command line, resulting in chaos. + */ + xasprintf(&arg0, "\"%s\"", arg0); +#endif + nargv[nargc++] = arg0; for(int i = 1; i < optind; i++) nargv[nargc++] = orig_argv[i]; for(int i = 1; i < argc; i++) From ea12a0fb066793c316ccc9ef21444f092f74b4ba Mon Sep 17 00:00:00 2001 From: Etienne Dechamps Date: Sat, 12 Jul 2014 18:53:25 +0100 Subject: [PATCH 2/2] Improve subprocess behavior in tinc start command. When invoking tincd, tinc start currently uses the execvp() function, which doesn't behave well in a console as the console displays a new prompt before the subprocess finishes (which makes me suspect the exit value is not handled at all). This new code uses spawnvp() instead, which seems like a better fit. --- src/tincctl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tincctl.c b/src/tincctl.c index 12cffebc..f4379b7f 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -829,9 +829,12 @@ static int cmd_start(int argc, char *argv[]) { nargv[nargc++] = argv[i]; #ifdef HAVE_MINGW - execvp(c, nargv); - fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno)); - return 1; + int status = spawnvp(_P_WAIT, c, nargv); + if (status == -1) { + fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno)); + return 1; + } + return status; #else pid_t pid = fork(); if(pid == -1) {