Back to index

cell-binutils  2.17cvs20070401
Defines | Functions | Variables
pex-win32.c File Reference
#include "pex-common.h"
#include <windows.h>
#include <assert.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>

Go to the source code of this file.

Defines

#define _P_WAIT   0
#define _P_NOWAIT   1
#define _P_OVERLAY   2
#define _P_NOWAITO   3
#define _P_DETACH   4
#define WAIT_CHILD   0
#define WAIT_GRANDCHILD   1
#define MINGW_NAME   "Minimalist GNU for Windows"
#define MINGW_NAME_LEN   (sizeof(MINGW_NAME) - 1)

Functions

char * stpcpy (char *dst, const char *src)
static void backslashify (char *s)
static int pex_win32_open_read (struct pex_obj *, const char *, int)
static int pex_win32_open_write (struct pex_obj *, const char *, int)
static long pex_win32_exec_child (struct pex_obj *, int, const char *, char *const *, char *const *, int, int, int, int, const char **, int *)
static int pex_win32_close (struct pex_obj *, int)
static int pex_win32_wait (struct pex_obj *, long, int *, struct pex_time *, int, const char **, int *)
static int pex_win32_pipe (struct pex_obj *, int *, int)
static FILE * pex_win32_fdopenr (struct pex_obj *, int, int)
static FILE * pex_win32_fdopenw (struct pex_obj *, int, int)
struct pex_objpex_init (int flags, const char *pname, const char *tempbase)
static int pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, int binary)
static int pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, int binary)
static int pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
static char * argv_to_cmdline (char *const *argv)
static char * find_executable (const char *program, BOOL search)
static int env_compare (const void *a_ptr, const void *b_ptr)
static long win32_spawn (const char *executable, BOOL search, char *const *argv, char *const *env, DWORD dwCreationFlags, LPSTARTUPINFO si, LPPROCESS_INFORMATION pi)
static long spawn_script (const char *executable, char *const *argv, char *const *env, DWORD dwCreationFlags, LPSTARTUPINFO si, LPPROCESS_INFORMATION pi)
static long pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags, const char *executable, char *const *argv, char *const *env, int in, int out, int errdes, int toclose ATTRIBUTE_UNUSED, const char **errmsg, int *err)
static int pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid, int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED, const char **errmsg, int *err)
static int pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, int binary)
static FILE * pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, int binary)
static FILE * pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, int binary)

Variables

static const char *const std_suffixes []

Define Documentation

#define _P_DETACH   4

Definition at line 55 of file pex-win32.c.

#define _P_NOWAIT   1

Definition at line 52 of file pex-win32.c.

#define _P_NOWAITO   3

Definition at line 54 of file pex-win32.c.

#define _P_OVERLAY   2

Definition at line 53 of file pex-win32.c.

#define _P_WAIT   0

Definition at line 51 of file pex-win32.c.

#define MINGW_NAME   "Minimalist GNU for Windows"

Definition at line 61 of file pex-win32.c.

#define MINGW_NAME_LEN   (sizeof(MINGW_NAME) - 1)

Definition at line 62 of file pex-win32.c.

#define WAIT_CHILD   0

Definition at line 57 of file pex-win32.c.

#define WAIT_GRANDCHILD   1

Definition at line 58 of file pex-win32.c.


Function Documentation

static char* argv_to_cmdline ( char *const argv) [static]

Definition at line 328 of file pex-win32.c.

