]> Zhao Yanbai Git Server - minix.git/commitdiff
(Incomplete) support for access control in PCI (pci_set_acl).
authorPhilip Homburg <philip@cs.vu.nl>
Fri, 20 Oct 2006 15:01:32 +0000 (15:01 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Fri, 20 Oct 2006 15:01:32 +0000 (15:01 +0000)
-script argument to service for crash recovery scripts
-config argument to service for driver resource configuration
restart command in service to restart a driver after a crash (for use in
crash recovery scripts).
down and refresh now take labels instead of pids.
verious changes in rs to make this work.

14 files changed:
drivers/pci/main.c
drivers/pci/pci.c
drivers/pci/pci.h
include/minix/com.h
include/minix/rs.h [new file with mode: 0644]
include/minix/syslib.h
lib/syslib/Makefile.in
lib/syslib/pci_set_acl.c [new file with mode: 0644]
servers/rs/inc.h
servers/rs/main.c
servers/rs/manager.c
servers/rs/manager.h
servers/rs/proto.h
servers/rs/service.c

index be1b0ca29f8a8417459c7cc8d8836e5e7b2ef384..1c4b8066ff7fcdeaf2824448515698871196f11d 100644 (file)
@@ -5,6 +5,7 @@ main.c
 #include "../drivers.h"
 
 #include <ibm/pci.h>
+#include <minix/rs.h>
 
 #include "pci.h"
 
@@ -16,6 +17,12 @@ PRIVATE struct name
        int tasknr;
 } names[NR_DRIVERS];
 
+PRIVATE struct acl
+{
+       int inuse;
+       struct rs_pci acl;
+} acl[NR_DRIVERS];
+
 FORWARD _PROTOTYPE( void do_init, (message *mp)                                );
 FORWARD _PROTOTYPE( void do_sig_handler, (void)                                );
 FORWARD _PROTOTYPE( void do_first_dev, (message *mp)                   );
@@ -26,6 +33,7 @@ FORWARD _PROTOTYPE( void do_dev_name, (message *mp)                   );
 FORWARD _PROTOTYPE( void do_dev_name_s, (message *mp)                  );
 FORWARD _PROTOTYPE( void do_slot_name, (message *mp)                   );
 FORWARD _PROTOTYPE( void do_slot_name_s, (message *mp)                 );
+FORWARD _PROTOTYPE( void do_acl, (message *mp)                         );
 FORWARD _PROTOTYPE( void do_reserve, (message *mp)                     );
 FORWARD _PROTOTYPE( void do_attr_r8, (message *mp)                     );
 FORWARD _PROTOTYPE( void do_attr_r16, (message *mp)                    );
@@ -34,6 +42,8 @@ FORWARD _PROTOTYPE( void do_attr_w8, (message *mp)                    );
 FORWARD _PROTOTYPE( void do_attr_w16, (message *mp)                    );
 FORWARD _PROTOTYPE( void do_attr_w32, (message *mp)                    );
 FORWARD _PROTOTYPE( void do_rescan_bus, (message *mp)                  );
