#include "headers.h" /* has all the important stuff */

/* just called at startup to setup setjmp() */
void init()
{
   tzset();
   srandom((int)time(NULL) + (int)getpid());

   /* just initialize stuff.. all we need to do for now is */
   /* initialize setjmp() that's located in quit()...      */
   quit(INIT);
}


/* -------------------------------- */


/* initialize the shared memory */
void shrMemInit()
{
   int res;

   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

#  ifdef HAVE_SHMGET
   debug("getting a new shared memory ID\n");

   clients[curClient].shmID = 
		shmget(IPC_PRIVATE, MAXSEGSIZE, IPC_CREAT | IPC_EXCL | 0600);

   if (clients[curClient].shmID == ERROR)
   {
      clients[curClient].pinging = NOPING;
      error("error getting shared memory ID: %s\n\n", strerror(errno));
      return;
   }

#  else
   clients[curClient].pinging = NOPING;
   return;
#  endif

#  ifdef HAVE_SHMAT
   debug("attaching the shared memory segment\n");

   clients[curClient].segptr = shmat(clients[curClient].shmID, 0, 0);
   if (clients[curClient].segptr == NULL)
   {
      clients[curClient].pinging = NOPING;
      error("error attaching shared memory: %s\n\n", strerror(errno));
      return;
   }

#  else
   clients[curClient].pinging = NOPING;
   return;
#  endif

   memset(clients[curClient].segptr, 0, MAXSEGSIZE);

#  ifdef HAVE_SHMCTL
   debug("removing the shared memory ID\n");

   res = shmctl(clients[curClient].shmID, IPC_RMID, 0);
   if (res == ERROR)
   {
      clients[curClient].pinging = NOPING;
      error("error removing the ID: %s\n\n", strerror(errno));

      debug("now detaching the shared memory segment too\n");

      res = shmdt(clients[curClient].segptr);
      if (res == ERROR)
         error("error detaching the segment: %s\n\n", strerror(errno));

      return;
   }

#  else
   clients[curClient].pinging = NOPING;
   return;
#  endif
}


/* -------------------------------- */


/* setup files and things */
void setup()
{
   if (locPort <= 0) locPort = PORT;

   createDirs(0); /* 0 == no client specifically yet */

   setupFiles();

   /* setup signals */
   signal(SIGHUP, SIG_IGN);
   signal(SIGINT, sighandler);
   signal(SIGTERM, sighandler);
   signal(SIGCHLD, sighandler);

   signal(SIGPIPE, SIG_IGN);

   signal(SIGUSR1, SIG_IGN);
   signal(SIGUSR2, SIG_IGN);
   /* ------------ */

   if (debugging != 1)
   {
      signal(SIGILL, sighandler);
      signal(SIGBUS, sighandler);
      signal(SIGSEGV, sighandler);

      signal(SIGQUIT, sighandler);
   }
}


/* -------------------------------- */


