/*
 * Copyright 2000, International Business Machines Corporation and others.
 * All Rights Reserved.
 * 
 * This software has been released under the terms of the IBM Public
 * License.  For details, see the LICENSE file in the top-level source
 * directory or online at http://www.openafs.org/dl/license10.html
 */

/* the wrapper nanny process around weblog that would restart it in case it 
 * failed and hopefully log the error somewhere! The need for this nanny 
 * process arises because the pipe descriptors need to be maintained. The 
 * process catches SIGTERM and kills the weblog process and exits. 
 * The following line needs to precede the kill -TERM line for httpd.pid
 * in the stopd script to stop the server
          kill -TERM `<cat /local/stronghold/apache/logs/httpd.pid>.afs`
 * or whatever the pid file 
 */

#include <afs/stds.h>

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>

#include "weblog_errors.h"
#include "AFS_component_version_number.c"

#define WEBLOG_BIN "weblog"

/* TODO - set restart_attempts to 0 if not within certain time period */
#define MAX_RESTARTS        3   /* after this many restarts just die */
static int restart_attempts=0;

int error_fd; /* error file descriptor */

void sig_term() {
#ifdef AIX
  pid_t pgrp=getpgrp();
#else
  pid_t pgrp=getpgrp(0);
#endif
  int n;

#ifdef DEBUG
  write(2, "weblog_starter: caught SIGTERM, shutting down",43);
#endif

  log_error("weblog_starter: caught SIGTERM, shutting down");

  if (pgrp == (pid_t)-1) {
    log_error("getpgrp failed - kill weblog manually");
    write(2,"getpgrp failed - kill weblog manually",38);
    exit(1);
  }
  kill(-pgrp,SIGKILL);
  exit(1);
}

/* strip out this binary and replace it with the weblog binary's name */
getpath(char *this, char *path) {
  char *temp=&this[0];
  int len=strlen(this);
  int pos=0,i=0,j=0;
  char bin_name[]=WEBLOG_BIN;
  int len1=strlen(bin_name);

  strcpy(path,this);
  temp+=(len);
  pos=len;
  while(*temp != '/') {
    temp--;
    pos--;
  }
  for (i=(pos+1);i<len;i++,j++) {
    path[i]=bin_name[j];
    if(j>=len1) 
      break;
  }
}

char *get_time() {
    time_t t;
    char *time_string;

    t=time(NULL);
    time_string = (char *) ctime((time_t *) &t);
    time_string[strlen(time_string) - 1] = '\0';
    return (time_string);
}

log_error(char *msg)
{
  char err_msg[1024];

  sprintf(err_msg,"[%s] weblog:%s\n",get_time(), msg);
  write(error_fd,(void *) err_msg, strlen(err_msg));
}


int main(int argc, char **argv)
{
  pid_t weblog_pid;
  int stat=-1;
  int exitstatus=0;
  char rn[]="weblog_starter";
  char path[1024];
  char error_fname[1024];

  struct sigaction sa;

  memset(&sa,0,sizeof sa);
  sa.sa_handler=(void (*)())sig_term;
  if(sigaction(SIGTERM,&sa,NULL) < 0) {
    perror("sigaction(SIGTERM)");
  }
  
  getpath(argv[1], path);
  strcpy(error_fname,argv[2]);

  error_fd=open(error_fname,O_WRONLY|O_APPEND|O_CREAT);
  if (error_fd < 0) {
    fprintf(stderr, "%s:Error opening log file:%s\nExiting\n",rn,error_fname);
    perror("open");
    exit(-1);
  }

  log_error("weblog_starter resuming normal operation");

  while(restart_attempts < MAX_RESTARTS) {
    /* fork the weblog process and wait till it exits */
    if((weblog_pid=fork()) < 0) {
      log_error("Could not fork process");
#ifdef DEBUG
      perror("apache_afs_weblog:Could not fork process");
#endif
      exit(-1);
    }
    switch (weblog_pid) {
    case 0:
      /* the child process - in this case weblog */
      execlp(path, "weblog", argv[3],argv[4],argv[5],argv[6],(char *)0);
#ifdef DEBUG
      perror("apache_afs_weblog:Could not execute weblog");
#endif
      exit(RESTARTERROR);
      
    default:
      /* parent: just wait for the child */
      weblog_pid=waitpid((pid_t) -1, &stat,0);
      
      if (weblog_pid == -1) {
#ifdef DEBUG
	perror("apache_Afs_weblog: wait error");
#endif
	log_error("wait error");
	kill(getpid(),SIGTERM);
      }
      
      if (WIFEXITED(stat)) {
	exitstatus=WEXITSTATUS(stat);
	switch(exitstatus) {
	case 0:
#ifdef DEBUG
	  fprintf(stderr, "%s:No error ... restarting\n",rn);
#endif
	  break;
	  
	case RESTART:
#ifdef DEBUG
	  fprintf(stderr, "%s:%s...Exiting\n", rn, RESTARTMSG);
#endif
	  log_error(RESTARTMSG);
	  exit(-1);
	  
	case NULLARGS:
#ifdef DEBUG
	  fprintf(stderr, "%s:%s...Exiting\n", rn, NULLARGSMSG);
	  log_error(NULLARGSMSG);
#endif
	  exit(-1);
	  
	case PIPESEND:
#ifdef DEBUG
	  fprintf(stderr, "%s:%s...Restarting\n", rn, PIPESENDMSG);
#endif
	  log_error(PIPESENDMSG);
	  break;
	  
	case PIPEREAD:
#ifdef DEBUG
	  fprintf(stderr, "%s:%s...Exiting\n", rn, PIPEREADMSG);
#endif
	  log_error(PIPEREADMSG);
	  exit(-1);
	  
	case PARSE:
#ifdef DEBUG
	  fprintf(stderr, "%s:%s...Exiting\n", rn, PARSEMSG);
#endif
	  log_error(PARSEMSG);
	  exit(-1);
	  
	case KA:
#ifdef DEBUG
	  fprintf(stderr, "%s:%s...Exiting\n", rn, KAMSG);
#endif
	  log_error(KAMSG);
	  exit(-1);
	
	default:
#ifdef DEBUG
	  fprintf(stderr, "%s:Unknown error...Exiting\n", rn);
#endif
	  log_error("Unknown error");
	  exit(-1);
	}      /* switch (exitstatus) */
      } /* if weblog exited */
      
      else {      /* weblog terminated abnormally */
	if (WIFSIGNALED(stat)) {
#ifdef DEBUG
	  fprintf(stderr, "%s:The signal that terminated weblog:%d\n"
		  "Restarting weblog ...\n",rn,WTERMSIG(stat));
#endif
	}
#ifndef AIX
	else if (WCOREDUMP(stat)){
#ifdef DEBUG
	  fprintf(stderr, "%s: weblog dumped core"
		  "Exiting ...\n",rn);
#endif
	  log_error("Core dump");
	  exit(-1);
	}
#endif
	else {
#ifdef DEBUG
	  fprintf(stderr, "%s: weblog died under STRANGE circumstances..."
		  "restarting weblog\n",rn);
#endif
	}
      }
      break;
    } /* switch(weblog_pid) */
    restart_attempts++;
  } /* while */
}




