]> Zhao Yanbai Git Server - minix.git/commitdiff
RS changes:
authorDavid van Moolenbroek <david@minix3.org>
Wed, 2 Dec 2009 09:54:50 +0000 (09:54 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 2 Dec 2009 09:54:50 +0000 (09:54 +0000)
- add new "control" config directive, to let drivers restart drivers
  (by Jorrit Herder)
- fix bug causing system processes to be started twice sometimes

include/minix/rs.h
servers/is/dmp_rs.c
servers/rs/inc.h
servers/rs/main.c
servers/rs/manager.c
servers/rs/manager.h
servers/rs/service.c

index c4fd652282694948ed7f3556ffe8243d04328bd9..c07807dbbe3e9748ec926f1400f8d882416d83b8 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef RS_H
+#define RS_H
+
 /*
 minix/rs.h
 
@@ -11,6 +14,14 @@ Interface to the reincarnation server
 #define RSS_NR_PCI_ID          32
 #define RSS_NR_PCI_CLASS        4
 #define RSS_NR_SYSTEM           2
+#define RSS_NR_CONTROL          8
+
+/* Labels are copied over separately. */
+struct rss_label
+{
+       char *l_addr;
+       size_t l_len;
+};
 
 /* Arguments needed to start a new driver or server */
 struct rs_start
@@ -33,12 +44,13 @@ struct rs_start
        int rss_nr_pci_class;
        struct { u32_t class; u32_t mask; } rss_pci_class[RSS_NR_PCI_CLASS];
        u32_t rss_system[RSS_NR_SYSTEM];
-       char *rss_label;
-       size_t rss_labellen;
+       struct rss_label rss_label;
        char *rss_ipc;
        size_t rss_ipclen;
 #define RSS_VM_CALL_SIZE BITMAP_CHUNKS(VM_NCALLS)
        bitchunk_t rss_vm[RSS_VM_CALL_SIZE];
+       int rss_nr_control;
+       struct rss_label rss_control[RSS_NR_CONTROL];
 };
 
 #define RF_COPY                0x01    /* Copy the brinary into RS to make it possible
@@ -64,3 +76,4 @@ struct rs_pci
 
 _PROTOTYPE( int minix_rs_lookup, (const char *name, endpoint_t *value));
 
+#endif
index 4b2904b2234fe384c9b865344623b1efab06f150..c3f738954c663f490d2cdc35f322dc228f871766 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "inc.h"
 #include <timers.h>
+#include <minix/rs.h>
 #include "../../kernel/priv.h"
 #include "../rs/manager.h"
 
index fe56dc6252f23d4021ccea8fdb33499f4c53fd4d..b4c6ee566b71526e546ff0e41a36abeab541a447 100644 (file)
@@ -25,6 +25,7 @@
 #include <minix/sysutil.h>
 #include <minix/keymap.h>
 #include <minix/bitmap.h>
+#include <minix/rs.h>
 
 #include <archtypes.h>
 #include <timers.h>                            /* For priv.h */
index d6e75219ff383b113f16d9d96d7f7f472f84a8c4..72174bc3c522a0cfcea3452b0bca3f2abfd0a141 100644 (file)
@@ -38,7 +38,6 @@ PUBLIC int main(void)
   int result;                                  /* result to return */
   sigset_t sigset;                             /* system signal set */
   int s;
-  uid_t euid;
 
   /* Initialize the server, then go to work. */
   init_server();       
@@ -73,8 +72,12 @@ PUBLIC int main(void)
              sig_handler();
               continue;                                
          default:                              /* heartbeat notification */
-             if (rproc_ptr[who_p] != NULL)     /* mark heartbeat time */ 
+             if (rproc_ptr[who_p] != NULL) {   /* mark heartbeat time */ 
                  rproc_ptr[who_p]->r_alive_tm = m.NOTIFY_TIMESTAMP;
+             } else {
+                 printf("Warning, RS got unexpected notify message from %d\n",
+                     m.m_source);
+             }
          }
       }
 
@@ -91,17 +94,7 @@ PUBLIC int main(void)
                continue;
          }
 
