/* 
 * startup - Initiate shared memory server and client processes.
 *
 * Programming Assignment #8.
 *
 * CSc 645  Spring 1995  Jim Warhol
 *
 * startup initiates the shared memory server process, prompts the user 
 * for the port number printed out by the server and for the number of
 * clients to be started, and forks off the desired client processes.
 *
 * The major advantage of using this program to start the client processes
 * is that when startup terminates (after all of the client processes exit)
 * all active child processes, if any, will by killed by * the system 
 * automatically (theoretically anyway). The user is also saved the trouble
 * of typing the client command repeatedly.
 *
 * Compile with: cc -o Apps/startup startup.c common.c
 *
 * Execute with: startup
 *
 * Related components: client.c/server.c, common.h/common.c, SMlib.c, 
 *                     RPCdg.c/RPCst.c.
 *
 */

#include "common.h"
#include <sys/param.h>
#include <sys/wait.h>

/* data definitions */

char hostname[MAXHOSTNAMELEN];		/* host name for server */
int serverPID;				/* PID of server from fork() */
int portnumn;				/* port number for server - integer */
char portnums[6];			/* port number for server - string */
int numclientsn;			/* number of clients - integer */
char numclientss[6];			/* number of clients - string */
int j;					/* scratch variable */

/* main program */

void main()
{
   /* determine host name for server (same as current host name) */

   if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
      error("An error occurred when calling gethostname().");

   /* fork off process to start up server */

   serverPID = fork();
   if (serverPID == 0) {		/* if child process */
      prints("startup: Forking process to execute \"server\" on host %s.\n",
         hostname);
      execlp("server", "server", 0);
      error("startup: Unexpected return from execlp.");
   }
   printn("startup: server PID is %d.\n", serverPID);

   /* ask user for the port number for the server */

   sleep(1);				/* give server time to start up */
   print("startup: Please enter the server port number as printed above: ");
   if (scanf("%d", &portnumn) != 1) error("startup: Incorrect port number.");
   sprintf(portnums, "%d", portnumn);

   /* ask user for the number of clients desired, and validate input */

   print("startup: Number of clients to execute: ");
   if (scanf("%d", &numclientsn) != 1) error("startup: Invalid client count.");
   if (numclientsn < 1 || numclientsn > MAXCLIENTS)
      errorn("startup: The number of clients must be in the range [1..%d].",
         MAXCLIENTS);
   sprintf(numclientss, "%d", numclientsn);

   /* fork off numclientsn client processes */

   for (i = 1; i <= numclientsn; i++) {
      sleep(1);				/* don't start clients simultaneously */
      printsnns("startup: Forking process to execute "
         "\"client %s %d %d\" on host %s.\n", hostname, portnumn, numclientsn,
         hostname); 
      if ((j = fork()) == 0) {		/* if child process */
         execlp("client", "client", hostname, portnums, numclientss, 0);
         error("startup: Unexpected return from execlp.");
      }
      printnnn("startup: client (%d of %d) PID is %d.\n", i, numclientsn, j);
   }

   /* now wait until all (numclientsn) client processes have terminated */

   for (i = 1; i <= numclientsn; i++) {
      j = wait((union wait *) 0);
      if (j == serverPID)
         error("startup: Server process unexpectedly terminated.");
      if (j == -1) error("startup: Unexpected error return from wait().");
      printn("startup: client process, PID %d, has terminated.\n", j);
   }
   print("startup: All client processes have terminated; startup process "
      "exiting.\n");
   sleep(2);				/* give output a chance to catch up */
   exit(0);
}

