Home | History | Annotate | Download | only in mkdir
      1 /*
      2  *
      3  *   Copyright (c) International Business Machines  Corp., 2002
      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 /* 06/30/2001	Port to Linux	nsharoff (at) us.ibm.com */
     21 /* 10/30/2002	Port to LTP	dbarrera (at) us.ibm.com */
     22 
     23 /*
     24  * Stress test of mkdir call.
     25  *
     26  * ALGORITHM
     27  *	Create multiple processes which create subdirectories in the
     28  *	same directory multiple times. On exit of all child processes,
     29  *	make sure all subdirectories can be removed.
     30  *
     31  *      USAGE: mkdir09 -c # -t # -d #
     32  *              -c = number of children groups
     33  *              -t = number of seconds to run test
     34  *              -d = number of directories created in test directory
     35  *
     36  */
     37 
     38 #include <stdio.h>
     39 #include <sys/wait.h>
     40 #include <sys/types.h>
     41 #include <sys/param.h>
     42 #include <sys/stat.h>
     43 #include <sys/mman.h>
     44 #include <errno.h>
     45 #include <signal.h>
     46 #include <unistd.h>
     47 #include <setjmp.h>
     48 #include "test.h"
     49 
     50 #include <stdlib.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 
     54 #define NCHILD		3
     55 
     56 #define MODE_RWX	07770
     57 #define DIR_NAME	"./X.%d"
     58 
     59 char *TCID = "mkdir09";
     60 int TST_TOTAL = 1;
     61 
     62 char testdir[MAXPATHLEN];
     63 int parent_pid, sigchld, sigterm, jump;
     64 void term(int sig);
     65 void chld(int sig);
     66 int *pidlist, child_count;
     67 jmp_buf env_buf;
     68 
     69 int getchild(int group, int child, int children);
     70 int dochild1(void);
     71 int dochild2(void);
     72 int dochild3(int group);
     73 int massmurder(void);
     74 int runtest(void);
     75 void setup(void);
     76 void cleanup(void);
     77 
     78 static int child_groups = 2;
     79 static int test_time = 5;
     80 static int nfiles = 5;
     81 
     82 static char *opt_child_groups;
     83 static char *opt_test_time;
     84 static char *opt_nfiles;
     85 
     86 static option_t options[] = {
     87 	{"c:", NULL, &opt_child_groups},
     88 	{"t:", NULL, &opt_test_time},
     89 	{"d:", NULL, &opt_nfiles},
     90 	{NULL, NULL, NULL}
     91 };
     92 
     93 static void usage(void)
     94 {
     95 	printf("  -c      Child groups\n");
     96 	printf("  -t      Test runtime\n");
     97 	printf("  -d      Directories\n");
     98 }
     99 
    100 int main(int argc, char *argv[])
    101 {
    102 	tst_parse_opts(argc, argv, options, usage);
    103 
    104 	if (opt_child_groups)
    105 		child_groups = atoi(opt_child_groups);
    106 
    107 	if (opt_test_time)
    108 		test_time = atoi(opt_test_time);
    109 
    110 	if (opt_nfiles)
    111 		nfiles = atoi(opt_nfiles);
    112 
    113 	setup();
    114 
    115 	if (signal(SIGTERM, term) == SIG_ERR) {
    116 		tst_brkm(TFAIL, cleanup,
    117 			 "Error setting up SIGTERM signal, ERRNO = %d", errno);
    118 
    119 	}
    120 
    121 	if (signal(SIGCHLD, chld) == SIG_ERR) {
    122 		tst_brkm(TFAIL, cleanup,
    123 			 "Error setting up SIGCHLD signal, ERRNO = %d", errno);
    124 
    125 	}
    126 
    127 	runtest();
    128 	cleanup();
    129 	tst_exit();
    130 }
    131 
    132 int runtest(void)
    133 {
    134 	int i, j;
    135 	int count, child, status;
    136 	char tmpdir[MAXPATHLEN];
    137 
    138 	/* Create permanent directories with holes in directory structure */
    139 
    140 	for (j = 0; j < nfiles; j++) {
    141 		sprintf(tmpdir, DIR_NAME, j);
    142 		TEST(mkdir(tmpdir, MODE_RWX));
    143 
    144 		if (TEST_RETURN < 0) {
    145 			tst_brkm(TFAIL, cleanup,
    146 				 "Error creating permanent directories, ERRNO = %d",
    147 				 TEST_ERRNO);
    148 		}
    149 		if ((j % NCHILD) != 0) {
    150 			if (rmdir(tmpdir) < 0) {
    151 				tst_brkm(TFAIL, cleanup,
    152 					 "Error removing directory, ERRNO = %d",
    153 					 errno);
    154 			}
    155 		}
    156 	}
    157 
    158 	parent_pid = getpid();
    159 
    160 	/* allocate space for list of child pid's */
    161 
    162 	if ((pidlist = malloc((child_groups * NCHILD) * sizeof(int))) ==
    163 	    NULL) {
    164 		tst_brkm(TWARN, NULL,
    165 			 "\tMalloc failed (may be OK if under stress)");
    166 	}
    167 
    168 	child_count = 0;
    169 	for (j = 0; j < child_groups; j++) {
    170 		for (i = 0; i < NCHILD; i++) {
    171 			getchild(j, i, child_count);
    172 			child_count++;
    173 		}
    174 	}
    175 
    176 	/* If signal already received, skip to cleanup */
    177 
    178 	if (!sigchld && !sigterm) {
    179 		if (test_time) {
    180 			/* To get out of sleep if signal caught */
    181 			if (!setjmp(env_buf)) {
    182 				jump++;
    183 				sleep(test_time);
    184 			}
    185 		} else {
    186 			pause();
    187 		}
    188 	}
    189 
    190 	/* Reset signals since we are about to clean-up and to avoid
    191 	 * problem with wait call *               $
    192 	 * */
    193 
    194 	if (signal(SIGTERM, SIG_IGN) == SIG_ERR) {
    195 		tst_brkm(TFAIL, cleanup,
    196 			 "Error resetting SIGTERM signal, ERRNO = %d", errno);
    197 	}
    198 	if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
    199 		tst_brkm(TFAIL, cleanup,
    200 			 "Error resetting SIGCHLD signal, ERRNO = %d", errno);
    201 	}
    202 
    203 	if (test_time) {
    204 		sleep(test_time);
    205 	}
    206 
    207 	/* Clean up children */
    208 	massmurder();
    209 	/*
    210 	 * Watch children finish and show returns.
    211 	 */
    212 
    213 	count = 0;
    214 	while (1) {
    215 		if ((child = wait(&status)) > 0) {
    216 			if (status != 0) {
    217 				tst_brkm(TWARN,
    218 					 NULL,
    219 					 "\tChild{%d} exited status = %0x",
    220 					 child, status);
    221 			}
    222 			count++;
    223 		} else {
    224 			if (errno != EINTR) {
    225 				break;
    226 			}
    227 			tst_resm(TINFO, "\tSignal detected during wait");
    228 		}
    229 	}
    230 
    231 	/*
    232 	 * Make sure correct number of children exited.
    233 	 */
    234 
    235 	if (count != child_count) {
    236 		tst_resm(TWARN, "\tWrong number of children waited on!");
    237 		tst_brkm(TWARN, NULL, "\tSaw %d, expected %d", count,
    238 			 NCHILD);
    239 	}
    240 
    241 	/* Check for core file in test directory. */
    242 
    243 	if (access("core", 0) == 0) {
    244 		tst_brkm(TWARN, NULL, "\tCore file found in test directory.");
    245 	}
    246 
    247 	/* Remove expected files */
    248 
    249 	for (j = 0; j < nfiles; j += NCHILD) {
    250 		sprintf(tmpdir, DIR_NAME, j);
    251 		if (rmdir(tmpdir) < 0) {
    252 			tst_brkm(TWARN,
    253 				 NULL,
    254 				 "\tError removing expected directory, ERRNO = %d",
    255 				 errno);
    256 		}
    257 	}
    258 
    259 	tst_resm(TPASS, "PASS");
    260 
    261 	return 0;
    262 }
    263 
    264 int getchild(int group, int child, int children)
    265 {
    266 	int pid;
    267 
    268 	pid = FORK_OR_VFORK();
    269 
    270 	if (pid < 0) {
    271 
    272 		massmurder();	/* kill the kids */
    273 		tst_brkm(TBROK, cleanup,
    274 			 "\tFork failed (may be OK if under stress)");
    275 	} else if (pid == 0) {	/* child does this */
    276 		switch (children % NCHILD) {
    277 		case 0:
    278 			dochild1();	/* create existing directories */
    279 			break;	/* so lint won't complain */
    280 		case 1:
    281 			dochild2();	/* remove nonexistant directories */
    282 			break;
    283 		case 2:
    284 			dochild3(group);	/* create/delete directories */
    285 			break;
    286 		default:
    287 			tst_brkm(TFAIL, cleanup,
    288 				 "Test not inplemented for child %d", child);
    289 			exit(1);
    290 			break;
    291 		}
    292 		exit(1);	/* If child gets here, something wrong */
    293 	}
    294 	pidlist[children] = pid;
    295 	return 0;
    296 }
    297 
    298 void term(int sig)
    299 {
    300 	/* Routine to handle SIGTERM signal. */
    301 
    302 	if (parent_pid == getpid()) {
    303 		tst_brkm(TWARN, NULL, "\tsignal SIGTERM received by parent.");
    304 	}
    305 	sigterm++;
    306 	if (jump) {
    307 		longjmp(env_buf, 1);
    308 	}
    309 }
    310 
    311 void chld(int sig)
    312 {
    313 	/* Routine to handle SIGCHLD signal. */
    314 
    315 	sigchld++;
    316 	if (jump) {
    317 		longjmp(env_buf, 1);
    318 	}
    319 }
    320 
    321 int dochild1(void)
    322 {
    323 	/* Child routine which attempts to create directories in the test
    324 	 * directory that already exist. Runs until a SIGTERM signal is
    325 	 * received. Will exit with an error if it is able to create the
    326 	 * directory or if the expected error is not received.
    327 	 */
    328 
    329 	int j;
    330 	char tmpdir[MAXPATHLEN];
    331 
    332 	while (!sigterm) {
    333 		for (j = 0; j < nfiles; j += NCHILD) {
    334 			sprintf(tmpdir, DIR_NAME, j);
    335 			TEST(mkdir(tmpdir, MODE_RWX));
    336 
    337 			if (TEST_RETURN < 0) {
    338 
    339 				if (TEST_ERRNO != EEXIST) {
    340 					tst_brkm(TFAIL, cleanup,
    341 						 "MKDIR %s, errno = %d; Wrong error detected.",
    342 						 tmpdir, TEST_ERRNO);
    343 					exit(1);
    344 				}
    345 			} else {
    346 				tst_brkm(TFAIL, cleanup,
    347 					 "MKDIR %s succeded when it shoud have failed.",
    348 					 tmpdir);
    349 				exit(1);
    350 			}
    351 		}
    352 	}
    353 	exit(0);
    354 }
    355 
    356 int dochild2(void)
    357 {
    358 	/* Child routine which attempts to remove directories from the
    359 	 * test directory which do not exist. Runs until a SIGTERM
    360 	 * signal is received. Exits with an error if the proper
    361 	 * error is not detected or if the remove operation is
    362 	 * successful.
    363 	 */
    364 
    365 	int j;
    366 	char tmpdir[MAXPATHLEN];
    367 
    368 	while (!sigterm) {
    369 		for (j = 1; j < nfiles; j += NCHILD) {
    370 			sprintf(tmpdir, DIR_NAME, j);
    371 			if (rmdir(tmpdir) < 0) {
    372 				if (errno != ENOENT) {
    373 					tst_brkm(TFAIL, cleanup,
    374 						 "RMDIR %s, errno = %d; Wrong error detected.",
    375 						 tmpdir, errno);
    376 					exit(1);
    377 				}
    378 			} else {
    379 				tst_brkm(TFAIL, cleanup,
    380 					 "RMDIR %s succeded when it should have failed.",
    381 					 tmpdir);
    382 				exit(1);
    383 			}
    384 		}
    385 	}
    386 	exit(0);
    387 	return 0;
    388 }
    389 
    390 int dochild3(int group)
    391 {
    392 	/* Child routine which creates and deletes directories in the
    393 	 * test directory. Runs until a SIGTERM signal is received, then
    394 	 * cleans up and exits. Detects error if the expected condition
    395 	 * is not encountered.
    396 	 */
    397 
    398 	int j;
    399 
    400 	char tmpdir[MAXPATHLEN];
    401 	char tmp[MAXPATHLEN];
    402 
    403 	while (!sigterm) {
    404 		for (j = 2; j < nfiles; j += NCHILD) {
    405 			strcpy(tmp, DIR_NAME);
    406 			strcat(tmp, ".%d");
    407 			sprintf(tmpdir, tmp, j, group);
    408 
    409 			TEST(mkdir(tmpdir, MODE_RWX));
    410 
    411 			if (TEST_RETURN < 0) {
    412 				tst_brkm(TFAIL, cleanup,
    413 					 "MKDIR %s, errno = %d; Wrong error detected.",
    414 					 tmpdir, TEST_ERRNO);
    415 				exit(1);
    416 			}
    417 		}
    418 		for (j = 2; j < nfiles; j += NCHILD) {
    419 			strcpy(tmp, DIR_NAME);
    420 			strcat(tmp, ".%d");
    421 			sprintf(tmpdir, tmp, j, group);
    422 			if (rmdir(tmpdir) < 0) {
    423 				tst_brkm(TFAIL, cleanup,
    424 					 "RMDIR %s, errno = %d; Wrong error detected.",
    425 					 tmpdir, errno);
    426 				exit(1);
    427 			}
    428 		}
    429 	}
    430 	exit(0);
    431 }
    432 
    433 int massmurder(void)
    434 {
    435 	register int j;
    436 	for (j = 0; j < child_count; j++) {
    437 		if (pidlist[j] > 0) {
    438 			if (kill(pidlist[j], SIGTERM) < 0) {
    439 				tst_brkm(TFAIL, cleanup,
    440 					 "Error killing child %d, ERRNO = %d",
    441 					 j, errno);
    442 			}
    443 		}
    444 	}
    445 	return 0;
    446 }
    447 
    448 void setup(void)
    449 {
    450 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
    451 
    452 	TEST_PAUSE;
    453 
    454 	tst_tmpdir();
    455 }
    456 
    457 void cleanup(void)
    458 {
    459 	tst_rmdir();
    460 }
    461