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#include <sys/mman.h>
21#include <ctype.h>
22#include <errno.h>
23#include <signal.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <time.h>
29#include <unistd.h>
30
31#ifndef _LINUX
32			/* LINUX INCLUDES */
33#include <sys/mode.h>
34#include <sys/timers.h>
35#else
36#include <sys/stat.h>
37#include <time.h>
38#include <sys/time.h>
39#include <sys/ipc.h>
40#endif
41#include <sys/msg.h>
42#include <sys/resource.h>
43#include <sys/select.h>
44#include <sys/sem.h>
45#include <sys/shm.h>
46#include <sys/types.h>
47#include <sys/wait.h>
48#include "lapi/semun.h"
49
50/* indexes into environment variable array */
51#define ADBG 0
52#define BNDX 1
53#define DNDX 2
54#define TNDX 3
55#define MAXBVAL 70
56#define MAXDVAL 11
57#define SLOTDIR "./slot/"
58
59#ifdef _LINUX
60			/* LINUX #defnes */
61#ifndef TRUE
62#define TRUE 1
63#endif
64#ifndef FALSE
65#define FALSE 0
66#endif
67#endif
68
69#if defined _LINUX && defined DEBUG
70#define prtln()	printf("At line number: %d\n", __LINE__); \
71		fflush(NULL)
72#define dprt(fmt, args...) printf(fmt, ## args)
73#else
74#define prtln()
75#define dprt(fmt, args...)
76#endif
77
78/* aliases for environment variable entries */
79#define    AUSDEBUG  (*edat[ADBG].eval.vint)	/* debug value */
80#define    BVAL  (*edat[BNDX].eval.vint)	/* # of childern per parent */
81#define    DVAL  (*edat[DNDX].eval.vint)	/* depth of process tree */
82#define    TVAL  (*edat[TNDX].eval.vint)	/* timer value */
83
84#ifdef _LINUX
85typedef long mtyp_t;
86#endif
87
88/* structure of information stored about each process in shared memory */
89typedef struct proc_info {
90#ifdef __64LDT__
91	pid_t pid;		/* process id */
92	pid_t ppid;		/* parent process id */
93#else
94	int pid;		/* process id */
95	int ppid;		/* parent process id */
96#endif
97	int msg;		/* parent process id */
98	int err;		/* error indicator */
99	int *list;		/* pointer to list of parent and sibling slot locations */
100} Pinfo;
101
102typedef struct messagebuf {
103	mtyp_t mtyp;		/* message type */
104	char mtext[80];		/* message text */
105} Msgbuf;
106
107union semun semarg;
108
109/* structure of all environment variable used by program */
110struct envstruct {
111	char *env_name;
112	union {
113		char *chptr;
114		int *vint;
115	} eval;
116} envdata[] = {
117	{
118		"AUSDBG", {
119	"0"}}, {
120		"BVAL", {
121	"3"}}, {
122		"DVAL", {
123	"2"}}, {
124		"FORCE", {
125	"0"}}, {
126		"TVAL", {
127	"1"}}, {
128		"", {
129	""}}
130};
131
132char *errfile;			/* pointer to errfile name */
133
134int msgid;			/* message queue for leaf nodes */
135int msgerr;			/* message queue for errors */
136int nodesum;			/* total number of process to be created */
137int sem_count;			/* counter semaphore */
138int sem_lock;			/* locks access to counter semaphore */
139int shmid;			/* global shared memory id varible */
140int procgrp;			/* process group id */
141
142timer_t timer;			/* timer structure */
143
144Pinfo *shmaddr;			/* Start address  of shared memory */
145
146#ifndef _LINUX
147FILE *errfp = stderr;		/* error file pointer, probably not necessary */
148FILE *debugfp = stderr;		/* debug file pointer, used if AUSDEBUG set */
149#else
150#define errfp stderr
151#define debugfp stderr
152#endif
153
154struct envstruct *edat = envdata;	/* pointer to environment data */
155
156/* external function declarations */
157extern int killpg(int procgrp, int sig);
158extern timer_t gettimerid(int Timer_type, int Notify_type);
159extern int reltimerid(timer_t timer);
160
161/* internal function declarations */
162void cleanup(int sig, int code, struct sigcontext *scp);
163void nextofkin(int sig, int code, struct sigcontext *scp);
164void doit(void);
165void debugout(char *fmt, ...);
166int getenv_val(void);
167void messenger(void);
168void nextofkin(int sig, int code, struct sigcontext *scp);
169int notify(int slot);
170void parse_args(int argc, char *argv[]);
171void print_shm(void);
172Pinfo *put_proc_info(int tval);
173void rm_msgqueue(void);
174void rm_semseg(void);
175void rm_shmseg(void);
176int semoper(int slot, int smid, int opval);
177int send_message(int id, mtyp_t type, char *text);
178void set_timer(void);
179void set_signals(void *sighandler());
180void setup_msgqueue(void);
181void setup_semaphores(void);
182void setup_shm(void);
183void severe(char *fmt, ...);
184Pinfo *shmgetseg(void);
185int spawn(int val);
186unsigned long sumit(int B, int D);
187
188/*
189 *  Prints out the data structures in shared memory.
190 */
191void print_shm(void)
192{
193	extern int nodesum;	/* total number of nodes created */
194	extern Pinfo *shmaddr;	/* shared memory pointer */
195	extern int shmid;	/* shared memory id */
196
197	Pinfo *pinfo;		/* pointer to process info in shared memory */
198	int *listp;		/* pointer to sibling info in shared memory */
199	int i, j;		/* counters */
200	struct shmid_ds buf;
201
202	if (shmctl(shmid, IPC_STAT, &buf))
203		return;
204
205	for (pinfo = shmaddr, i = 0; i < nodesum; i++, pinfo++) {
206		fprintf(errfp,
207			"slot: %-4d pid: %-6d ppid: %-6d msg: %-2d err: %-2d lst:",
208			i, pinfo->pid, pinfo->ppid, pinfo->msg, pinfo->err);
209		for (j = 0, listp = pinfo->list; j < BVAL; j++, listp++)
210			fprintf(errfp, " %d", *listp);
211		fprintf(errfp, "\n");
212	}
213}
214
215/*
216 *  Generalized send routine.  Sends a message on message queue.
217 */
218int send_message(int id, mtyp_t type, char *text)
219{
220	int rc;
221
222	Msgbuf sndbuf;
223
224	strcpy(sndbuf.mtext, text);
225	sndbuf.mtyp = type;
226	while (TRUE) {
227		rc = msgsnd(id, &sndbuf, sizeof(struct messagebuf), IPC_NOWAIT);
228		if (rc == -1 && errno == EAGAIN) {
229			debugout("msgqueue %d of mtyp %d not ready to send\n",
230				 msgid, type);
231			errno = 0;
232		} else
233			return (rc);
234	}
235}
236
237/*
238 *  Sends error message to initial parent (messenger).i
239 */
240void severe(char *fmt, ...)
241{
242	va_list args;
243	int rc;
244	char mtext[80];
245	extern int msgerr;
246
247	va_start(args, fmt);
248	vsprintf(mtext, fmt, args);
249	va_end(args);
250
251	rc = send_message(msgerr, 2, mtext);
252	if (rc == -1) {
253		perror("cannot send message to msgerr");
254		exit(1);
255	}
256}
257
258/*
259 *  if AUSDEBUG set will print information to file associated with slot number.
260 */
261void debugout(char *fmt, ...)
262{
263	va_list args;
264
265	if (AUSDEBUG) {
266		va_start(args, fmt);
267		vfprintf(debugfp, fmt, args);
268		va_end(args);
269	}
270}
271
272/*
273 *  Remove message queues.
274 */
275void rm_msgqueue(void)
276{
277	extern int msgid;
278
279	/* remove message queue id. */
280	if (msgctl(msgid, IPC_RMID, NULL) && errno != EINVAL) {
281		fprintf(errfp, "msgctl failed msgid: errno %d\n", errno);
282		perror("msgctl failed");
283	}
284
285	/* remove message queue id. */
286	if (msgctl(msgerr, IPC_RMID, NULL) && errno != EINVAL) {
287		fprintf(errfp, "msgctl failed msgerr: errno %d\n", errno);
288		perror("msgctl failed");
289	}
290}
291
292/*
293 *  Remove shared memory segment.
294 */
295void rm_shmseg(void)
296{
297	extern int shmid;	/* Global shared memory id */
298	extern Pinfo *shmaddr;	/* Global shared memory address */
299
300	/* remove shared memory id (and shared memory segment). */
301	if (shmctl(shmid, IPC_RMID, NULL) && errno != EINVAL) {
302		fprintf(errfp, "shmctl failed: errno %d\n", errno);
303		perror("shmctl failed");
304	}
305}
306
307/*
308 *  Remove semaphores.
309 */
310void rm_semseg(void)
311{
312	extern int sem_lock;
313	extern int sem_count;
314
315	/* remove sem_lock semaphore id */
316	semarg.val = 0;		/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
317	if (semctl(sem_lock, 0, IPC_RMID, semarg.val) && errno != EINVAL) {
318		fprintf(errfp, "semctl failed: errno %d\n", errno);
319		perror("semctl failed");
320	}
321	/* remove sem_count semaphore id. */
322	semarg.val = 0;		/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
323	if (semctl(sem_count, 0, IPC_RMID, semarg.val) && errno != EINVAL) {
324		fprintf(errfp, "semctl failed: errno %d\n", errno);
325		perror("semctl failed");
326	}
327}
328
329/*
330 * Routine to clean up shared memory and return exit status (CHILD handler).
331 */
332void cleanup(int sig, int code, struct sigcontext *scp)
333{
334	int rc;
335	char mtext[80];
336
337	killpg(procgrp, SIGTERM);
338	sprintf(mtext, "%d", sig);
339	rc = send_message(msgerr, 3, mtext);
340	if (rc == -1) {
341		severe("msgsnd failed: %d msgid %d mtyp %d mtext %d\n",
342		       errno, msgerr, 3, mtext);
343	}
344}
345
346/*
347 * Routine to clean up shared memory and return exit status (PARENT handler).
348 */
349void nextofkin(int sig, int code, struct sigcontext *scp)
350{
351	int rc;
352	char mtext[80];
353
354	sprintf(mtext, "%d", sig);
355	rc = send_message(msgerr, 3, mtext);
356	if (rc == -1) {
357		severe("msgsnd failed: %d msgid %d mtyp %d mtext %d\n",
358		       errno, msgerr, 3, mtext);
359	}
360#ifndef _LINUX
361	reltimerid(timer);
362#endif
363	exit(1);
364}
365
366/* given breadth and depth of a tree, sum up total number of nodes created */
367unsigned long sumit(int B, int D)
368{
369	int i;
370	int exp = 1;		/* exponent of breadth */
371	unsigned long sum = 1;	/* running sum of nodes */
372
373	for (sum = 1, i = 1; i <= D; i++) {
374		exp = B * exp;
375		sum += (int)exp;
376	}
377	return (sum);
378}
379
380/* Finds correct slot for current process in shared memory and stores
381 * information about process in it.
382 */
383Pinfo *put_proc_info(int tval)
384{
385	extern int nodesum;
386	extern Pinfo *shmaddr;
387
388	int sibslot = 0;	/* sibling slot number */
389	int *listp;		/* ptr to sibling info for current proc */
390	Pinfo *smp;		/* ptr to current process data slot */
391
392	smp = shmaddr + tval;
393	smp->pid = getpid();
394	smp->ppid = getppid();
395	smp->err = 0;
396	smp->msg = 0;
397
398	/* if very first process (slot 0), dont fill in info about siblings
399	 *  and parent.  Sibling and parent info is irrevelant in this case.
400	 */
401	if (!tval)
402		return (smp);
403
404	/* find parent of current process and store slot location */
405	smp->list = (int *)(Pinfo *) (shmaddr + nodesum) + (BVAL * tval);
406	*smp->list = (tval - 1) / BVAL;
407	listp = smp->list + 1;
408
409	/* calculate and store sibling slot numbers of current process */
410	for (sibslot = *smp->list * BVAL + 1; listp < smp->list + BVAL;
411	     sibslot++) {
412		if (tval != sibslot)
413			*(listp++) = sibslot;
414	}
415	return (smp);
416}
417
418/* This routine sends a message from the current process to all of her
419 * siblings and then waits to receive responses from them.  A timer is
420 * set so that if a message is lost or not received for some reason
421 * we can exit gracefully.
422 */
423int notify(int slot)
424{
425	extern int msgid;
426	extern Pinfo *shmaddr;
427
428	int i;
429	int rc;
430	int tslot;
431	int *listp = (shmaddr + slot)->list;
432	int cldcnt = 1;
433	int ndx = 0;
434#ifdef __64LDT__
435	pid_t pid = 0;
436#else
437	int pid = 0;
438#endif
439	char mtext[80];
440
441	Msgbuf rcvbuf;
442
443	for (i = 1, listp++; i < BVAL; i++, listp++) {
444		sprintf(mtext, "%d %d %d", i, slot, (shmaddr + slot)->pid);
445		rc = send_message(msgid, (mtyp_t) * listp, mtext);
446		if (rc == -1) {
447			severe
448			    ("notify: send_message Failed: %d msgid %d mtyp %d mtext %d\n",
449			     errno, msgid, *listp, mtext);
450			exit(1);
451		}
452	}
453
454	while (cldcnt < BVAL) {
455		rc = msgrcv(msgid, &rcvbuf, sizeof(struct messagebuf), slot, 0);
456		if (rc == -1) {
457			switch (errno) {
458			case EAGAIN:
459				printf("msgqueue %d not ready to receive\n",
460				       msgid);
461				fflush(stdout);
462				errno = 0;
463				break;
464			case ENOMSG:
465				printf("msgqueue %d no message\n", msgid);
466				fflush(stdout);
467				errno = 0;
468				break;
469			default:
470				perror("msgrcv failed");
471				severe("msgrcv failed, errno: %d\n", errno);
472				exit(1);
473			}
474		} else {
475			sscanf(rcvbuf.mtext, "%d %d %d", &ndx, &tslot, &pid);
476			if (*((shmaddr + tslot)->list + ndx) == slot &&
477			    (shmaddr + tslot)->pid == pid) {
478				debugout
479				    ("MSGRCV:slot: %d ndx: %d tslot: %d pid: %d\n",
480				     slot, ndx, tslot, pid);
481				(shmaddr + slot)->msg++;
482				cldcnt++;
483			} else {
484				(shmaddr + slot)->err--;
485				debugout
486				    ("MSGRCV: slot: %d ndx: %d tslot: %d pid: %d\n",
487				     slot, ndx, tslot, pid);
488			}
489		}
490	}
491	return 0;
492}
493
494/*
495 * Calculates semaphore number and sets semaphore (lock).
496 */
497int semoper(int slot, int smid, int opval)
498{
499	int pslot;		/* parent slot */
500	struct sembuf smop;	/* semaphore operator */
501
502	pslot = (slot - 1) / BVAL;	/* calculate parent node */
503	smop.sem_num = pslot;
504	smop.sem_op = opval;
505	smop.sem_flg = 0;
506	semop(smid, &smop, 1);
507	return (pslot);
508}
509
510/*
511 * This is the meat and potatoes of the program.  Spawn creates a tree
512 * of processes with Dval depth and Bval breadth.  Each parent will spawn
513 * Bval children.  Each child will store information about themselves
514 * in shared memory.  The leaf nodes will communicate the existence
515 * of one another through message queues, once each leaf node has
516 * received communication from all of her siblings she will reduce
517 * the semaphore count and exit.  Meanwhile all parents are waiting
518 * to hear from their children through the use of semaphores.  When
519 * the semaphore count reaches zero then the parent knows all the
520 * children have talked to one another.  Locking of the connter semaphore
521 * is provided by the use of another (binary) semaphore.
522 */
523int spawn(int val)
524{
525	extern int sem_count;	/* used to keep track of childern */
526	extern int sem_lock;	/* used to lock access to sem_count semaphore */
527
528	int i;			/* Breadth counter */
529	static int level = 0;	/* level counter */
530	int lvlflg = 0;		/* level toggle, limits parental spawning
531				   to one generation */
532	int pslot = 0;
533#ifdef __64LDT__
534	pid_t pid;		/* pid of child process */
535#else
536	int pid;		/* pid of child process */
537#endif
538	Pinfo *pinfo;		/* pointer to process information in shared mem */
539	int semval;		/* value of semaphore ( equals BVAL initially */
540	static int tval = 1;	/* tree node value of child. */
541
542	char foo[1024];
543
544	level++;
545
546	for (i = 1; i <= BVAL; i++) {
547		tval = (val * BVAL) + i;
548		if (!lvlflg) {
549			pid = fork();
550			if (!pid) {	/* CHILD */
551				if (AUSDEBUG) {
552					sprintf(foo, "%sslot%d", SLOTDIR, tval);
553					debugfp = fopen(foo, "a+");
554				}
555				pinfo = put_proc_info(tval);
556
557				debugout
558				    ("pid: %-6d ppid: %-6d lev: %-2d i: %-2d val: %-3d\n",
559				     pinfo->pid, pinfo->ppid, level, i, tval);
560
561				set_timer();	/* set up signal handlers and initialize pgrp */
562				if (level < DVAL) {
563					if (spawn(tval) == -1) {
564						pslot =
565						    semoper(tval, sem_lock, -1);
566						semarg.val = 0;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
567						semval =
568						    semctl(sem_count, pslot,
569							   GETVAL, semarg);
570						semarg.val = --semval;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
571						semctl(sem_count, pslot, SETVAL,
572						       semarg);
573						semarg.val = 1;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
574						semctl(sem_lock, pslot, SETVAL,
575						       semarg);
576					}
577					lvlflg++;
578				} else {	/* leaf node */
579					notify(tval);
580					return (-1);
581				}
582			}
583#ifdef __64LDT__
584			else if (pid > 0 && i >= BVAL) {	/* PARENT */
585#else
586			else if (pid > (pid_t) 0 && i >= BVAL) {	/* PARENT */
587#endif
588				pslot = semoper(tval, sem_count, 0);
589				pslot = semoper(pslot, sem_lock, -1);
590				semarg.val = 0;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
591				semval =
592				    semctl(sem_count, pslot, GETVAL, semarg);
593				semarg.val = --semval;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
594				semctl(sem_count, pslot, SETVAL, semarg);
595				semarg.val = 1;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
596				semctl(sem_lock, pslot, SETVAL, semarg);
597				(shmaddr + val)->msg++;
598			}
599#ifdef __64LDT__
600			else if (pid < (pid_t) 0) {
601#else
602			else if (pid < 0) {
603#endif
604				perror("spawn: fork failed");
605				severe
606				    ("spawn: fork failed, exiting with errno %d\n",
607				     errno);
608				exit(1);
609			} else
610				(shmaddr + val)->msg++;
611		}
612	}
613	return (pslot);
614}
615
616/*
617 * Allocate message queues.
618 */
619void setup_msgqueue(void)
620{
621	extern int msgid;
622	extern int msgerr;
623
624	msgid = msgget(IPC_PRIVATE,
625		       IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
626		       S_IWGRP);
627	if (msgid == -1) {
628		perror("msgget msgid failed");
629		fprintf(stderr, " SEVERE : msgget msgid failed: errno %d\n",
630			errno);
631		exit(1);
632	}
633
634	msgerr = msgget(IPC_PRIVATE,
635			IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
636			S_IWGRP);
637	if (msgerr == -1) {
638		perror("msgget msgerr failed");
639		fprintf(stderr, " SEVERE : msgget msgerr failed: errno %d\n",
640			errno);
641		exit(1);
642	}
643}
644
645/*
646 * Set up and initialize all semaphores
647 */
648void setup_semaphores(void)
649{
650	extern int sem_count;
651	extern int sem_lock;
652
653	int i;
654	int rc;
655
656	prtln();
657	sem_lock = semget(IPC_PRIVATE, nodesum - 1,
658			  IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
659			  S_IWGRP);
660	dprt("nodesum = %d, sem_lock = %d\n", nodesum, sem_lock);
661
662	prtln();
663	if (sem_lock == -1) {
664		perror("semget failed for sem_lock");
665		fprintf(stderr,
666			" SEVERE : semget failed for sem_lock, errno: %d\n",
667			errno);
668		rm_shmseg();
669		exit(1);
670	}
671
672	prtln();
673	sem_count = semget(IPC_PRIVATE, nodesum - 1,
674			   IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
675			   S_IWGRP);
676
677	if (sem_count == -1) {
678		perror("semget failed for sem_count");
679		fprintf(stderr,
680			" SEVERE : semget failed for sem_count, errno: %d\n",
681			errno);
682		rm_shmseg();
683		exit(1);
684	}
685	prtln();
686
687	for (i = 0; i < (nodesum - 1); i++) {
688		semarg.val = 1;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
689		rc = semctl(sem_lock, i, SETVAL, semarg);
690		prtln();
691		if (rc == -1) {
692			perror("semctl failed for sem_lock failed");
693			fprintf(stderr,
694				" SEVERE : semctl failed for sem_lock, errno: %d\n",
695				errno);
696			rm_shmseg();
697			exit(1);
698		}
699
700		semarg.val = BVAL;	/* to fix problem with 4th arg of semctl in 64 bits MARIOG */
701		rc = semctl(sem_count, i, SETVAL, semarg);
702		prtln();
703		if (rc == -1) {
704			perror("semctl failed for sem_lock failed");
705			fprintf(stderr,
706				" SEVERE : semctl failed for sem_lock, errno: %d\n",
707				errno);
708			rm_shmseg();
709			exit(1);
710		}
711	}
712}
713
714/*
715 * Set up and allocate shared memory.
716 */
717void setup_shm(void)
718{
719	extern int nodesum;	/* global shared memory id */
720	extern int shmid;	/* global shared memory id */
721	extern Pinfo *shmaddr;
722
723	int i, j;		/* counters */
724	Pinfo *shmad = NULL;	/* ptr to start of shared memory. */
725	Pinfo *pinfo = NULL;	/* ptr to struct in shared memory. */
726
727	debugout("size = %d, size (in hex) =  %#x  nodes: %d\n",
728		 sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)),
729		 sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)),
730		 nodesum);
731
732	/* Get shared memory id */
733	shmid = shmget(IPC_PRIVATE,
734		       sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)),
735		       IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
736		       S_IWGRP);
737	if (shmid < 0) {
738		perror("shmget failed");
739		fprintf(stderr, " SEVERE : shmget failed: errno %d\n", errno);
740		exit(1);
741	}
742
743	/* allocate shared memory */
744
745	if ((shmad = shmat(shmid, (char *)shmad, 0)) == MAP_FAILED) {
746		printf("SEVERE : shmat failed\n");
747		exit(1);
748	} else {
749		shmctl(shmid, IPC_RMID, NULL);
750	}
751
752	/* set all fields in shared memory to -1 */
753	for (pinfo = shmad, i = 0; i < nodesum; i++, pinfo++) {
754#ifdef __64LDT__
755		pinfo->pid = (pid_t) - 1;
756		pinfo->ppid = (pid_t) - 1;
757#else
758		pinfo->pid = -1;
759		pinfo->ppid = -1;
760#endif
761		pinfo->msg = -1;
762		pinfo->err = -1;
763
764		/* Changed 10/9/97 */
765		/* pinfo->list = (int *)((ulong)shmad + nodesum * sizeof(Pinfo)
766		   + (sizeof(int) * BVAL * i)); */
767		pinfo->list =
768		    (int *)((long)shmad + nodesum * sizeof(Pinfo) +
769			    (sizeof(int) * BVAL * i));
770		for (j = 0; j < BVAL; j++)
771			*(pinfo->list + j) = -1;
772	}
773	shmaddr = shmad;
774}
775
776/*
777 * Set up Signal handler and which signals to catch
778 */
779void set_signals(void *sighandler())
780{
781	int i;
782	int rc;
783
784	struct sigaction action;
785
786	/* list of signals we want to catch */
787	static struct signalinfo {
788		int signum;
789		char *signame;
790	} siginfo[] = {
791		{
792		SIGHUP, "SIGHUP"}, {
793		SIGINT, "SIGINT"}, {
794		SIGQUIT, "SIGQUIT"}, {
795		SIGABRT, "SIGABRT"}, {
796		SIGBUS, "SIGBUS"}, {
797		SIGSEGV, "SIGSEGV"}, {
798		SIGALRM, "SIGALRM"}, {
799		SIGUSR1, "SIGUSR1"}, {
800		SIGUSR2, "SIGUSR2"}, {
801		-1, "ENDSIG"}
802	};
803
804	char tmpstr[1024];
805
806	action.sa_handler = (void *)sighandler;
807
808#ifdef _LINUX
809	sigfillset(&action.sa_mask);
810#else
811	SIGINITSET(action.sa_mask);
812#endif
813	action.sa_flags = 0;
814
815	/* Set the signal handler up */
816#ifdef _LINUX
817	sigaddset(&action.sa_mask, SIGTERM);
818#else
819	SIGADDSET(action.sa_mask, SIGTERM);
820#endif
821	for (i = 0; siginfo[i].signum != -1; i++) {
822#ifdef _LINUX
823		sigaddset(&action.sa_mask, siginfo[i].signum);
824#else
825		SIGADDSET(action.sa_mask, siginfo[i].signum);
826#endif
827		rc = sigaction(siginfo[i].signum, &action, NULL);
828		if (rc == -1) {
829			sprintf(tmpstr, "sigaction: %s\n", siginfo[i].signame);
830			perror(tmpstr);
831			fprintf(stderr,
832				" SEVERE : Could not set %s signal action, errno=%d.",
833				siginfo[i].signame, errno);
834			exit(1);
835		}
836	}
837}
838
839/*
840* Get and set a timer for current process.
841*/
842#ifndef _LINUX
843void set_timer(void)
844{
845	struct itimerstruc_t itimer, old_itimer;
846
847	if ((timer = gettimerid(TIMERID_REAL, DELIVERY_SIGNALS)) == -1) {
848		perror("gettimerid");
849		fprintf(stderr, " SEVERE : Could not get timer id, errno=%d.",
850			errno);
851		exit(1);
852	}
853
854	/*
855	 * Start the timer.
856	 */
857	itimer.it_interval.tv_nsec = 0;
858	itimer.it_interval.tv_sec = 0;
859	itimer.it_value.tv_nsec = 0;
860	itimer.it_value.tv_sec = (time_t) (TVAL * 60.0);
861	if (incinterval(timer, &itimer, &old_itimer) == -1) {
862		perror("incinterval");
863		fprintf(stderr,
864			" SEVERE : Could not set timer interval, errno=%d.",
865			errno);
866		(void)reltimerid(timer);
867		exit(1);
868	}
869}
870#else
871
872void set_timer(void)
873{
874	struct itimerval itimer;
875
876	memset(&itimer, 0, sizeof(struct itimerval));
877	/*
878	 * Start the timer.
879	 */
880	itimer.it_interval.tv_usec = 0;
881	itimer.it_interval.tv_sec = 0;
882	itimer.it_value.tv_usec = 0;
883	itimer.it_value.tv_sec = (time_t) (TVAL * 60.0);
884
885	if (setitimer(ITIMER_REAL, &itimer, NULL)) {
886		perror("setitimer");
887		exit(1);
888	}
889}
890#endif
891
892/*
893 * parse_args
894 *
895 * Parse command line arguments.  Any errors cause the program to exit
896 * at this point.
897 */
898void parse_args(int argc, char *argv[])
899{
900	int i;
901	int opt, errflag = 0;
902	int dflag = 0, bflag = 0, fflag = 0, tflag = 0;
903	extern int optind;
904	extern char *optarg;
905
906	/* DVAL:        0  1     2      3   4  5  6  7  8  9  10 11 */
907	int limits[] = { -1, -1, MAXBVAL, 17, 8, 5, 4, 3, 2, 2, 2, 2 };
908
909	while ((opt = getopt(argc, argv, "b:d:ft:D?")) != EOF) {
910		switch (opt) {
911		case 'b':
912			if (bflag)
913				errflag++;
914			else {
915				bflag++;
916				errno = 0;
917				BVAL = atoi(optarg);
918				if (errno) {
919					perror("atoi");
920					fprintf(stderr,
921						" ERROR : atoi - errno %d.",
922						errno);
923					errflag++;
924				}
925			}
926			break;
927		case 'd':
928			if (dflag)
929				errflag++;
930			else {
931				dflag++;
932				errno = 0;
933				DVAL = atoi(optarg);
934				if (errno) {
935					perror("atoi");
936					fprintf(stderr,
937						" ERROR : atoi - errno %d.",
938						errno);
939					errflag++;
940				}
941			}
942			break;
943		case 'f':
944			fflag = 1;
945			break;
946		case 'D':
947			AUSDEBUG = 1;
948			break;
949		case 't':
950			if (tflag)
951				errflag++;
952			else {
953				tflag++;
954				errno = 0;
955				TVAL = atoi(optarg);
956				if (!TVAL || errno) {
957					perror("atoi");
958					fprintf(stderr,
959						" ERROR : atoi - errno %d.",
960						errno);
961					errflag++;
962				}
963			}
964			break;
965		case '?':
966			errflag++;
967			break;
968		}
969	}
970
971	if (BVAL < 2) {
972		errflag++;
973		fprintf(stderr, "The value of b must be greater than 1\n");
974	} else if (DVAL < 2) {
975		errflag++;
976		fprintf(stderr, "The depth value must be greater than 1\n");
977	} else if (!fflag && (DVAL > MAXDVAL)) {
978/* || BVAL > limits[DVAL])) { */
979		fprintf(stderr, "\tExceeded process creation limits.   \
980\n\tParameters will generate %lu processes.  \n\tThe preset limits are as \
981follows:\n\t\tdepth\tbreadth\ttotal\n", sumit(BVAL, DVAL));
982		for (i = 2; i <= MAXDVAL; i++)
983			fprintf(stderr, "\t\t %-3d\t  %-5d\t%-5lu\n", i,
984				limits[i], sumit(limits[i], i));
985		exit(1);
986	}
987
988	if (errflag) {
989		fprintf(stderr,
990			"usage: %s [-b number] [-d number] [-t number] \n",
991			argv[0]);
992		fprintf(stderr, "where:\n");
993		fprintf(stderr,
994			"\t-b number\tnumber of children each parent will spawn ( > 1)\n");
995		fprintf(stderr, "\t-d number\tdepth of process tree ( > 1)\n");
996		fprintf(stderr, "\t-t\t\tset timeout value\n");
997		fprintf(stderr, " SEVERE : Command line parameter error.\n");
998		exit(1);
999	}
1000}
1001
1002/*
1003 * Initializes environment variables, using defaults if not set in env.
1004 */
1005int getenv_val(void)
1006{
1007	char *c;		/* character pointer */
1008	struct envstruct *envd = envdata;	/* pointer to environment data */
1009
1010	union {
1011		int *vint;
1012		char *chptr;
1013	} val;
1014
1015	/*
1016	 * Loop through envdata, set default first then set environment
1017	 * variable value if present.
1018	 */
1019	for (; *envd->env_name != '\0'; envd++) {
1020		if ((val.chptr = getenv(envd->env_name)) == NULL)
1021			val.chptr = envd->eval.chptr;
1022
1023		c = val.chptr;
1024		while (isdigit(*c))
1025			c++;
1026
1027		if (*c == '\0') {
1028			(envd->eval.vint) = malloc(sizeof(int));
1029			*(envd->eval.vint) = atoi(val.chptr);
1030		} else {
1031			envd->eval.chptr = malloc(strlen(val.chptr) + 1);
1032			strcpy(envd->eval.chptr, val.chptr);
1033		}
1034	}
1035	return 0;
1036}
1037
1038/*
1039 * Prints all errors coming from the children and terminates execution if
1040 * an error execption is received.  In addition messenger() is sent the
1041 * process group id of the children so it can terminate all children.
1042 * This routine uses message queues to receive all communications.
1043 */
1044void messenger(void)
1045{				/* AKA Assassin */
1046	Msgbuf rcvbuf;
1047
1048	int discrim = 0;
1049	int rc;			/* generic return code var */
1050	int sig = -1;		/* type of signal received */
1051	extern int msgerr;	/* message queue used to send error messages */
1052	extern int procgrp;	/* process group of children (used to kill them) */
1053
1054	/*
1055	 *  Infinite loop used to receive error messages from children and
1056	 *  to terminate process tree.
1057	 */
1058	while (TRUE) {
1059		rc = msgrcv(msgerr, &rcvbuf, sizeof(struct messagebuf), 0, 0);
1060		if (rc == -1) {
1061			switch (errno) {
1062			case EAGAIN:
1063				printf("msgqueue %d not ready to receive\n",
1064				       msgid);
1065				fflush(stdout);
1066				errno = 0;
1067				break;
1068			case ENOMSG:
1069				printf("msgqueue %d no message\n", msgid);
1070				fflush(stdout);
1071				errno = 0;
1072				break;
1073			default:
1074				perror("msgrcv failed");
1075				fprintf(stderr,
1076					" SEVERE : messenger - msgrcv failed, errno: %d\n",
1077					errno);
1078				errno = 0;
1079				break;
1080			}
1081		} else {
1082			switch ((int)rcvbuf.mtyp) {
1083			case 1:	/* type 1: we received the process group id */
1084				sscanf(rcvbuf.mtext, "%d", &procgrp);
1085				break;
1086
1087			case 2:	/*  type 2: we received an error */
1088				fprintf(stderr, " SEVERE : %s ", rcvbuf.mtext);
1089				/* rcvbuf.mtext type %s ou %d ??? */
1090				break;
1091
1092			case 3:	/* type 3: somebody got a signal, now we terminate */
1093				sscanf(rcvbuf.mtext, "%d", &sig);
1094
1095				switch (sig) {
1096				case SIGALRM:
1097					/* a process is hung, we will terminate */
1098					killpg(procgrp, sig);
1099					fprintf(errfp,
1100						"ALERT! ALERT! WE HAVE TIMED OUT\n");
1101					fprintf(stderr,
1102						" SEVERE : SIGALRM: A process timed out, we failed\n");
1103					shmaddr->err++;
1104					break;
1105
1106				case SIGUSR1:
1107					/* Special: means everything went ok */
1108					discrim = 1;
1109					break;
1110
1111				default:
1112					/* somebody sent a signal, we will terminate */
1113					killpg(procgrp, sig);
1114					fprintf(errfp,
1115						"We received signal %d\n", sig);
1116					fprintf(stderr,
1117						" SEVERE : signal %d received, A proc was killed\n",
1118						sig);
1119					break;
1120				}
1121				/* clean up and exit with status */
1122				rm_msgqueue();
1123				rm_semseg();
1124				if (AUSDEBUG)
1125					print_shm();
1126				prtln();
1127				rm_shmseg();
1128				prtln();
1129				if (discrim) {
1130					prtln();
1131					printf("Test exiting with SUCCESS\n");
1132					exit(0);
1133				}
1134				exit(1);
1135
1136				break;
1137			}
1138		}
1139	}
1140}
1141
1142/*
1143 *  This routine spawns off the first child (node 0) of the process tree.
1144 *  This child set up the signal handler for all of the children and also
1145 *  sets up a process group so that all children can be terminated easily.
1146 *  The child then calls spawn which creates the process tree.  After spawn
1147 *  has returned the child contacts the parent and the parent exits.
1148 *  The parent sets her own signal handler and then calls messenger.
1149 */
1150void doit(void)
1151{
1152	pid_t pid;		/* process id */
1153	int rc;
1154	char mtext[80];		/* message text */
1155	extern int msgerr;
1156	extern int procgrp;
1157
1158	pid = fork();
1159#ifdef __64LDT__
1160	if (pid == (pid_t) 0) {
1161#else
1162	if (pid == 0) {
1163#endif
1164		/* set the process group so we can terminate all children */
1165		set_signals((void *)nextofkin);	/* set up signal handlers and initialize pgrp */
1166#ifndef _LINUX
1167		procgrp = setpgrp(0, 0);
1168#else
1169		procgrp = setpgrp();
1170#endif
1171		if (AUSDEBUG) {
1172			fprintf(stderr, "process group: %d\n", procgrp);
1173			fflush(stderr);
1174		}
1175		if (procgrp == -1) {
1176			perror("setpgid failed");
1177			fprintf(stderr, " SEVERE : setpgid failed, errno: %d\n",
1178				errno);
1179			exit(1);
1180		}
1181		sprintf(mtext, "%d", procgrp);
1182		rc = send_message(msgerr, 1, mtext);
1183		if (rc == -1) {
1184			perror("send_message failed");
1185			fprintf(stderr,
1186				" SEVERE : send_message failed, errno: %d\n",
1187				errno);
1188			exit(1);
1189		}
1190
1191		put_proc_info(0);	/* store process info for this (root) process */
1192		spawn(0);
1193		if (shmaddr->pid == getpid()) {
1194			sprintf(mtext, "%d", SIGUSR1);
1195			rc = send_message(msgerr, 3, mtext);
1196			if (rc == -1) {
1197				severe
1198				    ("msgsnd failed: %d msgid %d mtyp %d mtext %d\n",
1199				     errno, msgerr, 3, mtext);
1200				exit(1);
1201
1202			}
1203		}
1204		exit(0);
1205	}
1206#ifdef __64LDT__
1207	else if (pid > (pid_t) 0) {
1208#else
1209	else if (pid > 0) {
1210#endif
1211		set_signals((void *)cleanup);	/* set up signal handlers and initialize pgrp */
1212		messenger();	/* receives and acts upon messages */
1213		exit(1);
1214	} else {
1215		perror("fork failed");
1216		fprintf(stderr,
1217			" SEVERE : fork failed, exiting with errno %d\n",
1218			errno);
1219		exit(1);
1220	}
1221}
1222
1223/* main */
1224int main(int argc, char *argv[])
1225{
1226	extern Pinfo *shmaddr;	/* start address of shared memory */
1227
1228	prtln();
1229	getenv_val();		/* Get and initialize all environment variables */
1230	prtln();
1231
1232	if (argc < 2) {
1233		fprintf(stderr,
1234			"usage: %s [-b number] [-d number] [-t number] \n",
1235			argv[0]);
1236		fprintf(stderr, "where:\n");
1237		fprintf(stderr,
1238			"\t-b number\tnumber of children each parent will spawn ( > 1)\n");
1239		fprintf(stderr, "\t-d number\tdepth of process tree ( > 1)\n");
1240		fprintf(stderr, "\t-t\t\tset timeout value\n");
1241		fprintf(stderr, " SEVERE : Command line parameter error.\n");
1242		exit(1);
1243	}
1244
1245	parse_args(argc, argv);	/* Get all command line arguments */
1246	dprt("value of BVAL = %d, value of DVAL = %d\n", BVAL, DVAL);
1247	nodesum = sumit(BVAL, DVAL);
1248#ifdef _LINUX
1249	if (nodesum > 250) {
1250		printf("total number of process to be created "
1251		       "nodesum (%d) is greater\n than the allowed "
1252		       "SEMMSL value (250)\n", nodesum);
1253		printf("reseting the value of nodesum to SEMMSL\n");
1254		nodesum = 250;
1255	}
1256#endif
1257
1258	dprt("value of nodesum is initiallized to: %d\n", nodesum);
1259
1260	prtln();
1261	setup_shm();		/* Set up, allocate and initialize shared memory */
1262	prtln();
1263	setup_semaphores();	/* Set up, allocate and initialize semaphores */
1264	prtln();
1265	setup_msgqueue();	/* Set up, allocate and initialize message queues */
1266	prtln();
1267
1268	doit();			/* spawn off processes */
1269	prtln();
1270	return 0;
1271
1272}
1273