{
  char *cmdline;
  char *p;
  size_t cmdline_len;
  int i, j, k;

  cmdline_len = 0;
  for (i = 0; argv[i]; i++)
    {
      /* We quote every last argument.  This simplifies the problem;
        we need only escape embedded double-quotes and immediately
        preceeding backslash characters.  A sequence of backslach characters
        that is not follwed by a double quote character will not be
        escaped.  */
      for (j = 0; argv[i][j]; j++)
       {
         if (argv[i][j] == '"')
           {
             /* Escape preceeding backslashes.  */
             for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
              cmdline_len++;
             /* Escape the qote character.  */
             cmdline_len++;
           }
       }
      /* Trailing backslashes also need to be escaped because they will be
         followed by the terminating quote.  */
      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
       cmdline_len++;
      cmdline_len += j;
      cmdline_len += 3;  /* for leading and trailing quotes and space */
    }
  cmdline = XNEWVEC (char, cmdline_len);
  p = cmdline;
  for (i = 0; argv[i]; i++)
    {
      *p++ = '"';
      for (j = 0; argv[i][j]; j++)
       {
         if (argv[i][j] == '"')
           {
             for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
              *p++ = '\\';
             *p++ = '\\';
           }
         *p++ = argv[i][j];
       }
      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
       *p++ = '\\';
      *p++ = '"';
      *p++ = ' ';
    }
  p[-1] = '\0';
  return cmdline;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void backslashify ( char *  s) [static]

Definition at line 73 of file pex-win32.c.

{
  while ((s = strchr (s, '/')) != NULL)
    *s = '\\';
  return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int env_compare ( const void *  a_ptr,
const void *  b_ptr 
) [static]

Definition at line 490 of file pex-win32.c.

{
  const char *a;
  const char *b;
  unsigned char c1;
  unsigned char c2;

  a = *(const char **) a_ptr;
  b = *(const char **) b_ptr;

  /* a and b will be of the form: VAR=VALUE
     We compare only the variable name part here using a case-insensitive
     comparison algorithm.  It might appear that in fact strcasecmp () can
     take the place of this whole function, and indeed it could, save for
     the fact that it would fail in cases such as comparing A1=foo and
     A=bar (because 1 is less than = in the ASCII character set).
     (Environment variables containing no numbers would work in such a
     scenario.)  */

  do
    {
      c1 = (unsigned char) tolower (*a++);
      c2 = (unsigned char) tolower (*b++);

      if (c1 == '=')
        c1 = '\0';

      if (c2 == '=')
        c2 = '\0';
    }
  while (c1 == c2 && c1 != '\0');

  return c1 - c2;
}

Here is the caller graph for this function:

static char* find_executable ( const char *  program,
BOOL  search 
) [static]

Definition at line 405 of file pex-win32.c.

{
  char *full_executable;
  char *e;
  size_t fe_len;
  const char *path = 0;
  const char *const *ext;
  const char *p, *q;
  size_t proglen = strlen (program);
  int has_slash = (strchr (program, '/') || strchr (program, '\\'));
  HANDLE h;

  if (has_slash)
    search = FALSE;

  if (search)
    path = getenv ("PATH");
  if (!path)
    path = "";

  fe_len = 0;
  for (p = path; *p; p = q)
    {
      q = p;
      while (*q != ';' && *q != '\0')
       q++;
      if ((size_t)(q - p) > fe_len)
       fe_len = q - p;
      if (*q == ';')
       q++;
    }
  fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
  full_executable = XNEWVEC (char, fe_len);

  p = path;
  do
    {
      q = p;
      while (*q != ';' && *q != '\0')
       q++;

      e = full_executable;
      memcpy (e, p, q - p);
      e += (q - p);
      if (q - p)
       *e++ = '\\';
      strcpy (e, program);

      if (*q == ';')
       q++;

      for (e = full_executable; *e; e++)
       if (*e == '/')
         *e = '\\';

      /* At this point, e points to the terminating NUL character for
         full_executable.  */
      for (ext = std_suffixes; *ext; ext++)
       {
         /* Remove any current extension.  */
         *e = '\0';
         /* Add the new one.  */
         strcat (full_executable, *ext);

         /* Attempt to open this file.  */
         h = CreateFile (full_executable, GENERIC_READ,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
         if (h != INVALID_HANDLE_VALUE)
           goto found;
       }
      p = q;
    }
  while (*p);
  free (full_executable);
  return 0;

 found:
  CloseHandle (h);
  return full_executable;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct pex_obj* pex_init ( int  flags,
const char *  pname,
const char *  tempbase 
) [read]

Definition at line 111 of file pex-win32.c.

{
  return pex_init_common (flags, pname, tempbase, &funcs);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pex_win32_close ( struct pex_obj ,
int   
) [static]
static int pex_win32_close ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
int  fd 
) [static]

Definition at line 142 of file pex-win32.c.

{
  return _close (fd);
}
static long pex_win32_exec_child ( struct pex_obj ,
int  ,
const char *  ,
char *const ,
char *const ,
int  ,
int  ,
int  ,
int  ,
const char **  ,
int  
) [static]
static long pex_win32_exec_child ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
int  flags,
const char *  executable,
char *const argv,
char *const env,
int  in,
int  out,
int  errdes,
int toclose  ATTRIBUTE_UNUSED,
const char **  errmsg,
int err 
) [static]

Definition at line 700 of file pex-win32.c.

{
  long pid;
  HANDLE stdin_handle;
  HANDLE stdout_handle;
  HANDLE stderr_handle;
  DWORD dwCreationFlags;
  OSVERSIONINFO version_info;
  STARTUPINFO si;
  PROCESS_INFORMATION pi;

  stdin_handle = INVALID_HANDLE_VALUE;
  stdout_handle = INVALID_HANDLE_VALUE;
  stderr_handle = INVALID_HANDLE_VALUE;

  stdin_handle = (HANDLE) _get_osfhandle (in);
  stdout_handle = (HANDLE) _get_osfhandle (out);
  if (!(flags & PEX_STDERR_TO_STDOUT))
    stderr_handle = (HANDLE) _get_osfhandle (errdes);
  else
    stderr_handle = stdout_handle;

  /* Determine the version of Windows we are running on.  */
  version_info.dwOSVersionInfoSize = sizeof (version_info); 
  GetVersionEx (&version_info);
  if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
    /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
       supported, so we cannot avoid creating a console window.  */
    dwCreationFlags = 0;
  else
    {
      HANDLE conout_handle;

      /* Determine whether or not we have an associated console.  */
      conout_handle = CreateFile("CONOUT$", 
                             GENERIC_WRITE,
                             FILE_SHARE_WRITE,
                             /*lpSecurityAttributes=*/NULL,
                             OPEN_EXISTING,
                             FILE_ATTRIBUTE_NORMAL,
                             /*hTemplateFile=*/NULL);
      if (conout_handle == INVALID_HANDLE_VALUE)
       /* There is no console associated with this process.  Since
          the child is a console process, the OS would normally
          create a new console Window for the child.  Since we'll be
          redirecting the child's standard streams, we do not need
          the console window.  */ 
       dwCreationFlags = CREATE_NO_WINDOW;
      else 
       {
         /* There is a console associated with the process, so the OS
            will not create a new console.  And, if we use
            CREATE_NO_WINDOW in this situation, the child will have
            no associated console.  Therefore, if the child's
            standard streams are connected to the console, the output
            will be discarded.  */
         CloseHandle(conout_handle);
         dwCreationFlags = 0;
       }
    }

  /* Since the child will be a console process, it will, by default,
     connect standard input/output to its console.  However, we want
     the child to use the handles specifically designated above.  In
     addition, if there is no console (such as when we are running in
     a Cygwin X window), then we must redirect the child's
     input/output, as there is no console for the child to use.  */
  memset (&si, 0, sizeof (si));
  si.cb = sizeof (si);
  si.dwFlags = STARTF_USESTDHANDLES;
  si.hStdInput = stdin_handle;
  si.hStdOutput = stdout_handle;
  si.hStdError = stderr_handle;

  /* Create the child process.  */  
  pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
                   argv, env, dwCreationFlags, &si, &pi);
  if (pid == -1)
    pid = spawn_script (executable, argv, env, dwCreationFlags,
                        &si, &pi);
  if (pid == -1)
    {
      *err = ENOENT;
      *errmsg = "CreateProcess";
    }

  /* Close the standard output and standard error handles in the
     parent.  */ 
  if (out != STDOUT_FILENO)
    obj->funcs->close (obj, out);
  if (errdes != STDERR_FILENO)
    obj->funcs->close (obj, errdes);

  return pid;
}

Here is the call graph for this function:

static FILE* pex_win32_fdopenr ( struct pex_obj ,
int  ,
int   
) [static]
static FILE* pex_win32_fdopenr ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
int  fd,
int  binary 
) [static]

Definition at line 859 of file pex-win32.c.

{
  return fdopen (fd, binary ? "rb" : "r");
}
static FILE* pex_win32_fdopenw ( struct pex_obj ,
int  ,
int   
) [static]
static FILE* pex_win32_fdopenw ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
int  fd,
int  binary 
) [static]