+FORWARD _PROTOTYPE( void reply, (message *mp, int result)              );
+FORWARD _PROTOTYPE( struct rs_pci *find_acl, (int endpoint)            );
 
 int main(void)
 {
@@ -72,6 +82,7 @@ int main(void)
                case BUSC_PCI_RESCAN: do_rescan_bus(&m); break;
                case BUSC_PCI_DEV_NAME_S: do_dev_name_s(&m); break;
                case BUSC_PCI_SLOT_NAME_S: do_slot_name_s(&m); break;
+               case BUSC_PCI_ACL: do_acl(&m); break;
                case PROC_EVENT: do_sig_handler(); break;
                default:
                        printf("PCI: got message from %d, type %d\n",
@@ -140,10 +151,16 @@ message *mp;
 PRIVATE void do_first_dev(mp)
 message *mp;
 {
-       int r, devind;
+       int i, r, devind;
        u16_t vid, did;
+       struct rs_pci *aclp;
+
+       aclp= find_acl(mp->m_source);
+
+       if (!aclp)
+               printf("do_first_dev: no acl for caller %d\n", mp->m_source);
 
-       r= pci_first_dev(&devind, &vid, &did);
+       r= pci_first_dev_a(aclp, &devind, &vid, &did);
        if (r == 1)
        {
                mp->m1_i1= devind;
@@ -164,10 +181,12 @@ message *mp;
 {
        int r, devind;
        u16_t vid, did;
+       struct rs_pci *aclp;
 
        devind= mp->m1_i1;
+       aclp= find_acl(mp->m_source);
 
-       r= pci_next_dev(&devind, &vid, &did);
+       r= pci_next_dev_a(aclp, &devind, &vid, &did);
        if (r == 1)
        {
                mp->m1_i1= devind;
@@ -354,6 +373,48 @@ message *mp;
        }
 }
 
+PRIVATE void do_acl(mp)
+message *mp;
+{
+       int i, r, gid;
+
+       if (mp->m_source != RS_PROC_NR)
+       {
+printf("do_acl: not from RS\n");
+               reply(mp, EPERM);
+               return;
+       }
+
+       for (i= 0; i<NR_DRIVERS; i++)
+       {
+               if (!acl[i].inuse)
+                       break;
+       }
+       if (i >= NR_DRIVERS)
+       {
+printf("do_acl: table is full\n");
+               reply(mp, ENOMEM);
+               return;
+       }
+
+       gid= mp->m1_i1;
+
+       r= sys_safecopyfrom(mp->m_source, gid, 0, (vir_bytes)&acl[i].acl,
+               sizeof(acl[i].acl), D);
+       if (r != OK)
+       {
+printf("do_acl: safecopyfrom failed\n");
+               reply(mp, r);
+               return;
+       }
+       acl[i].inuse= 1;
+       printf("do_acl: setting ACL for %d ('%s') at entry %d\n",
+               acl[i].acl.rsp_endpoint, acl[i].acl.rsp_label,
+               i);
+
+       reply(mp, OK);
+}
+
 PRIVATE void do_reserve(mp)
 message *mp;
 {
@@ -521,3 +582,33 @@ message *mp;
        }
 }
 
+
+PRIVATE void reply(mp, result)
+message *mp;
+int result;
+{
+       int r;
+       message m;
+
+       m.m_type= result;
+       r= send(mp->m_source, &m);
+       if (r != 0)
+               printf("reply: unable to send to %d: %d\n", mp->m_source, r);
+}
+
+
+PRIVATE struct rs_pci *find_acl(endpoint)
+int endpoint;
+{
+       int i;
+
+       /* Find ACL entry for caller */
+       for (i= 0; i<NR_DRIVERS; i++)
+       {
+               if (!acl[i].inuse)
+                       continue;
+               if (acl[i].acl.rsp_endpoint == endpoint)
+                       return &acl[i].acl;
+       }
+       return NULL;
+}
index 7ef90f9c2721eb56805702799b953b2fb078f25d..b4bd7b5c858c914d8ff6ac724f800e083f2945e7 100644 (file)
@@ -13,6 +13,7 @@ Created:      Jan 2000 by Philip Homburg <philip@cs.vu.nl>
 #include <ibm/pci.h>
 #include <sys/vm.h>
 #include <minix/com.h>
+#include <minix/rs.h>
 #include <minix/syslib.h>
 
 #include "pci.h"
@@ -146,6 +147,7 @@ FORWARD _PROTOTYPE( void pcii_wreg32, (int busind, int devind, int port,
 FORWARD _PROTOTYPE( u16_t pcii_rsts, (int busind)                      );
 FORWARD _PROTOTYPE( void pcii_wsts, (int busind, U16_t value)          );
 FORWARD _PROTOTYPE( void print_capabilities, (int devind)              );
+FORWARD _PROTOTYPE( int visible, (struct rs_pci *aclp, int devind)     );
 
 /*===========================================================================*
  *                     helper functions for I/O                             *
@@ -248,19 +250,23 @@ int *devindp;
 }
 
 /*===========================================================================*
- *                             pci_first_dev                                *
+ *                             pci_first_dev_a                              *
  *===========================================================================*/
-PUBLIC int pci_first_dev(devindp, vidp, didp)
+PUBLIC int pci_first_dev_a(aclp, devindp, vidp, didp)
+struct rs_pci *aclp;
 int *devindp;
 u16_t *vidp;
 u16_t *didp;
 {
-       int devind;
+       int i, devind;
 
        for (devind= 0; devind < nr_pcidev; devind++)
        {
-               if (!pcidev[devind].pd_inuse)
-                       break;
+               if (pcidev[devind].pd_inuse)
+                       continue;
+               if (!visible(aclp, devind))
+                       continue;
+               break;
        }
        if (devind >= nr_pcidev)
                return 0;
@@ -273,7 +279,8 @@ u16_t *didp;
 /*===========================================================================*
  *                             pci_next_dev                                 *
  *===========================================================================*/
-PUBLIC int pci_next_dev(devindp, vidp, didp)
+PUBLIC int pci_next_dev_a(aclp, devindp, vidp, didp)
+struct rs_pci *aclp;
 int *devindp;
 u16_t *vidp;
 u16_t *didp;
@@ -282,8 +289,11 @@ u16_t *didp;
 
        for (devind= *devindp+1; devind < nr_pcidev; devind++)
        {
-               if (!pcidev[devind].pd_inuse)
-                       break;
+               if (pcidev[devind].pd_inuse)
+                       continue;
+               if (!visible(aclp, devind))
+                       continue;
+               break;
        }
        if (devind >= nr_pcidev)
                return 0;
@@ -2428,6 +2438,48 @@ int devind;
        }
 }
 
+
+/*===========================================================================*
+ *                             visible                                      *
+ *===========================================================================*/
+PRIVATE int visible(aclp, devind)
+struct rs_pci *aclp;
+int devind;
+{
+       int i;
+       u32_t class_id;
+
+       if (!aclp)
+               return TRUE;    /* Should be changed when ACLs become
+                                * mandatory.
+                                */
+       /* Check whether the caller is allowed to get this device. */
+       for (i= 0; i<aclp->rsp_nr_device; i++)
+       {
+               if (aclp->rsp_device[i].vid == pcidev[devind].pd_vid &&
+                       aclp->rsp_device[i].did == pcidev[devind].pd_did)
+               {
+                       return TRUE;
+               }
+       }
+       if (!aclp->rsp_nr_class)
+               return FALSE;
+
+       class_id= (pcidev[devind].pd_baseclass << 16) |
+               (pcidev[devind].pd_subclass << 8) |
+               pcidev[devind].pd_infclass;
+       for (i= 0; i<aclp->rsp_nr_class; i++)
+       {
+               if (aclp->rsp_class[i].class ==
+                       (class_id & aclp->rsp_class[i].mask))
+               {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
 /*
  * $PchId: pci.c,v 1.7 2003/08/07 09:06:51 philip Exp $
  */
index 5a56fffbaeb4a3f69478a4515590d462a42da9f1..898090484a383dd78cf8f0d2a370643f6d21ee72 100644 (file)
@@ -84,6 +84,10 @@ extern struct pci_pcibridge pci_pcibridge[];
 /* Utility functions */
 _PROTOTYPE( void pci_reserve3, (int devind, int proc, char name[M3_STRING]));
 _PROTOTYPE( void pci_release, (char name[M3_STRING])                   );
+_PROTOTYPE( int pci_first_dev_a, (struct rs_pci *aclp, int *devindp,
+                                       u16_t *vidp, u16_t *didp)       );
+_PROTOTYPE( int pci_next_dev_a, (struct rs_pci *aclp, int *devindp,
+                                       u16_t *vidp, u16_t *didp)       );
 
 /*
  * $PchId: pci.h,v 1.4 2001/12/06 20:21:22 philip Exp $
index 1705d128b776ac8f48d1fb96852a56aa5d2b6d66..b143cf1d0bdbb708edcd7fa26c0f8e1e3d730636 100755 (executable)
 #define BUSC_PCI_SLOT_NAME_S   (BUSC_RQ_BASE + 16)     /* Get the name of a
                                                         * PCI slot (safecopy)
                                                         */
+#define BUSC_PCI_ACL           (BUSC_RQ_BASE + 17)     /* Set the ACL for a
+                                                        * driver (safecopy)
+                                                        */
 
 /*===========================================================================*
  *                Messages for BLOCK and CHARACTER device drivers           *
 
 #define RS_UP          (RS_RQ_BASE + 0)        /* start system service */
 #define RS_DOWN                (RS_RQ_BASE + 1)        /* stop system service */
-#define RS_REFRESH     (RS_RQ_BASE + 2)        /* restart system service */
-#define RS_RESCUE      (RS_RQ_BASE + 3)        /* set rescue directory */
-#define RS_SHUTDOWN    (RS_RQ_BASE + 4)        /* alert about shutdown */
-#define RS_UP_COPY     (RS_RQ_BASE + 5)        /* start system service and
+#define RS_REFRESH     (RS_RQ_BASE + 2)        /* refresh system service */
+#define RS_RESTART     (RS_RQ_BASE + 3)        /* restart system service */
+#define RS_RESCUE      (RS_RQ_BASE + 4)        /* set rescue directory */
+#define RS_SHUTDOWN    (RS_RQ_BASE + 5)        /* alert about shutdown */
+#define RS_UP_COPY     (RS_RQ_BASE + 6)        /* start system service and
                                                 * keep the binary in memory
                                                 */
-#define RS_RUN         (RS_RQ_BASE + 6)        /* run without restart */
+#define RS_RUN         (RS_RQ_BASE + 7)        /* run without restart */
+#define RS_START       (RS_RQ_BASE + 8)        /* start a driver/service
+                                                * arguments are passed in 
+                                                * a struct rs_start
+                                                */
 
 #  define RS_CMD_ADDR          m1_p1           /* command string */
 #  define RS_CMD_LEN           m1_i1           /* length of command */
diff --git a/include/minix/rs.h b/include/minix/rs.h
new file mode 100644 (file)
index 0000000..371d871
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+minix/rs.h
+
+Interface to the reincarnation server
+*/
+
+#define RSS_NR_IRQ             16
+#define RSS_NR_IO              16
+#define RSS_NR_PCI_ID          16
+#define RSS_NR_PCI_CLASS        4
+#define RSS_NR_SYSTEM           2
+
+/* Arguments needed to start a new driver or server */
+struct rs_start
+{
+       unsigned rss_flags;
+       char *rss_cmd;
+       size_t rss_cmdlen;
+       uid_t rss_uid;
+       int rss_nice;
+       int rss_major;
+       long rss_period;
+       char *rss_script;
+       size_t rss_scriptlen;
+       int rss_nr_irq;
+       int rss_irq[RSS_NR_IRQ];
+       int rss_nr_io;
+       struct { unsigned base; unsigned len; } rss_io[RSS_NR_IO];
+       int rss_nr_pci_id;
+       struct { u16_t vid; u16_t did; } rss_pci_id[RSS_NR_PCI_ID];
+       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];
+};
+
+#define RF_COPY                0x01    /* Copy the brinary into RS to make it possible
+                                * to restart the driver without accessing FS
+                                */
+
+#define RSP_LABEL_SIZE 16
+#define RSP_NR_DEVICE  16
+#define RSP_NR_CLASS    4
+
+/* ACL information for access to PCI devices */
+struct rs_pci
+{
+       char rsp_label[RSP_LABEL_SIZE];         /* Name of the driver */
+       int rsp_endpoint;
+       int rsp_nr_device;
+       struct { u16_t vid; u16_t did; } rsp_device[RSP_NR_DEVICE];
+       int rsp_nr_class;
+       struct { u32_t class; u32_t mask; } rsp_class[RSP_NR_CLASS];
+};
index 2d04987fe5a71eb0f4993da6ab4b798a56441ce6..4ae273c304c0a30aa3f1df87a93147af567ccfac 100755 (executable)
@@ -19,6 +19,7 @@
 
 /* Forward declaration */
 struct reg86u;
+struct rs_pci;
 
 #define SYSTASK SYSTEM
 
@@ -194,6 +195,7 @@ _PROTOTYPE( void pci_attr_w16, (int devind, int port, U16_t value)  );
 _PROTOTYPE( void pci_attr_w32, (int devind, int port, u32_t value)     );
 _PROTOTYPE( char *pci_dev_name, (U16_t vid, U16_t did)                 );
 _PROTOTYPE( char *pci_slot_name, (int devind)                          );
+_PROTOTYPE( int pci_set_acl, (struct rs_pci *rs_pci)                   );
 
 #endif /* _SYSLIB_H */
 
index 63c0b14e3214cd20f68e2112232cf9937d32b389..48aeb2ae3d510b1c55da3c2ca1c109dc2d44ace4 100644 (file)
@@ -22,6 +22,7 @@ libsys_FILES=" \
        pci_next_dev.c \
        pci_rescan_bus.c \
        pci_reserve.c \
+       pci_set_acl.c \
        pci_slot_name.c \
        safecopies.c \
        sys_abort.c \
diff --git a/lib/syslib/pci_set_acl.c b/lib/syslib/pci_set_acl.c
new file mode 100644 (file)
index 0000000..b9f2082
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+pci_set_acl.c
+*/
+
+#include "pci.h"
+#include "syslib.h"
+#include <minix/rs.h>
+#include <minix/sysutil.h>
+
+/*===========================================================================*
+ *                             pci_set_acl                                  *
+ *===========================================================================*/
+PUBLIC int pci_set_acl(rs_pci)
+struct rs_pci *rs_pci;
+{
+       int r;
+       cp_grant_id_t gid;
+       message m;
+
+       if (pci_procnr == ANY)
+       {
+               r= _pm_findproc("pci", &pci_procnr);
+               if (r != 0)
+               {
+                       panic("pci",
+                               "pci_set_acl: _pm_findproc failed for 'pci'",
+                               r);
+               }
+       }
+
+
+printf("pci_set_acl: before cpf_grant_direct\n");
+       gid= cpf_grant_direct(pci_procnr, (vir_bytes)rs_pci, sizeof(*rs_pci),
+               CPF_READ);
+printf("pci_set_acl: after cpf_grant_direct: gid %d\n", gid);
+       if (gid == -1)
+       {
+               printf("pci_set_acl: cpf_grant_direct failed: %d\n",
+                       errno);
+               return EINVAL;
+       }
+
+       m.m_type= BUSC_PCI_ACL;
+       m.m1_i1= gid;
+
+printf("pci_set_acl: before sendrec to %d\n", pci_procnr);
+       r= sendrec(pci_procnr, &m);
+printf("pci_set_acl: after sendrec to %d\n", pci_procnr);
+       cpf_revoke(gid);
+printf("pci_set_acl: after cpf_revoke\n");
+       if (r != 0)
+               panic("pci", "pci_set_acl: can't talk to PCI", r);
+
+       return r;
+}
+
index 6248046faf25af6eed0f71fd09e059fc4885cd81..78407500cec92c0950946cb3786c403f21068316 100644 (file)
@@ -26,6 +26,9 @@
 #include <minix/keymap.h>
 #include <minix/bitmap.h>
 
+#include <timers.h>                            /* For priv.h */
+#include "../../kernel/priv.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
index 2e75aa12baadd5944af21dd88a2973fdacf4e7ef..140423bfec873502fb2975b26f1660e4e3fa19de 100644 (file)
@@ -84,9 +84,11 @@ PUBLIC int main(void)
           case RS_UP:          result = do_up(&m, FALSE, 0); break;
           case RS_UP_COPY:     result = do_up(&m, TRUE, 0); break;
          case RS_RUN:          result = do_up(&m, FALSE, RS_EXITING);  break;
+         case RS_START:        result = do_start(&m);          break;
           case RS_DOWN:        result = do_down(&m);           break;
           case RS_REFRESH:     result = do_refresh(&m);        break;
           case RS_RESCUE:      result = do_rescue(&m);         break;
+          case RS_RESTART:     result = do_restart(&m);        break;
           case RS_SHUTDOWN:    result = do_shutdown(&m);       break;
           case GETSYSINFO:     result = do_getsysinfo(&m);     break;
           default: 
index 506825eb562cecd07161366a9d24155ab50dca56..048da7ab646e06410e83f802138290964de509c0 100644 (file)
 #include <sys/wait.h>
 #include <minix/dmap.h>
 #include <minix/endpoint.h>
+#include <minix/rs.h>
 #include <lib.h>
 
+#include <timers.h>                            /* For priv.h */
+#include "../../kernel/priv.h"
+
 /* Allocate variables. */
 struct rproc rproc[NR_SYS_PROCS];              /* system process table */
 struct rproc *rproc_ptr[NR_PROCS];             /* mapping for fast access */
@@ -24,6 +28,9 @@ FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags) );
 FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
 FORWARD _PROTOTYPE( int fork_nb, (void) );
 FORWARD _PROTOTYPE( int read_exec, (struct rproc *rp) );
+FORWARD _PROTOTYPE( void run_script, (struct rproc *rp) );
+FORWARD _PROTOTYPE( void init_privs, (struct rproc *rp, struct priv *privp) );
+FORWARD _PROTOTYPE( void init_pci, (struct rproc *rp, int endpoint) );
 
 PRIVATE int shutting_down = FALSE;
 
@@ -45,8 +52,10 @@ int flags;                                   /* extra flags, if any */
   int slot_nr;                                 /* local table entry */
   int arg_count;                               /* number of arguments */
   char *cmd_ptr;                               /* parse command string */
+  char *label;                                 /* unique name of command */
   enum dev_style dev_style;                    /* device style */
   int s;                                       /* status variable */
+  int len;                                     /* length of string */
 
   /* See if there is a free entry in the table with system processes. */
   if (nr_in_use >= NR_SYS_PROCS) return(EAGAIN); 
@@ -66,6 +75,8 @@ int flags;                                    /* extra flags, if any */
   rp->r_cmd[m_ptr->RS_CMD_LEN] = '\0';         /* ensure it is terminated */
   if (rp->r_cmd[0] != '/') return(EINVAL);     /* insist on absolute path */
 
+  rp->r_script[0]= '\0';
+
   /* Build argument vector to be passed to execute call. The format of the
    * arguments vector is: path, arguments, NULL. 
    */
@@ -85,6 +96,22 @@ int flags;                                   /* extra flags, if any */
   rp->r_argv[arg_count] = NULL;                        /* end with NULL pointer */
   rp->r_argc = arg_count;
 
+  /* Default label for the driver */
+  label= strrchr(rp->r_argv[0], '/');
+  if (label)
+       label++;
+  else
+       label= rp->r_argv[0];
+  len= strlen(label);
+  if (len > MAX_LABEL_LEN-1)
+       len= MAX_LABEL_LEN-1;   /* truncate name */
+  memcpy(rp->r_label, label, len);
+  rp->r_label[len]= '\0';
+  printf("using label '%s'\n", rp->r_label);
+
+  rp->r_uid= 0;
+  rp->r_nice= 0;
+
   rp->r_exec= NULL;
   if (do_copy)
   {
@@ -98,31 +125,291 @@ int flags;                                        /* extra flags, if any */
   rp->r_dev_nr = m_ptr->RS_DEV_MAJOR;
   rp->r_dev_style = STYLE_DEV; 
   rp->r_restarts = -1;                                 /* will be incremented */
+  rp->r_set_resources= 0;                      /* old style */
   
   /* All information was gathered. Now try to start the system service. */
   return(start_service(rp, flags));
 }
 
 
+/*===========================================================================*
+ *                                     do_start                             *
+ *===========================================================================*/
+PUBLIC int do_start(m_ptr)
+message *m_ptr;                                        /* request message pointer */
+{
+/* A request was made to start a new system service. 
+ */
+  register struct rproc *rp;                   /* system process table */
+  int slot_nr;                                 /* local table entry */
+  int arg_count;                               /* number of arguments */
+  char *cmd_ptr;                               /* parse command string */
+  char *label;                                 /* unique name of command */
+  enum dev_style dev_style;                    /* device style */
+  int s;                                       /* status variable */
+  int len;                                     /* length of string */
+  int i;
+  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);
+
+  /* See if there is a free entry in the table with system processes. */
+  if (nr_in_use >= NR_SYS_PROCS) return(EAGAIN); 
+  for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+      rp = &rproc[slot_nr];                    /* get pointer to slot */
+      if (! rp->r_flags & RS_IN_USE)           /* check if available */
+         break;
+  }
+  nr_in_use ++;                                        /* update administration */
+
+  /* Obtain command name and parameters. This is a space-separated string
+   * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
+   */
+  if (rs_start.rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG);
+  s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_cmd, 
+       SELF, (vir_bytes) rp->r_cmd, rs_start.rss_cmdlen);
+  if (s != OK) return(s);
+  rp->r_cmd[rs_start.rss_cmdlen] = '\0';       /* ensure it is terminated */
+  if (rp->r_cmd[0] != '/') return(EINVAL);     /* insist on absolute path */
+
+  /* Build argument vector to be passed to execute call. The format of the
+   * arguments vector is: path, arguments, NULL. 
+   */
+  arg_count = 0;                               /* initialize arg count */
+  rp->r_argv[arg_count++] = rp->r_cmd;         /* start with path */
+  cmd_ptr = rp->r_cmd;                         /* do some parsing */ 
+  while(*cmd_ptr != '\0') {                    /* stop at end of string */
+      if (*cmd_ptr == ' ') {                   /* next argument */
+          *cmd_ptr = '\0';                     /* terminate previous */
+         while (*++cmd_ptr == ' ') ;           /* skip spaces */
+         if (*cmd_ptr == '\0') break;          /* no arg following */
+         if (arg_count>MAX_NR_ARGS+1) break;   /* arg vector full */
+          rp->r_argv[arg_count++] = cmd_ptr;   /* add to arg vector */
+      }
+      cmd_ptr ++;                              /* continue parsing */
+  }
+  rp->r_argv[arg_count] = NULL;                        /* end with NULL pointer */
+  rp->r_argc = arg_count;
+
+  /* Default label for the driver */
+  label= strrchr(rp->r_argv[0], '/');
+  if (label)
+       label++;
+  else
+       label= rp->r_argv[0];
+  len= strlen(label);
+  if (len > MAX_LABEL_LEN-1)
+       len= MAX_LABEL_LEN-1;   /* truncate name */
+  memcpy(rp->r_label, label, len);
+  rp->r_label[len]= '\0';
+  printf("using label '%s'\n", rp->r_label);
+
+  /* Check for duplicates */
+  for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+      tmp_rp = &rproc[slot_nr];                        /* get pointer to slot */
+      if (!(tmp_rp->r_flags & RS_IN_USE))      /* check if available */
+         continue;
+      if (tmp_rp == rp)
+         continue;                             /* Our slot */
+      if (strcmp(tmp_rp->r_label, rp->r_label) == 0)
+      {
+         printf("found duplicate: slot %d\n", slot_nr);
+         return EBUSY;
+      }
+  }
+
+  rp->r_script[0]= '\0';
+  if (rs_start.rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
+  if (rs_start.rss_script != NULL)
+  {
+         s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_script, 
+               SELF, (vir_bytes) rp->r_script, rs_start.rss_scriptlen);
+         if (s != OK) return(s);
+         rp->r_script[rs_start.rss_scriptlen] = '\0';
+  }
+  rp->r_uid= rs_start.rss_uid;
+  rp->r_nice= rs_start.rss_nice;
+
+  rp->r_exec= NULL;
+  if (rs_start.rss_flags & RF_COPY)
+  {
+       s= read_exec(rp);
+       if (s != OK)
+               return s;
+  }
+
+  /* Copy granted resources */
+  if (rs_start.rss_nr_irq > NR_IRQ)
+  {
+       printf("do_start: too many IRQs requested\n");
+       return EINVAL;
+  }
+  rp->r_priv.s_nr_irq= rs_start.rss_nr_irq;
+  for (i= 0; i<rp->r_priv.s_nr_irq; i++)
+  {
+       rp->r_priv.s_irq_tab[i]= rs_start.rss_irq[i];
+       printf("do_start: IRQ %d\n", rp->r_priv.s_irq_tab[i]);
+  }
+
+  if (rs_start.rss_nr_io > NR_IO_RANGE)
+  {
+       printf("do_start: too many I/O ranges requested\n");
+       return EINVAL;
+  }
+  rp->r_priv.s_nr_io_range= rs_start.rss_nr_io;
+  for (i= 0; i<rp->r_priv.s_nr_io_range; i++)
+  {
+       rp->r_priv.s_io_tab[i].ior_base= rs_start.rss_io[i].base;
+       rp->r_priv.s_io_tab[i].ior_limit=
+               rs_start.rss_io[i].base+rs_start.rss_io[i].len-1;
+       printf("do_start: I/O [%x..%x]\n",
+               rp->r_priv.s_io_tab[i].ior_base,
+               rp->r_priv.s_io_tab[i].ior_limit);
+  }
+
+  if (rs_start.rss_nr_pci_id > MAX_NR_PCI_ID)
+  {
+       printf("do_start: too many PCI device IDs\n");
+       return EINVAL;
+  }
+  rp->r_nr_pci_id= rs_start.rss_nr_pci_id;
+  for (i= 0; i<rp->r_nr_pci_id; i++)
+  {
+       rp->r_pci_id[i].vid= rs_start.rss_pci_id[i].vid;
+       rp->r_pci_id[i].did= rs_start.rss_pci_id[i].did;
+       printf("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)
+  {
+       printf("do_start: too many PCI class IDs\n");
+       return EINVAL;
+  }
+  rp->r_nr_pci_class= rs_start.rss_nr_pci_class;
+  for (i= 0; i<rp->r_nr_pci_class; i++)
+  {
+       rp->r_pci_class[i].class= rs_start.rss_pci_class[i].class;
+       rp->r_pci_class[i].mask= rs_start.rss_pci_class[i].mask;
+       printf("do_start: PCI class %06x mask %06x\n",
+               rp->r_pci_class[i].class, rp->r_pci_class[i].mask);
+  }
+
+  /* Copy 'system' call number bits */
+  if (sizeof(rs_start.rss_system[0]) == sizeof(rp->r_call_mask[0]) &&
+       sizeof(rs_start.rss_system) == sizeof(rp->r_call_mask))
+  {
+       for (i= 0; i<RSS_NR_SYSTEM; i++)
+               rp->r_call_mask[i]= rs_start.rss_system[i];
+  }
+  else
+  {
+       printf(
+       "do_start: internal inconsistency: bad size of r_call_mask\n");
+       memset(rp->r_call_mask, '\0', sizeof(rp->r_call_mask));
+  }
+
+  /* Initialize some fields. */
+  rp->r_period = rs_start.rss_period;
+  rp->r_dev_nr = rs_start.rss_major;
+  rp->r_dev_style = STYLE_DEV; 
+  rp->r_restarts = -1;                                 /* will be incremented */
+  rp->r_set_resources= 1;                      /* new style, enforece
+                                                * I/O resources
+                                                */
+  
+  /* All information was gathered. Now try to start the system service. */
+  return(start_service(rp, 0));
+}
+
+
 /*===========================================================================*
  *                             do_down                                      *
  *===========================================================================*/
 PUBLIC int do_down(message *m_ptr)
 {
   register struct rproc *rp;
-  pid_t pid = (pid_t) m_ptr->RS_PID;
+  size_t len;
+  int s, proc;
+  char label[MAX_LABEL_LEN];
+
+  len= m_ptr->RS_CMD_LEN;
+  if (len >= sizeof(label))
+       return EINVAL;          /* Too long */
+
+  s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, 
+       SELF, (vir_bytes) label, len);
+  if (s != OK) return(s);
+  label[len]= '\0';
 
   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
-      if (rp->r_flags & RS_IN_USE && rp->r_pid == pid) {
+      if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
 #if VERBOSE
-         printf("stopping %d (%d)\n", pid, m_ptr->RS_PID);
+         printf("stopping '%s' (%d)\n", label, rp->r_pid);
 #endif
          stop_service(rp,RS_EXITING);
+         if (rp->r_pid == -1)
+         {
+               /* Process is already gone */
+               rp->r_flags = 0;                        /* release slot */
+               if (rp->r_exec)
+               {
+                       free(rp->r_exec);
+                       rp->r_exec= NULL;
+               }
+               proc = _ENDPOINT_P(rp->r_proc_nr_e);
+               rproc_ptr[proc] = NULL;
+         }
+         return(OK);
+      }
+  }
+#if VERBOSE
+  printf("do_down: '%s' not found\n", label);
+#endif
+  return(ESRCH);
+}
+
+
+/*===========================================================================*
+ *                             do_restart                                   *
+ *===========================================================================*/
+PUBLIC int do_restart(message *m_ptr)
+{
+  register struct rproc *rp;
+  size_t len;
+  int s, proc;
+  char label[MAX_LABEL_LEN];
+
+  len= m_ptr->RS_CMD_LEN;
+  if (len >= sizeof(label))
+       return EINVAL;          /* Too long */
+
+  s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, 
+       SELF, (vir_bytes) label, len);
+  if (s != OK) return(s);
+  label[len]= '\0';
+
+  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
+         printf("restarting '%s' (%d)\n", label, rp->r_pid);
+#endif
+         if (rp->r_pid >= 0)
+         {
+               printf("do_restart: '%s' is (still) running, pid = %d\n",
+                       rp->r_pid);
+               return EBUSY;
+         }
+         rp->r_flags &= ~(RS_EXITING|RS_REFRESHING|RS_NOPINGREPLY);
+         start_service(rp, 0); 
          return(OK);
       }
   }
 #if VERBOSE
