]> Zhao Yanbai Git Server - minix.git/commitdiff
New signal handling behaviour at PM (services can be killed).
authorJorrit Herder <jnherder@minix3.org>
Wed, 12 Oct 2005 15:07:38 +0000 (15:07 +0000)
committerJorrit Herder <jnherder@minix3.org>
Wed, 12 Oct 2005 15:07:38 +0000 (15:07 +0000)
New Shift-F6 dump for RS server at IS.
New getnpid, getnproc, getpproc library calls at PM.
New reincarnation server (basic functionality is there now).

22 files changed:
servers/fs/main.c
servers/is/Makefile
servers/is/dmp.c
servers/is/dmp_kernel.c
servers/is/dmp_rs.c [new file with mode: 0644]
servers/is/glo.h
servers/is/is.c
servers/is/proto.h
servers/pm/getset.c
servers/pm/main.c
servers/pm/misc.c
servers/pm/param.h
servers/pm/signal.c
servers/pm/utility.c
servers/rs/Makefile
servers/rs/main.c [new file with mode: 0644]
servers/rs/manager.c
servers/rs/proto.h
servers/rs/rproc.h [new file with mode: 0644]
servers/rs/rs.c [deleted file]
servers/rs/rs.h
servers/rs/service.c

index 3bdd7ebfe4204570430cee0a673c965316445454..1092e2b2d7c66f3e2092e5e67895b5a8da72a293 100644 (file)
@@ -60,6 +60,7 @@ PUBLIC int main()
         if (call_nr == SYS_SIG) { 
                sigset = m_in.NOTIFY_ARG;
                if (sigismember(&sigset, SIGKSTOP)) {
+                       printf("FS got SIGKSTOP\n");
                        do_sync();
                        sys_exit(0);            /* never returns */
                }
index 724f46a5b7de91c57809188040d41fccdeee1fa6..dc519f0f0eb20f7224deac81a34b942325640ecf 100644 (file)
@@ -17,7 +17,7 @@ CFLAGS = -I$i
 LDFLAGS = -i
 LIBS = -lsys -lsysutil 
 
-OBJ = is.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o 
+OBJ = is.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o 
 
 # build local binary
 all build:     $(SERVER)
index 8f4ecaa281c1fd97e3262ee8c26948d5db429905..21f34813fa0f39de700fd3da56c06046c781e315 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "is.h"
 
-#define NHOOKS 15
+#define NHOOKS 17
 
 struct hook_entry {
        int key;
@@ -23,14 +23,16 @@ struct hook_entry {
        { F5,   monparams_dmp, "Boot monitor parameters" },
        { F6,   irqtab_dmp, "IRQ hooks and policies" },
        { F7,   kmessages_dmp, "Kernel messages" },
+       { F9,   sched_dmp, "Scheduling queues" },
        { F10,  kenv_dmp, "Kernel parameters" },
        { F11,  timing_dmp, "Timing details (if enabled)" },
-       { F12,  sched_dmp, "Scheduling queues" },
+       { F12,  reboot_dmp, "Reboot system after panic." },
        { SF1,  mproc_dmp, "Process manager process table" },
        { SF2,  sigaction_dmp, "Signals" },
        { SF3,  fproc_dmp, "Filesystem process table" },
        { SF4,  dtab_dmp, "Device/Driver mapping" },
        { SF5,  mapping_dmp, "Print key mappings" },
+       { SF6,  rproc_dmp, "Reincarnation server process table" },
 };
 
 /*===========================================================================*
@@ -74,6 +76,13 @@ PRIVATE char *keyname(int key)
        return name;
 }
 
+
+PUBLIC void reboot_dmp(void)
+{
+  if (sys_panic) sys_abort(RBT_HALT);
+}
+
+
 PUBLIC void mapping_dmp(void)
 {
        int h;
index 16baf484300163eb53b8e1eb931875f8bf4b95bc..b4e56254adf7d6d605b0df92d57ac01a10c37765 100644 (file)
@@ -435,7 +435,7 @@ PRIVATE char *p_rts_flags_str(int flags)
        str[0] = (flags & NO_MAP) ? 'M' : '-';
        str[1] = (flags & SENDING)  ? 'S' : '-';
        str[2] = (flags & RECEIVING)    ? 'R' : '-';
-       str[3] = (flags & SIGNALED)    ? 'S' : '-';
+       str[3] = (flags & SIGNALED)    ? 'I' : '-';
        str[4] = (flags & SIG_PENDING)    ? 'P' : '-';
        str[5] = (flags & P_STOP)    ? 'T' : '-';
        str[6] = '\0';
diff --git a/servers/is/dmp_rs.c b/servers/is/dmp_rs.c
new file mode 100644 (file)
index 0000000..c972644
--- /dev/null
@@ -0,0 +1,62 @@
+/* This file contains procedures to dump RS data structures.
+ *
+ * The entry points into this file are
+ *   rproc_dump:       display RS system process table   
+ *
+ * Created:
+ *   Oct 03, 2005:     by Jorrit N. Herder
+ */
+
+#include "is.h"
+#include "../rs/rproc.h"
+
+PUBLIC struct rproc rproc[NR_SYS_PROCS];
+
+FORWARD _PROTOTYPE( char *s_flags_str, (int flags)             );
+
+/*===========================================================================*
+ *                             rproc_dmp                                    *
+ *===========================================================================*/
+PUBLIC void rproc_dmp()
+{
+  struct rproc *rp;
+  int i,j, n=0;
+  static int prev_i=0;
+
+  getsysinfo(RS_PROC_NR, SI_PROC_TAB, rproc);
+
+  printf("Reincarnation Server (RS) system process table dump\n");
+  printf("-proc nr-pid- -dev nr/ style- -ticks-checked-alive-- --flags-- -command (argc)-\n");
+  for (i=prev_i; i<NR_SYS_PROCS; i++) {
+       rp = &rproc[i];
+       if (! rp->r_flags & IN_USE) continue;
+       if (++n > 22) break;
+       printf("%3d %5d  %3d/%2d  %3u %8u %8u %s  %s (%d)",
+               rp->r_proc_nr, rp->r_pid, 
+               rp->r_dev_nr, rp->r_dev_style,
+               rp->r_period, 
+               rp->r_check_tm,
+               rp->r_alive_tm,
+               s_flags_str(rp->r_flags),
+               rp->r_cmd,
+               rp->r_argc
+       );
+       printf("\n");
+  }
+  if (i >= NR_SYS_PROCS) i = 0;
+  else printf("--more--\r");
+  prev_i = i;
+}
+
+
+PRIVATE char *s_flags_str(int flags)
+{
+       static char str[5];
+       str[0] = (flags & IN_USE) ? 'U' : '-';
+       str[1] = (flags & EXIT_PENDING)    ? 'E' : '-';
+       str[2] = '-';
+       str[3] = '\0';
+
+       return(str);
+}
+
index e489ef9001165b0da6e08b1c187197d7c620fa82..35277f248304eca5e5adeb8b6860332c17155c02 100644 (file)
@@ -6,6 +6,9 @@ extern char diag_buf[DIAG_BUF_SIZE];    /* buffer for messages */
 extern int diag_next;                  /* next index to be written */
 extern int diag_size;                  /* size of all messages */
 
+/* Flag to indicate system-wide panic. */
+extern int sys_panic;          /* if set, shutdown can be done */
+
 /* The parameters of the call are kept here. */
 extern message m_in;           /* the input message itself */
 extern message m_out;          /* the output message used for reply */
index 3f29d43997d28638f2b1634fc48ba87ef1e0cdf5..087c326df10a7777d7f8c4c4f0eb8017aa8cf964 100644 (file)
@@ -18,6 +18,7 @@ message m_in;         /* the input message itself */
 message m_out;         /* the output message used for reply */
 int who;               /* caller's proc number */
 int callnr;            /* system call number */
+int sys_panic;         /* flag to indicate system-wide panic */
 
 extern int errno;      /* error number set by system library */
 
@@ -55,11 +56,16 @@ PUBLIC int main(int argc, char **argv)
               exit_server();
           }
           continue;
+      case PANIC_DUMPS:
+         printf("Oops ... panic in %d.  ", who);
+         printf("Hit F-keys for debug dumps or F12 to shut down.\n");
+         sys_panic = TRUE;                     /* set flag to allow exit */
+         continue;
       case FKEY_PRESSED:
           result = do_fkey_pressed(&m_in);
           break;
       default: 
-          report("IS","warning, got illegal request from %d\n", m_in.m_source);
+          report("IS","warning, got illegal request from:", m_in.m_source);
           result = EINVAL;
       }
 
