Lots of changes. They aren't visible though.
[egate.git] / kernel / monitor.c
index 405369b..d557979 100644 (file)
@@ -1,8 +1,85 @@
+/*
+ * 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;
@@ -54,8 +132,13 @@ static int no_process = 0;
 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)
@@ -67,19 +150,26 @@ static void reread_resources (void)
                 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;
@@ -93,6 +183,7 @@ struct ke_info *ke_info_add (int id)
     (*kip)->id = id;
     (*kip)->gip = NULL;
     (*kip)->queue = NULL;
+    (*kip)->stopped = 0;
     return *kip;
 }
 
@@ -107,6 +198,10 @@ static void ke_info_del (void)
     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;
@@ -122,23 +217,48 @@ static void catch_child (int num)
     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;
@@ -175,6 +295,27 @@ static pid_t start_kernel (int argc, char **argv, int id)
     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)
 {
@@ -197,68 +338,73 @@ static int deliver (int argc, char **argv, int id, struct str_queue *queue,
     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;
@@ -279,17 +425,58 @@ static void monitor_events (int argc, char **argv)
                 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);
@@ -302,14 +489,15 @@ static void monitor_events (int argc, char **argv)
                 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)
@@ -324,12 +512,14 @@ static void monitor_events (int argc, char **argv)
             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)
        {
@@ -349,10 +539,12 @@ static void monitor_events (int argc, char **argv)
                         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))
        {
@@ -392,6 +584,9 @@ static void monitor_events (int argc, char **argv)
     }
 }
 
+/*
+ * main: main of monitor
+ */
 int main (int argc, char **argv)
 {
     int argno = 0;
@@ -401,20 +596,44 @@ int main (int argc, char **argv)
     {
         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
@@ -424,9 +643,7 @@ int main (int argc, char **argv)
     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);
 }