-  printf("not found %d (%d)\n", pid, m_ptr->RS_PID);
+  printf("do_restart: '%s' not found\n", label);
 #endif
   return(ESRCH);
 }
@@ -134,19 +421,30 @@ PUBLIC int do_down(message *m_ptr)
 PUBLIC int do_refresh(message *m_ptr)
 {
   register struct rproc *rp;
-  pid_t pid = (pid_t) m_ptr->RS_PID;
+  size_t len;
+  int s;
+  char label[MAX_LABEL_LEN];
+
+  len= m_ptr->RS_CMD_LEN;
+  if (len >= sizeof(label))
+       return EINVAL;          /* Too long */
+
+  s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, 
+       SELF, (vir_bytes) label, len);
+  if (s != OK) return(s);
+  label[len]= '\0';
 
   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
-      if (rp->r_flags & RS_IN_USE && rp->r_pid == pid) {
+      if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
 #if VERBOSE
-         printf("refreshing %d (%d)\n", pid, m_ptr->RS_PID);
+         printf("refreshing %s (%d)\n", rp->r_label, rp->r_pid);
 #endif
          stop_service(rp,RS_REFRESHING);
          return(OK);
       }
   }
 #if VERBOSE
-  printf("not found %d (%d)\n", pid, m_ptr->RS_PID);
+  printf("do_refresh: '%s' not found\n", label);
 #endif
   return(ESRCH);
 }
