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 
51 char *TCID = "fork09";
52 int TST_TOTAL = 1;
53 
54 static void setup(void);
55 static void cleanup(void);
56 
57 static char filname[40], childfile[40];
58 static int first;
59 static FILE **fildeses;		/* file streams */
60 static int mypid, nfiles;
61 
62 #define OPEN_MAX (sysconf(_SC_OPEN_MAX))
63 
main(int ac,char ** av)64 int main(int ac, char **av)
65 {
66 	int pid, status, nf;
67 
68 	int lc;
69 
70 	tst_parse_opts(ac, av, NULL, NULL);
71 
72 	setup();
73 
74 	fildeses = malloc((OPEN_MAX + 10) * sizeof(FILE *));
75 	if (fildeses == NULL)
76 		tst_brkm(TBROK, cleanup, "malloc failed");
77 
78 	for (lc = 0; TEST_LOOPING(lc); lc++) {
79 		tst_count = 0;
80 		mypid = getpid();
81 
82 		tst_resm(TINFO, "OPEN_MAX is %ld", OPEN_MAX);
83 
84 		/* establish first free file */
85 		sprintf(filname, "fork09.%d", mypid);
86 		first = creat(filname, 0660);
87 		if (first == -1)
88 			tst_brkm(TBROK, cleanup, "Cannot open first file %s, "
89 				 "errno = %d", filname, errno);
90 		close(first);
91 
92 		tst_resm(TINFO, "first file descriptor is %d ", first);
93 
94 		if (unlink(filname) == -1)
95 			tst_brkm(TBROK, cleanup, "Cannot unlink file %s, "
96 				 "errno = %d", filname, errno);
97 
98 		/*
99 		 * now open all the files for the test
100 		 */
101 		for (nfiles = first; nfiles < OPEN_MAX; nfiles++) {
102 			sprintf(filname, "file%d.%d", nfiles, mypid);
103 			fildeses[nfiles] = fopen(filname, "a");
104 			if (fildeses[nfiles] == NULL) {
105 				/* Did we already reach OPEN_MAX ? */
106 				if (errno == EMFILE)
107 					break;
108 				tst_brkm(TBROK, cleanup, "Parent: cannot open "
109 					 "file %d %s errno = %d", nfiles,
110 					 filname, errno);
111 			}
112 #ifdef DEBUG
113 			tst_resm(TINFO, "filname: %s", filname);
114 #endif
115 		}
116 
117 		tst_resm(TINFO, "Parent reporting %d files open", nfiles - 1);
118 
119 		pid = fork();
120 		if (pid == -1)
121 			tst_brkm(TBROK, cleanup, "Fork failed");
122 
123 		if (pid == 0) {	/* child */
124 			nfiles--;
125 			if (fclose(fildeses[nfiles]) == -1) {
126 				tst_resm(TINFO, "Child could not close file "
127 					 "#%d, errno = %d", nfiles, errno);
128 				exit(1);
129 			} else {
130 				sprintf(childfile, "cfile.%d", getpid());
131 				fildeses[nfiles] = fopen(childfile, "a");
132 				if (fildeses[nfiles] == NULL) {
133 					tst_resm(TINFO, "Child could not open "
134 						 "file %s, errno = %d",
135 						 childfile, errno);
136 					exit(1);
137 				} else {
138 					tst_resm(TINFO, "Child opened new "
139 						 "file #%d", nfiles);
140 					unlink(childfile);
141 					exit(0);
142 				}
143 			}
144 		} else {	/* parent */
145 			wait(&status);
146 			if (status >> 8 != 0)
147 				tst_resm(TFAIL, "test 1 FAILED");
148 			else
149 				tst_resm(TPASS, "test 1 PASSED");
150 		}
151 
152 		/* clean up things in case we are looping */
153 		for (nf = first; nf < nfiles; nf++) {
154 			fclose(fildeses[nf]);
155 			sprintf(filname, "file%d.%d", nf, mypid);
156 			unlink(filname);
157 		}
158 	}
159 
160 	cleanup();
161 	tst_exit();
162 }
163 
setup(void)164 static void setup(void)
165 {
166 	tst_sig(FORK, DEF_HANDLER, cleanup);
167 	umask(0);
168 
169 	TEST_PAUSE;
170 	tst_tmpdir();
171 }
172 
cleanup(void)173 static void cleanup(void)
174 {
175 	tst_rmdir();
176 }
177