-         /* Only root can make calls to rs. unless it's RS_LOOKUP. */
-         euid= getnuid(m.m_source);
-         if (euid != 0 && call_nr != RS_LOOKUP)
-         {
-               printf("RS: got unauthorized request %d from endpoint %d\n",
-                       call_nr, m.m_source);
-               m.m_type = EPERM;
-               reply(who_e, &m);
-               continue;
-         }
-
+          /* Handler functions are responsible for permission checking. */
           switch(call_nr) {
           case RS_UP:          result = do_up(&m, FALSE, 0); break;
           case RS_UP_COPY:     result = do_up(&m, TRUE, 0); break;
index 20643b69f5713b15d6dc10f549425765390f240f..1528b2e0a900e2a22195eae04f74f488858712ae 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Changes:
+ *   Mar 02, 2009:     Extended isolation policies  (Jorrit N. Herder)
  *   Jul 22, 2005:     Created  (Jorrit N. Herder)
  */
 
@@ -15,7 +16,6 @@
 #include <minix/ds.h>
 #include <minix/endpoint.h>
 #include <minix/vm.h>
-#include <minix/rs.h>
 #include <lib.h>
 
 #include <timers.h>                            /* For priv.h */
@@ -26,6 +26,11 @@ struct rproc rproc[NR_SYS_PROCS];            /* system process table */
 struct rproc *rproc_ptr[NR_PROCS];             /* mapping for fast access */
 
 /* Prototypes for internal functions that do the hard work. */
+FORWARD _PROTOTYPE( int caller_is_root, (endpoint_t endpoint) );
+FORWARD _PROTOTYPE( int caller_can_control, (endpoint_t endpoint,
+       char *label) );
+FORWARD _PROTOTYPE( int copy_label, (endpoint_t src_e,
+       struct rss_label *src_label, char *dst_label, size_t dst_len) );
 FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags,
        endpoint_t *ep) );
 FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
@@ -48,7 +53,95 @@ PRIVATE int shutting_down = FALSE;
 extern int rs_verbose;
 
 /*===========================================================================*
- *                                     do_up                                *
+ *                             caller_is_root                               *
+ *===========================================================================*/
+PRIVATE int caller_is_root(endpoint)
+endpoint_t endpoint;                           /* caller endpoint */
+{
+  uid_t euid;
+
+  /* Check if caller has root user ID. */
+  euid = getnuid(endpoint);
+  if (rs_verbose && euid != 0)
+  {
+       printf("RS: got unauthorized request from endpoint %d\n", endpoint);
+  }
+  
+  return euid == 0;
+}
+
+/*===========================================================================*
+ *                             caller_can_control                           *
+ *===========================================================================*/
+PRIVATE int caller_can_control(endpoint, label)
+endpoint_t endpoint;
+char *label;
+{
+  int control_allowed = 0;
+  register struct rproc *rp;
+  int c;
+  char *progname;
+
+  /* Find name of binary for given label. */
+  for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
+       if (strcmp(rp->r_label, label) == 0) {
+               break;
+       }
+  }
+  if (rp == END_RPROC_ADDR) return 0;
+  progname = strrchr(rp->r_argv[0], '/');
+  if (progname != NULL)
+       progname++;
+  else
+       progname = rp->r_argv[0];
+
+  /* Check if label is listed in caller's isolation policy. */
+  for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
+       if (rp->r_proc_nr_e == endpoint) {
+               break;
+       }
+  }
+  if (rp == END_RPROC_ADDR) return 0;
+  if (rp->r_nr_control > 0) {
+       for (c = 0; c < rp->r_nr_control; c++) {
+               if (strcmp(rp->r_control[c], progname) == 0)
+                       control_allowed = 1;
+       }
+  }
+
+  if (rs_verbose) {
+       printf("RS: allowing %u control over %s via policy: %s\n",
+               endpoint, label, control_allowed ? "yes" : "no");
+  }
+  return control_allowed;
+}
+
+/*===========================================================================*
+ *                             copy_label                                   *
+ *===========================================================================*/
+PRIVATE int copy_label(src_e, src_label, dst_label, dst_len)
+endpoint_t src_e;
+struct rss_label *src_label;
+char *dst_label;
+size_t dst_len;
+{
+  int s, len;
+
+  len = MIN(dst_len-1, src_label->l_len);
+
+  s = sys_datacopy(src_e, (vir_bytes) src_label->l_addr,
+       SELF, (vir_bytes) dst_label, len);
+  if (s != OK) return s;
+
+  dst_label[len] = 0;
+
+  if (rs_verbose)
+       printf("RS: do_start: using label (custom) '%s'\n", dst_label);
+  return OK;
+}
+
+/*===========================================================================*
+ *                             do_up                                        *
  *===========================================================================*/
 PUBLIC int do_up(m_ptr, do_copy, flags)
 message *m_ptr;                                        /* request message pointer */
