• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /******************************************************************************/
usage(char * progname)227 static 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 /******************************************************************************/
init_compile(int what_todo,char * base_dir,char * hname)256 static 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 /******************************************************************************/
rm_file_dir(int numsdir,int numfiles,char * hname,char * base_dir)343 static 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 /******************************************************************************/
crte_mk_rm(void * args)477 static 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 /******************************************************************************/
main(int argc,char ** argv)717 int 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