1/******************************************************************************/ 2/* */ 3/* Copyright (c) International Business Machines Corp., 2001 */ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18/* */ 19/******************************************************************************/ 20 21/******************************************************************************/ 22/* */ 23/* History: Oct - 10 - 2001 Created - Manoj Iyer, IBM Austin TX. */ 24/* email:manjo@austin.ibm.com */ 25/* - create a directory tree that is */ 26/* unique to each process. The base directory */ 27/* looks like hostname.<pid of the process> */ 28/* the subdirectories will be <pid>.0 <pid.1> etc*/ 29/* eg: */ 30/* hostname.1234 */ 31/* |_ 1234.0 */ 32/* |_ 1234.1 */ 33/* |_1234.2 */ 34/* |.... */ 35/* hostname - hostname of the machine */ 36/* 1234 - pid of the current process. */ 37/* Each of these directories are populated with */ 38/* N number of ".c" files and a makefile that can*/ 39/* compile the ".c" files and also initiate */ 40/* compile of ".c" files in the subdirectories */ 41/* under it. */ 42/* */ 43/* Oct - 11 - 2001 Modified */ 44/* - fixed a bug in the makefiles, the last make-*/ 45/* file was expecting subdirectories. Added */ 46/* code to generate a different makefile for */ 47/* the last subdirectory. */ 48/* - Added logic to first compile all the c files*/ 49/* and upon completion remove them. */ 50/* - Added multithreading, arguments handling. */ 51/* By default the program will generate 8 */ 52/* threads, each creating by default 100 deep */ 53/* directory tree each containing default 100 */ 54/* ".c" files and one makefile. */ 55/* - Added usage message. */ 56/* */ 57/* Oct - 12 - 2001 Modified */ 58/* - Added logic to print missing arguments to */ 59/* options. */ 60/* */ 61/* Oct - 15 - 2001 Modified */ 62/* - Added logic to remove the files, makefiles */ 63/* and subdirectories that were created. */ 64/* - Added logic to print debug messages. */ 65/* */ 66/* Oct - 16 - 2001 Modified */ 67/* - Added sync() calls to commit changes. */ 68/* - Fixed bug. pthread_join() returns 0 when */ 69/* pthread_join fails, if the thread function */ 70/* fails pthread_join() will put the exit value*/ 71/* of the thread function in the thread_return */ 72/* output argument. */ 73/* - Debugging function crte_mk_rm fails to */ 74/* create fies, problem appears only in multi- */ 75/* threaded case. */ 76/* */ 77/* Oct - 17 - 2001 Checked in */ 78/* - GPL statement was added and the initial ver */ 79/* - checked into CVS. */ 80/* - note: this version works only if it is run */ 81/* single threaded, when its run multithreaded */ 82/* random thread will fail on open() sys call */ 83/* problem currently under investigation. */ 84/* */ 85/* Oct - 20 - 2001 Modified */ 86/* - fixed a whole bunch of problems. */ 87/* - created function init_compile. Apparently */ 88/* this code works!!. */ 89/* - removed system() system call that was doing */ 90/* make and make clean. init_compile() replaces*/ 91/* this piece of code. */ 92/* - on supplying the full pathname to unlink() */ 93/* solved most of the problems with rm_file_mk */ 94/* function. */ 95/* - reset the default vaulues for MAXT = 8 */ 96/* MAXD = 100 and MAXF = 100. */ 97/* ie. maximum number of threads = 8 */ 98/* directory depth (num of sub dirs) = 100 */ 99/* numeber of .c fils in each sub dir = 100*/ 100/* - finally program is now in working state. */ 101/* */ 102/* Nov - 01 - 2001 Modified. */ 103/* - fixed usage message default MAXT is 8 not 1 */ 104/* - fixed make to compile the files silently */ 105/* */ 106/* Nov - 19 - 2001 Modified. */ 107/* - changed th_status in function main() from */ 108/* dynamic variable to static array. */ 109/* */ 110/* File: make_tree.c */ 111/* */ 112/* Description: This program is designed stress the NFS implimentation. */ 113/* Many bugs were uncovered in the AIX operating system */ 114/* implimentation of NFS when AIX kernel was built over NFS. */ 115/* Source directory on a remote machine (one server many clients)*/ 116/* NFS-mounted on to a directory on a local machine from which */ 117/* the kernel build was initiated. Apparently many defects/bugs */ 118/* were uncovered when multiple users tried to build the kernel */ 119/* by NFS mounting the kernel source from a remote machine and */ 120/* tried to build the kernel on a local machine. AIX build envi- */ 121/* ronment is set up to create the object files and executable */ 122/* on the local machine. */ 123/* This testcase will try to recreate such a senario. */ 124/* Spawn N number of threads. Each thread does the following. */ 125/* * Create a directory tree. */ 126/* * Populate it with ".c" files and makefiles. */ 127/* * initate a build. Executable will print hello world when exed*/ 128/* * clean up all the executables that were created. */ 129/* * recurssively remove each subdir and its contents. */ 130/* The test is aimed at stressing the NFS client and server. */ 131/* hostname.1234 */ 132/* | */ 133/* | - 1234.0.0.c */ 134/* | - 1234.0.1.c */ 135/* | - .......... */ 136/* | - makefile */ 137/* | */ 138/* |_ 1234.0 */ 139/* | */ 140/* | - 1234.1.0.c */ 141/* | - 1234.1.1.c */ 142/* | - .......... */ 143/* | - makefile */ 144/* | */ 145/* |_ 1234.1 */ 146/* | */ 147/* | - 1234.2.0.c */ 148/* | - 1234.2.1.c */ 149/* | - .......... */ 150/* | - makefile */ 151/* | */ 152/* |_1234.2 */ 153/* |.... */ 154/* */ 155/* Setup: - on the server side: */ 156/* * create a directory /nfs_test */ 157/* * make an entry in /etc/exports file like this... */ 158/* "/nfs_test *(rw,no_root_squash)" */ 159/* * run command "exportfs -a" */ 160/* - on client side: */ 161/* * create a directory say for eg: /nfs_cli */ 162/* * mount -t nfs servername:/nfs_test /nfs_cli */ 163/* * set up the tescase in /nfs_cli directory */ 164/* - I reccomend that you have atleast 8 client machines running */ 165/* this test, linux has 8 NFSD's running by default, you might*/ 166/* have to increase it as per your requirement. */ 167/* */ 168/* Note: - assumed that NFS services are installed and configured */ 169/* - you have atleast 2 machines to act as client and server */ 170/* (you can have muiltiple client machines and one server) */ 171/* - large amount of disk space, this depends on the number of */ 172/* of clients you will have, if you have only one client, I */ 173/* reccomend that the server have atleast 4 Giga bytes of */ 174/* disk space (paranoid!). */ 175/* */ 176/******************************************************************************/ 177 178#include <stdio.h> 179#include <sys/stat.h> 180#include <sys/wait.h> 181#include <unistd.h> 182#include <stdlib.h> 183#include <fcntl.h> 184#include <unistd.h> 185#include <pthread.h> 186#include <sys/mount.h> 187#include <linux/limits.h> 188#include <errno.h> 189#include <linux/unistd.h> 190 191#define gettid() syscall(__NR_gettid) 192 193#ifdef DEBUG 194#define dprt(fmt, args...) printf(fmt, ## args) 195#else 196#define dprt(fmt, args...) 197#endif 198 199#define MAKE_EXE 1 /* initate a make */ 200#define MAKE_CLEAN 0 /* initate a make clean */ 201 202#define PTHREAD_EXIT(val) do {\ 203 exit_val = val; \ 204 dprt("pid[%d]: exiting with %d\n", gettid(),exit_val); \ 205 pthread_exit((void *)exit_val); \ 206 } while (0) 207 208#define OPT_MISSING(prog, opt) do{\ 209 fprintf(stderr, "%s: option -%c ", prog, opt); \ 210 fprintf(stderr, "requires an argument\n"); \ 211 usage(prog); \ 212 } while (0) 213 214#define MAXD 100 /* default number of directories to create. */ 215#define MAXF 100 /* default number of files to create. */ 216#define MAXT 8 /* default number of threads to create. */ 217 218/******************************************************************************/ 219/* */ 220/* Function: usage */ 221/* */ 222/* Description: Print the usage message. */ 223/* */ 224/* Return: exits with -1 */ 225/* */ 226/******************************************************************************/ 227static void usage(char *progname) 228{ /* name of this program */ 229 fprintf(stderr, 230 "Usage: %s -d NUMDIR -f NUMFILES -h -t NUMTHRD\n" 231 "\t -d Number of subdirectories to generate: Default: 100\n" 232 "\t -f Number of c files in each subdirectory: Default: 100\n" 233 "\t -h Help!\n" 234 "\t -t Number of threads to generate: Default: 8\n", 235 progname); 236 exit(-1); 237} 238 239/******************************************************************************/ 240/* */ 241/* Function: init_compile */ 242/* */ 243/* Description: This function compiles the .c files and removes the exeutables*/ 244/* This function does the same function as the system() system */ 245/* call, the code is available in the system() man page. When */ 246/* called with the parameter MAKE_EXE it will initiate make in */ 247/* the first directory created, the makefile is designed to build*/ 248/* recursively all the files in the subdirectories below. */ 249/* When called with the MAKE_CLEAN parameter it will remove the */ 250/* executables that were created design is similar to the case */ 251/* were it initiates a make. */ 252/* */ 253/* Return: exits with 1 on error, 0 on success */ 254/* */ 255/******************************************************************************/ 256static int init_compile(int what_todo, /* do a compile or clean */ 257 char *base_dir, /* base directory of the test */ 258 char *hname) 259{ /* hostname of the machine */ 260 int status; /* return status of execve process */ 261 pid_t pid; /* pid of the process that does compile */ 262 char *dirname; /* location where compile is initated */ 263 char *command; /* make or make clean command. */ 264 265 if ((dirname = malloc(sizeof(char) * 2048)) == NULL) { /* just paranoid */ 266 perror("init_compile(): dirname malloc()"); 267 return 1; 268 } 269 270 if ((command = malloc(sizeof(char) * 1024)) == NULL) { /* just paranoid */ 271 perror("init_compile(): dirname malloc()"); 272 return 1; 273 } 274 275 what_todo ? sprintf(command, "make -s") : sprintf(command, 276 "make -s clean"); 277 278 sprintf(dirname, "%s/%s.%ld", base_dir, hname, gettid()); 279 280 if (chdir(dirname) == -1) { 281 dprt("pid[%d]: init_compile(): dir name = %s\n", gettid(), 282 dirname); 283 perror("init_compile() chdir()"); 284 free(dirname); 285 return 1; 286 } 287 288 dprt("pid[%d]: init_compile(): command = %s\n", gettid(), command); 289 290 if ((pid = fork()) == -1) { 291 perror("init_compile(): fork()"); 292 return 1; 293 } 294 if (!pid) { 295 char *argv[4]; 296 297 argv[0] = "/bin/sh"; 298 argv[1] = "-c"; 299 argv[2] = command; 300 argv[3] = 0; 301 302 if (execv("/bin/sh", argv) == -1) { 303 perror("init_compile(): execv()"); 304 return 1; 305 } 306 } 307 do { 308 if (waitpid(pid, &status, 0) == -1) { 309 if (errno != EINTR) { 310 fprintf(stderr, 311 "init_compile(): waitpid() failed\n"); 312 return 1; 313 } 314 } else { 315 if (chdir(base_dir) == -1) { 316 dprt("pid[%d]: init_compile(): dir = %s\n", 317 gettid(), dirname); 318 perror("init_compile(): chdir()"); 319 return 1; 320 } 321 322 dprt("pid[%d]: init_compile(): status = %d\n", 323 gettid(), status); 324 dprt("we are here %d\n", __LINE__); 325 return status; 326 } 327 328 } while (1); 329} 330 331/******************************************************************************/ 332/* */ 333/* Function: rm_file_dir */ 334/* */ 335/* Description: This function removes the .c files makefiles and directories. */ 336/* First removes the files in the files in the last directory */ 337/* first then removes the last directory, then cycles through */ 338/* each subdirectory and does the same. */ 339/* */ 340/* Return: exits with 1 on error, 0 on success */ 341/* */ 342/******************************************************************************/ 343static int rm_file_dir(int numsdir, /* how many subdirs to remove */ 344 int numfiles, /* number of files to remove per dir */ 345 char *hname, /* hostname of the client machine */ 346 char *base_dir) 347{ /* directory where the test is located */ 348 int filecnt; /* index to the num of files to remove */ 349 int dircnt; /* index into directory tree */ 350 int sindex = numsdir; /* num subdirectory tree to remove */ 351 char *dirname; /* name of the directory to chdir() */ 352 char *tmpdirname; /* temp name for directory, for swap */ 353 char *filename; /* name of the cfile to remove */ 354 char *subdir; /* name of the sub dir to remove */ 355 356 if ((dirname = malloc(sizeof(char) * 2048)) == NULL) { /* just paranoid */ 357 perror("crte_mk_rm(): dirname malloc()"); 358 return 1; 359 } 360 361 if ((tmpdirname = malloc(sizeof(char) * 2048)) == NULL) { /* just paranoid */ 362 perror("crte_mk_rm(): tmpdirname malloc()"); 363 return 1; 364 } 365 366 if ((filename = malloc(sizeof(char) * 2048)) == NULL) { /* just paranoid */ 367 perror("crte_mk_rm(): filename malloc()"); 368 return 1; 369 } 370 371 if ((subdir = malloc(sizeof(char) * 2048)) == NULL) { /* just paranoid */ 372 perror("crte_mk_rm(): subdir malloc()"); 373 return 1; 374 } 375 376 dprt("pid[%d]: base directory: %s\n", gettid(), base_dir); 377 while (sindex) { 378 /* get the name of the last directory created. */ 379 for (dircnt = 0; dircnt < sindex; dircnt++) { 380 if (dircnt == 0) 381 sprintf(dirname, "%s/%s.%ld", base_dir, hname, 382 gettid()); 383 else { 384 sprintf(tmpdirname, "%s/%ld.%d", dirname, 385 gettid(), dircnt); 386 sprintf(dirname, "%s", tmpdirname); 387 } 388 sync(); 389 } 390 391 dprt("pid[%d]: cd'ing to last created dir: %s\n", gettid(), 392 dirname); 393 394 sindex--; 395 396 /* remove all the ".c" files and makefile in this directory */ 397 for (filecnt = 0; filecnt < numfiles; filecnt++) { 398 sprintf(filename, "%s/%ld.%d.%d.c", dirname, gettid(), 399 dircnt - 1, filecnt); 400 dprt("pid[%d]: removing file: %s\n", gettid(), 401 filename); 402 403 if (unlink(filename)) { 404 dprt("pid[%d]: failed removing file: %s\n", 405 gettid(), filename); 406 perror("rm_file_dir(): unlink()"); 407 free(tmpdirname); 408 free(dirname); 409 free(filename); 410 free(subdir); 411 return 1; 412 } 413 sync(); 414 } 415 416 sprintf(filename, "%s/%s", dirname, "makefile"); 417 dprt("pid[%d]: removing %s\n", gettid(), filename); 418 if (unlink(filename)) { 419 perror 420 ("rm_file_dir() cound not remove makefile unlink()"); 421 free(tmpdirname); 422 free(dirname); 423 free(filename); 424 free(subdir); 425 return 1; 426 } 427 sync(); 428 429 /* the last directory does not have any more sub directories */ 430 /* nothing to remove. */ 431 dprt("pid[%d]: in directory count(dircnt): %d\n", gettid(), 432 dircnt); 433 dprt("pid[%d]: last directory(numsdir): %d\n", gettid(), 434 numsdir); 435 if (dircnt < numsdir) { 436 /* remove the sub directory */ 437 sprintf(subdir, "%s/%ld.%d", dirname, gettid(), dircnt); 438 dprt("pid[%d]: removing subdirectory: %s\n", gettid(), 439 subdir); 440 if (rmdir(subdir) == -1) { 441 perror("rm_file_dir() rmdir()"); 442 free(tmpdirname); 443 free(dirname); 444 free(filename); 445 free(subdir); 446 return 1; 447 } 448 sync(); 449 } 450 } 451 452 free(tmpdirname); 453 free(dirname); 454 free(filename); 455 free(subdir); 456 return 0; 457} 458 459/******************************************************************************/ 460/* */ 461/* Function: crte_mk_rm */ 462/* */ 463/* Description: This function gets executed by each thread that is created. */ 464/* crte_mk_rm() created the directory tree, polpulates it with */ 465/* ".c" files and a makefile that will compile the ".c" files and*/ 466/* initiate the makefile in the subdirectory under it. Once the */ 467/* c source files are compiled it will remove them. */ 468/* */ 469/* Input: The argument pointer contains the following. */ 470/* arg[0] - number of directories to create, depth of the tree. */ 471/* arg[1] - number of ".c" files to create in each dir branch. */ 472/* */ 473/* Return: -1 on failure */ 474/* 0 on success */ 475/* */ 476/******************************************************************************/ 477static void *crte_mk_rm(void *args) 478{ 479 int dircnt; /* index to the number of subdirectories */ 480 int fd; /* file discriptor of the files genetated */ 481 int filecnt; /* index to the number of ".c" files created */ 482 int numchar[2]; /* number of characters written to buffer */ 483 char *dirname; /* name of the directory/idirectory tree */ 484 char *tmpdirname; /* name of a temporary directory, for swaping */ 485 char *cfilename; /* name of the ".c" file created */ 486 char *mkfilename; /* name of the makefile - which is "makefile" */ 487 char *hostname; /* hostname of the client machine */ 488 char *prog_buf; /* buffer containing contents of the ".c" file */ 489 char *make_buf; /* buffer the contents of the makefile */ 490 char *pwd; /* contains the current working directory */ 491 long *locargptr = /* local pointer to arguments */ 492 (long *)args; 493 volatile int exit_val = 0; /* exit value of the pthreads */ 494 495 if ((dirname = malloc(sizeof(char) * 2048)) == NULL) { /* just paranoid */ 496 perror("crte_mk_rm(): dirname malloc()"); 497 PTHREAD_EXIT(-1); 498 } 499 500 if ((tmpdirname = malloc(sizeof(char) * 2048)) == NULL) { 501 perror("crte_mk_rm(): tmpdirname malloc()"); 502 PTHREAD_EXIT(-1); 503 } 504 505 if ((cfilename = malloc(sizeof(char) * 2048)) == NULL) { 506 perror("crte_mk_rm(): cfilename malloc()"); 507 PTHREAD_EXIT(-1); 508 } 509 510 if ((mkfilename = malloc(sizeof(char) * 2048)) == NULL) { 511 perror("crte_mk_rm(): mkfilename malloc()"); 512 PTHREAD_EXIT(-1); 513 } 514 515 if ((prog_buf = malloc(sizeof(char) * 4096)) == NULL) { 516 perror("crte_mk_rm(): prog_buf malloc()"); 517 PTHREAD_EXIT(-1); 518 } 519 520 if ((pwd = malloc(PATH_MAX)) == NULL) { 521 perror("crte_mk_rm(): pwd malloc()"); 522 PTHREAD_EXIT(-1); 523 } 524 525 if ((hostname = malloc(sizeof(char) * 1024)) == NULL) { 526 perror("crte_mk_rm(): hostname malloc()"); 527 PTHREAD_EXIT(-1); 528 } 529 530 if (gethostname(hostname, 255) == -1) { 531 perror("crte_mk_rm(): gethostname()"); 532 PTHREAD_EXIT(-1); 533 } 534 if (!getcwd(pwd, PATH_MAX)) { 535 perror("crte_mk_rm(): getcwd()"); 536 PTHREAD_EXIT(-1); 537 } 538 539 numchar[0] = sprintf(prog_buf, 540 "main()\n{\n\t printf(\"hello world\");\n}\n"); 541 542 for (dircnt = 0; dircnt < (int)locargptr[0]; dircnt++) { 543 /* First create the base directory, then create the subdirectories */ 544 if (dircnt == 0) 545 sprintf(dirname, "%s.%ld", hostname, gettid()); 546 else { 547 sprintf(tmpdirname, "%s/%ld.%d", dirname, gettid(), 548 dircnt); 549 sprintf(dirname, "%s", tmpdirname); 550 } 551 sync(); 552 553 dprt("pid[%d] creating directory: %s\n", gettid(), dirname); 554 if (mkdir(dirname, 0777) == -1) { 555 perror("crte_mk_rm(): mkdir()"); 556 PTHREAD_EXIT(-1); 557 } 558 } 559 560 sync(); 561 usleep(10); 562 for (dircnt = 0; dircnt < (int)locargptr[0]; dircnt++) { 563 if (dircnt == 0) 564 sprintf(dirname, "%s/%s.%ld", pwd, hostname, gettid()); 565 else { 566 sprintf(tmpdirname, "%s/%ld.%d", dirname, gettid(), 567 dircnt); 568 sprintf(dirname, "%s", tmpdirname); 569 } 570 sync(); 571 if ((make_buf = malloc(sizeof(char) * 4096)) == NULL) { 572 perror("crte_mk_rm(): make_buf malloc()"); 573 PTHREAD_EXIT(-1); 574 } 575 sprintf(mkfilename, "%s/makefile", dirname); 576 { 577 /* HACK! I could not write "%.c" to the makefile */ 578 /* there is probably a correct way to do it */ 579 char *dotc = malloc(10); 580 dotc = ".c"; 581 sync(); 582 usleep(10); 583 if (dircnt == (locargptr[0] - 1)) { 584 numchar[1] = sprintf(make_buf, 585 "CFLAGS := -O -w -g\n" 586 "SUBDIRS = %ld.%d\n" 587 "SRCS=$(wildcard *.c)\n" 588 "TARGETS=$(patsubst %%%s,\%%,$(SRCS))\n" 589 "all:\t $(TARGETS)\n" 590 "clean:\n" 591 "\trm -f $(TARGETS)\n", 592 gettid(), dircnt + 1, 593 dotc); 594 } else { 595 numchar[1] = sprintf(make_buf, 596 "CFLAGS := -O -w -g\n" 597 "SUBDIRS = %ld.%d\n" 598 "SRCS=$(wildcard *.c)\n" 599 "TARGETS=$(patsubst %%%s,\%%,$(SRCS))\n\n\n" 600 "all:\t $(TARGETS)\n" 601 "\t@for i in $(SUBDIRS); do $(MAKE) -C $$i ; done\n\n" 602 "clean:\n" 603 "\trm -f $(TARGETS)\n" 604 "\t@for i in $(SUBDIRS); do $(MAKE) -C $$i clean ; done\n", 605 gettid(), dircnt + 1, 606 dotc); 607 } 608 } 609 610 sync(); 611 usleep(10); 612 dprt("pid[%d]: creating in dir: %s\n", gettid(), mkfilename); 613 /* create the makefile, complies .c files and initiates make in */ 614 /* subdirectories. */ 615 if ((fd = open(mkfilename, O_CREAT | O_RDWR, 616 S_IRWXU | S_IRWXG | S_IRWXO)) == -1) { 617 dprt(" pid[%d]: failed to create makefile\n", gettid()); 618 dprt("pid[%d]: failed in directory %s\n", gettid(), 619 dirname); 620 perror("crte_mk_rm() failed creating makefile: open()"); 621 PTHREAD_EXIT(-1); 622 } else { 623 sync(); 624 if (write(fd, make_buf, numchar[1]) == -1) { 625 perror("crte_mk_rm(): write()"); 626 PTHREAD_EXIT(-1); 627 } 628 629 free(make_buf); 630 631 if (close(fd) == -1) { 632 perror("crte_mk_rm(): close()"); 633 PTHREAD_EXIT(-1); 634 } 635 } 636 } 637 638 for (dircnt = 0; dircnt < (int)locargptr[0]; dircnt++) { 639 if (dircnt == 0) 640 sprintf(dirname, "%s/%s.%ld", pwd, hostname, gettid()); 641 else { 642 sprintf(tmpdirname, "%s/%ld.%d", dirname, gettid(), 643 dircnt); 644 sprintf(dirname, "%s", tmpdirname); 645 } 646 sync(); 647 /* In each directory create N ".c" files and a makefile. */ 648 for (filecnt = 0; filecnt < (int)locargptr[1]; filecnt++) { 649 sprintf(cfilename, "%s/%ld.%d.%d.c", dirname, gettid(), 650 dircnt, filecnt); 651 dprt("pid[%d]: creating file: %s\n", gettid(), 652 cfilename); 653 if ((fd = 654 open(cfilename, O_CREAT | O_RDWR, 655 S_IRWXU | S_IRWXG | S_IRWXO)) == -1) { 656 fprintf(stderr, 657 "open() failed to create file %s\n", 658 cfilename); 659 perror 660 ("crte_mk_rm(): failed creating .c files: open()"); 661 PTHREAD_EXIT(-1); 662 } else { 663 sync(); 664 /* write the code, this program prints hello world */ 665 if (write(fd, prog_buf, numchar[0]) == -1) { 666 perror("crte_mk_rm(): write()"); 667 PTHREAD_EXIT(-1); 668 } 669 670 fsync(fd); 671 672 if (close(fd) == -1) { 673 perror("crte_mk_rm(): close()"); 674 PTHREAD_EXIT(-1); 675 } 676 } 677 678 } 679 } 680 681 if (init_compile(MAKE_EXE, pwd, hostname) == 1) { 682 fprintf(stderr, "init_compile() make failed\n"); 683 PTHREAD_EXIT(-1); 684 } else { 685 if (init_compile(MAKE_CLEAN, pwd, hostname) == 1) { 686 fprintf(stderr, "init_compile() make clean failed\n"); 687 PTHREAD_EXIT(-1); 688 } 689 } 690 691 sync(); 692 /* remove all the files makefiles and subdirecotries */ 693 if (rm_file_dir((int)locargptr[0], (int)locargptr[1], hostname, pwd)) { 694 fprintf(stderr, "crte_mk_rm(): rm_file_dir() failed\n"); 695 PTHREAD_EXIT(-1); 696 } 697 /* if it made it this far exit with success */ 698 PTHREAD_EXIT(0); 699} 700 701/******************************************************************************/ 702/* */ 703/* Function: main */ 704/* */ 705/* Description: This is the entry point to the program. This function will */ 706/* parse the input arguments and set the values accordingly. If */ 707/* no arguments (or desired) are provided default values are used*/ 708/* refer the usage function for the arguments that this program */ 709/* takes. It also creates the threads which do most of the dirty */ 710/* work. If the threads exits with a value '0' the program exits */ 711/* with success '0' else it exits with failure '-1'. */ 712/* */ 713/* Return: -1 on failure */ 714/* 0 on success */ 715/* */ 716/******************************************************************************/ 717int main(int argc, /* number of input parameters */ 718 char **argv) 719{ /* pointer to the command line arguments. */ 720 int c; /* command line options */ 721 int num_thrd = MAXT; /* number of threads to create */ 722 int num_dirs = MAXD; /* number of subdirectories to create */ 723 int num_files = MAXF; /* number of files in each subdirectory */ 724 int thrd_ndx; /* index into the array of thread ids */ 725 void *th_status; /* exit status of LWP's */ 726 pthread_t thrdid[30]; /* maxinum of 30 threads allowed */ 727 long chld_args[3]; /* arguments to the thread function */ 728 extern int optopt; /* options to the program */ 729 730 while ((c = getopt(argc, argv, "d:f:ht:")) != -1) { 731 switch (c) { 732 case 'd': /* specify how deep the tree needs to grow */ 733 if ((num_dirs = atoi(optarg)) == 0) 734 OPT_MISSING(argv[0], optopt); 735 else if (num_dirs < 0) { 736 fprintf(stdout, 737 "WARNING: bad argument. Using default\n"); 738 num_dirs = MAXD; 739 } 740 break; 741 case 'f': /* how many ".c" files in each directory. */ 742 if ((num_files = atoi(optarg)) == 0) 743 OPT_MISSING(argv[0], optopt); 744 else if (num_files < 0) { 745 fprintf(stdout, 746 "WARNING: bad argument. Using default\n"); 747 num_files = MAXF; 748 } 749 break; 750 case 'h': 751 usage(argv[0]); 752 break; 753 case 't': 754 if ((num_thrd = atoi(optarg)) == 0) 755 OPT_MISSING(argv[0], optopt); 756 else if (num_thrd < 0) { 757 fprintf(stdout, 758 "WARNING: bad argument. Using default\n"); 759 num_thrd = MAXT; 760 } 761 break; 762 default: 763 usage(argv[0]); 764 break; 765 } 766 } 767 768 chld_args[0] = num_dirs; 769 chld_args[1] = num_files; 770 771 for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) { 772 if (pthread_create 773 (&thrdid[thrd_ndx], NULL, crte_mk_rm, chld_args)) { 774 perror("crte_mk_rm(): pthread_create()"); 775 exit(-1); 776 } 777 } 778 779 sync(); 780 781 for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) { 782 if (pthread_join(thrdid[thrd_ndx], &th_status) != 0) { 783 perror("crte_mk_rm(): pthread_join()"); 784 exit(-1); 785 } else { 786 dprt("WE ARE HERE %d\n", __LINE__); 787 if (th_status == (void *)-1) { 788 fprintf(stderr, 789 "thread [%ld] - process exited with errors\n", 790 thrdid[thrd_ndx]); 791 exit(-1); 792 } 793 } 794 } 795 return (0); 796} 797