"shutdown",
"update",
"clone",
+ "edit",
"catch for illegal requests"
};
#define ILLEGAL_REQUEST sizeof(known_requests)/sizeof(char *)
fprintf(stderr, "Warning, %s\n", problem);
fprintf(stderr, "Usage:\n");
fprintf(stderr,
- " %s [%s %s %s %s] (up|run|update) <binary|%s> [%s <args>] [%s <special>] [%s <style>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
+ " %s [%s %s %s %s] (up|run|edit|update) <binary|%s> [%s <args>] [%s <special>] [%s <style>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK, OPT_REPLICA, SELF_BINARY,
ARG_ARGS, ARG_DEV, ARG_DEVSTYLE, ARG_PERIOD, ARG_SCRIPT,
ARG_LABELNAME, ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME);
int req_nr;
int c, i, j;
int c_flag, r_flag, n_flag, p_flag;
+ int label_required;
c_flag = 0;
r_flag = 0;
}
rs_start.rss_flags = 0;
- if (req_nr == RS_UP || req_nr == RS_UPDATE) {
+ if (req_nr == RS_UP || req_nr == RS_UPDATE || req_nr == RS_EDIT) {
u32_t system_hz;
rs_start.rss_flags= RSS_IPC_VALID;
req_path = argv[optind+ARG_PATH];
if(req_nr == RS_UPDATE && !strcmp(req_path, SELF_BINARY)) {
+ /* Self update needs no real path or configuration file. */
req_config = NULL;
req_path = req_path_self;
rs_start.rss_flags |= RSS_SELF_LU;
}
+ if(req_nr == RS_EDIT) {
+ /* Edit action needs no configuration file. */
+ req_config = NULL;
+ }
+
if (do_run)
{
/* Set default recovery script for RUN */
else if (strcmp(argv[i], ARG_PERIOD)==0) {
req_period = strtol(argv[i+1], &hz, 10);
if (strcmp(hz,"HZ")==0) req_period *= system_hz;
- if (req_period < 1) {
- print_usage(argv[ARG_NAME],
- "period is at least be one tick");
+ if (req_period < 0) {
+ print_usage(argv[ARG_NAME], "bad period argument");
exit(EINVAL);
}
}
/* no extra arguments required */
}
- if((rs_start.rss_flags & RSS_SELF_LU) && !req_label) {
+ label_required = (rs_start.rss_flags & RSS_SELF_LU) || (req_nr == RS_EDIT);
+ if(label_required && !req_label) {
print_usage(argv[ARG_NAME], "label option mandatory for target action");
exit(EINVAL);
}
m.RS_LU_PREPARE_MAXTIME = req_lu_maxtime;
/* fall through */
case RS_UP:
+ case RS_EDIT:
/* Build space-separated command string to be passed to RS server. */
progname = strrchr(req_path, '/');
assert(progname); /* an absolute path was required */
/* Build request message and send the request. */
if(result == OK) {
- if (_syscall(RS_PROC_NR, request, &m) == -1)
+ if (_syscall(RS_PROC_NR, request, &m) == -1)
failure();
result = m.m_type;
}
+20100705:
+ /usr/src/etc/usr/rc updated: copy it (or merge it) to /usr/etc/rc.
+ /usr/src/etc/rc updated: copy it (or merge it) to /etc/rc.
+ Perform some cleanup (optional):
+ # rm -f /sbin/tty /sbin/log
20100630:
protocol change between service and rs: be sure to compile commands
together with the system image and don't use the new userspace with
MAN=
-BINDIR?= /sbin
+BINDIR?= /usr/sbin
INSTALLFLAGS+= -S 32k
.include <bsd.prog.mk>
235 400
d--755 0 0
bin d--755 0 0
- at_wini ---755 0 0 at_wini
- bios_wini ---755 0 0 bios_wini
cdprobe ---755 0 0 cdprobe
dev2name ---755 0 0 dev2name
- floppy ---755 0 0 floppy
loadramdisk ---755 0 0 loadramdisk
newroot ---755 0 0 newroot
- pci ---755 0 0 pci
sh ---755 0 0 sh
service ---755 0 0 service
sysenv ---755 0 0 sysenv
$
sbin d--755 0 0
+ at_wini ---755 0 0 at_wini
+ bios_wini ---755 0 0 bios_wini
+ floppy ---755 0 0 floppy
+ pci ---755 0 0 pci
mfs ---755 0 0 mfs
$
dev d--755 0 0
exec 2>/dev/log
exec </dev/null
-/bin/service -c up /bin/pci -config /etc/system.conf
-/bin/service -cn up /bin/floppy -config /etc/system.conf -dev /dev/fd0
+/bin/service -c up /sbin/pci
+/bin/service -cn up /sbin/floppy -dev /dev/fd0
if [ X`/bin/sysenv bios_wini` = Xyes ]
then
echo Using bios_wini.
- /bin/service -c up /bin/bios_wini -dev /dev/c0d0
+ /bin/service -c up /sbin/bios_wini -dev /dev/c0d0
else
- /bin/service -c up /bin/at_wini -dev /dev/c0d0 -config /etc/system.conf -label at_wini_0
- /bin/service -cr up /bin/at_wini -dev /dev/c1d0 -config /etc/system.conf -label at_wini_1 -args instance=1
+ /bin/service -c up /sbin/at_wini -dev /dev/c0d0 -label at_wini_0
+ /bin/service -cr up /sbin/at_wini -dev /dev/c1d0 -label at_wini_1 -args instance=1
fi
+/bin/service -c edit /sbin/mfs -label fs_imgrd
rootdev=`sysenv rootdev` || echo 'No rootdev?'
rootdevname=`/bin/dev2name "$rootdev"` ||
MAN=
-BINDIR?= /sbin
+BINDIR?= /usr/sbin
INSTALLFLAGS+= -S 16k
SUBDIR= keymaps
exec intr sh
}
-upopt()
+up()
{
- opt=$1
- shift
+ # Function to dynamically start a system service
+ opt=""
+ prefix=$(expr "$1 " : '\(-\)')
+ if [ "$prefix" = "-" ];
+ then
+ opt=$1
+ shift
+ fi
service=$1
shift
- # Function to dynamically start a system service
- echo -n " $service"
service $opt up /sbin/$service "$@"
}
+edit()
+{
+ # Function to dynamically edit system service settings
+ opt=""
+ prefix=$(expr "$1 " : '\(-\)')
+ if [ "$prefix" = "-" ];
+ then
+ opt=$1
+ shift
+ fi
+ service=$1
+ shift
+
+ # Assume binaries are always in /usr/sbin
+ service $opt edit /usr/sbin/$service -label $service "$@"
+}
+
while getopts 'saf' opt
do
case $opt in
case $action in
start)
- echo -n "Multiuser startup in progress ...:"
+ echo -n "Multiuser startup in progress ..."
# National keyboard?
test -f /etc/keymap && loadkeys /etc/keymap
if [ "`sysenv debug_fkeys`" != 0 ]
then
- upopt -n is -period 5HZ
+ up -n is -period 5HZ
fi
- echo .
+ echo
# Set timezone.
export TZ=GMT0
mount $bin_img $usr /usr
fi
+ # Edit settings for boot system services
+ edit rs
+ edit vm
+ edit pm
+ edit sched
+ edit vfs
+ edit ds
+ edit tty
+ edit memory
+ edit -p log
+ edit -c pfs
+
if [ ! -z "$home" ]
then mount $bin_img $home /home || echo "WARNING: couldn't mount $home on /home"
fi
up()
{
- upopt " " "$@"
-}
-
-upopt()
-{
- opt=$1
- shift
+ # Function to dynamically start a system service
+ opt=""
+ prefix=$(expr "$1 " : '\(-\)')
+ if [ "$prefix" = "-" ];
+ then
+ opt=$1
+ shift
+ fi
service=$1
shift
- # Function to dynamically start a system service
-
# First check if this service is disabled at the boot monitor.
if disabled $service; then return; fi
# Start servers and drivers set at the boot monitor.
echo -n "Starting services:"
- upopt -n random -dev /dev/random -devstyle STYLE_DEVA -period 3HZ
+ up -n random -dev /dev/random -devstyle STYLE_DEVA -period 3HZ
# load random number generator
if [ -f $RANDOM_FILE ]
eval up $driver -label $label $arg -period 5HZ
done
up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
- upopt -n printer -dev /dev/lp -period 10HZ
- upopt -n ipc
+ up -n printer -dev /dev/lp -period 10HZ
+ up -n ipc
echo .
# Network initialization.
#define RS_SHUTDOWN (RS_RQ_BASE + 4) /* alert about shutdown */
#define RS_UPDATE (RS_RQ_BASE + 5) /* update system service */
#define RS_CLONE (RS_RQ_BASE + 6) /* clone system service */
+#define RS_EDIT (RS_RQ_BASE + 7) /* edit system service */
#define RS_LOOKUP (RS_RQ_BASE + 8) /* lookup server name */
short in_use; /* set when the entry is in use */
unsigned sys_flags; /* sys flags */
endpoint_t endpoint; /* process endpoint number */
- long period; /* heartbeat period (or zero) */
int dev_flags; /* device flags */
dev_t dev_nr; /* major device number */
printf("%13s %9d %5d %6s %3d/%1d %3ld %8ld %5dx %s",
rpub->label, rpub->endpoint, rp->r_pid,
s_flags_str(rp->r_flags, rpub->sys_flags), rpub->dev_nr,
- rpub->dev_style, rpub->period, rp->r_alive_tm, rp->r_restarts,
+ rpub->dev_style, rp->r_period, rp->r_alive_tm, rp->r_restarts,
rp->r_args
);
printf("\n");
#define RUSR_SM PM_PROC_NR /* root user proc */
/* Define sys flags for the various process types. */
-#define SRV_SF (SF_CORE_SRV | SF_NEED_COPY) /* system services */
+#define SRV_SF (SF_CORE_SRV) /* system services */
#define SRVR_SF (SRV_SF | SF_NEED_REPL) /* services needing a replica */
#define DSRV_SF (0) /* dynamic system services */
#define VM_SF (SRVR_SF | SF_SYNCH_BOOT) /* vm */
*/
extern struct boot_image_dev boot_image_dev_table[];
-/* The buffer where the boot image is copied during initialization. */
-EXTERN int boot_image_buffer_size;
-EXTERN char *boot_image_buffer;
-
/* The system process table. This table only has entries for system
* services (servers and drivers), and thus is not directly indexed by
* slot number. The size of the table must match the size of the privilege
#include <minix/vm.h>
#include <minix/ds.h>
#include <minix/minlib.h>
+#include <minix/sched.h>
#include <machine/archtypes.h>
#include <timers.h> /* For priv.h */
#include <string.h>
#include <unistd.h>
#include <signal.h>
+#include <assert.h>
#include "proto.h"
#include "const.h"
#include "../pm/mproc.h"
/* Declare some local functions. */
-FORWARD _PROTOTYPE(void exec_image_copy, ( int boot_proc_idx,
- struct boot_image *ip, struct rproc *rp) );
FORWARD _PROTOTYPE(void boot_image_info_lookup, ( endpoint_t endpoint,
struct boot_image *image,
struct boot_image **ip, struct boot_image_priv **pp,
case RS_SHUTDOWN: result = do_shutdown(&m); break;
case RS_UPDATE: result = do_update(&m); break;
case RS_CLONE: result = do_clone(&m); break;
+ case RS_EDIT: result = do_edit(&m); break;
case GETSYSINFO: result = do_getsysinfo(&m); break;
case RS_LOOKUP: result = do_lookup(&m); break;
/* Ready messages. */
struct rprocpub *rpub;
struct boot_image image[NR_BOOT_PROCS];
struct mproc mproc[NR_PROCS];
- struct exec header;
struct boot_image_priv *boot_image_priv;
struct boot_image_sys *boot_image_sys;
struct boot_image_dev *boot_image_dev;
panic("unable to get copy of boot image table: %d", s);
}
- /* Determine the number of system services in the boot image table and
- * compute the size required for the boot image buffer.
- */
+ /* Determine the number of system services in the boot image table. */
nr_image_srvs = 0;
- boot_image_buffer_size = 0;
for(i=0;i<NR_BOOT_PROCS;i++) {
ip = &image[i];
continue;
}
nr_image_srvs++;
-
- /* Lookup the corresponding entry in the boot image sys table. */
- boot_image_info_lookup(ip->endpoint, image,
- NULL, NULL, &boot_image_sys, NULL);
-
- /* If we must keep a copy of this system service, read the header
- * and increase the size of the boot image buffer.
- */
- if(boot_image_sys->flags & SF_USE_REPL) {
- boot_image_sys->flags |= SF_USE_COPY;
- }
- if(boot_image_sys->flags & SF_USE_COPY) {
- if((s = sys_getaoutheader(&header, i)) != OK) {
- panic("unable to get copy of a.out header: %d", s);
- }
- boot_image_buffer_size += header.a_hdrlen
- + header.a_text + header.a_data;
- }
}
/* Determine the number of entries in the boot image priv table and make sure
panic("boot image table and boot image priv table mismatch");
}
- /* Allocate boot image buffer. */
- if(boot_image_buffer_size > 0) {
- boot_image_buffer = rs_startup_sbrk(boot_image_buffer_size);
- if(boot_image_buffer == (char *) -1) {
- panic("unable to allocate boot image buffer");
- }
- }
-
/* Reset the system process table. */
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
rp->r_flags = 0;
/* Initialize the system process table in 4 steps, each of them following
* the appearance of system services in the boot image priv table.
- * - Step 1: get a copy of the executable image of every system service that
- * requires it while it is not yet running.
- * In addition, set priviliges, sys properties, and dev properties (if any)
+ * - Step 1: set priviliges, sys properties, and dev properties (if any)
* for every system service.
*/
for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
rp = &rproc[boot_image_priv - boot_image_priv_table];
rpub = rp->r_pub;
- /*
- * Get a copy of the executable image if required.
- */
- rp->r_exec_len = 0;
- rp->r_exec = NULL;
- if(boot_image_sys->flags & SF_USE_COPY) {
- exec_image_copy(ip - image, ip, rp);
- }
-
/*
* Set privileges.
*/
/* Get label. */
strcpy(rpub->label, boot_image_priv->label);
- /* Get heartbeat period. */
- rpub->period = boot_image_priv->period;
-
/* Force a static priv id for system services in the boot image. */
rp->r_priv.s_id = static_priv_id(
_ENDPOINT_P(boot_image_priv->endpoint));
fill_call_mask(boot_image_priv->k_calls, NR_SYS_CALLS,
rp->r_priv.s_k_call_mask, KERNEL_CALL, TRUE);
- /* Set the privilege structure. */
+ /* Set the privilege structure. */
if(boot_image_priv->endpoint != RS_PROC_NR) {
if ((s = sys_privctl(ip->endpoint, SYS_PRIV_SET_SYS, &(rp->r_priv)))
!= OK) {
/* Get process name. */
strcpy(rpub->proc_name, ip->proc_name);
- /* Get command settings. */
- strcpy(rp->r_cmd, ip->proc_name);
+ /* Build command settings. */
+ rp->r_cmd[0]= '\0';
rp->r_script[0]= '\0';
build_cmd_dep(rp);
rp->r_stop_tm = 0; /* not exiting yet */
rp->r_restarts = 0; /* no restarts so far */
rp->r_set_resources = 0; /* don't set resources */
+ rp->r_period = 0; /* no period yet */
+ rp->r_exec = NULL; /* no in-memory copy yet */
+ rp->r_exec_len = 0;
/* Mark as in use and active. */
rp->r_flags = RS_IN_USE | RS_ACTIVE;
if(j == NR_PROCS) {
panic("unable to get pid");
}
-
- /* If we must keep a replica of this system service, create it now. */
- if(rpub->sys_flags & SF_USE_REPL) {
- if ((s = clone_service(rp)) != OK) {
- panic("unable to clone service: %d", s);
- }
- }
- }
-
- /*
- * Now complete RS initialization process in collaboration with other
- * system services.
- */
- /* Let the rest of the system know about our dynamically allocated buffer. */
- if(boot_image_buffer_size > 0) {
- boot_image_buffer = rs_startup_sbrk_synch(boot_image_buffer_size);
- if(boot_image_buffer == (char *) -1) {
- panic("unable to synch boot image buffer");
- }
}
/* Set alarm to periodically check service status. */
/* Map out our own text and data. */
unmap_ok = 1;
_minix_unmapzero();
- }
- else {
- /* Old RS instance running. */
/* Ask VM to pin memory for the new RS instance. */
- s = vm_memctl(replica_endpoint, VM_RS_MEM_PIN);
- if(s != OK) {
+ if((s = vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN)) != OK) {
panic("unable to pin memory for the new RS instance: %d", s);
}
+ }
+ else {
+ /* Old RS instance running. */
/* Set up privileges for the new instance and let it run. */
set_sys_bit(replica_rp->r_priv.s_ipc_to, static_priv_id(RS_PROC_NR));
return OK; /* signal has been delivered */
}
-/*===========================================================================*
- * exec_image_copy *
- *===========================================================================*/
-PRIVATE void exec_image_copy(boot_proc_idx, ip, rp)
-int boot_proc_idx;
-struct boot_image *ip;
-struct rproc *rp;
-{
-/* Copy the executable image of the given boot process. */
- int s;
- struct exec header;
- static char *boot_image_ptr = NULL;
-
- if(boot_image_ptr == NULL) {
- boot_image_ptr = boot_image_buffer;
- }
-
- /* Get a.out header. */
- s = ENOMEM;
- if(boot_image_buffer+boot_image_buffer_size - boot_image_ptr < sizeof(header)
- || (s = sys_getaoutheader(&header, boot_proc_idx)) != OK) {
- panic("unable to get copy of a.out header: %d", s);
- }
- memcpy(boot_image_ptr, &header, header.a_hdrlen);
- boot_image_ptr += header.a_hdrlen;
-
- /* Get text segment. */
- s = ENOMEM;
- if(boot_image_buffer+boot_image_buffer_size - boot_image_ptr < header.a_text
- || (s = rs_startup_segcopy(ip->endpoint, T, D, (vir_bytes) boot_image_ptr,
- header.a_text)) != OK) {
- panic("unable to get copy of text segment: %d", s);
- }
- boot_image_ptr += header.a_text;
-
- /* Get data segment. */
- s = ENOMEM;
- if(boot_image_buffer+boot_image_buffer_size - boot_image_ptr < header.a_data
- || (s = rs_startup_segcopy(ip->endpoint, D, D, (vir_bytes) boot_image_ptr,
- header.a_data)) != OK) {
- panic("unable to get copy of data segment: %d", s);
- }
- boot_image_ptr += header.a_data;
-
- /* Set the executable image for the given boot process. */
- rp->r_exec_len = header.a_hdrlen + header.a_text + header.a_data;
- rp->r_exec = boot_image_ptr - rp->r_exec_len;
-}
-
/*===========================================================================*
* boot_image_info_lookup *
*===========================================================================*/
if(rp) {
rpub = rp->r_pub;
- /* Disallow the call if the target is RS or a user process. */
- if(!(rp->r_priv.s_flags & SYS_PROC) || rpub->endpoint == RS_PROC_NR) {
+ /* Disallow the call if the target is a user process. */
+ if(!(rp->r_priv.s_flags & SYS_PROC)) {
return EPERM;
}
+ /* Only allow RS_EDIT for RS. */
+ if(rpub->endpoint == RS_PROC_NR) {
+ if(call != RS_EDIT) return EPERM;
+ }
+
/* Disallow the call if another call is in progress for the service. */
if(rp->r_flags & RS_LATEREPLY || rp->r_flags & RS_INITIALIZING) {
return EBUSY;
return(EPERM);
}
+ /* Do we have a copy or a command to create the service? */
+ if(!use_copy && !strcmp(rp->r_cmd, "")) {
+ printf("RS: unable to create service '%s' without a copy or command\n",
+ rpub->label);
+ free_slot(rp);
+ return(EPERM);
+ }
+
/* Now fork and branch for parent and child process (and check for error).
* After fork()ing, we need to pin RS memory again or pagefaults will occur
* on future writes.
int init_type;
{
/* Let a newly created service run. */
- int s, use_copy;
struct rprocpub *rpub;
+ int s;
rpub = rp->r_pub;
- use_copy= (rpub->sys_flags & SF_USE_COPY);
/* Allow the service to run. */
if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
rpub->dev_style2 = def_rpub->dev_style2;
/* Period. */
- if(!rpub->period && def_rpub->period) {
- rpub->period = def_rpub->period;
+ if(!rp->r_period && def_rp->r_period) {
+ rp->r_period = def_rp->r_period;
}
}
struct rproc *rp;
{
/* Free an exec image. */
- int slot_nr, has_shared_exec, is_boot_image_mem;
+ int slot_nr, has_shared_exec;
struct rproc *other_rp;
/* Search for some other slot sharing the same exec image. */
/* If nobody uses our copy of the exec image, we can try to get rid of it. */
if(!has_shared_exec) {
- is_boot_image_mem = (rp->r_exec >= boot_image_buffer
- && rp->r_exec < boot_image_buffer + boot_image_buffer_size);
-
- /* Free memory only if not part of the boot image buffer. */
- if(is_boot_image_mem) {
- if(rs_verbose)
- printf("RS: %s has exec image in the boot image buffer\n",
- srv_to_string(rp));
- }
- else {
- if(rs_verbose)
- printf("RS: %s frees exec image\n", srv_to_string(rp));
- free(rp->r_exec);
- }
+ if(rs_verbose)
+ printf("RS: %s frees exec image\n", srv_to_string(rp));
+ free(rp->r_exec);
}
else {
if(rs_verbose)
}
/*===========================================================================*
- * init_slot *
+ * edit_slot *
*===========================================================================*/
-PUBLIC int init_slot(rp, rs_start, source)
+PUBLIC int edit_slot(rp, rs_start, source)
struct rproc *rp;
struct rs_start *rs_start;
endpoint_t source;
{
-/* Initialize a slot as requested by the client. */
+/* Edit a given slot to override existing settings. */
struct rprocpub *rpub;
- char *label; /* unique name of command */
- int len; /* length of string */
- int i;
+ char *label;
+ int len;
int s;
- int basic_kc[] = { SYS_BASIC_CALLS, SYS_NULL_C };
- int basic_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C };
rpub = rp->r_pub;
-/* Obtain command name and parameters. This is a space-separated string
- * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
- */
+ /* Update command and arguments */
if (rs_start->rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG);
s=sys_datacopy(source, (vir_bytes) rs_start->rss_cmd,
SELF, (vir_bytes) rp->r_cmd, rs_start->rss_cmdlen);
/* Build cmd dependencies: argv and program name. */
build_cmd_dep(rp);
- if(rs_start->rss_label.l_len > 0) {
- /* RS_UP caller has supplied a custom label for this service. */
- int s = copy_label(source, rs_start->rss_label.l_addr,
- rs_start->rss_label.l_len, rpub->label, sizeof(rpub->label));
- if(s != OK)
- return s;
- if(rs_verbose)
- printf("RS: init_slot: using label (custom) '%s'\n", rpub->label);
- } else {
- /* Default label for the service. */
- label = rpub->proc_name;
- len= strlen(label);
- memcpy(rpub->label, label, len);
- rpub->label[len]= '\0';
- if(rs_verbose)
- printf("RS: init_slot: using label (from proc_name) '%s'\n",
- rpub->label);
- }
-
- if(rs_start->rss_nr_control > 0) {
- int i, s;
- if (rs_start->rss_nr_control > RS_NR_CONTROL)
- {
- printf("RS: init_slot: too many control labels\n");
- return EINVAL;
- }
- for (i=0; i<rs_start->rss_nr_control; i++) {
- s = copy_label(source, rs_start->rss_control[i].l_addr,
- rs_start->rss_control[i].l_len, 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) {
- printf("RS: init_slot: control labels:");
- for (i=0; i<rp->r_nr_control; i++)
- printf(" %s", rp->r_control[i]);
- printf("\n");
- }
+ /* Update label if not already set. */
+ if(!strcmp(rpub->label, "")) {
+ if(rs_start->rss_label.l_len > 0) {
+ /* RS_UP caller has supplied a custom label for this service. */
+ int s = copy_label(source, rs_start->rss_label.l_addr,
+ rs_start->rss_label.l_len, rpub->label, sizeof(rpub->label));
+ if(s != OK)
+ return s;
+ if(rs_verbose)
+ printf("RS: edit_slot: using label (custom) '%s'\n", rpub->label);
+ } else {
+ /* Default label for the service. */
+ label = rpub->proc_name;
+ len= strlen(label);
+ memcpy(rpub->label, label, len);
+ rpub->label[len]= '\0';
+ if(rs_verbose)
+ printf("RS: edit_slot: using label (from proc_name) '%s'\n",
+ rpub->label);
+ }
}
- rp->r_script[0]= '\0';
+ /* Update recovery script. */
if (rs_start->rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
- if (rs_start->rss_script != NULL)
+ if (rs_start->rss_script != NULL && !(rpub->sys_flags & SF_CORE_SRV))
{
s=sys_datacopy(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;
-
- s = rss_nice_decode(rs_start->rss_nice, &rp->r_scheduler,
- &rp->r_priority, &rp->r_quantum);
- if (s != OK) return(s);
-
- if (rs_start->rss_flags & RSS_IPC_VALID)
- {
- if (rs_start->rss_ipclen+1 > sizeof(rp->r_ipc_list))
- {
- printf("RS: ipc list too long for '%s'\n", rpub->label);
- return EINVAL;
- }
- s=sys_datacopy(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';
- /* Set system flags. */
- rpub->sys_flags = DSRV_SF;
- rp->r_exec= NULL;
- if (rs_start->rss_flags & RSS_COPY) {
+ /* Update system flags and in-memory copy. */
+ if ((rs_start->rss_flags & RSS_COPY) && !(rpub->sys_flags & SF_USE_COPY)) {
int exst_cpy;
struct rproc *rp2;
struct rprocpub *rpub2;
rpub->sys_flags |= SF_USE_REPL;
}
- /* All dynamically created services get the same privilege flags, and
+ /* Update period. */
+ if(rpub->endpoint != RS_PROC_NR) {
+ rp->r_period = rs_start->rss_period;
+ }
+
+ return OK;
+}
+
+/*===========================================================================*
+ * init_slot *
+ *===========================================================================*/
+PUBLIC int init_slot(rp, rs_start, source)
+struct rproc *rp;
+struct rs_start *rs_start;
+endpoint_t source;
+{
+/* Initialize a slot as requested by the client. */
+ struct rprocpub *rpub;
+ int i;
+ int s;
+ int basic_kc[] = { SYS_BASIC_CALLS, SYS_NULL_C };
+ int basic_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C };
+
+ rpub = rp->r_pub;
+
+ /* All dynamically created services get the same sys and privilege flags,
* allowed traps, and signal manager. Other privilege settings can be
* specified at runtime. The privilege id is dynamically allocated by
* the kernel.
*/
+ rpub->sys_flags = DSRV_SF; /* system flags */
rp->r_priv.s_flags = DSRV_F; /* privilege flags */
rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */
rp->r_priv.s_sig_mgr = DSRV_SM; /* signal manager */
- /* Copy granted resources */
+ /* Initialize control labels. */
+ if(rs_start->rss_nr_control > 0) {
+ int i, s;
+ if (rs_start->rss_nr_control > RS_NR_CONTROL)
+ {
+ printf("RS: init_slot: too many control labels\n");
+ return EINVAL;
+ }
+ for (i=0; i<rs_start->rss_nr_control; i++) {
+ s = copy_label(source, rs_start->rss_control[i].l_addr,
+ rs_start->rss_control[i].l_len, 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) {
+ printf("RS: init_slot: control labels:");
+ for (i=0; i<rp->r_nr_control; i++)
+ printf(" %s", rp->r_control[i]);
+ printf("\n");
+ }
+ }
+
+ /* Initialize IPC list. */
+ if (rs_start->rss_flags & RSS_IPC_VALID)
+ {
+ if (rs_start->rss_ipclen+1 > sizeof(rp->r_ipc_list))
+ {
+ printf("RS: ipc list too long for '%s'\n", rpub->label);
+ return EINVAL;
+ }
+ s=sys_datacopy(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';
+
+ /* Initialize granted resources */
if (rs_start->rss_nr_irq > NR_IRQ)
{
printf("RS: init_slot: too many IRQs requested\n");
(unsigned int) rpub->pci_acl.rsp_class[i].pciclass,
(unsigned int) rpub->pci_acl.rsp_class[i].mask);
}
+ rp->r_uid= rs_start->rss_uid;
+
+ s = rss_nice_decode(rs_start->rss_nice, &rp->r_scheduler,
+ &rp->r_priority, &rp->r_quantum);
+ if (s != OK) return(s);
- /* Copy kernel call mask. Inherit basic kernel calls. */
+ /* Initialize kernel call mask. Inherit basic kernel calls. */
memcpy(rp->r_priv.s_k_call_mask, rs_start->rss_system,
sizeof(rp->r_priv.s_k_call_mask));
fill_call_mask(basic_kc, NR_SYS_CALLS,
rp->r_priv.s_k_call_mask, KERNEL_CALL, FALSE);
- /* Device driver properties. */
+ /* Initialize device driver properties. */
rpub->dev_flags = DSRV_DF;
rpub->dev_nr = rs_start->rss_major;
rpub->dev_style = rs_start->rss_dev_style;
rpub->dev_style2 = STYLE_NDEV;
/* Initialize some fields. */
- rpub->period = rs_start->rss_period;
rp->r_restarts = 0; /* no restarts yet */
rp->r_set_resources= 1; /* set resources */
rp->r_old_rp = NULL; /* no old version yet */
rp->r_new_rp = NULL; /* no new version yet */
rp->r_prev_rp = NULL; /* no prev replica yet */
rp->r_next_rp = NULL; /* no next replica yet */
+ rp->r_exec = NULL; /* no in-memory copy yet */
+ rp->r_exec_len = 0;
+ rp->r_script[0]= '\0'; /* no recovery script yet */
+ rpub->label[0]= '\0'; /* no label yet */
- /* Copy VM call mask. Inherit basic VM calls. */
+ /* Initialize VM call mask. Inherit basic VM calls. */
memcpy(rpub->vm_call_mask, rs_start->rss_vm,
sizeof(rpub->vm_call_mask));
fill_call_mask(basic_vmc, NR_VM_CALLS,
rpub->vm_call_mask, VM_RQ_BASE, FALSE);
+ /* Initialize editable slot settings. */
+ s = edit_slot(rp, rs_start, source);
+ if(s != OK) {
+ return s;
+ }
+
return OK;
}
*/
#include "inc.h"
-#include "kernel/const.h"
-#include "kernel/type.h"
-#include "kernel/proc.h"
-
-EXTERN char *_brksize;
-
-PRIVATE char * _rs_startbrksize = NULL;
-PRIVATE char * _rs_endbrksize = NULL;
#define munmap _munmap
#define munmap_text _munmap_text
PUBLIC int unmap_ok = 0;
-/*===========================================================================*
- * check_mem_available *
- *===========================================================================*/
-PRIVATE int check_mem_available(char *new_brksize)
-{
-/* Check if enough memory is available to grow break size. */
- register struct mem_map *mem_sp, *mem_dp;
- vir_clicks sp_click, gap_base, sp_lower;
- int s;
- long base_of_stack, sp_delta; /* longs avoid certain problems */
- vir_bytes sp;
- struct proc proc;
- vir_clicks data_clicks;
-
- /* Get stack pointer and pointers to data/stack segment maps. */
- if ((s=sys_getproc(&proc, SELF)) != OK) {
- return(s);
- }
- sp = proc.p_reg.sp; /* stack pointer */
- mem_dp = &proc.p_memmap[D]; /* pointer to data segment map */
- mem_sp = &proc.p_memmap[S]; /* pointer to stack segment map */
-
- /* Compute how many clicks the data segment is to become. */
- data_clicks = (vir_clicks) (CLICK_CEIL(new_brksize) >> CLICK_SHIFT)
- - mem_dp->mem_vir;
-
- /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
- base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
- sp_click = sp >> CLICK_SHIFT; /* click containing sp */
- if (sp_click >= base_of_stack)
- {
- return(ENOMEM); /* sp too high */
- }
-
- /* Compute size of gap between stack and data segments. */
- sp_delta = (long) mem_sp->mem_vir - (long) sp_click;
- sp_lower = (sp_delta > 0 ? sp_click : mem_sp->mem_vir);
-
- /* Add a safety margin for future stack growth. Impossible to do right. */
-#define SAFETY_BYTES (384 * sizeof(char *))
-#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
- gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
- if (sp_lower < gap_base)
- {
- return(ENOMEM); /* data and stack collided */
- }
-
- return(OK);
-}
-
-/*===========================================================================*
- * rs_startup_sbrk *
- *===========================================================================*/
-PUBLIC void* rs_startup_sbrk(size)
-size_t size; /* the size to grow */
-{
-/* RS's own sbrk() used at startup. */
- void* addr;
- char* new_brksize;
-
- /* Check input for non-positive size or size overflows. */
- new_brksize = _brksize + size;
- if (size <= 0 || new_brksize < _brksize) {
- return( (char *) -1);
- }
-
- /* Check if enough memory is available. */
- if(check_mem_available(new_brksize) != OK) {
- return( (char *) -1);
- }
-
- /* Save initial break size. */
- if(_rs_startbrksize == NULL) {
- _rs_startbrksize = _brksize;
- }
-
- /* Set address and adjust break size. */
- addr = _brksize;
- _brksize = new_brksize;
- _rs_endbrksize = _brksize;
-
- return addr;
-}
-
-/*===========================================================================*
- * rs_startup_sbrk_synch *
- *===========================================================================*/
-PUBLIC void* rs_startup_sbrk_synch(size)
-size_t size; /* the size to grow */
-{
-/* Synchronize RS's own sbrk() with the rest of the system right after
- * startup. We use the original sbrk() here.
- */
- void* addr;
-
- /* Restore original break size. */
- _brksize = _rs_startbrksize;
-
- /* Call original sbrk() and see if we observe the same effect. */
- addr = (void*)sbrk(size);
- if(_rs_startbrksize != addr) {
- printf("Unable to synch rs_startup_sbrk() and sbrk(): addr 0x%x!=0x%x\n",
- (int) _rs_startbrksize, (int) addr);
- return( (char *) -1);
- }
- if(_rs_endbrksize != _brksize) {
- printf("Unable to synch rs_startup_sbrk() and sbrk(): size 0x%x!=0x%x\n",
- (int) _rs_endbrksize, (int) _brksize);
- return( (char *) -1);
- }
-
- return addr;
-}
-
-/*===========================================================================*
- * rs_startup_segcopy *
- *===========================================================================*/
-PUBLIC int rs_startup_segcopy(src_proc, src_seg, dst_seg, dst_vir, bytes)
-endpoint_t src_proc; /* source process */
-int src_seg; /* source memory segment */
-int dst_seg; /* destination memory segment */
-vir_bytes dst_vir; /* destination virtual address */
-phys_bytes bytes; /* how many bytes */
-{
-/* Copy a process's T, D, S segment to RS's address space. Used at startup. */
- struct proc src_p, dst_p;
- phys_bytes src_phys, dst_phys;
- int s;
-
- /* Check input. */
- if((src_seg != T && src_seg != D && src_seg != S) || bytes <= 0) {
- return EINVAL;
- }
-
- /* We don't override normal behavior when not copying to our data segment. */
- if(dst_seg != D) {
- s = sys_vircopy(src_proc, src_seg, 0, SELF, dst_seg, dst_vir, bytes);
- return(s);
- }
-
- /* Get kernel process slot for both source and destination. */
- if ((s=sys_getproc(&src_p, src_proc)) != OK) {
- return(s);
- }
- if ((s=sys_getproc(&dst_p, SELF)) != OK) {
- return(s);
- }
-
- /* Map source address to physical address. */
- src_phys = (phys_bytes) src_p.p_memmap[src_seg].mem_phys << CLICK_SHIFT;
-
- /* Check if destination address is out of bounds or overflows. */
- if(dst_vir+bytes > (vir_bytes)_rs_endbrksize
- || dst_vir < (vir_bytes)_rs_startbrksize || dst_vir+bytes < dst_vir) {
- return EFAULT;
- }
-
- /* Map destination address to physical address. */
- dst_phys = (phys_bytes) dst_p.p_memmap[D].mem_phys << CLICK_SHIFT;
- dst_phys += dst_vir - (dst_p.p_memmap[D].mem_vir << CLICK_SHIFT);
-
- /* Make a physical copy for the requested data. */
- s = sys_abscopy(src_phys, dst_phys, bytes);
-
- return(s);
-}
-
/*===========================================================================*
* munmap *
*===========================================================================*/
return _munmap_text(addrstart, len);
}
-
_PROTOTYPE( int do_refresh, (message *m));
_PROTOTYPE( int do_restart, (message *m));
_PROTOTYPE( int do_clone, (message *m));
+_PROTOTYPE( int do_edit, (message *m));
_PROTOTYPE( int do_shutdown, (message *m));
_PROTOTYPE( void do_period, (message *m));
_PROTOTYPE( int do_init_ready, (message *m));
_PROTOTYPE( void free_exec, (struct rproc *rp) );
_PROTOTYPE( int init_slot, (struct rproc *rp, struct rs_start *rs_start,
endpoint_t source) );
+_PROTOTYPE( int edit_slot, (struct rproc *rp, struct rs_start *rs_start,
+ endpoint_t source) );
_PROTOTYPE( int clone_slot, (struct rproc *rp, struct rproc **clone_rpp) );
_PROTOTYPE( void swap_slot, (struct rproc **src_rpp, struct rproc **dst_rpp) );
_PROTOTYPE( struct rproc* lookup_slot_by_label, (char *label) );
_PROTOTYPE( int rs_isokendpt, (endpoint_t endpoint, int *proc));
_PROTOTYPE( int sched_init_proc, (struct rproc *rp));
-/* memory.c */
-_PROTOTYPE( void* rs_startup_sbrk, (size_t size));
-_PROTOTYPE( void* rs_startup_sbrk_synch, (size_t size));
-_PROTOTYPE( int rs_startup_segcopy, (endpoint_t src_proc, int src_s,
- int dst_s, vir_bytes dst_vir, phys_bytes bytes));
-
/* error.c */
_PROTOTYPE( char * init_strerror, (int errnum) );
_PROTOTYPE( char * lu_strerror, (int errnum) );
struct rprocpub *rpub;
int s, r;
char label[RS_MAX_LABEL_LEN];
- char script[MAX_SCRIPT_LEN];
/* Copy label. */
s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
return OK;
}
+/*===========================================================================*
+ * do_edit *
+ *===========================================================================*/
+PUBLIC int do_edit(message *m_ptr)
+{
+ struct rproc *rp;
+ struct rprocpub *rpub;
+ struct rs_start rs_start;
+ int r;
+ char label[RS_MAX_LABEL_LEN];
+
+ /* Copy the request structure. */
+ r = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
+ if (r != OK) {
+ return r;
+ }
+
+ /* Copy label. */
+ r = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
+ rs_start.rss_label.l_len, label, sizeof(label));
+ if(r != OK) {
+ return r;
+ }
+
+ /* Lookup slot by label. */
+ rp = lookup_slot_by_label(label);
+ if(!rp) {
+ if(rs_verbose)
+ printf("RS: do_edit: service '%s' not found\n", label);
+ return ESRCH;
+ }
+ rpub = rp->r_pub;
+
+ /* Check if the call can be allowed. */
+ if((r = check_call_permission(m_ptr->m_source, RS_EDIT, rp)) != OK)
+ return r;
+
+ if(rs_verbose)
+ printf("RS: %s edits settings\n", srv_to_string(rp));
+
+ /* Edit the slot as requested. */
+ r = edit_slot(rp, &rs_start, m_ptr->m_source);
+ if(r != OK) {
+ printf("RS: do_edit: unable to edit the existing slot: %d\n", r);
+ return r;
+ }
+
+ /* Cleanup old replicas and create a new one, if necessary. */
+ if(rpub->sys_flags & SF_USE_REPL) {
+ if(rp->r_next_rp) {
+ cleanup_service(rp->r_next_rp);
+ rp->r_next_rp = NULL;
+ }
+ if ((r = clone_service(rp)) != OK) {
+ printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
+ }
+ }
+
+ return OK;
+}
+
/*===========================================================================*
* do_refresh *
*===========================================================================*/
if ((rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_UPDATING)) {
/* Compute period. */
- period = rpub->period;
+ period = rp->r_period;
if(rp->r_flags & RS_INITIALIZING) {
period = RS_INIT_T;
}
/* 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 > rpub->period) {
+ else if (now - rp->r_check_tm > rp->r_period) {
notify(rpub->endpoint); /* request status */
rp->r_check_tm = now; /* mark time */
}
* handled before user-scheduled ones.
*/
PUBLIC struct boot_image_priv boot_image_priv_table[] = {
-/*endpoint, label, flags, traps, ipcto, sigmgr, sched, kcalls, vmcalls, T */
-{RS_PROC_NR, "rs", RSYS_F, RSYS_T, RSYS_M, RSYS_SM, KERN_SCH, rs_kc, rs_vmc, 0 },
-{VM_PROC_NR, "vm", VM_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, vm_kc, vm_vmc, 0 },
-{PM_PROC_NR, "pm", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, pm_kc, pm_vmc, 0 },
-{SCHED_PROC_NR,"sched", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, sched_kc, sched_vmc, 0 },
-{VFS_PROC_NR, "vfs", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, vfs_kc, vfs_vmc, 0 },
-{DS_PROC_NR, "ds", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, ds_kc, ds_vmc, 0 },
-{TTY_PROC_NR, "tty", SRV_F, SRV_T, SRV_M, SRV_SM, USER_SCH, tty_kc, tty_vmc, 0 },
-{MEM_PROC_NR, "memory", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, mem_kc, mem_vmc, 0 },
-{LOG_PROC_NR, "log", SRV_F, SRV_T, SRV_M, SRV_SM, USER_SCH, log_kc, log_vmc, 0 },
-{MFS_PROC_NR,"fs_imgrd", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, mfs_kc, mfs_vmc, 0 },
-{PFS_PROC_NR, "pfs", SRV_F, SRV_T, SRV_M, SRV_SM, USER_SCH, pfs_kc, pfs_vmc, 0 },
-{INIT_PROC_NR, "init", RUSR_F, RUSR_T, RUSR_M, RUSR_SM, NONE, rusr_kc, rusr_vmc,0 },
-{NULL_BOOT_NR, "", 0, 0, 0, 0, 0, no_kc, no_vmc, 0 }
+/*endpoint, label, flags, traps, ipcto, sigmgr, sched, kcalls, vmcalls */
+{RS_PROC_NR, "rs", RSYS_F, RSYS_T, RSYS_M, RSYS_SM, KERN_SCH, rs_kc, rs_vmc },
+{VM_PROC_NR, "vm", VM_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, vm_kc, vm_vmc },
+{PM_PROC_NR, "pm", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, pm_kc, pm_vmc },
+{SCHED_PROC_NR,"sched", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, sched_kc, sched_vmc },
+{VFS_PROC_NR, "vfs", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, vfs_kc, vfs_vmc },
+{DS_PROC_NR, "ds", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, ds_kc, ds_vmc },
+{TTY_PROC_NR, "tty", SRV_F, SRV_T, SRV_M, SRV_SM, USER_SCH, tty_kc, tty_vmc },
+{MEM_PROC_NR, "memory", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, mem_kc, mem_vmc },
+{LOG_PROC_NR, "log", SRV_F, SRV_T, SRV_M, SRV_SM, USER_SCH, log_kc, log_vmc },
+{MFS_PROC_NR,"fs_imgrd", SRV_F, SRV_T, SRV_M, SRV_SM, KERN_SCH, mfs_kc, mfs_vmc },
+{PFS_PROC_NR, "pfs", SRV_F, SRV_T, SRV_M, SRV_SM, USER_SCH, pfs_kc, pfs_vmc },
+{INIT_PROC_NR, "init", RUSR_F, RUSR_T, RUSR_M, RUSR_SM, NONE, rusr_kc, rusr_vmc },
+{NULL_BOOT_NR, "", 0, 0, 0, 0, 0, no_kc, no_vmc }
};
/* Definition of the boot image sys table. */
{ VM_PROC_NR, VM_SF },
{ PM_PROC_NR, SRVR_SF },
{ VFS_PROC_NR, SRVR_SF },
- { LOG_PROC_NR, SRV_SF | SF_USE_REPL },
- { MFS_PROC_NR, SF_NEED_COPY | SF_USE_COPY },
- { PFS_PROC_NR, SRV_SF | SF_USE_COPY },
+ { LOG_PROC_NR, SRV_SF },
+ { MFS_PROC_NR, 0 },
+ { PFS_PROC_NR, SRV_SF },
{ DEFAULT_BOOT_NR, SRV_SF } /* default entry */
};
endpoint_t sched; /* scheduler */
int *k_calls; /* allowed kernel calls */
int *vm_calls; /* allowed vm calls */
- long period; /* heartbeat period (or zero) */
};
/* Definition of an entry of the boot image sys table. */
long r_backoff; /* number of periods to wait before revive */
unsigned r_flags; /* status and policy flags */
+ long r_period; /* heartbeat period (or zero) */
clock_t r_check_tm; /* timestamp of last check */
clock_t r_alive_tm; /* timestamp of last heartbeat */
clock_t r_stop_tm; /* timestamp of SIGTERM signal */
image: includes
$(MAKE) -C ../kernel
- $(MAKE) -C ../servers all
- $(MAKE) -C ../drivers all
+ $(MAKE) -C ../servers all install
+ $(MAKE) -C ../drivers all install
installboot -image $@ $(PROGRAMS)
# rebuild the program or system libraries