@@ -225,6 +523,7 @@ PUBLIC void do_exit(message *m_ptr)
              proc = _ENDPOINT_P(rp->r_proc_nr_e);
 
               rproc_ptr[proc] = NULL;          /* invalidate */
+             rp->r_pid= -1;
 
               if ((rp->r_flags & RS_EXITING) || shutting_down) {
                  rp->r_flags = 0;                      /* release slot */
@@ -237,7 +536,10 @@ PUBLIC void do_exit(message *m_ptr)
              }
              else if(rp->r_flags & RS_REFRESHING) {
                      rp->r_restarts = -1;              /* reset counter */
-                     start_service(rp, 0);             /* direct restart */
+                     if (rp->r_script[0] != '\0')
+                       run_script(rp);
+                     else
+                       start_service(rp, 0);           /* direct restart */
              }
               else if (WIFEXITED(exit_status) &&
                      WEXITSTATUS(exit_status) == EXEC_FAILED) {
@@ -254,7 +556,19 @@ PUBLIC void do_exit(message *m_ptr)
 #if 0
 rp->r_restarts= 0;
 #endif
-                  if (rp->r_restarts > 0) {
+                 if (WIFSIGNALED(exit_status)) {
+                       switch(WTERMSIG(exit_status))
+                       {
+                       case SIGKILL:   rp->r_flags |= RS_KILLED; break;
+                       default:        rp->r_flags |= RS_CRASHED; break;
+                       }
+                 } 
+                 else
+                       rp->r_flags |= RS_CRASHED;
+
+                 if (rp->r_script[0] != '\0')
+                     run_script(rp);
+                 else if (rp->r_restarts > 0) {
                      rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2));
                      rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF); 
                      if (rp->r_exec != NULL && rp->r_backoff > 1)