@@ -79,7 +85,6 @@ PRIVATE void init_server(int argc, char **argv)
 /* Initialize the information service. */
   int fkeys, sfkeys;
   int i, s;
-#if DEAD_CODE
   struct sigaction sigact;
 
   /* Install signal handler. Ask PM to transform signal into message. */
@@ -88,7 +93,6 @@ PRIVATE void init_server(int argc, char **argv)
   sigact.sa_flags = 0;                 /* default behaviour */
   if (sigaction(SIGTERM, &sigact, NULL) < 0) 
       report("IS","warning, sigaction() failed", errno);
-#endif
 
   /* Set key mappings. IS takes all of F1-F12 and Shift+F1-F6. */
   fkeys = sfkeys = 0;
index 5d27e0ae7ec01cdd4322146911f814c6ae5c6f25..43f15cb69c9dafb1f8eaeaa22af551688d4f0c9d 100644 (file)
@@ -6,6 +6,7 @@ _PROTOTYPE( int  main, (int argc, char **argv)                          );
 /* dmp.c */
 _PROTOTYPE( int do_fkey_pressed, (message *m)                          );
 _PROTOTYPE( void mapping_dmp, (void)                                   );
+_PROTOTYPE( void reboot_dmp, (void)                                    );
 
 /* dmp_kernel.c */
 _PROTOTYPE( void proctab_dmp, (void)                                   );
@@ -28,3 +29,5 @@ _PROTOTYPE( void sigaction_dmp, (void)                                        );
 _PROTOTYPE( void dtab_dmp, (void)                                      );
 _PROTOTYPE( void fproc_dmp, (void)                                     );
 
+/* dmp_rs.c */
+_PROTOTYPE( void rproc_dmp, (void)                                     );
index 10f4166ec88e1af28da94e5eea30b780e38fb996..20810574bf51be40302bf0a92f966c8638e5c593 100644 (file)
@@ -38,6 +38,8 @@ PUBLIC int do_getset()
        case GETPID:
                r = mproc[who].mp_pid;
                rmp->mp_reply.reply_res2 = mproc[rmp->mp_parent].mp_pid;
+               if (m_in.procnr >= 0 && m_in.procnr < NR_PROCS) 
+                       rmp->mp_reply.reply_res3 = mproc[m_in.procnr].mp_pid;
                break;
 
        case SETUID:
index 66731e601607c842a4814294c7a03cef58ab46a3..f2fec7e833a12901b23fdaf18913f7b598f46b1c 100644 (file)
@@ -155,7 +155,9 @@ PRIVATE void pm_init()
   static char core_sigs[] = { SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
                        SIGEMT, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2 };
   static char ign_sigs[] = { SIGCHLD, SIGWINCH };
+  static char mess_sigs[] = { SIGTERM, SIGHUP, SIGABRT, SIGQUIT };
   register struct mproc *rmp;
+  register int i;
   register char *sig_ptr;
   phys_clicks total_clicks, minix_clicks, free_clicks;
   message mess;
@@ -209,19 +211,24 @@ PRIVATE void pm_init()
                strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN); 
                rmp->mp_parent = RS_PROC_NR;
                rmp->mp_nice = get_nice_value(ip->priority);
+               sigemptyset(&rmp->mp_sig2mess);
+               sigemptyset(&rmp->mp_ignore);   
+               sigemptyset(&rmp->mp_sigmask);
+               sigemptyset(&rmp->mp_catch);
                if (ip->proc_nr == INIT_PROC_NR) {      /* user process */
                        rmp->mp_pid = INIT_PID;
                        rmp->mp_flags |= IN_USE; 
-                       sigemptyset(&rmp->mp_ignore);   
                }
                else {                                  /* system process */
                        rmp->mp_pid = get_free_pid();
                        rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC; 
-                       sigfillset(&rmp->mp_ignore);    
+#if DEAD_CODE
+                       for (sig_ptr = mess_sigs; 
+                               sig_ptr < mess_sigs+sizeof(mess_sigs); 
+                               sig_ptr++)
+                       sigaddset(&rmp->mp_sig2mess, *sig_ptr);
+#endif
                }
-               sigemptyset(&rmp->mp_sigmask);
-               sigemptyset(&rmp->mp_catch);
-               sigemptyset(&rmp->mp_sig2mess);
 
                /* Get memory map for this process from the kernel. */
                if ((s=get_mem_map(ip->proc_nr, rmp->mp_seg)) != OK)
@@ -241,9 +248,11 @@ PRIVATE void pm_init()
   }
   printf(".\n");                               /* last process done */
 
-  /* Override some details. PM is somewhat special. */
-  mproc[PM_PROC_NR].mp_pid = PM_PID;           /* magically override pid */
-  mproc[PM_PROC_NR].mp_parent = PM_PROC_NR;    /* PM doesn't have parent */
+  /* Override some details. INIT, PM, FS and RS are somewhat special. */
+  mproc[PM_PROC_NR].mp_pid = PM_PID;           /* PM has magic pid */
+  mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR;  /* INIT is root */
+  sigfillset(&mproc[PM_PROC_NR].mp_ignore);    /* guard against signals */
+  sigfillset(&mproc[FS_PROC_NR].mp_sig2mess);  /* forward signals */
 
   /* Tell FS that no more system processes follow and synchronize. */
   mess.PR_PROC_NR = NONE;
index 26828cf86f52d24fd34ef741e188eb05841ed75a..0364e59757a957ae2f5b0a78256324217d0b1a62 100644 (file)
@@ -95,7 +95,7 @@ PUBLIC int do_getprocnr()
   int key_len;
   int s;
 
-  if (m_in.pid >= 0) {                         /* lookup process by pid */
+  if (m_in.pid >= 0) {                 /* lookup process by pid */
        for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
                if ((rmp->mp_flags & IN_USE) && (rmp->mp_pid==m_in.pid)) {
                        mp->mp_reply.procnr = (int) (rmp - mproc);
@@ -103,7 +103,7 @@ PUBLIC int do_getprocnr()
                } 
        }
        return(ESRCH);                  
-  } else if (m_in.namelen > 0) {               /* lookup process by name */
+  } else if (m_in.namelen > 0) {       /* lookup process by name */
        key_len = MIN(m_in.namelen, PROC_NAME_LEN);
        if (OK != (s=sys_datacopy(who, (vir_bytes) m_in.addr, 
                        SELF, (vir_bytes) search_key, key_len))) 
@@ -117,8 +117,9 @@ PUBLIC int do_getprocnr()
                } 
        }
        return(ESRCH);                  
