(root)/
bison-3.8.2/
lib/
pipe2.c
       1  /* Create a pipe, with specific opening flags.
       2     Copyright (C) 2009-2021 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <unistd.h>
      21  
      22  #include <errno.h>
      23  #include <fcntl.h>
      24  
      25  #include "binary-io.h"
      26  #include "verify.h"
      27  
      28  #if GNULIB_defined_O_NONBLOCK
      29  # include "nonblocking.h"
      30  #endif
      31  
      32  #if defined _WIN32 && ! defined __CYGWIN__
      33  /* Native Windows API.  */
      34  
      35  # include <io.h>
      36  
      37  #endif
      38  
      39  int
      40  pipe2 (int fd[2], int flags)
      41  {
      42    /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
      43       creating the pipe but later fail at changing fcntl, we want
      44       to leave fd unchanged: http://austingroupbugs.net/view.php?id=467  */
      45    int tmp[2];
      46    tmp[0] = fd[0];
      47    tmp[1] = fd[1];
      48  
      49  #if HAVE_PIPE2
      50  # undef pipe2
      51    /* Try the system call first, if it exists.  (We may be running with a glibc
      52       that has the function but with an older kernel that lacks it.)  */
      53    {
      54      /* Cache the information whether the system call really exists.  */
      55      static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
      56      if (have_pipe2_really >= 0)
      57        {
      58          int result = pipe2 (fd, flags);
      59          if (!(result < 0 && errno == ENOSYS))
      60            {
      61              have_pipe2_really = 1;
      62              return result;
      63            }
      64          have_pipe2_really = -1;
      65        }
      66    }
      67  #endif
      68  
      69    /* Check the supported flags.  */
      70    if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
      71      {
      72        errno = EINVAL;
      73        return -1;
      74      }
      75  
      76  #if defined _WIN32 && ! defined __CYGWIN__
      77  /* Native Windows API.  */
      78  
      79    if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
      80      {
      81        fd[0] = tmp[0];
      82        fd[1] = tmp[1];
      83        return -1;
      84      }
      85  
      86    /* O_NONBLOCK handling.
      87       On native Windows platforms, O_NONBLOCK is defined by gnulib.  Use the
      88       functions defined by the gnulib module 'nonblocking'.  */
      89  # if GNULIB_defined_O_NONBLOCK
      90    if (flags & O_NONBLOCK)
      91      {
      92        if (set_nonblocking_flag (fd[0], true) != 0
      93            || set_nonblocking_flag (fd[1], true) != 0)
      94          goto fail;
      95      }
      96  # else
      97    {
      98      verify (O_NONBLOCK == 0);
      99    }
     100  # endif
     101  
     102    return 0;
     103  
     104  #else
     105  /* Unix API.  */
     106  
     107    if (pipe (fd) < 0)
     108      return -1;
     109  
     110    /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
     111       says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
     112       both fd[0] and fd[1].  */
     113  
     114    /* O_NONBLOCK handling.
     115       On Unix platforms, O_NONBLOCK is defined by the system.  Use fcntl().  */
     116    if (flags & O_NONBLOCK)
     117      {
     118        int fcntl_flags;
     119  
     120        if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
     121            || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
     122            || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
     123            || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
     124          goto fail;
     125      }
     126  
     127    if (flags & O_CLOEXEC)
     128      {
     129        int fcntl_flags;
     130  
     131        if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
     132            || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
     133            || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
     134            || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
     135          goto fail;
     136      }
     137  
     138  # if O_BINARY
     139    if (flags & O_BINARY)
     140      {
     141        set_binary_mode (fd[1], O_BINARY);
     142        set_binary_mode (fd[0], O_BINARY);
     143      }
     144    else if (flags & O_TEXT)
     145      {
     146        set_binary_mode (fd[1], O_TEXT);
     147        set_binary_mode (fd[0], O_TEXT);
     148      }
     149  # endif
     150  
     151    return 0;
     152  
     153  #endif
     154  
     155  #if GNULIB_defined_O_NONBLOCK || !(defined _WIN32 && ! defined __CYGWIN__)
     156   fail:
     157    {
     158      int saved_errno = errno;
     159      close (fd[0]);
     160      close (fd[1]);
     161      fd[0] = tmp[0];
     162      fd[1] = tmp[1];
     163      errno = saved_errno;
     164      return -1;
     165    }
     166  #endif
     167  }