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