@@ -315,10 +629,11 @@ message *m_ptr;
               */
               if (rp->r_alive_tm < rp->r_check_tm) { 
                  if (now - rp->r_alive_tm > 2*rp->r_period &&
-                     rp->r_pid > 0) { 
+                     rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) { 
 #if VERBOSE
                       printf("RS: service %d reported late\n", rp->r_proc_nr_e); 
 #endif
+                     rp->r_flags |= RS_NOPINGREPLY;
                       kill(rp->r_pid, SIGKILL);                /* simulate crash */
                  }
              }
@@ -327,7 +642,7 @@ message *m_ptr;
               * check and, if so request the system service's status.
               */
              else if (now - rp->r_check_tm > rp->r_period) {
-#if VERBOSE
+#if VERBOSE && 0
                   printf("RS: status request sent to %d\n", rp->r_proc_nr_e); 
 #endif
                  notify(rp->r_proc_nr_e);              /* request status */
@@ -358,6 +673,7 @@ int flags;
   pid_t child_pid;                             /* child's process id */
   char *file_only;
   int s, use_copy;
+  struct priv *privp;
   message m;
 
   use_copy= (rp->r_exec != NULL);
@@ -378,6 +694,10 @@ int flags;
        * e.g., because the root file system cannot be read, try to strip of
        * the path, and see if the command is in RS' current working dir.
        */
+      nice(rp->r_nice);                /* Nice before setuid, to allow negative
+                                * nice values.
+                                */
+      setuid(rp->r_uid);
       if (!use_copy)
       {
        execve(rp->r_argv[0], rp->r_argv, NULL);        /* POSIX execute */
@@ -399,10 +719,20 @@ int flags;
                environ);
   }
 
+  privp= NULL;
+  if (rp->r_set_resources)
+  {
+       init_privs(rp, &rp->r_priv);
+       privp= &rp->r_priv;
+
+       /* Inform the PCI server about the driver */
+       init_pci(rp, child_proc_nr_e);
+  }
+
   /* Set the privilege structure for the child process to let is run.
    * This should succeed: we tested number in use above.
    */
-  if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_INIT, 0, NULL)) < 0) {
+  if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_INIT, 0, privp)) < 0) {
       report("RS","sys_privctl call failed", s);       /* to let child run */
       rp->r_flags |= RS_EXITING;                       /* expect exit */
       if(child_pid > 0) kill(child_pid, SIGKILL);      /* kill driver */
@@ -462,7 +792,9 @@ int how;
 
   rp->r_flags |= how;                          /* what to on exit? */
   if(rp->r_pid > 0) kill(rp->r_pid, SIGTERM);  /* first try friendly */
-  else report("RS", "didn't kill pid", rp->r_pid);
+#if VERBOSE
+  else printf("no process to kill\n");
+#endif
   getuptime(&rp->r_stop_tm);                   /* record current time */
 }
 
@@ -543,3 +875,169 @@ struct rproc *rp;
        else
                return -e;
 }
+
+/*===========================================================================*
+ *                             run_script                                   *
+ *===========================================================================*/
+PRIVATE void run_script(rp)
+struct rproc *rp;
+{
+       int r, proc_nr_e;
+       pid_t pid;
+       char *reason;
+       char incarnation_str[20];       /* Enough for a counter? */
+
+       if (rp->r_flags & RS_EXITING)
+               reason= "exit";
+       else if (rp->r_flags & RS_REFRESHING)
+               reason= "restart";
+       else if (rp->r_flags & RS_NOPINGREPLY)
+               reason= "no-heartbeat";
+       else if (rp->r_flags & RS_KILLED)
+               reason= "killed";
+       else if (rp->r_flags & RS_CRASHED)
+               reason= "crashed";
+       else
+       {
+               printf(
+               "run_script: can't find reason for termination of '%s'\n",
+                       rp->r_label);
+               return;
+       }
+       sprintf(incarnation_str, "%d", rp->r_restarts);
+
+       printf("should call script '%s'\n", rp->r_script);
+       printf("sevice name: '%s'\n", rp->r_label);
+       printf("reason: '%s'\n", reason);
+       printf("incarnation: '%s'\n", incarnation_str);
+
+       pid= fork();
+       switch(pid)
+       {
+       case -1:        
+               printf("run_script: fork failed: %s\n", strerror(errno));
+               break;
+       case 0:
+               execle(rp->r_script, rp->r_script, rp->r_label, reason,
+                       incarnation_str, NULL, NULL);
+               {
+                       extern int kputc_use_private_grants;
+                       kputc_use_private_grants= 1;
+               }
+               printf("run_script: execl '%s' failed: %s\n",
+                       rp->r_script, strerror(errno));
+               exit(1);
+       default:
+               /* Set the privilege structure for the child process to let it
+                * run.
+                */
+               proc_nr_e = getnprocnr(pid);
+               r= sys_privctl(proc_nr_e, SYS_PRIV_USER, 0, NULL);
+               if (r < 0)
+                       printf("run_script: sys_privctl call failed: %d\n", r);
+
+               /* Do not wait for the child */
+               break;
+       }
+}
+
+
+/*===========================================================================*
+ *                             init_privs                                   *
+ *===========================================================================*/
+PRIVATE void init_privs(rp, privp)
+struct rproc *rp;
+struct priv *privp;
+{
+       int i, src_bits_per_word, dst_bits_per_word, src_word, dst_word,
+               src_bit, call_nr;
+       unsigned long mask;
+
+       /* Clear the privilege structure */
+       memset(privp, '\0', sizeof(*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_bit= 0; src_bit < src_bits_per_word; src_bit++)
+               {
+                       mask= (1UL << src_bit);
+                       if (!(rp->r_call_mask[src_word] & mask))
+                               continue;
+                       call_nr= src_word*src_bits_per_word+src_bit;
+                       printf("init_privs: system call %d\n", call_nr);
+                       dst_word= call_nr / dst_bits_per_word;
+                       mask= (1UL << (call_nr % dst_bits_per_word));
+                       if (dst_word >= CALL_MASK_SIZE)
+                       {
+                               printf(
+                               "init_privs: call number %d doesn't fit\n",
+                                       call_nr);
+                       }
+                       privp->s_k_call_mask[dst_word] |= mask;
+               }
+       }
+}
+
+
+/*===========================================================================*
+ *                             init_pci                                     *
+ *===========================================================================*/
+PRIVATE void init_pci(rp, endpoint)
+struct rproc *rp;
+int endpoint;
+{
+       /* Tell the PCI driver about the new driver */
+       size_t len;
+       int i, r;
+       struct rs_pci rs_pci;
+
+       len= strlen(rp->r_label);
+       if (len+1 > sizeof(rs_pci.rsp_label))
+       {
+               printf("init_pci: label '%s' too long for rsp_label\n",
+                       rp->r_label);
+               return;
+       }
+       strcpy(rs_pci.rsp_label, rp->r_label);
+       rs_pci.rsp_endpoint= endpoint;
+
+       rs_pci.rsp_nr_device= rp->r_nr_pci_id;
+       if (rs_pci.rsp_nr_device > RSP_NR_DEVICE)
+       {
+               printf("init_pci: too many PCI devices (max %d) truncating\n",
+                       RSP_NR_DEVICE);
+               rs_pci.rsp_nr_device= RSP_NR_DEVICE;
+       }
+       for (i= 0; i<rs_pci.rsp_nr_device; i++)
+       {
+               rs_pci.rsp_device[i].vid= rp->r_pci_id[i].vid;
+               rs_pci.rsp_device[i].did= rp->r_pci_id[i].did;
+       }
+
+       rs_pci.rsp_nr_class= rp->r_nr_pci_class;
+       if (rs_pci.rsp_nr_class > RSP_NR_CLASS)
+       {
+               printf("init_pci: too many PCI classes (max %d) truncating\n",
+                       RSP_NR_CLASS);
+               rs_pci.rsp_nr_class= RSP_NR_CLASS;
+       }
+       for (i= 0; i<rs_pci.rsp_nr_class; i++)
+       {
+               rs_pci.rsp_class[i].class= rp->r_pci_class[i].class;
+               rs_pci.rsp_class[i].mask= rp->r_pci_class[i].mask;
+       }
+
+       printf("init_pci: calling pci_set_acl\n");
+
+       r= pci_set_acl(&rs_pci);
+
+       printf("init_pci: after pci_set_acl\n");
+
+       if (r != OK)
+       {
+               printf("init_pci: pci_set_acl failed: %s\n", strerror(errno));
+               return;
+       }
+}
index 953d31685994133e43c193fa6ba2644c221b2b20..f6da67fe331b44eafe9251af492b35675415adc0 100644 (file)
@@ -5,15 +5,23 @@
 
 /* Space reserved for program and arguments. */
 #define MAX_COMMAND_LEN     512                /* maximum argument string length */
