gettimeofday: port recent C++ fix to Emacs
[gnulib.git] / lib / w32spawn.h
index 7ebbb4c..3b5c08a 100644 (file)
@@ -1,5 +1,5 @@
-/* Auxiliary functions for the creation of subprocesses.  Native Woe32 API.
-   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
+/* Auxiliary functions for the creation of subprocesses.  Native Windows API.
+   Copyright (C) 2001, 2003-2013 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2003.
 
    This program is free software: you can redistribute it and/or modify
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* Get declarations of the Win32 API functions.  */
+/* Get declarations of the native Windows API functions.  */
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
-/* Get _get_osfhandle() and _open_osfhandle().  */
+/* Get _open_osfhandle().  */
 #include <io.h>
 
 #include <stdbool.h>
 #include <string.h>
+#include <unistd.h>
 #include <errno.h>
 
+/* Get _get_osfhandle().  */
+#include "msvc-nothrow.h"
+
+#include "cloexec.h"
 #include "xalloc.h"
 
-/* Duplicates a file handle, making the copy uninheritable.  */
+/* Duplicates a file handle, making the copy uninheritable.
+   Returns -1 for a file handle that is equivalent to closed.  */
 static int
 dup_noinherit (int fd)
 {
-  HANDLE curr_process = GetCurrentProcess ();
-  HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
-  HANDLE new_handle;
-  int nfd;
-
-  if (!DuplicateHandle (curr_process,              /* SourceProcessHandle */
-                       old_handle,                 /* SourceHandle */
-                       curr_process,               /* TargetProcessHandle */
-                       (PHANDLE) &new_handle,      /* TargetHandle */
-                       (DWORD) 0,                  /* DesiredAccess */
-                       FALSE,                      /* InheritHandle */
-                       DUPLICATE_SAME_ACCESS))     /* Options */
-    error (EXIT_FAILURE, 0, _("DuplicateHandle failed with error code 0x%08x"),
-          GetLastError ());
-
-  nfd = _open_osfhandle ((long) new_handle, O_BINARY);
-  if (nfd < 0)
+  fd = dup_cloexec (fd);
+  if (fd < 0 && errno == EMFILE)
     error (EXIT_FAILURE, errno, _("_open_osfhandle failed"));
 
-  return nfd;
+  return fd;
+}
+
+/* Returns a file descriptor equivalent to FD, except that the resulting file
+   descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
+   FD must be open and non-inheritable.  The result will be non-inheritable as
+   well.
+   If FD < 0, FD itself is returned.  */
+static int
+fd_safer_noinherit (int fd)
+{
+  if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
+    {
+      /* The recursion depth is at most 3.  */
+      int nfd = fd_safer_noinherit (dup_noinherit (fd));
+      int saved_errno = errno;
+      close (fd);
+      errno = saved_errno;
+      return nfd;
+    }
+  return fd;
+}
+
+/* Duplicates a file handle, making the copy uninheritable and ensuring the
+   result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
+   Returns -1 for a file handle that is equivalent to closed.  */
+static int
+dup_safer_noinherit (int fd)
+{
+  return fd_safer_noinherit (dup_noinherit (fd));
+}
+
+/* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD);  */
+static void
+undup_safer_noinherit (int tempfd, int origfd)
+{
+  if (tempfd >= 0)
+    {
+      if (dup2 (tempfd, origfd) < 0)
+        error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"),
+               origfd);
+      close (tempfd);
+    }
+  else
+    {
+      /* origfd was closed or open to no handle at all.  Set it to a closed
+         state.  This is (nearly) equivalent to the original state.  */
+      close (origfd);
+    }
 }
 
 /* Prepares an argument vector before calling spawn().
@@ -62,7 +101,7 @@ dup_noinherit (int fd)
          v.dwPlatformId == VER_PLATFORM_WIN32_NT;
       }) ? "cmd.exe" : "command.com").
    Instead it simply concatenates the arguments, separated by ' ', and calls
-   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   CreateProcess().  We must quote the arguments since Windows CreateProcess()
    interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
    special way:
    - Space and tab are interpreted as delimiters. They are not treated as
@@ -76,8 +115,15 @@ dup_noinherit (int fd)
        \" -> "
        \\\" -> \"
        \\\\\" -> \\"
+   - '*', '?' characters may get expanded through wildcard expansion in the
+     callee: By default, in the callee, the initialization code before main()
+     takes the result of GetCommandLine(), wildcard-expands it, and passes it
+     to main(). The exceptions to this rule are:
+       - programs that inspect GetCommandLine() and ignore argv,
+       - mingw programs that have a global variable 'int _CRT_glob = 0;',
+       - Cygwin programs, when invoked from a Cygwin program.
  */
