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