(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
pipe2.c
       1  /* Create a pipe, with specific opening flags.
       2     Copyright (C) 2009-2023 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  
      27  #if GNULIB_defined_O_NONBLOCK
      28  # include "nonblocking.h"
      29  #endif
      30  
      31  #if defined _WIN32 && ! defined __CYGWIN__
      32  /* Native Windows API.  */
      33  
      34  # include <io.h>
      35  
      36  #endif
      37  
      38  int
      39  pipe2 (int fd[2], int flags)
      40  {
      41    /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
      42       creating the pipe but later fail at changing fcntl, we want
      43       to leave fd unchanged: http://austingroupbugs.net/view.php?id=467  */
      44    int tmp[2];
      45    tmp[0] = fd[0];
      46    tmp[1] = fd[1];
      47  
      48  #if HAVE_PIPE2
      49  # undef pipe2
      50    /* Try the system call first, if it exists.  (We may be running with a glibc
      51       that has the function but with an older kernel that lacks it.)  */
      52    {
      53      /* Cache the information whether the system call really exists.  */
      54      static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
      55      if (have_pipe2_really >= 0)
      56        {
      57          int result = pipe2 (fd, flags);
      58          if (!(result < 0 && errno == ENOSYS))
      59            {
      60              have_pipe2_really = 1;
      61              return result;
      62            }
      63          have_pipe2_really = -1;
      64        }
      65    }
      66  #endif
      67  
      68    /* Check the supported flags.  */
      69    if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
      70      {
      71        errno = EINVAL;
      72        return -1;
      73      }
      74  
      75  #if defined _WIN32 && ! defined __CYGWIN__
      76  /* Native Windows API.  */
      77  
      78    if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
      79      {
      80        fd[0] = tmp[0];
      81        fd[1] = tmp[1];
      82        return -1;
      83      }
      84  
      85    /* O_NONBLOCK handling.
      86       On native Windows platforms, O_NONBLOCK is defined by gnulib.  Use the
      87       functions defined by the gnulib module 'nonblocking'.  */
      88  # if GNULIB_defined_O_NONBLOCK
      89    if (flags & O_NONBLOCK)
      90      {
      91        if (set_nonblocking_flag (fd[0], true) != 0
      92            || set_nonblocking_flag (fd[1], true) != 0)
      93          goto fail;
      94      }
      95  # else
      96    {
      97      static_assert (O_NONBLOCK == 0);
      98    }
      99  # endif
     100  
     101    return 0;
     102  
     103  #else
     104  /* Unix API.  */
     105  
     106    if (pipe (fd) < 0)
     107      return -1;
     108  
     109    /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
     110       says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
     111       both fd[0] and fd[1].  */
     112  
     113    /* O_NONBLOCK handling.
     114       On Unix platforms, O_NONBLOCK is defined by the system.  Use fcntl().  */
     115    if (flags & O_NONBLOCK)
     116      {
     117        int fcntl_flags;
     118  
     119        if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
     120            || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
     121            || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
     122            || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
     123          goto fail;
     124      }
     125  
     126    if (flags & O_CLOEXEC)
     127      {
     128        int fcntl_flags;
     129  
     130        if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
     131            || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
     132            || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
     133            || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
     134          goto fail;
     135      }
     136  
     137  # if O_BINARY
     138    if (flags & O_BINARY)
     139      {
     140        set_binary_mode (fd[1], O_BINARY);
     141        set_binary_mode (fd[0], O_BINARY);
     142      }
     143    else if (flags & O_TEXT)
     144      {
     145        set_binary_mode (fd[1], O_TEXT);
     146        set_binary_mode (fd[0], O_TEXT);
     147      }
     148  # endif
     149  
     150    return 0;
     151  
     152  #endif
     153  
     154  #if GNULIB_defined_O_NONBLOCK || !(defined _WIN32 && ! defined __CYGWIN__)
     155   fail:
     156    {
     157      int saved_errno = errno;
     158      close (fd[0]);
     159      close (fd[1]);
     160      fd[0] = tmp[0];
     161      fd[1] = tmp[1];
     162      errno = saved_errno;
     163      return -1;
     164    }
     165  #endif
     166  }