New signal handling behaviour at PM (services can be killed).

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).
This commit is contained in:
Jorrit Herder 2005-10-12 15:07:38 +00:00
parent 46678bdb7f
commit 5a9dec8bd2
22 changed files with 787 additions and 301 deletions

View 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 */
}

View 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)

View 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;

View 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';

62
servers/is/dmp_rs.c Normal file
View file

@ -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);
}

View 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 */

View 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;

View 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) );

View 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:

View 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;

View 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.

View 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

View 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;

View 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;

View 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)

226
servers/rs/main.c Normal file
View file

@ -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);
}

View 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)
*/
@ -15,88 +9,81 @@
#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 */
}

View 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));

44
servers/rs/rproc.h Normal file
View file

@ -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)

View file

@ -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);
}

View 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"

View 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) {
/* 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 argument count. */
if (argc - 1 < ARG_PATH) {
print_usage(argv[ARG_NAME], "action requires a binary to start");
exit(EINVAL);
}
if (strcmp(argv[i], ARG_ARGS)==0) {
req_args = argv[i+1];
/* 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);
}
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);
}
if ( ! (stat_buf.st_mode & (S_IFBLK | S_IFCHR))) {
print_usage(argv[ARG_NAME], "special file is not a device node");
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);
}
/* 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);
}
req_major = (stat_buf.st_rdev >> MAJOR) & BYTE;
}
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];
}
else {
print_usage(argv[ARG_NAME], "unknown optional argument given");
exit(EINVAL);
}
}
else if (strcmp(argv[i], ARG_ARGS)==0) {
req_priv = argv[i+1];
}
else {
print_usage(argv[ARG_NAME], "unknown optional argument given");
}
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);
}
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;