Definition at line 866 of file pex-win32.c.

{
  HANDLE h = (HANDLE) _get_osfhandle (fd);
  if (h == INVALID_HANDLE_VALUE)
    return NULL;
  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
    return NULL;
  return fdopen (fd, binary ? "wb" : "w");
}
static int pex_win32_open_read ( struct pex_obj ,
const char *  ,
int   
) [static]
static int pex_win32_open_read ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
const char *  name,
int  binary 
) [static]

Definition at line 119 of file pex-win32.c.

{
  return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
}
static int pex_win32_open_write ( struct pex_obj ,
const char *  ,
int   
) [static]
static int pex_win32_open_write ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
const char *  name,
int  binary 
) [static]

Definition at line 128 of file pex-win32.c.

{
  /* Note that we can't use O_EXCL here because gcc may have already
     created the temporary file via make_temp_file.  */
  return _open (name,
              (_O_WRONLY | _O_CREAT | _O_TRUNC
               | (binary ? _O_BINARY : _O_TEXT)),
              _S_IREAD | _S_IWRITE);
}
static int pex_win32_pipe ( struct pex_obj ,
int ,
int   
) [static]
static int pex_win32_pipe ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
int p,
int  binary 
) [static]

Definition at line 850 of file pex-win32.c.

{
  return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
}
static int pex_win32_wait ( struct pex_obj ,
long  ,
int ,
struct pex_time ,
int  ,
const char **  ,
int  
) [static]
static int pex_win32_wait ( struct pex_obj *obj  ATTRIBUTE_UNUSED,
long  pid,
int status,
struct pex_time time,
int done  ATTRIBUTE_UNUSED,
const char **  errmsg,
int err 
) [static]

