ftest02.c revision 2c28215423293e443469a07ae7011135d058b671
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "usctest.h"
58#include "libftest.h"
59
60#define MAXCHILD	25
61#define K_1		1024
62#define K_2		2048
63#define K_4		4096
64
65char *TCID = "ftest02";
66int TST_TOTAL = 1;
67
68#define PASSED 1
69#define FAILED 0
70
71static void crfile(int, int);
72static void unlfile(int, int);
73static void fussdir(int, int);
74static void dotest(int, int);
75static void dowarn(int, char*, char*);
76static void term(int sig);
77static void cleanup(void);
78
79#define	M	(1024*1024)
80
81static int iterations;
82static int nchild;
83static int parent_pid;
84static int pidlist[MAXCHILD];
85
86static char homedir[MAXPATHLEN];
87static char dirname[MAXPATHLEN];
88static char tmpname[MAXPATHLEN];
89static int dirlen;
90static int mnt = 0;
91static char startdir[MAXPATHLEN], mntpoint[MAXPATHLEN];
92static char *partition;
93static char *cwd;
94static char *fstyp;
95static int local_flag;
96
97int main(void)
98{
99	int k, j, pid, child, status, count;
100	char name[128];
101
102	/*
103	 * Default values for run conditions.
104	 */
105	iterations = 50;
106	nchild = 5;
107
108	if (signal(SIGTERM, term) == SIG_ERR) {
109		tst_resm(TFAIL, "first signal failed");
110
111	}
112
113	/*
114	 * Make a directory to do this in; ignore error if already exists.
115	 */
116	local_flag = PASSED;
117	parent_pid = getpid();
118	tst_tmpdir();
119
120	if (!startdir[0]) {
121		if (getcwd(startdir, MAXPATHLEN) == NULL) {
122			tst_resm(TBROK,"getcwd failed");
123
124		}
125	}
126	cwd = startdir;
127	strcat(dirname, cwd);
128	sprintf(tmpname, "/ftest02.%d", getpid());
129	strcat(dirname, tmpname);
130	strcat(homedir, cwd);
131	sprintf(tmpname, "/ftest02h.%d", getpid());
132	strcat(homedir, tmpname);
133
134	mkdir(dirname, 0755);
135	mkdir(homedir, 0755);
136	if (chdir(dirname) < 0) {
137		tst_resm(TBROK,"\tCan't chdir(%s), error %d.", dirname, errno);
138		cleanup();
139
140	}
141	dirlen = strlen(dirname);
142	if (chdir(homedir) < 0) {
143		tst_resm(TBROK,"\tCan't chdir(%s), error %d.", homedir, errno);
144		cleanup();
145
146	}
147
148	for (k = 0; k < nchild; k++) {
149		if ((child = fork()) == 0) {
150			dotest(k, iterations);
151			exit(0);
152		}
153		if (child < 0) {
154			tst_brkm(TBROK|TERRNO, cleanup, "fork failed");
155		}
156		pidlist[k] = child;
157	}
158
159	/*
160	 * Wait for children to finish.
161	 */
162	count = 0;
163	while ((child = wait(&status)) > 0) {
164		//tst_resm(TINFO,"Test{%d} exited status = 0x%x", child, status);
165		//tst_resm(TINFO,"status is %d",status);
166		if (status) {
167			tst_resm(TFAIL,"Test{%d} failed, expected 0 exit.", 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", count);
178		local_flag = FAILED;
179	}
180
181	if (local_flag == FAILED)
182		tst_resm(TFAIL, "Test failed in fork-wait part.");
183	else
184		tst_resm(TPASS, "Test passed in fork-wait part.");
185
186	if (iterations > 26)
187		iterations = 26;
188
189	for (k = 0; k < nchild; k++)
190		for (j = 0; j < iterations + 1; j++) {
191			ft_mkname(name, dirname, k, j);
192			rmdir(name);
193			unlink(name);
194		}
195
196	chdir(startdir);
197
198	pid = fork();
199
200	if (pid < 0) {
201		tst_brkm(TBROK|TERRNO, cleanup, "fork failed");
202	}
203
204	if (pid == 0) {
205		execl("/bin/rm", "rm", "-rf", homedir, NULL);
206		exit(1);
207	} else
208		wait(&status);
209
210	if (status)
211		tst_resm(TINFO,"CAUTION - ftest02, '%s' may not have been removed.",
212		  homedir);
213
214	pid = fork();
215
216	if (pid < 0) {
217		tst_brkm(TBROK|TERRNO, cleanup, "fork failed");
218	}
219
220	if (pid == 0) {
221		execl("/bin/rm", "rm", "-rf", dirname, NULL);
222		exit(1);
223	} else
224		wait(&status);
225
226	if (status) {
227		tst_resm(TINFO,"CAUTION - ftest02, '%s' may not have been removed.",
228		  dirname);
229	}
230
231	sync();
232
233	cleanup();
234
235}
236
237#define	warn(val,m1,m2)	if ((val) < 0) dowarn(me,m1,m2)
238
239/*
240 * crfile()
241 *	Create a file and write something into it.
242 */
243
244char	crmsg[] = "Gee, let's write something in the file!\n";
245
246static void crfile(int me, int count)
247{
248	int fd, val;
249	char fname[MAXPATHLEN], buf[MAXPATHLEN];
250
251	ft_mkname(fname, dirname, me, count);
252
253	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
254	if (fd < 0 && errno == EISDIR) {
255		val = rmdir(fname);
256		warn(val, "rmdir", fname);
257		fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
258	}
259	warn(fd, "creating", fname);
260
261	val = lseek(fd, (rand() % M), 0);
262	warn(val, "lseek", 0);
263
264	val = write(fd, crmsg, sizeof(crmsg)-1);
265	warn(val, "write", 0);
266
267	val = lseek(fd, -(sizeof(crmsg)-1), 1);
268	warn(val, "lseek", 0);
269
270	val = read(fd, buf, sizeof(crmsg)-1);
271	warn(val, "read", 0);
272
273	if (strncmp(crmsg, buf, sizeof(crmsg)-1))
274		dowarn(me, "compare", 0);
275
276	val = close(fd);
277	warn(val, "close", 0);
278}
279
280/*
281 * unlfile()
282 *	Unlink some of the files.
283 */
284static void unlfile(int me, int count)
285{
286	int	i;
287	int	val;
288	char	fname[MAXPATHLEN];
289
290	i = count - 10;
291
292	if (i < 0)
293		i = 0;
294
295	for (; i < count; i++) {
296		ft_mkname(fname, dirname, me, i);
297		val = rmdir(fname);
298		if (val < 0)
299			val = unlink(fname);
300		if (val == 0 || errno == ENOENT)
301			continue;
302		dowarn(me, "unlink", fname);
303	}
304}
305
306/*
307 * fussdir()
308 *	Make a directory, put stuff in it, remove it, and remove directory.
309 *
310 * Randomly leave the directory there.
311 */
312static void fussdir(int me, int count)
313{
314	int val;
315	char dir[MAXPATHLEN], fname[MAXPATHLEN], savedir[MAXPATHLEN];
316
317	ft_mkname(dir, dirname, me, count);
318	rmdir(dir);
319	unlink(dir);
320
321	val = mkdir(dir, 0755);
322	warn(val, "mkdir", dir);
323
324	/*
325	 * Arrange to create files in the directory.
326	 */
327	strcpy(savedir, dirname);
328	strcpy(dirname, "");
329
330	val = chdir(dir);
331	warn(val, "chdir", dir);
332
333	crfile(me, count);
334	crfile(me, count+1);
335
336	val = chdir("..");
337	warn(val, "chdir", "..");
338
339	val = rmdir(dir);
340
341	if (val >= 0) {
342		tst_resm(TFAIL,"Test[%d]: rmdir of non-empty %s succeeds!", me, dir);
343		tst_exit();
344	}
345
346	val = chdir(dir);
347	warn(val, "chdir", dir);
348
349	ft_mkname(fname, dirname, me, count);
350	val = unlink(fname);
351	warn(val, "unlink", fname);
352
353	ft_mkname(fname, dirname, me, count+1);
354	val = unlink(fname);
355	warn(val, "unlink", fname);
356
357	val = chdir(homedir);
358	warn(val, "chdir", homedir);
359
360	if (rand() & 0x01) {
361		val = rmdir(dir);
362		warn(val, "rmdir", dir);
363	}
364
365	strcpy(dirname, savedir);
366}
367
368/*
369 * dotest()
370 *	Children execute this.
371 *
372 * Randomly do an inode thing; loop for # iterations.
373 */
374#define	THING(p)	{p, "p"}
375
376struct	ino_thing {
377	void	(*it_proc)();
378	char	*it_name;
379}	ino_thing[] = {
380	THING(crfile),
381	THING(unlfile),
382	THING(fussdir),
383	THING(sync),
384};
385
386#define	NTHING	(sizeof(ino_thing) / sizeof(ino_thing[0]))
387
388int	thing_cnt[NTHING];
389int	thing_last[NTHING];
390
391static void dotest(int me, int count)
392{
393	int i, thing;
394
395	//tst_resm(TINFO,"Test %d pid %d starting.", me, getpid());
396
397	srand(getpid());
398
399	for (i = 0; i < count; i++) {
400		thing = (rand() >> 3) % NTHING;
401		(*ino_thing[thing].it_proc)(me, i, ino_thing[thing].it_name);
402		++thing_cnt[thing];
403	}
404
405	//tst_resm(TINFO,"Test %d pid %d exiting.", me, getpid());
406}
407
408static void dowarn(int me, char *m1, char *m2)
409{
410	int err = errno;
411
412	tst_resm(TBROK,"Test[%d]: error %d on %s %s",
413		me, err, m1, (m2 ? m2 : ""));
414	tst_exit();
415}
416
417/*
418 * SIGTERM signal handler.
419 */
420static 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_resm(TBROK, "Child process exiting.");
432	tst_exit();
433}
434
435static void cleanup(void)
436{
437	char mount_buffer[1024];
438
439	if (mnt == 1) {
440
441		if (chdir(startdir) < 0)
442			tst_resm(TBROK,"Could not change to %s ", startdir);
443
444		if (!strcmp(fstyp, "cfs")) {
445
446			sprintf(mount_buffer, "/bin/umount %s", partition);
447
448			if (system(mount_buffer) != 0) {
449
450				tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint);
451
452				if (umount(partition))
453					tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint);
454				else
455					tst_resm(TINFO, "Forced umount for %s, /etc/mtab now dirty", partition);
456			}
457
458		} else
459			if (umount(partition))
460				tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint);
461
462		if (rmdir(mntpoint) != 0)
463			tst_resm(TBROK,"Unable to rmdir %s ", mntpoint);
464
465	}
466
467	tst_rmdir();
468}