2005-10-12 17:07:38 +02:00
|
|
|
/*
|
2005-07-26 15:08:57 +02:00
|
|
|
* Changes:
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
* Nov 22, 2009: added basic live update support (Cristiano Giuffrida)
|
2009-12-02 10:54:50 +01:00
|
|
|
* Mar 02, 2009: Extended isolation policies (Jorrit N. Herder)
|
2005-07-26 15:08:57 +02:00
|
|
|
* Jul 22, 2005: Created (Jorrit N. Herder)
|
|
|
|
*/
|
|
|
|
|
2005-10-20 22:31:18 +02:00
|
|
|
#include "inc.h"
|
2008-02-21 17:20:22 +01:00
|
|
|
#include <ctype.h>
|
2006-05-11 16:58:33 +02:00
|
|
|
#include <fcntl.h>
|
2005-07-26 15:08:57 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
2006-05-11 16:58:33 +02:00
|
|
|
#include <sys/stat.h>
|
2005-07-26 15:08:57 +02:00
|
|
|
#include <sys/wait.h>
|
2009-09-21 16:49:04 +02:00
|
|
|
#include <sys/vm.h>
|
2009-09-21 17:25:15 +02:00
|
|
|
#include <minix/vm.h>
|
2006-05-11 16:58:33 +02:00
|
|
|
#include <lib.h>
|
2005-07-26 15:08:57 +02:00
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
#include <minix/sysutil.h>
|
2005-07-26 15:08:57 +02:00
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
/* Prototypes for internal functions that do the hard work. */
|
2009-12-02 10:54:50 +01:00
|
|
|
FORWARD _PROTOTYPE( int caller_is_root, (endpoint_t endpoint) );
|
|
|
|
FORWARD _PROTOTYPE( int caller_can_control, (endpoint_t endpoint,
|
|
|
|
char *label) );
|
|
|
|
FORWARD _PROTOTYPE( int copy_label, (endpoint_t src_e,
|
|
|
|
struct rss_label *src_label, char *dst_label, size_t dst_len) );
|
2006-10-25 15:40:36 +02:00
|
|
|
FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags,
|
|
|
|
endpoint_t *ep) );
|
2005-10-20 22:31:18 +02:00
|
|
|
FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
|
2006-05-11 16:58:33 +02:00
|
|
|
FORWARD _PROTOTYPE( int fork_nb, (void) );
|
|
|
|
FORWARD _PROTOTYPE( int read_exec, (struct rproc *rp) );
|
2009-08-18 13:36:01 +02:00
|
|
|
FORWARD _PROTOTYPE( int copy_exec, (struct rproc *rp_src,
|
|
|
|
struct rproc *rp_dst) );
|
2006-10-20 17:01:32 +02:00
|
|
|
FORWARD _PROTOTYPE( void run_script, (struct rproc *rp) );
|
2009-07-02 18:25:31 +02:00
|
|
|
FORWARD _PROTOTYPE( char *get_next_label, (char *ptr, char *label,
|
|
|
|
char *caller_label) );
|
|
|
|
FORWARD _PROTOTYPE( void add_forward_ipc, (struct rproc *rp,
|
|
|
|
struct priv *privp) );
|
|
|
|
FORWARD _PROTOTYPE( void add_backward_ipc, (struct rproc *rp,
|
|
|
|
struct priv *privp) );
|
2006-10-20 17:01:32 +02:00
|
|
|
FORWARD _PROTOTYPE( void init_privs, (struct rproc *rp, struct priv *privp) );
|
|
|
|
FORWARD _PROTOTYPE( void init_pci, (struct rproc *rp, int endpoint) );
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
FORWARD _PROTOTYPE( void update_period, (message *m_ptr) );
|
|
|
|
FORWARD _PROTOTYPE( void end_update, (clock_t now) );
|
2005-08-02 17:29:17 +02:00
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
PRIVATE int shutting_down = FALSE;
|
|
|
|
|
2005-07-26 15:08:57 +02:00
|
|
|
/*===========================================================================*
|
2009-12-02 10:54:50 +01:00
|
|
|
* caller_is_root *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE int caller_is_root(endpoint)
|
|
|
|
endpoint_t endpoint; /* caller endpoint */
|
|
|
|
{
|
|
|
|
uid_t euid;
|
|
|
|
|
|
|
|
/* Check if caller has root user ID. */
|
|
|
|
euid = getnuid(endpoint);
|
|
|
|
if (rs_verbose && euid != 0)
|
|
|
|
{
|
|
|
|
printf("RS: got unauthorized request from endpoint %d\n", endpoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
return euid == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* caller_can_control *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE int caller_can_control(endpoint, label)
|
|
|
|
endpoint_t endpoint;
|
|
|
|
char *label;
|
|
|
|
{
|
|
|
|
int control_allowed = 0;
|
|
|
|
register struct rproc *rp;
|
|
|
|
int c;
|
|
|
|
char *progname;
|
|
|
|
|
|
|
|
/* Find name of binary for given label. */
|
|
|
|
for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
|
|
|
|
if (strcmp(rp->r_label, label) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rp == END_RPROC_ADDR) return 0;
|
|
|
|
progname = strrchr(rp->r_argv[0], '/');
|
|
|
|
if (progname != NULL)
|
|
|
|
progname++;
|
|
|
|
else
|
|
|
|
progname = rp->r_argv[0];
|
|
|
|
|
|
|
|
/* Check if label is listed in caller's isolation policy. */
|
|
|
|
for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
|
|
|
|
if (rp->r_proc_nr_e == endpoint) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rp == END_RPROC_ADDR) return 0;
|
|
|
|
if (rp->r_nr_control > 0) {
|
|
|
|
for (c = 0; c < rp->r_nr_control; c++) {
|
|
|
|
if (strcmp(rp->r_control[c], progname) == 0)
|
|
|
|
control_allowed = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rs_verbose) {
|
|
|
|
printf("RS: allowing %u control over %s via policy: %s\n",
|
|
|
|
endpoint, label, control_allowed ? "yes" : "no");
|
|
|
|
}
|
|
|
|
return control_allowed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* copy_label *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE int copy_label(src_e, src_label, dst_label, dst_len)
|
|
|
|
endpoint_t src_e;
|
|
|
|
struct rss_label *src_label;
|
|
|
|
char *dst_label;
|
|
|
|
size_t dst_len;
|
|
|
|
{
|
|
|
|
int s, len;
|
|
|
|
|
|
|
|
len = MIN(dst_len-1, src_label->l_len);
|
|
|
|
|
|
|
|
s = sys_datacopy(src_e, (vir_bytes) src_label->l_addr,
|
|
|
|
SELF, (vir_bytes) dst_label, len);
|
|
|
|
if (s != OK) return s;
|
|
|
|
|
|
|
|
dst_label[len] = 0;
|
|
|
|
|
|
|
|
if (rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: copy_label: using label (custom) '%s'\n", dst_label);
|
2009-12-02 10:54:50 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
2009-12-17 02:53:26 +01:00
|
|
|
* do_up *
|
2005-07-26 15:08:57 +02:00
|
|
|
*===========================================================================*/
|
2009-12-17 02:53:26 +01:00
|
|
|
PUBLIC int do_up(m_ptr)
|
2006-10-20 17:01:32 +02:00
|
|
|
message *m_ptr; /* request message pointer */
|
|
|
|
{
|
|
|
|
/* A request was made to start a new system service.
|
|
|
|
*/
|
|
|
|
register struct rproc *rp; /* system process table */
|
|
|
|
int slot_nr; /* local table entry */
|
|
|
|
int arg_count; /* number of arguments */
|
|
|
|
char *cmd_ptr; /* parse command string */
|
|
|
|
char *label; /* unique name of command */
|
|
|
|
enum dev_style dev_style; /* device style */
|
|
|
|
int s; /* status variable */
|
|
|
|
int len; /* length of string */
|
|
|
|
int i;
|
2006-10-25 15:40:36 +02:00
|
|
|
int r;
|
|
|
|
endpoint_t ep;
|
2006-10-20 17:01:32 +02:00
|
|
|
struct rproc *tmp_rp;
|
|
|
|
struct rs_start rs_start;
|
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
/* This call requires special privileges. */
|
|
|
|
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
/* See if there is a free entry in the table with system processes. */
|
|
|
|
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
|
|
|
|
rp = &rproc[slot_nr]; /* get pointer to slot */
|
2007-04-23 16:47:04 +02:00
|
|
|
if (!(rp->r_flags & RS_IN_USE)) /* check if available */
|
2006-10-20 17:01:32 +02:00
|
|
|
break;
|
|
|
|
}
|
2007-04-23 16:47:04 +02:00
|
|
|
if (slot_nr >= NR_SYS_PROCS)
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: system process table full\n");
|
2007-04-23 16:47:04 +02:00
|
|
|
return ENOMEM;
|
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
/* Ok, there is space. Get the request structure. */
|
|
|
|
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
|
|
|
SELF, (vir_bytes) &rs_start, sizeof(rs_start));
|
|
|
|
if (s != OK) return(s);
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
/* Obtain command name and parameters. This is a space-separated string
|
|
|
|
* that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
|
|
|
|
*/
|
|
|
|
if (rs_start.rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG);
|
|
|
|
s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_cmd,
|
|
|
|
SELF, (vir_bytes) rp->r_cmd, rs_start.rss_cmdlen);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
rp->r_cmd[rs_start.rss_cmdlen] = '\0'; /* ensure it is terminated */
|
|
|
|
if (rp->r_cmd[0] != '/') return(EINVAL); /* insist on absolute path */
|
|
|
|
|
|
|
|
/* Build argument vector to be passed to execute call. The format of the
|
|
|
|
* arguments vector is: path, arguments, NULL.
|
|
|
|
*/
|
|
|
|
arg_count = 0; /* initialize arg count */
|
|
|
|
rp->r_argv[arg_count++] = rp->r_cmd; /* start with path */
|
|
|
|
cmd_ptr = rp->r_cmd; /* do some parsing */
|
|
|
|
while(*cmd_ptr != '\0') { /* stop at end of string */
|
|
|
|
if (*cmd_ptr == ' ') { /* next argument */
|
|
|
|
*cmd_ptr = '\0'; /* terminate previous */
|
|
|
|
while (*++cmd_ptr == ' ') ; /* skip spaces */
|
|
|
|
if (*cmd_ptr == '\0') break; /* no arg following */
|
|
|
|
if (arg_count>MAX_NR_ARGS+1) break; /* arg vector full */
|
|
|
|
rp->r_argv[arg_count++] = cmd_ptr; /* add to arg vector */
|
|
|
|
}
|
|
|
|
cmd_ptr ++; /* continue parsing */
|
|
|
|
}
|
|
|
|
rp->r_argv[arg_count] = NULL; /* end with NULL pointer */
|
|
|
|
rp->r_argc = arg_count;
|
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
if(rs_start.rss_label.l_len > 0) {
|
2009-12-17 02:53:26 +01:00
|
|
|
/* RS_UP caller has supplied a custom label for this service. */
|
2009-12-02 10:54:50 +01:00
|
|
|
int s = copy_label(m_ptr->m_source, &rs_start.rss_label,
|
|
|
|
rp->r_label, sizeof(rp->r_label));
|
2007-01-22 16:25:41 +01:00
|
|
|
if(s != OK)
|
|
|
|
return s;
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: using label (custom) '%s'\n", rp->r_label);
|
2007-01-22 16:25:41 +01:00
|
|
|
} else {
|
2009-12-17 02:53:26 +01:00
|
|
|
/* Default label for the service. */
|
2007-01-22 16:25:41 +01:00
|
|
|
label= strrchr(rp->r_argv[0], '/');
|
|
|
|
if (label)
|
|
|
|
label++;
|
|
|
|
else
|
|
|
|
label= rp->r_argv[0];
|
|
|
|
len= strlen(label);
|
|
|
|
if (len > MAX_LABEL_LEN-1)
|
|
|
|
len= MAX_LABEL_LEN-1; /* truncate name */
|
|
|
|
memcpy(rp->r_label, label, len);
|
|
|
|
rp->r_label[len]= '\0';
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: using label (from binary %s) '%s'\n",
|
2007-01-22 16:25:41 +01:00
|
|
|
rp->r_argv[0], rp->r_label);
|
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
if(rs_start.rss_nr_control > 0) {
|
|
|
|
int i, s;
|
|
|
|
if (rs_start.rss_nr_control > RSS_NR_CONTROL)
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: too many control labels\n");
|
2009-12-02 10:54:50 +01:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
for (i=0; i<rs_start.rss_nr_control; i++) {
|
|
|
|
s = copy_label(m_ptr->m_source, &rs_start.rss_control[i],
|
|
|
|
rp->r_control[i], sizeof(rp->r_control[i]));
|
|
|
|
if(s != OK)
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
rp->r_nr_control = rs_start.rss_nr_control;
|
|
|
|
|
|
|
|
if (rs_verbose) {
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: control labels:");
|
2009-12-02 10:54:50 +01:00
|
|
|
for (i=0; i<rp->r_nr_control; i++)
|
|
|
|
printf(" %s", rp->r_control[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
/* Check for duplicates */
|
|
|
|
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
|
|
|
|
tmp_rp = &rproc[slot_nr]; /* get pointer to slot */
|
|
|
|
if (!(tmp_rp->r_flags & RS_IN_USE)) /* check if available */
|
|
|
|
continue;
|
|
|
|
if (tmp_rp == rp)
|
|
|
|
continue; /* Our slot */
|
|
|
|
if (strcmp(tmp_rp->r_label, rp->r_label) == 0)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: found duplicate label '%s': slot %d\n",
|
|
|
|
rp->r_label, slot_nr);
|
2006-10-20 17:01:32 +02:00
|
|
|
return EBUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rp->r_script[0]= '\0';
|
|
|
|
if (rs_start.rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
|
|
|
|
if (rs_start.rss_script != NULL)
|
|
|
|
{
|
|
|
|
s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_script,
|
|
|
|
SELF, (vir_bytes) rp->r_script, rs_start.rss_scriptlen);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
rp->r_script[rs_start.rss_scriptlen] = '\0';
|
|
|
|
}
|
|
|
|
rp->r_uid= rs_start.rss_uid;
|
|
|
|
rp->r_nice= rs_start.rss_nice;
|
|
|
|
|
2008-02-21 17:20:22 +01:00
|
|
|
if (rs_start.rss_flags & RF_IPC_VALID)
|
|
|
|
{
|
|
|
|
if (rs_start.rss_ipclen+1 > sizeof(rp->r_ipc_list))
|
|
|
|
{
|
|
|
|
printf("rs: ipc list too long for '%s'\n", rp->r_label);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_ipc,
|
|
|
|
SELF, (vir_bytes) rp->r_ipc_list, rs_start.rss_ipclen);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
rp->r_ipc_list[rs_start.rss_ipclen]= '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rp->r_ipc_list[0]= '\0';
|
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
rp->r_sys_flags = DSRV_SF;
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_exec= NULL;
|
2009-08-18 13:36:01 +02:00
|
|
|
if (rs_start.rss_flags & RF_COPY) {
|
|
|
|
int exst_cpy;
|
|
|
|
struct rproc *rp2;
|
|
|
|
exst_cpy = 0;
|
|
|
|
|
|
|
|
if(rs_start.rss_flags & RF_REUSE) {
|
|
|
|
char *cmd = rp->r_cmd;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = 0; i < NR_SYS_PROCS; i++) {
|
|
|
|
rp2 = &rproc[i];
|
|
|
|
if(strcmp(rp->r_cmd, rp2->r_cmd) == 0 &&
|
2009-12-11 01:08:19 +01:00
|
|
|
(rp2->r_sys_flags & SF_USE_COPY)) {
|
2009-08-18 13:36:01 +02:00
|
|
|
/* We have found the same binary that's
|
|
|
|
* already been copied */
|
|
|
|
exst_cpy = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!exst_cpy)
|
|
|
|
s = read_exec(rp);
|
|
|
|
else
|
|
|
|
s = copy_exec(rp, rp2);
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
if (s != OK)
|
|
|
|
return s;
|
2009-12-11 01:08:19 +01:00
|
|
|
|
|
|
|
rp->r_sys_flags |= SF_USE_COPY;
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
/* All dynamically created services get the same privilege flags, and
|
|
|
|
* allowed traps. Other privilege settings can be specified at runtime.
|
|
|
|
* The privilege id is dynamically allocated by the kernel.
|
|
|
|
*/
|
|
|
|
rp->r_priv.s_flags = DSRV_F; /* privilege flags */
|
|
|
|
rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
/* Copy granted resources */
|
|
|
|
if (rs_start.rss_nr_irq > NR_IRQ)
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: too many IRQs requested\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
rp->r_priv.s_nr_irq= rs_start.rss_nr_irq;
|
|
|
|
for (i= 0; i<rp->r_priv.s_nr_irq; i++)
|
|
|
|
{
|
|
|
|
rp->r_priv.s_irq_tab[i]= rs_start.rss_irq[i];
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: IRQ %d\n", rp->r_priv.s_irq_tab[i]);
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rs_start.rss_nr_io > NR_IO_RANGE)
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: too many I/O ranges requested\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
rp->r_priv.s_nr_io_range= rs_start.rss_nr_io;
|
|
|
|
for (i= 0; i<rp->r_priv.s_nr_io_range; i++)
|
|
|
|
{
|
|
|
|
rp->r_priv.s_io_tab[i].ior_base= rs_start.rss_io[i].base;
|
|
|
|
rp->r_priv.s_io_tab[i].ior_limit=
|
|
|
|
rs_start.rss_io[i].base+rs_start.rss_io[i].len-1;
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: I/O [%x..%x]\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_priv.s_io_tab[i].ior_base,
|
|
|
|
rp->r_priv.s_io_tab[i].ior_limit);
|
|
|
|
}
|
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
if (rs_start.rss_nr_pci_id > RSS_NR_PCI_ID)
|
2006-10-20 17:01:32 +02:00
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: too many PCI device IDs\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
rp->r_nr_pci_id= rs_start.rss_nr_pci_id;
|
|
|
|
for (i= 0; i<rp->r_nr_pci_id; i++)
|
|
|
|
{
|
|
|
|
rp->r_pci_id[i].vid= rs_start.rss_pci_id[i].vid;
|
|
|
|
rp->r_pci_id[i].did= rs_start.rss_pci_id[i].did;
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: PCI %04x/%04x\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_pci_id[i].vid, rp->r_pci_id[i].did);
|
|
|
|
}
|
2009-12-02 10:54:50 +01:00
|
|
|
if (rs_start.rss_nr_pci_class > RSS_NR_PCI_CLASS)
|
2006-10-20 17:01:32 +02:00
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: too many PCI class IDs\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
rp->r_nr_pci_class= rs_start.rss_nr_pci_class;
|
|
|
|
for (i= 0; i<rp->r_nr_pci_class; i++)
|
|
|
|
{
|
|
|
|
rp->r_pci_class[i].class= rs_start.rss_pci_class[i].class;
|
|
|
|
rp->r_pci_class[i].mask= rs_start.rss_pci_class[i].mask;
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: PCI class %06x mask %06x\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_pci_class[i].class, rp->r_pci_class[i].mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy 'system' call number bits */
|
|
|
|
if (sizeof(rs_start.rss_system[0]) == sizeof(rp->r_call_mask[0]) &&
|
|
|
|
sizeof(rs_start.rss_system) == sizeof(rp->r_call_mask))
|
|
|
|
{
|
|
|
|
for (i= 0; i<RSS_NR_SYSTEM; i++)
|
|
|
|
rp->r_call_mask[i]= rs_start.rss_system[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf(
|
2009-12-17 02:53:26 +01:00
|
|
|
"RS: do_up: internal inconsistency: bad size of r_call_mask\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
memset(rp->r_call_mask, '\0', sizeof(rp->r_call_mask));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize some fields. */
|
|
|
|
rp->r_period = rs_start.rss_period;
|
|
|
|
rp->r_dev_nr = rs_start.rss_major;
|
|
|
|
rp->r_dev_style = STYLE_DEV;
|
|
|
|
rp->r_restarts = -1; /* will be incremented */
|
2009-12-17 02:53:26 +01:00
|
|
|
rp->r_set_resources= 1; /* set resources */
|
|
|
|
|
2009-09-21 16:49:04 +02:00
|
|
|
if (sizeof(rp->r_vm) == sizeof(rs_start.rss_vm) &&
|
|
|
|
sizeof(rp->r_vm[0]) == sizeof(rs_start.rss_vm[0]))
|
|
|
|
{
|
|
|
|
memcpy(rp->r_vm, rs_start.rss_vm, sizeof(rp->r_vm));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
printf("RS: do_up: internal inconsistency: bad size of r_vm\n");
|
2009-09-21 16:49:04 +02:00
|
|
|
memset(rp->r_vm, '\0', sizeof(rp->r_vm));
|
|
|
|
}
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
/* All information was gathered. Now try to start the system service. */
|
2006-10-25 15:40:36 +02:00
|
|
|
r = start_service(rp, 0, &ep);
|
|
|
|
m_ptr->RS_ENDPOINT = ep;
|
|
|
|
return r;
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-26 15:08:57 +02:00
|
|
|
/*===========================================================================*
|
2005-10-20 22:31:18 +02:00
|
|
|
* do_down *
|
2005-07-26 15:08:57 +02:00
|
|
|
*===========================================================================*/
|
2005-10-20 22:31:18 +02:00
|
|
|
PUBLIC int do_down(message *m_ptr)
|
2005-07-26 15:08:57 +02:00
|
|
|
{
|
2005-10-12 17:07:38 +02:00
|
|
|
register struct rproc *rp;
|
2006-10-20 17:01:32 +02:00
|
|
|
size_t len;
|
|
|
|
int s, proc;
|
|
|
|
char label[MAX_LABEL_LEN];
|
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
/* This call requires special privileges. */
|
|
|
|
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
len= m_ptr->RS_CMD_LEN;
|
|
|
|
if (len >= sizeof(label))
|
|
|
|
return EINVAL; /* Too long */
|
|
|
|
|
|
|
|
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
|
|
|
SELF, (vir_bytes) label, len);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
label[len]= '\0';
|
2005-10-12 17:07:38 +02:00
|
|
|
|
|
|
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
2006-10-20 17:01:32 +02:00
|
|
|
if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: stopping '%s' (%d)\n", label, rp->r_pid);
|
2009-08-18 13:36:01 +02:00
|
|
|
stop_service(rp,RS_EXITING);
|
|
|
|
if (rp->r_pid == -1)
|
|
|
|
{
|
2006-10-20 17:01:32 +02:00
|
|
|
/* Process is already gone */
|
|
|
|
rp->r_flags = 0; /* release slot */
|
|
|
|
if (rp->r_exec)
|
|
|
|
{
|
|
|
|
free(rp->r_exec);
|
|
|
|
rp->r_exec= NULL;
|
|
|
|
}
|
|
|
|
proc = _ENDPOINT_P(rp->r_proc_nr_e);
|
|
|
|
rproc_ptr[proc] = NULL;
|
2007-01-22 17:44:03 +01:00
|
|
|
return(OK);
|
2009-08-18 13:36:01 +02:00
|
|
|
}
|
2007-01-22 17:44:03 +01:00
|
|
|
|
2009-08-18 13:36:01 +02:00
|
|
|
/* Late reply - send a reply when process dies. */
|
|
|
|
rp->r_flags |= RS_LATEREPLY;
|
|
|
|
rp->r_caller = m_ptr->m_source;
|
|
|
|
return EDONTREPLY;
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
}
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose) printf("RS: do_down: '%s' not found\n", label);
|
2006-10-20 17:01:32 +02:00
|
|
|
return(ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_restart *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_restart(message *m_ptr)
|
|
|
|
{
|
|
|
|
register struct rproc *rp;
|
|
|
|
size_t len;
|
2006-10-25 15:40:36 +02:00
|
|
|
int s, proc, r;
|
2006-10-20 17:01:32 +02:00
|
|
|
char label[MAX_LABEL_LEN];
|
2006-10-25 15:40:36 +02:00
|
|
|
endpoint_t ep;
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
len= m_ptr->RS_CMD_LEN;
|
|
|
|
if (len >= sizeof(label))
|
|
|
|
return EINVAL; /* Too long */
|
|
|
|
|
|
|
|
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
|
|
|
SELF, (vir_bytes) label, len);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
label[len]= '\0';
|
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
/* This call requires special privileges. */
|
|
|
|
if (! (caller_can_control(m_ptr->m_source, label) ||
|
|
|
|
caller_is_root(m_ptr->m_source))) {
|
|
|
|
return(EPERM);
|
|
|
|
}
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
2007-04-23 16:47:04 +02:00
|
|
|
if ((rp->r_flags & RS_IN_USE) && strcmp(rp->r_label, label) == 0) {
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose) printf("RS: restarting '%s' (%d)\n", label, rp->r_pid);
|
2006-10-20 17:01:32 +02:00
|
|
|
if (rp->r_pid >= 0)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: do_restart: '%s' is (still) running, pid = %d\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_pid);
|
|
|
|
return EBUSY;
|
|
|
|
}
|
2009-11-28 14:23:45 +01:00
|
|
|
rp->r_flags &= ~(RS_REFRESHING|RS_NOPINGREPLY);
|
2006-10-25 15:40:36 +02:00
|
|
|
r = start_service(rp, 0, &ep);
|
2007-04-23 16:47:04 +02:00
|
|
|
if (r != OK) printf("do_restart: start_service failed: %d\n", r);
|
2006-10-25 15:40:36 +02:00
|
|
|
m_ptr->RS_ENDPOINT = ep;
|
|
|
|
return(r);
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
|
|
|
}
|
2009-12-11 01:08:19 +01:00
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: do_restart: '%s' not found\n", label);
|
|
|
|
}
|
|
|
|
|
2005-10-20 22:31:18 +02:00
|
|
|
return(ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_refresh *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_refresh(message *m_ptr)
|
|
|
|
{
|
|
|
|
register struct rproc *rp;
|
2006-10-20 17:01:32 +02:00
|
|
|
size_t len;
|
|
|
|
int s;
|
|
|
|
char label[MAX_LABEL_LEN];
|
|
|
|
|
|
|
|
len= m_ptr->RS_CMD_LEN;
|
|
|
|
if (len >= sizeof(label))
|
|
|
|
return EINVAL; /* Too long */
|
|
|
|
|
|
|
|
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
|
|
|
SELF, (vir_bytes) label, len);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
label[len]= '\0';
|
2005-10-20 22:31:18 +02:00
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
/* This call requires special privileges. */
|
|
|
|
if (! (caller_can_control(m_ptr->m_source, label) ||
|
|
|
|
caller_is_root(m_ptr->m_source))) {
|
|
|
|
return(EPERM);
|
|
|
|
}
|
|
|
|
|
2005-10-20 22:31:18 +02:00
|
|
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
2006-10-20 17:01:32 +02:00
|
|
|
if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
|
2009-12-11 01:08:19 +01:00
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: refreshing %s (%d)\n", rp->r_label, rp->r_pid);
|
|
|
|
}
|
2005-10-20 22:31:18 +02:00
|
|
|
stop_service(rp,RS_REFRESHING);
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
}
|
2009-12-11 01:08:19 +01:00
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: do_refresh: '%s' not found\n", label);
|
|
|
|
}
|
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
return(ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_shutdown *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_shutdown(message *m_ptr)
|
|
|
|
{
|
2009-12-02 10:54:50 +01:00
|
|
|
/* This call requires special privileges. */
|
|
|
|
if (m_ptr != NULL && !caller_is_root(m_ptr->m_source)) return(EPERM);
|
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
/* Set flag so that RS server knows services shouldn't be restarted. */
|
|
|
|
shutting_down = TRUE;
|
|
|
|
return(OK);
|
2005-07-26 15:08:57 +02:00
|
|
|
}
|
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* do_update *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_update(message *m_ptr)
|
|
|
|
{
|
|
|
|
register struct rproc *rp;
|
|
|
|
size_t len;
|
|
|
|
int s;
|
|
|
|
char label[MAX_LABEL_LEN];
|
|
|
|
int lu_state;
|
|
|
|
int prepare_maxtime;
|
|
|
|
|
|
|
|
/* Retrieve label. */
|
|
|
|
len= m_ptr->RS_CMD_LEN;
|
|
|
|
if (len >= sizeof(label))
|
|
|
|
return EINVAL; /* Too long */
|
|
|
|
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
|
|
|
SELF, (vir_bytes) label, len);
|
|
|
|
if (s != OK) return(s);
|
|
|
|
label[len]= '\0';
|
|
|
|
|
|
|
|
/* Retrieve live update state. */
|
|
|
|
lu_state = m_ptr->RS_LU_STATE;
|
|
|
|
if(lu_state == SEF_LU_STATE_NULL) {
|
|
|
|
return(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Retrieve prepare max time. */
|
|
|
|
prepare_maxtime = m_ptr->RS_LU_PREPARE_MAXTIME;
|
|
|
|
if(prepare_maxtime) {
|
|
|
|
if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) {
|
|
|
|
return(EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure we are not already updating. */
|
|
|
|
if(rupdate.flags & RS_UPDATING) {
|
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: do_update: an update is already in progress");
|
|
|
|
}
|
|
|
|
return(EBUSY);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to start the update process. */
|
|
|
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
|
|
|
if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
|
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: updating %s (%d)\n", rp->r_label, rp->r_pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
rp->r_flags |= RS_UPDATING;
|
|
|
|
rupdate.flags |= RS_UPDATING;
|
|
|
|
getuptime(&rupdate.prepare_tm);
|
|
|
|
rupdate.prepare_maxtime = prepare_maxtime;
|
|
|
|
rupdate.rp = rp;
|
|
|
|
|
|
|
|
m_ptr->m_type = RS_LU_PREPARE;
|
|
|
|
asynsend(rp->r_proc_nr_e, m_ptr); /* request to prepare for update */
|
|
|
|
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: do_update: '%s' not found\n", label);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_upd_ready *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_upd_ready(message *m_ptr)
|
|
|
|
{
|
|
|
|
register struct rproc *rp;
|
|
|
|
int who_p;
|
|
|
|
clock_t now = m_ptr->NOTIFY_TIMESTAMP;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
who_p = _ENDPOINT_P(m_ptr->m_source);
|
|
|
|
rp = rproc_ptr[who_p];
|
|
|
|
result = m_ptr->RS_LU_RESULT;
|
|
|
|
|
|
|
|
/* Make sure the originating process was requested to prepare for update. */
|
|
|
|
if(! (rp->r_flags & RS_UPDATING) ) {
|
|
|
|
if(rs_verbose) {
|
|
|
|
printf("RS: do_upd_ready: got unexpected update ready msg from %d\n",
|
|
|
|
m_ptr->m_source);
|
|
|
|
}
|
|
|
|
return(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if something went wrong and the process failed to prepare
|
|
|
|
* for the update. In that case, end the update process.
|
|
|
|
*/
|
|
|
|
if(result != OK) {
|
|
|
|
end_update(now);
|
|
|
|
switch(result) {
|
|
|
|
case EACCES:
|
|
|
|
printf("RS: update failed: %s\n",
|
|
|
|
"process does not support live update");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EINVAL:
|
|
|
|
printf("RS: update failed: %s\n",
|
|
|
|
"process does not support the required state");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EBUSY:
|
|
|
|
printf("RS: update failed: %s\n",
|
|
|
|
"process is not able to prepare for the update now");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EGENERIC:
|
|
|
|
printf("RS: update failed: %s\n",
|
|
|
|
"a generic error occurred while preparing for the update");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
printf("RS: update failed: %s (%d)\n",
|
|
|
|
"an unknown error occurred while preparing for the update\n",
|
|
|
|
result);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ENOTREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Kill the process now and mark it for refresh, the new version will
|
|
|
|
* be automatically restarted.
|
|
|
|
*/
|
|
|
|
rp->r_flags &= ~RS_EXITING;
|
|
|
|
rp->r_flags |= RS_REFRESHING;
|
|
|
|
kill(rp->r_pid, SIGKILL);
|
|
|
|
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* update_period *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void update_period(message *m_ptr)
|
|
|
|
{
|
|
|
|
clock_t now = m_ptr->NOTIFY_TIMESTAMP;
|
|
|
|
short has_update_timed_out;
|
|
|
|
message m;
|
|
|
|
|
|
|
|
/* See if a timeout has occurred. */
|
|
|
|
has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime);
|
|
|
|
|
|
|
|
/* If an update timed out, end the update process and notify the service. */
|
|
|
|
if(has_update_timed_out) {
|
|
|
|
end_update(now);
|
|
|
|
printf("RS: update failed: maximum prepare time reached\n");
|
|
|
|
|
|
|
|
/* Prepare cancel request. */
|
|
|
|
m.m_type = RS_LU_PREPARE;
|
|
|
|
m.RS_LU_STATE = SEF_LU_STATE_NULL;
|
|
|
|
asynsend(rupdate.rp->r_proc_nr_e, &m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* end_update *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void end_update(clock_t now)
|
|
|
|
{
|
|
|
|
/* End the update process and mark the affected service as no longer under
|
|
|
|
* update. Eventual late ready to update message (if any) will simply be
|
|
|
|
* ignored and the service can continue executing.
|
|
|
|
* Also, if the service has a period, update the alive and check timestamps
|
|
|
|
* of the service to force a status request in the next period.
|
|
|
|
*/
|
|
|
|
rupdate.flags &= ~RS_UPDATING;
|
|
|
|
rupdate.rp->r_flags &= ~RS_UPDATING;
|
|
|
|
if(rupdate.rp->r_period > 0 ) {
|
|
|
|
rupdate.rp->r_alive_tm = now;
|
|
|
|
rupdate.rp->r_check_tm = now - rupdate.rp->r_period - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-26 15:08:57 +02:00
|
|
|
/*===========================================================================*
|
2005-09-11 18:45:46 +02:00
|
|
|
* do_exit *
|
2005-07-26 15:08:57 +02:00
|
|
|
*===========================================================================*/
|
2005-10-12 17:07:38 +02:00
|
|
|
PUBLIC void do_exit(message *m_ptr)
|
2005-07-26 15:08:57 +02:00
|
|
|
{
|
2005-10-12 17:07:38 +02:00
|
|
|
register struct rproc *rp;
|
2005-07-26 15:08:57 +02:00
|
|
|
pid_t exit_pid;
|
2007-04-23 16:47:04 +02:00
|
|
|
int exit_status, r, slot_nr;
|
2006-10-25 15:40:36 +02:00
|
|
|
endpoint_t ep;
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
clock_t now = m_ptr->NOTIFY_TIMESTAMP;
|
2005-07-26 15:08:57 +02:00
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
|
2005-07-26 15:08:57 +02:00
|
|
|
|
|
|
|
/* See which child exited and what the exit status is. This is done in a
|
2009-07-11 19:59:05 +02:00
|
|
|
* loop because multiple children may have exited, all reported by one
|
2005-07-26 15:08:57 +02:00
|
|
|
* SIGCHLD signal. The WNOHANG options is used to prevent blocking if,
|
|
|
|
* somehow, no exited child can be found.
|
|
|
|
*/
|
|
|
|
while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) {
|
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose) {
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2006-05-11 16:58:33 +02:00
|
|
|
printf("RS: pid %d, ", exit_pid);
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
2005-10-12 17:07:38 +02:00
|
|
|
if (WIFSIGNALED(exit_status)) {
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2005-10-12 17:07:38 +02:00
|
|
|
printf("killed, signal number %d\n", WTERMSIG(exit_status));
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
|
|
|
else if (WIFEXITED(exit_status)) {
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2005-10-12 17:07:38 +02:00
|
|
|
printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
2007-02-16 16:50:30 +01:00
|
|
|
}
|
2005-08-03 18:58:22 +02:00
|
|
|
|
2007-04-23 16:47:04 +02:00
|
|
|
/* Read from the exec pipe */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
r= read(exec_pipe[0], &slot_nr, sizeof(slot_nr));
|
|
|
|
if (r == -1)
|
|
|
|
{
|
2009-05-06 17:38:32 +02:00
|
|
|
break; /* No data */
|
2007-04-23 16:47:04 +02:00
|
|
|
}
|
|
|
|
if (r != sizeof(slot_nr))
|
|
|
|
{
|
|
|
|
panic("RS", "do_exit: unaligned read from exec pipe",
|
|
|
|
r);
|
|
|
|
}
|
|
|
|
printf("do_exit: got slot %d\n", slot_nr);
|
|
|
|
if (slot_nr < 0 || slot_nr >= NR_SYS_PROCS)
|
|
|
|
{
|
|
|
|
panic("RS", "do_exit: bad slot number from exec pipe",
|
|
|
|
slot_nr);
|
|
|
|
}
|
|
|
|
rp= &rproc[slot_nr];
|
2009-11-28 14:23:45 +01:00
|
|
|
rp->r_flags |= RS_EXITING;
|
2007-04-23 16:47:04 +02:00
|
|
|
}
|
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
/* Search the system process table to see who exited.
|
|
|
|
* This should always succeed.
|
|
|
|
*/
|
|
|
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
2005-10-20 22:31:18 +02:00
|
|
|
if ((rp->r_flags & RS_IN_USE) && rp->r_pid == exit_pid) {
|
2006-03-08 15:38:35 +01:00
|
|
|
int proc;
|
|
|
|
proc = _ENDPOINT_P(rp->r_proc_nr_e);
|
2005-10-12 17:07:38 +02:00
|
|
|
|
2006-03-08 15:38:35 +01:00
|
|
|
rproc_ptr[proc] = NULL; /* invalidate */
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_pid= -1;
|
2005-10-12 17:07:38 +02:00
|
|
|
|
2009-12-17 02:53:26 +01:00
|
|
|
/* If PCI properties are set, inform the PCI driver. */
|
|
|
|
if(rp->r_nr_pci_id || rp->r_nr_pci_class) {
|
|
|
|
pci_del_acl(rp->r_proc_nr_e);
|
|
|
|
}
|
2007-04-23 16:47:04 +02:00
|
|
|
|
2005-10-20 22:31:18 +02:00
|
|
|
if ((rp->r_flags & RS_EXITING) || shutting_down) {
|
2007-01-22 17:44:03 +01:00
|
|
|
/* No reply sent to RS_DOWN yet. */
|
|
|
|
if(rp->r_flags & RS_LATEREPLY) {
|
|
|
|
message rsm;
|
|
|
|
rsm.m_type = OK;
|
|
|
|
send(rp->r_caller, &rsm);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release slot. */
|
|
|
|
rp->r_flags = 0;
|
2006-05-11 16:58:33 +02:00
|
|
|
if (rp->r_exec)
|
|
|
|
{
|
|
|
|
free(rp->r_exec);
|
|
|
|
rp->r_exec= NULL;
|
|
|
|
}
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
2005-10-20 22:31:18 +02:00
|
|
|
else if(rp->r_flags & RS_REFRESHING) {
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
short is_updating = rp->r_flags & RS_UPDATING;
|
|
|
|
|
|
|
|
/* Refresh */
|
2005-10-20 22:31:18 +02:00
|
|
|
rp->r_restarts = -1; /* reset counter */
|
2006-10-20 17:01:32 +02:00
|
|
|
if (rp->r_script[0] != '\0')
|
|
|
|
run_script(rp);
|
2006-10-25 15:40:36 +02:00
|
|
|
else {
|
|
|
|
start_service(rp, 0, &ep); /* direct restart */
|
2009-09-21 16:49:04 +02:00
|
|
|
if(m_ptr)
|
|
|
|
m_ptr->RS_ENDPOINT = ep;
|
2006-10-25 15:40:36 +02:00
|
|
|
}
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
|
|
|
|
/* If updating, end the update process. */
|
|
|
|
if(is_updating) {
|
|
|
|
end_update(now);
|
|
|
|
printf("RS: update succeeded\n");
|
|
|
|
}
|
2005-10-20 22:31:18 +02:00
|
|
|
}
|
2005-10-12 17:07:38 +02:00
|
|
|
else {
|
2005-10-20 22:31:18 +02:00
|
|
|
/* Determine what to do. If this is the first unexpected
|
|
|
|
* exit, immediately restart this service. Otherwise use
|
2009-11-28 14:23:45 +01:00
|
|
|
* a binary exponential backoff.
|
2005-10-20 22:31:18 +02:00
|
|
|
*/
|
2006-05-11 16:58:33 +02:00
|
|
|
#if 0
|
|
|
|
rp->r_restarts= 0;
|
|
|
|
#endif
|
2006-10-20 17:01:32 +02:00
|
|
|
if (WIFSIGNALED(exit_status)) {
|
|
|
|
switch(WTERMSIG(exit_status))
|
|
|
|
{
|
|
|
|
case SIGKILL: rp->r_flags |= RS_KILLED; break;
|
2007-04-23 16:47:04 +02:00
|
|
|
default: rp->r_flags |= RS_SIGNALED; break;
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rp->r_flags |= RS_CRASHED;
|
|
|
|
|
2009-05-06 17:38:32 +02:00
|
|
|
if (rp->r_script[0] != '\0') {
|
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: running restart script for %s\n",
|
|
|
|
rp->r_cmd);
|
2006-10-20 17:01:32 +02:00
|
|
|
run_script(rp);
|
2009-05-06 17:38:32 +02:00
|
|
|
} else if (rp->r_restarts > 0) {
|
|
|
|
printf("RS: restarting %s, restarts %d\n",
|
|
|
|
rp->r_cmd, rp->r_backoff);
|
2006-05-15 14:08:43 +02:00
|
|
|
rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2));
|
2005-10-20 22:31:18 +02:00
|
|
|
rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
|
2009-12-11 01:08:19 +01:00
|
|
|
if ((rp->r_sys_flags & SF_USE_COPY) && rp->r_backoff > 1)
|
2006-05-15 14:08:43 +02:00
|
|
|
rp->r_backoff= 1;
|
2005-10-20 22:31:18 +02:00
|
|
|
}
|
|
|
|
else {
|
2009-05-06 17:38:32 +02:00
|
|
|
printf("RS: restarting %s\n", rp->r_cmd);
|
2006-10-25 15:40:36 +02:00
|
|
|
start_service(rp, 0, &ep); /* direct restart */
|
2009-09-21 16:49:04 +02:00
|
|
|
if(m_ptr)
|
|
|
|
m_ptr->RS_ENDPOINT = ep;
|
2006-10-25 15:40:36 +02:00
|
|
|
/* Do this even if no I/O happens with the ioctl, in
|
|
|
|
* order to disambiguate requests with DEV_IOCTL_S.
|
|
|
|
*/
|
2005-10-20 22:31:18 +02:00
|
|
|
}
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
}
|
2005-07-26 15:08:57 +02:00
|
|
|
}
|
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* do_period *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void do_period(m_ptr)
|
|
|
|
message *m_ptr;
|
|
|
|
{
|
|
|
|
register struct rproc *rp;
|
|
|
|
clock_t now = m_ptr->NOTIFY_TIMESTAMP;
|
|
|
|
int s;
|
2006-10-25 15:40:36 +02:00
|
|
|
endpoint_t ep;
|
2005-10-12 17:07:38 +02:00
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* If an update is in progress, check its status. */
|
|
|
|
if(rupdate.flags & RS_UPDATING) {
|
|
|
|
update_period(m_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search system services table. Only check slots that are in use and not
|
|
|
|
* updating.
|
|
|
|
*/
|
2005-10-12 17:07:38 +02:00
|
|
|
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
if ((rp->r_flags & RS_IN_USE) && !(rp->r_flags & RS_UPDATING)) {
|
2005-10-20 22:31:18 +02:00
|
|
|
|
|
|
|
/* If the service is to be revived (because it repeatedly exited,
|
|
|
|
* and was not directly restarted), the binary backoff field is
|
|
|
|
* greater than zero.
|
|
|
|
*/
|
|
|
|
if (rp->r_backoff > 0) {
|
|
|
|
rp->r_backoff -= 1;
|
|
|
|
if (rp->r_backoff == 0) {
|
2006-10-25 15:40:36 +02:00
|
|
|
start_service(rp, 0, &ep);
|
|
|
|
m_ptr->RS_ENDPOINT = ep;
|
2005-10-20 22:31:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the service was signaled with a SIGTERM and fails to respond,
|
|
|
|
* kill the system service with a SIGKILL signal.
|
|
|
|
*/
|
2005-10-21 13:13:17 +02:00
|
|
|
else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
|
|
|
|
&& rp->r_pid > 0) {
|
2005-10-20 22:31:18 +02:00
|
|
|
kill(rp->r_pid, SIGKILL); /* terminate */
|
|
|
|
}
|
2005-10-12 17:07:38 +02:00
|
|
|
|
2005-10-20 22:31:18 +02:00
|
|
|
/* There seems to be no special conditions. If the service has a
|
|
|
|
* period assigned check its status.
|
|
|
|
*/
|
|
|
|
else if (rp->r_period > 0) {
|
2005-10-12 17:07:38 +02:00
|
|
|
|
|
|
|
/* Check if an answer to a status request is still pending. If
|
2009-12-17 02:53:26 +01:00
|
|
|
* the service didn't respond within time, kill it to simulate
|
2005-10-12 17:07:38 +02:00
|
|
|
* a crash. The failure will be detected and the service will
|
|
|
|
* be restarted automatically.
|
|
|
|
*/
|
|
|
|
if (rp->r_alive_tm < rp->r_check_tm) {
|
2005-10-21 13:13:17 +02:00
|
|
|
if (now - rp->r_alive_tm > 2*rp->r_period &&
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: service %d reported late\n",
|
|
|
|
rp->r_proc_nr_e);
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_flags |= RS_NOPINGREPLY;
|
2005-10-12 17:07:38 +02:00
|
|
|
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) {
|
2009-12-11 01:08:19 +01:00
|
|
|
#if 0
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
2009-12-11 01:08:19 +01:00
|
|
|
printf("RS: status request sent to %d\n", rp->r_proc_nr_e);
|
|
|
|
#endif
|
endpoint-aware conversion of servers.
'who', indicating caller number in pm and fs and some other servers, has
been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.).
In both PM and FS, isokendpt() convert endpoints to process slot
numbers, returning OK if it was a valid and consistent endpoint number.
okendpt() does the same but panic()s if it doesn't succeed. (In PM,
this is pm_isok..)
pm and fs keep their own records of process endpoints in their proc tables,
which are needed to make kernel calls about those processes.
message field names have changed.
fs drivers are endpoints.
fs now doesn't try to get out of driver deadlock, as the protocol isn't
supposed to let that happen any more. (A warning is printed if ELOCKED
is detected though.)
fproc[].fp_task (indicating which driver the process is suspended on)
became an int.
PM and FS now get endpoint numbers of initial boot processes from the
kernel. These happen to be the same as the old proc numbers, to let
user processes reach them with the old numbers, but FS and PM don't know
that. All new processes after INIT, even after the generation number
wraps around, get endpoint numbers with generation 1 and higher, so
the first instances of the boot processes are the only processes ever
to have endpoint numbers in the old proc number range.
More return code checks of sys_* functions have been added.
IS has become endpoint-aware. Ditched the 'text' and 'data' fields
in the kernel dump (which show locations, not sizes, so aren't terribly
useful) in favour of the endpoint number. Proc number is still visible.
Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got
the formatting changed.
PM reading segments using rw_seg() has changed - it uses other fields
in the message now instead of encoding the segment and process number and
fd in the fd field. For that it uses _read_pm() and _write_pm() which to
_taskcall()s directly in pm/misc.c.
PM now sys_exit()s itself on panic(), instead of sys_abort().
RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
|
|
|
notify(rp->r_proc_nr_e); /* request status */
|
2005-10-12 17:07:38 +02:00
|
|
|
rp->r_check_tm = now; /* mark time */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reschedule a synchronous alarm for the next period. */
|
2005-10-20 22:31:18 +02:00
|
|
|
if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
|
2005-10-12 17:07:38 +02:00
|
|
|
panic("RS", "couldn't set alarm", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* start_service *
|
|
|
|
*===========================================================================*/
|
2006-10-25 15:40:36 +02:00
|
|
|
PRIVATE int start_service(rp, flags, endpoint)
|
2005-10-12 17:07:38 +02:00
|
|
|
struct rproc *rp;
|
2006-08-15 17:54:51 +02:00
|
|
|
int flags;
|
2006-10-25 15:40:36 +02:00
|
|
|
endpoint_t *endpoint;
|
2005-10-12 17:07:38 +02:00
|
|
|
{
|
|
|
|
/* 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.
|
|
|
|
*/
|
endpoint-aware conversion of servers.
'who', indicating caller number in pm and fs and some other servers, has
been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.).
In both PM and FS, isokendpt() convert endpoints to process slot
numbers, returning OK if it was a valid and consistent endpoint number.
okendpt() does the same but panic()s if it doesn't succeed. (In PM,
this is pm_isok..)
pm and fs keep their own records of process endpoints in their proc tables,
which are needed to make kernel calls about those processes.
message field names have changed.
fs drivers are endpoints.
fs now doesn't try to get out of driver deadlock, as the protocol isn't
supposed to let that happen any more. (A warning is printed if ELOCKED
is detected though.)
fproc[].fp_task (indicating which driver the process is suspended on)
became an int.
PM and FS now get endpoint numbers of initial boot processes from the
kernel. These happen to be the same as the old proc numbers, to let
user processes reach them with the old numbers, but FS and PM don't know
that. All new processes after INIT, even after the generation number
wraps around, get endpoint numbers with generation 1 and higher, so
the first instances of the boot processes are the only processes ever
to have endpoint numbers in the old proc number range.
More return code checks of sys_* functions have been added.
IS has become endpoint-aware. Ditched the 'text' and 'data' fields
in the kernel dump (which show locations, not sizes, so aren't terribly
useful) in favour of the endpoint number. Proc number is still visible.
Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got
the formatting changed.
PM reading segments using rw_seg() has changed - it uses other fields
in the message now instead of encoding the segment and process number and
fd in the fd field. For that it uses _read_pm() and _write_pm() which to
_taskcall()s directly in pm/misc.c.
PM now sys_exit()s itself on panic(), instead of sys_abort().
RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
|
|
|
int child_proc_nr_e, child_proc_nr_n; /* child process slot */
|
2005-10-12 17:07:38 +02:00
|
|
|
pid_t child_pid; /* child's process id */
|
2005-10-21 15:28:26 +02:00
|
|
|
char *file_only;
|
2007-04-23 16:47:04 +02:00
|
|
|
int s, use_copy, slot_nr;
|
2009-09-21 16:49:04 +02:00
|
|
|
bitchunk_t *vm_mask;
|
2005-10-12 17:07:38 +02:00
|
|
|
message m;
|
2009-09-21 16:49:04 +02:00
|
|
|
char * null_env = NULL;
|
2005-10-12 17:07:38 +02:00
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
use_copy= (rp->r_sys_flags & SF_USE_COPY);
|
|
|
|
|
|
|
|
/* See if we are not using a copy but we do need one to start the service. */
|
|
|
|
if(!use_copy && (rp->r_sys_flags & SF_NEED_COPY)) {
|
|
|
|
printf("RS: unable to start service %s without an in-memory copy\n",
|
|
|
|
rp->r_label);
|
|
|
|
return(EPERM);
|
|
|
|
}
|
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
/* Now fork and branch for parent and child process (and check for error). */
|
2008-11-19 13:26:10 +01:00
|
|
|
if (use_copy) {
|
|
|
|
if(rs_verbose) printf("RS: fork_nb..\n");
|
2006-05-11 16:58:33 +02:00
|
|
|
child_pid= fork_nb();
|
2008-11-19 13:26:10 +01:00
|
|
|
} else {
|
|
|
|
if(rs_verbose) printf("RS: fork regular..\n");
|
2006-05-11 16:58:33 +02:00
|
|
|
child_pid = fork();
|
2008-11-19 13:26:10 +01:00
|
|
|
}
|
2006-05-11 16:58:33 +02:00
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
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 */
|
2005-10-21 15:28:26 +02:00
|
|
|
/* Try to execute the binary that has an absolute path. If this fails,
|
2009-12-02 10:54:50 +01:00
|
|
|
* e.g., because the root file system cannot be read, try to strip off
|
2005-10-21 15:28:26 +02:00
|
|
|
* the path, and see if the command is in RS' current working dir.
|
|
|
|
*/
|
2006-10-20 17:01:32 +02:00
|
|
|
nice(rp->r_nice); /* Nice before setuid, to allow negative
|
|
|
|
* nice values.
|
|
|
|
*/
|
|
|
|
setuid(rp->r_uid);
|
2007-04-23 16:47:04 +02:00
|
|
|
cpf_reload(); /* Tell kernel about grant table */
|
2006-05-11 16:58:33 +02:00
|
|
|
if (!use_copy)
|
|
|
|
{
|
2009-09-21 16:49:04 +02:00
|
|
|
execve(rp->r_argv[0], rp->r_argv, &null_env); /* POSIX execute */
|
2006-05-11 16:58:33 +02:00
|
|
|
file_only = strrchr(rp->r_argv[0], '/') + 1;
|
2009-12-02 10:54:50 +01:00
|
|
|
execve(file_only, rp->r_argv, &null_env); /* POSIX execute */
|
2006-05-11 16:58:33 +02:00
|
|
|
}
|
2005-10-21 15:28:26 +02:00
|
|
|
printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno);
|
2007-04-23 16:47:04 +02:00
|
|
|
slot_nr= rp-rproc;
|
|
|
|
s= write(exec_pipe[1], &slot_nr, sizeof(slot_nr));
|
|
|
|
if (s != sizeof(slot_nr))
|
|
|
|
printf("RS: write to exec pipe failed: %d/%d\n", s, errno);
|
|
|
|
exit(1); /* terminate child */
|
2005-10-12 17:07:38 +02:00
|
|
|
|
|
|
|
default: /* parent process */
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2009-11-28 14:23:45 +01:00
|
|
|
if(rs_verbose) printf("RS: parent forked, pid %d..\n", child_pid);
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
endpoint-aware conversion of servers.
'who', indicating caller number in pm and fs and some other servers, has
been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.).
In both PM and FS, isokendpt() convert endpoints to process slot
numbers, returning OK if it was a valid and consistent endpoint number.
okendpt() does the same but panic()s if it doesn't succeed. (In PM,
this is pm_isok..)
pm and fs keep their own records of process endpoints in their proc tables,
which are needed to make kernel calls about those processes.
message field names have changed.
fs drivers are endpoints.
fs now doesn't try to get out of driver deadlock, as the protocol isn't
supposed to let that happen any more. (A warning is printed if ELOCKED
is detected though.)
fproc[].fp_task (indicating which driver the process is suspended on)
became an int.
PM and FS now get endpoint numbers of initial boot processes from the
kernel. These happen to be the same as the old proc numbers, to let
user processes reach them with the old numbers, but FS and PM don't know
that. All new processes after INIT, even after the generation number
wraps around, get endpoint numbers with generation 1 and higher, so
the first instances of the boot processes are the only processes ever
to have endpoint numbers in the old proc number range.
More return code checks of sys_* functions have been added.
IS has become endpoint-aware. Ditched the 'text' and 'data' fields
in the kernel dump (which show locations, not sizes, so aren't terribly
useful) in favour of the endpoint number. Proc number is still visible.
Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got
the formatting changed.
PM reading segments using rw_seg() has changed - it uses other fields
in the message now instead of encoding the segment and process number and
fd in the fd field. For that it uses _read_pm() and _write_pm() which to
_taskcall()s directly in pm/misc.c.
PM now sys_exit()s itself on panic(), instead of sys_abort().
RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
|
|
|
child_proc_nr_e = getnprocnr(child_pid); /* get child slot */
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2009-11-28 14:23:45 +01:00
|
|
|
if(rs_verbose) printf("RS: forked into %d..\n", child_proc_nr_e);
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
2005-10-12 17:07:38 +02:00
|
|
|
break; /* continue below */
|
|
|
|
}
|
|
|
|
|
2009-11-28 14:23:45 +01:00
|
|
|
/* Regardless of any following failures, there is now a child process.
|
|
|
|
* Update the system process table that is maintained by the RS server.
|
|
|
|
*/
|
|
|
|
child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
|
|
|
|
rp->r_flags = RS_IN_USE | flags; /* mark slot in use */
|
|
|
|
rp->r_restarts += 1; /* raise nr of restarts */
|
|
|
|
rp->r_proc_nr_e = child_proc_nr_e; /* set child details */
|
|
|
|
rp->r_pid = child_pid;
|
|
|
|
rp->r_check_tm = 0; /* not checked yet */
|
|
|
|
getuptime(&rp->r_alive_tm); /* currently alive */
|
|
|
|
rp->r_stop_tm = 0; /* not exiting yet */
|
2009-12-02 10:54:50 +01:00
|
|
|
rp->r_backoff = 0; /* not to be restarted */
|
2009-11-28 14:23:45 +01:00
|
|
|
rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
|
|
|
|
|
|
|
|
/* If any of the calls below fail, the RS_EXITING flag is set. This implies
|
|
|
|
* that the process will be removed from RS's process table once it has
|
|
|
|
* terminated. The assumption is that it is not useful to try to restart the
|
|
|
|
* process later in these failure cases.
|
|
|
|
*/
|
|
|
|
|
2006-05-11 16:58:33 +02:00
|
|
|
if (use_copy)
|
|
|
|
{
|
|
|
|
extern char **environ;
|
2009-11-28 14:23:45 +01:00
|
|
|
|
|
|
|
/* Copy the executable image into the child process. If this call
|
|
|
|
* fails, the child process may or may not be killed already. If it is
|
|
|
|
* not killed, it's blocked because of NO_PRIV. Kill it now either way.
|
|
|
|
*/
|
|
|
|
s = dev_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rp->r_argv,
|
2006-05-11 16:58:33 +02:00
|
|
|
environ);
|
2009-11-28 14:23:45 +01:00
|
|
|
if (s != OK) {
|
|
|
|
report("RS", "dev_execve call failed", s);
|
|
|
|
kill(child_pid, SIGKILL);
|
|
|
|
rp->r_flags |= RS_EXITING; /* don't try again */
|
|
|
|
return(s);
|
|
|
|
}
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
|
|
|
|
2009-12-17 02:53:26 +01:00
|
|
|
/* Set resources when asked to. */
|
2006-10-20 17:01:32 +02:00
|
|
|
if (rp->r_set_resources)
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
/* Initialize privilege structure. */
|
2006-10-20 17:01:32 +02:00
|
|
|
init_privs(rp, &rp->r_priv);
|
2009-09-21 16:49:04 +02:00
|
|
|
|
2009-12-17 02:53:26 +01:00
|
|
|
/* Tell VM about allowed calls. */
|
2009-09-21 16:49:04 +02:00
|
|
|
vm_mask = &rp->r_vm[0];
|
2009-12-17 02:53:26 +01:00
|
|
|
if ((s = vm_set_priv(child_proc_nr_e, vm_mask)) < 0) {
|
|
|
|
report("RS", "vm_set_priv call failed", s);
|
|
|
|
kill(child_pid, SIGKILL);
|
|
|
|
rp->r_flags |= RS_EXITING;
|
|
|
|
return (s);
|
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* Set and synch the privilege structure for the new service. */
|
|
|
|
if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_SET_SYS, &rp->r_priv)) != OK
|
|
|
|
|| (s = sys_getpriv(&rp->r_priv, child_proc_nr_e)) != OK) {
|
|
|
|
report("RS","unable to set privileges", s);
|
|
|
|
kill(child_pid, SIGKILL); /* kill the service */
|
|
|
|
rp->r_flags |= RS_EXITING; /* expect exit */
|
|
|
|
return(s); /* return error */
|
|
|
|
}
|
|
|
|
|
2009-12-17 02:53:26 +01:00
|
|
|
/* If PCI properties are set, inform the PCI driver about the new service. */
|
|
|
|
if(rp->r_nr_pci_id || rp->r_nr_pci_class) {
|
|
|
|
init_pci(rp, child_proc_nr_e);
|
2005-10-12 17:07:38 +02:00
|
|
|
}
|
|
|
|
|
Merge of David's ptrace branch. Summary:
o Support for ptrace T_ATTACH/T_DETACH and T_SYSCALL
o PM signal handling logic should now work properly, even with debuggers
being present
o Asynchronous PM/VFS protocol, full IPC support for senda(), and
AMF_NOREPLY senda() flag
DETAILS
Process stop and delay call handling of PM:
o Added sys_runctl() kernel call with sys_stop() and sys_resume()
aliases, for PM to stop and resume a process
o Added exception for sending/syscall-traced processes to sys_runctl(),
and matching SIGKREADY pseudo-signal to PM
o Fixed PM signal logic to deal with requests from a process after
stopping it (so-called "delay calls"), using the SIGKREADY facility
o Fixed various PM panics due to race conditions with delay calls versus
VFS calls
o Removed special PRIO_STOP priority value
o Added SYS_LOCK RTS kernel flag, to stop an individual process from
running while modifying its process structure
Signal and debugger handling in PM:
o Fixed debugger signals being dropped if a second signal arrives when
the debugger has not retrieved the first one
o Fixed debugger signals being sent to the debugger more than once
o Fixed debugger signals unpausing process in VFS; removed PM_UNPAUSE_TR
protocol message
o Detached debugger signals from general signal logic and from being
blocked on VFS calls, meaning that even VFS can now be traced
o Fixed debugger being unable to receive more than one pending signal in
one process stop
o Fixed signal delivery being delayed needlessly when multiple signals
are pending
o Fixed wait test for tracer, which was returning for children that were
not waited for
o Removed second parallel pending call from PM to VFS for any process
o Fixed process becoming runnable between exec() and debugger trap
o Added support for notifying the debugger before the parent when a
debugged child exits
o Fixed debugger death causing child to remain stopped forever
o Fixed consistently incorrect use of _NSIG
Extensions to ptrace():
o Added T_ATTACH and T_DETACH ptrace request, to attach and detach a
debugger to and from a process
o Added T_SYSCALL ptrace request, to trace system calls
o Added T_SETOPT ptrace request, to set trace options
o Added TO_TRACEFORK trace option, to attach automatically to children
of a traced process
o Added TO_ALTEXEC trace option, to send SIGSTOP instead of SIGTRAP upon
a successful exec() of the tracee
o Extended T_GETUSER ptrace support to allow retrieving a process's priv
structure
o Removed T_STOP ptrace request again, as it does not help implementing
debuggers properly
o Added MINIX3-specific ptrace test (test42)
o Added proper manual page for ptrace(2)
Asynchronous PM/VFS interface:
o Fixed asynchronous messages not being checked when receive() is called
with an endpoint other than ANY
o Added AMF_NOREPLY senda() flag, preventing such messages from
satisfying the receive part of a sendrec()
o Added asynsend3() that takes optional flags; asynsend() is now a
#define passing in 0 as third parameter
o Made PM/VFS protocol asynchronous; reintroduced tell_fs()
o Made PM_BASE request/reply number range unique
o Hacked in a horrible temporary workaround into RS to deal with newly
revealed RS-PM-VFS race condition triangle until VFS is asynchronous
System signal handling:
o Fixed shutdown logic of device drivers; removed old SIGKSTOP signal
o Removed is-superuser check from PM's do_procstat() (aka getsigset())
o Added sigset macros to allow system processes to deal with the full
signal set, rather than just the POSIX subset
Miscellaneous PM fixes:
o Split do_getset into do_get and do_set, merging common code and making
structure clearer
o Fixed setpriority() being able to put to sleep processes using an
invalid parameter, or revive zombie processes
o Made find_proc() global; removed obsolete proc_from_pid()
o Cleanup here and there
Also included:
o Fixed false-positive boot order kernel warning
o Removed last traces of old NOTIFY_FROM code
THINGS OF POSSIBLE INTEREST
o It should now be possible to run PM at any priority, even lower than
user processes
o No assumptions are made about communication speed between PM and VFS,
although communication must be FIFO
o A debugger will now receive incoming debuggee signals at kill time
only; the process may not yet be fully stopped
o A first step has been made towards making the SYSTEM task preemptible
2009-09-30 11:57:22 +02:00
|
|
|
/* The purpose of non-blocking forks is to avoid involving VFS in the forking
|
|
|
|
* process, because VFS may be blocked on a sendrec() to a MFS that is
|
|
|
|
* waiting for a endpoint update for a dead driver. We have just published
|
|
|
|
* that update, but VFS may still be blocked. As a result, VFS may not yet
|
|
|
|
* have received PM's fork message. Hence, if we call mapdriver5()
|
|
|
|
* immediately, VFS may not know about the process and thus refuse to add the
|
|
|
|
* driver entry. The following temporary hack works around this by forcing
|
|
|
|
* blocking communication from PM to VFS. Once VFS has been made non-blocking
|
|
|
|
* towards MFS instances, this hack and the entire fork_nb() call can go.
|
|
|
|
*/
|
|
|
|
if (use_copy)
|
|
|
|
setuid(0);
|
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
/* Publish the new system service. */
|
|
|
|
s = publish_service(rp);
|
|
|
|
if (s != OK) {
|
|
|
|
printf("RS: warning: publish_service failed: %d\n", s);
|
|
|
|
}
|
2006-05-11 16:58:33 +02:00
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* Allow the service to run.
|
|
|
|
* XXX FIXME: we should let the service run only after publishing information
|
|
|
|
* about the new system service, but this is not currently possible due to
|
|
|
|
* the blocking nature of mapdriver() that expects the service to be running.
|
|
|
|
* The current solution is not race-free. This hack can go once service
|
|
|
|
* publishing is made fully asynchronous in RS.
|
2009-12-17 02:53:26 +01:00
|
|
|
*/
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_ALLOW, NULL)) != OK) {
|
|
|
|
report("RS","unable to allow the service to run", s);
|
2009-12-17 02:53:26 +01:00
|
|
|
kill(child_pid, SIGKILL); /* kill the service */
|
|
|
|
rp->r_flags |= RS_EXITING; /* expect exit */
|
|
|
|
return(s); /* return error */
|
|
|
|
}
|
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* Map the new service. */
|
|
|
|
if (rp->r_dev_nr > 0) { /* set driver map */
|
|
|
|
if ((s=mapdriver5(rp->r_label, strlen(rp->r_label),
|
|
|
|
rp->r_dev_nr, rp->r_dev_style, !!use_copy /* force */)) < 0) {
|
|
|
|
report("RS", "couldn't map driver (continuing)", errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
endpoint-aware conversion of servers.
'who', indicating caller number in pm and fs and some other servers, has
been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.).
In both PM and FS, isokendpt() convert endpoints to process slot
numbers, returning OK if it was a valid and consistent endpoint number.
okendpt() does the same but panic()s if it doesn't succeed. (In PM,
this is pm_isok..)
pm and fs keep their own records of process endpoints in their proc tables,
which are needed to make kernel calls about those processes.
message field names have changed.
fs drivers are endpoints.
fs now doesn't try to get out of driver deadlock, as the protocol isn't
supposed to let that happen any more. (A warning is printed if ELOCKED
is detected though.)
fproc[].fp_task (indicating which driver the process is suspended on)
became an int.
PM and FS now get endpoint numbers of initial boot processes from the
kernel. These happen to be the same as the old proc numbers, to let
user processes reach them with the old numbers, but FS and PM don't know
that. All new processes after INIT, even after the generation number
wraps around, get endpoint numbers with generation 1 and higher, so
the first instances of the boot processes are the only processes ever
to have endpoint numbers in the old proc number range.
More return code checks of sys_* functions have been added.
IS has become endpoint-aware. Ditched the 'text' and 'data' fields
in the kernel dump (which show locations, not sizes, so aren't terribly
useful) in favour of the endpoint number. Proc number is still visible.
Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got
the formatting changed.
PM reading segments using rw_seg() has changed - it uses other fields
in the message now instead of encoding the segment and process number and
fd in the fd field. For that it uses _read_pm() and _write_pm() which to
_taskcall()s directly in pm/misc.c.
PM now sys_exit()s itself on panic(), instead of sys_abort().
RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
|
|
|
printf("RS: started '%s', major %d, pid %d, endpoint %d, proc %d\n",
|
|
|
|
rp->r_cmd, rp->r_dev_nr, child_pid,
|
|
|
|
child_proc_nr_e, child_proc_nr_n);
|
2005-10-12 17:07:38 +02:00
|
|
|
|
2009-11-28 14:23:45 +01:00
|
|
|
/* The system service now has been successfully started. The only thing
|
|
|
|
* that can go wrong now, is that execution fails at the child. If that's
|
|
|
|
* the case, the child will exit.
|
2005-10-12 17:07:38 +02:00
|
|
|
*/
|
2006-10-25 15:40:36 +02:00
|
|
|
if(endpoint) *endpoint = child_proc_nr_e; /* send back child endpoint */
|
2007-04-27 15:03:33 +02:00
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
return(OK);
|
|
|
|
}
|
2005-08-23 13:31:32 +02:00
|
|
|
|
2005-10-12 17:07:38 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* stop_service *
|
|
|
|
*===========================================================================*/
|
2005-10-20 22:31:18 +02:00
|
|
|
PRIVATE int stop_service(rp,how)
|
2005-10-12 17:07:38 +02:00
|
|
|
struct rproc *rp;
|
2005-10-20 22:31:18 +02:00
|
|
|
int how;
|
2005-10-12 17:07:38 +02:00
|
|
|
{
|
|
|
|
/* 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.
|
|
|
|
*/
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose) printf("RS tries to stop %s (pid %d)\n", rp->r_cmd, rp->r_pid);
|
2005-10-20 22:31:18 +02:00
|
|
|
|
|
|
|
rp->r_flags |= how; /* what to on exit? */
|
2005-10-21 13:13:17 +02:00
|
|
|
if(rp->r_pid > 0) kill(rp->r_pid, SIGTERM); /* first try friendly */
|
2007-02-16 16:50:30 +01:00
|
|
|
else if(rs_verbose) printf("RS: no process to kill\n");
|
2005-10-12 17:07:38 +02:00
|
|
|
getuptime(&rp->r_stop_tm); /* record current time */
|
|
|
|
}
|
2005-10-20 22:31:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_getsysinfo *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_getsysinfo(m_ptr)
|
|
|
|
message *m_ptr;
|
|
|
|
{
|
|
|
|
vir_bytes src_addr, dst_addr;
|
|
|
|
int dst_proc;
|
|
|
|
size_t len;
|
|
|
|
int s;
|
|
|
|
|
2009-12-02 10:54:50 +01:00
|
|
|
/* This call requires special privileges. */
|
|
|
|
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
|
|
|
|
|
2005-10-20 22:31:18 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-05-11 16:58:33 +02:00
|
|
|
PRIVATE pid_t fork_nb()
|
|
|
|
{
|
|
|
|
message m;
|
|
|
|
|
|
|
|
return(_syscall(PM_PROC_NR, FORK_NB, &m));
|
|
|
|
}
|
|
|
|
|
2009-08-18 13:36:01 +02:00
|
|
|
PRIVATE int copy_exec(rp_dst, rp_src)
|
|
|
|
struct rproc *rp_dst, *rp_src;
|
|
|
|
{
|
|
|
|
/* Copy binary from rp_src to rp_dst. */
|
|
|
|
rp_dst->r_exec_len = rp_src->r_exec_len;
|
|
|
|
rp_dst->r_exec = malloc(rp_dst->r_exec_len);
|
|
|
|
if(rp_dst->r_exec == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
|
|
|
|
memcpy(rp_dst->r_exec, rp_src->r_exec, rp_dst->r_exec_len);
|
|
|
|
if(rp_dst->r_exec_len != 0 && rp_dst->r_exec != NULL)
|
|
|
|
return OK;
|
|
|
|
|
|
|
|
rp_dst->r_exec = NULL;
|
|
|
|
return EIO;
|
|
|
|
}
|
|
|
|
|
2006-05-11 16:58:33 +02:00
|
|
|
PRIVATE int read_exec(rp)
|
|
|
|
struct rproc *rp;
|
|
|
|
{
|
|
|
|
int e, r, fd;
|
|
|
|
char *e_name;
|
|
|
|
struct stat sb;
|
|
|
|
|
2009-08-18 13:36:01 +02:00
|
|
|
|
2006-05-11 16:58:33 +02:00
|
|
|
e_name= rp->r_argv[0];
|
|
|
|
r= stat(e_name, &sb);
|
2009-08-18 13:36:01 +02:00
|
|
|
if (r != 0)
|
2006-05-11 16:58:33 +02:00
|
|
|
return -errno;
|
|
|
|
|
|
|
|
fd= open(e_name, O_RDONLY);
|
|
|
|
if (fd == -1)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
rp->r_exec_len= sb.st_size;
|
|
|
|
rp->r_exec= malloc(rp->r_exec_len);
|
|
|
|
if (rp->r_exec == NULL)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: read_exec: unable to allocate %d bytes\n",
|
2006-05-11 16:58:33 +02:00
|
|
|
rp->r_exec_len);
|
|
|
|
close(fd);
|
|
|
|
return ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
r= read(fd, rp->r_exec, rp->r_exec_len);
|
|
|
|
e= errno;
|
|
|
|
close(fd);
|
|
|
|
if (r == rp->r_exec_len)
|
|
|
|
return OK;
|
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: read_exec: read failed %d, errno %d\n", r, e);
|
2006-05-11 16:58:33 +02:00
|
|
|
|
|
|
|
free(rp->r_exec);
|
|
|
|
rp->r_exec= NULL;
|
|
|
|
|
|
|
|
if (r >= 0)
|
|
|
|
return EIO;
|
|
|
|
else
|
|
|
|
return -e;
|
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* run_script *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void run_script(rp)
|
|
|
|
struct rproc *rp;
|
|
|
|
{
|
|
|
|
int r, proc_nr_e;
|
|
|
|
pid_t pid;
|
|
|
|
char *reason;
|
|
|
|
char incarnation_str[20]; /* Enough for a counter? */
|
2009-09-21 16:49:04 +02:00
|
|
|
char *envp[1] = { NULL };
|
2006-10-20 17:01:32 +02:00
|
|
|
|
2009-11-28 14:23:45 +01:00
|
|
|
if (rp->r_flags & RS_REFRESHING)
|
2006-10-20 17:01:32 +02:00
|
|
|
reason= "restart";
|
|
|
|
else if (rp->r_flags & RS_NOPINGREPLY)
|
|
|
|
reason= "no-heartbeat";
|
|
|
|
else if (rp->r_flags & RS_KILLED)
|
|
|
|
reason= "killed";
|
|
|
|
else if (rp->r_flags & RS_CRASHED)
|
|
|
|
reason= "crashed";
|
2007-04-23 16:47:04 +02:00
|
|
|
else if (rp->r_flags & RS_SIGNALED)
|
|
|
|
reason= "signaled";
|
2006-10-20 17:01:32 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
printf(
|
2007-02-16 16:50:30 +01:00
|
|
|
"RS: run_script: can't find reason for termination of '%s'\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_label);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sprintf(incarnation_str, "%d", rp->r_restarts);
|
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose) {
|
2008-02-21 17:20:22 +01:00
|
|
|
printf("RS: calling script '%s'\n", rp->r_script);
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: sevice name: '%s'\n", rp->r_label);
|
|
|
|
printf("RS: reason: '%s'\n", reason);
|
|
|
|
printf("RS: incarnation: '%s'\n", incarnation_str);
|
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
pid= fork();
|
|
|
|
switch(pid)
|
|
|
|
{
|
|
|
|
case -1:
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: run_script: fork failed: %s\n", strerror(errno));
|
2006-10-20 17:01:32 +02:00
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
execle(rp->r_script, rp->r_script, rp->r_label, reason,
|
2009-09-21 16:49:04 +02:00
|
|
|
incarnation_str, NULL, envp);
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: run_script: execl '%s' failed: %s\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_script, strerror(errno));
|
|
|
|
exit(1);
|
|
|
|
default:
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* Set the privilege structure for the child process. */
|
2006-10-20 17:01:32 +02:00
|
|
|
proc_nr_e = getnprocnr(pid);
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
if ((r = sys_privctl(proc_nr_e, SYS_PRIV_SET_USER, NULL))
|
|
|
|
!= OK) {
|
|
|
|
printf("RS: run_script: can't set privileges: %d\n",r);
|
|
|
|
}
|
|
|
|
/* Allow the process to run. */
|
|
|
|
if ((r = sys_privctl(proc_nr_e, SYS_PRIV_ALLOW, NULL)) != OK) {
|
|
|
|
printf("RS: run_script: process can't run: %d\n",r);
|
2009-12-11 01:08:19 +01:00
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
/* Do not wait for the child */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-02 18:25:31 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* get_next_label *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE char *get_next_label(ptr, label, caller_label)
|
|
|
|
char *ptr;
|
|
|
|
char *label;
|
|
|
|
char *caller_label;
|
|
|
|
{
|
|
|
|
/* Get the next label from the list of (IPC) labels.
|
|
|
|
*/
|
|
|
|
char *p, *q;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
for (p= ptr; p[0] != '\0'; p= q)
|
|
|
|
{
|
|
|
|
/* Skip leading space */
|
|
|
|
while (p[0] != '\0' && isspace((unsigned char)p[0]))
|
|
|
|
p++;
|
|
|
|
|
|
|
|
/* Find start of next word */
|
|
|
|
q= p;
|
|
|
|
while (q[0] != '\0' && !isspace((unsigned char)q[0]))
|
|
|
|
q++;
|
|
|
|
if (q == p)
|
|
|
|
continue;
|
|
|
|
len= q-p;
|
|
|
|
if (len > MAX_LABEL_LEN)
|
|
|
|
{
|
|
|
|
printf(
|
|
|
|
"rs:get_next_label: bad ipc list entry '.*s' for %s: too long\n",
|
|
|
|
len, p, caller_label);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
memcpy(label, p, len);
|
|
|
|
label[len]= '\0';
|
|
|
|
|
|
|
|
return q; /* found another */
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL; /* done */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* add_forward_ipc *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void add_forward_ipc(rp, privp)
|
|
|
|
struct rproc *rp;
|
|
|
|
struct priv *privp;
|
|
|
|
{
|
|
|
|
/* Add IPC send permissions to a process based on that process's IPC
|
|
|
|
* list.
|
|
|
|
*/
|
|
|
|
char label[MAX_LABEL_LEN+1], *p;
|
|
|
|
struct rproc *tmp_rp;
|
|
|
|
endpoint_t proc_nr_e;
|
2009-12-11 01:08:19 +01:00
|
|
|
int r;
|
2009-07-02 18:25:31 +02:00
|
|
|
int slot_nr, priv_id;
|
2009-12-11 01:08:19 +01:00
|
|
|
struct priv priv;
|
2009-07-02 18:25:31 +02:00
|
|
|
|
|
|
|
p = rp->r_ipc_list;
|
|
|
|
|
|
|
|
while ((p = get_next_label(p, label, rp->r_label)) != NULL) {
|
|
|
|
|
|
|
|
if (strcmp(label, "SYSTEM") == 0)
|
|
|
|
proc_nr_e= SYSTEM;
|
|
|
|
else if (strcmp(label, "USER") == 0)
|
|
|
|
proc_nr_e= INIT_PROC_NR; /* all user procs */
|
|
|
|
else if (strcmp(label, "PM") == 0)
|
|
|
|
proc_nr_e= PM_PROC_NR;
|
|
|
|
else if (strcmp(label, "VFS") == 0)
|
|
|
|
proc_nr_e= FS_PROC_NR;
|
|
|
|
else if (strcmp(label, "RS") == 0)
|
|
|
|
proc_nr_e= RS_PROC_NR;
|
|
|
|
else if (strcmp(label, "LOG") == 0)
|
|
|
|
proc_nr_e= LOG_PROC_NR;
|
|
|
|
else if (strcmp(label, "TTY") == 0)
|
|
|
|
proc_nr_e= TTY_PROC_NR;
|
|
|
|
else if (strcmp(label, "DS") == 0)
|
|
|
|
proc_nr_e= DS_PROC_NR;
|
|
|
|
else if (strcmp(label, "VM") == 0)
|
|
|
|
proc_nr_e= VM_PROC_NR;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Try to find process */
|
|
|
|
for (slot_nr = 0; slot_nr < NR_SYS_PROCS;
|
|
|
|
slot_nr++)
|
|
|
|
{
|
|
|
|
tmp_rp = &rproc[slot_nr];
|
|
|
|
if (!(tmp_rp->r_flags & RS_IN_USE))
|
|
|
|
continue;
|
|
|
|
if (strcmp(tmp_rp->r_label, label) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (slot_nr >= NR_SYS_PROCS)
|
|
|
|
{
|
2009-10-01 21:21:57 +02:00
|
|
|
if (rs_verbose)
|
|
|
|
printf(
|
|
|
|
"add_forward_ipc: unable to find '%s'\n", label);
|
2009-07-02 18:25:31 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
proc_nr_e= tmp_rp->r_proc_nr_e;
|
|
|
|
}
|
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
if ((r = sys_getpriv(&priv, proc_nr_e)) < 0)
|
2009-07-02 18:25:31 +02:00
|
|
|
{
|
|
|
|
printf(
|
|
|
|
"add_forward_ipc: unable to get priv_id for '%s': %d\n",
|
2009-12-11 01:08:19 +01:00
|
|
|
label, r);
|
2009-07-02 18:25:31 +02:00
|
|
|
continue;
|
|
|
|
}
|
2009-12-11 01:08:19 +01:00
|
|
|
priv_id= priv.s_id;
|
2009-07-02 18:25:31 +02:00
|
|
|
set_sys_bit(privp->s_ipc_to, priv_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* add_backward_ipc *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void add_backward_ipc(rp, privp)
|
|
|
|
struct rproc *rp;
|
|
|
|
struct priv *privp;
|
|
|
|
{
|
|
|
|
/* Add IPC send permissions to a process based on other processes' IPC
|
|
|
|
* lists. This is enough to allow each such two processes to talk to
|
|
|
|
* each other, as the kernel guarantees send mask symmetry. We need to
|
|
|
|
* add these permissions now because the current process may not yet
|
|
|
|
* have existed at the time that the other process was initialized.
|
|
|
|
*/
|
|
|
|
char label[MAX_LABEL_LEN+1], *p;
|
|
|
|
struct rproc *rrp;
|
|
|
|
int priv_id, found;
|
|
|
|
|
|
|
|
for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
|
|
|
|
if (!(rrp->r_flags & RS_IN_USE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If an IPC target list was provided for the process being
|
|
|
|
* checked here, make sure that the label of the new process
|
|
|
|
* is in that process's list.
|
|
|
|
*/
|
|
|
|
if (rrp->r_ipc_list[0]) {
|
|
|
|
found = 0;
|
|
|
|
|
|
|
|
p = rrp->r_ipc_list;
|
|
|
|
|
|
|
|
while ((p = get_next_label(p, label, rp->r_label)) !=
|
|
|
|
NULL) {
|
|
|
|
if (!strcmp(rp->r_label, label)) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-12-11 01:08:19 +01:00
|
|
|
priv_id= rrp->r_priv.s_id;
|
2009-07-02 18:25:31 +02:00
|
|
|
|
|
|
|
set_sys_bit(privp->s_ipc_to, priv_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* init_privs *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void init_privs(rp, privp)
|
|
|
|
struct rproc *rp;
|
|
|
|
struct priv *privp;
|
|
|
|
{
|
|
|
|
int i, src_bits_per_word, dst_bits_per_word, src_word, dst_word,
|
2009-07-02 18:25:31 +02:00
|
|
|
src_bit, call_nr;
|
2006-10-20 17:01:32 +02:00
|
|
|
unsigned long mask;
|
|
|
|
|
2006-10-31 14:35:04 +01:00
|
|
|
/* Clear s_k_call_mask */
|
|
|
|
memset(privp->s_k_call_mask, '\0', sizeof(privp->s_k_call_mask));
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
src_bits_per_word= 8*sizeof(rp->r_call_mask[0]);
|
|
|
|
dst_bits_per_word= 8*sizeof(privp->s_k_call_mask[0]);
|
2009-12-02 10:54:50 +01:00
|
|
|
for (src_word= 0; src_word < RSS_NR_SYSTEM; src_word++)
|
2006-10-20 17:01:32 +02:00
|
|
|
{
|
|
|
|
for (src_bit= 0; src_bit < src_bits_per_word; src_bit++)
|
|
|
|
{
|
|
|
|
mask= (1UL << src_bit);
|
|
|
|
if (!(rp->r_call_mask[src_word] & mask))
|
|
|
|
continue;
|
|
|
|
call_nr= src_word*src_bits_per_word+src_bit;
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: init_privs: system call %d\n", call_nr);
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
2006-10-20 17:01:32 +02:00
|
|
|
dst_word= call_nr / dst_bits_per_word;
|
|
|
|
mask= (1UL << (call_nr % dst_bits_per_word));
|
|
|
|
if (dst_word >= CALL_MASK_SIZE)
|
|
|
|
{
|
|
|
|
printf(
|
2007-02-16 16:50:30 +01:00
|
|
|
"RS: init_privs: call number %d doesn't fit\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
call_nr);
|
|
|
|
}
|
|
|
|
privp->s_k_call_mask[dst_word] |= mask;
|
|
|
|
}
|
|
|
|
}
|
2007-04-23 16:47:04 +02:00
|
|
|
|
2009-07-02 18:25:31 +02:00
|
|
|
/* Clear s_ipc_to */
|
2007-04-23 16:47:04 +02:00
|
|
|
memset(&privp->s_ipc_to, '\0', sizeof(privp->s_ipc_to));
|
|
|
|
|
2008-02-21 17:20:22 +01:00
|
|
|
if (strlen(rp->r_ipc_list) != 0)
|
2007-04-23 16:47:04 +02:00
|
|
|
{
|
2009-07-02 18:25:31 +02:00
|
|
|
add_forward_ipc(rp, privp);
|
|
|
|
add_backward_ipc(rp, privp);
|
2007-04-23 16:47:04 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-02 18:25:31 +02:00
|
|
|
for (i= 0; i<NR_SYS_PROCS; i++)
|
2007-04-23 16:47:04 +02:00
|
|
|
{
|
2009-07-02 18:25:31 +02:00
|
|
|
if (i != USER_PRIV_ID)
|
|
|
|
set_sys_bit(privp->s_ipc_to, i);
|
2007-04-23 16:47:04 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-20 17:01:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* init_pci *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void init_pci(rp, endpoint)
|
|
|
|
struct rproc *rp;
|
|
|
|
int endpoint;
|
|
|
|
{
|
2009-12-17 02:53:26 +01:00
|
|
|
/* Inform the PCI driver about the new service. */
|
2006-10-20 17:01:32 +02:00
|
|
|
size_t len;
|
|
|
|
int i, r;
|
|
|
|
struct rs_pci rs_pci;
|
|
|
|
|
2006-10-31 14:35:04 +01:00
|
|
|
if (strcmp(rp->r_label, "pci") == 0)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: init_pci: not when starting 'pci'\n");
|
2006-10-31 14:35:04 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-20 17:01:32 +02:00
|
|
|
len= strlen(rp->r_label);
|
|
|
|
if (len+1 > sizeof(rs_pci.rsp_label))
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: init_pci: label '%s' too long for rsp_label\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
rp->r_label);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
strcpy(rs_pci.rsp_label, rp->r_label);
|
|
|
|
rs_pci.rsp_endpoint= endpoint;
|
|
|
|
|
|
|
|
rs_pci.rsp_nr_device= rp->r_nr_pci_id;
|
|
|
|
if (rs_pci.rsp_nr_device > RSP_NR_DEVICE)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: init_pci: too many PCI devices (max %d) "
|
|
|
|
"truncating\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
RSP_NR_DEVICE);
|
|
|
|
rs_pci.rsp_nr_device= RSP_NR_DEVICE;
|
|
|
|
}
|
|
|
|
for (i= 0; i<rs_pci.rsp_nr_device; i++)
|
|
|
|
{
|
|
|
|
rs_pci.rsp_device[i].vid= rp->r_pci_id[i].vid;
|
|
|
|
rs_pci.rsp_device[i].did= rp->r_pci_id[i].did;
|
|
|
|
}
|
|
|
|
|
|
|
|
rs_pci.rsp_nr_class= rp->r_nr_pci_class;
|
|
|
|
if (rs_pci.rsp_nr_class > RSP_NR_CLASS)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: init_pci: too many PCI classes "
|
|
|
|
"(max %d) truncating\n",
|
2006-10-20 17:01:32 +02:00
|
|
|
RSP_NR_CLASS);
|
|
|
|
rs_pci.rsp_nr_class= RSP_NR_CLASS;
|
|
|
|
}
|
|
|
|
for (i= 0; i<rs_pci.rsp_nr_class; i++)
|
|
|
|
{
|
|
|
|
rs_pci.rsp_class[i].class= rp->r_pci_class[i].class;
|
|
|
|
rs_pci.rsp_class[i].mask= rp->r_pci_class[i].mask;
|
|
|
|
}
|
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: init_pci: calling pci_set_acl\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
r= pci_set_acl(&rs_pci);
|
|
|
|
|
2007-02-16 16:50:30 +01:00
|
|
|
if(rs_verbose)
|
|
|
|
printf("RS: init_pci: after pci_set_acl\n");
|
2006-10-20 17:01:32 +02:00
|
|
|
|
|
|
|
if (r != OK)
|
|
|
|
{
|
2007-02-16 16:50:30 +01:00
|
|
|
printf("RS: init_pci: pci_set_acl failed: %s\n",
|
|
|
|
strerror(errno));
|
2006-10-20 17:01:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-09-21 17:25:15 +02:00
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_lookup *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int do_lookup(m_ptr)
|
|
|
|
message *m_ptr;
|
|
|
|
{
|
|
|
|
static char namebuf[100];
|
|
|
|
int len, r;
|
|
|
|
struct rproc *rrp;
|
|
|
|
|
|
|
|
len = m_ptr->RS_NAME_LEN;
|
|
|
|
|
|
|
|
if(len < 2 || len >= sizeof(namebuf)) {
|
|
|
|
printf("RS: len too weird (%d)\n", len);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((r=sys_vircopy(m_ptr->m_source, D, (vir_bytes) m_ptr->RS_NAME,
|
|
|
|
SELF, D, (vir_bytes) namebuf, len)) != OK) {
|
|
|
|
printf("RS: name copy failed\n");
|
|
|
|
return r;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
namebuf[len] = '\0';
|
|
|
|
|
|
|
|
for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
|
|
|
|
if (!(rrp->r_flags & RS_IN_USE))
|
|
|
|
continue;
|
|
|
|
if (!strcmp(rrp->r_label, namebuf)) {
|
|
|
|
m_ptr->RS_ENDPOINT = rrp->r_proc_nr_e;
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ESRCH;
|
|
|
|
}
|
|
|
|
|