ftest02.c revision f81795e0876f9dd0d95b42aec99a9a5de04d883d
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 <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, NULL); 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, NULL); 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