@@ -70,6 +163,9 @@ int flags;                                   /* extra flags, if any */
   int r;
   endpoint_t ep;                               /* new endpoint no. */
 
+  /* This call requires special privileges. */
+  if (!caller_is_root(m_ptr->m_source)) return(EPERM);
+
   /* See if there is a free entry in the table with system processes. */
   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
       rp = &rproc[slot_nr];                    /* get pointer to slot */
@@ -148,7 +244,7 @@ int flags;                                  /* extra flags, if any */
 
 
 /*===========================================================================*
- *                                     do_start                             *
+ *                             do_start                                     *
  *===========================================================================*/
 PUBLIC int do_start(m_ptr)
 message *m_ptr;                                        /* request message pointer */
@@ -169,10 +265,8 @@ message *m_ptr;                                    /* request message pointer */
   struct rproc *tmp_rp;
   struct rs_start rs_start;
 
-  /* Get the request structure */
-  s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, 
-       SELF, (vir_bytes) &rs_start, sizeof(rs_start));
-  if (s != OK) return(s);
+  /* This call requires special privileges. */
+  if (!caller_is_root(m_ptr->m_source)) return(EPERM);
 
   /* See if there is a free entry in the table with system processes. */
   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
@@ -186,6 +280,11 @@ message *m_ptr;                                    /* request message pointer */
        return ENOMEM;
   }
 
+  /* Ok, there is space. Get the request structure. */
+  s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, 
+       SELF, (vir_bytes) &rs_start, sizeof(rs_start));
+  if (s != OK) return(s);
+
   /* Obtain command name and parameters. This is a space-separated string
    * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
    */
@@ -215,15 +314,12 @@ message *m_ptr;                                   /* request message pointer */
   rp->r_argv[arg_count] = NULL;                        /* end with NULL pointer */
   rp->r_argc = arg_count;
 
-  if(rs_start.rss_label) {
-       int len;
+  if(rs_start.rss_label.l_len > 0) {
        /* RS_START caller has supplied a custom label for this driver. */
-       len = MIN(sizeof(rp->r_label)-1, rs_start.rss_labellen);
-        s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_label,
-               SELF, (vir_bytes) rp->r_label, len);
+       int s = copy_label(m_ptr->m_source, &rs_start.rss_label,
+               rp->r_label, sizeof(rp->r_label));
        if(s != OK)
                return s;
-       rp->r_label[len] = '\0';
         if(rs_verbose)
          printf("RS: do_start: using label (custom) '%s'\n", rp->r_label);
   } else {
@@ -243,6 +339,29 @@ message *m_ptr;                                    /* request message pointer */
                rp->r_argv[0], rp->r_label);
   }
 
+  if(rs_start.rss_nr_control > 0) {
+       int i, s;
+       if (rs_start.rss_nr_control > RSS_NR_CONTROL)
+       {
+               printf("RS: do_start: too many control labels\n");
+               return EINVAL;
+       }
+       for (i=0; i<rs_start.rss_nr_control; i++) {
+               s = copy_label(m_ptr->m_source, &rs_start.rss_control[i],
+                       rp->r_control[i], sizeof(rp->r_control[i]));
+               if(s != OK)
+                       return s;
+       }
+       rp->r_nr_control = rs_start.rss_nr_control;
+
+       if (rs_verbose) {
+               printf("RS: do_start: control labels:");
+               for (i=0; i<rp->r_nr_control; i++)
+                       printf(" %s", rp->r_control[i]);
+               printf("\n");
+       }
+  }
+
   /* Check for duplicates */
   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
       tmp_rp = &rproc[slot_nr];                        /* get pointer to slot */
@@ -349,7 +468,7 @@ message *m_ptr;                                     /* request message pointer */
 #endif
   }
 
-  if (rs_start.rss_nr_pci_id > MAX_NR_PCI_ID)
+  if (rs_start.rss_nr_pci_id > RSS_NR_PCI_ID)
   {
        printf("RS: do_start: too many PCI device IDs\n");
        return EINVAL;
@@ -363,7 +482,7 @@ message *m_ptr;                                     /* request message pointer */
           printf("RS: do_start: PCI %04x/%04x\n",
                rp->r_pci_id[i].vid, rp->r_pci_id[i].did);
   }