-  } else {                             /* return own process number */
+  } else {                             /* return own/parent process number */
        mp->mp_reply.procnr = who;
+       mp->mp_reply.pprocnr = mp->mp_parent;  
   }
   return(OK);
 }
@@ -159,8 +160,8 @@ PUBLIC int do_reboot()
        return(EINVAL);
   }
 
+  tell_fs(REBOOT, 0, 0, 0);            /* tell FS to synchronize */
   check_sig(-1, SIGKILL);              /* kill all processes except init */
-  tell_fs(REBOOT,0,0,0);               /* tell FS to prepare for shutdown */
 
   /* Ask the kernel to abort. All system services, including the PM, will 
    * get a HARD_STOP notification. Await the notification in the main loop.
index 15b0e4fd2c3afe112de6bd2e59fae8872078a218..dbcd9d36ff00568ff450e581cfdad538345d0f07 100644 (file)
@@ -7,6 +7,7 @@
 #define namelen                m1_i2
 #define pid            m1_i1
 #define procnr         m1_i1
+#define pprocnr                m1_i2
 #define seconds                m1_i1
 #define sig            m6_i1
 #define stack_bytes    m1_i2
@@ -41,6 +42,7 @@
 /* The following names are synonyms for the variables in a reply message. */
 #define reply_res      m_type
 #define reply_res2     m2_i1
+#define reply_res3     m2_i2
 #define reply_ptr      m2_p1
 #define reply_mask     m2_l1   
 #define reply_trace    m2_l2   
index b2bc1a649f315354f1bfbe073049ea0f85183f4d..dee78d54614204c2d11fb88f2d66b450ac74c130 100644 (file)
@@ -257,12 +257,6 @@ sigset_t sig_map;
                id = 0; break;  /* broadcast to process group */
            case SIGKILL:
                id = -1; break; /* broadcast to all except INIT */
-#if DEAD_CODE
-           case SIGALRM:
-               if ((rmp->mp_flags & ALARM_ON) == 0) continue;
-               rmp->mp_flags &= ~ALARM_ON;
-               /* fall through */
-#endif
            default:
                id = proc_id;
                break;
index 1935279d23fe6bcd13e01983d35cc5687af9fe4c..866db003b10f2ccec34606d2be0a287c15b840bf 100644 (file)
@@ -113,9 +113,21 @@ int num;                   /* number to go with it */
  * defined constant. The process manager decides to shut down. This results 
  * in a HARD_STOP notification to all system processes to allow local cleanup.
  */
+  message m;
+  int s;
+
+  /* Switch to primary console and print panic message. */
+  check_sig(mproc[TTY_PROC_NR].mp_pid, SIGTERM);
   printf("PM panic (%s): %s", who, mess);
   if (num != NO_NUM) printf(": %d",num);
   printf("\n");
+
+  /* Allow for debug dumps if the IS server is available. */
+  m.m_type = PANIC_DUMPS;
+  if (OK == (s= nb_send(11, &m))) {
+      return;                          /* IS responsible for exit */
+  }
+  printf("Shutting down: IS is not answering: %d\n", s);
   sys_abort(RBT_PANIC);
 }
 
@@ -135,9 +147,13 @@ int what, p1, p2, p3;
  *      tell_fs(SETUID, proc, realuid, effuid)
  *      tell_fs(UNPAUSE, proc, signr, 0)
  *      tell_fs(STIME, time, 0, 0)
+ * Ignore this call if the FS is already dead, e.g. on shutdown.
  */
   message m;
 
+  if ((mproc[FS_PROC_NR].mp_flags & (IN_USE|ZOMBIE)) != IN_USE)
+      return;
+
   m.tell_fs_arg1 = p1;
   m.tell_fs_arg2 = p2;
   m.tell_fs_arg3 = p3;
index ae8b1673477703e0302df278d946833aad5a301c..296e1fd0033c99eb5772eff94a7d9e8b1bbe149c 100644 (file)
@@ -17,7 +17,7 @@ UTIL_LIBS = -lsys
 LIBS = -lsys -lsysutil 
 
 UTIL_OBJ = service.o
-OBJ = rs.o manager.o 
+OBJ = main.o manager.o 
 
 # build local binary
 all build:     $(SERVER) $(UTIL)
