1210284Sjmallett/* cloexec.c - set or clear the close-on-exec descriptor flag
2232812Sjmallett
3215990Sjmallett   Copyright (C) 1991, 2004-2006, 2009-2020 Free Software Foundation, Inc.
4210284Sjmallett
5210284Sjmallett   This program is free software: you can redistribute it and/or modify
6215990Sjmallett   it under the terms of the GNU General Public License as published by
7215990Sjmallett   the Free Software Foundation; either version 3 of the License, or
8215990Sjmallett   (at your option) any later version.
9210284Sjmallett
10215990Sjmallett   This program is distributed in the hope that it will be useful,
11215990Sjmallett   but WITHOUT ANY WARRANTY; without even the implied warranty of
12210284Sjmallett   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13215990Sjmallett   GNU General Public License for more details.
14215990Sjmallett
15215990Sjmallett   You should have received a copy of the GNU General Public License
16215990Sjmallett   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17215990Sjmallett
18232812Sjmallett   The code is taken from glibc/manual/llio.texi  */
19215990Sjmallett
20215990Sjmallett#include <config.h>
21215990Sjmallett
22215990Sjmallett#include "cloexec.h"
23215990Sjmallett
24215990Sjmallett#include <errno.h>
25215990Sjmallett#include <fcntl.h>
26215990Sjmallett#include <unistd.h>
27215990Sjmallett
28215990Sjmallett/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true,
29232812Sjmallett   or clear the flag if VALUE is false.
30215990Sjmallett   Return 0 on success, or -1 on error with 'errno' set.
31215990Sjmallett
32215990Sjmallett   Note that on MingW, this function does NOT protect DESC from being
33215990Sjmallett   inherited into spawned children.  Instead, either use dup_cloexec
34215990Sjmallett   followed by closing the original DESC, or use interfaces such as
35215990Sjmallett   open or pipe2 that accept flags like O_CLOEXEC to create DESC
36215990Sjmallett   non-inheritable in the first place.  */
37215990Sjmallett
38210284Sjmallettint
39210284Sjmallettset_cloexec_flag (int desc, bool value)
40210284Sjmallett{
41210284Sjmallett#ifdef F_SETFD
42210284Sjmallett
43210284Sjmallett  int flags = fcntl (desc, F_GETFD, 0);
44210284Sjmallett
45215990Sjmallett  if (0 <= flags)
46210284Sjmallett    {
47210284Sjmallett      int newflags = (value ? flags | FD_CLOEXEC : flags & ~FD_CLOEXEC);
48210284Sjmallett
49210284Sjmallett      if (flags == newflags
50210284Sjmallett          || fcntl (desc, F_SETFD, newflags) != -1)
51210284Sjmallett        return 0;
52232812Sjmallett    }
53210284Sjmallett
54210284Sjmallett  return -1;
55210284Sjmallett
56210284Sjmallett#else /* !F_SETFD */
57210284Sjmallett
58210284Sjmallett  /* Use dup2 to reject invalid file descriptors; the cloexec flag
59210284Sjmallett     will be unaffected.  */
60210284Sjmallett  if (desc < 0)
61210284Sjmallett    {
62210284Sjmallett      errno = EBADF;
63210284Sjmallett      return -1;
64210284Sjmallett    }
65210284Sjmallett  if (dup2 (desc, desc) < 0)
66210284Sjmallett    /* errno is EBADF here.  */
67210284Sjmallett    return -1;
68210284Sjmallett
69210284Sjmallett  /* There is nothing we can do on this kind of platform.  Punt.  */
70232812Sjmallett  return 0;
71232812Sjmallett#endif /* !F_SETFD */
72232812Sjmallett}
73232812Sjmallett
74232812Sjmallett
75210284Sjmallett/* Duplicates a file handle FD, while marking the copy to be closed
76210284Sjmallett   prior to exec or spawn.  Returns -1 and sets errno if FD could not
77210284Sjmallett   be duplicated.  */
78210284Sjmallett
79210284Sjmallettint
80210284Sjmallettdup_cloexec (int fd)
81210284Sjmallett{
82210284Sjmallett  return fcntl (fd, F_DUPFD_CLOEXEC, 0);
83215990Sjmallett}
84215990Sjmallett