• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@us.ibm.com */
21 /* 10/30/2002	Port to LTP	dbarrera@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 
usage(void)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 
main(int argc,char * argv[])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 
runtest(void)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 
getchild(int group,int child,int children)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 
term(int sig)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 
chld(int sig)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 
dochild1(void)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 
dochild2(void)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 
dochild3(int group)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 
massmurder(void)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 
setup(void)448 void setup(void)
449 {
450 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
451 
452 	TEST_PAUSE;
453 
454 	tst_tmpdir();
455 }
456 
cleanup(void)457 void cleanup(void)
458 {
459 	tst_rmdir();
460 }
461