diff --git a/servers/rs/main.c b/servers/rs/main.c
new file mode 100644 (file)
index 0000000..d168ae9
--- /dev/null
@@ -0,0 +1,226 @@
+/* Reincarnation Server.  This servers starts new system services and detects
+ * they are exiting.   In case of errors, system services can be restarted.  
+ * The RS server periodically checks the status of all registered services
+ * services to see whether they are still alive.   The system services are 
+ * expected to periodically send a heartbeat message. 
+ * 
+ * Created:
+ *   Jul 22, 2005      by Jorrit N. Herder
+ */
+#include "rs.h"
+#include <minix/dmap.h>
+#include "../../kernel/const.h"
+#include "../../kernel/type.h"
+
+/* Declare some local functions. */
+FORWARD _PROTOTYPE(void init_server, (void)                            );
+FORWARD _PROTOTYPE(void get_work, (message *m)                         );
+FORWARD _PROTOTYPE(void reply, (int whom, int result)                  );
+FORWARD _PROTOTYPE(int do_getsysinfo, (message *m)                     );
+
+/* Data buffers to retrieve info during initialization. */
+PRIVATE struct boot_image image[NR_BOOT_PROCS];
+PUBLIC struct dmap dmap[NR_DEVICES];
+
+/*===========================================================================*
+ *                             main                                         *
+ *===========================================================================*/
+PUBLIC int main(void)
+{
+/* This is the main routine of this service. The main loop consists of 
+ * three major activities: getting new work, processing the work, and
+ * sending the reply. The loop never terminates, unless a panic occurs.
+ */
+  message m;                                   /* request message */
+  int call_nr, who;                            /* call number and caller */
+  int result;                                  /* result to return */
+  sigset_t sigset;                             /* system signal set */
+  int s;
+
+  /* Initialize the server, then go to work. */
+  init_server();       
+
+  /* Main loop - get work and do it, forever. */         
+  while (TRUE) {              
+
+      /* Wait for request message. */
+      get_work(&m);
+      who = m.m_source;
+      call_nr = m.m_type;
+
+      /* Now determine what to do.  Three types of requests are expected: 
+       * - Heartbeat messages (notifications from registered system services)
+       * - System notifications (POSIX signals or synchronous alarm)
+       * - User requests (control messages to manage system services)
+       */
+
+      /* Notification messages are control messages and do not need a reply.
+       * These include heartbeat messages and system notifications.
+       */
+      if (m.m_type & NOTIFY_MESSAGE) {
+          switch (call_nr) {
+          case SYN_ALARM:
+             do_period(&m);                    /* check drivers status */
+             continue;                         /* no reply is expected */
+          case SYS_SIG:
+              sigset = (sigset_t) m.NOTIFY_ARG;
+              if (sigismember(&sigset, SIGCHLD)) {
+                  do_exit(&m);
+              } 
+              if (sigismember(&sigset, SIGTERM) ||
+                  sigismember(&sigset, SIGKSTOP)) {
+                  /* Prevent restarting services. */
+                 do_shutdown(NULL);
+              }
+              continue;                                /* no reply is expected */
+         default:                              /* heartbeat notification */
+             printf("Got heartbeat from %d\n", who);
+             if (rproc_ptr[who] != NULL)       /* mark heartbeat time */ 
+                 rproc_ptr[who]->r_alive_tm = m.NOTIFY_TIMESTAMP;
+         }
+      }
+
+      /* If this is not a notification message, it is a normal request. 
+       * Handle the request and send a reply to the caller. 
+       */
+      else {   
+          switch(call_nr) {
+          case SRV_UP:
+              result = do_start(&m);
+              break;
+          case SRV_DOWN:
+              result = do_stop(&m);
+              break;
+          case SRV_SHUTDOWN:
+              result = do_shutdown(&m);
+              break;
+          case GETSYSINFO:
+             printf("RS got GETSYSINFO request from %d\n", m.m_source);
+              result = do_getsysinfo(&m);
+              break;
+          default: 
+              printf("Warning, RS got unexpected request %d from %d\n",
+                  m.m_type, m.m_source);
+              result = EINVAL;
+          }
+
+          /* Finally send reply message, unless disabled. */
+          if (result != EDONTREPLY) {
+              reply(who, result);
+          }
+      }
+  }
+}
+
+
+/*===========================================================================*
+ *                             init_server                                  *
+ *===========================================================================*/
+PRIVATE void init_server(void)
+{
+/* Initialize the reincarnation server. */
+  struct sigaction sa;
+  struct boot_image *ip;
+  int s,t;
+
+  /* Install signal handlers. Ask PM to transform signal into message. */
+  sa.sa_handler = SIG_MESS;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction(SIGCHLD,&sa,NULL)<0) panic("RS","sigaction failed", errno);
+  if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno);
+  if (sigaction(SIGABRT,&sa,NULL)<0) panic("RS","sigaction failed", errno);
+  if (sigaction(SIGHUP, &sa,NULL)<0) panic("RS","sigaction failed", errno);
+
+  /* Initialize the system process table. Use the boot image from the kernel
+   * and the device map from the FS to gather all needed information.
+   */
+  if ((s = sys_getimage(image)) != OK) 
+      panic("RS","warning: couldn't get copy of image table", s);
+  if ((s = getsysinfo(FS_PROC_NR, SI_DMAP_TAB, dmap)) < 0)
+      panic("RS","warning: couldn't get copy of dmap table", errno);
+  
+  /* Change working directory to /sbin, where the binaries for the programs
+   * in the system image are. 
+   */
+  chdir("/sbin/");
+  for (s=0; s< NR_BOOT_PROCS; s++) {
+      ip = &image[s];
+      if (ip->proc_nr >= 0) {
+          nr_in_use ++;
+          rproc[s].r_flags = IN_USE;
+          rproc[s].r_proc_nr = ip->proc_nr;
+          rproc[s].r_pid = getnpid(ip->proc_nr);
+         for(t=0; t< NR_DEVICES; t++)
+             if (dmap[t].dmap_driver == ip->proc_nr)
+                  rproc[s].r_dev_nr = t;
+          strcpy(rproc[s].r_cmd, ip->proc_name);
+          rproc[s].r_argc = 1;
+          rproc[s].r_argv[0] = rproc[s].r_cmd;
+          rproc[s].r_argv[1] = NULL;
+      }
+  }
+
+  /* Set alarm to periodically check driver status. */
+  if (OK != (s=sys_setalarm(HZ, 0)))
+      panic("RS", "couldn't set alarm", s);
+
+}
+
+
+/*===========================================================================*
+ *                             do_getsysinfo                                *
+ *===========================================================================*/
+PRIVATE int do_getsysinfo(m_ptr)
+message *m_ptr;
+{
+  vir_bytes src_addr, dst_addr;
+  int dst_proc;
+  size_t len;
+  int s;
+
+  switch(m_ptr->m1_i1) {
+  case SI_PROC_TAB:
+       src_addr = (vir_bytes) rproc;
+       len = sizeof(struct rproc) * NR_SYS_PROCS;
+       break; 
+  default:
+       return(EINVAL);
+  }
+
+  dst_proc = m_ptr->m_source;
+  dst_addr = (vir_bytes) m_ptr->m1_p1;
+  if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
+       return(s);
+  return(OK);
+}
+
+/*===========================================================================*
+ *                             get_work                                     *
+ *===========================================================================*/
+PRIVATE void get_work(m_in)
+message *m_in;                         /* pointer to message */
+{
+    int s;                             /* receive status */
+    if (OK != (s=receive(ANY, m_in)))  /* wait for message */
+        panic("RS","receive failed", s);
+}
+
+
+/*===========================================================================*
+ *                             reply                                        *
+ *===========================================================================*/
+PRIVATE void reply(who, result)
+int who;                               /* replyee */
+int result;                            /* report result */
+{
+    message m_out;                     /* reply message */
+    int s;                             /* send status */
+
+    m_out.m_type = result;             /* build reply message */
+    if (OK != (s=send(who, &m_out)))    /* send the message */
+        panic("RS", "unable to send reply", s);
+}
+
+
+
index 1a300fa2075c01cbdf60dcb9f97489b3f4f2a0ab..214e06f82f54b19f43ba4fdd09926f0ea5fe1c29 100644 (file)
@@ -1,10 +1,4 @@
-/* This file contains procedures to manage the system processes.
- *
- * The entry points into this file are
- *   do_start:
- *   do_stop:
- *   do_exit:          a child of this server exited
- *
+/*
  * Changes:
  *   Jul 22, 2005:     Created  (Jorrit N. Herder)
  */
 #include <sys/wait.h>
 #include <minix/dmap.h>
 
-extern int errno;
+/* Allocate variables. */
+struct rproc rproc[NR_SYS_PROCS];              /* system process table */
+struct rproc *rproc_ptr[NR_PROCS];             /* mapping for fast access */
+int nr_in_use;                                         /* number of services */
+extern int errno;                              /* error status */
 
-#define EXEC_FAILED    49              /* arbitrary, recognizable status */
-#define MAX_PATH_LEN    256            /* maximum path string length */
-#define MAX_ARGS_LEN    4096           /* maximum argument string length */
-#define MAX_ARG_COUNT   1              /* parsed arguments count */
+/* Prototypes for internal functions that do the hard work. */
+FORWARD _PROTOTYPE( int start_service, (struct rproc *rp) );
+FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp) );
 
-PRIVATE char command[MAX_PATH_LEN+1];
-PRIVATE char arg_buf[MAX_ARGS_LEN+1];
+PRIVATE int shutting_down = FALSE;
+
+#define EXEC_FAILED    49                      /* recognizable status */
 
 /*===========================================================================*
  *                             do_start                                     *
  *===========================================================================*/
-PUBLIC int do_start(message *m_ptr)
+PUBLIC int do_start(m_ptr)
+message *m_ptr;                                        /* request message pointer */
 {
-  message m;
-  int child_proc_nr;
-  int major_nr;
-  enum dev_style dev_style;
-  pid_t child_pid;
-  char *args[MAX_ARG_COUNT+1];
-  int s;
+/* A request was made to start a new system service. Dismember the request 
+ * message and gather all information needed to start the service. Starting
+ * is done by a helper routine.
+ */
+  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 */
+  enum dev_style dev_style;                    /* device style */
+  int s;                                       /* status variable */
 
-  /* Obtain command name and parameters. */
-  if (m_ptr->SRV_PATH_LEN > MAX_PATH_LEN) return(E2BIG);
-  if (OK != (s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->SRV_PATH_ADDR, 
-       SELF, (vir_bytes) command, m_ptr->SRV_PATH_LEN))) return(s);
-  command[m_ptr->SRV_PATH_LEN] = '\0';
-  if (command[0] != '/') return(EINVAL);
-
-  args[0] = command;
-  if (m_ptr->SRV_ARGS_LEN > 0) {
-      if (m_ptr->SRV_ARGS_LEN > MAX_ARGS_LEN) return(E2BIG);
-      if (OK != (s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->SRV_ARGS_ADDR, 
-       SELF, (vir_bytes) arg_buf, m_ptr->SRV_ARGS_LEN))) return(s);
-      arg_buf[m_ptr->SRV_ARGS_LEN] = '\0';
-      args[1] = &arg_buf[0];
-      args[2] = NULL;
-  } else {
-      args[1] = NULL;
+  /* 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 & IN_USE)              /* check if available */
+         break;
   }
