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