root/maint/gnulib/lib/freopen-safer.c

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

DEFINITIONS

This source file includes following definitions.
  1. protect_fd
  2. freopen_safer

   1 /* Invoke freopen, but avoid some glitches.
   2 
   3    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   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 /* Written by Eric Blake.  */
  19 
  20 #include <config.h>
  21 
  22 #include "stdio-safer.h"
  23 
  24 #include "attribute.h"
  25 
  26 #include <errno.h>
  27 #include <fcntl.h>
  28 #include <stdbool.h>
  29 #include <unistd.h>
  30 
  31 /* Guarantee that FD is open; all smaller FDs must already be open.
  32    Return true if successful.  */
  33 static bool
  34 protect_fd (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36   int value = open ("/dev/null", O_RDONLY);
  37   if (value != fd)
  38     {
  39       if (0 <= value)
  40         {
  41           close (value);
  42           errno = EBADF; /* Unexpected; this is as good as anything else.  */
  43         }
  44       return false;
  45     }
  46   return true;
  47 }
  48 
  49 /* Like freopen, but guarantee that reopening stdin, stdout, or stderr
  50    preserves the invariant that STDxxx_FILENO==fileno(stdxxx), and
  51    that no other stream will interfere with the standard streams.
  52    This is necessary because most freopen implementations will change
  53    the associated fd of a stream to the lowest available slot.  */
  54 
  55 FILE *
  56 freopen_safer (char const *name, char const *mode, FILE *f)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58   /* Unfortunately, we cannot use the fopen_safer approach of using
  59      fdopen (dup_safer (fileno (freopen (cmd, mode, f)))), because we
  60      need to return f itself.  The implementation of freopen(NULL,m,f)
  61      is system-dependent, so the best we can do is guarantee that all
  62      lower-valued standard fds are open prior to the freopen call,
  63      even though this puts more pressure on open fds.  */
  64   bool protect_in = false;
  65   bool protect_out = false;
  66   bool protect_err = false;
  67   int saved_errno;
  68 
  69   switch (fileno (f))
  70     {
  71     default: /* -1 or not a standard stream.  */
  72       if (dup2 (STDERR_FILENO, STDERR_FILENO) != STDERR_FILENO)
  73         protect_err = true;
  74       FALLTHROUGH;
  75     case STDERR_FILENO:
  76       if (dup2 (STDOUT_FILENO, STDOUT_FILENO) != STDOUT_FILENO)
  77         protect_out = true;
  78       FALLTHROUGH;
  79     case STDOUT_FILENO:
  80       if (dup2 (STDIN_FILENO, STDIN_FILENO) != STDIN_FILENO)
  81         protect_in = true;
  82       FALLTHROUGH;
  83     case STDIN_FILENO:
  84       /* Nothing left to protect.  */
  85       break;
  86     }
  87   if (protect_in && !protect_fd (STDIN_FILENO))
  88     f = NULL;
  89   else if (protect_out && !protect_fd (STDOUT_FILENO))
  90     f = NULL;
  91   else if (protect_err && !protect_fd (STDERR_FILENO))
  92     f = NULL;
  93   else
  94     f = freopen (name, mode, f);
  95   saved_errno = errno;
  96   if (protect_err)
  97     close (STDERR_FILENO);
  98   if (protect_out)
  99     close (STDOUT_FILENO);
 100   if (protect_in)
 101     close (STDIN_FILENO);
 102   if (!f)
 103     errno = saved_errno;
 104   return f;
 105 }

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