/* create/setup files to log */
void setupFiles()
{
   int maxfds;
   register int i;

   time_t tm = time(NULL);

   char buf[128];
   char dblog[MAXFNAMESIZE]; 
   char errlog[MAXFNAMESIZE]; 

   memset(dblog, 0, sizeof(dblog));
   memset(errlog, 0, sizeof(errlog));

   maxfds = (int)sysconf(_SC_OPEN_MAX);
   if (maxfds == ERROR) 
   {
      (void)fprintf(stderr,
                    "error getting the max. # of open files: %s\n\n",
                    strerror(errno));

      (void)fprintf(stderr,
              "setting the maximum number of open files to 256..\n\n");

      maxfds = 256;
   }

   else if (maxfds != ERROR)
      if (debugging == 1)
         (void)printf("Maximum # of open files supported: (%d)\n\n", maxfds);

   /* start with 3 to skip stdin, stdout, and stderr */
   for (i = 3; i <= maxfds; i++) (void)close(i);

   /* -------------- open errlog junk ---------------- */

   if (errorFile == NULL) 
      (void)snprintf(errlog, sizeof(errlog)-1, "%s/%s", SRSDIR, ERRLOG);

   else (void)snprintf(errlog, sizeof(errlog)-1, errorFile);

   errlogfd = open(errlog, O_CREAT | O_WRONLY | O_APPEND, 0600);
   if (errlogfd == ERROR)
   {
      (void)fprintf(stderr, "error opening %s: %s\n\n", errlog,
                    strerror(errno));

      exit(ERROR);
   }

   errlogfd1 = fopen(errlog, "a");
   if (errlogfd1 == NULL)
   {
      (void)fprintf(stderr, "error opening %s: %s\n\n", errlog,
                    strerror(errno));

      exit(ERROR);
   }

   /* --------------- open dblog junk ---------------- */

   if (debugging == 1)
   {
      snprintf(dblog, sizeof(dblog)-1, "%s/%s", SRSDIR, DEBLOG);

      dblogfd = open(dblog, O_CREAT | O_WRONLY | O_APPEND, 0600);
      if (dblogfd == ERROR)
      {
         (void)fprintf(stderr, "error opening %s: %s\n\n", dblog,
                       strerror(errno));

         exit(ERROR);
      }

      dblogfd1 = fopen(dblog, "a");
      if (dblogfd == ERROR)
      {
         (void)fprintf(stderr, "error opening %s: %s\n\n", dblog,
                       strerror(errno));

         exit(ERROR);
      }
   }

   /* ------------------------------------------------ */

   memset(buf, 0, sizeof(buf));

   sprintf(buf, "----------------------------------------------\n\n");
   (void)write(errlogfd, buf, strlen(buf));

   if (debugging == 1) (void)write(dblogfd, buf, strlen(buf));

   memset(buf, 0, sizeof(buf));

   sprintf(buf, "SRS restarted on: %s\n", ctime(&tm));
   (void)write(errlogfd, buf, strlen(buf));

   if (debugging == 1) (void)write(dblogfd, buf, strlen(buf));
}


/* ------------------------------- */


/* set the process ID's */
void setPids(int pid)
{
   int res;

   (clients[curClient]).free = ERROR;
   (clients[curClient]).pidstats[curPid].pid  = pid; 
   (clients[curClient]).pidstats[curPid].ppid = getpid();
   (clients[curClient]).pidstats[curPid].pgid = getpgid(pid);

   debug("clients[%d].pid = %d\n", curClient, pid);

   (void)sleep(NORMPAUSE); /* give the child time to setup    */

   res = seteuid(0); 
   if (res == ERROR) 
   {
      error("error with seteuid: %s\n\n", strerror(errno));
      quit(ERROR);
   }

   /* send it the signal that it can now start up */
   res = kill((clients[curClient]).pidstats[curPid].pid, SIGUSR1);

   if (res == ERROR) 
      error("error killing pid %d: %s\n\n",
            clients[curClient].pidstats[curPid].pid, strerror(errno));

   res = seteuid(pwd->pw_uid);
   if (res == ERROR) 
   {
      error("error with seteuid: %s\n\n", strerror(errno));
      quit(ERROR);
   }
}


/* -------------------------------- */


/* setup default client structures */
void setupClients()
{
   register int i, j;

   /* setup start/default values.. */
   for (i = 0; i < MAXCONNS; i++)
   {
      clients[i].free    = 1; /* yes, it's free   */
      clients[i].running = 0; /* no.. not running */
      clients[i].newData = 0; /* no new data yet  */

      memset(clients[i].oldbuf, 0, sizeof(clients[i].oldbuf));

      /* 1 main pid and 1 pid for pinging */
      for (j = 0; j < MAXNUMKIDS; j++) 
      {
         clients[i].pidstats[j].pid  = ERROR;
         clients[i].pidstats[j].ppid = ERROR;
         clients[i].pidstats[j].pgid = ERROR;
      }
   }
}


/* -------------------------------- */


/* count the clients sub-ID's */
void setupSubIDs()
{
   int res;
   register int i;

   for (i = 0; i < MAXCONNS; i++)
   {
       if (clients[i].free == 1) continue;
       else if (i == curClient) continue; /* skip our own struct */
       else if (clients[i].pidstats[0].pid <= 0) continue;

       if (clients[i].ID == clients[curClient].ID)
       {
          debug("clients[%d].ID = clients[%d].ID (ID %04d)\n", i, 
                curClient, clients[i].ID);

          clients[curClient].numSubIDs++;
       }
   }

   clients[curClient].numSubIDs++;

   debug("current sub-ID for ID %04d = %d\n\n", 
         clients[curClient].ID, clients[curClient].numSubIDs);

   res = checkMaxSubIDs();
   if (res == ERROR) 
   {
      errors = 1;
      return;
   }
}
