Home | History | Annotate | Download | only in ftest
      1 /*
      2  *
      3  *   Copyright (c) International Business Machines  Corp., 2002
      4  *   Copyright (c) Cyril Hrubis chrubis (at) suse.cz 2009
      5  *
      6  *   This program is free software;  you can redistribute it and/or modify
      7  *   it under the terms of the GNU General Public License as published by
      8  *   the Free Software Foundation; either version 2 of the License, or
      9  *   (at your option) any later version.
     10  *
     11  *   This program is distributed in the hope that it will be useful,
     12  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     14  *   the GNU General Public License for more details.
     15  *
     16  *   You should have received a copy of the GNU General Public License
     17  *   along with this program;  if not, write to the Free Software
     18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     19  */
     20 
     21 /*
     22  * NAME
     23  *	ftest02.c -- test inode things (ported from SPIE section2, filesuite, by Airong Zhang)
     24  *
     25  * CALLS
     26  *	open, close,  read, write, lseek,
     27  *	unlink, chdir
     28  *
     29  *
     30  * ALGORITHM
     31  *
     32  *
     33  *	ftest02 [-f tmpdirname] nchild iterations [partition]
     34  *
     35  *	This forks some child processes, they do some random operations
     36  *	which use lots of directory operations.
     37  *
     38  * RESTRICTIONS
     39  *	Runs a long time with default args - can take others on input
     40  *	line.  Use with "term mode".
     41  *	If run on vax the ftruncate will not be random - will always go to
     42  *	start of file.  NOTE: produces a very high load average!!
     43  *
     44  */
     45 
     46 #include <stdio.h>
     47 #include <sys/types.h>
     48 #include <sys/param.h>
     49 #include <sys/wait.h>
     50 #include <fcntl.h>
     51 #include <sys/stat.h>
     52 #include <errno.h>
     53 #include <sys/mount.h>
     54 #include <signal.h>
     55 #include <unistd.h>
     56 #include "test.h"
     57 #include "libftest.h"
     58 
     59 #define MAXCHILD	25
     60 #define K_1		1024
     61 #define K_2		2048
     62 #define K_4		4096
     63 
     64 char *TCID = "ftest02";
     65 int TST_TOTAL = 1;
     66 
     67 #define PASSED 1
     68 #define FAILED 0
     69 
     70 static void crfile(int, int);
     71 static void unlfile(int, int);
     72 static void fussdir(int, int);
     73 static void dotest(int, int);
     74 static void dowarn(int, char *, char *);
     75 static void term(int sig);
     76 static void cleanup(void);
     77 
     78 #define	M	(1024*1024)
     79 
     80 static int iterations;
     81 static int nchild;
     82 static int parent_pid;
     83 static int pidlist[MAXCHILD];
     84 
     85 static char homedir[MAXPATHLEN];
     86 static char dirname[MAXPATHLEN];
     87 static char tmpname[MAXPATHLEN];
     88 static int dirlen;
     89 static int mnt = 0;
     90 static char startdir[MAXPATHLEN], mntpoint[MAXPATHLEN];
     91 static char *partition;
     92 static char *cwd;
     93 static char *fstyp;
     94 static int local_flag;
     95 
     96 int main(void)
     97 {
     98 	int k, j, pid, child, status, count;
     99 	char name[128];
    100 
    101 	/*
    102 	 * Default values for run conditions.
    103 	 */
    104 	iterations = 50;
    105 	nchild = 5;
    106 
    107 	if (signal(SIGTERM, term) == SIG_ERR) {
    108 		tst_resm(TFAIL, "first signal failed");
    109 
    110 	}
    111 
    112 	/*
    113 	 * Make a directory to do this in; ignore error if already exists.
    114 	 */
    115 	local_flag = PASSED;
    116 	parent_pid = getpid();
    117 	tst_tmpdir();
    118 
    119 	if (!startdir[0]) {
    120 		if (getcwd(startdir, MAXPATHLEN) == NULL) {
    121 			tst_resm(TBROK, "getcwd failed");
    122 
    123 		}
    124 	}
    125 	cwd = startdir;
    126 	strcat(dirname, cwd);
    127 	sprintf(tmpname, "/ftest02.%d", getpid());
    128 	strcat(dirname, tmpname);
    129 	strcat(homedir, cwd);
    130 	sprintf(tmpname, "/ftest02h.%d", getpid());
    131 	strcat(homedir, tmpname);
    132 
    133 	mkdir(dirname, 0755);
    134 	mkdir(homedir, 0755);
    135 	if (chdir(dirname) < 0) {
    136 		tst_resm(TBROK, "\tCan't chdir(%s), error %d.", dirname, errno);
    137 		cleanup();
    138 
    139 	}
    140 	dirlen = strlen(dirname);
    141 	if (chdir(homedir) < 0) {
    142 		tst_resm(TBROK, "\tCan't chdir(%s), error %d.", homedir, errno);
    143 		cleanup();
    144 
    145 	}
    146 
    147 	for (k = 0; k < nchild; k++) {
    148 		if ((child = fork()) == 0) {
    149 			dotest(k, iterations);
    150 			exit(0);
    151 		}
    152 		if (child < 0) {
    153 			tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
    154 		}
    155 		pidlist[k] = child;
    156 	}
    157 
    158 	/*
    159 	 * Wait for children to finish.
    160 	 */
    161 	count = 0;
    162 	while ((child = wait(&status)) > 0) {
    163 		//tst_resm(TINFO,"Test{%d} exited status = 0x%x", child, status);
    164 		//tst_resm(TINFO,"status is %d",status);
    165 		if (status) {
    166 			tst_resm(TFAIL, "Test{%d} failed, expected 0 exit.",
    167 				 child);
    168 			local_flag = FAILED;
    169 		}
    170 		++count;
    171 	}
    172 
    173 	/*
    174 	 * Should have collected all children.
    175 	 */
    176 	if (count != nchild) {
    177 		tst_resm(TFAIL, "Wrong # children waited on, count = %d",
    178 			 count);
    179 		local_flag = FAILED;
    180 	}
    181 
    182 	if (local_flag == FAILED)
    183 		tst_resm(TFAIL, "Test failed in fork-wait part.");
    184 	else
    185 		tst_resm(TPASS, "Test passed in fork-wait part.");
    186 
    187 	if (iterations > 26)
    188 		iterations = 26;
    189 
    190 	for (k = 0; k < nchild; k++)
    191 		for (j = 0; j < iterations + 1; j++) {
    192 			ft_mkname(name, dirname, k, j);
    193 			rmdir(name);
    194 			unlink(name);
    195 		}
    196 
    197 	chdir(startdir);
    198 
    199 	pid = fork();
    200 
    201 	if (pid < 0) {
    202 		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
    203 	}
    204 
    205 	if (pid == 0) {
    206 		execl("/bin/rm", "rm", "-rf", homedir, NULL);
    207 		exit(1);
    208 	} else
    209 		wait(&status);
    210 
    211 	if (status)
    212 		tst_resm(TINFO,
    213 			 "CAUTION - ftest02, '%s' may not have been removed.",
    214 			 homedir);
    215 
    216 	pid = fork();
    217 
    218 	if (pid < 0) {
    219 		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
    220 	}
    221 
    222 	if (pid == 0) {
    223 		execl("/bin/rm", "rm", "-rf", dirname, NULL);
    224 		exit(1);
    225 	} else
    226 		wait(&status);
    227 
    228 	if (status) {
    229 		tst_resm(TINFO,
    230 			 "CAUTION - ftest02, '%s' may not have been removed.",
    231 			 dirname);
    232 	}
    233 
    234 	sync();
    235 
    236 	cleanup();
    237 
    238 	tst_exit();
    239 }
    240 
    241 #define	warn(val,m1,m2)	if ((val) < 0) dowarn(me,m1,m2)
    242 
    243 /*
    244  * crfile()
    245  *	Create a file and write something into it.
    246  */
    247 
    248 char crmsg[] = "Gee, let's write something in the file!\n";
    249 
    250 static void crfile(int me, int count)
    251 {
    252 	int fd, val;
    253 	char fname[MAXPATHLEN], buf[MAXPATHLEN];
    254 
    255 	ft_mkname(fname, dirname, me, count);
    256 
    257 	fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
    258 	if (fd < 0 && errno == EISDIR) {
    259 		val = rmdir(fname);
    260 		warn(val, "rmdir", fname);
    261 		fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
    262 	}
    263 	warn(fd, "creating", fname);
    264 
    265 	val = lseek(fd, (rand() % M), 0);
    266 	warn(val, "lseek", 0);
    267 
    268 	val = write(fd, crmsg, sizeof(crmsg) - 1);
    269 	warn(val, "write", 0);
    270 
    271 	val = lseek(fd, -((off_t) sizeof(crmsg) - 1), 1);
    272 	warn(val, "lseek", 0);
    273 
    274 	val = read(fd, buf, sizeof(crmsg) - 1);
    275 	warn(val, "read", 0);
    276 
    277 	if (strncmp(crmsg, buf, sizeof(crmsg) - 1))
    278 		dowarn(me, "compare", 0);
    279 
    280 	val = close(fd);
    281 	warn(val, "close", 0);
    282 }
    283 
    284 /*
    285  * unlfile()
    286  *	Unlink some of the files.
    287  */
    288 static void unlfile(int me, int count)
    289 {
    290 	int i;
    291 	int val;
    292 	char fname[MAXPATHLEN];
    293 
    294 	i = count - 10;
    295 
    296 	if (i < 0)
    297 		i = 0;
    298 
    299 	for (; i < count; i++) {
    300 		ft_mkname(fname, dirname, me, i);
    301 		val = rmdir(fname);
    302 		if (val < 0)
    303 			val = unlink(fname);
    304 		if (val == 0 || errno == ENOENT)
    305 			continue;
    306 		dowarn(me, "unlink", fname);
    307 	}
    308 }
    309 
    310 /*
    311  * fussdir()
    312  *	Make a directory, put stuff in it, remove it, and remove directory.
    313  *
    314  * Randomly leave the directory there.
    315  */
    316 static void fussdir(int me, int count)
    317 {
    318 	int val;
    319 	char dir[MAXPATHLEN], fname[MAXPATHLEN], savedir[MAXPATHLEN];
    320 
    321 	ft_mkname(dir, dirname, me, count);
    322 	rmdir(dir);
    323 	unlink(dir);
    324 
    325 	val = mkdir(dir, 0755);
    326 	warn(val, "mkdir", dir);
    327 
    328 	/*
    329 	 * Arrange to create files in the directory.
    330 	 */
    331 	strcpy(savedir, dirname);
    332 	strcpy(dirname, "");
    333 
    334 	val = chdir(dir);
    335 	warn(val, "chdir", dir);
    336 
    337 	crfile(me, count);
    338 	crfile(me, count + 1);
    339 
    340 	val = chdir("..");
    341 	warn(val, "chdir", "..");
    342 
    343 	val = rmdir(dir);
    344 
    345 	if (val >= 0) {
    346 		tst_brkm(TFAIL, NULL,
    347 			 "Test[%d]: rmdir of non-empty %s succeeds!", me,
    348 			 dir);
    349 	}
    350 
    351 	val = chdir(dir);
    352 	warn(val, "chdir", dir);
    353 
    354 	ft_mkname(fname, dirname, me, count);
    355 	val = unlink(fname);
    356 	warn(val, "unlink", fname);
    357 
    358 	ft_mkname(fname, dirname, me, count + 1);
    359 	val = unlink(fname);
    360 	warn(val, "unlink", fname);
    361 
    362 	val = chdir(homedir);
    363 	warn(val, "chdir", homedir);
    364 
    365 	if (rand() & 0x01) {
    366 		val = rmdir(dir);
    367 		warn(val, "rmdir", dir);
    368 	}
    369 
    370 	strcpy(dirname, savedir);
    371 }
    372 
    373 /*
    374  * dotest()
    375  *	Children execute this.
    376  *
    377  * Randomly do an inode thing; loop for # iterations.
    378  */
    379 #define	THING(p)	{p, "p"}
    380 
    381 struct ino_thing {
    382 	void (*it_proc) ();
    383 	char *it_name;
    384 } ino_thing[] = {
    385 THING(crfile), THING(unlfile), THING(fussdir), THING(sync),};
    386 
    387 #define	NTHING	ARRAY_SIZE(ino_thing)
    388 
    389 int thing_cnt[NTHING];
    390 int thing_last[NTHING];
    391 
    392 static void dotest(int me, int count)
    393 {
    394 	int i, thing;
    395 
    396 	//tst_resm(TINFO,"Test %d pid %d starting.", me, getpid());
    397 
    398 	srand(getpid());
    399 
    400 	for (i = 0; i < count; i++) {
    401 		thing = (rand() >> 3) % NTHING;
    402 		(*ino_thing[thing].it_proc) (me, i, ino_thing[thing].it_name);
    403 		++thing_cnt[thing];
    404 	}
    405 
    406 	//tst_resm(TINFO,"Test %d pid %d exiting.", me, getpid());
    407 }
    408 
    409 static void dowarn(int me, char *m1, char *m2)
    410 {
    411 	int err = errno;
    412 
    413 	tst_brkm(TBROK, NULL, "Test[%d]: error %d on %s %s",
    414 		 me, err, m1, (m2 ? m2 : ""));
    415 }
    416 
    417 /*
    418  * SIGTERM signal handler.
    419  */
    420 static void term(int sig LTP_ATTRIBUTE_UNUSED)
    421 {
    422 	int i;
    423 
    424 	if (parent_pid == getpid()) {
    425 		for (i = 0; i < nchild; i++)
    426 			if (pidlist[i])
    427 				kill(pidlist[i], SIGTERM);
    428 		return;
    429 	}
    430 
    431 	tst_brkm(TBROK, NULL, "Child process exiting.");
    432 }
    433 
    434 static void cleanup(void)
    435 {
    436 	char mount_buffer[1024];
    437 
    438 	if (mnt == 1) {
    439 
    440 		if (chdir(startdir) < 0)
    441 			tst_resm(TBROK, "Could not change to %s ", startdir);
    442 
    443 		if (!strcmp(fstyp, "cfs")) {
    444 
    445 			sprintf(mount_buffer, "/bin/umount %s", partition);
    446 
    447 			if (system(mount_buffer) != 0) {
    448 
    449 				tst_resm(TBROK, "Unable to unmount %s from %s ",
    450 					 partition, mntpoint);
    451 
    452 				if (umount(partition))
    453 					tst_resm(TBROK,
    454 						 "Unable to unmount %s from %s ",
    455 						 partition, mntpoint);
    456 				else
    457 					tst_resm(TINFO,
    458 						 "Forced umount for %s, /etc/mtab now dirty",
    459 						 partition);
    460 			}
    461 
    462 		} else if (umount(partition))
    463 			tst_resm(TBROK, "Unable to unmount %s from %s ",
    464 				 partition, mntpoint);
    465 
    466 		if (rmdir(mntpoint) != 0)
    467 			tst_resm(TBROK, "Unable to rmdir %s ", mntpoint);
    468 
    469 	}
    470 
    471 	tst_rmdir();
    472 }
    473