(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
os2-spawn.c
       1  /* Auxiliary functions for the creation of subprocesses.  OS/2 kLIBC API.
       2     Copyright (C) 2001, 2003-2023 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 <stdlib.h>
      27  #include <string.h>
      28  #include <unistd.h>
      29  #include <errno.h>
      30  
      31  #include "cloexec.h"
      32  #include "error.h"
      33  #include "gettext.h"
      34  
      35  #define _(str) gettext (str)
      36  
      37  
      38  /* Duplicates a file handle, making the copy uninheritable.
      39     Returns -1 for a file handle that is equivalent to closed.  */
      40  static int
      41  dup_noinherit (int fd)
      42  {
      43    fd = dup_cloexec (fd);
      44    if (fd < 0 && errno == EMFILE)
      45      error (EXIT_FAILURE, errno, _("_open_osfhandle failed"));
      46  
      47    return fd;
      48  }
      49  
      50  /* Returns a file descriptor equivalent to FD, except that the resulting file
      51     descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
      52     FD must be open and non-inheritable.  The result will be non-inheritable as
      53     well.
      54     If FD < 0, FD itself is returned.  */
      55  static int
      56  fd_safer_noinherit (int fd)
      57  {
      58    if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
      59      {
      60        /* The recursion depth is at most 3.  */
      61        int nfd = fd_safer_noinherit (dup_noinherit (fd));
      62        int saved_errno = errno;
      63        close (fd);
      64        errno = saved_errno;
      65        return nfd;
      66      }
      67    return fd;
      68  }
      69  
      70  int
      71  dup_safer_noinherit (int fd)
      72  {
      73    return fd_safer_noinherit (dup_noinherit (fd));
      74  }
      75  
      76  void
      77  undup_safer_noinherit (int tempfd, int origfd)
      78  {
      79    if (tempfd >= 0)
      80      {
      81        if (dup2 (tempfd, origfd) < 0)
      82          error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"),
      83                 origfd);
      84        close (tempfd);
      85      }
      86    else
      87      {
      88        /* origfd was closed or open to no handle at all.  Set it to a closed
      89           state.  This is (nearly) equivalent to the original state.  */
      90        close (origfd);
      91      }
      92  }
      93  
      94  const char **
      95  prepare_spawn (const char * const *argv, char **mem_to_free)
      96  {
      97    size_t argc;
      98    const char **new_argv;
      99    size_t i;
     100  
     101    /* Count number of arguments.  */
     102    for (argc = 0; argv[argc] != NULL; argc++)
     103      ;
     104  
     105    /* Allocate new argument vector.  */
     106    new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
     107    if (new_argv == NULL)
     108      return NULL;
     109  
     110    /* Add an element upfront that can be used when argv[0] turns out to be a
     111       script, not a program.
     112       On Unix, this would be "/bin/sh".  */
     113    new_argv[0] = "sh.exe";
     114  
     115    /* Put quoted arguments into the new argument vector.  */
     116    size_t needed_size = 0;
     117    for (i = 0; i < argc; i++)
     118      {
     119        const char *string = argv[i];
     120        const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
     121        size_t length = strlen (quoted_string);
     122        needed_size += length + 1;
     123      }
     124  
     125    char *mem;
     126    if (needed_size == 0)
     127      mem = NULL;
     128    else
     129      {
     130        mem = (char *) malloc (needed_size);
     131        if (mem == NULL)
     132          {
     133            /* Memory allocation failure.  */
     134            free (new_argv);
     135            errno = ENOMEM;
     136            return NULL;
     137          }
     138      }
     139    *mem_to_free = mem;
     140  
     141    for (i = 0; i < argc; i++)
     142      {
     143        const char *string = argv[i];
     144  
     145        new_argv[1 + i] = mem;
     146        const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
     147        size_t length = strlen (quoted_string);
     148        memcpy (mem, quoted_string, length + 1);
     149        mem += length + 1;
     150      }
     151    new_argv[1 + argc] = NULL;
     152  
     153    return new_argv;
     154  }