+#define MAX_LABEL_LEN       16         /* Unique name of (this instance of)
+                                        * the driver
+                                        */
+#define MAX_SCRIPT_LEN      256                /* maximum restart script name length */
 #define MAX_NR_ARGS          4         /* maximum number of arguments */
 #define MAX_RESCUE_DIR_LEN   64                /* maximum rescue dir length */
 
+#define MAX_NR_PCI_ID        4         /* 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 */
+
 /* Definition of the system process table. This table only has entries for
  * the servers and drivers, and thus is not directly indexed by slot number.
  */
 extern struct rproc {
   int r_proc_nr_e;             /* process endpoint number */
-  pid_t r_pid;                 /* process id */
+  pid_t r_pid;                 /* process id, -1 if the process is not there */
   dev_t r_dev_nr;              /* major device number */
   int r_dev_style;             /* device style */
 
@@ -29,9 +37,25 @@ extern struct rproc {
   char *r_exec;                        /* Executable image */ 
   size_t r_exec_len;           /* Length of image */
 
+  char r_label[MAX_LABEL_LEN]; /* unique name of this driver */
   char r_cmd[MAX_COMMAND_LEN]; /* raw command plus arguments */
+  char r_script[MAX_SCRIPT_LEN]; /* name of the restart script executable */
   char *r_argv[MAX_NR_ARGS+2];  /* parsed arguments vector */
   int r_argc;                          /* number of arguments */
+
+  /* Resources */
+  int r_set_resources;
+  struct priv r_priv;          /* Privilege structure to be passed to the
+                                * kernel.
+                                */
+  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];
+  int r_nr_pci_class;          /* Number of PCI class IDs */
+  struct { u32_t class; u32_t mask; } r_pci_class[MAX_NR_PCI_CLASS];
+
+  u32_t r_call_mask[MAX_NR_SYSTEM];
 } rproc[NR_SYS_PROCS];
 
 /* Mapping for fast access to the system process table. */ 
@@ -40,8 +64,11 @@ extern int nr_in_use;
 
 /* Flag values. */
 #define RS_IN_USE       0x001  /* set when process slot is in use */
-#define RS_EXITING      0x002  /* set when exit is expected */
-#define RS_REFRESHING   0x004  /* set when refresh must be done */
+#define RS_EXITING      0x004  /* set when exit is expected */
+#define RS_REFRESHING   0x008  /* set when refresh must be done */
+#define RS_NOPINGREPLY         0x010   /* driver failed to reply to a ping request */
+#define RS_KILLED      0x020   /* driver is killed */
+#define RS_CRASHED     0x040   /* driver crashed */
 
 /* Constants determining RS period and binary exponential backoff. */
 #define RS_DELTA_T       60                    /* check every T ticks */
index df862313d6b7c50904c0ab92efa80a7f4b3c677a..1e0ccf5e45817d7d31bb7101a656329ed0765360 100644 (file)
@@ -9,9 +9,11 @@ _PROTOTYPE( int main, (void));
 
 /* manager.c */
 _PROTOTYPE( int do_up, (message *m, int do_copy, int flags));
+_PROTOTYPE( int do_start, (message *m));
 _PROTOTYPE( int do_down, (message *m));
 _PROTOTYPE( int do_refresh, (message *m));
 _PROTOTYPE( int do_rescue, (message *m));
+_PROTOTYPE( int do_restart, (message *m));
 _PROTOTYPE( int do_shutdown, (message *m));
 _PROTOTYPE( void do_period, (message *m));
 _PROTOTYPE( void do_exit, (message *m));
index 4e70ea8d92050b883efbd55ce6ae1eb28d477194..470cf060dd1cb9dd0fe764d672ef957d7c1980d5 100644 (file)
@@ -5,19 +5,23 @@
  *   Jul 22, 2005:     Created  (Jorrit N. Herder)
  */
 
+#include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <pwd.h>
 #include <unistd.h>
 #include <minix/config.h>
 #include <minix/com.h>
 #include <minix/const.h>
 #include <minix/type.h>
 #include <minix/ipc.h>
+#include <minix/rs.h>
 #include <minix/syslib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <configfile.h>
 
 
 /* This array defines all known requests. */
@@ -25,6 +29,7 @@ PRIVATE char *known_requests[] = {
   "up", 
   "down",
   "refresh", 
+  "restart",
   "rescue", 
   "shutdown", 
   "upcopy",    /* fill for RS_UP_COPY */
@@ -46,7 +51,7 @@ extern int errno;
 /* The following are relative to optind */
 #define ARG_REQUEST    0               /* request to perform */
 #define ARG_PATH       1               /* rescue dir or system service */
-#define ARG_PID                1               /* pid of system service */
+#define ARG_LABEL      1               /* name of system service */
 
 #define MIN_ARG_COUNT  1               /* require an action */
 
@@ -54,22 +59,37 @@ extern int errno;
 #define ARG_DEV                "-dev"          /* major device number for drivers */
 #define ARG_PRIV       "-priv"         /* required privileges */
 #define ARG_PERIOD     "-period"       /* heartbeat period in ticks */
+#define ARG_SCRIPT     "-script"       /* name of the script to restart a
+                                        * driver 
+                                        */
+#define ARG_CONFIG     "-config"       /* name of the file with the resource
+                                        * configuration 
+                                        */
+
+#define DRIVER_LOGIN   "driver"        /* Passwd file entry for drivers */
+
+#define MAX_CLASS_RECURS       100     /* Max nesting level for classes */
 
 /* The function parse_arguments() verifies and parses the command line 
  * parameters passed to this utility. Request parameters that are needed
  * are stored globally in the following variables:
  */
 PRIVATE int req_type;
-PRIVATE int req_pid;
+PRIVATE char *req_label;
 PRIVATE char *req_path;
 PRIVATE char *req_args;
 PRIVATE int req_major;
 PRIVATE long req_period;
-PRIVATE char *req_priv;
+PRIVATE char *req_script;
+PRIVATE char *req_config;
+PRIVATE int class_recurs;      /* Nesting level of class statements */
 
 /* Buffer to build "/command arg1 arg2 ..." string to pass to RS server. */
 PRIVATE char command[4096];    
 
+/* Arguments for RS to start a new service */
+PRIVATE struct rs_start rs_start;
+
 /* An error occurred. Report the problem, print the usage, and exit. 
  */
 PRIVATE void print_usage(char *app_name, char *problem) 
@@ -78,8 +98,9 @@ PRIVATE void print_usage(char *app_name, char *problem)
   printf("Usage:\n");
   printf("    %s [-c] (up|run) <binary> [%s <args>] [%s <special>] [%s <ticks>]\n", 
        app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD);
-  printf("    %s down <pid>\n", app_name);
-  printf("    %s refresh <pid>\n", app_name);
+  printf("    %s down label\n", app_name);
+  printf("    %s refresh label\n", app_name);
+  printf("    %s restart label\n", app_name);
   printf("    %s rescue <dir>\n", app_name);
   printf("    %s shutdown\n", app_name);
   printf("\n");
@@ -141,6 +162,10 @@ PRIVATE int parse_arguments(int argc, char **argv)
 
   if (req_nr == RS_UP || req_nr == RS_RUN) {
 
+      rs_start.rss_flags= 0;
+      if (c_flag)
+       rs_start.rss_flags |= RF_COPY;
+
       if (req_nr == RS_UP && c_flag)
        req_nr= RS_UP_COPY;
 
@@ -195,8 +220,13 @@ PRIVATE int parse_arguments(int argc, char **argv)
                      } 
               req_major = (stat_buf.st_rdev >> MAJOR) & BYTE;
           }
-          else if (strcmp(argv[i], ARG_ARGS)==0) {
-              req_priv = argv[i+1];
+          else if (strcmp(argv[i], ARG_SCRIPT)==0) {
+              req_script = argv[i+1];
+             req_nr = RS_START;
+          }
+          else if (strcmp(argv[i], ARG_CONFIG)==0) {
+              req_config = argv[i+1];
+             req_nr = RS_START;
           }
           else {
               print_usage(argv[ARG_NAME], "unknown optional argument given");
@@ -204,17 +234,14 @@ PRIVATE int parse_arguments(int argc, char **argv)
           }
       }
   }
