1 /*
2  * fdclosed.cc: Part of GNU CSSC.
3  *
4  *  Copyright (C) 1998, 2000, 2007, 2008, 2009, 2010, 2011, 2014, 2019
5  *  Free Software Foundation, Inc.
6  *
7  *  This program is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 /* This class exists to ensure that the standard file descriptors are
23  * not closed.  That would mean that we could open an ordinary file
24  * and then corrupt it since we don't realise that output to stdout or
25  * stderr will go to it.
26  *
27  *
28  * If any of the file descriptors 0, 1, 2 are not open, attach them
29  * to /dev/null so that we don't fopen() a file, get a low numbered
30  * file descriptor, and accidentally corrupt our file with a printf()
31  * to stdout or stderr, or trying to read from stdin (hence changing
32  * the file pointer on our file too).
33  */
34 
35 #include <config.h>
36 
37 #include <unistd.h>
38 #include <stdio.h>		/* perror() */
39 
40 #include "cssc.h"
41 #include "sysdep.h"
42 #include "defaults.h"		// CONFIG_NULL_FILENAME
43 
44 class SafeFdCheck
45 {
46 public:
47   SafeFdCheck();
48 };
49 
50 
51 /* We want to emit an error message.  If stderr has been closed, this
52  * is difficult.  We just send the output to the closed file
53  * descriptor (using perror()).
54  *
55  * We do this becauase (1) there isn't really a better option, and
56  * (2) because the output will still show up in the strace(8) output
57  * if the user really needs to track down the problem.
58  *
59  * If you have an idea for a better way of implementing it, please
60  * feel free to do so; but remember, it needs to work when we just
61  * failed to open() /dev/null.  So opening another file (e.g. /dev/log
62  * with syslog) isn't going to work.
63  */
64 
SafeFdCheck()65 SafeFdCheck::SafeFdCheck()
66 {
67   int i, fd;
68 
69   for (i=0; i<3; ++i)
70     {
71       fd = open(CONFIG_NULL_FILENAME, O_RDONLY, 0);
72       if (fd < 0)
73 	{
74 	  perror(CONFIG_NULL_FILENAME);
75 	  _exit(1);
76 	}
77       else if (fd > 2)
78 	{
79 	  close(fd);
80 	  return;
81 	}
82     }
83 }
84 
85 
86 /* Instantiate the class so that the constructor is called to do the check.
87  */
88 static SafeFdCheck PleaseDoIt;
89 
90 /* Local variables: */
91 /* mode: c++ */
92 /* End: */
93