+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ * University College Dublin
+ * Danmarks Teknologiske Videnscenter
+ * An Chomhairle Leabharlanna
+ * Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ *
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
/* Gateway Resource Monitor
* Europagate, 1995
*
* $Log: monitor.c,v $
- * Revision 1.4 1995/05/02 15:26:00 adam
+ * Revision 1.15 1995/07/11 11:49:12 adam
+ * LINE_MAX renamed to STR_LINE_MAX.
+ *
+ * Revision 1.14 1995/05/23 08:12:59 adam
+ * Minor changes.
+ *
+ * Revision 1.13 1995/05/22 11:42:48 adam
+ * Minor changes on dtbsun.
+ *
+ * Revision 1.12 1995/05/19 14:51:06 adam
+ * Bug fix: stopped kernels sometimes got IPC messages from the monitor.
+ *
+ * Revision 1.11 1995/05/19 13:26:00 adam
+ * Bug fixes. Better command line options.
+ *
+ * Revision 1.10 1995/05/18 12:03:09 adam
+ * Bug fixes and minor improvements.
+ *
+ * Revision 1.9 1995/05/17 10:51:32 adam
+ * Added a few more error checks to the show command.
+ *
+ * Revision 1.8 1995/05/16 09:40:42 adam
+ * LICENSE. Setting of CCL token names (and/or/not/set) in read_kernel_res.
+ *
+ * Revision 1.7 1995/05/03 12:18:46 adam
+ * This code ran on dtbsun. Minor changes.
+ *
+ * Revision 1.6 1995/05/03 09:16:17 adam
+ * Minor changes.
+ *
+ * Revision 1.5 1995/05/03 07:37:42 adam
+ * CCL commands stop/continue implemented. New functions gw_res_{int,bool}
+ * are used when possible.
+ *
+ * Revision 1.4 1995/05/02 15:26:00 adam
* Monitor observes death of child (email kernel). The number
* of simultanous processes is controlled now. Email requests are
* queued if necessary. This scheme should only be forced if no kernels
#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
+#include <errno.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <strqueue.h>
#include <lgets.h>
-#define LINE_MAX 1024
+#define STR_LINE_MAX 1024
-#define MONITOR_FIFO_S "fifo.s"
-#define MONITOR_FIFO_C "fifo.c"
+#define MONITOR_FIFO_S "fifo.s.m"
+#define MONITOR_FIFO_C "fifo.c.m"
static char *module = "monitor";
static jmp_buf retry_jmp;
static int max_process = 1;
static int got_sighup = 0;
static int got_term = 0;
+static int got_int = 0;
const char *default_res = "default.res";
+/*
+ * reread_resources: reread monitor resources. The static variable,
+ * max_process, is updated.
+ */
static void reread_resources (void)
{
if (monitor_res)
default_res);
exit (1);
}
- max_process = atoi (gw_res_get (monitor_res, "gw.max.process", "10"));
+ max_process = gw_res_int (monitor_res, "gw.max.process", 10);
}
struct ke_info {
- pid_t pid;
- int id;
- GIP gip;
- struct str_queue *queue;
- struct ke_info *next;
+ int id; /* email user-id */
+ int stopped; /* stop flag */
+ pid_t pid; /* pid of email kernel child */
+ GIP gip; /* fifo information */
+ struct str_queue *queue; /* message queue */
+ struct ke_info *next; /* link to next */
};
-struct ke_info *ke_info_list = NULL;
+/* list of email kernel infos */
+static struct ke_info *ke_info_list = NULL;
+/*
+ * ke_info_add: add/lookup of email kernel info.
+ * id: email user-id to search for.
+ * return: pointer to info structure.
+ */
struct ke_info *ke_info_add (int id)
{
struct ke_info **kip;
(*kip)->id = id;
(*kip)->gip = NULL;
(*kip)->queue = NULL;
+ (*kip)->stopped = 0;
return *kip;
}
free (ki);
}
+/*
+ * catch_child: catch SIGCHLD. Set email kernel pid to -1
+ * to indicate that child has exited
+ */
static void catch_child (int num)
{
pid_t pid;
signal (SIGCHLD, catch_child);
}
+/*
+ * catch_int: catch SIGHUP.
+ */
static void catch_hup (int num)
{
got_sighup = 1;
signal (SIGHUP, catch_hup);
}
+/*
+ * catch_int: catch SIGTERM.
+ */
static void catch_term (int num)
{
got_term = 1;
signal (SIGTERM, catch_term);
}
+/*
+ * catch_int: catch SIGINT.
+ */
+static void catch_int (int num)
+{
+ got_int = 1;
+ signal (SIGINT, catch_int);
+}
+
+/*
+ * pipe_handle: handle SIGPIPE when transferring message to kernel
+ */
static void pipe_handle (int dummy)
{
longjmp (retry_jmp, 1);
}
+/*
+ * start_kernel: start email kernel.
+ * argc: argc of email kernel
+ * argv: argv of email kernel
+ * id: email user-id
+ * return: pid of email kernel child
+ */
static pid_t start_kernel (int argc, char **argv, int id)
{
pid_t pid;
return pid;
}
+/*
+ * deliver: deliver message to child (email kernel).
+ * argc: exec argc to child (if it need to be started)
+ * argv: exec argv to child (if it need to be started)
+ * id: email userid
+ * queue: message queue to be transferred
+ * gip: pointer to FIFO info. if *gip is NULL prior invocation
+ * it will be created (initialized) and the pointer will be
+ * updated.
+ * pidp: pointer to pid. Will hold process-id of child (if it need to
+ * be started)
+ * dont_exec: if non-zero a child will never be started; otherwise child
+ * will be started if not already running.
+ * return: 0 if message couldn't be transferred, i.e. dont_exec is non-zero
+ * and the child is not already running.
+ * 1 if message was transferred and the child was already running.
+ * 2 if message was transferred and the child was started and
+ * dont_exec was zero.
+ * 3 serious error. Permissions denied or kernel couldn't be
+ * started at all.
+ */
static int deliver (int argc, char **argv, int id, struct str_queue *queue,
GIP *gip, pid_t *pidp, int dont_exec)
{
setjmp (retry_jmp);
++pass;
if (pass == 1)
- {
- gipc_close (*gip);
- r = gipc_open (*gip, fifo_server_name, 0);
+ { /* assume child is running */
+ gipc_close (*gip); /* shut down existing FIFOs */
+ r = gipc_open (*gip, fifo_server_name, 0); /* try re-open ... */
}
else if (pass == 2)
- {
+ { /* assume child is NOT running */
pid_t pid;
if (dont_exec)
- {
+ { /* we aren't allowed to start */
signal (SIGPIPE, oldsig);
return 0;
}
mknod (fifo_server_name, S_IFIFO|0666, 0);
pid = start_kernel (argc, argv, id);
- if (pidp)
+ if (pidp) /* set pid of child */
*pidp = pid;
r = gipc_open (*gip, fifo_server_name, 1);
}
else
- {
+ { /* message couldn't be transferred */
signal (SIGPIPE, oldsig);
gw_log (GW_LOG_WARN, module, "Cannot start kernel");
- return 0;
+ return 3;
}
- if (r < 0)
+ if (r < 0) /* gipc_open fail? */
{
if (r == -2)
- {
gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-2");
- longjmp (retry_jmp, 1);
- }
else if (r == -1)
- {
gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-1");
- longjmp (retry_jmp, 1);
- }
else
- {
gw_log (GW_LOG_WARN|GW_LOG_ERRNO, module, "gipc_open");
- }
+ longjmp (retry_jmp, 1); /* yet another pass */
}
- index = 0;
+ index = 0; /* transfer. may be interrupted */
while ((msg = str_queue_get (queue, index++)))
+ {
+ gw_log (GW_LOG_DEBUG, module, "deliver: %s", msg);
gip_wline (*gip, msg);
+ }
signal (SIGPIPE, oldsig);
- return pass;
+ return pass; /* successful transfer */
}
+/*
+ * monitor_events: Event loop of monitor
+ * argc: argc of monitor (used in exec of Email kernel children)
+ * argv: argv of monitor (used in exec of Email kernel children)
+ */
static void monitor_events (int argc, char **argv)
{
GIP gip_m;
- int r, gip_m_fd;
+ int r, gip_m_fd, too_many;
char line_buf[1024];
fd_set set_r;
char command[128], *cp;
+ mknod (MONITOR_FIFO_C, S_IFIFO|0666, 0);
+ open (MONITOR_FIFO_C, O_RDONLY|O_NONBLOCK);
gip_m = gips_initialize (MONITOR_FIFO_S);
- r = gips_open (gip_m, MONITOR_FIFO_C);
+ r = gips_open (gip_m, MONITOR_FIFO_C, 0);
gip_m_fd = gip_infileno (gip_m);
+#if 1
open (MONITOR_FIFO_S, O_WRONLY);
-
+#endif
+ gw_log (GW_LOG_DEBUG, module, "Starting event loop");
while (1)
{
int fd_max;
unlink (MONITOR_FIFO_C);
exit (0);
}
+ if (got_int)
+ {
+ gw_log (GW_LOG_STAT, module, "Got SIGINT. Exiting...");
+ unlink (MONITOR_FIFO_S);
+ unlink (MONITOR_FIFO_C);
+ exit (0);
+ }
+ /* deliver any unsent messages to Email kernels */
+ too_many = 0;
for (ki = ke_info_list; ki; ki = ki->next)
{
- if (!ki->queue)
+ if (!ki->queue || ki->stopped)
continue;
gw_log (GW_LOG_DEBUG, module, "Transfer mail to %d", ki->id);
r = deliver (argc, argv, ki->id, ki->queue, &ki->gip, &ki->pid,
no_process >= max_process);
- if (r == 2)
+ if (r == 2) /* new child was spawned? */
+ {
++no_process;
- if (r == 1 || r == 2)
+ gw_log (GW_LOG_DEBUG, module, "Start of %d", ki->id);
+ }
+ if (r == 1 || r == 2) /* transfer at all? */
str_queue_rm (&ki->queue);
+ if (r == 0) /* too many pending? */
+ too_many++;
+ }
+ if (too_many)
+ {
+ gw_log (GW_LOG_DEBUG, module, "%d too many pending",
+ too_many);
+ for (ki = ke_info_list; ki; ki = ki->next)
+ {
+ if (!ki->queue && ki->pid != -1 && !ki->stopped)
+ {
+ if (!(ki->queue = str_queue_mk ()))
+ {
+ gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module,
+ "str_queue_mk");
+ exit (1);
+ }
+ str_queue_enq (ki->queue, "stop\n");
+ str_queue_enq (ki->queue, "\001");
+ r = deliver (argc, argv, ki->id, ki->queue, &ki->gip,
+ &ki->pid, 1);
+ if (r != 1)
+ gw_log (GW_LOG_DEBUG, module,
+ "Stop not sent: %d", r);
+ str_queue_rm (&ki->queue);
+ ki->stopped = 1;
+ break;
+ }
+ }
}
FD_ZERO (&set_r);
FD_SET (gip_m_fd, &set_r);
if (ki->gip)
{
if (ki->pid == -1)
- {
+ { /* child has exited */
gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id);
gipc_close (ki->gip);
gipc_destroy (ki->gip);
ki->gip = NULL;
+ ki->stopped = 0;
}
else if ((fd = gip_infileno (ki->gip)) != -1)
- {
+ { /* read select on child FIFO */
gw_log (GW_LOG_DEBUG, module, "set fd %d", fd);
FD_SET (fd, &set_r);
if (fd > fd_max)
if (r != -1)
break;
if (errno != EINTR)
- {
+ { /* select aborted. And it was not due to interrupt */
gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "select");
exit (1);
}
+ /* select was interrupted. Probably child has died */
gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "select");
}
+ /* go through list of Email kernels. See if any message has arrived */
gw_log (GW_LOG_DEBUG, module, "Testing ke_info_list");
for (ki = ke_info_list; ki; ki = ki->next)
{
gipc_close (ki->gip);
gipc_destroy (ki->gip);
ki->gip = NULL;
+ ki->stopped = 0;
}
}
}
}
+ /* see if any message from eti has arrived */
gw_log (GW_LOG_DEBUG, module, "Testing gip_m_fd %d", gip_m_fd);
if (FD_ISSET (gip_m_fd, &set_r))
{
}
}
+/*
+ * main: main of monitor
+ */
int main (int argc, char **argv)
{
int argno = 0;
{
if (argv[argno][0] == '-')
{
+ if (argv[argno][1] == '-')
+ break;
switch (argv[argno][1])
{
+ case 'h':
case 'H':
- fprintf (stderr, "monitor [option..] [resource]\n");
- fprintf (stderr, "If no resource file is given");
+ fprintf (stderr, "monitor [options] [resourceFile]"
+ " -- [kernelOptions]\n");
+ fprintf (stderr, "If no resource file is specified");
fprintf (stderr, " default.res is used\n");
- fprintf (stderr, "Options are transferred to kernel\n");
+ fprintf (stderr, "Options:\n");
+ fprintf (stderr, " -l log Set Log file\n");
+ fprintf (stderr, " -d Enable debugging log\n");
+ fprintf (stderr, " -D Enable more debugging log\n");
+ fprintf (stderr, " -- Precedes kernel options\n");
+ fprintf (stderr, "Kernel options are transferred to kernel\n");
exit (1);
+ case 'l':
+ if (argv[argno][2])
+ gw_log_file (GW_LOG_ALL, argv[argno]+2);
+ else if (++argno < argc)
+ gw_log_file (GW_LOG_ALL, argv[argno]);
+ else
+ {
+ fprintf (stderr, "%s: missing log filename\n", *argv);
+ exit (1);
+ }
+ break;
case 'd':
gw_log_level (GW_LOG_ALL & ~RES_DEBUG);
break;
case 'D':
gw_log_level (GW_LOG_ALL);
break;
+ default:
+ fprintf (stderr, "%s: unknown option `%s'; use -H for help\n",
+ *argv, argv[argno]);
+ exit (1);
}
}
else
signal (SIGCHLD, catch_child);
signal (SIGHUP, catch_hup);
signal (SIGTERM, catch_term);
-#if 0
- gw_log_file (GW_LOG_ALL, "monitor.log");
-#endif
- monitor_events (argc, argv);
+ signal (SIGINT, catch_int);
+ monitor_events (argc-argno, argv+argno);
exit (0);
}