ftest02.c revision af64a878a5f86f98675e1d00691f12f9fa57bd8f
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
22 *	ftest02.c -- test inode things (ported from SPIE section2, filesuite, by Airong Zhang)
23 *
24 * CALLS
25 *	open, close,  read, write, lseek,
26 *	unlink, chdir
27 *
28 *
29 * ALGORITHM
30 *
31 *
32 *	ftest02 [-f tmpdirname] nchild iterations [partition]
33 *
34 *	This forks some child processes, they do some random operations
35 *	which use lots of directory operations.
36 *
37 * RESTRICTIONS
38 *	Runs a long time with default args - can take others on input
39 *	line.  Use with "term mode".
40 *	If run on vax the ftruncate will not be random - will always go to
41 *	start of file.  NOTE: produces a very high load average!!
42 *
43 */
44
45
46#include <stdio.h>		/* needed by testhead.h		*/
47#include "test.h"	/* standard test header		*/
48#include "usctest.h"
49#include <sys/types.h>
50#include <sys/param.h>
51#include <sys/wait.h>
52#include <fcntl.h>
53#include <sys/stat.h>
54#include <errno.h>
55#include <sys/mount.h>
56#include <signal.h>		/* DEM - added SIGTERM support */
57#include <unistd.h>
58
59#define MAXCHILD	25	/* max number of children to allow */
60#define K_1		1024
61#define K_2		2048
62#define K_4		4096
63
64
65char *TCID = "ftest02";
66int TST_TOTAL = 1;
67extern int Tst_count;
68
69#define PASSED 1
70#define FAILED 0
71
72void crfile(int, int);
73void unlfile(int, int);
74void fussdir(int, int);
75int dotest(int, int);
76void Warn(int, char*, char*);
77int mkname(char*, int, int);
78int term();
79void cleanup();
80
81/*--------------------------------------------------------------*/
82
83
84#define	M	(1024*1024)
85/* #define temp stderr */
86
87int	iterations;			/* # total iterations */
88int	nchild;
89int	parent_pid;
90int	pidlist[MAXCHILD];
91
92char	homedir[MAXPATHLEN];
93char	dirname[MAXPATHLEN];
94char	tmpname[MAXPATHLEN];
95char	*prog;
96int	dirlen;
97int 	mnt = 0;
98char	startdir[MAXPATHLEN], mntpoint[MAXPATHLEN], newfsstring[90];
99char	*partition;
100char 	*cwd;
101char 	*fstyp;
102int 	local_flag;
103
104/*--------------------------------------------------------------*/
105int main (ac, av)
106	int  ac;
107	char *av[];
108{
109	register int k, j;
110	int	pid;
111	int	child;
112	int	status;
113	int	count;
114	char	name[3];
115
116
117	/*
118	 * Default values for run conditions.
119	 */
120
121	iterations = 50;
122	nchild = 5;
123
124	if (signal(SIGTERM, (void (*)())term) == SIG_ERR) {
125		tst_resm(TFAIL, "first signal failed");
126		tst_exit();
127	}
128
129	/*
130	 * Make a directory to do this in; ignore error if already exists.
131	 */
132
133
134	local_flag = PASSED;
135	parent_pid = getpid();
136	tst_tmpdir();
137
138	if (!startdir[0]) {
139		if (getcwd(startdir, MAXPATHLEN) == NULL) {
140			tst_resm(TBROK,"getcwd failed");
141			tst_exit();
142		}
143	}
144	cwd = startdir;
145	strcat(dirname, cwd);
146	sprintf(tmpname, "/ftest02.%d", getpid());
147	strcat(dirname, tmpname);
148	strcat(homedir, cwd);
149	sprintf(tmpname, "/ftest02h.%d", getpid());
150	strcat(homedir, tmpname);
151
152	mkdir(dirname, 0755);
153	mkdir(homedir, 0755);
154	if (chdir(dirname) < 0) {
155		tst_resm(TBROK,"\tCan't chdir(%s), error %d.", dirname, errno);
156		cleanup();
157		tst_exit();
158	}
159	dirlen = strlen(dirname);
160	if (chdir(homedir) < 0) {
161		tst_resm(TBROK,"\tCan't chdir(%s), error %d.", homedir, errno);
162		cleanup();
163		tst_exit();
164	}
165
166
167	for(k = 0; k < nchild; k++) {
168		if ((child = fork()) == 0) {		/* child */
169			dotest(k, iterations);		/* do it! */
170			exit(0);
171		}
172		if (child < 0) {
173			tst_resm(TINFO, "System resource may be too low, fork() malloc()"
174					   " etc are likely to fail.");
175			tst_resm(TBROK, "Test broken due to inability of fork.");
176			cleanup();
177		}
178		pidlist[k] = child;
179	} /* end for */
180
181		/*
182		 * Wait for children to finish.
183	 */
184
185	count = 0;
186	while((child = wait(&status)) > 0) {
187		//tst_resm(TINFO,"Test{%d} exited status = 0x%x", child, status);
188		//tst_resm(TINFO,"status is %d",status);
189		if (status) {
190			tst_resm(TFAIL,"Test{%d} failed, expected 0 exit.", child);
191			local_flag = FAILED;
192		}
193		++count;
194	}
195
196	/*
197	 * Should have collected all children.
198	 */
199
200	if (count != nchild) {
201		tst_resm(TFAIL,"Wrong # children waited on, count = %d", count);
202		local_flag = FAILED;
203	}
204
205	if (local_flag == FAILED) {
206		tst_resm(TFAIL, "Test failed in fork-wait part.");
207	} else {
208		tst_resm(TPASS, "Test passed in fork-wait part.");
209	}
210
211	if (iterations > 26)
212		iterations = 26;
213	for (k=0; k < nchild; k++)
214		for (j=0; j < iterations + 1; j++) {
215			mkname(name, k, j);
216			rmdir(name);
217			unlink(name);
218		}
219
220	chdir(startdir);
221
222	pid = fork();
223	if (pid < 0) {
224		tst_resm(TINFO, "System resource may be too low, fork() malloc()"
225				    " etc are likely to fail.");
226		tst_resm(TBROK, "Test broken due to inability of fork.");
227		cleanup();
228	}
229	if (pid == 0) {
230		execl("/bin/rm", "rm", "-rf", homedir, NULL);
231		exit(1);
232	} else
233		wait(&status);
234	if (status)
235		tst_resm(TINFO,"CAUTION - ftest02, '%s' may not have been removed.",
236		  homedir);
237
238	pid = fork();
239	if (pid < 0) {
240		tst_resm(TINFO, "System resource may be too low, fork() malloc()"
241	                        " etc are likely to fail.");
242	        tst_resm(TBROK, "Test broken due to inability of fork.");
243	        cleanup();
244	}
245	if (pid == 0) {
246		execl("/bin/rm", "rm", "-rf", dirname, NULL);
247		exit(1);
248	} else
249		wait(&status);
250	if (status) {
251		tst_resm(TINFO,"CAUTION - ftest02, '%s' may not have been removed.",
252		  dirname);
253	}
254
255	sync();				/* safeness */
256
257	cleanup();
258
259	return(0);
260
261}
262
263/*--------------------------------------------------------------*/
264
265
266
267#define	warn(val,m1,m2)	if ((val) < 0) Warn(me,m1,m2)
268
269/*
270 * crfile()
271 *	Create a file and write something into it.
272 */
273
274char	crmsg[] = "Gee, let's write something in the file!\n";
275
276void crfile(me, count)
277{
278	int	fd;
279	int	val;
280	char	fname[128];
281	char	buf[128];
282
283	mkname(fname, me, count);
284
285	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
286	if (fd < 0 && errno == EISDIR) {
287		val = rmdir(fname);
288		warn(val, (char*)"rmdir", fname);
289		fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
290	}
291	warn(fd, "creating", fname);
292
293	val = lseek(fd, (rand() % M), 0);
294	warn(val, "lseek", 0);
295
296	val = write(fd, crmsg, sizeof(crmsg)-1);
297	warn(val, "write", 0);
298
299	val = lseek(fd, -(sizeof(crmsg)-1), 1);
300	warn(val, "lseek", 0);
301
302	val = read(fd, buf, sizeof(crmsg)-1);
303	warn(val, "read", 0);
304
305	if (strncmp(crmsg, buf, sizeof(crmsg)-1)) Warn(me, "compare", 0);
306
307	val = close(fd);
308	warn(val, "close", 0);
309}
310
311/*
312 * unlfile()
313 *	Unlink some of the files.
314 */
315
316void unlfile(me, count)
317{
318	int	i;
319	int	val;
320	char	fname[128];
321
322	i = count - 10;
323	if (i < 0)
324		i = 0;
325	for(; i < count; i++) {
326		mkname(fname, me, i);
327		val = rmdir(fname);
328		if (val < 0 )
329			val = unlink(fname);
330		if (val == 0 || errno == ENOENT)
331			continue;
332		Warn(me, "unlink", fname);
333	}
334}
335
336/*
337 * fussdir()
338 *	Make a directory, put stuff in it, remove it, and remove directory.
339 *
340 * Randomly leave the directory there.
341 */
342
343void fussdir(me, count)
344{
345	int	val;
346	char	dir[128];
347	char	fname[128];
348	char	savedir[128];
349
350	mkname(dir, me, count);
351	rmdir(dir); unlink(dir);		/* insure not there */
352
353	val = mkdir(dir, 0755);
354	warn(val, "mkdir", dir);
355
356	/*
357	 * Arrange to create files in the directory.
358	 */
359
360	strcpy(savedir, dirname);
361	strcpy(dirname, "");
362
363	val = chdir(dir);
364	warn(val, "chdir", dir);
365
366	crfile(me, count);
367	crfile(me, count+1);
368
369	val = chdir("..");
370	warn(val, "chdir", "..");
371
372	val = rmdir(dir);
373	if (val >= 0) {
374		tst_resm(TFAIL,"Test[%d]: rmdir of non-empty %s succeeds!", me, dir);
375		tst_exit();
376	}
377
378	val = chdir(dir);
379	warn(val, "chdir", dir);
380
381	mkname(fname, me, count);
382	val = unlink(fname);
383	warn(val, "unlink", fname);
384
385	mkname(fname, me, count+1);
386	val = unlink(fname);
387	warn(val, "unlink", fname);
388
389	val = chdir(homedir);
390	warn(val, "chdir", homedir);
391
392	if (rand() & 0x01) {
393		val = rmdir(dir);
394		warn(val, "rmdir", dir);
395	}
396
397	strcpy(dirname, savedir);
398}
399
400
401/*
402 * dotest()
403 *	Children execute this.
404 *
405 * Randomly do an inode thing; loop for # iterations.
406 */
407
408
409#define	THING(p)	{p, "p"}
410
411struct	ino_thing {
412	void	(*it_proc)();
413	char	*it_name;
414}	ino_thing[] = {
415	THING(crfile),
416	THING(unlfile),
417	THING(fussdir),
418	THING(sync),
419};
420
421#define	NTHING	(sizeof(ino_thing) / sizeof(ino_thing[0]))
422
423int	thing_cnt[NTHING];
424int	thing_last[NTHING];
425
426int dotest(me, count)
427	int	me;
428	int	count;
429{
430	int	i;
431	int	thing;
432
433	//tst_resm(TINFO,"Test %d pid %d starting.", me, getpid());
434
435	srand(getpid());
436	for(i = 0; i < count; i++) {
437		thing = (rand() >> 3) % NTHING;
438		(*ino_thing[thing].it_proc)(me, i, ino_thing[thing].it_name);
439		++thing_cnt[thing];
440	}
441
442	//tst_resm(TINFO,"Test %d pid %d exiting.", me, getpid());
443	return(0);
444}
445
446
447void Warn(me, m1, m2)
448	int	me;
449	char	*m1;
450	char	*m2;
451{
452	int	err = errno;
453
454	tst_resm(TBROK,"Test[%d]: error %d on %s %s",
455		me, err, m1, (m2 ? m2 : ""));
456	tst_exit();
457}
458
459int mkname(name, me, idx)
460	register char	*name;
461{
462	register int len;
463
464	(void) strcpy(name, dirname);
465	if (name[0]) {
466		len = dirlen+1;
467		name[len-1] = '/';
468	} else
469		len = 0;
470	name[len+0] = 'A' + (me % 26);
471	name[len+1] = 'a' + (idx % 26);
472	name[len+2] = '\0';
473	return(0);
474}
475
476/*--------------------------------------------------------------*/
477
478/* term1()
479 *
480 *	Parent - this is called when a SIGTERM signal arrives.
481 */
482
483int term()
484{
485	register int i;
486
487	//tst_resm(TINFO, "term -[%d]- got sig term.", getpid());
488
489	if (parent_pid == getpid()) {
490		for (i=0; i < nchild; i++)
491			if (pidlist[i])		/* avoid embarassment */
492				kill(pidlist[i], SIGTERM);
493		return(0);
494	}
495
496	tst_resm(TBROK, "Child process exiting.");
497	tst_exit();
498	return(0);
499}
500
501void cleanup()
502{
503	char mount_buffer[1024];
504
505	if (mnt == 1) {
506		if (chdir(startdir) < 0) {
507			tst_resm(TBROK,"Could not change to %s ", startdir);
508		}
509		if (!strcmp(fstyp, "cfs")) {
510			sprintf(mount_buffer, "/etc/umount %s", partition);
511			if (system(mount_buffer) != 0) {
512				tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint);
513				if (umount(partition)) {
514					tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint);
515				}
516				else {
517					tst_resm(TINFO, "Forced umount for %s, /etc/mnttab now dirty", partition );
518				}
519			}
520		}
521		else {
522			if (umount(partition)) {
523				tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint);
524			}
525		}
526		if (rmdir(mntpoint) != 0) {
527			tst_resm(TBROK,"Unable to rmdir %s ", mntpoint);
528		}
529	}
530	tst_rmdir();
531	tst_exit();
532}
533