• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2002
4  *   Copyright (c) Cyril Hrubis chrubis@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 
main(void)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 
crfile(int me,int count)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  */
unlfile(int me,int count)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  */
fussdir(int me,int count)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 
dotest(int me,int count)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 
dowarn(int me,char * m1,char * m2)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  */
term(int sig LTP_ATTRIBUTE_UNUSED)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 
cleanup(void)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