-  else if (req_nr == RS_DOWN || req_nr == RS_REFRESH) {
+  else if (req_nr == RS_DOWN || req_nr == RS_REFRESH || req_nr == RS_RESTART) {
 
       /* Verify argument count. */ 
-      if (argc - 1 < optind+ARG_PID) {
-          print_usage(argv[ARG_NAME], "action requires a pid to stop");
-          exit(EINVAL);
-      }
-      if (! (req_pid = atoi(argv[optind+ARG_PID])) > 0) {
-          print_usage(argv[ARG_NAME], "pid must be greater than zero");
+      if (argc - 1 < optind+ARG_LABEL) {
+          print_usage(argv[ARG_NAME], "action requires a label to stop");
           exit(EINVAL);
       }
+      req_label= argv[optind+ARG_LABEL];
   } 
   else if (req_nr == RS_RESCUE) {
 
@@ -245,6 +272,574 @@ PRIVATE int parse_arguments(int argc, char **argv)
   return(req_nr);
 }
 
+PRIVATE void fatal(char *fmt, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "fatal error: ");
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+
+       exit(1);
+}
+
+#define KW_DRIVER      "driver"
+#define KW_UID         "uid"
+#define KW_NICE                "nice"
+#define KW_IRQ         "irq"
+#define KW_IO          "io"
+#define KW_PCI         "pci"
+#define KW_DEVICE      "device"
+#define KW_CLASS       "class"
+#define KW_SYSTEM      "system"
+
+FORWARD void do_driver(config_t *cpe, config_t *config);
+
+PRIVATE void do_class(config_t *cpe, config_t *config)
+{
+       config_t *cp, *cp1;
+
+       if (class_recurs > MAX_CLASS_RECURS)
+       {
+               fatal(
+               "do_class: nesting level too high for class '%s' at %s:%d",
+                       cpe->word, cpe->file, cpe->line);
+       }
+       class_recurs++;
+
+       /* Process classes */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_class: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_uid: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+
+               /* Find entry for the class */
+               for (cp= config; cp; cp= cp->next)
+               {
+                       if (!(cp->flags & CFG_SUBLIST))
+                       {
+                               fatal("do_class: expected list at %s:%d\n",
+                                       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",
+                                       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",
+                                       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",
+                                       cp1->file, cp1->line);
+                       }
+
+                       /* At this place we expect the name of the driver */
+                       if (strcmp(cp1->word, cpe->word) == 0)
+                               break;
+               }
+               if (cp == NULL)
+               {
+                       fatal(
+                       "do_class: no entry found for class '%s' at %s:%d\n",
+                               cpe->word, cpe->file, cpe->line);
+               }
+               do_driver(cp1->next, config);
+       }
+
+       class_recurs--;
+}
+
+PRIVATE void do_uid(config_t *cpe)
+{
+       uid_t uid;
+       struct passwd *pw;
+       char *check;
+
+       /* Process a uid */
+       if (cpe->next != NULL)
+       {
+               fatal("do_uid: just one uid/login expected at %s:%d",
+                       cpe->file, cpe->line);
+       }       
+
+       if (cpe->flags & CFG_SUBLIST)
+       {
+               fatal("do_uid: unexpected sublist at %s:%d",
+                       cpe->file, cpe->line);
+       }
+       if (cpe->flags & CFG_STRING)
+       {
+               fatal("do_uid: unexpected string at %s:%d",
+                       cpe->file, cpe->line);
+       }
+       pw= getpwnam(cpe->word);
+       if (pw != NULL)
+               uid= pw->pw_uid;
+       else
+       {
+               uid= strtol(cpe->word, &check, 0);
+               if (check[0] != '\0')
+               {
+                       fatal("do_uid: bad uid/login '%s' at %s:%d",
+                               cpe->word, cpe->file, cpe->line);
+               }
+       }
+
+       rs_start.rss_uid= uid;
+}
+
+PRIVATE void do_nice(config_t *cpe)
+{
+       int nice_val;
+       char *check;
+
+       /* Process a nice value */
+       if (cpe->next != NULL)
+       {
+               fatal("do_nice: just one nice value expected at %s:%d",
+                       cpe->file, cpe->line);
+       }       
+       
+
+       if (cpe->flags & CFG_SUBLIST)
+       {
+               fatal("do_nice: unexpected sublist at %s:%d",
+                       cpe->file, cpe->line);
+       }
+       if (cpe->flags & CFG_STRING)
+       {
+               fatal("do_nice: unexpected string at %s:%d",
+                       cpe->file, cpe->line);
+       }
+       nice_val= strtol(cpe->word, &check, 0);
+       if (check[0] != '\0')
+       {
+               fatal("do_nice: bad nice value '%s' at %s:%d",
+                       cpe->word, cpe->file, cpe->line);
+       }
+       /* Check range? */
+
+       rs_start.rss_nice= nice_val;
+}
+
+PRIVATE void do_irq(config_t *cpe)
+{
+       int irq;
+       char *check;
+
+       /* Process a list of IRQs */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_irq: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_irq: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               irq= strtoul(cpe->word, &check, 0);
+               if (check[0] != '\0')
+               {
+                       fatal("do_irq: bad irq '%s' at %s:%d",
+                               cpe->word, cpe->file, cpe->line);
+               }
+               if (rs_start.rss_nr_irq >= RSS_NR_IRQ)
+                       fatal("do_irq: too many IRQs (max %d)", RSS_NR_IRQ);
+               rs_start.rss_irq[rs_start.rss_nr_irq]= irq;
+               rs_start.rss_nr_irq++;
+       }
+}
+
+PRIVATE void do_io(config_t *cpe)
+{
+       int irq;
+       unsigned base, len;
+       char *check;
+
+       /* Process a list of I/O ranges */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_io: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_io: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               base= strtoul(cpe->word, &check, 0x10);
+               len= 1;
+               if (check[0] == ':')
+               {
+                       len= strtoul(check+1, &check, 0x10);
+               }
+               if (check[0] != '\0')
+               {
+                       fatal("do_io: bad I/O range '%s' at %s:%d",
+                               cpe->word, cpe->file, cpe->line);
+               }
+
+               if (rs_start.rss_nr_io >= RSS_NR_IO)
+                       fatal("do_io: too many I/O ranges (max %d)", RSS_NR_IO);
+               rs_start.rss_io[rs_start.rss_nr_io].base= base;
+               rs_start.rss_io[rs_start.rss_nr_io].len= len;
+               rs_start.rss_nr_io++;
+       }
+}
+
+PRIVATE void do_pci_device(config_t *cpe)
+{
+       u16_t vid, did;
+       char *check, *check2;
+
+       /* Process a list of PCI device IDs */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_pci_device: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_pci_device: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               vid= strtoul(cpe->word, &check, 0x10);
+               if (check[0] == '/')
+                       did= strtoul(check+1, &check2, 0x10);
+               if (check[0] != '/' || check2[0] != '\0')
+               {
+                       fatal("do_pci_device: bad ID '%s' at %s:%d",
+                               cpe->word, cpe->file, cpe->line);
+               }
+               if (rs_start.rss_nr_pci_id >= RSS_NR_PCI_ID)
+               {
+                       fatal("do_pci_device: too many device IDs (max %d)",
+                               RSS_NR_PCI_ID);
+               }
+               rs_start.rss_pci_id[rs_start.rss_nr_pci_id].vid= vid;
+               rs_start.rss_pci_id[rs_start.rss_nr_pci_id].did= did;
+               rs_start.rss_nr_pci_id++;
+       }
+}
+
+PRIVATE void do_pci_class(config_t *cpe)
+{
+       u8_t baseclass, subclass, interface;
+       u32_t class_id, mask;
+       char *check;
+
+       /* Process a list of PCI device class IDs */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_pci_device: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_pci_device: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+
+               baseclass= strtoul(cpe->word, &check, 0x10);
+               subclass= 0;
+               interface= 0;
+               mask= 0xff0000;
+               if (check[0] == '/')
+               {
+                       subclass= strtoul(check+1, &check, 0x10);
+                       mask= 0xffff00;
+                       if (check[0] == '/')
+                       {
+                               interface= strtoul(check+1, &check, 0x10);
+                               mask= 0xffffff;
+                       }
+               }
+
+               if (check[0] != '\0')
+               {
+                       fatal("do_pci_class: bad class ID '%s' at %s:%d",
+                               cpe->word, cpe->file, cpe->line);
+               }
+               class_id= (baseclass << 16) | (subclass << 8) | interface;
+               if (rs_start.rss_nr_pci_class >= RSS_NR_PCI_CLASS)
+               {
+                       fatal("do_pci_class: too many class IDs (max %d)",
+                               RSS_NR_PCI_CLASS);
+               }
+               rs_start.rss_pci_class[rs_start.rss_nr_pci_class].class=
+                       class_id;
+               rs_start.rss_pci_class[rs_start.rss_nr_pci_class].mask= mask;
+               rs_start.rss_nr_pci_class++;
+       }
+}
+
+PRIVATE void do_pci(config_t *cpe)
+{
+       int i, call_nr, word, bits_per_word;
+       unsigned long mask;
+
+       if (cpe == NULL)
+               return; /* Empty PCI statement */
+
+       if (cpe->flags & CFG_SUBLIST)
+       {
+               fatal("do_pci: unexpected sublist at %s:%d",
+                       cpe->file, cpe->line);
+       }
+       if (cpe->flags & CFG_STRING)
+       {
+               fatal("do_pci: unexpected string at %s:%d",
+                       cpe->file, cpe->line);
+       }
+
+       if (strcmp(cpe->word, KW_DEVICE) == 0)
+       {
+               do_pci_device(cpe->next);
+               return;
+       }
+       if (strcmp(cpe->word, KW_CLASS) == 0)
+       {
+               do_pci_class(cpe->next);
+               return;
+       }
+       fatal("do_pci: unexpected word '%s' at %s:%d",
+               cpe->word, cpe->file, cpe->line);
+}
+
+struct
+{
+       char *label;
+       int call_nr;
+} system_tab[]=
+{
+       { "KILL",               SYS_KILL },
+       { "UMAP",               SYS_UMAP },
+       { "VIRCOPY",            SYS_VIRCOPY },
+       { "IRQCTL",             SYS_IRQCTL },
+       { "DEVIO",              SYS_DEVIO },
+       { "SDEVIO",             SYS_SDEVIO },
+       { "VDEVIO",             SYS_VDEVIO },
+       { "SETALARM",           SYS_SETALARM },
+       { "TIMES",              SYS_TIMES },
+       { "GETINFO",            SYS_GETINFO },
+       { "SAFECOPYFROM",       SYS_SAFECOPYFROM },
+       { "SAFECOPYTO",         SYS_SAFECOPYTO },
+       { "SETGRANT",           SYS_SETGRANT },
+       { NULL,         0 }
+};
+
+PRIVATE void do_system(config_t *cpe)
+{
+       int i, call_nr, word, bits_per_word;
+       unsigned long mask;
+
+       bits_per_word= sizeof(rs_start.rss_system[0])*8;
+
+       /* Process a list of 'system' calls that are allowed */
+       for (; cpe; cpe= cpe->next)
+       {
+               if (cpe->flags & CFG_SUBLIST)
+               {
+                       fatal("do_system: unexpected sublist at %s:%d",
+                               cpe->file, cpe->line);
+               }
+               if (cpe->flags & CFG_STRING)
+               {
+                       fatal("do_system: unexpected string at %s:%d",
+                               cpe->file, cpe->line);
+               }
+
+               /* Get call number */
+               for (i= 0; system_tab[i].label != NULL; i++)
+               {
+                       if (strcmp(cpe->word, system_tab[i].label) == 0)
+                               break;
+               }
+               if (system_tab[i].label == NULL)
+               {
+                       fatal("do_system: unknown call '%s' at %s:%d",
+                               cpe->word, cpe->file, cpe->line);
+               }
+               call_nr= system_tab[i].call_nr;
+
+               /* Subtract KERNEL_CALL */
+               if (call_nr < KERNEL_CALL)
+               {
+                       fatal(
+               "do_system: bad call number %d in system tab for '%s'\n",
+                               call_nr, system_tab[i].label);
+               }
+               call_nr -= KERNEL_CALL;
+
+               word= call_nr / bits_per_word;
+               mask= (1UL << (call_nr % bits_per_word));
+
+               if (word >= RSS_NR_SYSTEM)
+               {
+                       fatal(
+                       "do_system: RSS_NR_SYSTEM is too small (%d needed)\n",
+                               word+1);
+               }
+               rs_start.rss_system[word] |= mask;
+       }
+}
+
+PRIVATE void do_driver(config_t *cpe, config_t *config)
+{
+       config_t *cp;
+
+       /* At this point we expect one sublist that contains the varios
+        * resource allocations
+        */
+       if (!(cpe->flags & CFG_SUBLIST))
+       {
+               fatal("do_driver: expected list at %s:%d\n",
+                       cpe->file, cpe->line);
+       }
+       if (cpe->next != NULL)
+       {
+               cpe= cpe->next;
+               fatal("do_driver: expected end of list at %s:%d\n",
+                       cpe->file, cpe->line);
+       }
+       cpe= cpe->list;
+
+       /* Process the list */
+       for (cp= cpe; cp; cp= cp->next)
+       {
+               if (!(cp->flags & CFG_SUBLIST))
+               {
+                       fatal("do_driver: expected list at %s:%d\n",
+                               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",
+                               cpe->file, cpe->line);
+               }
+
+               if (strcmp(cpe->word, KW_CLASS) == 0)
+               {
+                       do_class(cpe->next, config);
+                       continue;
+               }
+               if (strcmp(cpe->word, KW_UID) == 0)
+               {
+                       do_uid(cpe->next);
+                       continue;
+               }
+               if (strcmp(cpe->word, KW_NICE) == 0)
+               {
+                       do_nice(cpe->next);
+                       continue;
+               }
+               if (strcmp(cpe->word, KW_IRQ) == 0)
+               {
+                       do_irq(cpe->next);
+                       continue;
+               }
+               if (strcmp(cpe->word, KW_IO) == 0)
+               {
+                       do_io(cpe->next);
+                       continue;
+               }
+               if (strcmp(cpe->word, KW_PCI) == 0)
+               {
+                       do_pci(cpe->next);
+                       continue;
+               }
+               if (strcmp(cpe->word, KW_SYSTEM) == 0)
+               {
+                       do_system(cpe->next);
+                       continue;
+               }
+
+               printf("found word '%s'\n", cpe->word);
+       }
+}
+
+PRIVATE void do_config(char *label, char *filename)
+{
+       config_t *config, *cp, *cpe;
+
+       config= config_read(filename, 0, NULL);
+       if (config == NULL)
+       {
+               fprintf(stderr, "config_read failed for '%s': %s\n",
+                       filename, strerror(errno));
+               exit(1);
+       }
+
+       /* Find an entry for our driver */
+       for (cp= config; cp; cp= cp->next)
+       {
+               if (!(cp->flags & CFG_SUBLIST))
+               {
+                       fatal("do_config: expected list at %s:%d\n",
+                               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",
+                               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",
+                               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",
+                               cpe->file, cpe->line);
+               }
+
+               /* At this place we expect the name of the driver */
+               if (strcmp(cpe->word, label) == 0)
+                       break;
+       }
+       if (cp == NULL)
+       {
+               printf("driver '%s' not found\n", label);
+               return;
+       }
+
+       cpe= cpe->next;
+
+       do_driver(cpe, config);
+}
 
 /* Main program. 
  */
