424 lines
11 KiB
C
424 lines
11 KiB
C
/*
|
|
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* Further, this software is distributed without any warranty that it is
|
|
* free of the rightful claim of any third person regarding infringement
|
|
* or the like. Any license provided herein, whether implied or
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
|
* any, provided herein do not apply to combinations of this program with
|
|
* other software, or any other product whatsoever.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write the Free Software Foundation, Inc., 59
|
|
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
|
*
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
|
* Mountain View, CA 94043, or:
|
|
*
|
|
* http://www.sgi.com
|
|
*
|
|
* For further information regarding this notice, see:
|
|
*
|
|
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
|
|
*
|
|
*/
|
|
/* $Id$ */
|
|
/**********************************************************
|
|
*
|
|
* OS Test - Silicon Graphics, Inc.
|
|
*
|
|
* TEST IDENTIFIER : fcntl07
|
|
*
|
|
* EXECUTED BY : anyone
|
|
*
|
|
* TEST TITLE : Close-On-Exec functional test
|
|
*
|
|
* PARENT DOCUMENT : none
|
|
*
|
|
* TEST CASE TOTAL : 2
|
|
*
|
|
* WALL CLOCK TIME : 5
|
|
*
|
|
* CPU TYPES : ALL
|
|
*
|
|
* AUTHOR : Glen Overby
|
|
*
|
|
* CO-PILOT : William Roske
|
|
*
|
|
* DATE STARTED : 08/11/93
|
|
*
|
|
* INITIAL RELEASE : UNICOS 7.0
|
|
*
|
|
* TEST CASES
|
|
*
|
|
* 1.) test close-on-exec with a regular file
|
|
* 2.) test close-on-exec with a system pipe
|
|
*
|
|
* INPUT SPECIFICATIONS
|
|
*
|
|
* Standard arguments accepted by parse_opts(3).
|
|
*
|
|
* The -t (timing) and -e options apply to the fcntl(.., F_SETFD, ..)
|
|
* system call.
|
|
*
|
|
* -T fd : If this option is given, the program runs as "test_open",
|
|
* testing <fd> to see if it is open or not and exiting
|
|
* accordingly:
|
|
* 0 not open (EBADF from fcntl(..., F_GETFD, ...))
|
|
* 3 no error from fcntl
|
|
* errno fcntl returned an error other than EBADF
|
|
*
|
|
* -F name : File to open. Must be an absolute path
|
|
* and the file must be writable;
|
|
* -n program: path to the 'test_open' program
|
|
*
|
|
* OUTPUT SPECIFICATIONS
|
|
* This test uses the cuts-style test_res format output consisting of:
|
|
*
|
|
* test-name PASS/FAIL/BROK message
|
|
*
|
|
* the message will tell what type of test and, if it failed, indicate
|
|
* what the failure was.
|
|
*
|
|
* DURATION
|
|
* Terminates
|
|
*
|
|
* SIGNALS
|
|
* None
|
|
*
|
|
* RESOURCES
|
|
* None
|
|
*
|
|
* ENVIRONMENTAL NEEDS
|
|
* No run-time environmental needs.
|
|
*
|
|
* If this test is not called with a full pathname, it must be able
|
|
* to find itself on $PATH
|
|
*
|
|
* INTERCASE DEPENDENCIES
|
|
* none
|
|
*
|
|
* DETAILED DESCRIPTION
|
|
*
|
|
* Setup:
|
|
* Setup signal handling.
|
|
* Create and make current a temporary directory.
|
|
* Open a regular file for writing
|
|
* Create a system pipe
|
|
* Create a named pipe and open it for writing
|
|
*
|
|
* Test:
|
|
* Set the file descriptor for close-on-exec
|
|
* Fork
|
|
* Child execlp's the program "test_open".
|
|
* If the exec fails, exit "2"
|
|
* Parent waits
|
|
* Report results.
|
|
*
|
|
* Cleanup:
|
|
* Close file and pipes
|
|
* Remove the temporary directory
|
|
*
|
|
* BUGS
|
|
*
|
|
*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
|
|
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#include <sys/wait.h>
|
|
#include <limits.h>
|
|
|
|
#include "test.h"
|
|
#include "usctest.h"
|
|
#include "search_path.h"
|
|
|
|
void setup();
|
|
void cleanup(void) __attribute__((noreturn));
|
|
void help();
|
|
|
|
const char *TCID="fcntl07"; /* Test program identifier. */
|
|
int TST_TOTAL=2; /* Total number of test cases. */
|
|
extern int Tst_count; /* Test Case counter for tst_* routines */
|
|
|
|
|
|
|
|
/* for parse_opts */
|
|
int fflag, Tflag; /* binary flags: opt or not */
|
|
char *fopt, *Topt; /* option arguments */
|
|
|
|
option_t options[] = {
|
|
{ "F:", &fflag, &fopt }, /* -F filename */
|
|
{ "T:", &Tflag, &Topt }, /* -T <fd> exec'ed by test: test FD */
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
|
|
int stat_loc; /* for waitpid() */
|
|
|
|
int file_fd, pipe_fds[2];
|
|
/* file descriptors for a file and a system pipe */
|
|
#define DEFAULT_FILE "DefaultFileName"
|
|
const char *File1 = DEFAULT_FILE;
|
|
|
|
#define DEFAULT_SUBPROG "test_open"
|
|
const char *openck = DEFAULT_SUBPROG; /* support program name to check for open FD */
|
|
char subprog_path[_POSIX_PATH_MAX]; /* path to exec "openck" with */
|
|
#define STRSIZE 255
|
|
|
|
int *testfds[] = {
|
|
&file_fd, &pipe_fds[1], 0
|
|
};
|
|
|
|
const char *testfdtypes[] = {
|
|
"regular file",
|
|
"write side of system pipe",
|
|
};
|
|
|
|
int test_open(const char *arg);
|
|
int do_exec(const char *prog, int fd, const char *tcd);
|
|
|
|
int
|
|
main(int ac, char **av)
|
|
{
|
|
int lc; /* loop counter */
|
|
const char *msg; /* message returned from parse_opts */
|
|
|
|
int exec_return; /* return from do_exec */
|
|
int **tcp; /* testcase pointer (pointer to FD) */
|
|
const char **tcd; /* testcase description pointer */
|
|
|
|
/***************************************************************
|
|
* parse standard options, and exit if there is an error
|
|
***************************************************************/
|
|
if ( (msg=parse_opts(ac, av, options, &help)) != (char *) NULL ) {
|
|
tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
|
|
tst_exit();
|
|
}
|
|
|
|
if(fflag) /* -F option */
|
|
File1 = fopt;
|
|
|
|
if(Tflag) { /* -T option */
|
|
exit(test_open(Topt));
|
|
}
|
|
|
|
/***************************************************************
|
|
* perform global setup for test
|
|
***************************************************************/
|
|
setup(av[0]);
|
|
|
|
/***************************************************************
|
|
* check looping state if -c option given
|
|
***************************************************************/
|
|
for (lc=0; TEST_LOOPING(lc); lc++) {
|
|
|
|
/* reset Tst_count in case we are looping. */
|
|
Tst_count=0;
|
|
|
|
for(tcp = testfds, tcd = testfdtypes; *tcp; tcp++, tcd++) {
|
|
|
|
TEST(fcntl(**tcp, F_SETFD, FD_CLOEXEC));
|
|
|
|
/* check return code */
|
|
if ( TEST_RETURN == -1 ) {
|
|
TEST_ERROR_LOG(TEST_ERRNO);
|
|
tst_resm(TFAIL, "fcntl(%s[%d], F_SETFD, FD_CLOEXEC) Failed, errno=%d : %s",
|
|
*tcd, **tcp, TEST_ERRNO, strerror(TEST_ERRNO));
|
|
} else {
|
|
|
|
/*************************************************************
|
|
* only perform functional verification if flag set
|
|
* (-f not given)
|
|
*************************************************************/
|
|
if ( STD_FUNCTIONAL_TEST ) {
|
|
|
|
exec_return = do_exec(subprog_path, **tcp, *tcd);
|
|
|
|
switch(exec_return) {
|
|
case -1:
|
|
tst_resm(TBROK, "fork failed. Errno %s [%d]",
|
|
strerror(errno), errno);
|
|
break;
|
|
case 1:
|
|
tst_resm(TBROK, "waitpid return was 0%o", stat_loc);
|
|
break;
|
|
case 2:
|
|
tst_resm(TBROK, "exec failed"); /* errno was in child */
|
|
break;
|
|
case 0:
|
|
tst_resm(TPASS, "%s child exited 0, indicating that the file was closed",
|
|
*tcd);
|
|
break;
|
|
default:
|
|
tst_resm(TFAIL, "%s child exited non-zero, %d", *tcd,
|
|
exec_return);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} /* End for TEST_LOOPING */
|
|
|
|
/***************************************************************
|
|
* cleanup and exit
|
|
***************************************************************/
|
|
cleanup();
|
|
|
|
return 0;
|
|
} /* End main */
|
|
|
|
/***************************************************************
|
|
* setup() - performs all ONE TIME setup for this test.
|
|
***************************************************************/
|
|
void
|
|
setup(char *path)
|
|
{
|
|
search_path(path, subprog_path, X_OK, 1);
|
|
|
|
/* capture signals */
|
|
tst_sig(FORK, DEF_HANDLER, cleanup);
|
|
|
|
/* create a temporary directory and go to it */
|
|
tst_tmpdir();
|
|
|
|
/* set up a regular file */
|
|
if((file_fd=open(File1, O_CREAT|O_RDWR, 0666)) == -1) {
|
|
tst_brkm(TBROK, cleanup, "Open of file %s failed errno %d (%s)\n", File1, errno, strerror(errno));
|
|
}
|
|
|
|
/* set up a system pipe (write side gets CLOSE-ON-EXEC) */
|
|
pipe(pipe_fds);
|
|
|
|
/* Pause if that option was specified */
|
|
TEST_PAUSE;
|
|
} /* End setup() */
|
|
|
|
|
|
/***************************************************************
|
|
* cleanup() - performs all ONE TIME cleanup for this test at
|
|
* completion or premature exit.
|
|
***************************************************************/
|
|
void
|
|
cleanup()
|
|
{
|
|
/*
|
|
* print timing stats if that option was specified.
|
|
* print errno log if that option was specified.
|
|
*/
|
|
TEST_CLEANUP;
|
|
|
|
/* close everything */
|
|
close(file_fd);
|
|
close(pipe_fds[0]);
|
|
close(pipe_fds[1]);
|
|
|
|
/* remove temporary directory and all files in it. */
|
|
tst_rmdir();
|
|
|
|
/* exit with return code appropriate for results */
|
|
tst_exit();
|
|
} /* End cleanup() */
|
|
|
|
/***************************************************************************
|
|
* issue a help message
|
|
***************************************************************************/
|
|
void
|
|
help()
|
|
{
|
|
printf("-T fd : If this option is given, the program runs as 'test_open'\n");
|
|
printf(" testing <fd> to see if it is open or not and exiting accordingly\n");
|
|
printf("-F name : File to open. Must be an absolute path,\n");
|
|
printf(" and the file must be writable\n");
|
|
printf("-n program: path to the 'test_open' program\n");
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Perform an exec, then wait for the child to terminate.
|
|
* The child's termination status determines the success of the test
|
|
*
|
|
* Return codes:
|
|
* -1 BROK fork failed
|
|
* 1 BROK waitpid returned != exit status
|
|
* <else> ???? exit code from child:
|
|
* 2 BROK exec failed
|
|
* 0 PASS fd was properly closed
|
|
*
|
|
*/
|
|
|
|
int
|
|
do_exec(const char *prog, int fd, const char *tcd)
|
|
{
|
|
int pid;
|
|
char pidname[STRSIZE];
|
|
#ifdef DEBUG
|
|
int rc, status; /* for the fcntl */
|
|
#endif
|
|
|
|
/* set up arguments to exec'ed child */
|
|
sprintf(pidname, "%d", fd);
|
|
|
|
#ifdef DEBUG
|
|
rc = fcntl(fd, F_GETFD, &status);
|
|
printf("%s: fd = %d rc = %d status= %d, errno= %d\n", tcd, fd, rc, status, errno);
|
|
#endif
|
|
|
|
switch(pid=fork()) {
|
|
case -1:
|
|
return(-1);
|
|
case 0: /* child */
|
|
execlp(prog, openck, "-T", pidname, 0);
|
|
|
|
/* the ONLY reason to do this is to get the errno printed out */
|
|
fprintf(stderr, "exec(%s, %s, -T, %s) failed. Errno %s [%d]\n",
|
|
prog, openck, pidname, strerror(errno), errno);
|
|
exit(2);
|
|
default: /* parent */
|
|
waitpid(pid, &stat_loc, 0);
|
|
if(WIFEXITED(stat_loc)) {
|
|
return(WEXITSTATUS(stat_loc));
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* PROGRAM TITLE : Test if a named file descriptor is open
|
|
* This function is called when fcntcs07 is called with the -T option.
|
|
* It tests if a file descriptor is open and exits accordingly.
|
|
*/
|
|
int
|
|
test_open(const char *arg)
|
|
{
|
|
int fd, rc;
|
|
int status;
|
|
|
|
fd = atoi(arg);
|
|
|
|
rc = fcntl(fd, F_GETFD, &status);
|
|
|
|
#ifdef DEBUG_T
|
|
printf("%s: fd = %d rc = %d status= %d, errno= %d\n", openck, fd, rc,
|
|
status, errno);
|
|
#endif
|
|
|
|
if(rc == -1 && errno == EBADF) {
|
|
exit(0);
|
|
}
|
|
|
|
if(rc != -1)
|
|
exit(3);
|
|
|
|
exit(errno);
|
|
return -1; /* to remove compiler warning on IRIX */
|
|
}
|