blob: 41685d9b870bb6f904189e255d87156552c1623c [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 *
32 */
33/* $Id: fcntl07.c,v 1.1 2001/08/27 22:15:13 plars Exp $ */
34/**********************************************************
35 *
36 * OS Test - Silicon Graphics, Inc.
37 *
38 * TEST IDENTIFIER : fcntl07
39 *
40 * EXECUTED BY : anyone
41 *
42 * TEST TITLE : Close-On-Exec functional test
43 *
44 * PARENT DOCUMENT : none
45 *
46 * TEST CASE TOTAL : 2
47 *
48 * WALL CLOCK TIME : 5
49 *
50 * CPU TYPES : ALL
51 *
52 * AUTHOR : Glen Overby
53 *
54 * CO-PILOT : William Roske
55 *
56 * DATE STARTED : 08/11/93
57 *
58 * INITIAL RELEASE : UNICOS 7.0
59 *
60 * TEST CASES
61 *
62 * 1.) test close-on-exec with a regular file
63 * 2.) test close-on-exec with a system pipe
64 *
65 * INPUT SPECIFICATIONS
66 *
67 * Standard arguments accepted by parse_opts(3).
68 *
69 * The -t (timing) and -e options apply to the fcntl(.., F_SETFD, ..)
70 * system call.
71 *
72 * -T fd : If this option is given, the program runs as "test_open",
73 * testing <fd> to see if it is open or not and exiting
74 * accordingly:
75 * 0 not open (EBADF from fcntl(..., F_GETFD, ...))
76 * 3 no error from fcntl
77 * errno fcntl returned an error other than EBADF
78 *
79 * -F name : File to open. Must be an absolute path
80 * and the file must be writable;
81 * -n program: path to the 'test_open' program
82 *
83 * OUTPUT SPECIFICATIONS
84 * This test uses the cuts-style test_res format output consisting of:
85 *
86 * test-name PASS/FAIL/BROK message
87 *
88 * the message will tell what type of test and, if it failed, indicate
89 * what the failure was.
90 *
91 * DURATION
92 * Terminates
93 *
94 * SIGNALS
95 * None
96 *
97 * RESOURCES
98 * None
99 *
100 * ENVIRONMENTAL NEEDS
101 * No run-time environmental needs.
102 *
103 * If this test is not called with a full pathname, it must be able
104 * to find itself on $PATH
105 *
106 * INTERCASE DEPENDENCIES
107 * none
108 *
109 * DETAILED DESCRIPTION
110 *
111 * Setup:
112 * Setup signal handling.
113 * Create and make current a temporary directory.
114 * Open a regular file for writing
115 * Create a system pipe
116 * Create a named pipe and open it for writing
117 *
118 * Test:
119 * Set the file descriptor for close-on-exec
120 * Fork
121 * Child execlp's the program "test_open".
122 * If the exec fails, exit "2"
123 * Parent waits
124 * Report results.
125 *
126 * Cleanup:
127 * Close file and pipes
128 * Remove the temporary directory
129 *
130 * BUGS
131 *
132 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
133
134#include <errno.h>
135#include <string.h>
136#include <signal.h>
137#include <sys/types.h>
138#include <unistd.h>
139#include <stdlib.h>
140#include <fcntl.h>
141#include <sys/wait.h>
142#include <limits.h>
143
144#include "test.h"
145#include "usctest.h"
146#include "search_path.h"
147
148void setup();
149void cleanup();
150void help();
151
152char *TCID="fcntl07"; /* Test program identifier. */
153int TST_TOTAL=2; /* Total number of test cases. */
154extern int Tst_count; /* Test Case counter for tst_* routines */
155
156
157
158/* for parse_opts */
159int fflag, Tflag; /* binary flags: opt or not */
160char *fopt, *Topt; /* option arguments */
161
162option_t options[] = {
163 { "F:", &fflag, &fopt }, /* -F filename */
164 { "T:", &Tflag, &Topt }, /* -T <fd> exec'ed by test: test FD */
165 { NULL, NULL, NULL }
166};
167
168int stat_loc; /* for waitpid() */
169
170int file_fd, pipe_fds[2];
171 /* file descriptors for a file and a system pipe */
172#define DEFAULT_FILE "DefaultFileName"
173char *File1 = DEFAULT_FILE;
174
175#define DEFAULT_SUBPROG "test_open"
176char *openck = DEFAULT_SUBPROG; /* support program name to check for open FD */
177char subprog_path[_POSIX_PATH_MAX]; /* path to exec "openck" with */
178#define STRSIZE 255
179
180int *testfds[] = {
181 &file_fd, &pipe_fds[1], 0
182 };
183
184char *testfdtypes[] = {
185 "regular file",
186 "write side of system pipe",
187 };
188
189int test_open(char *arg);
190int do_exec(char *prog, int fd, char *tcd);
191
192int
193main(int ac, char **av)
194{
195 int lc; /* loop counter */
196 char *msg; /* message returned from parse_opts */
197
198 int exec_return; /* return from do_exec */
199 int **tcp; /* testcase pointer (pointer to FD) */
200 char **tcd; /* testcase description pointer */
201
202 /***************************************************************
203 * parse standard options, and exit if there is an error
204 ***************************************************************/
205 if ( (msg=parse_opts(ac, av, options, &help)) != (char *) NULL ) {
206 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
207 tst_exit();
208 }
209
210 if(fflag) /* -F option */
211 File1 = fopt;
212
213 if(Tflag) { /* -T option */
214 exit(test_open(Topt));
215 }
216
217 /***************************************************************
218 * perform global setup for test
219 ***************************************************************/
220 setup(av[0]);
221
222 /***************************************************************
223 * check looping state if -c option given
224 ***************************************************************/
225 for (lc=0; TEST_LOOPING(lc); lc++) {
226
227 /* reset Tst_count in case we are looping. */
228 Tst_count=0;
229
230 for(tcp = testfds, tcd = testfdtypes; *tcp; tcp++, tcd++) {
231
232 TEST(fcntl(**tcp, F_SETFD, FD_CLOEXEC));
233
234 /* check return code */
235 if ( TEST_RETURN == -1 ) {
236 TEST_ERROR_LOG(TEST_ERRNO);
237 tst_resm(TFAIL, "fcntl(%s[%d], F_SETFD, FD_CLOEXEC) Failed, errno=%d : %s",
238 *tcd, **tcp, TEST_ERRNO, strerror(TEST_ERRNO));
239 } else {
240
241 /*************************************************************
242 * only perform functional verification if flag set
243 * (-f not given)
244 *************************************************************/
245 if ( STD_FUNCTIONAL_TEST ) {
246
247 exec_return = do_exec(subprog_path, **tcp, *tcd);
248
249 switch(exec_return) {
250 case -1:
251 tst_resm(TBROK, "fork failed. Errno %s [%d]",
252 strerror(errno), errno);
253 break;
254 case 1:
255 tst_resm(TBROK, "waitpid return was 0%o", stat_loc);
256 break;
257 case 2:
258 tst_resm(TBROK, "exec failed"); /* errno was in child */
259 break;
260 case 0:
261 tst_resm(TPASS, "%s child exited 0, indicating that the file was closed",
262 *tcd);
263 break;
264 default:
265 tst_resm(TFAIL, "%s child exited non-zero, %d", *tcd,
266 exec_return);
267 break;
268 }
269 }
270 }
271 }
272 } /* End for TEST_LOOPING */
273
274 /***************************************************************
275 * cleanup and exit
276 ***************************************************************/
277 cleanup();
278
279 return 0;
280} /* End main */
281
282/***************************************************************
283 * setup() - performs all ONE TIME setup for this test.
284 ***************************************************************/
285void
286setup(char *path)
287{
288 search_path(path, subprog_path, X_OK, 1);
289
290 /* capture signals */
291 tst_sig(FORK, DEF_HANDLER, cleanup);
292
293 /* Pause if that option was specified */
294 TEST_PAUSE;
295
296 /* create a temporary directory and go to it */
297 tst_tmpdir();
298
299 /* set up a regular file */
300 if((file_fd=open(File1, O_CREAT|O_RDWR, 0666)) == -1) {
301 tst_brkm(TBROK, cleanup, "Open of file %s failed errno %d (%s)\n", File1, errno, strerror(errno));
302 }
303
304 /* set up a system pipe (write side gets CLOSE-ON-EXEC) */
305 pipe(pipe_fds);
306} /* End setup() */
307
308
309/***************************************************************
310 * cleanup() - performs all ONE TIME cleanup for this test at
311 * completion or premature exit.
312 ***************************************************************/
313void
314cleanup()
315{
316 /*
317 * print timing stats if that option was specified.
318 * print errno log if that option was specified.
319 */
320 TEST_CLEANUP;
321
322 /* close everything */
323 close(file_fd);
324 close(pipe_fds[0]);
325 close(pipe_fds[1]);
326
327 /* remove temporary directory and all files in it. */
328 tst_rmdir();
329
330 /* exit with return code appropriate for results */
331 tst_exit();
332} /* End cleanup() */
333
334/***************************************************************************
335 * issue a help message
336 ***************************************************************************/
337void
338help()
339{
340 printf("-T fd : If this option is given, the program runs as 'test_open'\n");
341 printf(" testing <fd> to see if it is open or not and exiting accordingly\n");
342 printf("-F name : File to open. Must be an absolute path,\n");
343 printf(" and the file must be writable\n");
344 printf("-n program: path to the 'test_open' program\n");
345}
346
347/*---------------------------------------------------------------------------*/
348/* Perform an exec, then wait for the child to terminate.
349 * The child's termination status determines the success of the test
350 *
351 * Return codes:
352 * -1 BROK fork failed
353 * 1 BROK waitpid returned != exit status
354 * <else> ???? exit code from child:
355 * 2 BROK exec failed
356 * 0 PASS fd was properly closed
357 *
358 */
359
360int
361do_exec(char *prog, int fd, char *tcd)
362{
363 int pid;
364 char pidname[STRSIZE];
365#ifdef DEBUG
366 int rc, status; /* for the fcntl */
367#endif
368
369 /* set up arguments to exec'ed child */
370 sprintf(pidname, "%d", fd);
371
372#ifdef DEBUG
373 rc = fcntl(fd, F_GETFD, &status);
374 printf("%s: fd = %d rc = %d status= %d, errno= %d\n", tcd, fd, rc, status, errno);
375#endif
376
377 switch(pid=fork()) {
378 case -1:
379 return(-1);
380 case 0: /* child */
381 execlp(prog, openck, "-T", pidname, 0);
382
383 /* the ONLY reason to do this is to get the errno printed out */
384 fprintf(stderr, "exec(%s, %s, -T, %s) failed. Errno %s [%d]\n",
385 prog, openck, pidname, strerror(errno), errno);
386 exit(2);
387 default: /* parent */
388 waitpid(pid, &stat_loc, 0);
389 if(WIFEXITED(stat_loc)) {
390 return(WEXITSTATUS(stat_loc));
391 } else {
392 return(1);
393 }
394 }
395}
396
397/*
398 * PROGRAM TITLE : Test if a named file descriptor is open
399 * This function is called when fcntcs07 is called with the -T option.
400 * It tests if a file descriptor is open and exits accordingly.
401 */
402int
403test_open(char *arg)
404{
405 int fd, rc;
406 int status;
407
408 extern char *optarg;
409 extern int optind;
410
411 fd = atoi(arg);
412
413 rc = fcntl(fd, F_GETFD, &status);
414
415#ifdef DEBUG_T
416 printf("%s: fd = %d rc = %d status= %d, errno= %d\n", openck, fd, rc,
417 status, errno);
418#endif
419
420 if(rc == -1 && errno == EBADF) {
421 exit(0);
422 }
423
424 if(rc != -1)
425 exit(3);
426
427 exit(errno);
428 return -1; /* to remove compiler warning on IRIX */
429}