root/maint/gnulib/lib/os2-spawn.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dup_noinherit
  2. fd_safer_noinherit
  3. dup_safer_noinherit
  4. undup_safer_noinherit
  5. prepare_spawn

   1 /* Auxiliary functions for the creation of subprocesses.  OS/2 kLIBC API.
   2    Copyright (C) 2001, 2003-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <bruno@clisp.org>, 2003.
   4 
   5    This program is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU General Public License as published by
   7    the Free Software Foundation; either version 3 of the License, or
   8    (at your option) any later version.
   9 
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU General Public License for more details.
  14 
  15    You should have received a copy of the GNU General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 /* Specification.  */
  21 #include "os2-spawn.h"
  22 
  23 /* Get _open_osfhandle().  */
  24 #include <io.h>
  25 
  26 #include <stdbool.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <unistd.h>
  30 #include <errno.h>
  31 
  32 #include "cloexec.h"
  33 #include "error.h"
  34 #include "gettext.h"
  35 
  36 #define _(str) gettext (str)
  37 
  38 
  39 /* Duplicates a file handle, making the copy uninheritable.
  40    Returns -1 for a file handle that is equivalent to closed.  */
  41 static int
  42 dup_noinherit (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44   fd = dup_cloexec (fd);
  45   if (fd < 0 && errno == EMFILE)
  46     error (EXIT_FAILURE, errno, _("_open_osfhandle failed"));
  47 
  48   return fd;
  49 }
  50 
  51 /* Returns a file descriptor equivalent to FD, except that the resulting file
  52    descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
  53    FD must be open and non-inheritable.  The result will be non-inheritable as
  54    well.
  55    If FD < 0, FD itself is returned.  */
  56 static int
  57 fd_safer_noinherit (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59   if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
  60     {
  61       /* The recursion depth is at most 3.  */
  62       int nfd = fd_safer_noinherit (dup_noinherit (fd));
  63       int saved_errno = errno;
  64       close (fd);
  65       errno = saved_errno;
  66       return nfd;
  67     }
  68   return fd;
  69 }
  70 
  71 int
  72 dup_safer_noinherit (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74   return fd_safer_noinherit (dup_noinherit (fd));
  75 }
  76 
  77 void
  78 undup_safer_noinherit (int tempfd, int origfd)
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80   if (tempfd >= 0)
  81     {
  82       if (dup2 (tempfd, origfd) < 0)
  83         error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"),
  84                origfd);
  85       close (tempfd);
  86     }
  87   else
  88     {
  89       /* origfd was closed or open to no handle at all.  Set it to a closed
  90          state.  This is (nearly) equivalent to the original state.  */
  91       close (origfd);
  92     }
  93 }
  94 
  95 const char **
  96 prepare_spawn (const char * const *argv, char **mem_to_free)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98   size_t argc;
  99   const char **new_argv;
 100   size_t i;
 101 
 102   /* Count number of arguments.  */
 103   for (argc = 0; argv[argc] != NULL; argc++)
 104     ;
 105 
 106   /* Allocate new argument vector.  */
 107   new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
 108   if (new_argv == NULL)
 109     return NULL;
 110 
 111   /* Add an element upfront that can be used when argv[0] turns out to be a
 112      script, not a program.
 113      On Unix, this would be "/bin/sh".  */
 114   new_argv[0] = "sh.exe";
 115 
 116   /* Put quoted arguments into the new argument vector.  */
 117   size_t needed_size = 0;
 118   for (i = 0; i < argc; i++)
 119     {
 120       const char *string = argv[i];
 121       const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
 122       size_t length = strlen (quoted_string);
 123       needed_size += length + 1;
 124     }
 125 
 126   char *mem;
 127   if (needed_size == 0)
 128     mem = NULL;
 129   else
 130     {
 131       mem = (char *) malloc (needed_size);
 132       if (mem == NULL)
 133         {
 134           /* Memory allocation failure.  */
 135           free (new_argv);
 136           errno = ENOMEM;
 137           return NULL;
 138         }
 139     }
 140   *mem_to_free = mem;
 141 
 142   for (i = 0; i < argc; i++)
 143     {
 144       const char *string = argv[i];
 145 
 146       new_argv[1 + i] = mem;
 147       const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
 148       size_t length = strlen (quoted_string);
 149       memcpy (mem, quoted_string, length + 1);
 150       mem += length + 1;
 151     }
 152   new_argv[1 + argc] = NULL;
 153 
 154   return new_argv;
 155 }

/* [previous][next][first][last][top][bottom][index][help] */