-#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?"
 #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
 static char **
 prepare_spawn (char **argv)
@@ -91,7 +137,15 @@ prepare_spawn (char **argv)
     ;
 
   /* Allocate new argument vector.  */
-  new_argv = XNMALLOC (argc + 1, char *);
+  new_argv = XNMALLOC (1 + argc + 1, char *);
+
+  /* Add an element upfront that can be used when argv[0] turns out to be a
+     script, not a program.
+     On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
+     "sh.exe".  We have to omit the directory part and rely on the search in
+     PATH, because the mingw "mount points" are not visible inside Windows
+     CreateProcess().  */
+  *new_argv++ = "sh.exe";
 
   /* Put quoted arguments into the new argument vector.  */
   for (i = 0; i < argc; i++)
@@ -99,68 +153,68 @@ prepare_spawn (char **argv)
       const char *string = argv[i];
 
       if (string[0] == '\0')
-       new_argv[i] = xstrdup ("\"\"");
+        new_argv[i] = xstrdup ("\"\"");
       else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
-       {
-         bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
-         size_t length;
-         unsigned int backslashes;
-         const char *s;
-         char *quoted_string;
-         char *p;
-
-         length = 0;
-         backslashes = 0;
-         if (quote_around)
-           length++;
-         for (s = string; *s != '\0'; s++)
-           {
-             char c = *s;
-             if (c == '"')
-               length += backslashes + 1;
-             length++;
-             if (c == '\\')
-               backslashes++;
-             else
-               backslashes = 0;
-           }
-         if (quote_around)
-           length += backslashes + 1;
-
-         quoted_string = (char *) xmalloc (length + 1);
-
-         p = quoted_string;
-         backslashes = 0;
-         if (quote_around)
-           *p++ = '"';
-         for (s = string; *s != '\0'; s++)
-           {
-             char c = *s;
-             if (c == '"')
-               {
-                 unsigned int j;
-                 for (j = backslashes + 1; j > 0; j--)
-                   *p++ = '\\';
-               }
-             *p++ = c;
-             if (c == '\\')
-               backslashes++;
-             else
-               backslashes = 0;
-           }
-         if (quote_around)
-           {
-             unsigned int j;
-             for (j = backslashes; j > 0; j--)
-               *p++ = '\\';
-             *p++ = '"';
-           }
-         *p = '\0';
-
-         new_argv[i] = quoted_string;
-       }
+        {
+          bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+          size_t length;
+          unsigned int backslashes;
+          const char *s;
+          char *quoted_string;
+          char *p;
+
+          length = 0;
+          backslashes = 0;
+          if (quote_around)
+            length++;
+          for (s = string; *s != '\0'; s++)
+            {
+              char c = *s;
+              if (c == '"')
+                length += backslashes + 1;
+              length++;
+              if (c == '\\')
+                backslashes++;
+              else
+                backslashes = 0;
+            }
+          if (quote_around)
+            length += backslashes + 1;
+
+          quoted_string = (char *) xmalloc (length + 1);
+
+          p = quoted_string;
+          backslashes = 0;
+          if (quote_around)
+            *p++ = '"';
+          for (s = string; *s != '\0'; s++)
+            {
+              char c = *s;
+              if (c == '"')
+                {
+                  unsigned int j;
+                  for (j = backslashes + 1; j > 0; j--)
+                    *p++ = '\\';
+                }
+              *p++ = c;
+              if (c == '\\')
+                backslashes++;
+              else
+                backslashes = 0;
+            }
+          if (quote_around)
+            {
+              unsigned int j;
+              for (j = backslashes; j > 0; j--)
+                *p++ = '\\';
+              *p++ = '"';
+            }
+          *p = '\0';
+
+          new_argv[i] = quoted_string;
+        }
       else
-       new_argv[i] = (char *) string;
+        new_argv[i] = (char *) string;
     }
   new_argv[argc] = NULL;