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