/* Ew-too guardian angel ( the newer one) */
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#if !defined(linux)
#include <sys/filio.h>
#endif /* LINUX */
#include "config.h"
/* Namesetting of the Server and Angel */
char *angel_name = "EW-too Angel on port";
char *server_name = "EW-for talk server on port";
char *stack, *stack_start;
int fh = 0, die = 0, crashes = 0, syncing = 0;
long int time_out = 0, t = 0;
int no_tty=0;
/* return a string of the system time */
char *sys_time()
{
time_t t;
static char time_string[25];
t = time(0);
strftime(time_string, 25, "%H:%M:%S - %d/%m/%y", localtime(&t));
return time_string;
}
/* log errors and things to file */
void log(char *file, char *string)
{
int fd, length;
sprintf(stack, "logs/%s.log", file);
fd = open(stack, O_CREAT | O_WRONLY | O_SYNC, S_IRUSR | S_IWUSR);
length = lseek(fd, 0, SEEK_END);
if (length > MAX_LOG_SIZE)
{
close(fd);
fd = open(stack, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, S_IRUSR
| S_IWUSR);
}
sprintf(stack, "%s - %s\n", sys_time(), string);
if (!no_tty)
printf(stack);
write(fd, stack, strlen(stack));
close(fd);
}
void error(char *str)
{
log("angel", str);
exit(-1);
}
void sigpipe()
{
error("Sigpipe received.");
}
void sighup()
{
kill(fh, SIGHUP);
die = 1;
}
void sigquit()
{
error("Quit signal received.");
}
void sigill()
{
error("Illegal instruction.");
}
void sigfpe()
{
error("Floating Point Error.");
}
void sigbus()
{
error("Bus Error.");
}
void sigsegv()
{
error("Segmentation Violation.");
}
void sigsys()
{
error("Bad system call.");
}
void sigterm()
{
error("Terminate signal received.");
}
void sigxfsz()
{
error("File descriptor limit exceeded.");
}
void sigchld()
{
log("angel", "Received SIGCHLD");
return;
}
/* Woo woo, the main function thang */
main(int argc, char *argv[])
{
int status;
int length, alive_fd, sock_fd, dieing;
struct sockaddr_un sa;
char dummy;
fd_set fds;
struct timeval timeout;
#if defined(hpux) | defined(linux)
struct sigaction siga;
#endif /* hpux | linux */
stack_start = (char *) malloc(1000);
stack = stack_start;
if (chdir(ROOT) < 0)
error("Can't change to root directory.\n");
if (strcmp(angel_name, argv[0]))
{
if (!argv[1])
{
sprintf(stack, "%d", DEFAULT_PORT);
execlp("bin/angel", angel_name, stack, 0);
} else
{
argv[0] = angel_name;
execvp("bin/angel", argv);
}
error("exec failed");
}
if (nice(5) < 0)
error("Failed to renice");
t = time(0);
time_out = t + 60;
#if defined(hpux) | defined(linux)
siga.sa_handler = sigpipe;
siga.sa_mask = 0;
siga.sa_flags = 0;
sigaction(SIGPIPE, &siga, 0);
siga.sa_handler = sighup;
sigaction(SIGHUP, &siga, 0);
siga.sa_handler = sigquit;
sigaction(SIGQUIT, &siga, 0);
siga.sa_handler = sigill;
sigaction(SIGILL, &siga, 0);
siga.sa_handler = sigfpe;
sigaction(SIGFPE, &siga, 0);
siga.sa_handler = sigbus;
sigaction(SIGBUS, &siga, 0);
siga.sa_handler = sigsegv;
sigaction(SIGSEGV, &siga, 0);
#if !defined(linux)
siga.sa_handler = sigsys;
sigaction(SIGSYS, &siga, 0);
#endif /* LINUX */
siga.sa_handler = sigterm;
sigaction(SIGTERM, &siga, 0);
siga.sa_handler = sigxfsz;
sigaction(SIGXFSZ, &siga, 0);
siga.sa_handler = sigchld;
sigaction(SIGCHLD, &siga, 0);
#else /* hpux | linux */
signal(SIGPIPE, sigpipe);
signal(SIGHUP, sighup);
signal(SIGQUIT, sigquit);
signal(SIGILL, sigill);
signal(SIGFPE, sigfpe);
signal(SIGBUS, sigbus);
signal(SIGSEGV, sigsegv);
signal(SIGSYS, sigsys);
signal(SIGTERM, sigterm);
signal(SIGXFSZ, sigxfsz);
signal(SIGCHLD, sigchld);
#endif /* hpux | linux */
while (!die)
{
t = time(0);
if (crashes >= 4 && time_out >= t)
{
log("error", "Total barf.. crashing lots... Giving up");
log("error", "Question is, what now ??");
exit(-1);
} else if (time_out < t)
{
time_out = t + 30;
crashes = 0;
}
crashes++;
log("angel", "Forking to boot server");
dieing = 0;
fh = fork();
switch (fh)
{
case 0:
setsid();
argv[0] = server_name;
execvp("bin/talker", argv);
error("failed to exec server");
break;
case -1:
error("Failed to fork()");
break;
default:
no_tty = 1;
unlink(SOCKET_PATH);
sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0)
error("failed to create socket");
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path, SOCKET_PATH);
if (bind(sock_fd, (struct sockaddr *) & sa, sizeof(sa)) < 0)
error("failed to bind");
if (listen(sock_fd, 1) < 0)
error("failed to listen");
timeout.tv_sec = 120;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock_fd, &fds);
if (select(FD_SETSIZE, &fds, 0, 0, &timeout) <= 0)
{
kill(fh, SIGKILL);
log("angel", "Killed server before connect");
waitpid(fh, &status, 0);
} else
{
length = sizeof(sa);
alive_fd = accept(sock_fd, (struct sockaddr *) & sa, &length);
if (alive_fd < 0)
error("bad accept");
close(sock_fd);
while (waitpid(fh, &status, WNOHANG) <= 0)
{
timeout.tv_sec = 300;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(alive_fd, &fds);
if (select(FD_SETSIZE, &fds, 0, 0, &timeout) <= 0)
{
if (errno != EINTR)
{
if (dieing)
{
kill(fh, SIGKILL);
log("angel", "Server KILLED");
} else
{
kill(fh, SIGTERM);
log("angel", "Server TERMINATED");
dieing = 1;
}
}
} else
{
if (ioctl(alive_fd, FIONREAD, &length) < 0)
error("bad FIONREAD");
if (!length)
{
kill(fh, SIGKILL);
log("angel", "Server disconnected");
dieing = 1;
} else
{
for (; length; length--)
{
read(alive_fd, &dummy, 1);
}
}
}
}
}
close(alive_fd);
switch ((status & 255))
{
case 0:
log("angel", "Server exited safely");
break;
case 127:
sprintf(stack, "Server stopped due to signal %d.",
(status >> 8) & 255);
while (*stack)
stack++;
stack++;
log("angel", stack_start);
stack = stack_start;
break;
default:
sprintf(stack, "Server terminated due to signal %d.",
status & 127);
while (*stack)
stack++;
stack++;
log("angel", stack_start);
stack = stack_start;
if (status & 128)
log("angel", "Core dump produced");
break;
}
break;
}
}
}