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).
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 */
}
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)
#include "is.h"
-#define NHOOKS 15
+#define NHOOKS 17
struct hook_entry {
int key;
{ 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" },
};
/*===========================================================================*
return name;
}
+
+PUBLIC void reboot_dmp(void)
+{
+ if (sys_panic) sys_abort(RBT_HALT);
+}
+
+
PUBLIC void mapping_dmp(void)
{
int h;
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';
--- /dev/null
+/* 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);
+}
+
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 */
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 */
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;
}
/* 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. */
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;
/* 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) );
_PROTOTYPE( void dtab_dmp, (void) );
_PROTOTYPE( void fproc_dmp, (void) );
+/* dmp_rs.c */
+_PROTOTYPE( void rproc_dmp, (void) );
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:
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;
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)
}
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;
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);
}
}
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)))
}
}
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);
}
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.
#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
/* 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
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;
* 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);
}
* 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;
LIBS = -lsys -lsysutil
UTIL_OBJ = service.o
-OBJ = rs.o manager.o
+OBJ = main.o manager.o
# build local binary
all build: $(SERVER) $(UTIL)
--- /dev/null
+/* 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);
+}
+
+
+
-/* 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));
}
*===========================================================================*/
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
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 */
+}
/* 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));
--- /dev/null
+/* 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)
+
+++ /dev/null
-/* 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);
-}
-
-
-
#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>
#include <signal.h>
#include "proto.h"
+#include "rproc.h"
PRIVATE char *known_requests[] = {
"up",
"down",
+ "shutdown",
"catch for illegal requests"
};
#define ILLEGAL_REQUEST sizeof(known_requests)/sizeof(char *)
#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);
}
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);
}
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);
}
*/
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;