@@ -253,7 +848,9 @@ PUBLIC int main(int argc, char **argv)
   message m;
   int result;
   int request;
-  int s;
+  int i, s;
+  char *label;
+  struct passwd *pw;
 
   /* Verify and parse the command line arguments. All arguments are checked
    * here. If an error occurs, the problem is reported and exit(2) is called. 
@@ -283,9 +880,47 @@ PUBLIC int main(int argc, char **argv)
           failure(-s);
       result = m.m_type;
       break;
+  case RS_START:
+      /* Build space-separated command string to be passed to RS server. */
+      strcpy(command, req_path);
+      command[strlen(req_path)] = ' ';
+      strcpy(command+strlen(req_path)+1, req_args);
+
+      rs_start.rss_cmd= command;
+      rs_start.rss_cmdlen= strlen(command);
+      rs_start.rss_major= req_major;
+      rs_start.rss_period= req_period;
+      rs_start.rss_script= req_script;
+      if (req_script)
+             rs_start.rss_scriptlen= strlen(req_script);
+      else
+             rs_start.rss_scriptlen= 0;
+
+      pw= getpwnam(DRIVER_LOGIN);
+      if (pw == NULL)
+       fatal("no passwd file entry for '%s'", DRIVER_LOGIN);
+      rs_start.rss_uid= pw->pw_uid;
+
+      /* The name of the driver */
+      (label= strrchr(req_path, '/')) ? label++ : (label= req_path);
+
+      if (req_config)
+       do_config(label, req_config);
+
+      m.RS_CMD_ADDR = (char *) &rs_start;
+
+      /* Build request message and send the request. */
+      if (OK != (s=_taskcall(RS_PROC_NR, request, &m))) 
+          failure(-s);
+      result = m.m_type;
+      break;
+
   case RS_DOWN:
   case RS_REFRESH:
-      m.RS_PID = req_pid;
+  case RS_RESTART:
+      m.RS_CMD_ADDR = req_label;
+      m.RS_CMD_LEN = strlen(req_label);
+printf("RS_CMD_LEN = %d\n", m.RS_CMD_LEN);
       if (OK != (s=_taskcall(RS_PROC_NR, request, &m))) 
           failure(-s);
       break;