root/maint/gnulib/tests/test-fcntl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zero
  2. is_open
  3. is_inheritable
  4. is_mode
  5. func1
  6. func2
  7. check_flags
  8. main

   1 /* Test of fcntl(2).
   2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program 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 General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Eric Blake <ebb9@byu.net>, 2009.  */
  18 
  19 #include <config.h>
  20 
  21 /* Specification.  */
  22 #include <fcntl.h>
  23 
  24 #include "signature.h"
  25 SIGNATURE_CHECK (fcntl, int, (int, int, ...));
  26 
  27 /* Helpers.  */
  28 #include <errno.h>
  29 #include <stdarg.h>
  30 #include <stdbool.h>
  31 #include <unistd.h>
  32 
  33 #if defined _WIN32 && ! defined __CYGWIN__
  34 /* Get declarations of the native Windows API functions.  */
  35 # define WIN32_LEAN_AND_MEAN
  36 # include <windows.h>
  37 /* Get _get_osfhandle.  */
  38 # if GNULIB_MSVC_NOTHROW
  39 #  include "msvc-nothrow.h"
  40 # else
  41 #  include <io.h>
  42 # endif
  43 #endif
  44 
  45 #include "binary-io.h"
  46 #include "macros.h"
  47 
  48 #if !O_BINARY
  49 # define set_binary_mode(f,m) zero ()
  50 static int zero (void) { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  51 #endif
  52 
  53 /* Return true if FD is open.  */
  54 static bool
  55 is_open (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57 #if defined _WIN32 && ! defined __CYGWIN__
  58   /* On native Windows, the initial state of unassigned standard file
  59      descriptors is that they are open but point to an
  60      INVALID_HANDLE_VALUE, and there is no fcntl.  */
  61   return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
  62 #else
  63 # ifndef F_GETFL
  64 #  error Please port fcntl to your platform
  65 # endif
  66   return 0 <= fcntl (fd, F_GETFL);
  67 #endif
  68 }
  69 
  70 /* Return true if FD is open and inheritable across exec/spawn.  */
  71 static bool
  72 is_inheritable (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74 #if defined _WIN32 && ! defined __CYGWIN__
  75   /* On native Windows, the initial state of unassigned standard file
  76      descriptors is that they are open but point to an
  77      INVALID_HANDLE_VALUE, and there is no fcntl.  */
  78   HANDLE h = (HANDLE) _get_osfhandle (fd);
  79   DWORD flags;
  80   if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
  81     return false;
  82   return (flags & HANDLE_FLAG_INHERIT) != 0;
  83 #else
  84 # ifndef F_GETFD
  85 #  error Please port fcntl to your platform
  86 # endif
  87   int i = fcntl (fd, F_GETFD);
  88   return 0 <= i && (i & FD_CLOEXEC) == 0;
  89 #endif
  90 }
  91 
  92 /* Return non-zero if FD is open in the given MODE, which is either
  93    O_TEXT or O_BINARY.  */
  94 static bool
  95 is_mode (int fd, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97   int value = set_binary_mode (fd, O_BINARY);
  98   set_binary_mode (fd, value);
  99   return mode == value;
 100 }
 101 
 102 /* Since native fcntl can have more supported operations than our
 103    replacement is aware of, and since various operations assign
 104    different types to the vararg argument, a wrapper around fcntl must
 105    be able to pass a vararg of unknown type on through to the original
 106    fcntl.  Make sure that this works properly: func1 behaves like the
 107    original fcntl interpreting the vararg as an int or a pointer to a
 108    struct, and func2 behaves like rpl_fcntl that doesn't know what
 109    type to forward.  */
 110 struct dummy_struct
 111 {
 112   long filler;
 113   int value;
 114 };
 115 static int
 116 func1 (int a, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118   va_list arg;
 119   int i;
 120   va_start (arg, a);
 121   if (a < 4)
 122     i = va_arg (arg, int);
 123   else
 124     {
 125       struct dummy_struct *s = va_arg (arg, struct dummy_struct *);
 126       i = s->value;
 127     }
 128   va_end (arg);
 129   return i;
 130 }
 131 static int
 132 func2 (int a, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134   va_list arg;
 135   void *p;
 136   va_start (arg, a);
 137   p = va_arg (arg, void *);
 138   va_end (arg);
 139   return func1 (a, p);
 140 }
 141 
 142 /* Ensure that all supported fcntl actions are distinct, and
 143    usable in preprocessor expressions.  */
 144 static void
 145 check_flags (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147   switch (0)
 148     {
 149     case F_DUPFD:
 150 #if F_DUPFD
 151 #endif
 152 
 153     case F_DUPFD_CLOEXEC:
 154 #if F_DUPFD_CLOEXEC
 155 #endif
 156 
 157     case F_GETFD:
 158 #if F_GETFD
 159 #endif
 160 
 161 #ifdef F_SETFD
 162     case F_SETFD:
 163 # if F_SETFD
 164 # endif
 165 #endif
 166 
 167 #ifdef F_GETFL
 168     case F_GETFL:
 169 # if F_GETFL
 170 # endif
 171 #endif
 172 
 173 #ifdef F_SETFL
 174     case F_SETFL:
 175 # if F_SETFL
 176 # endif
 177 #endif
 178 
 179 #ifdef F_GETOWN
 180     case F_GETOWN:
 181 # if F_GETOWN
 182 # endif
 183 #endif
 184 
 185 #ifdef F_SETOWN
 186     case F_SETOWN:
 187 # if F_SETOWN
 188 # endif
 189 #endif
 190 
 191 #ifdef F_GETLK
 192     case F_GETLK:
 193 # if F_GETLK
 194 # endif
 195 #endif
 196 
 197 #ifdef F_SETLK
 198     case F_SETLK:
 199 # if F_SETLK
 200 # endif
 201 #endif
 202 
 203 #ifdef F_SETLKW
 204     case F_SETLKW:
 205 # if F_SETLKW
 206 # endif
 207 #endif
 208 
 209     default:
 210       ;
 211     }
 212 }
 213 
 214 int
 215 main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217   if (argc > 1)
 218     /* child process */
 219     return (is_open (10) ? 42 : 0);
 220 
 221   const char *file = "test-fcntl.tmp";
 222   int fd;
 223   int bad_fd = getdtablesize ();
 224 
 225   /* Sanity check that rpl_fcntl is likely to work.  */
 226   ASSERT (func2 (1, 2) == 2);
 227   ASSERT (func2 (2, -2) == -2);
 228   ASSERT (func2 (3, 0x80000000) == 0x80000000);
 229   {
 230     struct dummy_struct s = { 0L, 4 };
 231     ASSERT (func2 (4, &s) == 4);
 232   }
 233   check_flags ();
 234 
 235   /* Assume std descriptors were provided by invoker, and ignore fds
 236      that might have been inherited.  */
 237   fd = creat (file, 0600);
 238   ASSERT (STDERR_FILENO < fd);
 239   close (fd + 1);
 240   close (fd + 2);
 241 
 242   /* For F_DUPFD*, the source must be valid.  */
 243   errno = 0;
 244   ASSERT (fcntl (-1, F_DUPFD, 0) == -1);
 245   ASSERT (errno == EBADF);
 246   errno = 0;
 247   ASSERT (fcntl (fd + 1, F_DUPFD, 0) == -1);
 248   ASSERT (errno == EBADF);
 249   errno = 0;
 250   ASSERT (fcntl (bad_fd, F_DUPFD, 0) == -1);
 251   ASSERT (errno == EBADF);
 252   errno = 0;
 253   ASSERT (fcntl (-1, F_DUPFD_CLOEXEC, 0) == -1);
 254   ASSERT (errno == EBADF);
 255   errno = 0;
 256   ASSERT (fcntl (fd + 1, F_DUPFD_CLOEXEC, 0) == -1);
 257   ASSERT (errno == EBADF);
 258   errno = 0;
 259   ASSERT (fcntl (bad_fd, F_DUPFD_CLOEXEC, 0) == -1);
 260   ASSERT (errno == EBADF);
 261 
 262   /* For F_DUPFD*, the destination must be valid.  */
 263   errno = 0;
 264   ASSERT (fcntl (fd, F_DUPFD, -1) == -1);
 265   ASSERT (errno == EINVAL);
 266   errno = 0;
 267   ASSERT (fcntl (fd, F_DUPFD, bad_fd) == -1);
 268   ASSERT (errno == EINVAL);
 269   errno = 0;
 270   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, -1) == -1);
 271   ASSERT (errno == EINVAL);
 272   errno = 0;
 273   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, bad_fd) == -1);
 274   ASSERT (errno == EINVAL
 275           || errno == EMFILE /* WSL */);
 276 
 277   /* For F_DUPFD*, check for correct inheritance, as well as
 278      preservation of text vs. binary.  */
 279   set_binary_mode (fd, O_BINARY);
 280   ASSERT (is_open (fd));
 281   ASSERT (!is_open (fd + 1));
 282   ASSERT (!is_open (fd + 2));
 283   ASSERT (is_inheritable (fd));
 284   ASSERT (is_mode (fd, O_BINARY));
 285 
 286   ASSERT (fcntl (fd, F_DUPFD, fd) == fd + 1);
 287   ASSERT (is_open (fd));
 288   ASSERT (is_open (fd + 1));
 289   ASSERT (!is_open (fd + 2));
 290   ASSERT (is_inheritable (fd + 1));
 291   ASSERT (is_mode (fd, O_BINARY));
 292   ASSERT (is_mode (fd + 1, O_BINARY));
 293   ASSERT (close (fd + 1) == 0);
 294 
 295   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, fd + 2) == fd + 2);
 296   ASSERT (is_open (fd));
 297   ASSERT (!is_open (fd + 1));
 298   ASSERT (is_open (fd + 2));
 299   ASSERT (is_inheritable (fd));
 300   ASSERT (!is_inheritable (fd + 2));
 301   ASSERT (is_mode (fd, O_BINARY));
 302   ASSERT (is_mode (fd + 2, O_BINARY));
 303   ASSERT (close (fd) == 0);
 304 
 305   set_binary_mode (fd + 2, O_TEXT);
 306   ASSERT (fcntl (fd + 2, F_DUPFD, fd + 1) == fd + 1);
 307   ASSERT (!is_open (fd));
 308   ASSERT (is_open (fd + 1));
 309   ASSERT (is_open (fd + 2));
 310   ASSERT (is_inheritable (fd + 1));
 311   ASSERT (!is_inheritable (fd + 2));
 312   ASSERT (is_mode (fd + 1, O_TEXT));
 313   ASSERT (is_mode (fd + 2, O_TEXT));
 314   ASSERT (close (fd + 1) == 0);
 315 
 316   ASSERT (fcntl (fd + 2, F_DUPFD_CLOEXEC, 0) == fd);
 317   ASSERT (is_open (fd));
 318   ASSERT (!is_open (fd + 1));
 319   ASSERT (is_open (fd + 2));
 320   ASSERT (!is_inheritable (fd));
 321   ASSERT (!is_inheritable (fd + 2));
 322   ASSERT (is_mode (fd, O_TEXT));
 323   ASSERT (is_mode (fd + 2, O_TEXT));
 324   ASSERT (close (fd + 2) == 0);
 325 
 326   /* Test F_GETFD on invalid file descriptors.  */
 327   errno = 0;
 328   ASSERT (fcntl (-1, F_GETFD) == -1);
 329   ASSERT (errno == EBADF);
 330   errno = 0;
 331   ASSERT (fcntl (fd + 1, F_GETFD) == -1);
 332   ASSERT (errno == EBADF);
 333   errno = 0;
 334   ASSERT (fcntl (bad_fd, F_GETFD) == -1);
 335   ASSERT (errno == EBADF);
 336 
 337   /* Test F_GETFD, the FD_CLOEXEC bit.  */
 338   {
 339     int result = fcntl (fd, F_GETFD);
 340     ASSERT (0 <= result);
 341     ASSERT ((result & FD_CLOEXEC) == FD_CLOEXEC);
 342     ASSERT (dup (fd) == fd + 1);
 343     result = fcntl (fd + 1, F_GETFD);
 344     ASSERT (0 <= result);
 345     ASSERT ((result & FD_CLOEXEC) == 0);
 346     ASSERT (close (fd + 1) == 0);
 347   }
 348 
 349 #ifdef F_SETFD
 350   /* Test F_SETFD on invalid file descriptors.  */
 351   errno = 0;
 352   ASSERT (fcntl (-1, F_SETFD, 0) == -1);
 353   ASSERT (errno == EBADF);
 354   errno = 0;
 355   ASSERT (fcntl (fd + 1, F_SETFD, 0) == -1);
 356   ASSERT (errno == EBADF);
 357   errno = 0;
 358   ASSERT (fcntl (bad_fd, F_SETFD, 0) == -1);
 359   ASSERT (errno == EBADF);
 360 #endif
 361 
 362 #ifdef F_GETFL
 363   /* Test F_GETFL on invalid file descriptors.  */
 364   errno = 0;
 365   ASSERT (fcntl (-1, F_GETFL) == -1);
 366   ASSERT (errno == EBADF);
 367   errno = 0;
 368   ASSERT (fcntl (fd + 1, F_GETFL) == -1);
 369   ASSERT (errno == EBADF);
 370   errno = 0;
 371   ASSERT (fcntl (bad_fd, F_GETFL) == -1);
 372   ASSERT (errno == EBADF);
 373 #endif
 374 
 375 #ifdef F_SETFL
 376   /* Test F_SETFL on invalid file descriptors.  */
 377   errno = 0;
 378   ASSERT (fcntl (-1, F_SETFL, 0) == -1);
 379   ASSERT (errno == EBADF);
 380   errno = 0;
 381   ASSERT (fcntl (fd + 1, F_SETFL, 0) == -1);
 382   ASSERT (errno == EBADF);
 383   errno = 0;
 384   ASSERT (fcntl (bad_fd, F_SETFL, 0) == -1);
 385   ASSERT (errno == EBADF);
 386 #endif
 387 
 388 #ifdef F_GETOWN
 389   /* Test F_GETOWN on invalid file descriptors.  */
 390   errno = 0;
 391   ASSERT (fcntl (-1, F_GETOWN) == -1);
 392   ASSERT (errno == EBADF);
 393   errno = 0;
 394   ASSERT (fcntl (fd + 1, F_GETOWN) == -1);
 395   ASSERT (errno == EBADF);
 396   errno = 0;
 397   ASSERT (fcntl (bad_fd, F_GETOWN) == -1);
 398   ASSERT (errno == EBADF);
 399 #endif
 400 
 401 #ifdef F_SETOWN
 402   /* Test F_SETFL on invalid file descriptors.  */
 403   errno = 0;
 404   ASSERT (fcntl (-1, F_SETOWN, 0) == -1);
 405   ASSERT (errno == EBADF);
 406   errno = 0;
 407   ASSERT (fcntl (fd + 1, F_SETOWN, 0) == -1);
 408   ASSERT (errno == EBADF);
 409   errno = 0;
 410   ASSERT (fcntl (bad_fd, F_SETOWN, 0) == -1);
 411   ASSERT (errno == EBADF);
 412 #endif
 413 
 414   /* Cleanup.  */
 415   ASSERT (close (fd) == 0);
 416   ASSERT (unlink (file) == 0);
 417 
 418   /* Close file descriptors that may have been inherited from the parent
 419      process and that would cause failures below.
 420      Such file descriptors have been seen:
 421        - with GNU make, when invoked as 'make -j N' with j > 1,
 422        - in some versions of the KDE desktop environment,
 423        - on NetBSD,
 424        - in MacPorts with the "trace mode" enabled.
 425    */
 426   (void) close (10);
 427 
 428   /* Test whether F_DUPFD_CLOEXEC is effective.  */
 429   ASSERT (fcntl (1, F_DUPFD_CLOEXEC, 10) >= 0);
 430 #if defined _WIN32 && !defined __CYGWIN__
 431   return _execl ("./test-fcntl", "./test-fcntl", "child", NULL);
 432 #else
 433   return execl ("./test-fcntl", "./test-fcntl", "child", NULL);
 434 #endif
 435 }

/* [previous][next][first][last][top][bottom][index][help] */