-  
-  /* Now try to execute the new system service. Fork a new process. The child
-   * process will be inhibited from running by the NO_PRIV flag. Only let the
-   * child run once its privileges have been set by the parent.
+  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 ((s = _taskcall(PM_PROC_NR, FORK, &m)) < 0)       /* use raw interface */
-       report("SM", "_taskcall to PM failed", s);      /* to get both */
-  child_pid = m.m_type;                                        /* - child's pid */
-  child_proc_nr = m.PR_PROC_NR;                                /* - process nr */
+  if (m_ptr->SRV_CMD_LEN > MAX_COMMAND_LEN) return(E2BIG);
+  if (OK!=(s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->SRV_CMD_ADDR, 
+       SELF, (vir_bytes) rp->r_cmd, m_ptr->SRV_CMD_LEN))) return(s);
+  rp->r_cmd[m_ptr->SRV_CMD_LEN] = '\0';                /* ensure it is terminated */
+  if (rp->r_cmd[0] != '/') return(EINVAL);     /* insist on absolute path */
 
-  /* Now branch for parent and child process, and check for error. */
-  switch(child_pid) {                                  /* see fork(2) */
-  case 0:                                              /* child process */
-      execve(command, args, NULL);                     /* POSIX exec */
-      report("SM", "warning, exec() failed", errno);   /* shouldn't happen */
-      exit(EXEC_FAILED);                               /* terminate child */
-      break;
-  case -1:                                             /* fork failed */
-      report("SM", "warning, fork() failed", errno);   /* shouldn't happen */
-      return(errno);
-  default:                                             /* parent process */
-      if ((major_nr = m_ptr->SRV_DEV_MAJOR) > 0) {     /* set driver map */
-          dev_style = STYLE_DEV;
-          if ((s=mapdriver(child_proc_nr, major_nr, dev_style)) < 0) {
-            
-#if VERBOSE
-      printf("SM: '%s %s', major %d, pid %d, proc_nr %d", 
-          command, arg_buf, major_nr, child_pid, child_proc_nr);
-#endif
-             report("SM", "couldn't map driver", errno);
-          }
+  /* 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 */
       }
-      if ((s = _taskcall(SYSTEM, SYS_PRIVCTL, &m)) < 0) /* set privileges */
-          report("SM", "_taskcall to SYSTEM failed", s); /* to let child run */
-#if VERBOSE
-      printf("SM: started '%s %s', major %d, pid %d, proc_nr %d", 
-          command, arg_buf, major_nr, child_pid, child_proc_nr);
-#endif
-                                                       /* update tables */
+      cmd_ptr ++;                              /* continue parsing */
   }
-  return(OK);
+  rp->r_argv[arg_count] = NULL;                        /* end with NULL pointer */
+  rp->r_argc = arg_count;
+
+  /* Check if a heartbeat period was given. */
+  rp->r_period = m_ptr->SRV_PERIOD;
+  rp->r_dev_nr = m_ptr->SRV_DEV_MAJOR;
+  rp->r_dev_style = STYLE_DEV; 
+  
+  /* All information was gathered. Now try to start the system service. */
+  return(start_service(rp));
 }
 
 
@@ -105,19 +92,42 @@ PUBLIC int do_start(message *m_ptr)
  *===========================================================================*/
 PUBLIC int do_stop(message *m_ptr)
 {
-  return(ENOSYS);
+  register struct rproc *rp;
+  pid_t pid = (pid_t) m_ptr->SRV_PID;
+
+  for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
+      if (rp->r_flags & IN_USE && rp->r_pid == pid) {
+         printf("stopping %d (%d)\n", pid, m_ptr->SRV_PID);
+         stop_service(rp);
+         return(OK);
+      }
+  }
+  printf("not found %d (%d)\n", pid, m_ptr->SRV_PID);
+  return(ESRCH);
+}
+
+
+/*===========================================================================*
+ *                             do_shutdown                                  *
+ *===========================================================================*/
+PUBLIC int do_shutdown(message *m_ptr)
+{
+  /* Set flag so that RS server knows services shouldn't be restarted. */
+  shutting_down = TRUE;
+  return(OK);
 }
 
 /*===========================================================================*
  *                             do_exit                                      *
  *===========================================================================*/
-PUBLIC int do_exit(message *m_ptr)
+PUBLIC void do_exit(message *m_ptr)
 {
+  register struct rproc *rp;
   pid_t exit_pid;
   int exit_status;
 
 #if VERBOSE
-  printf("SM: got SIGCHLD signal, doing wait to get exited child.\n");
+  printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
 #endif
 
   /* See which child exited and what the exit status is. This is done in a
@@ -128,16 +138,192 @@ PUBLIC int do_exit(message *m_ptr)
   while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) {
 
 #if VERBOSE
-       printf("SM: pid %d,", exit_pid); 
-       if (WIFSIGNALED(exit_status)) {
-               printf("killed, signal number %d\n", WTERMSIG(exit_status));
-       } else if (WIFEXITED(exit_status)) {
-               printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
-       }
+      printf("RS: proc %d, pid %d,", rp->r_proc_nr, exit_pid); 
+      if (WIFSIGNALED(exit_status)) {
+          printf("killed, signal number %d\n", WTERMSIG(exit_status));
+      } 
+      else if (WIFEXITED(exit_status)) {
+          printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
+      }
 #endif
 
+      /* Search the system process table to see who exited. 
+       * This should always succeed. 
+       */
+      for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
+          if ((rp->r_flags & IN_USE) && rp->r_pid == exit_pid) {
+
+             printf("Slot found!\n");
+              rproc_ptr[rp->r_proc_nr] = NULL;         /* invalidate */
+
+              if ((rp->r_flags & EXIT_PENDING) || shutting_down) {
+                 printf("Expected exit. Doing nothing.\n");
+                 rp->r_flags = 0;                      /* release slot */
+                 rproc_ptr[rp->r_proc_nr] = NULL;
+             }
+              else if (WIFEXITED(exit_status) &&
+                     WEXITSTATUS(exit_status) == EXEC_FAILED) {
+                 printf("Exit because EXEC() failed. Doing nothing.\n");
+                 rp->r_flags = 0;                      /* release slot */
+              }
+             else {
+                 printf("Unexpected exit. Restarting %s\n", rp->r_cmd);
+                 start_service(rp);                    /* restart */
+              }
+             break;
+         }
+      }
   }
-  return(OK);
 }
 
