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