-  if (rs_start.rss_nr_pci_class > MAX_NR_PCI_CLASS)
+  if (rs_start.rss_nr_pci_class > RSS_NR_PCI_CLASS)
   {
        printf("RS: do_start: too many PCI class IDs\n");
        return EINVAL;
@@ -428,6 +547,9 @@ PUBLIC int do_down(message *m_ptr)
   int s, proc;
   char label[MAX_LABEL_LEN];
 
+  /* This call requires special privileges. */
+  if (!caller_is_root(m_ptr->m_source)) return(EPERM);
+
   len= m_ptr->RS_CMD_LEN;
   if (len >= sizeof(label))
        return EINVAL;          /* Too long */
@@ -487,6 +609,12 @@ PUBLIC int do_restart(message *m_ptr)
   if (s != OK) return(s);
   label[len]= '\0';
 
+  /* This call requires special privileges. */
+  if (! (caller_can_control(m_ptr->m_source, label) ||
+               caller_is_root(m_ptr->m_source))) {
+       return(EPERM);
+  }
+
   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
       if ((rp->r_flags & RS_IN_USE) && strcmp(rp->r_label, label) == 0) {
          if(rs_verbose) printf("RS: restarting '%s' (%d)\n", label, rp->r_pid);
@@ -530,6 +658,12 @@ PUBLIC int do_refresh(message *m_ptr)
   if (s != OK) return(s);
   label[len]= '\0';
 
+  /* This call requires special privileges. */
+  if (! (caller_can_control(m_ptr->m_source, label) ||
+               caller_is_root(m_ptr->m_source))) {
+       return(EPERM);
+  }
+
   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
       if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
 #if VERBOSE
@@ -550,6 +684,9 @@ PUBLIC int do_refresh(message *m_ptr)
  *===========================================================================*/
 PUBLIC int do_shutdown(message *m_ptr)
 {
+  /* This call requires special privileges. */
+  if (m_ptr != NULL && !caller_is_root(m_ptr->m_source)) return(EPERM);
+
   /* Set flag so that RS server knows services shouldn't be restarted. */
   shutting_down = TRUE;
   return(OK);
@@ -814,7 +951,7 @@ endpoint_t *endpoint;
 
   case 0:                                              /* child process */
       /* Try to execute the binary that has an absolute path. If this fails, 
-       * e.g., because the root file system cannot be read, try to strip of
+       * e.g., because the root file system cannot be read, try to strip off
        * the path, and see if the command is in RS' current working dir.
        */
       nice(rp->r_nice);                /* Nice before setuid, to allow negative
@@ -826,7 +963,7 @@ endpoint_t *endpoint;
       {
        execve(rp->r_argv[0], rp->r_argv, &null_env);   /* POSIX execute */
        file_only = strrchr(rp->r_argv[0], '/') + 1;
-       execve(file_only, rp->r_argv, &null_env);               /* POSIX execute */
+       execve(file_only, rp->r_argv, &null_env);       /* POSIX execute */
       }
       printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno);
       slot_nr= rp-rproc;
@@ -857,6 +994,7 @@ endpoint_t *endpoint;
   rp->r_check_tm = 0;                          /* not checked yet */
   getuptime(&rp->r_alive_tm);                  /* currently alive */
   rp->r_stop_tm = 0;                           /* not exiting yet */
+  rp->r_backoff = 0;                           /* not to be restarted */
   rproc_ptr[child_proc_nr_n] = rp;             /* mapping for fast access */
 
   /* If any of the calls below fail, the RS_EXITING flag is set. This implies
@@ -994,6 +1132,9 @@ message *m_ptr;
   size_t len;
   int s;
 
+  /* This call requires special privileges. */
+  if (!caller_is_root(m_ptr->m_source)) return(EPERM);
+
   switch(m_ptr->m1_i1) {
   case SI_PROC_TAB:
        src_addr = (vir_bytes) rproc;
@@ -1329,7 +1470,7 @@ struct priv *privp;
 
        src_bits_per_word= 8*sizeof(rp->r_call_mask[0]);
        dst_bits_per_word= 8*sizeof(privp->s_k_call_mask[0]);
-       for (src_word= 0; src_word < MAX_NR_SYSTEM; src_word++)
+       for (src_word= 0; src_word < RSS_NR_SYSTEM; src_word++)
        {
                for (src_bit= 0; src_bit < src_bits_per_word; src_bit++)
                {
index 8c64022b6325389cdadf44b8e49f7fdd837d12b7..2c21e6e7601a4897bb8cf99518fbbdb47ff0fda9 100644 (file)
@@ -12,9 +12,6 @@
 #define MAX_NR_ARGS          4         /* maximum number of arguments */
 #define MAX_RESCUE_DIR_LEN   64                /* maximum rescue dir length */
 
-#define MAX_NR_PCI_ID       32         /* maximum number of PCI device IDs */
-#define MAX_NR_PCI_CLASS      4                /* maximum number of PCI class IDs */
-#define MAX_NR_SYSTEM        2         /* should match RSS_NR_SYSTEM */
 #define MAX_IPC_LIST       256         /* Max size of list for IPC target
                                         * process names
                                         */
@@ -56,14 +53,15 @@ extern struct rproc {
   uid_t r_uid;
   int r_nice;
   int r_nr_pci_id;             /* Number of PCI devices IDs */
-  struct { u16_t vid; u16_t did; } r_pci_id[MAX_NR_PCI_ID];
+  struct { u16_t vid; u16_t did; } r_pci_id[RSS_NR_PCI_ID];
   int r_nr_pci_class;          /* Number of PCI class IDs */
-  struct { u32_t class; u32_t mask; } r_pci_class[MAX_NR_PCI_CLASS];
+  struct { u32_t class; u32_t mask; } r_pci_class[RSS_NR_PCI_CLASS];
 
-  u32_t r_call_mask[MAX_NR_SYSTEM];
+  u32_t r_call_mask[RSS_NR_SYSTEM];
   char r_ipc_list[MAX_IPC_LIST];
-#define R_VM_CALL_SIZE BITMAP_CHUNKS(VM_NCALLS)
-  bitchunk_t r_vm[R_VM_CALL_SIZE];
+  bitchunk_t r_vm[RSS_VM_CALL_SIZE];
+  int r_nr_control;
+  char r_control[RSS_NR_CONTROL][MAX_LABEL_LEN];
 } rproc[NR_SYS_PROCS];
 
 /* Mapping for fast access to the system process table. */ 
index 2e787200729795c1a5861fe4c3af064dd8db7a49..80c66e87239fe15c7b98f143b1f4be0721568ad3 100644 (file)
@@ -336,6 +336,7 @@ PRIVATE void fatal(char *fmt, ...)
 #define KW_SYSTEM      "system"
 #define KW_IPC         "ipc"
 #define KW_VM          "vm"
+#define KW_CONTROL     "control"
 
 FORWARD void do_driver(config_t *cpe, config_t *config);
 
@@ -370,27 +371,27 @@ PRIVATE void do_class(config_t *cpe, config_t *config)
                {
                        if (!(cp->flags & CFG_SUBLIST))
                        {
-                               fatal("do_class: expected list at %s:%d\n",
+                               fatal("do_class: expected list at %s:%d",
                                        cp->file, cp->line);
                        }
                        cp1= cp->list;
                        if ((cp1->flags & CFG_STRING) ||
                                (cp1->flags & CFG_SUBLIST))
                        {
-                               fatal("do_class: expected word at %s:%d\n",
+                               fatal("do_class: expected word at %s:%d",
                                        cp1->file, cp1->line);
                        }
 
                        /* At this place we expect the word 'driver' */
                        if (strcmp(cp1->word, KW_DRIVER) != 0)
-                               fatal("do_class: exected word '%S' at %s:%d\n",
+                               fatal("do_class: exected word '%S' at %s:%d",
                                        KW_DRIVER, cp1->file, cp1->line);
 
                        cp1= cp1->next;
                        if ((cp1->flags & CFG_STRING) ||
                                (cp1->flags & CFG_SUBLIST))
                        {
-                               fatal("do_class: expected word at %s:%d\n",
+                               fatal("do_class: expected word at %s:%d",
                                        cp1->file, cp1->line);
                        }
 
@@ -401,7 +402,7 @@ PRIVATE void do_class(config_t *cpe, config_t *config)
                if (cp == NULL)
                {
                        fatal(
-                       "do_class: no entry found for class '%s' at %s:%d\n",
+                       "do_class: no entry found for class '%s' at %s:%d",
                                cpe->word, cpe->file, cpe->line);
                }
                do_driver(cp1->next, config);
@@ -838,7 +839,7 @@ PRIVATE void do_system(config_t *cpe)
                if (call_nr < KERNEL_CALL)
                {
                        fatal(
-               "do_system: bad call number %d in system tab for '%s'\n",
+               "do_system: bad call number %d in system tab for '%s'",
                                call_nr, system_tab[i].label);
                }
                call_nr -= KERNEL_CALL;
@@ -849,13 +850,43 @@ PRIVATE void do_system(config_t *cpe)
                if (word >= RSS_NR_SYSTEM)
                {
                        fatal(
-                       "do_system: RSS_NR_SYSTEM is too small (%d needed)\n",
+                       "do_system: RSS_NR_SYSTEM is too small (%d needed)",
                                word+1);
                }
                rs_start.rss_system[word] |= mask;
        }
 }
 
+PRIVATE void do_control(config_t *cpe)
+{
+       int nr_control = 0;
+
+       /* Process a list of 'control' labels. */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_control: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_control: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (nr_control >= RSS_NR_CONTROL)
+               {
+                       fatal(
+                       "do_control: RSS_NR_CONTROL is too small (%d needed)",
+                               nr_control+1);
+               }
+
+               rs_start.rss_control[nr_control].l_addr = cpe->word;
+               rs_start.rss_control[nr_control].l_len = strlen(cpe->word);
+               rs_start.rss_nr_control = ++nr_control;
+       }
+}
+
 PRIVATE void do_driver(config_t *cpe, config_t *config)
 {
        config_t *cp;
@@ -865,13 +896,13 @@ PRIVATE void do_driver(config_t *cpe, config_t *config)
         */
        if (!(cpe->flags & CFG_SUBLIST))
        {
-               fatal("do_driver: expected list at %s:%d\n",
+               fatal("do_driver: expected list at %s:%d",
                        cpe->file, cpe->line);
        }
        if (cpe->next != NULL)
        {
                cpe= cpe->next;
-               fatal("do_driver: expected end of list at %s:%d\n",
+               fatal("do_driver: expected end of list at %s:%d",
                        cpe->file, cpe->line);
        }
        cpe= cpe->list;
@@ -881,13 +912,13 @@ PRIVATE void do_driver(config_t *cpe, config_t *config)
        {
                if (!(cp->flags & CFG_SUBLIST))
                {
-                       fatal("do_driver: expected list at %s:%d\n",
+                       fatal("do_driver: expected list at %s:%d",
                                cp->file, cp->line);
                }
                cpe= cp->list;
                if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
                {
-                       fatal("do_driver: expected word at %s:%d\n",
+                       fatal("do_driver: expected word at %s:%d",
                                cpe->file, cpe->line);
                }
 
@@ -936,7 +967,11 @@ PRIVATE void do_driver(config_t *cpe, config_t *config)
                        do_vm(cpe->next);
                        continue;
                }
-
+               if (strcmp(cpe->word, KW_CONTROL) == 0)
+               {
+                       do_control(cpe->next);
+                       continue;
+               }
        }
 }
 
@@ -957,25 +992,25 @@ PRIVATE void do_config(char *label, char *filename)
        {
                if (!(cp->flags & CFG_SUBLIST))
                {
-                       fatal("do_config: expected list at %s:%d\n",
+                       fatal("do_config: expected list at %s:%d",
                                cp->file, cp->line);
                }
                cpe= cp->list;
                if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
                {
-                       fatal("do_config: expected word at %s:%d\n",
+                       fatal("do_config: expected word at %s:%d",
                                cpe->file, cpe->line);
                }
 
                /* At this place we expect the word 'driver' */
                if (strcmp(cpe->word, KW_DRIVER) != 0)
-                       fatal("do_config: exected word '%S' at %s:%d\n",
+                       fatal("do_config: exected word '%S' at %s:%d",
                                KW_DRIVER, cpe->file, cpe->line);
 
                cpe= cpe->next;
                if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
                {
-                       fatal("do_config: expected word at %s:%d\n",
+                       fatal("do_config: expected word at %s:%d",
                                cpe->file, cpe->line);
                }
 
@@ -987,7 +1022,7 @@ PRIVATE void do_config(char *label, char *filename)
        {
                fprintf(stderr, "service: driver '%s' not found in config\n",
                        label);
-               return;
+               exit(1);
        }
 
        cpe= cpe->next;
@@ -1052,11 +1087,11 @@ PUBLIC int main(int argc, char **argv)
       rs_start.rss_period= req_period;
       rs_start.rss_script= req_script;
       if(req_label) {
-       rs_start.rss_label = req_label;
-       rs_start.rss_labellen = strlen(req_label);
+        rs_start.rss_label.l_addr = req_label;
+        rs_start.rss_label.l_len = strlen(req_label);
       } else {
-        rs_start.rss_label = progname;
-        rs_start.rss_labellen = strlen(progname);
+        rs_start.rss_label.l_addr = progname;
+        rs_start.rss_label.l_len = strlen(progname);
       }
       if (req_script)
              rs_start.rss_scriptlen= strlen(req_script);