+/*===========================================================================*
+ *                             do_period                                    *
+ *===========================================================================*/
+PUBLIC void do_period(m_ptr)
+message *m_ptr;
+{
+  register struct rproc *rp;
+  clock_t now = m_ptr->NOTIFY_TIMESTAMP;
+  int s;
+
+  /* Search system services table. Only check slots that are in use. */
+  for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
+      if (rp->r_flags & IN_USE) {
+       
+         /* If the service has a period assigned check its status. */
+         if (rp->r_period > 0) {
+
+             /* Check if an answer to a status request is still pending. If 
+              * the driver didn't respond within time, kill it to simulate 
+              * a crash. The failure will be detected and the service will 
+              * be restarted automatically.
+              */
+              if (rp->r_alive_tm < rp->r_check_tm) { 
+                 if (now - rp->r_alive_tm > 2*rp->r_period) { 
+#if VERBOSE
+                      printf("RS: service %d reported late\n", rp->r_proc_nr); 
+#endif
+                      kill(rp->r_pid, SIGKILL);                /* simulate crash */
+                 }
+             }
+
+             /* No answer pending. Check if a period expired since the last
+              * check and, if so request the system service's status.
+              */
+             else if (now - rp->r_check_tm > rp->r_period) {
+#if VERBOSE
+                  printf("RS: status request sent to %d\n", rp->r_proc_nr); 
+#endif
+                 notify(rp->r_proc_nr);                /* request status */
+                 rp->r_check_tm = now;                 /* mark time */
+              }
+          }
+
+         /* If the service was signaled with a SIGTERM and fails to respond,
+          * kill the system service with a SIGKILL signal.
+          */
+         if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*HZ) {
+              kill(rp->r_pid, SIGKILL);                /* terminate */
+         }
+      }
+  }
+
+  /* Reschedule a synchronous alarm for the next period. */
+  if (OK != (s=sys_setalarm(HZ, 0)))
+      panic("RS", "couldn't set alarm", s);
+}
+
+
+/*===========================================================================*
+ *                             start_service                                *
+ *===========================================================================*/
+PRIVATE int start_service(rp)
+struct rproc *rp;
+{
+/* Try to execute the given system service. Fork a new process. The child
+ * process will be inhibited from running by the NO_PRIV flag. Only let the
+ * child run once its privileges have been set by the parent.
+ */
+  int child_proc_nr;                           /* child process slot */
+  pid_t child_pid;                             /* child's process id */
+  int s;
+  message m;
+
+  /* Now fork and branch for parent and child process (and check for error). */
+  child_pid = fork();
+  switch(child_pid) {                                  /* see fork(2) */
+  case -1:                                             /* fork failed */
+      report("RS", "warning, fork() failed", errno);   /* shouldn't happen */
+      return(errno);                                   /* return error */
+
+  case 0:                                              /* child process */
+      execve(rp->r_argv[0], rp->r_argv, NULL);         /* POSIX execute */
+      report("RS", "warning, exec() failed", errno);   /* shouldn't happen */
+      exit(EXEC_FAILED);                               /* terminate child */
+
+  default:                                             /* parent process */
+      child_proc_nr = getnprocnr(child_pid);           /* get child slot */ 
+      break;                                           /* continue below */
+  }
+
+  /* Only the parent process (the RS server) gets to this point. The child
+   * is still inhibited from running because it's privilege structure is
+   * not yet set. First try to set the device driver mapping at the FS.
+   */
+  if (rp->r_dev_nr > 0) {                              /* set driver map */
+      if ((s=mapdriver(child_proc_nr, rp->r_dev_nr, rp->r_dev_style)) < 0) {
+          report("RS", "couldn't map driver", errno);
+          kill(child_pid, SIGKILL);                    /* kill driver */
+          rp->r_flags |= EXIT_PENDING;                 /* expect exit */
+         return(s);                                    /* return error */
+      }
+  }
+
+  /* The device driver mapping has been set, or the service was not a driver.
+   * Now, set the privilege structure for the child process to let is run.
+   * This should succeed: we tested number in use above.
+   */
+  m.PR_PROC_NR = child_proc_nr;
+  if ((s = _taskcall(SYSTEM, SYS_PRIVCTL, &m)) < 0) {  /* set privileges */
+      report("RS","call to SYSTEM failed", s);         /* to let child run */
+      kill(child_pid, SIGKILL);                                /* kill driver */
+      rp->r_flags |= EXIT_PENDING;                     /* expect exit */
+      return(s);                                       /* return error */
+  }
+
+#if VERBOSE
+      printf("RS: started '%s', major %d, pid %d, proc_nr %d", 
+          rp->r_cmd, rp->r_dev_nr, child_pid, child_proc_nr);
+#endif
+
+  /* The system service now has been successfully started. Update the rest
+   * of the system process table that is maintain by the RS server. The only 
+   * thing that can go wrong now, is that execution fails at the child. If 
+   * that's the case, the child will exit. 
+   */
+  rp->r_flags = IN_USE;                                /* mark slot in use */
+  rp->r_proc_nr = child_proc_nr;               /* set child details */
+  rp->r_pid = child_pid;
+  rp->r_check_tm = 0;                          /* not check yet */
+  getuptime(&rp->r_alive_tm);                  /* currently alive */
+  rp->r_stop_tm = 0;                           /* not exiting yet */
+  rproc_ptr[child_proc_nr] = rp;               /* mapping for fast access */
+  return(OK);
+}
 
+/*===========================================================================*
+ *                             stop_service                                 *
+ *===========================================================================*/
+PRIVATE int stop_service(rp)
+struct rproc *rp;
+{
+  printf("RS tries to stop %s (pid %d)\n", rp->r_cmd, rp->r_pid);
+  /* Try to stop the system service. First send a SIGTERM signal to ask the
+   * system service to terminate. If the service didn't install a signal 
+   * handler, it will be killed. If it did and ignores the signal, we'll
+   * find out because we record the time here and send a SIGKILL.
+   */
+  rp->r_flags |= EXIT_PENDING;                 /* expect exit */
+  kill(rp->r_pid, SIGTERM);                    /* first try friendly */
+  getuptime(&rp->r_stop_tm);                   /* record current time */
+}
index d118c3c4a35dc71d84e80ca45e18abc31fb67cf9..26e7cc1155bfc3f6626e2678eeb6107e35495bff 100644 (file)
@@ -1,11 +1,13 @@
 /* Function prototypes. */
 
-/* sm.c */
+/* main.c */
 _PROTOTYPE( int main, (void));
 
 /* manager.c */
-_PROTOTYPE( int do_exit, (message *m));
 _PROTOTYPE( int do_start, (message *m));
 _PROTOTYPE( int do_stop, (message *m));
