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