1 /*
2  *   Copyright (c) International Business Machines  Corp., 2001
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 2 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
12  *   the 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, write to the Free Software
16  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * NAME
19  *	fork09.c
20  *
21  * DESCRIPTION
22  *	Check that child has access to a full set of files.
23  *
24  * ALGORITHM
25  *	Parent opens a maximum number of files
26  *	Child closes one and attempts to open another, it should be
27  *	available
28  *
29  * USAGE
30  *	fork09
31  *
32  * HISTORY
33  *	07/2001 Ported by Wayne Boyer
34  *
35  *	10/2008 Suzuki K P <suzuki@in.ibm.com>
36  *		Fix maximum number of files open logic.
37  *
38  * RESTRICTIONS
39  *	None
40  */
41 
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <errno.h>
48 #include <unistd.h>		/* for _SC_OPEN_MAX */
49 #include "test.h"
50 #include "safe_macros.h"
51 
52 char *TCID = "fork09";
53 int TST_TOTAL = 1;
54 
55 static void setup(void);
56 static void cleanup(void);
57 
58 static char filname[40], childfile[40];
59 static int first;
60 static FILE **fildeses;		/* file streams */
61 static int mypid, nfiles;
62 
63 #define OPEN_MAX (sysconf(_SC_OPEN_MAX))
64 
main(int ac,char ** av)65 int main(int ac, char **av)
66 {
67 	int pid, status, nf;
68 
69 	int lc;
70 
71 	tst_parse_opts(ac, av, NULL, NULL);
72 
73 	setup();
74 
75 	fildeses = malloc((OPEN_MAX + 10) * sizeof(FILE *));
76 	if (fildeses == NULL)
77 		tst_brkm(TBROK, cleanup, "malloc failed");
78 
79 	for (lc = 0; TEST_LOOPING(lc); lc++) {
80 		tst_count = 0;
81 		mypid = getpid();
82 
83 		tst_resm(TINFO, "OPEN_MAX is %ld", OPEN_MAX);
84 
85 		/* establish first free file */
86 		sprintf(filname, "fork09.%d", mypid);
87 		first = SAFE_CREAT(cleanup, filname, 0660);
88 		close(first);
89 
90 		tst_resm(TINFO, "first file descriptor is %d ", first);
91 
92 		SAFE_UNLINK(cleanup, filname);
93 
94 		/*
95 		 * now open all the files for the test
96 		 */
97 		for (nfiles = first; nfiles < OPEN_MAX; nfiles++) {
98 			sprintf(filname, "file%d.%d", nfiles, mypid);
99 			fildeses[nfiles] = fopen(filname, "a");
100 			if (fildeses[nfiles] == NULL) {
101 				/* Did we already reach OPEN_MAX ? */
102 				if (errno == EMFILE)
103 					break;
104 				tst_brkm(TBROK, cleanup, "Parent: cannot open "
105 					 "file %d %s errno = %d", nfiles,
106 					 filname, errno);
107 			}
108 #ifdef DEBUG
109 			tst_resm(TINFO, "filname: %s", filname);
110 #endif
111 		}
112 
113 		tst_resm(TINFO, "Parent reporting %d files open", nfiles - 1);
114 
115 		pid = fork();
116 		if (pid == -1)
117 			tst_brkm(TBROK, cleanup, "Fork failed");
118 
119 		if (pid == 0) {	/* child */
120 			nfiles--;
121 			if (fclose(fildeses[nfiles]) == -1) {
122 				tst_resm(TINFO, "Child could not close file "
123 					 "#%d, errno = %d", nfiles, errno);
124 				exit(1);
125 			} else {
126 				sprintf(childfile, "cfile.%d", getpid());
127 				fildeses[nfiles] = fopen(childfile, "a");
128 				if (fildeses[nfiles] == NULL) {
129 					tst_resm(TINFO, "Child could not open "
130 						 "file %s, errno = %d",
131 						 childfile, errno);
132 					exit(1);
133 				} else {
134 					tst_resm(TINFO, "Child opened new "
135 						 "file #%d", nfiles);
136 					unlink(childfile);
137 					exit(0);
138 				}
139 			}
140 		} else {	/* parent */
141 			wait(&status);
142 			if (status >> 8 != 0)
143 				tst_resm(TFAIL, "test 1 FAILED");
144 			else
145 				tst_resm(TPASS, "test 1 PASSED");
146 		}
147 
148 		/* clean up things in case we are looping */
149 		for (nf = first; nf < nfiles; nf++) {
150 			fclose(fildeses[nf]);
151 			sprintf(filname, "file%d.%d", nf, mypid);
152 			unlink(filname);
153 		}
154 	}
155 
156 	cleanup();
157 	tst_exit();
158 }
159 
setup(void)160 static void setup(void)
161 {
162 	tst_sig(FORK, DEF_HANDLER, cleanup);
163 	umask(0);
164 
165 	TEST_PAUSE;
166 	tst_tmpdir();
167 }
168 
cleanup(void)169 static void cleanup(void)
170 {
171 	tst_rmdir();
172 }
173