+_PROTOTYPE( int do_shutdown, (message *m));
+_PROTOTYPE( void do_period, (message *m));
+_PROTOTYPE( void do_exit, (message *m));
 
 
diff --git a/servers/rs/rproc.h b/servers/rs/rproc.h
new file mode 100644 (file)
index 0000000..b60fb63
--- /dev/null
@@ -0,0 +1,44 @@
+/* This table has one slot per system process.  It contains information for
+ * servers and driver needed by the reincarnation server to keep track of 
+ * each process' status. 
+ */
+
+/* Space reserved for program and arguments. */
+#define MAX_COMMAND_LEN     512                /* maximum argument string length */
+#define MAX_NR_ARGS          4         /* maximum number of arguments */
+
+/* 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;               /* process slot number */
+  pid_t r_pid;                 /* process id */
+  dev_t r_dev_nr;              /* major device number */
+  int r_dev_style;             /* device style */
+
+  unsigned r_flags;            /* status and policy flags */
+
+  long r_period;               /* heartbeat period (or zero) */
+  clock_t r_check_tm;          /* timestamp of last check */
+  clock_t r_alive_tm;          /* timestamp of last heartbeat */
+  clock_t r_stop_tm;           /* timestamp of SIGTERM signal */
+
+  char r_cmd[MAX_COMMAND_LEN]; /* raw command plus arguments */
+  char *r_argv[MAX_NR_ARGS+2];  /* parsed arguments vector */
+  int r_argc;                          /* number of arguments */
+} rproc[NR_SYS_PROCS];
+
+/* Mapping for fast access to the system process table. */ 
+extern struct rproc *rproc_ptr[NR_PROCS];
+extern int nr_in_use;
+
+/* Flag values. */
+#define IN_USE          0x001  /* set when process slot is in use */
+#define EXIT_PENDING    0x002  /* set when exit is expected */
+#define STAT_PENDING    0x003   /* set when heartbeat is expected */
+
+/* Magic process table addresses. */
+#define BEG_RPROC_ADDR (&rproc[0])
+#define END_RPROC_ADDR (&rproc[NR_SYS_PROCS])
+#define NIL_RPROC ((struct mproc *) 0)
+
diff --git a/servers/rs/rs.c b/servers/rs/rs.c
deleted file mode 100644 (file)
index 31cf356..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Reincarnation Server.  This servers starts new system services and detects
- * they are exiting.  In case of errors, system services can be restarted.  
- * 
- * Created:
- *   Jul 22, 2005      by Jorrit N. Herder
- */
-
-#include "rs.h"
-
-/* Set debugging level to 0, 1, or 2 to see no, some, all debug output. */
-#define DEBUG_LEVEL    1
-#define DPRINTF                if (DEBUG_LEVEL > 0) printf
-
-/* Allocate space for the global variables. */
-message m_in;          /* the input message itself */
-message m_out;         /* the output message used for reply */
-int who;               /* caller's proc number */
-int callnr;            /* system call number */
-
-/* Declare some local functions. */
-FORWARD _PROTOTYPE(void init_server, (void)                            );
-FORWARD _PROTOTYPE(void get_work, (void)                               );
-FORWARD _PROTOTYPE(void reply, (int whom, int result)                  );
-
-/*===========================================================================*
- *                             main                                         *
- *===========================================================================*/
-PUBLIC int main(void)
-{
-/* This is the main routine of this service. The main loop consists of 
- * three major activities: getting new work, processing the work, and
- * sending the reply. The loop never terminates, unless a panic occurs.
- */
-  int result;                 
-  sigset_t sigset;
-
-  /* Initialize the server, then go to work. */
-  init_server();
-
-  /* Main loop - get work and do it, forever. */         
-  while (TRUE) {              
-
-      /* Wait for incoming message, sets 'callnr' and 'who'. */
-      get_work();
-
-      switch (callnr) {
-      case SYS_SIG:
-          /* Signals are passed by means of a notification message from SYSTEM. 
-           * Extract the map of pending signals from the notification argument.
-           */ 
-          sigset = (sigset_t) m_in.NOTIFY_ARG;
-  
-          if (sigismember(&sigset, SIGCHLD)) {
-                /* A child of this server exited. Take action. */    
-                do_exit(&m_in);
-          } 
-          if (sigismember(&sigset, SIGUSR1)) {
-                do_start(&m_in);
-          } 
-          if (sigismember(&sigset, SIGTERM)) {
-                /* Nothing to do on shutdown. */    
-          } 
-          if (sigismember(&sigset, SIGKSTOP)) {
-                /* Nothing to do on shutdown. */    
-          }
-          continue;
-      case SRV_UP:
-          result = do_start(&m_in);
-          break;
-      case SRV_DOWN:
-          result = do_stop(&m_in);
-          break;
-      default: 
-          printf("Warning, RS got unexpected request %d from %d\n",
-               m_in.m_type, m_in.m_source);
-          result = EINVAL;
-      }
-
-      /* Finally send reply message, unless disabled. */
-      if (result != EDONTREPLY) {
-          reply(who, result);
-      }
-  }
-}
-
-
-/*===========================================================================*
- *                             init_server                                  *
- *===========================================================================*/
-PRIVATE void init_server(void)
-{
-/* Initialize the reincarnation server. */
-  struct sigaction sa;
-
-  /* Install signal handlers. Ask PM to transform signal into message. */
-  sa.sa_handler = SIG_MESS;
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-  if (sigaction(SIGCHLD, &sa, NULL)<0) panic("RS","sigaction failed", errno);
-  if (sigaction(SIGTERM, &sa, NULL)<0) panic("RS","sigaction failed", errno);
-  if (sigaction(SIGABRT, &sa, NULL)<0) panic("RS","sigaction failed", errno);
-  if (sigaction(SIGHUP,  &sa, NULL)<0) panic("RS","sigaction failed", errno);
-}
-
-
-/*===========================================================================*
- *                             get_work                                     *
- *===========================================================================*/
-PRIVATE void get_work()
-{
-    int status = 0;
-    status = receive(ANY, &m_in);   /* this blocks until message arrives */
-    if (OK != status)
-        panic("RS","failed to receive message!", status);
-    who = m_in.m_source;        /* message arrived! set sender */
-    callnr = m_in.m_type;       /* set function call number */
-}
-
-
-/*===========================================================================*
- *                             reply                                        *
- *===========================================================================*/
-PRIVATE void reply(who, result)
-int who;                               /* destination */
-int result;                            /* report result to replyee */
-{
-    int send_status;
-    m_out.m_type = result;             /* build reply message */
-    send_status = send(who, &m_out);    /* send the message */
-    if (OK != send_status)
-        panic("RS", "unable to send reply!", send_status);
-}
-
-
-
index a4c51aef2e9fabf7beb056929bfc52b8672ef120..edd81fb51326f6c3c1e832c24423838ad4ff4917 100644 (file)
@@ -7,13 +7,14 @@
 #define _SYSTEM            1    /* get OK and negative error codes */
 #define _MINIX             1   /* tell headers to include MINIX stuff */
 
-#define VERBOSE                0       /* display diagnostics */
+#define VERBOSE                   1    /* display diagnostics */
 
 #include <ansi.h>
 #include <sys/types.h>
 #include <limits.h>
 #include <errno.h>
 #include <signal.h>
+#include <unistd.h>
 
 #include <minix/callnr.h>
 #include <minix/config.h>
@@ -32,4 +33,5 @@
 #include <signal.h>
 
 #include "proto.h"
+#include "rproc.h"
 
index 8719ca9de23c344525f20d975773f736a3dc128b..c2a5b120f92e5dd80caad50b56db399e59f3f757 100644 (file)
@@ -23,6 +23,7 @@
 PRIVATE char *known_requests[] = {
   "up", 
   "down",
+  "shutdown", 
   "catch for illegal requests"
 };
 #define ILLEGAL_REQUEST  sizeof(known_requests)/sizeof(char *)
@@ -38,42 +39,49 @@ extern int errno;
 #define ARG_NAME       0               /* own application name */
 #define ARG_REQUEST    1               /* request to perform */
 #define ARG_PATH       2               /* binary of system service */
+#define ARG_PID                2               /* pid of system service */
 
-#define MIN_ARG_COUNT  3               /* minimum number of arguments */
+#define MIN_ARG_COUNT  2               /* require an action */
 
 #define ARG_ARGS       "-args"         /* list of arguments to be passed */
 #define ARG_DEV                "-dev"          /* major device number for drivers */
 #define ARG_PRIV       "-priv"         /* required privileges */
+#define ARG_PERIOD     "-period"       /* heartbeat period in ticks */
 
 /* 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_path;
 PRIVATE char *req_args;
 PRIVATE int req_major;
+PRIVATE long req_period;
 PRIVATE char *req_priv;
 
+/* Buffer to build "/command arg1 arg2 ..." string to pass to RS server. */
+PRIVATE char command[4096];    
+
 /* An error occurred. Report the problem, print the usage, and exit. 
  */
 PRIVATE void print_usage(char *app_name, char *problem) 
 {
   printf("Warning, %s\n", problem);
   printf("Usage:\n");
-  printf("    %s <request> <binary> [%s <args>] [%s <special>]\n", 
-       app_name, ARG_ARGS, ARG_DEV);
+  printf("    %s up <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 shutdown\n", app_name);
   printf("\n");
 }
 
