#include "headers.h"

/* this file has various functions for exiting and aborting */

/* free structures and exit */
void quit(int stat)
{
   int res;
   int jumped;    

   jumped = setjmp(doquit);
   if ((jumped == ERROR) && (errno != 0)) 
      error("error with setjmp: %s\n\n", strerror(errno));

   /* just for setjmp()..not to quit */
   if (stat == INIT) return; 

   signal(SIGINT,  SIG_IGN);
   signal(SIGTERM, SIG_IGN);

   signal(SIGPIPE, SIG_IGN);

   signal(SIGUSR1, SIG_IGN);
   signal(SIGUSR2, SIG_IGN);
   
   if (debugging != 1)
   {
      signal(SIGILL,  SIG_IGN);
      signal(SIGBUS,  SIG_IGN);
      signal(SIGSEGV, SIG_IGN);
      signal(SIGQUIT, SIG_IGN);
   }

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

   /* this is where all the closing/killing/freeing takes place */
    
   error("received abort request...\n\n");

   if (mainpid <= 0)
   {
      error("main pid unknown.. aborting immediately\n\n");
      exit(ERROR);
   }

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

   closeSockets(); /* close open sockets */

   if (mainpid == getpid())
      if (mainfd > 0) (void)close(mainfd);

   if (mainpid != getpid()) closeLogFiles();

   freeSharedMem();
   /* freeClients(); - we're not using dynamic memory right now */

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

   if (mainpid == getpid()) doKills();
   else if (clients[curClient].pidstats[0].pid == getpid()) doKills();

   if (pwd != NULL)
   {
      res = seteuid(pwd->pw_uid);

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

   if (mainpid == getpid())
   {
      (void)close(errlogfd), (void)fclose(errlogfd1);

      if (debugging == 1)
      {
         (void)close(dblogfd);
         (void)fclose(dblogfd1);
      }
   }

   else
   {
      if (debugging == 1)
      {
         (void)close(dblogfd);
         (void)fclose(dblogfd1);
      }
   }

   if ((debugging == 1) && (mainpid == getpid()))
   {
      (void)printf("\nfinished closing..\n");
      (void)printf("see error.log for a log\n\n");
   }

   /* jumped == value passed by longjmp() */
   if (jumped == 0) exit(stat);
   else exit(jumped);
}


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


/* close all open sockets  */
void closeSockets()
{
   int res;
   register int i;

   debug("closing sockets\n");
   if (mainpid != getpid()) 
   {
      if (clients[curClient].sockfd > 0) 
         res = close(clients[curClient].sockfd);

      if (res == ERROR)
      {
         error("error closing sockfd: %s\n\n", strerror(errno));
         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }
      }

      return;
   }

   for (i = 0; i < MAXCONNS; i++)
   {
      if ((clients[i].free == 1) || (clients[i].sockfd <= 0)) continue;

      res = close(clients[i].sockfd);
      if (res == ERROR) 
         error("error closing client's fd: %s\n\n", strerror(errno));
   }
}


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


/* close and free logs */
void closeLogFiles()
{
   register int i;

   debug("closing log files\n");

   for (i = 0; i <= curlogfd; i++)
   {
      if (clients[curClient].logs[i].fd > 0)
         (void)close(clients[curClient].logs[i].fd);

      /* okay.. so technically it shouldn't be in closeSockets() */
      /* but when we play with logs[].fd.. this goes too         */
      if (clients[curClient].logs[i].filename != NULL) 
         free(clients[curClient].logs[i].filename);
   }
}


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


/* free shared memory, remove shared mem IDs, detach segments, etc. */
void freeSharedMem()
{
   int res;
   register int i = 0;

   if (mainpid != getpid())
   {
      debug("detaching shared memory\n");
      res = shmdt(clients[i].segptr);

      if (res == ERROR)
      {
         error("error detaching shared memory: %s\n\n", strerror(errno));
         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }
      }

      return;
   }

   debug("detaching shared memory\n");

   for (i = 0; clients[i].segptr != NULL; i++)
   {
      res = shmdt(clients[i].segptr);
      if (res == ERROR)
         error("error detaching shared memory: %s\n\n", strerror(errno));
   }
}


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


/* free up client structures */
void freeClients()
{
/* 
   register int i = 0;

   debug("freeing client structures\n");

   for (i = 0; i < MAXCONNS; i++)
      if (clients[i] != NULL)
         free(clients[i]);
*/
}


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


/* kill all child processes */
void doKills()
{
   int res;
   int didkill = 0;

   register int i = 0;

   if (mainpid != getpid())
   {
      if (clients[curClient].pinging == 1)
      {
         if (debugging == 1)
         {
            (void)putchar('\n'); 
            (void)write(dblogfd, "\n", 1);
         }

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

         if (clients[curClient].pidstats[0].pid <= 0)
         {
            error("(in doKills) pidstats[0].pid <= 0..\n\n");

            if ((clients[curClient].pidstats[1].pid > 0) && 
                (clients[curClient].pidstats[1].pid == getpid()))
               clients[curClient].pidstats[0].pid = getpid();

            else return;
         }

         if (clients[curClient].pidstats[0].pid == getpid())
         {
            if (clients[curClient].pidstats[1].pid <= 0) return;

            debug("killing ping process (pid %d)\n",
                  clients[curClient].pidstats[1].pid);

            res = kill(clients[curClient].pidstats[1].pid, SIGTERM);
            if (res == ERROR)
               error("error killing ping process: %s\n\n", strerror(errno));

            didkill = 1;
         }

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

      return;      
   }

   /* kill all client handlers (but not the main superserver.. that's us) */
   for (i = 0; i < MAXCONNS; i++)
   {
      if (clients[i].free == 1) continue;
      else if (clients[i].pidstats[0].pid <= 0) continue;
      else if (clients[i].pidstats[0].pid != getpid())
      {
         debug("killing the client hander (pid %d)... ID %04d\n",
               clients[i].pidstats[0].pid, clients[i].ID);

         (void)kill(clients[i].pidstats[0].pid, SIGTERM);
         didkill = 1;
      }
   }
}


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