(root)/
m4-1.4.19/
lib/
os2-spawn.c
       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)
      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)
      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)
      73  {
      74    return fd_safer_noinherit (dup_noinherit (fd));
      75  }
      76  
      77  void
      78  undup_safer_noinherit (int tempfd, int origfd)
      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)
      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  }