-/* An unexpected, unrecoverable error occurred. Report and exit. 
+/* A request to the RS server failed. Report and exit. 
  */
-PRIVATE void panic(char *app_name, char *mess, int num) 
+PRIVATE void failure(int num) 
 {
-  printf("Panic in %s: %s", app_name, mess);
-  if (num != NO_NUM) printf(": %d", num);
-  printf("\n");
-  exit(EGENERIC);
+  printf("Request to RS failed: %s (%d)\n", strerror(num), num);
+  exit(num);
 }
 
 
@@ -83,10 +91,12 @@ PRIVATE void panic(char *app_name, char *mess, int num)
 PRIVATE int parse_arguments(int argc, char **argv)
 {
   struct stat stat_buf;
+  char *hz;
+  int req_nr;
   int i;
 
   /* Verify argument count. */ 
-  if (! argc >= MIN_ARG_COUNT) {
+  if (argc < MIN_ARG_COUNT) {
       print_usage(argv[ARG_NAME], "wrong number of arguments");
       exit(EINVAL);
   }
@@ -100,52 +110,85 @@ PRIVATE int parse_arguments(int argc, char **argv)
       exit(ENOSYS);
   }
 
-  /* Verify the name of the binary of the system service. */
-  req_path = argv[ARG_PATH];
-  if (req_path[0] != '/') {
-      print_usage(argv[ARG_NAME], "binary should be absolute path");
-      exit(EINVAL);
-  }
-  if (stat(req_path, &stat_buf) == -1) {
-      print_usage(argv[ARG_NAME], "couldn't get status of binary");
-      exit(errno);
-  }
-  if (! (stat_buf.st_mode & S_IFREG)) {
-      print_usage(argv[ARG_NAME], "binary is not a regular file");
-      exit(EINVAL);
-  }
+  req_nr = SRV_RQ_BASE + req_type;
+  if (req_nr == SRV_UP) {
+
+      /* Verify argument count. */ 
+      if (argc - 1 < ARG_PATH) {
+          print_usage(argv[ARG_NAME], "action requires a binary to start");
+          exit(EINVAL);
+      }
 
-  /* Check optional arguments that come in pairs like "-args arglist". */
-  for (i=MIN_ARG_COUNT; i<argc; i=i+2) {
-      if (! (i+1 < argc)) {
-          print_usage(argv[ARG_NAME], "optional argument not complete");
+      /* Verify the name of the binary of the system service. */
+      req_path = argv[ARG_PATH];
+      if (req_path[0] != '/') {
+          print_usage(argv[ARG_NAME], "binary should be absolute path");
           exit(EINVAL);
       }
-      if (strcmp(argv[i], ARG_ARGS)==0) {
-          req_args = argv[i+1];
+      if (stat(req_path, &stat_buf) == -1) {
+          print_usage(argv[ARG_NAME], "couldn't get status of binary");
+          exit(errno);
+      }
+      if (! (stat_buf.st_mode & S_IFREG)) {
+          print_usage(argv[ARG_NAME], "binary is not a regular file");
+          exit(EINVAL);
       }
-      else if (strcmp(argv[i], ARG_DEV)==0) {
-          if (stat(argv[i+1], &stat_buf) == -1) {
-              print_usage(argv[ARG_NAME], "couldn't get status of device node");
-              exit(errno);
+
+      /* Check optional arguments that come in pairs like "-args arglist". */
+      for (i=MIN_ARG_COUNT+1; i<argc; i=i+2) {
+          if (! (i+1 < argc)) {
+              print_usage(argv[ARG_NAME], "optional argument not complete");
+              exit(EINVAL);
+          }
+          if (strcmp(argv[i], ARG_ARGS)==0) {
+              req_args = argv[i+1];
+          }
+          else if (strcmp(argv[i], ARG_PERIOD)==0) {
+             req_period = strtol(argv[i+1], &hz, 10);
+             if (strcmp(hz,"HZ")==0) req_period *= HZ;
+             if (req_period < 1) {
+                  print_usage(argv[ARG_NAME], "period is at least be one tick");
+                  exit(EINVAL);
+             }
+          }
+          else if (strcmp(argv[i], ARG_DEV)==0) {
+              if (stat(argv[i+1], &stat_buf) == -1) {
+                  print_usage(argv[ARG_NAME], "couldn't get status of device");
+                  exit(errno);
+              }
+             if ( ! (stat_buf.st_mode & (S_IFBLK | S_IFCHR))) {
+                  print_usage(argv[ARG_NAME], "special file is not a device node");
+                  exit(EINVAL);
+                     } 
+              req_major = (stat_buf.st_rdev >> MAJOR) & BYTE;
+          }
+          else if (strcmp(argv[i], ARG_ARGS)==0) {
+              req_priv = argv[i+1];
           }
-         if ( ! (stat_buf.st_mode & (S_IFBLK | S_IFCHR))) {
-              print_usage(argv[ARG_NAME], "special file is not a device node");
+          else {
+              print_usage(argv[ARG_NAME], "unknown optional argument given");
               exit(EINVAL);
-         } 
-          req_major = (stat_buf.st_rdev >> MAJOR) & BYTE;
+          }
       }
-      else if (strcmp(argv[i], ARG_ARGS)==0) {
-          req_priv = argv[i+1];
+  }
+  else if (req_nr == SRV_DOWN) {
+
+      /* Verify argument count. */ 
+      if (argc - 1 < ARG_PID) {
+          print_usage(argv[ARG_NAME], "action requires a pid to stop");
+          exit(EINVAL);
       }
-      else {
-          print_usage(argv[ARG_NAME], "unknown optional argument given");
+      if (! (req_pid = atoi(argv[ARG_PID])) > 0) {
+          print_usage(argv[ARG_NAME], "pid must be greater than zero");
           exit(EINVAL);
       }
+  } 
+  else if (req_nr == SRV_SHUTDOWN) {
+       /* no extra arguments required */
   }
 
   /* Return the request number if no error were found. */
-  return(i);
+  return(req_nr);
 }
 
 
@@ -169,17 +212,29 @@ PUBLIC int main(int argc, char **argv)
    */
   switch(req_type+SRV_RQ_BASE) {
   case SRV_UP:
-      m.SRV_PATH_ADDR = req_path;
-      m.SRV_PATH_LEN = strlen(req_path);
-      m.SRV_ARGS_ADDR = req_args;
-      m.SRV_ARGS_LEN = strlen(req_args);
+      /* 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);
+
+      /* Build request message and send the request. */
+      m.SRV_CMD_ADDR = command;
+      m.SRV_CMD_LEN = strlen(command);
       m.SRV_DEV_MAJOR = req_major;
+      m.SRV_PERIOD = req_period;
       if (OK != (s=_taskcall(RS_PROC_NR, SRV_UP, &m))) 
-          panic(argv[ARG_NAME], "sendrec to manager server failed", s);
+          failure(s);
       result = m.m_type;
       break;
   case SRV_DOWN:
-  case SRV_STATUS:
+      m.SRV_PID = req_pid;
+      if (OK != (s=_taskcall(RS_PROC_NR, SRV_DOWN, &m))) 
+          failure(s);
+      break;
+  case SRV_SHUTDOWN:
+      if (OK != (s=_taskcall(RS_PROC_NR, SRV_SHUTDOWN, &m))) 
+          failure(s);
+      break;
   default:
       print_usage(argv[ARG_NAME], "request is not yet supported");
       result = EGENERIC;