Definition at line 811 of file pex-win32.c.

{
  DWORD termstat;
  HANDLE h;

  if (time != NULL)
    memset (time, 0, sizeof *time);

  h = (HANDLE) pid;

  /* FIXME: If done is non-zero, we should probably try to kill the
     process.  */
  if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
    {
      CloseHandle (h);
      *err = ECHILD;
      *errmsg = "WaitForSingleObject";
      return -1;
    }

  GetExitCodeProcess (h, &termstat);
  CloseHandle (h);
 
  /* A value of 3 indicates that the child caught a signal, but not
     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
     report SIGABRT.  */
  if (termstat == 3)
    *status = SIGABRT;
  else
    *status = (termstat & 0xff) << 8;

  return 0;
}

Here is the call graph for this function:

static long spawn_script ( const char *  executable,
char *const argv,
char *const env,
DWORD  dwCreationFlags,
LPSTARTUPINFO  si,
LPPROCESS_INFORMATION  pi 
) [static]

Definition at line 623 of file pex-win32.c.

{
  int pid = -1;
  int save_errno = errno;
  int fd = _open (executable, _O_RDONLY);

  if (fd >= 0)
    {
      char buf[MAX_PATH + 5];
      int len = _read (fd, buf, sizeof (buf) - 1);
      _close (fd);
      if (len > 3)
       {
         char *eol;
         buf[len] = '\0';
         eol = strchr (buf, '\n');
         if (eol && strncmp (buf, "#!", 2) == 0)
           {
             char *executable1;
             const char ** avhere = (const char **) --argv;
             do
              *eol = '\0';
             while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
             for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
              continue;

             backslashify (executable1);
             *avhere = executable1;
#ifndef USE_MINGW_MSYS
             executable = strrchr (executable1, '\\') + 1;
             if (!executable)
              executable = executable1;
             pid = win32_spawn (executable, TRUE, argv, env,
                             dwCreationFlags, si, pi);
#else
             if (strchr (executable1, '\\') == NULL)
              pid = win32_spawn (executable1, TRUE, argv, env,
                               dwCreationFlags, si, pi);
             else if (executable1[0] != '\\')
              pid = win32_spawn (executable1, FALSE, argv, env,
                               dwCreationFlags, si, pi);
             else
              {
                const char *newex = mingw_rootify (executable1);
                *avhere = newex;
                pid = win32_spawn (newex, FALSE, argv, env,
                                 dwCreationFlags, si, pi);
                if (executable1 != newex)
                  free ((char *) newex);
                if (pid < 0)
                  {
                    newex = msys_rootify (executable1);
                    if (newex != executable1)
                     {
                       *avhere = newex;
                       pid = win32_spawn (newex, FALSE, argv, env,
                                        dwCreationFlags, si, pi);
                       free ((char *) newex);
                     }
                  }
              }
#endif
           }
       }
    }
  if (pid < 0)
    errno = save_errno;
  return pid;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* stpcpy ( char *  dst,
const char *  src 
)

Definition at line 39 of file stpcpy.c.

{
  const size_t len = strlen (src);
  return (char *) memcpy (dst, src, len + 1) + len;
}

Here is the call graph for this function:

static long win32_spawn ( const char *  executable,
BOOL  search,
char *const argv,
char *const env,
DWORD  dwCreationFlags,
LPSTARTUPINFO  si,
LPPROCESS_INFORMATION  pi 
) [static]

Definition at line 526 of file pex-win32.c.

{
  char *full_executable;
  char *cmdline;
  char **env_copy;
  char *env_block = NULL;

  full_executable = NULL;
  cmdline = NULL;

  if (env)
    {
      int env_size;

      /* Count the number of environment bindings supplied.  */
      for (env_size = 0; env[env_size]; env_size++)
        continue;
    
      /* Assemble an environment block, if required.  This consists of
         VAR=VALUE strings juxtaposed (with one null character between each
         pair) and an additional null at the end.  */
      if (env_size > 0)
        {
          int var;
          int total_size = 1; /* 1 is for the final null.  */
          char *bufptr;
    
          /* Windows needs the members of the block to be sorted by variable
             name.  */
          env_copy = (char **) alloca (sizeof (char *) * env_size);
          memcpy (env_copy, env, sizeof (char *) * env_size);
          qsort (env_copy, env_size, sizeof (char *), env_compare);
    
          for (var = 0; var < env_size; var++)
            total_size += strlen (env[var]) + 1;
    
          env_block = XNEWVEC (char, total_size);
          bufptr = env_block;
          for (var = 0; var < env_size; var++)
            bufptr = stpcpy (bufptr, env_copy[var]) + 1;
    
          *bufptr = '\0';
        }
    }

  full_executable = find_executable (executable, search);
  if (!full_executable)
    goto error;
  cmdline = argv_to_cmdline (argv);
  if (!cmdline)
    goto error;
    
  /* Create the child process.  */  
  if (!CreateProcess (full_executable, cmdline, 
                    /*lpProcessAttributes=*/NULL,
                    /*lpThreadAttributes=*/NULL,
                    /*bInheritHandles=*/TRUE,
                    dwCreationFlags,
                    (LPVOID) env_block,
                    /*lpCurrentDirectory=*/NULL,
                    si,
                    pi))
    {
      if (env_block)
        free (env_block);

      free (full_executable);

      return -1;
    }

  /* Clean up.  */
  CloseHandle (pi->hThread);
  free (full_executable);
  if (env_block)
    free (env_block);

  return (long) pi->hProcess;

 error:
  if (env_block)
    free (env_block);
  if (cmdline)
    free (cmdline);
  if (full_executable)
    free (full_executable);

  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char* const std_suffixes[] [static]
Initial value:
 {
  ".com",
  ".exe",
  ".bat",
  ".cmd",
  "",
  0
}

Definition at line 392 of file pex-win32.c.