Home | History | Annotate | Download | only in writev
      1 /*
      2  *
      3  *   Copyright (c) International Business Machines  Corp., 2001
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program;  if not, write to the Free Software
     17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     18  */
     19 
     20 /*
     21  * NAME
     22  *	writev05.c
     23  *
     24  * DESCRIPTION
     25  *	These testcases are written to test writev() on sparse files. This
     26  *	is same as writev02.c. But the initial write() with valid data is
     27  *	done at the beginning of the file.
     28  *
     29  * USAGE:  <for command-line>
     30  *      writev05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     31  *      where,  -c n : Run n copies concurrently.
     32  *              -e   : Turn on errno logging.
     33  *              -i n : Execute test n times.
     34  *              -I x : Execute test for x seconds.
     35  *              -P x : Pause for x seconds between iterations.
     36  *              -t   : Turn on syscall timing.
     37  *
     38  * History
     39  *	07/2001 John George
     40  *		-Ported
     41  *      04/2002 wjhuie sigset cleanups
     42  *
     43  * Restrictions
     44  *	NONE
     45  */
     46 
     47 #include <sys/types.h>
     48 #include <signal.h>
     49 #include <sys/uio.h>
     50 #include <fcntl.h>
     51 #include <memory.h>
     52 #include <errno.h>
     53 #include "test.h"
     54 #include <sys/mman.h>
     55 
     56 #define	K_1	8192
     57 
     58 #define	NBUFS		2
     59 #define	CHUNK		K_1	/* single chunk */
     60 #define	MAX_IOVEC	2
     61 #define	DATA_FILE	"writev_data_file"
     62 
     63 char buf1[K_1];
     64 char buf2[K_1];
     65 char buf3[K_1];
     66 
     67 char *bad_addr = 0;
     68 
     69 struct iovec wr_iovec[MAX_IOVEC] = {
     70 	{(caddr_t) - 1, CHUNK},
     71 	{NULL, 0}
     72 };
     73 
     74 char name[K_1], f_name[K_1];
     75 int fd[2], in_sighandler;
     76 char *buf_list[NBUFS];
     77 
     78 char *TCID = "writev05";
     79 int TST_TOTAL = 1;
     80 
     81 void sighandler(int);
     82 long l_seek(int, long, int);
     83 void setup(void);
     84 void cleanup(void);
     85 int fail;
     86 
     87 #if !defined(UCLINUX)
     88 
     89 int main(int argc, char **argv)
     90 {
     91 	int lc;
     92 
     93 	int nbytes;
     94 
     95 	tst_parse_opts(argc, argv, NULL, NULL);
     96 
     97 	setup();		/* set "tstdir", and "testfile" vars */
     98 
     99 	/* The following loop checks looping state if -i option given */
    100 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    101 
    102 		/* reset tst_count in case we are looping */
    103 		tst_count = 0;
    104 
    105 		buf_list[0] = buf1;
    106 		buf_list[1] = buf2;
    107 
    108 		fd[1] = -1;	/* Invalid file descriptor */
    109 
    110 		if (signal(SIGTERM, sighandler) == SIG_ERR) {
    111 			perror("signal");
    112 			tst_resm(TFAIL, "signal() SIGTERM FAILED");
    113 			cleanup();
    114 		}
    115 
    116 		if (signal(SIGPIPE, sighandler) == SIG_ERR) {
    117 			perror("signal");
    118 			tst_resm(TFAIL, "signal() SIGPIPE FAILED");
    119 			cleanup();
    120 		}
    121 
    122 		/* Fill the buf_list[0] and buf_list[1] with 0 zeros */
    123 		memset(buf_list[0], 0, K_1);
    124 		memset(buf_list[1], 0, K_1);
    125 
    126 		if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
    127 			tst_resm(TFAIL, "open(2) failed: fname = %s, "
    128 				 "errno = %d", f_name, errno);
    129 			cleanup();
    130 		} else {
    131 			if ((nbytes = write(fd[0], buf_list[1], K_1)) != K_1) {
    132 				tst_resm(TFAIL, "write(2) failed: nbytes "
    133 					 "= %d, errno = %d", nbytes, errno);
    134 				cleanup();
    135 			}
    136 		}
    137 
    138 		if (close(fd[0]) < 0) {
    139 			tst_resm(TFAIL, "close failed: errno = %d", errno);
    140 			cleanup();
    141 		}
    142 
    143 		if ((fd[0] = open(f_name, O_RDWR, 0666)) < 0) {
    144 			tst_resm(TFAIL, "open failed: fname = %s, errno = %d",
    145 				 f_name, errno);
    146 			cleanup();
    147 		}
    148 
    149 		/*
    150 		 * In this block we are trying to call writev() with invalid
    151 		 * vector to be written in a sparse file. This will return
    152 		 * EFAULT. At the same time, check should be made whether
    153 		 * the scheduled write() with valid data is done correctly
    154 		 * or not.
    155 		 */
    156 //block1:
    157 		tst_resm(TINFO, "Enter block 1");
    158 		fail = 0;
    159 
    160 		l_seek(fd[0], 0, 0);
    161 		TEST(writev(fd[0], wr_iovec, 2));
    162 		if (TEST_RETURN < 0) {
    163 			if (TEST_ERRNO == EFAULT) {
    164 				tst_resm(TINFO, "Received EFAULT as expected");
    165 			} else {
    166 				tst_resm(TFAIL, "Expected EFAULT, got %d",
    167 					 TEST_ERRNO);
    168 				fail = 1;
    169 			}
    170 			l_seek(fd[0], K_1, 0);
    171 			if ((nbytes = read(fd[0], buf_list[0], CHUNK)) != 0) {
    172 				tst_resm(TFAIL, "Expected nbytes = 0, got "
    173 					 "%d", nbytes);
    174 				fail = 1;
    175 			}
    176 		} else {
    177 			tst_resm(TFAIL, "Error writev returned a positive "
    178 				 "value");
    179 			fail = 1;
    180 		}
    181 		if (fail) {
    182 			tst_resm(TINFO, "block 1 FAILED");
    183 		} else {
    184 			tst_resm(TINFO, "block 1 PASSED");
    185 		}
    186 		tst_resm(TINFO, "Exit block 1");
    187 	}
    188 	close(fd[0]);
    189 	close(fd[1]);
    190 	cleanup();
    191 	tst_exit();
    192 
    193 }
    194 
    195 #else
    196 
    197 int main(void)
    198 {
    199 	tst_resm(TINFO, "test is not available on uClinux");
    200 	tst_exit();
    201 }
    202 
    203 #endif /* if !defined(UCLINUX) */
    204 
    205 /*
    206  * setup()
    207  *	performs all ONE TIME setup for this test
    208  */
    209 void setup(void)
    210 {
    211 
    212 	tst_sig(FORK, DEF_HANDLER, cleanup);
    213 
    214 	/* Pause if that option was specified.
    215 	 * TEST_PAUSE contains the code to fork the test with the -i option.
    216 	 * You want to make sure you do this before you create your temporary
    217 	 * directory.
    218 	 */
    219 	TEST_PAUSE;
    220 
    221 	/* Create a unique temporary directory and chdir() to it. */
    222 	tst_tmpdir();
    223 
    224 	strcpy(name, DATA_FILE);
    225 	sprintf(f_name, "%s.%d", name, getpid());
    226 
    227 	bad_addr = mmap(0, 1, PROT_NONE,
    228 			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    229 	if (bad_addr == MAP_FAILED) {
    230 		printf("mmap failed\n");
    231 	}
    232 	wr_iovec[0].iov_base = bad_addr;
    233 
    234 }
    235 
    236 /*
    237  * cleanup()
    238  *	performs all ONE TIME cleanup for this test at
    239  *	completion or premature exit
    240  */
    241 void cleanup(void)
    242 {
    243 
    244 	if (unlink(f_name) < 0) {
    245 		tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
    246 			 f_name, errno);
    247 	}
    248 	tst_rmdir();
    249 
    250 }
    251 
    252 /*
    253  * sighandler()
    254  *	Signal handler for SIGTERM and SIGPIPE
    255  */
    256 void sighandler(int sig)
    257 {
    258 	switch (sig) {
    259 	case SIGTERM:
    260 		break;
    261 	case SIGPIPE:
    262 		++in_sighandler;
    263 		return;
    264 	default:
    265 		tst_resm(TFAIL, "sighandler() received invalid signal "
    266 			 ": %d", sig);
    267 		break;
    268 	}
    269 
    270 	if ((unlink(f_name) < 0) && (errno != ENOENT)) {
    271 		tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
    272 			 f_name, errno);
    273 		cleanup();
    274 	}
    275 	exit(sig);
    276 }
    277 
    278 /*
    279  * l_seek()
    280  *	Wrap around for regular lseek() to give error message on failure
    281  */
    282 long l_seek(int fdesc, long offset, int whence)
    283 {
    284 	if (lseek(fdesc, offset, whence) < 0) {
    285 		tst_resm(TFAIL, "lseek Failed : errno = %d", errno);
    286 		fail = 1;
    287 	}
    288 	return 0;
    289 }
    290