int i;
network_t *np;
struct sigaction sa;
- ssize_t r= -1;
- buf_t *bp= nil;
+ ssize_t r;
+ buf_t *bp;
static struct timeval eventtv;
+main:
+ r = -1;
+ bp = nil;
program= argv[0];
start= now= time(nil);
}
}
}
- if (debug >= 1) printf("Nothing more to do! Bailing out...\n");
+ if (debug >= 1) printf("Nothing more to do! Starting over...\n");
+ sleep(2);
+ goto main;
+
return 0;
}
16,0)
des="pseudo random number generator" dev=urandom
;;
+ 17,0)
+ des="hello" dev=hello
+ ;;
BAD,BAD)
des= dev=
;;
ttypa ttypb ttypc ttypd ttype ttypf \
ttyq0 ttyq1 ttyq2 ttyq3 ttyq4 ttyq5 ttyq6 ttyq7 ttyq8 ttyq9 \
ttyqa ttyqb ttyqc ttyqd ttyqe ttyqf \
- eth klog random filter
+ eth klog random filter hello
;;
0:|1:-\?)
cat >&2 <<EOF
kbd # Make /dev/kbd
kbdaux # Make /dev/kbdaux
filter # Make /dev/filter
+ hello # Make /dev/hello
video # Make /dev/video
std # All standard devices
EOF
$e mknod filter b 11 0
$e chmod 644 filter
;;
+ hello)
+ # hello driver
+ $e mknod hello c 17 0
+ $e chmod 644 hello
+ ;;
*)
echo "$0: don't know about $dev" >&2
ex=1
if [ $# -gt 0 ]
then ARGS="-args $@"
fi
-/bin/service up /sbin/readclock.drv -config /etc/system.conf -script /etc/rs.single $ARGS
+/bin/service up /sbin/readclock.drv -config /etc/system.conf -period 5HZ -script /etc/rs.single $ARGS
-20100316:
- /usr/man/man9 is required
- # mkdir /usr/man/man9
-20100308:
- Include directory reorganization:
- # mv /usr/include/ibm /usr/include/i386
- # ln -s /usr/include/i386 /usr/include/machine
- Install(1) updates:
- # cd commands/simple && make /bin/install
-20100303:
- Gas2ack updates: Run 'make install' in commands/i386/gas2ack
-20100215:
- Make(1) has been replaced: Run 'make install' in commands/make
- Mkdep updates: Copy commands/scripts/mkdep.sh to /usr/bin/mkdep
- Make(1) needs mkfiles: Copy files in etc/mk to /etc/mk
- ACK update: Copy commands/i386/acd.descr to /usr/lib/descr
- End.a renamed:
- -Copy /usr/lib/i86/end.a to /usr/lib/i86/libend.a
- -Copy /usr/lib/i386/end.a to /usr/lib/i386/libend.a
- -Copy /usr/gnu/lib/end.a to /usr/gnu/lib/libend.a
- Asmconv updates: Run 'make install' in commands/i386/asmconv
-20091212:
- /etc/drivers.conf has been renamed to /etc/system.conf.
- user "service" has been added to password file /etc/passwd.
20060818:
You need flex in your $PATH, which has become part of the base
system. This needs bigger binaries.
20091006 (r5422):
OSS requires an improved make to be compiled; run "make install"
in /usr/src/commands/make before running "make world".
+20091212:
+ /etc/drivers.conf has been renamed to /etc/system.conf.
+ user "service" has been added to password file /etc/passwd.
+20100215:
+ Make(1) has been replaced: Run 'make install' in commands/make
+ Mkdep updates: Copy commands/scripts/mkdep.sh to /usr/bin/mkdep
+ Make(1) needs mkfiles: Copy files in etc/mk to /etc/mk
+ ACK update: Copy commands/i386/acd.descr to /usr/lib/descr
+ End.a renamed:
+ -Copy /usr/lib/i86/end.a to /usr/lib/i86/libend.a
+ -Copy /usr/lib/i386/end.a to /usr/lib/i386/libend.a
+ -Copy /usr/gnu/lib/end.a to /usr/gnu/lib/libend.a
+ Asmconv updates: Run 'make install' in commands/i386/asmconv
+20100303:
+ Gas2ack updates: Run 'make install' in commands/i386/gas2ack
+20100308:
+ Include directory reorganization:
+ # mv /usr/include/ibm /usr/include/i386
+ # ln -s /usr/include/i386 /usr/include/machine
+ Install(1) updates:
+ # cd commands/simple && make /bin/install
+20100316:
+ /usr/man/man9 is required
+ # mkdir /usr/man/man9
+20100317:
+ /usr/src/etc/system.conf updated to ignore default kernel calls: copy
+ it (or merge it) to /etc/system.conf.
+ The hello driver (/dev/hello) added to the distribution:
+ # cd /usr/src/commands/scripts && make clean install
+ # cd /dev && MAKEDEV hello
+
cd ./log && $(MAKE) $@
cd ./bios_wini && $(MAKE) $@
cd ./filter && $(MAKE) $@
+ cd ./hello && $(MAKE) $@
cd ./random && $(MAKE) $@
cd ./readclock && $(MAKE) $@
cd ./dp8390 && $(MAKE) $@
#include <string.h>
#include <unistd.h>
#include <machine/vm.h>
+#include <signal.h>
#include <minix/com.h>
#include <minix/const.h>
#include <minix/ipc.h>
static int do_add4pci(message *m);
static void add_range(u32_t busaddr, u32_t size);
static void del_range(u32_t busaddr, u32_t size);
-static void do_pm_notify(message *m);
static void report_exceptions(void);
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
int main(void)
{
r= sef_receive(ANY, &m);
if (r != OK)
panic("sef_receive failed: %d", r);
- if (is_notify(m.m_type)) {
- if (_ENDPOINT_P(m.m_source) == PM_PROC_NR) {
- do_pm_notify(&m);
- continue;
- }
- }
- else if (m.m_type == IOMMU_MAP) {
+ if (m.m_type == IOMMU_MAP) {
r= do_add4pci(&m);
m.m_type= r;
send(m.m_source, &m);
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int r;
+ endpoint_t proc_e;
+ phys_bytes base, size;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (;;)
+ {
+ r= getdma(&proc_e, &base, &size);
+ if (r == -1)
+ {
+ if (errno != -EAGAIN)
+ {
+ printf(
+ "amddev: getdma failed: %d\n",
+ errno);
+ }
+ break;
+ }
+
+ printf(
+ "amddev: deleting 0x%x@0x%x for proc %d\n",
+ size, base, proc_e);
+ del_range(base, size);
+ r= deldma(proc_e, base, size);
+ if (r == -1)
+ {
+ printf("amddev: deldma failed: %d\n",
+ errno);
+ break;
+ }
+ }
+}
+
/* Returns 0 if no device found, or 1 if a device is found. */
static int find_dev(devindp, capaddrp)
int *devindp;
}
}
-static void do_pm_notify(message *m)
-{
- int r;
- endpoint_t proc_e;
- phys_bytes base, size;
-
- if (m->m_source != PM_PROC_NR)
- {
- printf("amddev`do_pm_notify: notify not from PM (from %d)\n",
- m->m_source);
- return;
- }
-
- for (;;)
- {
- r= getdma(&proc_e, &base, &size);
- if (r == -1)
- {
- if (errno != -EAGAIN)
- {
- printf(
- "amddev`do_pm_notify: getdma failed: %d\n",
- errno);
- }
- break;
- }
-
- printf(
- "amddev`do_pm_notify: deleting 0x%x@0x%x for proc %d\n",
- size, base, proc_e);
- del_range(base, size);
- r= deldma(proc_e, base, size);
- if (r == -1)
- {
- printf("amddev`do_pm_notify: deldma failed: %d\n",
- errno);
- break;
- }
- }
-}
-
static void report_exceptions(void)
{
u32_t status;
w_transfer, /* do the I/O */
nop_cleanup, /* nothing to clean up */
w_geometry, /* tell the geometry of the disk */
- nop_signal, /* no cleanup needed on shutdown */
nop_alarm, /* ignore leftover alarms */
nop_cancel, /* ignore CANCELs */
nop_select, /* ignore selects */
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
{
/* Initialize the at_wini driver. */
- struct sigaction sa;
-
- /* Install signal handlers. Ask PM to transform signal into message. */
system_hz = sys_hz();
init_buffer();
w_identify_wakeup_ticks = WAKEUP_TICKS;
wakeup_ticks = WAKEUP_TICKS;
- sa.sa_handler = SIG_MESS;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGTERM,&sa,NULL)<0) panic("sigaction failed: %d", errno);
-
/* Set special disk parameters. */
init_params();
- signal(SIGTERM, SIG_IGN);
return(OK);
}
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
#include "../drivers.h"
-#include <signal.h>
#include <sys/mman.h>
#include <minix/ds.h>
#include <minix/vm.h>
printf("ATL2: unable to send reply (%d)\n", r);
}
-/*===========================================================================*
- * atl2_shutdown *
- *===========================================================================*/
-PRIVATE void atl2_shutdown(void)
-{
- /* Shut down this driver. Stop the device, and deallocate resources
- * as proof of concept.
- */
- int r;
-
- atl2_stop();
-
- if ((r = sys_irqrmpolicy(&state.hook_id)) != OK)
- panic("unable to deregister IRQ: %d", r);
-
- free_contig(state.txd_base, ATL2_TXD_BUFSIZE);
- free_contig(state.txs_base, ATL2_TXS_COUNT * sizeof(u32_t));
- free_contig(state.rxd_base_u,
- state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE);
-
- vm_unmap_phys(SELF, state.base, ATL2_MMAP_SIZE);
-
- /* We cannot free the PCI device at this time. */
-
- exit(0);
-}
-
/*===========================================================================*
* atl2_dump_link *
*===========================================================================*/
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* In case of a termination signal, shut down this driver.
+ * Stop the device, and deallocate resources as proof of concept.
+ */
+ int r;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ atl2_stop();
+
+ if ((r = sys_irqrmpolicy(&state.hook_id)) != OK)
+ panic("unable to deregister IRQ: %d", r);
+
+ free_contig(state.txd_base, ATL2_TXD_BUFSIZE);
+ free_contig(state.txs_base, ATL2_TXS_COUNT * sizeof(u32_t));
+ free_contig(state.rxd_base_u,
+ state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE);
+
+ vm_unmap_phys(SELF, state.base, ATL2_MMAP_SIZE);
+
+ /* We cannot free the PCI device at this time. */
+
+ exit(0);
+}
+
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
/* No support for live update yet. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
break;
- case PM_PROC_NR: /* signal */
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- atl2_shutdown();
-
- break;
-
case TTY_PROC_NR: /* function key */
atl2_dump();
FORWARD _PROTOTYPE( void msg_write, (message *m_ptr) );
FORWARD _PROTOTYPE( void msg_read, (message *m_ptr) );
FORWARD _PROTOTYPE( void msg_hardware, (void) );
-FORWARD _PROTOTYPE( void msg_sig_stop, (void) );
FORWARD _PROTOTYPE( void msg_status, (message *m_ptr) );
FORWARD _PROTOTYPE( int init_driver, (void) );
FORWARD _PROTOTYPE( int open_sub_dev, (int sub_dev_nr, int operation) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
PUBLIC int is_status_msg_expected = FALSE;
case HARDWARE:
msg_hardware();
break;
- case PM_PROC_NR:
- msg_sig_stop();
- break;
default:
dprint("%s: %d uncaught notify!\n",
drv.DriverName, mess.m_type);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
error("%s: init driver couldn't set IRQ policy", drv.DriverName, i);
return EIO;
}
- irq_hook_set = TRUE; /* now msg_sig_stop knows it must unregister policy*/
+ irq_hook_set = TRUE; /* now signal handler knows it must unregister policy*/
return OK;
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int i;
+ char irq;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i = 0; i < drv.NrOfSubDevices; i++) {
+ drv_stop(i); /* stop all sub devices */
+ }
+ if (irq_hook_set) {
+ if (sys_irqdisable(&irq_hook_id) != OK) {
+ error("Could not disable IRQ\n");
+ }
+ /* get irq from device driver*/
+ if (drv_get_irq(&irq) != OK) {
+ error("Msg SIG_STOP Couldn't get IRQ");
+ }
+ /* remove the policy */
+ if (sys_irqrmpolicy(&irq_hook_id) != OK) {
+ error("%s: Could not disable IRQ\n",drv.DriverName);
+ }
+ }
+}
PRIVATE int msg_open (int minor_dev_nr) {
int r, read_chan, write_chan, io_ctl;
is_status_msg_expected = FALSE;
}
-
-PRIVATE void msg_sig_stop(void)
-{
- int i; char irq;
- for (i = 0; i < drv.NrOfSubDevices; i++) {
- drv_stop(i); /* stop all sub devices */
- }
- if (irq_hook_set) {
- if (sys_irqdisable(&irq_hook_id) != OK) {
- error("Could not disable IRQ\n");
- }
- /* get irq from device driver*/
- if (drv_get_irq(&irq) != OK) {
- error("Msg SIG_STOP Couldn't get IRQ");
- }
- /* remove the policy */
- if (sys_irqrmpolicy(&irq_hook_id) != OK) {
- error("%s: Could not disable IRQ\n",drv.DriverName);
- }
- }
-}
-
-
/* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/
PRIVATE void handle_int_write(int sub_dev_nr)
{
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
w_transfer, /* do the I/O */
nop_cleanup, /* no cleanup needed */
w_geometry, /* tell the geometry of the disk */
- nop_signal, /* no cleanup needed on shutdown */
nop_alarm, /* ignore leftover alarms */
nop_cancel, /* ignore CANCELs */
nop_select, /* ignore selects */
PRIVATE dpeth_t de_table[DE_PORT_NR];
PRIVATE const char *progname;
-int sef_cb_init(int type, sef_init_info_t *info)
-{
- int r;
- int fkeys, sfkeys;
- endpoint_t tasknr;
- /* Request function key for debug dumps */
- fkeys = sfkeys = 0; bit_set(sfkeys, DE_FKEY);
- if ((fkey_map(&fkeys, &sfkeys)) != OK)
- printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno);
-
- /* Try to notify inet that we are present (again) */
- r = ds_retrieve_label_num("inet", &tasknr);
- if (r == OK)
- notify(tasknr);
- else if(r != ESRCH)
- printf("%s unable to notify inet: %d\n", str_DevName, r);
-
- return OK;
-}
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+EXTERN char **env_argv;
/*===========================================================================*
* main *
message m;
int r;
- (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
-
+ /* SEF local startup. */
env_setargs(argc, argv);
-
- sef_setcb_init_fresh(sef_cb_init);
- sef_setcb_init_restart(sef_cb_init);
- sef_startup();
+ sef_local_startup();
while (TRUE)
{
}
}
break;
- case PM_PROC_NR:
- exit(0);
- break;
default:
printf("ignoring notify from %d\n", m.m_source);
break;
}
}
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+ /* Register init callbacks. */
+ sef_setcb_init_fresh(sef_cb_init_fresh);
+ sef_setcb_init_restart(sef_setcb_init_fresh);
+
+ /* No support for live update yet. */
+
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler_term);
+
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
+/*===========================================================================*
+ * sef_cb_init_fresh *
+ *===========================================================================*/
+PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
+{
+/* Initialize the DEC 21140A driver. */
+ int r;
+ int fkeys, sfkeys;
+ endpoint_t tasknr;
+
+ (progname=strrchr(env_argv[0],'/')) ? progname++ : (progname=env_argv[0]);
+
+ /* Request function key for debug dumps */
+ fkeys = sfkeys = 0; bit_set(sfkeys, DE_FKEY);
+ if ((fkey_map(&fkeys, &sfkeys)) != OK)
+ printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno);
+
+ /* Try to notify inet that we are present (again) */
+ r = ds_retrieve_label_num("inet", &tasknr);
+ if (r == OK)
+ notify(tasknr);
+ else if(r != ESRCH)
+ printf("%s unable to notify inet: %d\n", str_DevName, r);
+
+ return OK;
+}
+
PRIVATE void do_get_stat_s(message * mp)
{
int port, rc;
_PROTOTYPE( static void dp_check_ints, (dpeth_t *dep) );
_PROTOTYPE( static void dp_recv, (dpeth_t *dep) );
_PROTOTYPE( static void dp_send, (dpeth_t *dep) );
-_PROTOTYPE( static void dp8390_stop, (void) );
_PROTOTYPE( static void dp_getblock, (dpeth_t *dep, int page,
size_t offset, size_t size, void *dst) );
_PROTOTYPE( static void dp_pio8_getblock, (dpeth_t *dep, int page,
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
case HARDWARE:
r = handle_hw_intr();
break;
- case PM_PROC_NR:
- {
- sigset_t set;
-
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- dp8390_stop();
-
- break;
- }
case CLOCK:
printf("dp8390: notify from CLOCK\n");
break;
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ message mess;
+ int i;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i= 0; i<DE_PORT_NR; i++)
+ {
+ if (de_table[i].de_mode != DEM_ENABLED)
+ continue;
+ mess.m_type= DL_STOP;
+ mess.DL_PORT= i;
+ do_stop(&mess);
+ }
+}
+
#if 0
/*===========================================================================*
* dp8390_dump *
}
#endif
-/*===========================================================================*
- * dp8390_stop *
- *===========================================================================*/
-static void dp8390_stop()
-{
- message mess;
- int i;
-
- for (i= 0; i<DE_PORT_NR; i++)
- {
- if (de_table[i].de_mode != DEM_ENABLED)
- continue;
- mess.m_type= DL_STOP;
- mess.DL_PORT= i;
- do_stop(&mess);
- }
-}
-
#if ENABLE_PCI
/*===========================================================================*
* pci_conf *
return;
}
-PRIVATE void handle_system_signal(message *m)
-{
- sigset_t set;
- int port;
-
- if (getsigset(&set) != 0) return;
-
- if (sigismember(&set, SIGTERM)) { /* Shut down */
- for (port = 0; port < DE_PORT_NR; port += 1) {
- if (de_table[port].de_mode == DEM_ENABLED) {
- m->m_type = DL_STOP;
- m->DL_PORT = port;
- do_stop(m);
- }
- }
- }
-}
-
PRIVATE void handle_hw_intr(void)
{
dpeth_t *dep;
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN char **env_argv;
/*
/* Function key pressed */
do_dump(&m);
break;
- case PM_PROC_NR:
- handle_system_signal(&m);
- break;
default:
/* Invalid message type */
panic(TypeErrMsg, m.m_type);
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int port;
+ message m;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (port = 0; port < DE_PORT_NR; port += 1) {
+ if (de_table[port].de_mode == DEM_ENABLED) {
+ m.m_type = DL_STOP;
+ m.DL_PORT = port;
+ do_stop(&m);
+ }
+ }
+}
+
/** dp.c **/
_PROTOTYPE( PRIVATE void e1000_getstat_s, (message *mp) );
_PROTOTYPE( PRIVATE void e1000_getname, (message *mp) );
_PROTOTYPE( PRIVATE void e1000_interrupt, (message *mp) );
-_PROTOTYPE( PRIVATE void e1000_signal, (void) );
_PROTOTYPE( PRIVATE int e1000_link_changed, (e1000_t *e) );
_PROTOTYPE( PRIVATE void e1000_stop, (void) );
_PROTOTYPE( PRIVATE e1000_t * e1000_port, (int port) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
case HARDWARE:
e1000_interrupt(&m);
break;
-
- case PM_PROC_NR:
- e1000_signal();
- break;
-
+
case CLOCK:
break;
}
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ E1000_DEBUG(3, ("e1000: got signal\n"));
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ e1000_stop();
+}
+
/*===========================================================================*
* e1000_init *
*===========================================================================*/
}
}
-/*===========================================================================*
- * e1000_signal *
- *===========================================================================*/
-PRIVATE void e1000_signal(void)
-{
- sigset_t sigset;
-
- E1000_DEBUG(3, ("e1000: signal()\n"));
-
- /* Try to obtain signal set from PM. */
- if (getsigset(&sigset) != 0)
- {
- return;
- }
- /* Check for known signals. */
- if (sigismember(&sigset, SIGTERM))
- {
- e1000_stop();
- }
-}
-
/*===========================================================================*
* e1000_link_changed *
*===========================================================================*/
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
return OK;
}
-/*===========================================================================*
- * got_signal *
- *===========================================================================*/
-static void got_signal(void)
-{
- sigset_t set;
-
- /* See if PM sent us a SIGTERM. */
- if (getsigset(&set) != 0) return;
-
- if (!sigismember(&set, SIGTERM)) return;
-
- /* If so, shut down this driver. */
-#if DEBUG
- printf("Filter: shutdown...\n");
-#endif
-
- driver_shutdown();
-
- exit(0);
-}
-
/*===========================================================================*
* main *
*===========================================================================*/
m_in.m_type, m_in.m_source);
#endif
- if (is_notify(m_in.m_type) && m_in.m_source == PM_PROC_NR)
- got_signal();
-
who_e = m_in.m_source;
proc_e = m_in.IO_ENDPT;
grant_id = (cp_grant_id_t) m_in.IO_GRANT;
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ /* If so, shut down this driver. */
+#if DEBUG
+ printf("Filter: shutdown...\n");
+#endif
+
+ driver_shutdown();
+
+ exit(0);
+}
+
*===========================================================================*/
void flt_sleep(int secs)
{
- /* Sleep for the given number of seconds. Don't use sleep(), as that
- * will end up calling select() to VFS. This implementation could be
- * improved.
- */
-
- signal(SIGALRM, got_alarm);
- alarm(secs);
+ u32_t system_hz;
- pause();
+ /* Sleep for the given number of seconds. */
+ system_hz = sys_hz();
+ tickdelay(system_hz * secs);
}
+
FORWARD _PROTOTYPE( int f_intr_wait, (void) );
FORWARD _PROTOTYPE( int read_id, (void) );
FORWARD _PROTOTYPE( int f_do_open, (struct driver *dp, message *m_ptr) );
-FORWARD _PROTOTYPE( void floppy_stop, (struct driver *dp, sigset_t *set));
FORWARD _PROTOTYPE( int test_read, (int density) );
FORWARD _PROTOTYPE( void f_geometry, (struct partition *entry) );
f_transfer, /* do the I/O */
f_cleanup, /* cleanup before sending reply to user process */
f_geometry, /* tell the geometry of the diskette */
- floppy_stop, /* floppy cleanup on shutdown */
f_expire_tmrs,/* expire all alarm timers */
nop_cancel,
nop_select,
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
PUBLIC int last_transfer_opcode;
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
if ((s=sys_irqenable(&irq_hook_id)) != OK)
panic("Couldn't enable IRQs: %d", s);
- /* Ignore signals */
- signal(SIGHUP, SIG_IGN);
-
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int s;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ /* Stop all activity and cleanly exit with the system. */
+ if ((s=sys_outb(DOR, ENABLE_INT)) != OK)
+ panic("Sys_outb failed: %d", s);
+ exit(0);
+}
+
/*===========================================================================*
* f_expire_tmrs *
*===========================================================================*/
/* First check the DMA memory address not to exceed maximum. */
if (floppy_buf_phys != (floppy_buf_phys & DMA_ADDR_MASK)) {
- printf("floppy: DMA denied because address out of range");
+ printf("floppy: DMA denied because address out of range\n");
return(EIO);
}
panic("Sys_outb in stop_motor() failed: %d", s);
}
-/*===========================================================================*
- * floppy_stop *
- *===========================================================================*/
-PRIVATE void floppy_stop(struct driver *dp, sigset_t *set)
-{
-/* Stop all activity and cleanly exit with the system. */
- int s;
- if (sigismember(set, SIGTERM)) {
- if ((s=sys_outb(DOR, ENABLE_INT)) != OK)
- panic("Sys_outb in floppy_stop() failed: %d", s);
- exit(0);
- }
-}
-
/*===========================================================================*
* seek *
*===========================================================================*/
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
_PROTOTYPE( static void fxp_watchdog_f, (timer_t *tp) );
_PROTOTYPE( static int fxp_link_changed, (fxp_t *fp) );
_PROTOTYPE( static void fxp_report_link, (fxp_t *fp) );
-_PROTOTYPE( static void fxp_stop, (void));
_PROTOTYPE( static void reply, (fxp_t *fp, int err, int may_block) );
_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
_PROTOTYPE( static u16_t eeprom_read, (fxp_t *fp, int reg) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
case HARDWARE:
handle_hw_intr();
break;
- case PM_PROC_NR:
- {
- sigset_t set;
-
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- fxp_stop();
-
- break;
- }
case CLOCK:
fxp_expire_timers();
break;
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int i;
+ port_t port;
+ fxp_t *fp;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
+ {
+ if (fp->fxp_mode != FM_ENABLED)
+ continue;
+ if (!(fp->fxp_flags & FF_ENABLED))
+ continue;
+ port= fp->fxp_base_port;
+
+ /* Reset device */
+ if (debug)
+ printf("%s: resetting device\n", fp->fxp_name);
+ fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
+ }
+ exit(0);
+}
+
/*===========================================================================*
* fxp_init *
*===========================================================================*/
;
}
-/*===========================================================================*
- * fxp_stop *
- *===========================================================================*/
-static void fxp_stop()
-{
- int i;
- port_t port;
- fxp_t *fp;
-
- for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
- {
- if (fp->fxp_mode != FM_ENABLED)
- continue;
- if (!(fp->fxp_flags & FF_ENABLED))
- continue;
- port= fp->fxp_base_port;
-
- /* Reset device */
- if (debug)
- printf("%s: resetting device\n", fp->fxp_name);
- fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
- }
- exit(0);
-}
-
/*===========================================================================*
* reply *
*===========================================================================*/
--- /dev/null
+#
+# Makefile for the hello driver.
+#
+DRIVER = hello
+
+#
+# Directories.
+#
+u = /usr
+i = $u/include
+s = $i/sys
+m = $i/minix
+b = $i/ibm
+d = ..
+
+#
+# Build Programs, Flags and Variables.
+#
+CC = exec cc
+CFLAGS = -I$i $(CPROFILE)
+LDFLAGS = -i -L../libdriver
+LIBS = -ldriver -lsys
+OBJ = hello.o
+
+# build local binary
+all build: $(DRIVER)
+$(DRIVER): $(OBJ)
+ $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
+ install -S 128k $(DRIVER)
+
+# install with other drivers
+install: /usr/sbin/$(DRIVER)
+/usr/sbin/$(DRIVER): $(DRIVER)
+ install -o root -cs $? $@
+
+# clean up local files
+clean:
+ rm -f *.o $(DRIVER)
+
+depend:
+ mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
+
+# Include generated dependencies.
+include .depend
\ No newline at end of file
--- /dev/null
+#include "../drivers.h"
+#include "../libdriver/driver.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <minix/ds.h>
+#include "hello.h"
+
+/*
+ * Function prototypes for the hello driver.
+ */
+FORWARD _PROTOTYPE( char * hello_name, (void) );
+FORWARD _PROTOTYPE( int hello_open, (struct driver *d, message *m) );
+FORWARD _PROTOTYPE( int hello_close, (struct driver *d, message *m) );
+FORWARD _PROTOTYPE( struct device * hello_prepare, (int device) );
+FORWARD _PROTOTYPE( int hello_transfer, (int procnr, int opcode,
+ u64_t position, iovec_t *iov,
+ unsigned nr_req) );
+FORWARD _PROTOTYPE( void hello_geometry, (struct partition *entry) );
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+FORWARD _PROTOTYPE( int sef_cb_init, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( int sef_cb_lu_state_save, (int) );
+FORWARD _PROTOTYPE( int lu_state_restore, (void) );
+
+/* Entry points to the hello driver. */
+PRIVATE struct driver hello_tab =
+{
+ hello_name,
+ hello_open,
+ hello_close,
+ nop_ioctl,
+ hello_prepare,
+ hello_transfer,
+ nop_cleanup,
+ hello_geometry,
+ nop_alarm,
+ nop_cancel,
+ nop_select,
+ nop_ioctl,
+ do_nop,
+};
+
+/** Represents the /dev/hello device. */
+PRIVATE struct device hello_device;
+
+/** State variable to count the number of times the device has been opened. */
+PRIVATE int open_counter;
+
+PRIVATE char * hello_name(void)
+{
+ printf("hello_name()\n");
+ return "hello";
+}
+
+PRIVATE int hello_open(d, m)
+ struct driver *d;
+ message *m;
+{
+ printf("hello_open(). Called %d time(s).\n", ++open_counter);
+ return OK;
+}
+
+PRIVATE int hello_close(d, m)
+ struct driver *d;
+ message *m;
+{
+ printf("hello_close()\n");
+ return OK;
+}
+
+PRIVATE struct device * hello_prepare(dev)
+ int dev;
+{
+ hello_device.dv_base.lo = 0;
+ hello_device.dv_base.hi = 0;
+ hello_device.dv_size.lo = strlen(HELLO_MESSAGE);
+ hello_device.dv_size.hi = 0;
+ return &hello_device;
+}
+
+PRIVATE int hello_transfer(proc_nr, opcode, position, iov, nr_req)
+ int proc_nr;
+ int opcode;
+ u64_t position;
+ iovec_t *iov;
+ unsigned nr_req;
+{
+ int bytes, ret;
+
+ printf("hello_transfer()\n");
+
+ bytes = strlen(HELLO_MESSAGE) - position.lo < iov->iov_size ?
+ strlen(HELLO_MESSAGE) - position.lo : iov->iov_size;
+
+ if (bytes <= 0)
+ {
+ return OK;
+ }
+ switch (opcode)
+ {
+ case DEV_GATHER_S:
+ ret = sys_safecopyto(proc_nr, iov->iov_addr, 0,
+ (vir_bytes) (HELLO_MESSAGE + position.lo),
+ bytes, D);
+ iov->iov_size -= bytes;
+ break;
+
+ default:
+ return EINVAL;
+ }
+ return ret;
+}
+
+PRIVATE void hello_geometry(entry)
+ struct partition *entry;
+{
+ printf("hello_geometry()\n");
+ entry->cylinders = 0;
+ entry->heads = 0;
+ entry->sectors = 0;
+}
+
+PRIVATE int sef_cb_lu_state_save(int state) {
+/* Save the state. */
+ ds_publish_u32("open_counter", open_counter, DSF_OVERWRITE);
+
+ return OK;
+}
+
+PRIVATE int lu_state_restore() {
+/* Restore the state. */
+ u32_t value;
+
+ ds_retrieve_u32("open_counter", &value);
+ ds_delete_u32("open_counter");
+ open_counter = (int) value;
+
+ return OK;
+}
+
+PRIVATE void sef_local_startup()
+{
+ /*
+ * Register init callbacks. Use the same function for all event types
+ */
+ sef_setcb_init_fresh(sef_cb_init);
+ sef_setcb_init_lu(sef_cb_init);
+ sef_setcb_init_restart(sef_cb_init);
+
+ /*
+ * Register live update callbacks.
+ */
+ /* - Agree to update immediately when LU is requested in a valid state. */
+ sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
+ /* - Support live update starting from any standard state. */
+ sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
+ /* - Register a custom routine to save the state. */
+ sef_setcb_lu_state_save(sef_cb_lu_state_save);
+
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
+PRIVATE int sef_cb_init(int type, sef_init_info_t *info)
+{
+/* Initialize the hello driver. */
+ int do_mapdriver = TRUE;
+
+ open_counter = 0;
+ switch(type) {
+ case SEF_INIT_FRESH:
+ printf("%s", HELLO_MESSAGE);
+ break;
+
+ case SEF_INIT_LU:
+ /* Restore the state. */
+ lu_state_restore();
+ do_mapdriver = FALSE;
+
+ printf("%sHey, I'm a new version!\n", HELLO_MESSAGE);
+ break;
+
+ case SEF_INIT_RESTART:
+ printf("%sHey, I've just been restarted!\n", HELLO_MESSAGE);
+ break;
+ }
+
+ /* Map major number to our process. */
+ if (do_mapdriver && mapdriver("hello", HELLO_MAJOR, STYLE_DEV, TRUE) != OK)
+ {
+ printf("hello: mapdriver() failed: %s\n",
+ strerror(errno));
+ return EINVAL;
+ }
+
+ /* Initialization completed successfully. */
+ return OK;
+}
+
+PUBLIC int main(int argc, char **argv)
+{
+ /*
+ * Perform initialization.
+ */
+ sef_local_startup();
+
+ /*
+ * Run the main loop.
+ */
+ driver_task(&hello_tab, DRIVER_STD);
+ return OK;
+}
+
--- /dev/null
+#ifndef __HELLO_H
+#define __HELLO_H
+
+/** The Hello, World! message. */
+#define HELLO_MESSAGE "Hello, World!\n"
+
+#endif /* __HELLO_H */
_PROTOTYPE( static void do_getname, (message *mp) );
_PROTOTYPE( static void lance_dump, (void) );
-_PROTOTYPE( static void lance_stop, (void) );
_PROTOTYPE( static void getAddressing, (int devind, ether_card_t *ec) );
/* probe+init LANCE cards */
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN char **env_argv;
/*===========================================================================*
}
}
break;
- case PM_PROC_NR:
- {
- sigset_t set;
-
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- lance_stop();
-
- break;
- }
default:
panic("illegal notify source: %d", m.m_source);
}
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
else if (r != ESRCH)
printf("lance: ds_retrieve_label_num failed for 'inet': %d\n", r);
- return(OK);
+ return OK;
+}
+
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ message mess;
+ int i;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i= 0; i<EC_PORT_NR_MAX; i++)
+ {
+ if (ec_table[i].mode != EC_ENABLED)
+ continue;
+ mess.m_type= DL_STOP;
+ mess.DL_PORT= i;
+ do_stop(&mess);
+ }
+
+#if VERBOSE
+ printf("LANCE driver stopped.\n");
+#endif
+
+ exit(0);
}
/*===========================================================================*
}
}
-/*===========================================================================*
- * lance_stop *
- *===========================================================================*/
-static void lance_stop()
-{
- message mess;
- int i;
-
- for (i= 0; i<EC_PORT_NR_MAX; i++)
- {
- if (ec_table[i].mode != EC_ENABLED)
- continue;
- mess.m_type= DL_STOP;
- mess.DL_PORT= i;
- do_stop(&mess);
- }
-
-#if VERBOSE
- printf("LANCE driver stopped.\n");
-#endif
-
- exit( 0 );
-}
-
-
/*===========================================================================*
* do_init *
*===========================================================================*/
(*dp->dr_hw_int)(dp, &mess);
}
break;
- case PM_PROC_NR:
- if (getsigset(&set) != 0) break;
- (*dp->dr_signal)(dp, &set);
- break;
- case SYSTEM:
- set = mess.NOTIFY_ARG;
- (*dp->dr_signal)(dp, &set);
- break;
case CLOCK:
(*dp->dr_alarm)(dp, &mess);
break;
return(ENOTTY);
}
-/*============================================================================*
- * nop_signal *
- *============================================================================*/
-PUBLIC void nop_signal(dp, set)
-struct driver *dp;
-sigset_t *set;
-{
-/* Default action for signal is to ignore. */
-}
-
/*============================================================================*
* nop_alarm *
*============================================================================*/
iovec_t *iov, unsigned nr_req) );
_PROTOTYPE( void (*dr_cleanup), (void) );
_PROTOTYPE( void (*dr_geometry), (struct partition *entry) );
- _PROTOTYPE( void (*dr_signal), (struct driver *dp, sigset_t *set) );
_PROTOTYPE( void (*dr_alarm), (struct driver *dp, message *m_ptr) );
_PROTOTYPE( int (*dr_cancel), (struct driver *dp, message *m_ptr) );
_PROTOTYPE( int (*dr_select), (struct driver *dp, message *m_ptr) );
_PROTOTYPE( struct device *nop_prepare, (int device) );
_PROTOTYPE( void nop_cleanup, (void) );
_PROTOTYPE( void nop_task, (void) );
-_PROTOTYPE( void nop_signal, (struct driver *dp, sigset_t *set) );
_PROTOTYPE( void nop_alarm, (struct driver *dp, message *m_ptr) );
_PROTOTYPE( int nop_cancel, (struct driver *dp, message *m_ptr) );
_PROTOTYPE( int nop_select, (struct driver *dp, message *m_ptr) );
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) );
FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) );
FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) );
-FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, sigset_t *set) );
FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr) );
FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) );
FORWARD _PROTOTYPE( int subread, (struct logdevice *log, int count, int proc_nr, vir_bytes user_vir, size_t) );
log_transfer, /* do the I/O */
nop_cleanup, /* no need to clean up */
log_geometry, /* geometry */
- log_signal, /* handle system signal */
nop_alarm, /* no alarm */
log_cancel, /* CANCEL request */
log_select, /* DEV_SELECT request */
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
/*===========================================================================*
* main *
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* Only check for a pending message from the kernel, ignore anything else. */
+ if (signo != SIGKMESS) return;
+
+ do_new_kmess(SYSTEM);
+}
+
/*===========================================================================*
* log_name *
*===========================================================================*/
return(OK);
}
-
-/*============================================================================*
- * log_signal *
- *============================================================================*/
-PRIVATE void log_signal(dp, set)
-struct driver *dp;
-sigset_t *set;
-{
- if (sigismember(set, SIGKMESS)) {
- do_new_kmess(SYSTEM);
- }
-}
-
-
/*============================================================================*
* log_other *
*============================================================================*/
m_transfer, /* do the I/O */
nop_cleanup, /* no need to clean up */
m_geometry, /* memory device "geometry" */
- nop_signal, /* system signals */
nop_alarm,
nop_cancel,
nop_select,
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
{
/* Initialize the memory driver. */
- struct sigaction sa;
u32_t ramdev_size;
int i, s;
- sa.sa_handler = SIG_MESS;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGTERM,&sa,NULL)<0) panic("sigaction failed: %d", errno);
-
/* Initialize all minor devices one by one. */
if (OK != (s=sys_getkinfo(&kinfo))) {
panic("Couldn't get kernel information: %d", s);
exec 2>/dev/log
exec </dev/null
-/bin/service up /bin/pci -config /etc/system.conf
+/bin/service -c up /bin/pci -config /etc/system.conf
/bin/service -c up /bin/floppy -config /etc/system.conf -dev /dev/fd0
if [ X`/bin/sysenv bios_wini` = Xyes ]
then
_PROTOTYPE (static void print_linkstatus, (t_or * orp, u16_t status));
_PROTOTYPE (static int or_get_recvd_packet, (t_or *orp, u16_t rxfid,
u8_t *databuf));
-_PROTOTYPE (static void orinoco_stop, (void));
_PROTOTYPE (static void or_reset, (void));
_PROTOTYPE (static void or_watchdog_f, (timer_t *tp) );
_PROTOTYPE (static void setup_wepkey, (t_or *orp, char *wepkey0) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN char **env_argv;
/*****************************************************************************
case TTY_PROC_NR:
or_dump(&m);
break;
- case PM_PROC_NR:
- {
- sigset_t set;
-
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- orinoco_stop();
-
- break;
- }
default:
panic("orinoco: illegal notify from: %d",
m.m_source);
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int i;
+ t_or *orp;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i= 0, orp= &or_table[0]; i<OR_PORT_NR; i++, orp++) {
+ if (orp->or_mode != OR_M_ENABLED)
+ continue;
+ /* TODO: send a signal to the card to shut it down */
+ }
+ exit(0);
+}
+
/*****************************************************************************
* check_int_events *
* *
}
}
-
-
-/*****************************************************************************
- * orinoco_stop *
- * *
- * Stops the card. The signal to the card itself is not implemented yet. *
- *****************************************************************************/
-static void orinoco_stop () {
- int i;
- t_or *orp;
-
- for (i= 0, orp= &or_table[0]; i<OR_PORT_NR; i++, orp++) {
- if (orp->or_mode != OR_M_ENABLED)
- continue;
- /* TODO: send a signal to the card to shut it down */
- }
- exit(0);
-}
-
/*****************************************************************************
* or_reset *
* *
}
if (is_notify(m.m_type)) {
- switch (_ENDPOINT_P(m.m_source)) {
- case PM_PROC_NR:
- break;
- default:
- printf("PCI: got notify from %d\n",
- m.m_source);
- break;
- }
+ printf("PCI: got notify from %d\n", m.m_source);
/* done, get a new message */
continue;
printf("pci:pci_reserve2: bad devind: %d\n", devind);
return EINVAL;
}
- if(pcidev[devind].pd_inuse)
+ if(pcidev[devind].pd_inuse && pcidev[devind].pd_proc != proc)
return EBUSY;
pcidev[devind].pd_inuse= 1;
pcidev[devind].pd_proc= proc;
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
FORWARD _PROTOTYPE( void do_initialize, (void) );
FORWARD _PROTOTYPE( void reply, (int code,int replyee,int proc,int status));
FORWARD _PROTOTYPE( void do_printer_output, (void) );
-FORWARD _PROTOTYPE( void do_signal, (void) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
-FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
PUBLIC int is_status_msg_expected = FALSE;
case HARDWARE:
do_printer_output();
break;
- case PM_PROC_NR:
- do_signal();
- break;
default:
reply(TASK_REPLY, pr_mess.m_source,
pr_mess.IO_ENDPT, EINVAL);
*===========================================================================*/
PRIVATE void sef_local_startup()
{
- /* Register init callbacks. */
- sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_lu(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_fresh);
+ /* Nothing to on initialization. */
/* Register live update callbacks. */
sef_setcb_lu_prepare(sef_cb_lu_prepare);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler_term);
+
/* Let SEF perform startup. */
sef_startup();
}
-/*===========================================================================*
- * sef_cb_init_fresh *
- *===========================================================================*/
-PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
-{
-/* Initialize the printer driver. */
- struct sigaction sa;
-
- /* Install signal handlers. Ask PM to transform signal into message. */
- sa.sa_handler = SIG_MESS;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGTERM,&sa,NULL)<0) panic("sigaction failed: %d", errno);
-
- return(OK);
-}
-
-/*===========================================================================*
- * do_signal *
- *===========================================================================*/
-PRIVATE void do_signal()
-{
- sigset_t sigset;
-
- if (getsigset(&sigset) != 0) return;
-
- /* Expect a SIGTERM signal when this server must shutdown. */
- if (sigismember(&sigset, SIGTERM)) {
- exit(0);
- }
- /* Ignore all other signals. */
-}
-
/*===========================================================================*
* do_write *
*===========================================================================*/
r_transfer, /* do the I/O */
nop_cleanup, /* no need to clean up */
r_geometry, /* device "geometry" */
- nop_signal, /* system signals */
r_random, /* get randomness from kernel (alarm) */
nop_cancel,
nop_select,
#include <stdio.h>
#include <time.h>
#include <errno.h>
-#include <signal.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/syslib.h>
/* */
/***********************************************************************/
-int dead;
-void timeout(int sig) { dead= 1; }
-
void get_time(struct tm *t)
{
int osec, n;
unsigned long i;
- struct sigaction sa;
-
- /* Start a timer to keep us from getting stuck on a dead clock. */
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = timeout;
- sigaction(SIGALRM, &sa, NULL);
- dead = 0;
- alarm(5);
do {
osec = -1;
n = 0;
do {
- if (dead) {
- printf("readclock: CMOS clock appears dead\n");
- exit(1);
- }
-
/* Clock update in progress? */
if (read_register(RTC_REG_A) & RTC_A_UIP) continue;
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
_PROTOTYPE( static void rl_getname, (message *mp) );
_PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
-_PROTOTYPE( static void rtl8139_stop, (void) );
_PROTOTYPE( static void check_int_events, (void) );
_PROTOTYPE( static int do_hard_int, (void) );
_PROTOTYPE( static void rtl8139_dump, (message *m) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
EXTERN int env_argc;
case TTY_PROC_NR:
rtl8139_dump(&m);
break;
- case PM_PROC_NR:
- {
- sigset_t set;
-
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- rtl8139_stop();
-
- break;
- }
default:
panic("illegal notify from: %d",
m.m_source);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int i;
+ re_t *rep;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
+ {
+ if (rep->re_mode != REM_ENABLED)
+ continue;
+ rl_outb(rep->re_base_port, RL_CR, 0);
+ }
+ exit(0);
+}
+
/*===========================================================================*
* check_int_events *
*===========================================================================*/
}
}
-/*===========================================================================*
- * rtl8139_stop *
- *===========================================================================*/
-static void rtl8139_stop()
-{
- int i;
- re_t *rep;
-
- for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
- {
- if (rep->re_mode != REM_ENABLED)
- continue;
- rl_outb(rep->re_base_port, RL_CR, 0);
- }
- exit(0);
-}
-
/*===========================================================================*
* rtl8139_dump *
*===========================================================================*/
_PROTOTYPE( static void rl_getname, (message *mp) );
_PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
-_PROTOTYPE( static void rtl8169_stop, (void) );
_PROTOTYPE( static void check_int_events, (void) );
_PROTOTYPE( static void do_hard_int, (void) );
_PROTOTYPE( static void rtl8169_dump, (void) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
check_int_events();
}
break ;
- case PM_PROC_NR:
- {
- sigset_t set;
-
- if (getsigset(&set) != 0) break;
-
- if (sigismember(&set, SIGTERM))
- rtl8169_stop();
-
- break;
- }
default:
panic("illegal notify from: %d", m.m_type);
}
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int i;
+ re_t *rep;
+
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) {
+ if (rep->re_mode != REM_ENABLED)
+ continue;
+ rl_outb(rep->re_base_port, RL_CR, 0);
+ }
+
+ exit(0);
+}
+
static void mdio_write(U16_t port, int regaddr, int value)
{
int i;
}
}
-/*===========================================================================*
- * rtl8169_stop *
- *===========================================================================*/
-static void rtl8169_stop()
-{
- int i;
- re_t *rep;
-
- for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) {
- if (rep->re_mode != REM_ENABLED)
- continue;
- rl_outb(rep->re_base_port, RL_CR, 0);
- }
-
- exit(0);
-}
-
static void rtl8169_update_stat(re_t *rep)
{
port_t port;
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
-EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
+EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
PUBLIC int is_processing = FALSE;
case HARDWARE:
dsp_hardware_msg();
continue; /* don't reply */
- case SYSTEM:
- continue; /* don't reply */
default:
r = EINVAL;
}
/*===========================================================================*
* sef_cb_lu_prepare *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare(int state)
+PUBLIC int sef_cb_lu_prepare(int state)
{
int is_ready;
}
/* Tell SEF if we are ready. */
- if(is_ready) {
- sef_lu_ready(OK);
- }
+ return is_ready ? OK : ENOTREADY;
}
/*===========================================================================*
/*===========================================================================*
* do_new_kmess *
*===========================================================================*/
-PUBLIC void do_new_kmess(m)
-message *m;
+PUBLIC void do_new_kmess()
{
/* Notification for a new kernel message. */
static struct kmessages kmess; /* kmessages structure */
struct kmessages kmess;
-FORWARD _PROTOTYPE( void got_signal, (void) );
FORWARD _PROTOTYPE( void tty_timed_out, (timer_t *tp) );
FORWARD _PROTOTYPE( void expire_timers, (void) );
FORWARD _PROTOTYPE( void settimer, (tty_t *tty_ptr, int enable) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
/*===========================================================================*
* tty_task *
/* run watchdogs of expired timers */
expire_timers();
break;
- case PM_PROC_NR:
- /* signal */
- got_signal();
- break;
- case SYSTEM:
- /* system signal */
- if (sigismember((sigset_t*)&tty_mess.NOTIFY_ARG,
- SIGKMESS))
- do_new_kmess(&tty_mess);
- break;
default:
/* do nothing */
break;
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
}
/*===========================================================================*
- * got_signal *
+ * sef_cb_signal_handler *
*===========================================================================*/
-PRIVATE void got_signal()
+PRIVATE void sef_cb_signal_handler(int signo)
{
-/* PM notified us that we have received a signal. If it is a SIGTERM, assume
- * that the system is shutting down.
- */
- sigset_t set;
-
- if (getsigset(&set) != 0) return;
-
- if (!sigismember(&set, SIGTERM)) return;
-
- /* switch to primary console */
- cons_stop();
+ /* Check for known signals, ignore anything else. */
+ switch(signo) {
+ /* There is a pending message from the kernel. */
+ case SIGKMESS:
+ do_new_kmess();
+ break;
+ /* Switch to primary console on termination. */
+ case SIGTERM:
+ cons_stop();
+ break;
+ }
}
/*===========================================================================*
/* console.c */
_PROTOTYPE( void kputc, (int c) );
_PROTOTYPE( void cons_stop, (void) );
-_PROTOTYPE( void do_new_kmess, (message *m) );
+_PROTOTYPE( void do_new_kmess, (void) );
_PROTOTYPE( void do_diagnostics, (message *m, int safe) );
_PROTOTYPE( void do_get_kmess, (message *m) );
_PROTOTYPE( void do_get_kmess_s, (message *m) );
exec > /dev/console
echo "Arguments: $@"
+service down "$1"
kill_by_name dhcpd
kill_by_name nonamed
kill_by_name syslogd
-sleep 1
-service restart "$1"
-sleep 1
+sleep 3
+service up /usr/sbin/inet -script /etc/rs.inet
daemonize dhcpd
daemonize nonamed -L
daemonize syslogd
+
IRQCTL # 19
DEVIO # 21
VDEVIO # 23
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- PROFBUF # 38
- SYSCTL # 44
;
};
IRQCTL # 19
DEVIO # 21
SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 10ec/8029;
uid 0;
IRQCTL # 19
DEVIO # 21
SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
uid 0;
};
UMAP # 14
IRQCTL # 19
DEVIO # 21
- #SDEVIO # 22
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 1022/2000;
uid 0;
UMAP # 14
IRQCTL # 19
DEVIO # 21
- #SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 10ec/8139;
pci device 02ac/1012;
UMAP # 14
IRQCTL # 19
DEVIO # 21
- #SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 8086/103d;
pci device 8086/1064;
service inet
{
- system
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- VSAFECOPY # 33
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
- ;
uid 0;
};
service random
{
- system
- UMAP # 14
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
- ;
};
service readclock.drv
{
io 70:2;
system
+ UMAP # 14
DEVIO # 21
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
READBIOS # 35
- PROFBUF # 38
- SYSCTL # 44
;
uid 0;
};
service is
{
- system
- TIMES # 25
- GETINFO # 26
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
- ;
vm
INFO
;
system
PRIVCTL # 4
DEVIO # 21
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
uid 0;
};
DEVIO # 21
SDEVIO # 22
VDEVIO # 23
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
READBIOS # 35
- PROFBUF # 38
- SYSCTL # 44
;
pci class
1/1 # Mass storage / IDE
system
UMAP # 14
INT86 # 20
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
READBIOS # 35
- PROFBUF # 38
- SYSCTL # 44
;
};
service mfs
{
- system
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
- ;
uid 0;
};
service isofs
{
system
- UMAP # 14
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
+ UMAP # 14
;
uid 0;
};
service hgfs
{
- system
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
- ;
ipc
SYSTEM PM VFS RS VM
;
IRQCTL # 19
DEVIO # 21
VDEVIO # 23
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
};
UMAP # 14
IRQCTL # 19
DEVIO # 21
- #SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
VM_MAP # 30
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 1260/3873;
pci device 1186/1300;
UMAP # 14
IRQCTL # 19
DEVIO # 21
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 1274/5000;
};
service es1371
{
system
- SAFECOPYFROM
- SAFECOPYTO
- UMAP
- SETGRANT
- TIMES # 25
- GETINFO
+ UMAP # 14
IRQCTL # 19
DEVIO # 21
- PROFBUF # 38
- SYSCTL
;
pci device 1274/1371;
};
pci device 1022/1103;
system
UMAP # 14
- TIMES # 25
- GETINFO # 26
- SETGRANT # 34
- PROFBUF # 38
- REGDEV # 40
- SYSCTL # 44
;
uid 0;
};
{
system
UMAP # 14
- VIRCOPY # 15
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
+ VIRCOPY # 15
;
uid 0;
ipc
IRQCTL # 19
DEVIO # 21
SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci class
4/1 # Multimedia / Audio device
UMAP # 14
IRQCTL # 19
DEVIO # 21
- #SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL # 44
;
pci device 10ec/8129;
pci device 10ec/8167;
service filter
{
- system
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- SYSCTL # 44
- ;
ipc
SYSTEM PM VFS RS DS VM
at_wini
UMAP # 14
IRQCTL # 19
DEVIO # 21
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- SYSCTL # 44
;
pci device 8086/100e;
pci device 8086/107c;
system
UMAP # 14
IRQCTL # 19
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- SYSCTL # 44
;
pci device 1969/2048;
ipc
UMAP # 14
IRQCTL # 19
DEVIO # 21
- #SDEVIO # 22
- SETALARM # 24
- TIMES # 25
- GETINFO # 26
- SAFECOPYFROM # 31
- SAFECOPYTO # 32
- SETGRANT # 34
- PROFBUF # 38
- SYSCTL
;
pci device 1011/0009;
ipc
pci inet
;
};
+
+service hello
+{
+ system
+ IRQCTL # 19
+ DEVIO # 21
+ ;
+ ipc
+ SYSTEM PM RS LOG TTY DS VM VFS
+ pci inet amddev
+ ;
+ uid 0;
+};
+
#define ENOSYS (_SIGN 38) /* function not implemented */
#define ENOTEMPTY (_SIGN 39) /* directory not empty */
#define ELOOP (_SIGN 40) /* too many levels of symlinks detected */
-#define ERESTART (_SIGN 41) /* driver restarted */
+#define ERESTART (_SIGN 41) /* service restarted */
#define EIDRM (_SIGN 43) /* Identifier removed */
#define EILSEQ (_SIGN 44) /* illegal byte sequence */
-#define NCALLS 111 /* number of system calls allowed */
+#define NCALLS 112 /* number of system calls allowed */
#define EXIT 1
#define FORK 2
#define EXEC_NEWMEM 100 /* from FS or RS to PM: new memory map for
* exec
*/
-#define FORK_NB 101 /* to PM: special fork call for RS */
+#define SRV_FORK 101 /* to PM: special fork call for RS */
#define EXEC_RESTART 102 /* to PM: final part of exec for RS */
#define PROCSTAT 103 /* to PM */
#define GETPROCNR 104 /* to PM */
* that should not be used for bus-master DMA
* any longer
*/
+#define SRV_KILL 111 /* to PM: special kill call for RS */
#define TASK_REPLY 121 /* to FS: reply code from drivers, not
* really a standalone call.
* 0xB00 - 0xBFF Requests from VM to VFS
* 0xC00 - 0xCFF Virtual Memory (VM) requests
* 0xD00 - 0xDFF IPC server requests
+ * 0xE00 - 0xEFF Common system messages (e.g. system signals)
* 0x1000 - 0x10FF Notify messages
*
* Zero and negative values are widely used for OK and error responses.
# define SYS_FORK (KERNEL_CALL + 0) /* sys_fork() */
# define SYS_EXEC (KERNEL_CALL + 1) /* sys_exec() */
-# define SYS_EXIT (KERNEL_CALL + 2) /* sys_exit() */
+# define SYS_CLEAR (KERNEL_CALL + 2) /* sys_clear() */
# define SYS_NICE (KERNEL_CALL + 3) /* sys_nice() */
# define SYS_PRIVCTL (KERNEL_CALL + 4) /* sys_privctl() */
# define SYS_TRACE (KERNEL_CALL + 5) /* sys_trace() */
# define SYS_GETMCONTEXT (KERNEL_CALL + 50) /* sys_getmcontext() */
# define SYS_SETMCONTEXT (KERNEL_CALL + 51) /* sys_setmcontext() */
-#define NR_SYS_CALLS 52 /* number of system calls */
+# define SYS_UPDATE (KERNEL_CALL + 52) /* sys_update() */
+# define SYS_EXIT (KERNEL_CALL + 53) /* sys_exit() */
+
+/* Total */
+#define NR_SYS_CALLS 54 /* number of system calls */
+
#define SYS_CALL_MASK_SIZE BITMAP_CHUNKS(NR_SYS_CALLS)
+/* Basic kernel calls allowed to every system process. */
+#define SYS_BASIC_CALLS \
+ SYS_EXIT, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, SYS_VSAFECOPY, SYS_GETINFO, \
+ SYS_TIMES, SYS_SETALARM, SYS_SETGRANT, SYS_SAFEMAP, SYS_SAFEREVMAP, \
+ SYS_SAFEUNMAP, SYS_PROFBUF, SYS_SYSCTL
+
/* Field names for SYS_MEMSET. */
#define MEM_PTR m2_p1 /* base */
#define MEM_COUNT m2_l1 /* count */
#define RC_FLAGS m1_i3 /* request flags */
# define RC_DELAY 1 /* delay stop if process is sending */
+/* Field names for SYS_UPDATE. */
+#define SYS_UPD_SRC_ENDPT m1_i1 /* source endpoint */
+#define SYS_UPD_DST_ENDPT m1_i2 /* destination endpoint */
+
/*===========================================================================*
* Messages for the Reincarnation Server *
*===========================================================================*/
# define DS_VAL m2_l1 /* data (u32, char *, etc.) */
# define DS_VAL_LEN m2_l2 /* data length */
# define DS_NR_SNAPSHOT m2_i3 /* number of snapshot */
-# define DS_STRING m2_i3 /* inline string */
/*===========================================================================*
* Miscellaneous messages used by TTY *
#define PM_DUMPCORE (PM_RQ_BASE + 5) /* Process is to dump core */
#define PM_EXEC (PM_RQ_BASE + 6) /* Forwarded exec call */
#define PM_FORK (PM_RQ_BASE + 7) /* Newly forked process */
-#define PM_FORK_NB (PM_RQ_BASE + 8) /* Non-blocking fork */
+#define PM_SRV_FORK (PM_RQ_BASE + 8) /* fork for system services */
#define PM_UNPAUSE (PM_RQ_BASE + 9) /* Interrupt process call */
#define PM_REBOOT (PM_RQ_BASE + 10) /* System reboot */
#define PM_SETGROUPS (PM_RQ_BASE + 11) /* Tell VFS about setgroups */
#define PM_CORE_REPLY (PM_RS_BASE + 5)
#define PM_EXEC_REPLY (PM_RS_BASE + 6)
#define PM_FORK_REPLY (PM_RS_BASE + 7)
-#define PM_FORK_NB_REPLY (PM_RS_BASE + 8)
+#define PM_SRV_FORK_REPLY (PM_RS_BASE + 8)
#define PM_UNPAUSE_REPLY (PM_RS_BASE + 9)
#define PM_REBOOT_REPLY (PM_RS_BASE + 10)
#define PM_SETGROUPS_REPLY (PM_RS_BASE + 11)
/* Additional parameters for PM_INIT */
# define PM_SLOT m1_i2 /* process slot number */
-# define PM_PID m2_i3 /* process pid */
+# define PM_PID m1_i3 /* process pid */
/* Additional parameters for PM_SETUID and PM_SETGID */
# define PM_EID m1_i2 /* effective user/group id */
/* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */
# define PM_STATUS m1_i2 /* OK or failure */
-/* Additional parameters for PM_FORK and PM_FORK_NB */
+/* Additional parameters for PM_FORK and PM_SRV_FORK */
# define PM_PPROC m1_i2 /* parent process endpoint */
# define PM_CPID m1_i3 /* child pid */
* Miscellaneous field names *
*===========================================================================*/
+#define COMMON_RQ_BASE 0xE00
+
/* PM field names */
/* BRK */
#define PMBRK_ADDR m1_p1
#define SEL_ERRORFDS m8_p3
#define SEL_TIMEOUT m8_p4
+/* Field names for system signals (sent by a signal manager). */
+#define SIGS_SIGNAL_RECEIVED (COMMON_RQ_BASE+0)
+# define SIGS_SIG_NUM m2_i1
+
/*===========================================================================*
* Messages for VM server *
*===========================================================================*/
#define VMIW_USAGE 2
#define VMIW_REGION 3
+#define VM_RS_UPDATE (VM_RQ_BASE+41)
+# define VM_RS_SRC_ENDPT m1_i1
+# define VM_RS_DST_ENDPT m1_i2
+
/* Total. */
-#define NR_VM_CALLS 41
+#define NR_VM_CALLS 42
#define VM_CALL_MASK_SIZE BITMAP_CHUNKS(NR_VM_CALLS)
/* Basic vm calls allowed to every process. */
#define LOG_MAJOR 15 /* major device for log driver */
# define IS_KLOG_DEV 0 /* minor device for /dev/klog */
+#define HELLO_MAJOR 17 /* major device for hello driver */
+
#endif /* _DMAP_H */
/* DS constants. */
#define DS_MAX_KEYLEN 80 /* Max length of a key, including '\0'. */
-#define DS_MAX_STRLEN 16 /* Max length of string, including '\0'. */
/* ds.c */
#define RSS_REUSE 0x04 /* Try to reuse previously copied binary */
/* Common definitions. */
-#define RS_SYS_CALL_MASK_SIZE 2
#define RS_NR_CONTROL 8
#define RS_NR_PCI_DEVICE 32
#define RS_NR_PCI_CLASS 4
struct { u16_t vid; u16_t did; } rss_pci_id[RS_NR_PCI_DEVICE];
int rss_nr_pci_class;
struct { u32_t class; u32_t mask; } rss_pci_class[RS_NR_PCI_CLASS];
- u32_t rss_system[RS_SYS_CALL_MASK_SIZE];
+ bitchunk_t rss_system[SYS_CALL_MASK_SIZE];
struct rss_label rss_label;
char *rss_ipc;
size_t rss_ipclen;
#include <minix/sys_config.h>
#include <minix/types.h>
+#include <minix/vm.h>
#include <stdint.h>
typedef struct {
size_t v_bytes; /* no. of bytes */
};
-/* Types on VM invocation. */
-#define VMPTYPE_NONE 0
-#define VMPTYPE_CHECK 1
-#define VMPTYPE_COWMAP 2
-#define VMPTYPE_SMAP 3
-#define VMPTYPE_SUNMAP 4
-
/* Invalid grant number. */
#define GRANT_INVALID ((cp_grant_id_t) -1)
#define GRANT_VALID(g) ((g) > GRANT_INVALID)
/* SEF entry points for system processes. */
_PROTOTYPE( void sef_startup, (void) );
_PROTOTYPE( int sef_receive, (endpoint_t src, message *m_ptr) );
+_PROTOTYPE( void sef_exit, (int status) );
/* SEF Debug. */
#include <stdio.h>
} sef_init_info_t;
/* Callback type definitions. */
-typedef int(*sef_cb_init_fresh_t)(int type, sef_init_info_t *info);
-typedef int(*sef_cb_init_lu_t)(int type, sef_init_info_t *info);
-typedef int(*sef_cb_init_restart_t)(int type, sef_init_info_t *info);
+typedef int(*sef_cb_init_t)(int type, sef_init_info_t *info);
/* Callback registration helpers. */
-_PROTOTYPE( void sef_setcb_init_fresh, (sef_cb_init_fresh_t cb));
-_PROTOTYPE( void sef_setcb_init_lu, (sef_cb_init_lu_t cb));
-_PROTOTYPE( void sef_setcb_init_restart, (sef_cb_init_restart_t cb));
+_PROTOTYPE( void sef_setcb_init_fresh, (sef_cb_init_t cb));
+_PROTOTYPE( void sef_setcb_init_lu, (sef_cb_init_t cb));
+_PROTOTYPE( void sef_setcb_init_restart, (sef_cb_init_t cb));
/* Predefined callback implementations. */
-_PROTOTYPE( int sef_cb_init_fresh_null, (int type, sef_init_info_t *info) );
-_PROTOTYPE( int sef_cb_init_lu_null, (int type, sef_init_info_t *info) );
-_PROTOTYPE( int sef_cb_init_restart_null, (int type, sef_init_info_t *info) );
+_PROTOTYPE( int sef_cb_init_null, (int type, sef_init_info_t *info) );
-_PROTOTYPE( int sef_cb_init_restart_fail, (int type, sef_init_info_t *info) );
+_PROTOTYPE( int sef_cb_init_fail, (int type, sef_init_info_t *info) );
+_PROTOTYPE( int sef_cb_init_crash, (int type, sef_init_info_t *info) );
/* Macros for predefined callback implementations. */
-#define SEF_CB_INIT_FRESH_NULL sef_cb_init_fresh_null
-#define SEF_CB_INIT_LU_NULL sef_cb_init_lu_null
-#define SEF_CB_INIT_RESTART_NULL sef_cb_init_restart_null
+#define SEF_CB_INIT_FRESH_NULL sef_cb_init_null
+#define SEF_CB_INIT_LU_NULL sef_cb_init_null
+#define SEF_CB_INIT_RESTART_NULL sef_cb_init_null
-#define SEF_CB_INIT_FRESH_DEFAULT sef_cb_init_fresh_null
-#define SEF_CB_INIT_LU_DEFAULT sef_cb_init_lu_null
-#define SEF_CB_INIT_RESTART_DEFAULT sef_cb_init_restart_null
+#define SEF_CB_INIT_FRESH_DEFAULT sef_cb_init_null
+#define SEF_CB_INIT_LU_DEFAULT sef_cb_init_null
+#define SEF_CB_INIT_RESTART_DEFAULT sef_cb_init_null
/* Init types. */
#define SEF_INIT_FRESH 0 /* init fresh */
&& (mp)->m_source == RS_PROC_NR)
/* Callback type definitions. */
-typedef void(*sef_cb_ping_reply_t)(message *m_ptr);
+typedef void(*sef_cb_ping_reply_t)(endpoint_t source);
/* Callback registration helpers. */
_PROTOTYPE( void sef_setcb_ping_reply, (sef_cb_ping_reply_t cb));
/* Predefined callback implementations. */
-_PROTOTYPE( void sef_cb_ping_reply_null, (message *m_ptr) );
+_PROTOTYPE( void sef_cb_ping_reply_null, (endpoint_t source) );
-_PROTOTYPE( void sef_cb_ping_reply_pong, (message *m_ptr) );
+_PROTOTYPE( void sef_cb_ping_reply_pong, (endpoint_t source) );
/* Macros for predefined callback implementations. */
#define SEF_CB_PING_REPLY_NULL sef_cb_ping_reply_null
#define IS_SEF_LU_REQUEST(mp) ((mp)->m_type == RS_LU_PREPARE \
&& (mp)->m_source == RS_PROC_NR)
-/* Global helpers. */
-_PROTOTYPE( void sef_lu_ready, (int result) );
-
/* Callback type definitions. */
-typedef void(*sef_cb_lu_prepare_t)(int);
+typedef int(*sef_cb_lu_prepare_t)(int);
typedef int(*sef_cb_lu_state_isvalid_t)(int);
typedef void(*sef_cb_lu_state_changed_t)(int, int);
typedef void(*sef_cb_lu_state_dump_t)(int);
-typedef int(*sef_cb_lu_ready_pre_t)(int);
+typedef int(*sef_cb_lu_state_save_t)(int);
/* Callback registration helpers. */
_PROTOTYPE( void sef_setcb_lu_prepare, (sef_cb_lu_prepare_t cb) );
_PROTOTYPE( void sef_setcb_lu_state_isvalid, (sef_cb_lu_state_isvalid_t cb) );
_PROTOTYPE( void sef_setcb_lu_state_changed, (sef_cb_lu_state_changed_t cb) );
_PROTOTYPE( void sef_setcb_lu_state_dump, (sef_cb_lu_state_dump_t cb) );
-_PROTOTYPE( void sef_setcb_lu_ready_pre, (sef_cb_lu_ready_pre_t cb) );
+_PROTOTYPE( void sef_setcb_lu_state_save, (sef_cb_lu_state_save_t cb) );
/* Predefined callback implementations. */
-_PROTOTYPE( void sef_cb_lu_prepare_null, (int state) );
+_PROTOTYPE( int sef_cb_lu_prepare_null, (int state) );
_PROTOTYPE( int sef_cb_lu_state_isvalid_null, (int state) );
_PROTOTYPE( void sef_cb_lu_state_changed_null, (int old_state, int state) );
_PROTOTYPE( void sef_cb_lu_state_dump_null, (int state) );
-_PROTOTYPE( int sef_cb_lu_ready_pre_null, (int result) );
+_PROTOTYPE( int sef_cb_lu_state_save_null, (int state) );
-_PROTOTYPE( void sef_cb_lu_prepare_always_ready, (int state) );
+_PROTOTYPE( int sef_cb_lu_prepare_always_ready, (int state) );
+_PROTOTYPE( int sef_cb_lu_prepare_never_ready, (int state) );
+_PROTOTYPE( int sef_cb_lu_prepare_crash, (int state) );
_PROTOTYPE( int sef_cb_lu_state_isvalid_standard, (int state) );
/* Macros for predefined callback implementations. */
#define SEF_CB_LU_STATE_ISVALID_NULL sef_cb_lu_state_isvalid_null
#define SEF_CB_LU_STATE_CHANGED_NULL sef_cb_lu_state_changed_null
#define SEF_CB_LU_STATE_DUMP_NULL sef_cb_lu_state_dump_null
-#define SEF_CB_LU_READY_PRE_NULL sef_cb_lu_ready_pre_null
+#define SEF_CB_LU_STATE_SAVE_NULL sef_cb_lu_state_save_null
#define SEF_CB_LU_PREPARE_DEFAULT sef_cb_lu_prepare_null
#define SEF_CB_LU_STATE_ISVALID_DEFAULT sef_cb_lu_state_isvalid_null
#define SEF_CB_LU_STATE_CHANGED_DEFAULT sef_cb_lu_state_changed_null
#define SEF_CB_LU_STATE_DUMP_DEFAULT sef_cb_lu_state_dump_null
-#define SEF_CB_LU_READY_PRE_DEFAULT sef_cb_lu_ready_pre_null
+#define SEF_CB_LU_STATE_SAVE_DEFAULT sef_cb_lu_state_save_null
/* Standard live update states. */
#define SEF_LU_STATE_NULL 0 /* null state */
#define sef_lu_debug_begin sef_debug_begin
#define sef_lu_debug_end sef_debug_end
+/*===========================================================================*
+ * SEF Signal *
+ *===========================================================================*/
+/* What to intercept. */
+#define INTERCEPT_SEF_SIGNAL_REQUESTS 1
+#define IS_SEF_SIGNAL_REQUEST(mp) \
+ (((mp)->m_type == SIGS_SIGNAL_RECEIVED && (mp)->m_source < INIT_PROC_NR) \
+ || (is_notify((mp)->m_type) && (mp)->m_source == SYSTEM))
+
+/* Callback type definitions. */
+typedef void(*sef_cb_signal_handler_t)(int signo);
+typedef int(*sef_cb_signal_manager_t)(endpoint_t target, int signo);
+
+/* Callback registration helpers. */
+_PROTOTYPE( void sef_setcb_signal_handler, (sef_cb_signal_handler_t cb));
+_PROTOTYPE( void sef_setcb_signal_manager, (sef_cb_signal_manager_t cb));
+
+/* Predefined callback implementations. */
+_PROTOTYPE( void sef_cb_signal_handler_null, (int signo) );
+_PROTOTYPE( int sef_cb_signal_manager_null, (endpoint_t target, int signo) );
+
+_PROTOTYPE( void sef_cb_signal_handler_term, (int signo) );
+_PROTOTYPE( void sef_cb_signal_handler_posix_default, (int signo) );
+
+/* Macros for predefined callback implementations. */
+#define SEF_CB_SIGNAL_HANDLER_NULL sef_cb_signal_handler_null
+#define SEF_CB_SIGNAL_MANAGER_NULL sef_cb_signal_manager_null
+
+#define SEF_CB_SIGNAL_HANDLER_DEFAULT sef_cb_signal_handler_null
+#define SEF_CB_SIGNAL_MANAGER_DEFAULT sef_cb_signal_manager_null
+
+/* Debug. */
+#define SEF_SIGNAL_DEBUG_DEFAULT 0
+
+#ifndef SEF_SIGNAL_DEBUG
+#define SEF_SIGNAL_DEBUG SEF_SIGNAL_DEBUG_DEFAULT
+#endif
+
+#define sef_signal_dprint sef_dprint
+#define sef_signal_debug_begin sef_debug_begin
+#define sef_signal_debug_end sef_debug_end
+
#endif /* _SEF_H */
_PROTOTYPE( int sys_fork, (endpoint_t parent, endpoint_t child, endpoint_t *,
struct mem_map *ptr, u32_t vm, vir_bytes *));
_PROTOTYPE( int sys_newmap, (endpoint_t proc_ep, struct mem_map *ptr));
-_PROTOTYPE( int sys_exit, (endpoint_t proc_ep));
+_PROTOTYPE( int sys_clear, (endpoint_t proc_ep));
+_PROTOTYPE( int sys_exit, (void));
_PROTOTYPE( int sys_trace, (int req, endpoint_t proc_ep, long addr, long *data_p));
/* Shorthands for sys_runctl() system call. */
#define sys_resume(proc_ep) sys_runctl(proc_ep, RC_RESUME, 0)
_PROTOTYPE( int sys_runctl, (endpoint_t proc_ep, int action, int flags));
+_PROTOTYPE( int sys_update, (endpoint_t src_ep, endpoint_t dst_ep));
_PROTOTYPE( int sys_privctl, (endpoint_t proc_ep, int req, void *p));
_PROTOTYPE( int sys_privquery_mem, (endpoint_t proc_ep,
phys_bytes physstart, phys_bytes physlen));
_PROTOTYPE( int vm_notify_sig, (endpoint_t ep, endpoint_t ipc_ep));
_PROTOTYPE( int vm_ctl, (int what, int param));
_PROTOTYPE( int vm_set_priv, (int procnr, void *buf));
+_PROTOTYPE( int vm_update, (endpoint_t src_e, endpoint_t dst_e));
_PROTOTYPE( int vm_query_exit, (int *endpt));
+/* VM kernel request types. */
+#define VMPTYPE_NONE 0
+#define VMPTYPE_CHECK 1
+#define VMPTYPE_COWMAP 2
+#define VMPTYPE_SMAP 3
+#define VMPTYPE_SUNMAP 4
+
struct vm_stats_info {
int vsi_pagesize; /* page size */
int vsi_total; /* total number of memory pages */
/* MINIX specific signals. These signals are not used by user proceses,
* but meant to inform system processes, like the PM, about system events.
+ * The order here determines the order signals are processed by system
+ * processes in user-space. Higher-priority signals should be first.
*/
-#define SIGKMESS 29 /* new kernel message */
+#define SIGKPF 26 /* kernel page fault request pending */
+#define SIGKMEM 27 /* kernel memory request pending */
+#define SIGKMESS 28 /* new kernel message */
+#define SIGKSIGSM 29 /* kernel signal pending for signal manager */
#define SIGKSIG 30 /* kernel signal pending */
-#define SIGNDELAY 31 /* end of delay for signal delivery */
+#define SIGKNDELAY 31 /* end of delay for signal delivery */
+
+#define SIGK_FIRST SIGKPF /* first kernel signal */
+#define SIGK_LAST SIGKNDELAY /* last kernel signal */
+#define IS_SIGK(signo) (signo>=SIGK_FIRST && signo<=SIGK_LAST)
+
+/* Termination signals for Minix system processes. */
+#define SIGS_IS_LETHAL(sig) \
+ (sig == SIGILL || sig == SIGBUS || sig == SIGFPE || sig == SIGSEGV \
+ || sig == SIGEMT || sig == SIGABRT)
+#define SIGS_IS_TERMINATION(sig) (SIGS_IS_LETHAL(sig) \
+ || (sig == SIGKILL || sig == SIGPIPE))
#endif
#define SIG_IGN ((__sighandler_t) 1) /* ignore signal */
#define SIG_HOLD ((__sighandler_t) 2) /* block signal */
#define SIG_CATCH ((__sighandler_t) 3) /* catch signal */
-#define SIG_MESS ((__sighandler_t) 4) /* pass as message (MINIX) */
#ifdef _POSIX_SOURCE
struct sigaction {
pr->p_nextpagefault = pagefaults;
pagefaults = pr;
- mini_notify(proc_addr(HARDWARE), VM_PROC_NR);
+ send_sig(VM_PROC_NR, SIGKPF);
return;
}
#include <minix/cpufeature.h>
#include <string.h>
#include <assert.h>
+#include <signal.h>
#include <machine/vm.h>
/* Connect caller on vmrequest wait queue. */
if(!(caller->p_vmrequest.nextrequestor = vmrequest))
- mini_notify(proc_addr(SYSTEM), VM_PROC_NR);
+ send_sig(VM_PROC_NR, SIGKMEM);
vmrequest = caller;
}
#define USE_FORK 1 /* fork a new process */
#define USE_NEWMAP 1 /* set a new memory map */
#define USE_EXEC 1 /* update process after execute */
-#define USE_EXIT 1 /* clean up after process exit */
+#define USE_CLEAR 1 /* clean up after process exit */
+#define USE_EXIT 1 /* a system process wants to exit */
#define USE_TRACE 1 /* process information and tracing */
#define USE_GETKSIG 1 /* retrieve pending kernel signals */
#define USE_ENDKSIG 1 /* finish pending kernel signals */
#define USE_PHYSCOPY 1 /* copy using physical addressing */
#define USE_MEMSET 1 /* write char to a given memory area */
#define USE_RUNCTL 1 /* control stop flags of a process */
+#define USE_UPDATE 1 /* update a process into another */
#define USE_MCONTEXT 1 /* enable getting and setting of mach context*/
/* Length of program names stored in the process table. This is only used
hook->id = id;
*line = hook;
irq_use |= 1 << irq; /* this does not work for irq >= 32 */
-
+
/* And as last enable the irq at the hardware.
*
* Internal this activates the line or source of the given interrupt.
if( irq < 0 || irq >= NR_IRQ_VECTORS )
panic("invalid call to rm_irq_handler: %d", irq);
- /* disable the irq. */
- irq_actids[hook->irq] |= hook->id;
- hw_intr_mask(hook->irq);
-
- /* remove the hook. */
+ /* remove the hook */
line = &irq_handlers[irq];
-
while( (*line) != NULL ) {
- if((*line)->id == id) {
- (*line) = (*line)->next;
+ if((*line)->id == id) {
+ (*line) = (*line)->next;
if(!irq_handlers[irq])
irq_use &= ~(1 << irq);
if (irq_actids[irq] & id)
irq_actids[irq] &= ~id;
- return;
- }
- line = &(*line)->next;
+ }
+ else {
+ line = &(*line)->next;
+ }
+ }
+
+ /* Disable the irq if there are no other handlers registered.
+ * If the irq is shared, reenable it if there is no active handler.
+ */
+ if (irq_handlers[irq] == NULL) {
+ hw_intr_mask(irq);
+ }
+ else if (irq_actids[irq] == 0) {
+ hw_intr_unmask(irq);
}
- /* When the handler is not found, normally return here. */
}
/*===========================================================================*
hw_intr_mask(irq);
hook = irq_handlers[irq];
+ /* Sanity check. */
+ if(hook == NULL) {
+ printf("%s: irq_handle:no handler registered, masking the IRQ...\n",
+ __FILE__);
+ return;
+ }
+
/* Call list of handlers for an IRQ. */
while( hook != NULL ) {
/* For each handler in the list, mark it active by setting its ID bit,
priv(rp)->s_trap_mask= RSYS_T; /* allowed traps */
ipc_to_m = RSYS_M; /* allowed targets */
kcalls = RSYS_KC; /* allowed kernel calls */
+ priv(rp)->s_sig_mgr = RSYS_SM; /* signal manager */
}
/* Priviliges for ordinary process. */
else {
sys_map_t s_ipc_to; /* allowed destination processes */
/* allowed kernel calls */
- bitchunk_t s_k_call_mask[SYS_CALL_MASK_SIZE];
+ bitchunk_t s_k_call_mask[SYS_CALL_MASK_SIZE];
+ endpoint_t s_sig_mgr; /* signal manager for system signals */
sys_map_t s_notify_pending; /* bit map with pending notifications */
irq_id_t s_int_pending; /* pending hardware interrupts */
sigset_t s_sig_pending; /* pending signals */
#define RSYS_KC ALL_C /* root system proc */
#define DEF_SYS_KC RSYS_KC /* default sys proc */
+/* signal manager */
+#define RSYS_SM ROOT_SYS_PROC_NR /* root system proc */
+#define DEF_SYS_SM ROOT_SYS_PROC_NR /* default sys proc */
+
#endif /* PRIV_H */
struct proc *p_nextready; /* pointer to next ready process */
struct proc *p_caller_q; /* head of list of procs wishing to send */
struct proc *p_q_link; /* link to next proc wishing to send */
- int p_getfrom_e; /* from whom does process want to receive? */
- int p_sendto_e; /* to whom does process want to send? */
+ endpoint_t p_getfrom_e; /* from whom does process want to receive? */
+ endpoint_t p_sendto_e; /* to whom does process want to send? */
sigset_t p_pending; /* bit map for pending kernel signals */
* set_sendto_bit: allow a process to send messages to a new target
* unset_sendto_bit: disallow a process from sending messages to a target
* send_sig: send a signal directly to a system process
- * cause_sig: take action to cause a signal to occur via PM
+ * cause_sig: take action to cause a signal to occur via a signal mgr
* sig_delay_done: tell PM that a process is not sending
* umap_bios: map virtual address in BIOS_SEG to physical
* get_randomness: accumulate randomness in a buffer
/* Process management. */
map(SYS_FORK, do_fork); /* a process forked a new process */
map(SYS_EXEC, do_exec); /* update process after execute */
- map(SYS_EXIT, do_exit); /* clean up after process exit */
+ map(SYS_CLEAR, do_clear); /* clean up after process exit */
+ map(SYS_EXIT, do_exit); /* a system process wants to exit */
map(SYS_NICE, do_nice); /* set scheduling priority */
map(SYS_PRIVCTL, do_privctl); /* system privileges control */
map(SYS_TRACE, do_trace); /* request a trace operation */
map(SYS_SETGRANT, do_setgrant); /* get/set own parameters */
map(SYS_RUNCTL, do_runctl); /* set/clear stop flag of a process */
+ map(SYS_UPDATE, do_update); /* update a process into another */
/* Signal handling. */
map(SYS_KILL, do_kill); /* cause a process to be signaled */
- map(SYS_GETKSIG, do_getksig); /* PM checks for pending signals */
- map(SYS_ENDKSIG, do_endksig); /* PM finished processing signal */
+ map(SYS_GETKSIG, do_getksig); /* signal manager checks for signals */
+ map(SYS_ENDKSIG, do_endksig); /* signal manager finished signal */
map(SYS_SIGSEND, do_sigsend); /* start POSIX-style signal */
map(SYS_SIGRETURN, do_sigreturn); /* return from POSIX-style signal */
* - HARDWARE wanting to cause a SIGSEGV after a CPU exception
* - TTY wanting to cause SIGINT upon getting a DEL
* - FS wanting to cause SIGPIPE for a broken pipe
- * Signals are handled by sending a message to PM. This function handles the
- * signals and makes sure the PM gets them by sending a notification. The
- * process being signaled is blocked while PM has not finished all signals
- * for it.
+ * Signals are handled by sending a message to the signal manager assigned to
+ * the process. This function handles the signals and makes sure the signal
+ * manager gets them by sending a notification. The process being signaled
+ * is blocked while the signal manager has not finished all signals for it.
* Race conditions between calls to this function and the system calls that
* process pending kernel signals cannot exist. Signal related functions are
* only called when a user process causes a CPU exception and from the kernel
* process level, which runs to completion.
*/
register struct proc *rp;
+ endpoint_t sig_mgr;
- if (proc_nr == PM_PROC_NR)
- panic("cause_sig: PM gets signal");
+ /* Lookup signal manager. */
+ rp = proc_addr(proc_nr);
+ sig_mgr = priv(rp)->s_sig_mgr;
+
+ /* If the target is the signal manager of itself, send the signal directly. */
+ if(rp->p_endpoint == sig_mgr) {
+ if(SIGS_IS_LETHAL(sig_nr)) {
+ panic("cause_sig: signal manager gets lethal signal for itself");
+ }
+ sigaddset(&priv(rp)->s_sig_pending, sig_nr);
+ send_sig(rp->p_endpoint, SIGKSIGSM);
+ return;
+ }
/* Check if the signal is already pending. Process it otherwise. */
- rp = proc_addr(proc_nr);
if (! sigismember(&rp->p_pending, sig_nr)) {
sigaddset(&rp->p_pending, sig_nr);
if (! (RTS_ISSET(rp, RTS_SIGNALED))) { /* other pending */
RTS_SET(rp, RTS_SIGNALED | RTS_SIG_PENDING);
- send_sig(PM_PROC_NR, SIGKSIG);
+ send_sig(sig_mgr, SIGKSIG);
}
}
}
rp->p_misc_flags &= ~MF_SIG_DELAY;
- cause_sig(proc_nr(rp), SIGNDELAY);
+ cause_sig(proc_nr(rp), SIGKNDELAY);
}
#if _MINIX_CHIP == _CHIP_INTEL
* into a message with type SYS_CALL that is handled in a function do_call().
*
* Changes:
+ * Mar 01, 2010 SYS_CLEAR and SYS_EXIT split (Cristiano Giuffrida)
* Jul 30, 2005 created SYS_INT86 to support BIOS driver (Philip Homburg)
* Jul 13, 2005 created SYS_PRIVCTL to manage services (Jorrit N. Herder)
* Jul 09, 2005 updated SYS_KILL to signal services (Jorrit N. Herder)
#define do_newmap do_unused
#endif
-_PROTOTYPE( int do_exit, (struct proc * caller, message *m_ptr) );
-#if ! USE_EXIT
-#define do_exit do_unused
+_PROTOTYPE( int do_clear, (struct proc * caller, message *m_ptr) );
+#if ! USE_CLEAR
+#define do_clear do_unused
#endif
_PROTOTYPE( int do_trace, (struct proc * caller, message *m_ptr) );
#define do_runctl do_unused
#endif
+_PROTOTYPE( int do_update, (struct proc * caller, message *m_ptr) );
+#if ! USE_UPDATE
+#define do_update do_unused
+#endif
+
+_PROTOTYPE( int do_exit, (struct proc * caller, message *m_ptr) );
+#if ! USE_EXIT
+#define do_exit do_unused
+#endif
+
_PROTOTYPE( int do_copy, (struct proc * caller, message *m_ptr) );
#define do_vircopy do_copy
#if ! (USE_VIRCOPY || USE_PHYSCOPY)
do_fork.o \
do_exec.o \
do_newmap.o \
+ do_clear.o \
do_exit.o \
do_trace.o \
do_nice.o \
do_runctl.o \
+ do_update.o \
do_times.o \
do_setalarm.o \
do_stime.o \
PUBLIC int do_abort(struct proc * caller, message * m_ptr)
{
/* Handle sys_abort. MINIX is unable to continue. This can originate e.g.
- * in the PM (normal abort or panic) or TTY (after CTRL-ALT-DEL).
+ * in the PM (normal abort) or TTY (after CTRL-ALT-DEL).
*/
int how = m_ptr->ABRT_HOW;
--- /dev/null
+/* The kernel call implemented in this file:
+ * m_type: SYS_CLEAR
+ *
+ * The parameters for this kernel call are:
+ * m1_i1: PR_ENDPT (endpoint of process to clean up)
+ */
+
+#include "../system.h"
+
+#include <minix/endpoint.h>
+
+#if USE_CLEAR
+
+/*===========================================================================*
+ * do_clear *
+ *===========================================================================*/
+PUBLIC int do_clear(struct proc * caller, message * m_ptr)
+{
+/* Handle sys_clear. Only the PM can request other process slots to be cleared
+ * when a process has exited.
+ * The routine to clean up a process table slot cancels outstanding timers,
+ * possibly removes the process from the message queues, and resets certain
+ * process table fields to the default values.
+ */
+ struct proc *rc;
+ int exit_p;
+ int i;
+
+ if(!isokendpt(m_ptr->PR_ENDPT, &exit_p)) { /* get exiting process */
+ return EINVAL;
+ }
+ rc = proc_addr(exit_p); /* clean up */
+
+ /* Don't clear if already cleared. */
+ if(isemptyp(rc)) return;
+
+ /* Check the table with IRQ hooks to see if hooks should be released. */
+ for (i=0; i < NR_IRQ_HOOKS; i++) {
+ if (rc->p_endpoint == irq_hooks[i].proc_nr_e) {
+ rm_irq_handler(&irq_hooks[i]); /* remove interrupt handler */
+ irq_hooks[i].proc_nr_e = NONE; /* mark hook as free */
+ }
+ }
+
+ /* Remove the process' ability to send and receive messages */
+ clear_endpoint(rc);
+
+ /* Turn off any alarm timers at the clock. */
+ reset_timer(&priv(rc)->s_alarm_timer);
+
+ /* Make sure that the exiting process is no longer scheduled,
+ * and mark slot as FREE. Also mark saved fpu contents as not significant.
+ */
+ RTS_SETFLAGS(rc, RTS_SLOT_FREE);
+ rc->p_misc_flags &= ~MF_FPU_INITIALIZED;
+
+ /* Release the process table slot. If this is a system process, also
+ * release its privilege structure. Further cleanup is not needed at
+ * this point. All important fields are reinitialized when the
+ * slots are assigned to another, new process.
+ */
+ if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE;
+
+#if 0
+ /* Clean up virtual memory */
+ if (rc->p_misc_flags & MF_VM) {
+ vm_map_default(rc);
+ }
+#endif
+
+ return OK;
+}
+
+#endif /* USE_CLEAR */
+
PUBLIC int do_endksig(struct proc * caller, message * m_ptr)
{
/* Finish up after a kernel type signal, caused by a SYS_KILL message or a
- * call to cause_sig by a task. This is called by the PM after processing a
- * signal it got with SYS_GETKSIG.
+ * call to cause_sig by a task. This is called by a signal manager after
+ * processing a signal it got with SYS_GETKSIG.
*/
register struct proc *rp;
int proc_nr;
return EINVAL;
rp = proc_addr(proc_nr);
+ if (caller->p_endpoint != priv(rp)->s_sig_mgr) return(EPERM);
if (!RTS_ISSET(rp, RTS_SIG_PENDING)) return(EINVAL);
- /* PM has finished one kernel signal. Perhaps process is ready now? */
+ /* The signal manager has finished one kernel signal. Is the process ready? */
if (!RTS_ISSET(rp, RTS_SIGNALED)) /* new signal arrived */
RTS_UNSET(rp, RTS_SIG_PENDING); /* remove pending flag */
return(OK);
/* The kernel call implemented in this file:
* m_type: SYS_EXIT
- *
- * The parameters for this kernel call are:
- * m1_i1: PR_ENDPT (slot number of exiting process)
*/
#include "../system.h"
#include <minix/endpoint.h>
+#include <signal.h>
#if USE_EXIT
-FORWARD _PROTOTYPE( void clear_proc, (register struct proc *rc));
-
/*===========================================================================*
- * do_exit *
+ * do_exit *
*===========================================================================*/
PUBLIC int do_exit(struct proc * caller, message * m_ptr)
{
-/* Handle sys_exit. A user process has exited or a system process requests
- * to exit. Only the PM can request other process slots to be cleared.
- * The routine to clean up a process table slot cancels outstanding timers,
- * possibly removes the process from the message queues, and resets certain
- * process table fields to the default values.
+/* Handle sys_exit. A system process has requested to exit. Generate a
+ * self-termination signal.
*/
- int exit_e;
-
- /* Determine what process exited. User processes are handled here. */
- if (PM_PROC_NR == caller->p_endpoint) {
- if (m_ptr->PR_ENDPT != SELF) { /* PM tries to exit self */
- if(!isokendpt(m_ptr->PR_ENDPT, &exit_e)) /* get exiting process */
- return EINVAL;
- clear_proc(proc_addr(exit_e)); /* exit a user process */
- return(OK); /* report back to PM */
- }
- }
-
- /* The PM or some other system process requested to be exited. */
- clear_proc(caller);
- return(EDONTREPLY);
-}
-
-/*===========================================================================*
- * clear_proc *
- *===========================================================================*/
-PRIVATE void clear_proc(rc)
-register struct proc *rc; /* slot of process to clean up */
-{
- int i;
-
- /* Don't clear if already cleared. */
- if(isemptyp(rc)) return;
-
- /* Check the table with IRQ hooks to see if hooks should be released. */
- for (i=0; i < NR_IRQ_HOOKS; i++) {
- if (rc->p_endpoint == irq_hooks[i].proc_nr_e) {
- rm_irq_handler(&irq_hooks[i]); /* remove interrupt handler */
- irq_hooks[i].proc_nr_e = NONE; /* mark hook as free */
- }
- }
-
- /* Remove the process' ability to send and receive messages */
- clear_endpoint(rc);
-
-
- /* Turn off any alarm timers at the clock. */
- reset_timer(&priv(rc)->s_alarm_timer);
-
- /* Make sure that the exiting process is no longer scheduled,
- * and mark slot as FREE. Also mark saved fpu contents as not significant.
- */
- RTS_SETFLAGS(rc, RTS_SLOT_FREE);
- rc->p_misc_flags &= ~MF_FPU_INITIALIZED;
+ int sig_nr = SIGABRT;
- /* Release the process table slot. If this is a system process, also
- * release its privilege structure. Further cleanup is not needed at
- * this point. All important fields are reinitialized when the
- * slots are assigned to another, new process.
- */
- if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE;
+ cause_sig(caller->p_nr, sig_nr); /* send a signal to the caller */
-#if 0
- /* Clean up virtual memory */
- if (rc->p_misc_flags & MF_VM) {
- vm_map_default(rc);
- }
-#endif
+ return(EDONTREPLY); /* don't reply */
}
#endif /* USE_EXIT */
*===========================================================================*/
PUBLIC int do_getksig(struct proc * caller, message * m_ptr)
{
-/* PM is ready to accept signals and repeatedly does a kernel call to get
- * one. Find a process with pending signals. If no signals are available,
- * return NONE in the process number field.
- * It is not sufficient to ready the process when PM is informed, because
- * PM can block waiting for FS to do a core dump.
+/* The signal manager is ready to accept signals and repeatedly does a kernel
+ * call to get one. Find a process with pending signals. If no signals are
+ * available, return NONE in the process number field.
*/
register struct proc *rp;
/* Find the next process with pending signals. */
for (rp = BEG_USER_ADDR; rp < END_PROC_ADDR; rp++) {
if (RTS_ISSET(rp, RTS_SIGNALED)) {
+ if (caller->p_endpoint != priv(rp)->s_sig_mgr) continue;
/* store signaled process' endpoint */
m_ptr->SIG_ENDPT = rp->p_endpoint;
m_ptr->SIG_MAP = rp->p_pending; /* pending signals map */
- sigemptyset(&rp->p_pending); /* ball is in PM's court */
+ sigemptyset(&rp->p_pending); /* clear map in the kernel */
RTS_UNSET(rp, RTS_SIGNALED); /* blocked by SIG_PENDING */
return(OK);
}
*===========================================================================*/
PUBLIC int do_kill(struct proc * caller, message * m_ptr)
{
-/* Handle sys_kill(). Cause a signal to be sent to a process. The PM is the
- * central server where all signals are processed and handler policies can
- * be registered. Any request, except for PM requests, is added to the map
- * of pending signals and the PM is informed about the new signal.
- * Since system servers cannot use normal POSIX signal handlers (because they
- * are usually blocked on a RECEIVE), they can request the PM to transform
- * signals into messages. This is done by the PM with a call to sys_kill().
+/* Handle sys_kill(). Cause a signal to be sent to a process. Any request
+ * is added to the map of pending signals and the signal manager
+ * associated to the process is informed about the new signal. The signal
+ * is then delivered using POSIX signal handlers for user processes, or
+ * translated into an IPC message for system services.
*/
proc_nr_t proc_nr, proc_nr_e;
int sig_nr = m_ptr->SIG_NUMBER;
if (sig_nr >= _NSIG) return(EINVAL);
if (iskerneln(proc_nr)) return(EPERM);
- /* Set pending signal to be processed by the PM. */
+ /* Set pending signal to be processed by the signal manager. */
cause_sig(proc_nr, sig_nr);
- if (sig_nr == SIGKILL)
- clear_endpoint(proc_addr(proc_nr));
+
return(OK);
}
priv(rp)->s_k_call_mask[i] = (kcalls == NO_C ? 0 : (~0));
}
+ /* Set the default signal manager. */
+ priv(rp)->s_sig_mgr = DEF_SYS_SM;
+
/* Set defaults for resources: no I/O resources, no memory resources,
* no IRQs, no grant table
*/
/* Override defaults if the caller has supplied a privilege structure. */
if (m_ptr->CTL_ARG_PTR)
{
- /* Copy s_flags. */
+ /* Copy s_flags and signal manager. */
priv(rp)->s_flags = priv.s_flags;
+ priv(rp)->s_sig_mgr = priv.s_sig_mgr;
/* Copy IRQs */
if(priv.s_flags & CHECK_IRQ) {
/* Control a process's RTS_PROC_STOP flag. Used for process management.
* If the process is queued sending a message or stopped for system call
* tracing, and the RC_DELAY request flag is given, set MF_SIG_DELAY instead
- * of RTS_PROC_STOP, and send a SIGNDELAY signal later when the process is done
+ * of RTS_PROC_STOP, and send a SIGKNDELAY signal later when the process is done
* sending (ending the delay). Used by PM for safe signal delivery.
*/
int proc_nr, action, flags, delayed;
#include <assert.h>
+#include <minix/type.h>
#include <minix/type.h>
#include <minix/safecopies.h>
#include "../system.h"
+#include <signal.h>
struct map_info_s {
int flag;
/* Connect caller on vmrequest wait queue. */
if(!(caller->p_vmrequest.nextrequestor = vmrequest))
- mini_notify(proc_addr(SYSTEM), VM_PROC_NR);
+ send_sig(VM_PROC_NR, SIGKMEM);
vmrequest = caller;
return OK;
--- /dev/null
+/* The kernel call implemented in this file:
+ * m_type: SYS_UPDATE
+ *
+ * The parameters for this kernel call are:
+ * m2_i1: SYS_UPD_SRC_ENDPT (source process endpoint)
+ * m2_i2: SYS_UPD_DST_ENDPT (destination process endpoint)
+ */
+
+#include "../system.h"
+#include "../ipc.h"
+#include <string.h>
+
+#if USE_UPDATE
+
+#define DEBUG 0
+
+#define proc_is_updatable(p) \
+ (RTS_ISSET(p, RTS_NO_PRIV) || RTS_ISSET(p, RTS_SIG_PENDING) \
+ || (RTS_ISSET(p, RTS_RECEIVING) && !RTS_ISSET(p, RTS_SENDING)))
+
+FORWARD _PROTOTYPE(void adjust_proc_slot, (struct proc *rp,
+ struct proc *from_rp));
+FORWARD _PROTOTYPE(void adjust_priv_slot, (struct priv *privp,
+ struct priv *from_privp));
+FORWARD _PROTOTYPE(void swap_proc_slot_pointer, (struct proc **rpp,
+ struct proc *src_rp, struct proc *dst_rp));
+
+/*===========================================================================*
+ * do_update *
+ *===========================================================================*/
+PUBLIC int do_update(struct proc * caller, message * m_ptr)
+{
+/* Handle sys_update(). Update a process into another by swapping their process
+ * slots.
+ */
+ endpoint_t src_e, dst_e;
+ int src_p, dst_p;
+ struct proc *src_rp, *dst_rp, *rp;
+ struct priv *src_privp, *dst_privp;
+ struct proc orig_src_proc;
+ struct proc orig_dst_proc;
+ struct priv orig_src_priv;
+ struct priv orig_dst_priv;
+ int r;
+ reg_t src_vbp, dst_vbp;
+
+ /* Lookup slots for source and destination process. */
+ src_e = m_ptr->SYS_UPD_SRC_ENDPT;
+ if(!isokendpt(src_e, &src_p)) {
+ return EINVAL;
+ }
+ src_rp = proc_addr(src_p);
+ src_privp = priv(src_rp);
+ if(!(src_privp->s_flags & SYS_PROC)) {
+ return EPERM;
+ }
+
+ dst_e = m_ptr->SYS_UPD_DST_ENDPT;
+ if(!isokendpt(dst_e, &dst_p)) {
+ return EINVAL;
+ }
+ dst_rp = proc_addr(dst_p);
+ dst_privp = priv(dst_rp);
+ if(!(dst_privp->s_flags & SYS_PROC)) {
+ return EPERM;
+ }
+
+ /* Check if processes are updatable. */
+ if(!proc_is_updatable(src_rp) || !proc_is_updatable(dst_rp)) {
+ return EBUSY;
+ }
+
+#if DEBUG
+ printf("do_update: updating %d (%s, %d, %d) into %d (%s, %d, %d)\n",
+ src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
+ dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
+
+ proc_stacktrace(src_rp);
+ proc_stacktrace(dst_rp);
+ printf("do_update: curr ptproc %d\n", ptproc->p_endpoint);
+#endif
+
+ /* Save existing data. */
+ orig_src_proc = *src_rp;
+ orig_src_priv = *(priv(src_rp));
+ orig_dst_proc = *dst_rp;
+ orig_dst_priv = *(priv(dst_rp));
+
+ /* Swap slots. */
+ *src_rp = orig_dst_proc;
+ *src_privp = orig_dst_priv;
+ *dst_rp = orig_src_proc;
+ *dst_privp = orig_src_priv;
+
+ /* Adjust process slots. */
+ adjust_proc_slot(src_rp, &orig_src_proc);
+ adjust_proc_slot(dst_rp, &orig_dst_proc);
+
+ /* Adjust privilege slots. */
+ adjust_priv_slot(priv(src_rp), &orig_src_priv);
+ adjust_priv_slot(priv(dst_rp), &orig_dst_priv);
+
+ /* Swap global process slot addresses. */
+ swap_proc_slot_pointer(&ptproc, src_rp, dst_rp);
+
+ /* Fix segments. */
+ alloc_segments(src_rp);
+ alloc_segments(dst_rp);
+ prot_init();
+
+#if DEBUG
+ printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n",
+ src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
+ dst_rp->p_endpoint, dst_rp->p_name, dst_rp->p_nr, priv(dst_rp)->s_proc_nr);
+
+ proc_stacktrace(src_rp);
+ proc_stacktrace(dst_rp);
+ printf("do_update: curr ptproc %d\n", ptproc->p_endpoint);
+#endif
+
+ return OK;
+}
+
+/*===========================================================================*
+ * adjust_proc_slot *
+ *===========================================================================*/
+PRIVATE void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
+{
+ /* Preserve endpoints, slot numbers, priv structure. */
+ rp->p_endpoint = from_rp->p_endpoint;
+ rp->p_nr = from_rp->p_nr;
+ rp->p_priv = from_rp->p_priv;
+ priv(rp)->s_proc_nr = from_rp->p_nr;
+}
+
+/*===========================================================================*
+ * adjust_priv_slot *
+ *===========================================================================*/
+PRIVATE void adjust_priv_slot(struct priv *privp, struct priv *from_privp)
+{
+ /* Preserve privilege ids and non-privilege stuff in the priv structure. */
+ privp->s_id = from_privp->s_id;
+ privp->s_notify_pending = from_privp->s_notify_pending;
+ privp->s_int_pending = from_privp->s_int_pending;
+ privp->s_sig_pending = from_privp->s_sig_pending;
+ privp->s_alarm_timer = from_privp->s_alarm_timer;
+ memcpy(privp->s_farmem, from_privp->s_farmem, sizeof(privp->s_farmem));
+}
+
+/*===========================================================================*
+ * swap_proc_slot_pointer *
+ *===========================================================================*/
+PRIVATE void swap_proc_slot_pointer(struct proc **rpp, struct proc *src_rp,
+ struct proc *dst_rp)
+{
+ if(*rpp == src_rp) {
+ *rpp = dst_rp;
+ }
+ else if(*rpp == dst_rp) {
+ *rpp = src_rp;
+ }
+}
+
+#endif /* USE_UPDATE */
+
"Function not implemented", /* ENOSYS */
"Directory not empty", /* ENOTEMPTY */
"Too many levels of symbolic links", /* ELOOP */
- "Driver restarted", /* ERESTART */
+ "Service restarted", /* ERESTART */
unknown, /* 42 */
"Identifier removed", /* EIDRM */
"Illegal byte sequence", /* EILSEQ */
_sysuname.c \
_vm_dmacalls.c \
_vm_set_priv.c \
+ _vm_update.c \
_vm_query_exit.c \
asynchio.c \
basename.c \
--- /dev/null
+#include <lib.h>
+#define vm_update _vm_update
+#include <unistd.h>
+
+PUBLIC int vm_update(endpoint_t src_e, endpoint_t dst_e)
+{
+ message m;
+ m.VM_RS_SRC_ENDPT = src_e;
+ m.VM_RS_DST_ENDPT = dst_e;
+
+ return _syscall(VM_PROC_NR, VM_RS_UPDATE, &m);
+}
vm_remap.S \
vm_unmap.S \
vm_set_priv.S \
+ vm_update.S \
vm_query_exit.S \
mount.S \
nanosleep.S \
--- /dev/null
+.text
+.extern __vm_update
+.globl _vm_update
+.balign 2
+
+_vm_update:
+ jmp __vm_update
pci_slot_name.c \
safecopies.c \
sef.c \
+ sef_init.c \
sef_liveupdate.c \
sef_ping.c \
- sef_init.c \
+ sef_signal.c \
sys_abort.c \
+ sys_clear.c \
sys_mcontext.c \
sys_cprof.c \
sys_endsig.c \
sys_physcopy.c \
sys_readbios.c \
sys_runctl.c \
+ sys_update.c \
sys_safecopy.c \
sys_safemap.c \
sys_sysctl.c \
return do_invoke_ds(DS_PUBLISH, ds_name);
}
-int ds_publish_str(const char *ds_name, char *value, int flags)
-{
- if(strlen(value) >= DS_MAX_STRLEN)
- return EINVAL;
- strcpy((char *)(&m.DS_STRING), value);
- m.DS_FLAGS = DSF_TYPE_STR | flags;
- return do_invoke_ds(DS_PUBLISH, ds_name);
-}
-
-int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags)
+static int ds_publish_raw(const char *ds_name, void *vaddr, size_t length,
+ int flags)
{
cp_grant_id_t gid;
int r;
m.DS_VAL = gid;
m.DS_VAL_LEN = length;
- m.DS_FLAGS = DSF_TYPE_MEM | flags;
+ m.DS_FLAGS = flags;
r = do_invoke_ds(DS_PUBLISH, ds_name);
cpf_revoke(gid);
return r;
}
+int ds_publish_str(const char *ds_name, char *value, int flags)
+{
+ size_t length;
+ length = strlen(value) + 1;
+ value[length - 1] = '\0';
+ return ds_publish_raw(ds_name, value, length, flags | DSF_TYPE_STR);
+}
+
+int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags)
+{
+ return ds_publish_raw(ds_name, vaddr, length, flags | DSF_TYPE_MEM);
+}
+
int ds_publish_map(const char *ds_name, void *vaddr, size_t length, int flags)
{
cp_grant_id_t gid;
m.DS_FLAGS = DSF_TYPE_MAP | flags;
r = do_invoke_ds(DS_PUBLISH, ds_name);
- cpf_revoke(gid);
return r;
}
return r;
}
-int ds_retrieve_str(const char *ds_name, char *value, size_t len_str)
-{
- int r;
- m.DS_FLAGS = DSF_TYPE_STR;
- r = do_invoke_ds(DS_RETRIEVE, ds_name);
- strncpy(value, (char *)(&m.DS_STRING), DS_MAX_STRLEN);
- value[DS_MAX_STRLEN - 1] = '\0';
- return r;
-}
-
-int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length)
+static int ds_retrieve_raw(const char *ds_name, char *vaddr, size_t *length,
+ int flags)
{
cp_grant_id_t gid;
int r;
m.DS_VAL = gid;
m.DS_VAL_LEN = *length;
- m.DS_FLAGS = DSF_TYPE_MEM;
+ m.DS_FLAGS = flags;
r = do_invoke_ds(DS_RETRIEVE, ds_name);
*length = m.DS_VAL_LEN;
cpf_revoke(gid);
return r;
}
+int ds_retrieve_str(const char *ds_name, char *value, size_t len_str)
+{
+ int r;
+ size_t length = len_str + 1;
+ r = ds_retrieve_raw(ds_name, value, &length, DSF_TYPE_STR);
+ value[length - 1] = '\0';
+ return r;
+}
+
+int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length)
+{
+ return ds_retrieve_raw(ds_name, vaddr, length, DSF_TYPE_MEM);
+}
+
int ds_retrieve_map(const char *ds_name, char *vaddr, size_t *length,
int nr_snapshot, int flags)
{
/* Self variables. */
#define SEF_SELF_NAME_MAXLEN 20
-PRIVATE char sef_self_name[SEF_SELF_NAME_MAXLEN];
-PRIVATE endpoint_t sef_self_endpoint;
+PUBLIC char sef_self_name[SEF_SELF_NAME_MAXLEN];
+PUBLIC endpoint_t sef_self_endpoint;
/* Debug. */
#define SEF_DEBUG_HEADER_MAXLEN 32
EXTERN _PROTOTYPE( int do_sef_rs_init, (void) );
EXTERN _PROTOTYPE( int do_sef_init_request, (message *m_ptr) );
+/* SEF Ping prototypes. */
+EXTERN _PROTOTYPE( int do_sef_ping_request, (message *m_ptr) );
+
/* SEF Live update prototypes. */
EXTERN _PROTOTYPE( void do_sef_lu_before_receive, (void) );
EXTERN _PROTOTYPE( int do_sef_lu_request, (message *m_ptr) );
-/* SEF Ping prototypes. */
-EXTERN _PROTOTYPE( int do_sef_ping_request, (message *m_ptr) );
+/* SEF Signal prototypes. */
+EXTERN _PROTOTYPE( int do_sef_signal_request, (message *m_ptr) );
/*===========================================================================*
* sef_startup *
*===========================================================================*/
PUBLIC void sef_startup()
{
-/* SEF startup interface for system processes. */
+/* SEF startup interface for system services. */
int r;
/* Get information about self. */
}
}
else {
- panic("unable to receive init request");
+ panic("got an unexpected message type %d", m.m_type);
}
}
#endif
*===========================================================================*/
PUBLIC int sef_receive(endpoint_t src, message *m_ptr)
{
-/* SEF receive() interface for system processes. */
+/* SEF receive() interface for system services. */
int r;
while(TRUE) {
}
#endif
+#if INTERCEPT_SEF_SIGNAL_REQUESTS
+ /* Intercept SEF Signal requests. */
+ if(IS_SEF_SIGNAL_REQUEST(m_ptr)) {
+ if(do_sef_signal_request(m_ptr) == OK) {
+ continue;
+ }
+ }
+#endif
+
/* If we get this far, this is not a valid SEF request, return and
* let the caller deal with that.
*/
return r;
}
+/*===========================================================================*
+ * sef_exit *
+ *===========================================================================*/
+PUBLIC void sef_exit(int status)
+{
+/* System services use a special version of exit() that generates a
+ * self-termination signal.
+ */
+ message m;
+
+ /* Ask the kernel to exit. */
+ sys_exit();
+
+ /* If sys_exit() fails, this is not a system service. Exit through PM. */
+ m.m1_i1 = status;
+ _syscall(PM_PROC_NR, EXIT, &m);
+
+ /* If everything else fails, hang. */
+ printf("Warning: system service %d couldn't exit\n", sef_self_endpoint);
+ for(;;) { }
+}
+
+/*===========================================================================*
+ * _exit *
+ *===========================================================================*/
+PUBLIC void _exit(int status)
+{
+/* Make exit() an alias for sef_exit() for system services. */
+ sef_exit(status);
+}
+
+/*===========================================================================*
+ * __exit *
+ *===========================================================================*/
+PUBLIC void __exit(int status)
+{
+/* Make exit() an alias for sef_exit() for system services. */
+ sef_exit(status);
+}
+
/*===========================================================================*
* sef_debug_refresh_params *
*===========================================================================*/
/* SEF Init callbacks. */
PRIVATE struct sef_cbs {
- sef_cb_init_fresh_t sef_cb_init_fresh;
- sef_cb_init_lu_t sef_cb_init_lu;
- sef_cb_init_restart_t sef_cb_init_restart;
+ sef_cb_init_t sef_cb_init_fresh;
+ sef_cb_init_t sef_cb_init_lu;
+ sef_cb_init_t sef_cb_init_restart;
} sef_cbs = {
SEF_CB_INIT_FRESH_DEFAULT,
SEF_CB_INIT_LU_DEFAULT,
break;
}
- /* Report back to RS. XXX FIXME: we should use send, but this would cause
- * a deadlock due to the current blocking nature of mapdriver().
- */
+ /* Report back to RS. */
m_ptr->RS_INIT_RESULT = r;
- r = asynsend(RS_PROC_NR, m_ptr);
+ r = sendrec(RS_PROC_NR, m_ptr);
return r;
}
/*===========================================================================*
* sef_setcb_init_fresh *
*===========================================================================*/
-PUBLIC void sef_setcb_init_fresh(sef_cb_init_fresh_t cb)
+PUBLIC void sef_setcb_init_fresh(sef_cb_init_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_init_fresh = cb;
/*===========================================================================*
* sef_setcb_init_lu *
*===========================================================================*/
-PUBLIC void sef_setcb_init_lu(sef_cb_init_lu_t cb)
+PUBLIC void sef_setcb_init_lu(sef_cb_init_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_init_lu = cb;
/*===========================================================================*
* sef_setcb_init_restart *
*===========================================================================*/
-PUBLIC void sef_setcb_init_restart(sef_cb_init_restart_t cb)
+PUBLIC void sef_setcb_init_restart(sef_cb_init_t cb)
{
assert(cb != NULL);
sef_cbs.sef_cb_init_restart = cb;
}
/*===========================================================================*
- * sef_cb_init_fresh_null *
+ * sef_cb_init_null *
*===========================================================================*/
-PUBLIC int sef_cb_init_fresh_null(int UNUSED(type),
+PUBLIC int sef_cb_init_null(int UNUSED(type),
sef_init_info_t *UNUSED(info))
{
- return(OK);
+ return OK;
}
/*===========================================================================*
- * sef_cb_init_lu_null *
+ * sef_cb_init_fail *
*===========================================================================*/
-PUBLIC int sef_cb_init_lu_null(int UNUSED(type), sef_init_info_t *UNUSED(info))
+PUBLIC int sef_cb_init_fail(int UNUSED(type), sef_init_info_t *UNUSED(info))
{
- return(OK);
+ return ENOSYS;
}
/*===========================================================================*
- * sef_cb_init_restart_null *
+ * sef_cb_init_crash *
*===========================================================================*/
-PUBLIC int sef_cb_init_restart_null(int UNUSED(type),
- sef_init_info_t *UNUSED(info))
+PUBLIC int sef_cb_init_crash(int UNUSED(type), sef_init_info_t *UNUSED(info))
{
- return(OK);
-}
+ panic("Simulating a crash at initialization time...");
-/*===========================================================================*
- * sef_cb_init_restart_fail *
- *===========================================================================*/
-PUBLIC int sef_cb_init_restart_fail(int UNUSED(type),
- sef_init_info_t *UNUSED(info))
-{
- return(ENOSYS);
+ return OK;
}
sef_cb_lu_state_isvalid_t sef_cb_lu_state_isvalid;
sef_cb_lu_state_changed_t sef_cb_lu_state_changed;
sef_cb_lu_state_dump_t sef_cb_lu_state_dump;
- sef_cb_lu_ready_pre_t sef_cb_lu_ready_pre;
+ sef_cb_lu_state_save_t sef_cb_lu_state_save;
} sef_cbs = {
SEF_CB_LU_PREPARE_DEFAULT,
SEF_CB_LU_STATE_ISVALID_DEFAULT,
SEF_CB_LU_STATE_CHANGED_DEFAULT,
SEF_CB_LU_STATE_DUMP_DEFAULT,
- SEF_CB_LU_READY_PRE_DEFAULT,
+ SEF_CB_LU_STATE_SAVE_DEFAULT,
};
/* SEF Live update prototypes for sef_receive(). */
PUBLIC _PROTOTYPE( void do_sef_lu_before_receive, (void) );
PUBLIC _PROTOTYPE( int do_sef_lu_request, (message *m_ptr) );
+/* SEF Live update helpers. */
+PRIVATE _PROTOTYPE( void sef_lu_ready, (int result) );
+
/* Debug. */
EXTERN _PROTOTYPE( char* sef_debug_header, (void) );
PRIVATE int sef_lu_debug_cycle = 0;
PUBLIC void do_sef_lu_before_receive()
{
/* Handle SEF Live update before receive events. */
+ int r;
/* Nothing to do if we are not preparing for a live update. */
if(sef_lu_state == SEF_LU_STATE_NULL) {
/* Let the callback code handle the event.
* For SEF_LU_STATE_WORK_FREE, we're always ready, tell immediately.
*/
- if(sef_lu_state == SEF_LU_STATE_WORK_FREE) {
- sef_lu_ready(OK);
+ r = OK;
+ if(sef_lu_state != SEF_LU_STATE_WORK_FREE) {
+ r = sef_cbs.sef_cb_lu_prepare(sef_lu_state);
}
- else {
- sef_cbs.sef_cb_lu_prepare(sef_lu_state);
+ if(r == OK) {
+ sef_lu_ready(OK);
}
}
PUBLIC int do_sef_lu_request(message *m_ptr)
{
/* Handle a SEF Live update request. */
- int old_state, is_valid_state;
+ int state, old_state, is_valid_state;
sef_lu_debug_cycle = 0;
old_state = sef_lu_state;
+ state = m_ptr->RS_LU_STATE;
- /* Only accept live update requests with a valid state. */
- is_valid_state = sef_cbs.sef_cb_lu_state_isvalid(m_ptr->RS_LU_STATE);
+ /* Deal with prepare cancel requests first. */
+ is_valid_state = (state == SEF_LU_STATE_NULL);
+
+ /* Otherwise only accept live update requests with a valid state. */
+ is_valid_state = is_valid_state || sef_cbs.sef_cb_lu_state_isvalid(state);
if(!is_valid_state) {
- sef_lu_ready(EINVAL);
+ if(sef_cbs.sef_cb_lu_state_isvalid == SEF_CB_LU_STATE_ISVALID_NULL) {
+ sef_lu_ready(ENOSYS);
+ }
+ else {
+ sef_lu_ready(EINVAL);
+ }
}
else {
/* Set the new live update state. */
- sef_lu_state = m_ptr->RS_LU_STATE;
+ sef_lu_state = state;
/* If the live update state changed, let the callback code
* handle the rest.
/*===========================================================================*
* sef_lu_ready *
*===========================================================================*/
-PUBLIC void sef_lu_ready(int result)
+PRIVATE void sef_lu_ready(int result)
{
message m;
- int old_state, r;
+ int old_state, rs_result, r;
#if SEF_LU_DEBUG
sef_lu_debug_begin();
sef_lu_debug_end();
#endif
- /* Let the callback code perform any pre-ready operations. */
- r = sef_cbs.sef_cb_lu_ready_pre(result);
- if(r != OK) {
- /* Abort update if callback returned error. */
- result = r;
- }
- else {
- /* Inform RS that we're ready with the given result. */
- m.m_type = RS_LU_PREPARE;
- m.RS_LU_STATE = sef_lu_state;
- m.RS_LU_RESULT = result;
- r = sendrec(RS_PROC_NR, &m);
- if ( r != OK) {
- panic("sendrec failed: %d", r);
+ /* If result is OK, let the callback code save
+ * any state that must be carried over to the new version.
+ */
+ if(result == OK) {
+ r = sef_cbs.sef_cb_lu_state_save(sef_lu_state);
+ if(r != OK) {
+ /* Abort update if callback returned error. */
+ result = r;
}
}
+ /* Inform RS that we're ready with the given result. */
+ m.m_type = RS_LU_PREPARE;
+ m.RS_LU_STATE = sef_lu_state;
+ m.RS_LU_RESULT = result;
+ r = sendrec(RS_PROC_NR, &m);
+ if ( r != OK) {
+ panic("sendrec failed: %d", r);
+ }
+
#if SEF_LU_DEBUG
+ rs_result = m.m_type == RS_LU_PREPARE ? EINTR : m.m_type;
sef_lu_debug_begin();
- sef_lu_dprint("%s, cycle=%d. The %s aborted the update!\n",
+ sef_lu_dprint("%s, cycle=%d. The %s aborted the update with result %d!\n",
sef_debug_header(), sef_lu_debug_cycle,
- (result == OK ? "server" : "client"));
+ (result == OK ? "server" : "client"),
+ (result == OK ? rs_result : result)); /* EINTR if update was canceled. */
sef_lu_debug_end();
#endif
}
/*===========================================================================*
- * sef_setcb_lu_ready_pre *
+ * sef_setcb_lu_state_save *
*===========================================================================*/
-PUBLIC void sef_setcb_lu_ready_pre(sef_cb_lu_ready_pre_t cb)
+PUBLIC void sef_setcb_lu_state_save(sef_cb_lu_state_save_t cb)
{
assert(cb != NULL);
- sef_cbs.sef_cb_lu_ready_pre = cb;
+ sef_cbs.sef_cb_lu_state_save = cb;
}
/*===========================================================================*
* sef_cb_lu_prepare_null *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare_null(int UNUSED(state))
+PUBLIC int sef_cb_lu_prepare_null(int UNUSED(state))
{
+ return ENOTREADY;
}
/*===========================================================================*
}
/*===========================================================================*
- * sef_cb_lu_ready_pre_null *
+ * sef_cb_lu_state_save_null *
*===========================================================================*/
-PUBLIC int sef_cb_lu_ready_pre_null(int UNUSED(result))
+PUBLIC int sef_cb_lu_state_save_null(int UNUSED(result))
{
- return(OK);
+ return OK;
}
/*===========================================================================*
* sef_cb_lu_prepare_always_ready *
*===========================================================================*/
-PUBLIC void sef_cb_lu_prepare_always_ready(int UNUSED(state))
+PUBLIC int sef_cb_lu_prepare_always_ready(int UNUSED(state))
+{
+ return OK;
+}
+
+/*===========================================================================*
+ * sef_cb_lu_prepare_never_ready *
+ *===========================================================================*/
+PUBLIC int sef_cb_lu_prepare_never_ready(int UNUSED(state))
{
- sef_lu_ready(OK);
+#if SEF_LU_DEBUG
+ sef_lu_debug_begin();
+ sef_lu_dprint("%s, cycle=%d. Simulating a service never ready to update...\n",
+ sef_debug_header(), sef_lu_debug_cycle);
+ sef_lu_debug_end();
+#endif
+
+ return ENOTREADY;
+}
+
+/*===========================================================================*
+ * sef_cb_lu_prepare_crash *
+ *===========================================================================*/
+PUBLIC int sef_cb_lu_prepare_crash(int UNUSED(state))
+{
+ panic("Simulating a crash at update prepare time...");
+
+ return OK;
}
/*===========================================================================*
#endif
/* Let the callback code handle the request. */
- sef_cbs.sef_cb_ping_reply(m_ptr);
+ sef_cbs.sef_cb_ping_reply(m_ptr->m_source);
/* Return OK not to let anybody else intercept the request. */
return(OK);
/*===========================================================================*
* sef_cb_ping_reply_null *
*===========================================================================*/
-PUBLIC void sef_cb_ping_reply_null(message *UNUSED(m_ptr))
+PUBLIC void sef_cb_ping_reply_null(endpoint_t UNUSED(source))
{
}
/*===========================================================================*
* sef_cb_ping_reply_pong *
*===========================================================================*/
-PUBLIC void sef_cb_ping_reply_pong(message *m_ptr)
+PUBLIC void sef_cb_ping_reply_pong(endpoint_t source)
{
- notify(m_ptr->m_source);
+ notify(source);
}
--- /dev/null
+#include "syslib.h"
+#include <assert.h>
+#include <signal.h>
+#include <minix/sysutil.h>
+
+/* SEF Signal callbacks. */
+PRIVATE struct sef_cbs {
+ sef_cb_signal_handler_t sef_cb_signal_handler;
+ sef_cb_signal_manager_t sef_cb_signal_manager;
+} sef_cbs = {
+ SEF_CB_SIGNAL_HANDLER_DEFAULT,
+ SEF_CB_SIGNAL_MANAGER_DEFAULT
+};
+
+/* SEF Signal prototypes for sef_receive(). */
+PUBLIC _PROTOTYPE( int do_sef_signal_request, (message *m_ptr) );
+
+/* Debug. */
+EXTERN _PROTOTYPE( char* sef_debug_header, (void) );
+
+/* Information about SELF. */
+EXTERN endpoint_t sef_self_endpoint;
+
+/*===========================================================================*
+ * process_sigmgr_signals *
+ *===========================================================================*/
+PRIVATE void process_sigmgr_signals(void)
+{
+/* A signal manager has pending signals in the kernel. Process them. */
+ endpoint_t target;
+ sigset_t sigset;
+ int signo, r;
+
+ while (TRUE) {
+ /* Get an arbitrary pending signal. */
+ if((r=sys_getksig(&target, &sigset)) != OK)
+ panic("SEF", "sys_getksig failed", r);
+
+ if (target == NONE) {
+ /* Stop if there are no more pending signals. */
+ break;
+ } else {
+ /* Process every signal in the signal set. */
+ r = OK;
+ for(signo = 1; signo < _NSIG; signo++) {
+ if(sigismember(&sigset, signo)) {
+ /* Let the callback code process the signal. */
+ r = sef_cbs.sef_cb_signal_manager(target, signo);
+
+ /* Stop if process is gone. */
+ if(r == EDEADSRCDST) {
+ break;
+ }
+ }
+ }
+ /* Tell the kernel we are done if the target is still alive. */
+ if(r == OK) {
+ if((r=sys_endksig(target)) != OK)
+ panic("SEF","sys_endksig failed", r);
+ }
+ }
+ }
+}
+
+/*===========================================================================*
+ * process_sigmgr_self_signals *
+ *===========================================================================*/
+PRIVATE void process_sigmgr_self_signals(sigset_t sigset)
+{
+/* A signal manager has pending signals for itself. Process them. */
+ int signo;
+
+ for(signo = 1; signo < _NSIG; signo++) {
+ if(sigismember(&sigset, signo)) {
+ /* Let the callback code process the signal. */
+ sef_cbs.sef_cb_signal_handler(signo);
+ }
+ }
+}
+
+/*===========================================================================*
+ * do_sef_signal_request *
+ *===========================================================================*/
+PUBLIC int do_sef_signal_request(message *m_ptr)
+{
+/* Handle a SEF Signal request. */
+ int signo;
+ sigset_t sigset;
+
+ if(m_ptr->m_source == SYSTEM) {
+ /* Handle kernel signals. */
+ sigset = m_ptr->NOTIFY_ARG;
+ for (signo = SIGK_FIRST; signo <= SIGK_LAST; signo++) {
+ if (sigismember(&sigset, signo)) {
+ /* Let the callback code handle the kernel signal. */
+ sef_cbs.sef_cb_signal_handler(signo);
+
+ /* Handle SIGKSIG for a signal manager. */
+ if(signo == SIGKSIG) {
+ process_sigmgr_signals();
+ }
+ /* Handle SIGKSIGSM for a signal manager. */
+ else if(signo == SIGKSIGSM) {
+ process_sigmgr_self_signals(sigset);
+ }
+ }
+ }
+ }
+ else {
+ /* Handle system signals from a signal manager. */
+ signo = m_ptr->SIGS_SIG_NUM;
+
+ /* Debug. */
+#if SEF_SIGNAL_DEBUG
+ sef_signal_debug_begin();
+ sef_signal_dprint("%s. Got a SEF Signal request for signal %d! About to handle signal.\n",
+ sef_debug_header(), signo);
+ sef_signal_debug_end();
+#endif
+
+ /* Let the callback code handle the signal. */
+ sef_cbs.sef_cb_signal_handler(signo);
+ }
+
+ /* Return OK not to let anybody else intercept the request. */
+ return OK;
+}
+
+/*===========================================================================*
+ * sef_setcb_signal_handler *
+ *===========================================================================*/
+PUBLIC void sef_setcb_signal_handler(sef_cb_signal_handler_t cb)
+{
+ assert(cb != NULL);
+ sef_cbs.sef_cb_signal_handler = cb;
+}
+
+/*===========================================================================*
+ * sef_setcb_signal_manager *
+ *===========================================================================*/
+PUBLIC void sef_setcb_signal_manager(sef_cb_signal_manager_t cb)
+{
+ assert(cb != NULL);
+ sef_cbs.sef_cb_signal_manager = cb;
+}
+
+/*===========================================================================*
+ * sef_cb_signal_handler_null *
+ *===========================================================================*/
+PUBLIC void sef_cb_signal_handler_null(int signo)
+{
+}
+
+/*===========================================================================*
+ * sef_cb_signal_manager_null *
+ *===========================================================================*/
+PUBLIC int sef_cb_signal_manager_null(endpoint_t target, int signo)
+{
+ return OK;
+}
+
+/*===========================================================================*
+ * sef_cb_signal_handler_term *
+ *===========================================================================*/
+PUBLIC void sef_cb_signal_handler_term(int signo)
+{
+ /* Terminate in case of SIGTERM, ignore other signals. */
+ if(signo == SIGTERM) {
+ sef_exit(1);
+ }
+}
+
+/*===========================================================================*
+ * sef_cb_signal_handler_posix_default *
+ *===========================================================================*/
+PUBLIC void sef_cb_signal_handler_posix_default(int signo)
+{
+ switch(signo) {
+ /* Ignore when possible. */
+ case SIGCHLD:
+ case SIGWINCH:
+ case SIGCONT:
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ break;
+
+ /* Terminate in any other case unless it is a kernel signal. */
+ default:
+ if(!IS_SIGK(signo)) {
+ sef_exit(1);
+ }
+ break;
+ }
+}
+
--- /dev/null
+#include "syslib.h"
+
+/*===========================================================================*
+ * sys_clear *
+ *===========================================================================*/
+PUBLIC int sys_clear(proc_ep)
+endpoint_t proc_ep; /* which process has exited */
+{
+/* A process has exited. PM tells the kernel.
+ */
+ message m;
+
+ m.PR_ENDPT = proc_ep;
+ return(_kernel_call(SYS_CLEAR, &m));
+}
/*===========================================================================*
* sys_exit *
*===========================================================================*/
-PUBLIC int sys_exit(proc_ep)
-endpoint_t proc_ep; /* which process has exited */
+PUBLIC int sys_exit()
{
-/* A process has exited. PM tells the kernel. In addition this call can be
- * used by system processes to directly exit without passing through the
- * PM. This should be used with care to prevent inconsistent PM tables.
- */
+/* A system process requests to exit. */
message m;
- m.PR_ENDPT = proc_ep;
return(_kernel_call(SYS_EXIT, &m));
}
--- /dev/null
+#include "syslib.h"
+
+int sys_update(endpoint_t src_ep, endpoint_t dst_ep)
+{
+ message m;
+
+ m.SYS_UPD_SRC_ENDPT = src_ep;
+ m.SYS_UPD_DST_ENDPT = dst_ep;
+
+ return _kernel_call(SYS_UPDATE, &m);
+}
was supplied to a remove directory or rename call.
.en 40 ELOOP "Too many symbolic links"
A path name lookup involved too many symbolic links.
-.en 41 ERESTART "Device driver restarted
+.en 41 ERESTART "Service restarted
.en 43 EIDRM "Identifier removed
.en 44 EILSEQ "Illegal byte sequence
.en 50 EPACKSIZE "Invalid packet size
/* Header file including all needed system headers. */
-#define _SYSTEM 1 /* get OK and negative error codes */
+#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
#define _MINIX 1 /* tell headers to include MINIX stuff */
+#define _SYSTEM 1 /* get OK and negative error codes */
#include <ansi.h>
#include <sys/types.h>
PRIVATE int callnr; /* system call number */
/* Declare some local functions. */
-FORWARD _PROTOTYPE(void exit_server, (void) );
-FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void get_work, (message *m_ptr) );
FORWARD _PROTOTYPE(void reply, (int whom, message *m_ptr) );
get_work(&m);
if (is_notify(callnr)) {
- switch (_ENDPOINT_P(who_e)) {
- case PM_PROC_NR:
- sig_handler();
- break;
- default:
- printf("DS: warning, got illegal notify from: %d\n",
- m.m_source);
- result = EINVAL;
- goto send_reply;
- }
-
- /* done, get a new message */
+ printf("DS: warning, got illegal notify from: %d\n", m.m_source);
+ result = EINVAL;
+ goto send_reply;
}
switch (callnr) {
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
sef_startup();
}
-/*===========================================================================*
- * sig_handler *
- *===========================================================================*/
-PRIVATE void sig_handler()
-{
-/* Signal handler. */
- sigset_t sigset;
-
- /* Try to obtain signal set from PM. */
- if (getsigset(&sigset) != 0) return;
-
- /* Check for known signals. */
- if (sigismember(&sigset, SIGTERM)) {
- exit_server();
- }
-}
-
-/*===========================================================================*
- * exit_server *
- *===========================================================================*/
-PRIVATE void exit_server()
-{
-/* Shut down the information service. */
-
- /* Done. Now exit. */
- exit(0);
-}
-
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE int check_auth(struct data_store *p, endpoint_t ep, int perm)
{
/* Check authorization for a given type of permission. */
+ char *source;
+
if(!(p->flags & perm))
return 1;
- return !strcmp(p->owner, ds_getprocname(ep));
+ source = ds_getprocname(ep);
+ return source && !strcmp(p->owner, source);
}
/*===========================================================================*
/* Set attributes. */
strcpy(dsp->key, rpub->label);
dsp->u.u32 = (u32_t) rpub->endpoint;
- strcpy(dsp->owner, ds_getprocname(DS_PROC_NR));
+ strcpy(dsp->owner, "rs");
dsp->flags = DSF_IN_USE | DSF_TYPE_LABEL;
/* Update subscribers having a matching subscription. */
{
struct data_store *dsp;
char key_name[DS_MAX_KEYLEN];
+ char *source;
int flags = m_ptr->DS_FLAGS;
size_t length;
int r;
+ /* Lookup the source. */
+ source = ds_getprocname(m_ptr->m_source);
+ if(source == NULL)
+ return EPERM;
+
/* MAP should not be overwritten. */
if((flags & DSF_TYPE_MAP) && (flags & DSF_OVERWRITE))
return EINVAL;
dsp->u.u32 = m_ptr->DS_VAL;
break;
case DSF_TYPE_STR:
- strncpy(dsp->u.string, (char *)(&m_ptr->DS_STRING), DS_MAX_STRLEN);
- dsp->u.string[DS_MAX_STRLEN - 1] = '\0';
- break;
case DSF_TYPE_MEM:
length = m_ptr->DS_VAL_LEN;
/* Allocate a new data buffer if necessary. */
return r;
}
dsp->u.mem.length = length;
+ if(flags & DSF_TYPE_STR) {
+ ((char*)dsp->u.mem.data)[length-1] = '\0';
+ }
break;
case DSF_TYPE_MAP:
/* Allocate buffer, the address should be aligned by CLICK_SIZE. */
/* Set attributes. */
strcpy(dsp->key, key_name);
- strcpy(dsp->owner, ds_getprocname(m_ptr->m_source));
+ strcpy(dsp->owner, source);
dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
/* Update subscribers having a matching subscription. */
m_ptr->DS_VAL = dsp->u.u32;
break;
case DSF_TYPE_STR:
- strncpy((char *)(&m_ptr->DS_STRING), dsp->u.string, DS_MAX_STRLEN);
- break;
case DSF_TYPE_MEM:
length = MIN(m_ptr->DS_VAL_LEN, dsp->u.mem.length);
r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->DS_VAL, 0,
{
struct data_store *dsp;
char key_name[DS_MAX_KEYLEN];
+ char *source;
int type = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
int top, i, r;
+ /* Lookup the source. */
+ source = ds_getprocname(m_ptr->m_source);
+ if(source == NULL)
+ return EPERM;
+
/* Get key name. */
if((r = get_key_name(m_ptr, key_name)) != OK)
return r;
return ESRCH;
/* Only the owner can delete. */
- if(strcmp(dsp->owner, ds_getprocname(m_ptr->m_source)))
+ if(strcmp(dsp->owner, source))
return EPERM;
switch(type) {
case DSF_TYPE_U32:
- case DSF_TYPE_STR:
case DSF_TYPE_LABEL:
break;
+ case DSF_TYPE_STR:
case DSF_TYPE_MEM:
free(dsp->u.mem.data);
break;
/* Unmap the mapped data. */
r = sys_safeunmap(D, (vir_bytes)dsp->u.map.data);
if(r != OK)
- return r;
+ printf("DS: sys_safeunmap failed. Grant already revoked?\n");
/* Revoke all the mapped grants. */
r = sys_saferevmap_addr((vir_bytes)dsp->u.map.data);
union {
unsigned u32;
- char string[DS_MAX_STRLEN];
struct {
void *data;
size_t length;
#include <signal.h>
#include <unistd.h>
+#include <stdlib.h>
-FORWARD _PROTOTYPE( int init, (int type, sef_init_info_t *info) );
-FORWARD _PROTOTYPE( void sef_local_startup, (void) );
-FORWARD _PROTOTYPE( void cleanup, (void) );
FORWARD _PROTOTYPE( int get_work, (endpoint_t *who_e) );
FORWARD _PROTOTYPE( void send_reply, (int err) );
-FORWARD _PROTOTYPE( int proc_event, (void) );
PRIVATE struct optset optset_table[] = {
{ "prefix", OPT_STRING, opt.prefix, sizeof(opt.prefix) },
{ NULL }
};
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
/*===========================================================================*
- * init *
+ * sef_cb_init_fresh *
*===========================================================================*/
-PRIVATE int init(type, info)
+PRIVATE int sef_cb_init_fresh(type, info)
int type;
sef_init_info_t *info;
{
}
/*===========================================================================*
- * sef_local_startup *
+ * sef_cb_signal_handler *
*===========================================================================*/
-PRIVATE void sef_local_startup()
+PRIVATE void sef_cb_signal_handler(int signo)
{
-/* Specify initialization routines and start the SEF framework.
- */
+ sigset_t set;
+ int r;
- sef_setcb_init_fresh(init);
- sef_setcb_init_restart(init);
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
- /* No live update support yet. */
+ if (state.mounted) {
+ dprintf(("HGFS: got SIGTERM, still mounted\n"));
+ }
+ else {
+ dprintf(("HGFS: got SIGTERM, shutting down\n"));
- sef_startup();
+ /* Pass on the cleanup request to the HGFS library. */
+ hgfs_cleanup();
+ exit(0);
+ }
}
/*===========================================================================*
- * cleanup *
+ * sef_local_startup *
*===========================================================================*/
-PRIVATE void cleanup()
+PRIVATE void sef_local_startup()
{
-/* Clean up any resources in use by this file server. Called at shutdown time.
- */
+ /* Register init callbacks. */
+ sef_setcb_init_fresh(sef_cb_init_fresh);
+ sef_setcb_init_restart(sef_cb_init_fresh);
+
+ /* No live update support yet. */
- /* Pass on the cleanup request to the HGFS library. */
- hgfs_cleanup();
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
+ sef_startup();
}
/*===========================================================================*
call_nr = get_work(&who_e);
if (who_e != FS_PROC_NR) {
- /* Is this PM telling us to shut down? */
- if (who_e == PM_PROC_NR && is_notify(call_nr))
- if (proc_event()) break;
-
continue;
}
send_reply(err);
}
- cleanup();
-
return 0;
}
printf("HGFS: send failed (%d)\n", r);
}
-/*===========================================================================*
- * proc_event *
- *===========================================================================*/
-PRIVATE int proc_event()
-{
-/* We got a notification from PM; see what it's about. Return TRUE if this
- * server has been told to shut down.
- */
- sigset_t set;
- int r;
-
- if ((r = getsigset(&set)) != OK) {
- printf("HGFS: unable to get pending signals from PM (%d)\n", r);
-
- return FALSE;
- }
-
- if (sigismember(&set, SIGTERM)) {
- if (state.mounted) {
- dprintf(("HGFS: got SIGTERM, still mounted\n"));
-
- return FALSE;
- }
-
- dprintf(("HGFS: got SIGTERM, shutting down\n"));
-
- return TRUE;
- }
-
- return FALSE;
-}
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fresh);
/* No live update support for now. */
/* Initialize the inet server. */
int r;
int timerand, fd;
- u32_t tasknr;
+ endpoint_t tasknr;
struct fssignon device;
u8_t randbits[32];
struct timeval tv;
+ char my_name[32];
#if DEBUG
printf("Starting inet...\n");
init_rand256(randbits);
/* Our new identity as a server. */
- r= ds_retrieve_label_num("inet", &tasknr);
+ r = sys_whoami(&tasknr, my_name, sizeof(my_name));
if (r != OK)
- ip_panic(("inet: ds_retrieve_label_num failed for 'inet': %d", r));
+ ip_panic(("inet: sys_whoami failed for 'inet': %d", r));
this_proc= tasknr;
/* Register the device group. */
}
if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)
{
+#if 0
printf("eth_rec: OEPF_NEED_CONF is set\n");
+#endif
}
if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
(loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT))
eth_port->etp_osdep.etp_port);
}
- if (eth_port->etp_osdep.etp_task == tasknr)
- {
- printf(
- "eth_restart: task number did not change. Aborting restart\n");
- return;
- }
eth_port->etp_osdep.etp_task= tasknr;
switch(eth_port->etp_osdep.etp_state)
-#define _SYSTEM 1
-#define _MINIX 1
+#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
+#define _MINIX 1 /* tell headers to include MINIX stuff */
+#define _SYSTEM 1 /* get OK and negative error codes */
#include <minix/callnr.h>
#include <minix/com.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
+#include <signal.h>
_PROTOTYPE( int do_shmget, (message *) );
_PROTOTYPE( int do_shmat, (message *) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
PUBLIC int main(int argc, char *argv[])
{
if (call_type & NOTIFY_MESSAGE) {
switch (who_e) {
- case PM_PROC_NR:
- /* PM sends a notify() on shutdown,
- * checkout if there are still IPC keys,
- * give warning messages.
- */
- if (!is_sem_nil() || !is_shm_nil())
- printf("IPC: exit with un-clean states.\n");
- break;
case VM_PROC_NR:
/* currently, only semaphore needs such information. */
sem_process_vm_notify();
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ /* Checkout if there are still IPC keys. Inform the user in that case. */
+ if (!is_sem_nil() || !is_shm_nil())
+ printf("IPC: exit with un-clean states.\n");
+}
+
printf("%-10s %12u\n", "U32", p->u.u32);
break;
case DSF_TYPE_STR:
- printf("%-10s %12s\n", "STR", p->u.string);
+ printf("%-10s %12s\n", "STR", (char*) p->u.mem.data);
break;
case DSF_TYPE_MEM:
printf("%-10s %12u\n", "MEM", p->u.mem.length);
getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc);
getuptime(&uptime);
- printf("-process- -nr- --ignore- --catch- --block- -tomess- -pending- -alarm---\n");
+ printf("-process- -nr- --ignore- --catch- --block- -pending- -alarm---\n");
for (i=prev_i; i<NR_PROCS; i++) {
mp = &mproc[i];
if (mp->mp_pid == 0 && i != PM_PROC_NR) continue;
if (++n > 22) break;
printf("%8.8s %3d ", mp->mp_name, i);
- printf(" %08x %08x %08x %08x ",
- mp->mp_ignore, mp->mp_catch, mp->mp_sigmask, mp->mp_sig2mess);
+ printf(" %08x %08x %08x ",
+ mp->mp_ignore, mp->mp_catch, mp->mp_sigmask);
printf("%08x ", mp->mp_sigpending);
if (mp->mp_flags & ALARM_ON) printf("%8u", mp->mp_timer.tmr_exp_time-uptime);
else printf(" -");
rpub->label, rpub->endpoint, rp->r_pid,
s_flags_str(rp->r_flags), rpub->dev_nr, rpub->dev_style,
rpub->period, rp->r_alive_tm, rp->r_restarts,
- rp->r_cmd
+ rp->r_args
);
printf("\n");
}
PRIVATE char *s_flags_str(int flags)
{
static char str[10];
- str[0] = (flags & RS_IN_USE) ? 'U' : '-';
+ str[0] = (flags & RS_ACTIVE) ? 'A' : '-';
str[1] = (flags & RS_INITIALIZING) ? 'I' : '-';
- str[2] = (flags & RS_UPDATING) ? 'u' : '-';
+ str[2] = (flags & RS_UPDATING) ? 'U' : '-';
str[3] = (flags & RS_EXITING) ? 'E' : '-';
str[4] = (flags & RS_NOPINGREPLY) ? 'N' : '-';
str[5] = '\0';
extern int errno; /* error number set by system library */
/* Declare some local functions. */
-FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void get_work, (void) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
/*===========================================================================*
* main *
if (is_notify(callnr)) {
switch (_ENDPOINT_P(who_e)) {
- case SYSTEM:
- printf("got message from SYSTEM\n");
- sigset = m_in.NOTIFY_ARG;
- for ( result=0; result< _NSIG; result++) {
- if (sigismember(&sigset, result))
- printf("signal %d found\n", result);
- }
- continue;
- case PM_PROC_NR:
- sig_handler();
- continue;
case TTY_PROC_NR:
result = do_fkey_pressed(&m_in);
break;
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
{
/* Initialize the information server. */
- struct sigaction sigact;
-
- /* Install signal handler. Ask PM to transform signal into message. */
- sigact.sa_handler = SIG_MESS;
- sigact.sa_mask = ~0; /* block all other signals */
- sigact.sa_flags = 0; /* default behaviour */
- if (sigaction(SIGTERM, &sigact, NULL) < 0)
- printf("IS: warning, sigaction() failed: %d\n", errno);
/* Set key mappings. */
map_unmap_fkeys(TRUE /*map*/);
}
/*===========================================================================*
- * sig_handler *
+ * sef_cb_signal_handler *
*===========================================================================*/
-PRIVATE void sig_handler()
+PRIVATE void sef_cb_signal_handler(int signo)
{
- sigset_t sigset;
-
- /* Try to obtain signal set from PM. */
- if (getsigset(&sigset) != 0) return;
-
- /* Only check for termination signal. */
- if (!sigismember(&sigset, SIGTERM)) return;
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
/* Shutting down. Unset key mappings, and quit. */
map_unmap_fkeys(FALSE /*map*/);
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
/*===========================================================================*
* main *
caller_uid = -1; /* To trap errors */
caller_gid = -1;
- /* Exit request? */
- if(src == PM_PROC_NR) {
- exitsignaled = 1;
- fs_sync();
- continue;
- }
-
/* This must be a regular VFS request. */
assert(src == VFS_PROC_NR && !unmountdone);
}
}
-
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ exitsignaled = 1;
+ fs_sync();
+}
/*===========================================================================*
* get_work *
panic("sef_receive failed: %d", r);
src = fs_m_in.m_source;
- if (src != FS_PROC_NR) {
- if(src == PM_PROC_NR) {
- if(is_notify(fs_m_in.m_type))
- srcok = 1; /* Normal exit request. */
- else
- printf("MFS: unexpected message from PM\n");
- } else
- printf("MFS: unexpected source %d\n", src);
- } else if(src == FS_PROC_NR) {
+ if(src == FS_PROC_NR) {
if(unmountdone)
printf("MFS: unmounted: unexpected message from FS\n");
else
printf("MFS: unexpected source %d\n", src);
} while(!srcok);
- assert((src == FS_PROC_NR && !unmountdone) ||
- (src == PM_PROC_NR && is_notify(fs_m_in.m_type)));
+ assert((src == FS_PROC_NR && !unmountdone));
}
#include "fs.h"
#include <assert.h>
+#include <signal.h>
#include <minix/dmap.h>
#include <minix/endpoint.h>
#include <minix/vfsif.h>
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
/*===========================================================================*
* main *
caller_uid = -1; /* To trap errors */
caller_gid = -1;
- if (src == PM_PROC_NR) continue; /* Exit signal */
assert(src == VFS_PROC_NR); /* Otherwise this must be VFS talking */
req_nr = fs_m_in.m_type;
if (req_nr < VFS_BASE) {
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ exitsignaled = 1;
+}
/*===========================================================================*
* get_work *
panic("sef_receive failed: %d", r);
src = fs_m_in.m_source;
- if (src != VFS_PROC_NR) {
- if(src == PM_PROC_NR) {
- if(is_notify(fs_m_in.m_type)) {
- exitsignaled = 1; /* Normal exit request. */
- srcok = 1;
- } else
- printf("PFS: unexpected message from PM\n");
- } else
- printf("PFS: unexpected source %d\n", src);
- } else if(src == VFS_PROC_NR) {
+ if(src == VFS_PROC_NR) {
srcok = 1; /* Normal FS request. */
} else
printf("PFS: unexpected source %d\n", src);
} while(!srcok);
- assert( src == VFS_PROC_NR ||
- (src == PM_PROC_NR && is_notify(fs_m_in.m_type))
- );
+ assert( src == VFS_PROC_NR );
}
{
if (rmp->mp_flags & PARTIAL_EXEC)
{
- /* Use SIGILL signal that something went wrong */
- rmp->mp_sigstatus = SIGILL;
- exit_proc(rmp, 0, FALSE /*dump_core*/);
+ /* Use SIGKILL to signal that something went wrong */
+ sys_kill(rmp->mp_endpoint, SIGKILL);
return;
}
setreply(rmp-mproc, result);
*
* The entry points into this file are:
* do_fork: perform the FORK system call
- * do_fork_nb: special nonblocking version of FORK, for RS
+ * do_srv_fork: special FORK, used by RS to create sys services
* do_exit: perform the EXIT system call (by calling exit_proc())
* exit_proc: actually do the exiting, and tell FS about it
* exit_restart: continue exiting a process after FS has replied
rmc->mp_trace_flags = 0;
sigemptyset(&rmc->mp_sigtrace);
}
- /* inherit only these flags */
- rmc->mp_flags &= (IN_USE|PRIV_PROC|DELAY_CALL);
+ /* Inherit only these flags. In normal fork(), PRIV_PROC is not inherited. */
+ rmc->mp_flags &= (IN_USE|DELAY_CALL);
rmc->mp_child_utime = 0; /* reset administration */
rmc->mp_child_stime = 0; /* reset administration */
rmc->mp_exitstatus = 0;
}
/*===========================================================================*
- * do_fork_nb *
+ * do_srv_fork *
*===========================================================================*/
-PUBLIC int do_fork_nb()
+PUBLIC int do_srv_fork()
{
/* The process pointed to by 'mp' has forked. Create a child process. */
register struct mproc *rmp; /* pointer to parent */
endpoint_t child_ep;
message m;
- /* Only system processes are allowed to use fork_nb */
- if (!(mp->mp_flags & PRIV_PROC))
+ /* Only RS is allowed to use srv_fork. */
+ if (mp->mp_endpoint != RS_PROC_NR)
return EPERM;
/* If tables might fill up during FORK, don't even start since recovery half
new_pid = get_free_pid();
rmc->mp_pid = new_pid; /* assign pid to child */
- m.m_type = PM_FORK_NB;
+ m.m_type = PM_SRV_FORK;
m.PM_PROC = rmc->mp_endpoint;
m.PM_PPROC = rmp->mp_endpoint;
m.PM_CPID = rmc->mp_pid;
*===========================================================================*/
PUBLIC int do_exit()
{
-/* Perform the exit(status) system call. The real work is done by exit_proc(),
- * which is also called when a process is killed by a signal.
- */
- exit_proc(mp, m_in.status, FALSE /*dump_core*/);
+ /* Perform the exit(status) system call. The real work is done by exit_proc(),
+ * which is also called when a process is killed by a signal. System processes
+ * do not use PM's exit() to terminate. If they try to, we warn the user
+ * and send a SIGKILL signal to the system process.
+ */
+ if(mp->mp_flags & PRIV_PROC) {
+ printf("PM: system process %d (%s) tries to exit(), sending SIGKILL\n",
+ mp->mp_endpoint, mp->mp_name);
+ sys_kill(mp->mp_endpoint, SIGKILL);
+ }
+ else {
+ exit_proc(mp, m_in.status, FALSE /*dump_core*/);
+ }
return(SUSPEND); /* can't communicate from beyond the grave */
}
panic("exit_proc: vm_willexit failed: %d", r);
}
vm_notify_sig_wrapper(rmp->mp_endpoint);
-
if (proc_nr_e == INIT_PROC_NR)
{
printf("PM: INIT died\n");
* needed because the system process might be a block device
* driver that FS is blocked waiting on.
*/
- if((r= sys_exit(rmp->mp_endpoint)) != OK)
- panic("exit_proc: sys_exit failed: %d", r);
+ if((r= sys_clear(rmp->mp_endpoint)) != OK)
+ panic("exit_proc: sys_clear failed: %d", r);
}
/* Clean up most of the flags describing the process's state before the exit,
if (!(rmp->mp_flags & PRIV_PROC))
{
/* destroy the (user) process */
- if((r=sys_exit(rmp->mp_endpoint)) != OK)
- panic("exit_restart: sys_exit failed: %d", r);
+ if((r=sys_clear(rmp->mp_endpoint)) != OK)
+ panic("exit_restart: sys_clear failed: %d", r);
}
/* Release the memory occupied by the child. */
procs_in_use--;
}
-PUBLIC void _exit(int code)
-{
- sys_exit(SELF);
-}
-
-PUBLIC void __exit(int code)
-{
- sys_exit(SELF);
-}
EXTERN unsigned long calls_stats[NCALLS];
#endif
+FORWARD _PROTOTYPE( void sendreply, (void) );
FORWARD _PROTOTYPE( void get_work, (void) );
FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
FORWARD _PROTOTYPE( void handle_fs_reply, (void) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( int sef_cb_signal_manager, (endpoint_t target, int signo) );
/*===========================================================================*
* main *
pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
result = SUSPEND; /* don't reply */
break;
- case SYSTEM: /* signals pending */
- sigset = m_in.NOTIFY_ARG;
- if (sigismember(&sigset, SIGKSIG)) {
- (void) ksig_pending();
- }
- result = SUSPEND; /* don't reply */
- break;
default :
result = ENOSYS;
}
/* done, send reply and continue */
- goto send_reply;
+ if (result != SUSPEND) setreply(who_p, result);
+ sendreply();
+ continue;
}
switch(call_nr)
case PM_EXIT_REPLY:
case PM_CORE_REPLY:
case PM_FORK_REPLY:
- case PM_FORK_NB_REPLY:
+ case PM_SRV_FORK_REPLY:
case PM_UNPAUSE_REPLY:
case PM_REBOOT_REPLY:
case PM_SETGROUPS_REPLY:
break;
}
-send_reply:
- /* Send the results back to the user to indicate completion. */
+ /* Send reply. */
if (result != SUSPEND) setreply(who_p, result);
-
- /* Send out all pending reply messages, including the answer to
- * the call just made above.
- */
- for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
- /* In the meantime, the process may have been killed by a
- * signal (e.g. if a lethal pending signal was unblocked)
- * without the PM realizing it. If the slot is no longer in
- * use or the process is exiting, don't try to reply.
- */
- if ((rmp->mp_flags & (REPLY | IN_USE | EXITING)) ==
- (REPLY | IN_USE)) {
- s=sendnb(rmp->mp_endpoint, &rmp->mp_reply);
- if (s != OK) {
- printf("PM can't reply to %d (%s): %d\n",
- rmp->mp_endpoint, rmp->mp_name, s);
- }
- rmp->mp_flags &= ~REPLY;
- }
- }
+ sendreply();
}
return(OK);
}
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_manager(sef_cb_signal_manager);
+
/* Let SEF perform startup. */
sef_startup();
}
SIGBUS, SIGSEGV };
register struct mproc *rmp;
register char *sig_ptr;
+ register int signo;
message mess;
/* Initialize process table, including timers. */
rmp = &mproc[ip->proc_nr];
strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN);
rmp->mp_nice = get_nice_value(ip->priority);
- sigemptyset(&rmp->mp_sig2mess);
sigemptyset(&rmp->mp_ignore);
sigemptyset(&rmp->mp_sigmask);
sigemptyset(&rmp->mp_catch);
rmp->mp_parent = RS_PROC_NR;
}
rmp->mp_pid = get_free_pid();
- rmp->mp_flags |= IN_USE | PRIV_PROC;
- for (sig_ptr = mess_sigs;
- sig_ptr < mess_sigs+sizeof(mess_sigs);
- sig_ptr++)
- sigaddset(&rmp->mp_sig2mess, *sig_ptr);
+ rmp->mp_flags |= IN_USE | PRIV_PROC;
}
/* Get kernel endpoint identifier. */
}
}
- /* Override some details for PM. */
- sigfillset(&mproc[PM_PROC_NR].mp_ignore); /* guard against signals */
-
/* Tell FS that no more system processes follow and synchronize. */
mess.PR_ENDPT = NONE;
if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK)
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_manager *
+ *===========================================================================*/
+PRIVATE int sef_cb_signal_manager(endpoint_t target, int signo)
+{
+/* Process signal on behalf of the kernel. */
+ int r;
+
+ r = process_ksig(target, signo);
+ sendreply();
+
+ return r;
+}
+
/*===========================================================================*
* get_work *
*===========================================================================*/
rmp->mp_flags |= REPLY; /* reply pending */
}
+/*===========================================================================*
+ * sendreply *
+ *===========================================================================*/
+PRIVATE void sendreply()
+{
+ int proc_nr;
+ int s;
+ struct mproc *rmp;
+
+ /* Send out all pending reply messages, including the answer to
+ * the call just made above.
+ */
+ for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
+ /* In the meantime, the process may have been killed by a
+ * signal (e.g. if a lethal pending signal was unblocked)
+ * without the PM realizing it. If the slot is no longer in
+ * use or the process is exiting, don't try to reply.
+ */
+ if ((rmp->mp_flags & (REPLY | IN_USE | EXITING)) ==
+ (REPLY | IN_USE)) {
+ s=sendnb(rmp->mp_endpoint, &rmp->mp_reply);
+ if (s != OK) {
+ printf("PM can't reply to %d (%s): %d\n",
+ rmp->mp_endpoint, rmp->mp_name, s);
+ }
+ rmp->mp_flags &= ~REPLY;
+ }
+ }
+}
+
/*===========================================================================*
* get_nice_value *
*===========================================================================*/
break;
- case PM_FORK_NB_REPLY:
+ case PM_SRV_FORK_REPLY:
/* Nothing to do */
break;
/* Signal handling information. */
sigset_t mp_ignore; /* 1 means ignore the signal, 0 means don't */
sigset_t mp_catch; /* 1 means catch the signal, 0 means don't */
- sigset_t mp_sig2mess; /* 1 means transform into notify message */
sigset_t mp_sigmask; /* signals to be blocked */
sigset_t mp_sigmask2; /* saved copy of mp_sigmask */
sigset_t mp_sigpending; /* pending signals to be handled */
/* forkexit.c */
_PROTOTYPE( int do_fork, (void) );
-_PROTOTYPE( int do_fork_nb, (void) );
+_PROTOTYPE( int do_srv_fork, (void) );
_PROTOTYPE( int do_exit, (void) );
_PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status,
int dump_core) );
/* signal.c */
_PROTOTYPE( int do_kill, (void) );
-_PROTOTYPE( int ksig_pending, (void) );
+_PROTOTYPE( int do_srv_kill, (void) );
+_PROTOTYPE( int process_ksig, (endpoint_t proc_nr_e, int signo) );
_PROTOTYPE( int do_pause, (void) );
_PROTOTYPE( int check_sig, (pid_t proc_id, int signo, int ksig) );
_PROTOTYPE( void sig_proc, (struct mproc *rmp, int signo, int trace,
* do_sigsuspend: perform the SIGSUSPEND system call
* do_kill: perform the KILL system call
* do_pause: perform the PAUSE system call
- * ksig_pending: the kernel notified about pending signals
+ * process_ksig: process a signal an behalf of the kernel
* sig_proc: interrupt or terminate a signaled process
* check_sig: check which processes to signal with sig_proc()
* check_pending: check if a pending signal can now be delivered
#include "param.h"
FORWARD _PROTOTYPE( void unpause, (struct mproc *rmp) );
-FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
FORWARD _PROTOTYPE( int sig_send, (struct mproc *rmp, int signo) );
+FORWARD _PROTOTYPE( void sig_proc_exit, (struct mproc *rmp, int signo) );
/*===========================================================================*
* do_sigaction *
if (m_in.sig_nr == SIGKILL) return(OK);
if (m_in.sig_nr < 1 || m_in.sig_nr >= _NSIG) return(EINVAL);
+
svp = &mp->mp_sigact[m_in.sig_nr];
if ((struct sigaction *) m_in.sig_osa != (struct sigaction *) NULL) {
r = sys_datacopy(PM_PROC_NR,(vir_bytes) svp,
sigaddset(&mp->mp_ignore, m_in.sig_nr);
sigdelset(&mp->mp_sigpending, m_in.sig_nr);
sigdelset(&mp->mp_catch, m_in.sig_nr);
- sigdelset(&mp->mp_sig2mess, m_in.sig_nr);
} else if (svec.sa_handler == SIG_DFL) {
sigdelset(&mp->mp_ignore, m_in.sig_nr);
sigdelset(&mp->mp_catch, m_in.sig_nr);
- sigdelset(&mp->mp_sig2mess, m_in.sig_nr);
- } else if (svec.sa_handler == SIG_MESS) {
- if (! (mp->mp_flags & PRIV_PROC)) return(EPERM);
- sigdelset(&mp->mp_ignore, m_in.sig_nr);
- sigaddset(&mp->mp_sig2mess, m_in.sig_nr);
- sigdelset(&mp->mp_catch, m_in.sig_nr);
} else {
sigdelset(&mp->mp_ignore, m_in.sig_nr);
sigaddset(&mp->mp_catch, m_in.sig_nr);
- sigdelset(&mp->mp_sig2mess, m_in.sig_nr);
}
mp->mp_sigact[m_in.sig_nr].sa_handler = svec.sa_handler;
sigdelset(&svec.sa_mask, SIGKILL);
}
/*===========================================================================*
- * ksig_pending *
+ * do_srv_kill *
*===========================================================================*/
-PUBLIC int ksig_pending()
+PUBLIC int do_srv_kill()
{
-/* Certain signals, such as segmentation violations originate in the kernel.
- * When the kernel detects such signals, it notifies the PM to take further
- * action. The PM requests the kernel to send messages with the process
- * slot and bit map for all signaled processes. The File System, for example,
- * uses this mechanism to signal writing on broken pipes (SIGPIPE).
- *
- * The kernel has notified the PM about pending signals. Request pending
- * signals until all signals are handled. If there are no more signals,
- * NONE is returned in the process number field.
- */
- endpoint_t proc_nr_e;
- sigset_t sig_map;
-
- while (TRUE) {
- int r;
- /* get an arbitrary pending signal */
- if((r=sys_getksig(&proc_nr_e, &sig_map)) != OK)
- panic("sys_getksig failed: %d", r);
- if (NONE == proc_nr_e) { /* stop if no more pending signals */
- break;
- } else {
- int proc_nr_p;
- if(pm_isokendpt(proc_nr_e, &proc_nr_p) != OK)
- panic("sys_getksig strange process: %d", proc_nr_e);
- handle_ksig(proc_nr_e, sig_map); /* handle the received signal */
- /* If the process still exists to the kernel after the signal
- * has been handled ...
- */
- if ((mproc[proc_nr_p].mp_flags & (IN_USE | EXITING)) == IN_USE)
- {
- if((r=sys_endksig(proc_nr_e)) != OK) /* ... tell kernel it's done */
- panic("sys_endksig failed: %d", r);
- }
- }
- }
- return(SUSPEND); /* prevents sending reply */
+/* Perform the srv_kill(pid, signo) system call. */
+
+ /* Only RS is allowed to use srv_kill. */
+ if (mp->mp_endpoint != RS_PROC_NR)
+ return EPERM;
+
+ /* Pretend the signal comes from the kernel when RS wants to deliver a signal
+ * to a system process. RS sends a SIGKILL when it wants to perform cleanup.
+ * In that case, ksig == TRUE forces PM to exit the process immediately.
+ */
+ return check_sig(m_in.pid, m_in.sig_nr, TRUE /* ksig */);
}
/*===========================================================================*
- * handle_ksig *
+ * process_ksig *
*===========================================================================*/
-PRIVATE void handle_ksig(proc_nr_e, sig_map)
+PUBLIC int process_ksig(proc_nr_e, signo)
int proc_nr_e;
-sigset_t sig_map;
+int signo;
{
register struct mproc *rmp;
- int i, proc_nr;
+ int proc_nr;
pid_t proc_id, id;
if(pm_isokendpt(proc_nr_e, &proc_nr) != OK || proc_nr < 0) {
- printf("PM: handle_ksig: %d?? not ok\n", proc_nr_e);
+ printf("PM: process_ksig: %d?? not ok\n", proc_nr_e);
return;
}
rmp = &mproc[proc_nr];
if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) {
#if 0
- printf("PM: handle_ksig: %d?? exiting / not in use\n", proc_nr_e);
+ printf("PM: process_ksig: %d?? exiting / not in use\n", proc_nr_e);
#endif
return;
}
mp = &mproc[0]; /* pretend signals are from PM */
mp->mp_procgrp = rmp->mp_procgrp; /* get process group right */
- /* Check each bit in turn to see if a signal is to be sent. Unlike
- * kill(), the kernel may collect several unrelated signals for a
- * process and pass them to PM in one blow. Thus loop on the bit
- * map. For SIGVTALRM and SIGPROF, see if we need to restart a
+ /* For SIGVTALRM and SIGPROF, see if we need to restart a
* virtual timer. For SIGINT, SIGWINCH and SIGQUIT, use proc_id 0
* to indicate a broadcast to the recipient's process group. For
* SIGKILL, use proc_id -1 to indicate a systemwide broadcast.
*/
- for (i = 1; i < _NSIG; i++) {
- if (!sigismember(&sig_map, i)) continue;
-#if 0
- printf("PM: sig %d for %d from kernel\n",
- i, proc_nr_e);
-#endif
- switch (i) {
- case SIGINT:
- case SIGQUIT:
- case SIGWINCH:
- id = 0; break; /* broadcast to process group */
- case SIGVTALRM:
- case SIGPROF:
- check_vtimer(proc_nr, i);
- /* fall-through */
- default:
- id = proc_id;
- break;
- }
- check_sig(id, i, TRUE /* ksig */);
+ switch (signo) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGWINCH:
+ id = 0; break; /* broadcast to process group */
+ case SIGVTALRM:
+ case SIGPROF:
+ check_vtimer(proc_nr, signo);
+ /* fall-through */
+ default:
+ id = proc_id;
+ break;
}
+ check_sig(id, signo, TRUE /* ksig */);
- /* If SIGNDELAY is set, an earlier sys_stop() failed because the process was
+ /* If SIGKNDELAY is set, an earlier sys_stop() failed because the process was
* still sending, and the kernel hereby tells us that the process is now done
* with that. We can now try to resume what we planned to do in the first
* place: set up a signal handler. However, the process's message may have
* been a call to PM, in which case the process may have changed any of its
* signal settings. The process may also have forked, exited etcetera.
*/
- if (sigismember(&sig_map, SIGNDELAY) && (rmp->mp_flags & DELAY_CALL)) {
+ if (signo == SIGKNDELAY && (rmp->mp_flags & DELAY_CALL)) {
rmp->mp_flags &= ~DELAY_CALL;
if (rmp->mp_flags & (FS_CALL | PM_SIG_PENDING))
- panic("handle_ksig: bad process state");
+ panic("process_ksig: bad process state");
/* Process as many normal signals as possible. */
check_pending(rmp);
if (rmp->mp_flags & DELAY_CALL)
- panic("handle_ksig: multiple delay calls?");
+ panic("process_ksig: multiple delay calls?");
+ }
+
+ /* See if the process is still alive */
+ if ((mproc[proc_nr].mp_flags & (IN_USE | EXITING)) == IN_USE) {
+ return OK; /* signal has been delivered */
+ }
+ else {
+ return EDEADSRCDST; /* process is gone */
}
}
return;
}
- /* some signals cannot be safely ignored */
+ /* Handle system signals for system processes first. */
+ if(rmp->mp_flags & PRIV_PROC) {
+ /* System signals have always to go through the kernel first to let it
+ * pick the right signal manager. If PM is the assigned signal manager,
+ * the signal will come back and will actually be processed.
+ */
+ if(!ksig) {
+ sys_kill(rmp->mp_endpoint, signo);
+ return;
+ }
+ if(!SIGS_IS_TERMINATION(signo)) {
+ /* Translate every non-termination sys signal into a message. */
+ message m;
+ m.m_type = SIGS_SIGNAL_RECEIVED;
+ m.SIGS_SIG_NUM = signo;
+ asynsend3(rmp->mp_endpoint, &m, AMF_NOREPLY);
+ }
+ else {
+ /* Exit the process in case of termination system signal. */
+ sig_proc_exit(rmp, signo);
+ }
+ return;
+ }
+
+ /* Handle user processes now. See if the signal cannot be safely ignored. */
badignore = ksig && sigismember(&noign_sset, signo) && (
sigismember(&rmp->mp_ignore, signo) ||
- sigismember(&rmp->mp_sigmask, signo) ||
- sigismember(&rmp->mp_sig2mess, signo));
+ sigismember(&rmp->mp_sigmask, signo));
if (!badignore && sigismember(&rmp->mp_ignore, signo)) {
/* Signal should be ignored. */
sigaddset(&rmp->mp_sigpending, signo);
return;
}
- if (!badignore && sigismember(&rmp->mp_sig2mess, signo)) {
- /* Mark event pending in process slot and send notification. */
- sigaddset(&rmp->mp_sigpending, signo);
- notify(rmp->mp_endpoint);
- return;
- }
if ((rmp->mp_flags & STOPPED) && signo != SIGKILL) {
/* If the process is stopped for a debugger, do not deliver any signals
sigaddset(&rmp->mp_sigpending, signo);
return;
}
-
if (!badignore && sigismember(&rmp->mp_catch, signo)) {
/* Signal is caught. First interrupt the process's current call, if
* applicable. This may involve a roundtrip to FS, in which case we'll
}
/* Terminate process */
+ sig_proc_exit(rmp, signo);
+}
+
+/*===========================================================================*
+ * sig_proc_exit *
+ *===========================================================================*/
+PRIVATE void sig_proc_exit(rmp, signo)
+struct mproc *rmp; /* process that must exit */
+int signo; /* signal that caused termination */
+{
rmp->mp_sigstatus = (char) signo;
if (sigismember(&core_sset, signo)) {
printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid,
/* Return EINVAL for attempts to send SIGKILL to INIT alone. */
if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL);
- /* Search the proc table for processes to signal.
+ /* Signal RS first when broadcasting SIGTERM. */
+ if (proc_id == -1 && signo == SIGTERM)
+ sys_kill(RS_PROC_NR, signo);
+
+ /* Search the proc table for processes to signal. Start from the end of the
+ * table to analyze core system processes at the end when broadcasting.
* (See forkexit.c about pid magic.)
*/
count = 0;
error_code = ESRCH;
- for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
+ for (rmp = &mproc[NR_PROCS-1]; rmp >= &mproc[0]; rmp--) {
if (!(rmp->mp_flags & IN_USE)) continue;
/* Check for selection. */
if (proc_id == -1 && signo == SIGKILL &&
(rmp->mp_flags & PRIV_PROC)) continue;
+ /* Disallow lethal signals sent by user processes to sys processes. */
+ if (!ksig && SIGS_IS_LETHAL(signo) && (rmp->mp_flags & PRIV_PROC)) {
+ error_code = EPERM;
+ continue;
+ }
+
/* Check for permission. */
if (mp->mp_effuid != SUPER_USER
&& mp->mp_realuid != rmp->mp_realuid
r = sys_delay_stop(rmp->mp_endpoint);
/* If the process is still busy sending a message, the kernel will give
- * us EBUSY now and send a SIGNDELAY to the process as soon as sending
+ * us EBUSY now and send a SIGKNDELAY to the process as soon as sending
* is done.
*/
if (r == EBUSY) {
do_cprofile, /* 99 = cprofile */
/* THE MINIX3 ABI ENDS HERE */
do_exec_newmem, /* 100 = exec_newmem */
- do_fork_nb, /* 101 = forknb */
+ do_srv_fork, /* 101 = srv_fork */
do_execrestart, /* 102 = exec_restart */
do_procstat, /* 103 = procstat */
do_getprocnr, /* 104 = getprocnr */
do_adddma, /* 108 = adddma */
do_deldma, /* 109 = deldma */
do_getdma, /* 110 = getdma */
+ do_srv_kill, /* 111 = srv_kill */
};
/* This should not fail with "array size is negative": */
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
LIBS = -lsys
UTIL_OBJ = service.o
-OBJ = exec.o main.o manager.o table.o utility.o memory.o
+OBJ = exec.o main.o request.o manager.o table.o utility.o memory.o error.o
# build local binary
all build: $(SERVER) $(UTIL)
$(CC) -o $@ $(LDFLAGS) $(UTIL_OBJ) $(UTIL_LIBS)
$(SERVER): $(OBJ)
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
- install -S 450k $@
+ install -S 850k $@
# install with other servers
install: /bin/$(UTIL) /usr/sbin/$(SERVER)
#ifndef RS_CONST_H
#define RS_CONST_H
+#define DEBUG_DEFAULT 0
+
+#ifndef DEBUG
+#define DEBUG DEBUG_DEFAULT
+#endif
+
/* Space reserved for program and arguments. */
#define MAX_COMMAND_LEN 512 /* maximum argument string length */
#define MAX_SCRIPT_LEN 256 /* maximum restart script name length */
/* Flag values. */
#define RS_IN_USE 0x001 /* set when process slot is in use */
-#define RS_EXITING 0x004 /* set when exit is expected */
-#define RS_REFRESHING 0x008 /* set when refresh must be done */
-#define RS_NOPINGREPLY 0x010 /* service failed to reply to a ping request */
-#define RS_KILLED 0x020 /* service is killed */
-#define RS_CRASHED 0x040 /* service crashed */
-#define RS_LATEREPLY 0x080 /* no reply sent to RS_DOWN caller yet */
-#define RS_SIGNALED 0x100 /* service crashed */
-#define RS_INITIALIZING 0x200 /* set when init is in progress */
-#define RS_UPDATING 0x400 /* set when update is in progress */
+#define RS_EXITING 0x002 /* set when exit is expected */
+#define RS_REFRESHING 0x004 /* set when refresh must be done */
+#define RS_NOPINGREPLY 0x008 /* service failed to reply to a ping request */
+#define RS_TERMINATED 0x010 /* service has terminated */
+#define RS_LATEREPLY 0x020 /* no reply sent to RS_DOWN caller yet */
+#define RS_INITIALIZING 0x040 /* set when init is in progress */
+#define RS_UPDATING 0x080 /* set when update is in progress */
+#define RS_ACTIVE 0x100 /* set for the active instance of a service */
/* Sys flag values. */
-#define SF_CORE_SRV 0x001 /* set for core system services
- * XXX FIXME: This should trigger a system
- * panic when a CORE_SRV service cannot
- * be restarted. We need better error-handling
- * in RS to change this.
- */
+#define SF_CORE_SRV 0x001 /* set for core system services */
#define SF_SYNCH_BOOT 0X002 /* set when process needs synch boot init */
#define SF_NEED_COPY 0x004 /* set when process needs copy to restart */
#define SF_USE_COPY 0x008 /* set when process has a copy in memory */
( spi_to(PM_PROC_NR) | spi_to(FS_PROC_NR) | spi_to(RS_PROC_NR) \
| spi_to(VM_PROC_NR) ) /* root user proc */
+/* Define the signal manager for the various process types. */
+#define SRV_SM RS_PROC_NR /* system services */
+#define DSRV_SM RS_PROC_NR /* dynamic system services */
+#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 SRVC_SF (SRV_SF | SF_USE_COPY) /* system services with a copy */
--- /dev/null
+/*
+ * Changes:
+ * Mar 07, 2010: Created (Cristiano Giuffrida)
+ */
+
+#include "inc.h"
+
+/* A single error entry. */
+struct errentry {
+ int errnum;
+ char* errstr;
+};
+
+/* Initialization errors. */
+PRIVATE struct errentry init_errlist[] = {
+ { ENOSYS, "service does not support the requested initialization type" }
+};
+PRIVATE const int init_nerr = sizeof(init_errlist) / sizeof(init_errlist[0]);
+
+/* Live update errors. */
+PRIVATE struct errentry lu_errlist[] = {
+ { ENOSYS, "service does not support live update" },
+ { EINVAL, "service does not support the required state" },
+ { EBUSY, "service is not able to prepare for the update now" },
+ { EGENERIC, "generic error occurred while preparing for the update" }
+};
+PRIVATE const int lu_nerr = sizeof(lu_errlist) / sizeof(lu_errlist[0]);
+
+/*===========================================================================*
+ * rs_strerror *
+ *===========================================================================*/
+PRIVATE char * rs_strerror(int errnum, struct errentry *errlist, const int nerr)
+{
+ int i;
+
+ for(i=0; i < nerr; i++) {
+ if(errnum == errlist[i].errnum)
+ return errlist[i].errstr;
+ }
+
+ return strerror(-errnum);
+}
+
+/*===========================================================================*
+ * init_strerror *
+ *===========================================================================*/
+PUBLIC char * init_strerror(int errnum)
+{
+ return rs_strerror(errnum, init_errlist, init_nerr);
+}
+
+/*===========================================================================*
+ * lu_strerror *
+ *===========================================================================*/
+PUBLIC char * lu_strerror(int errnum)
+{
+ return rs_strerror(errnum, lu_errlist, lu_nerr);
+}
FORWARD _PROTOTYPE( int read_seg, (char *exec, size_t exec_len, off_t off,
int proc_e, int seg, phys_bytes seg_bytes) );
-int dev_execve(int proc_e, char *exec, size_t exec_len, char **argv,
+int srv_execve(int proc_e, char *exec, size_t exec_len, char **argv,
char **Xenvp)
{
char * const *ap;
argc++;
}
-#if 0
-printf("here: %s, %d\n", __FILE__, __LINE__);
- for (ep= envp; *ep != NULL; ep++) {
- n = sizeof(*ep) + strlen(*ep) + 1;
- frame_size+= n;
- if (frame_size < n) ov= 1;
- string_off+= sizeof(*ap);
- }
-#endif
-
/* Add an argument count and two terminating nulls. */
frame_size+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
string_off+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
if (r != OK)
{
printf("do_exec: read_header failed\n");
+ error= r;
goto fail;
}
need_restart= 1;
/* The system process table. This table only has entries for system
* services (servers and drivers), and thus is not directly indexed by
- * slot number.
+ * slot number. The size of the table must match the size of the privilege
+ * table in the kernel.
*/
EXTERN struct rprocpub rprocpub[NR_SYS_PROCS]; /* public entries */
EXTERN struct rproc rproc[NR_SYS_PROCS];
EXTERN struct rproc *rproc_ptr[NR_PROCS]; /* mapping for fast access */
-/* Pipe for detection of exec failures. The pipe is close-on-exec, and
- * no data will be written to the pipe if the exec succeeds. After an
- * exec failure, the slot number is written to the pipe. After each exit,
- * a non-blocking read retrieves the slot number from the pipe.
- */
-EXTERN int exec_pipe[2];
-
/* Global init descriptor. This descriptor holds data to initialize system
* services.
*/
/* Enable/disable verbose output. */
EXTERN long rs_verbose;
+/* Set when we are shutting down. */
+EXTERN int shutting_down;
+
#endif /* RS_GLO_H */
#include <ansi.h>
#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ptrace.h>
#include <limits.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <lib.h>
#include <minix/callnr.h>
#include <minix/config.h>
#include <minix/rs.h>
#include <minix/dmap.h>
#include <minix/endpoint.h>
+#include <minix/vm.h>
+#include <minix/ds.h>
+#include <minix/minlib.h>
#include <machine/archtypes.h>
#include <timers.h> /* For priv.h */
#include "../../kernel/type.h"
#include "../../kernel/proc.h"
#include "../pm/mproc.h"
-#include "../pm/const.h"
/* Declare some local functions. */
FORWARD _PROTOTYPE(void exec_image_copy, ( int boot_proc_idx,
struct boot_image **ip, struct boot_image_priv **pp,
struct boot_image_sys **sp, struct boot_image_dev **dp) );
FORWARD _PROTOTYPE(void catch_boot_init_ready, (endpoint_t endpoint) );
-FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void get_work, (message *m) );
-FORWARD _PROTOTYPE(void reply, (int whom, message *m_out) );
/* The buffer where the boot image is copied during initialization. */
PRIVATE int boot_image_buffer_size;
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
+FORWARD _PROTOTYPE( int sef_cb_signal_manager, (endpoint_t target, int signo) );
/*===========================================================================*
* main *
/* Wait for request message. */
get_work(&m);
who_e = m.m_source;
- who_p = _ENDPOINT_P(who_e);
- if(who_p < -NR_TASKS || who_p >= NR_PROCS)
- panic("message from bogus source: %d", who_e);
+ if(rs_isokendpt(who_e, &who_p) != OK) {
+ panic("message from bogus source: %d", who_e);
+ }
call_nr = m.m_type;
/* Now determine what to do. Four types of requests are expected:
* - Heartbeat messages (notifications from registered system services)
- * - System notifications (POSIX signals or synchronous alarm)
+ * - System notifications (synchronous alarm)
* - User requests (control messages to manage system services)
* - Ready messages (reply messages from registered services)
*/
case CLOCK:
do_period(&m); /* check services status */
continue;
- case PM_PROC_NR: /* signal or PM heartbeat */
- sig_handler();
default: /* heartbeat notification */
if (rproc_ptr[who_p] != NULL) { /* mark heartbeat time */
rproc_ptr[who_p]->r_alive_tm = m.NOTIFY_TIMESTAMP;
} else {
- printf("Warning, RS got unexpected notify message from %d\n",
+ printf("RS: warning: got unexpected notify message from %d\n",
m.m_source);
}
}
(call_nr < RS_RQ_BASE || call_nr >= RS_RQ_BASE+0x100))
{
/* Ignore invalid requests. Do not try to reply. */
- printf("RS: got invalid request %d from endpoint %d\n",
+ printf("RS: warning: got invalid request %d from endpoint %d\n",
call_nr, m.m_source);
continue;
}
case RS_INIT: result = do_init_ready(&m); break;
case RS_LU_PREPARE: result = do_upd_ready(&m); break;
default:
- printf("Warning, RS got unexpected request %d from %d\n",
+ printf("RS: warning: got unexpected request %d from %d\n",
m.m_type, m.m_source);
result = EINVAL;
}
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh); /* RS can only start fresh. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+ sef_setcb_signal_manager(sef_cb_signal_manager);
+
/* Let SEF perform startup. */
sef_startup();
}
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
{
/* Initialize the reincarnation server. */
- struct sigaction sa;
struct boot_image *ip;
int s,i,j;
int nr_image_srvs, nr_image_priv_srvs, nr_uncaught_init_srvs;
panic("unable to create rprocpub table grant: %d", rinit.rproctab_gid);
}
- /* Initialize the global update descriptor. */
+ /* Initialize some global variables. */
rupdate.flags = 0;
+ shutting_down = FALSE;
/* Get a copy of the boot image table. */
if ((s = sys_getimage(image)) != OK) {
rp->r_priv.s_id = static_priv_id(
_ENDPOINT_P(boot_image_priv->endpoint));
- /* Initialize privilege bitmaps. */
+ /* Initialize privilege bitmaps and signal manager. */
rp->r_priv.s_flags = boot_image_priv->flags; /* priv flags */
rp->r_priv.s_trap_mask = boot_image_priv->trap_mask; /* traps */
memcpy(&rp->r_priv.s_ipc_to, &boot_image_priv->ipc_to,
sizeof(rp->r_priv.s_ipc_to)); /* targets */
+ rp->r_priv.s_sig_mgr = boot_image_priv->sig_mgr; /* sig mgr */
/* Initialize kernel call mask bitmap from unordered set. */
fill_call_mask(boot_image_priv->k_calls, NR_SYS_CALLS,
/* Get command settings. */
rp->r_cmd[0]= '\0';
- rp->r_argv[0] = rp->r_cmd;
- rp->r_argv[1] = NULL;
- rp->r_argc = 1;
rp->r_script[0]= '\0';
+ build_cmd_dep(rp);
/* Initialize vm call mask bitmap from unordered set. */
fill_call_mask(boot_image_priv->vm_calls, NR_VM_CALLS,
rpub->endpoint = ip->endpoint;
/* Set some defaults. */
+ 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_uid = 0; /* root */
rp->r_check_tm = 0; /* not checked yet */
getuptime(&rp->r_alive_tm); /* currently alive */
rp->r_restarts = 0; /* no restarts so far */
rp->r_set_resources = 0; /* don't set resources */
- /* Mark as in use. */
- rp->r_flags = RS_IN_USE;
+ /* Mark as in use and active. */
+ rp->r_flags = RS_IN_USE | RS_ACTIVE;
rproc_ptr[_ENDPOINT_P(rpub->endpoint)]= rp;
rpub->in_use = TRUE;
}
/* - Step 4: all the system services in the boot image are now running.
* Complete the initialization of the system process table in collaboration
- * with other system processes.
+ * with other system services.
*/
if ((s = getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc)) != OK) {
panic("unable to get copy of PM process table: %d", s);
rpub = rp->r_pub;
/* Get pid from PM process table. */
- rp->r_pid = NO_PID;
+ rp->r_pid = -1;
for (j = 0; j < NR_PROCS; j++) {
if (mproc[j].mp_endpoint == rpub->endpoint) {
rp->r_pid = mproc[j].mp_pid;
if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
panic("couldn't set alarm: %d", s);
- /* Install signal handlers. Ask PM to transform signal into message. */
- sa.sa_handler = SIG_MESS;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGCHLD,&sa,NULL)<0) panic("sigaction failed: %d", errno);
- if (sigaction(SIGTERM,&sa,NULL)<0) panic("sigaction failed: %d", errno);
-
- /* Initialize the exec pipe. */
- if (pipe(exec_pipe) == -1)
- panic("pipe failed: %d", errno);
- if (fcntl(exec_pipe[0], F_SETFD,
- fcntl(exec_pipe[0], F_GETFD) | FD_CLOEXEC) == -1)
- {
- panic("fcntl set FD_CLOEXEC on pipe input failed: %d", errno);
- }
- if (fcntl(exec_pipe[1], F_SETFD,
- fcntl(exec_pipe[1], F_GETFD) | FD_CLOEXEC) == -1)
- {
- panic("fcntl set FD_CLOEXEC on pipe output failed: %d", errno);
- }
- if (fcntl(exec_pipe[0], F_SETFL,
- fcntl(exec_pipe[0], F_GETFL) | O_NONBLOCK) == -1)
- {
- panic("fcntl set O_NONBLOCK on pipe input failed: %d", errno);
- }
-
/* Map out our own text and data. This is normally done in crtso.o
* but RS is an exception - we don't get to talk to VM so early on.
* That's why we override munmap() and munmap_text() in utility.c.
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ int exit_status;
+
+ /* Check for known signals, ignore anything else. */
+ switch(signo) {
+ case SIGCHLD:
+ do_sigchld();
+ break;
+ case SIGTERM:
+ do_shutdown(NULL);
+ break;
+ }
+}
+
+/*===========================================================================*
+ * sef_cb_signal_manager *
+ *===========================================================================*/
+PRIVATE int sef_cb_signal_manager(endpoint_t target, int signo)
+{
+/* Process system signal on behalf of the kernel. */
+ int target_p;
+ struct rproc *rp;
+ struct rprocpub *rpub;
+ message m;
+
+ /* Lookup slot. */
+ if(rs_isokendpt(target, &target_p) != OK || rproc_ptr[target_p] == NULL) {
+ if(rs_verbose)
+ printf("RS: ignoring spurious signal %d for process %d\n",
+ signo, target);
+ return;
+ }
+ rp = rproc_ptr[target_p];
+ rpub = rp->r_pub;
+
+ /* Don't bother if a termination signal has already been processed. */
+ if( rp->r_flags & (RS_TERMINATED|RS_EXITING) == RS_TERMINATED ) {
+ return EDEADSRCDST; /* process is gone */
+ }
+
+ if(rs_verbose)
+ printf("RS: %s got %s signal %d\n", srv_to_string(rp),
+ SIGS_IS_TERMINATION(signo) ? "termination" : "non-termination",signo);
+
+ /* In case of termination signal handle the event. */
+ if(SIGS_IS_TERMINATION(signo)) {
+ rp->r_flags |= RS_TERMINATED;
+ terminate_service(rp);
+
+ return EDEADSRCDST; /* process is now gone */
+ }
+
+ /* Translate every non-termination signal into a message. */
+ m.m_type = SIGS_SIGNAL_RECEIVED;
+ m.SIGS_SIG_NUM = signo;
+ asynsend3(rpub->endpoint, &m, AMF_NOREPLY);
+
+ return OK; /* signal has been delivered */
+}
+
/*===========================================================================*
* exec_image_copy *
*===========================================================================*/
panic("unable to complete init for service: %d", m.m_source);
}
+ /* Send a reply to unblock the service. */
+ m.m_type = OK;
+ reply(m.m_source, &m);
+
/* Mark the slot as no longer initializing. */
rp->r_flags &= ~RS_INITIALIZING;
rp->r_check_tm = 0;
getuptime(&rp->r_alive_tm);
}
-/*===========================================================================*
- * sig_handler *
- *===========================================================================*/
-PRIVATE void sig_handler()
-{
- sigset_t sigset;
- int sig;
-
- /* Try to obtain signal set from PM. */
- if (getsigset(&sigset) != 0) return;
-
- /* Check for known signals. */
- if (sigismember(&sigset, SIGCHLD)) do_exit(NULL);
- if (sigismember(&sigset, SIGTERM)) do_shutdown(NULL);
-}
-
/*===========================================================================*
* get_work *
*===========================================================================*/
panic("sef_receive failed: %d", s);
}
-/*===========================================================================*
- * reply *
- *===========================================================================*/
-PRIVATE void reply(who, m_out)
-int who; /* replyee */
-message *m_out; /* reply message */
-{
- int s; /* send status */
-
- s = sendnb(who, m_out); /* send the message */
- if (s != OK)
- printf("RS: unable to send reply to %d: %d\n", who, s);
-}
-
*/
#include "inc.h"
-#include <ctype.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/vm.h>
-#include <minix/vm.h>
-#include <lib.h>
-
-#include <minix/sysutil.h>
-
-/* Prototypes for internal functions that do the hard work. */
-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) );
-FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags,
- endpoint_t *ep) );
-FORWARD _PROTOTYPE( void stop_service, (struct rproc *rp,int how) );
-FORWARD _PROTOTYPE( int fork_nb, (void) );
-FORWARD _PROTOTYPE( int read_exec, (struct rproc *rp) );
-FORWARD _PROTOTYPE( int share_exec, (struct rproc *rp_src,
- struct rproc *rp_dst) );
-FORWARD _PROTOTYPE( void free_slot, (struct rproc *rp) );
-FORWARD _PROTOTYPE( void run_script, (struct rproc *rp) );
-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) );
-FORWARD _PROTOTYPE( void init_privs, (struct rproc *rp, struct priv *privp) );
-FORWARD _PROTOTYPE( void init_pci, (struct rproc *rp, int endpoint) );
-FORWARD _PROTOTYPE( void update_period, (message *m_ptr) );
-FORWARD _PROTOTYPE( void end_update, (clock_t now) );
-
-PRIVATE int shutting_down = FALSE;
/*===========================================================================*
* caller_is_root *
*===========================================================================*/
-PRIVATE int caller_is_root(endpoint)
+PUBLIC int caller_is_root(endpoint)
endpoint_t endpoint; /* caller endpoint */
{
uid_t euid;
/*===========================================================================*
* caller_can_control *
*===========================================================================*/
-PRIVATE int caller_can_control(endpoint, label)
+PUBLIC int caller_can_control(endpoint, label)
endpoint_t endpoint;
char *label;
{
char *progname;
/* Find name of binary for given label. */
- for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if (strcmp(rpub->label, label) == 0) {
- break;
- }
- }
- if (rp == END_RPROC_ADDR) return 0;
+ rp = lookup_slot_by_label(label);
+ if (!rp) return 0;
progname = strrchr(rp->r_argv[0], '/');
if (progname != NULL)
progname++;
}
}
- if (rs_verbose) {
+ if (rs_verbose)
printf("RS: allowing %u control over %s via policy: %s\n",
endpoint, label, control_allowed ? "yes" : "no");
- }
+
return control_allowed;
}
+/*===========================================================================*
+ * check_call_permission *
+ *===========================================================================*/
+PUBLIC int check_call_permission(caller, call, rp)
+endpoint_t caller;
+int call;
+struct rproc *rp;
+{
+/* Check if the caller has permission to execute a particular call. */
+ struct rprocpub *rpub;
+ int call_allowed;
+
+ /* Caller should be either root or have control privileges. */
+ call_allowed = caller_is_root(caller);
+ if(rp) {
+ call_allowed |= caller_can_control(caller, rp->r_pub->label);
+ }
+ if(!call_allowed) {
+ return EPERM;
+ }
+
+ 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) {
+ 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;
+ }
+
+ /* Only allow RS_DOWN and RS_RESTART if the service has terminated. */
+ if(rp->r_flags & RS_TERMINATED) {
+ if(call != RS_DOWN && call != RS_RESTART) return EPERM;
+ }
+
+ /* Disallow RS_DOWN for core system services. */
+ if (rpub->sys_flags & SF_CORE_SRV) {
+ if(call == RS_DOWN) return EPERM;
+ }
+ }
+
+ return OK;
+}
+
+/*===========================================================================*
+ * copy_rs_start *
+ *===========================================================================*/
+PUBLIC int copy_rs_start(src_e, src_rs_start, dst_rs_start)
+endpoint_t src_e;
+char *src_rs_start;
+struct rs_start *dst_rs_start;
+{
+ int r;
+
+ r = sys_datacopy(src_e, (vir_bytes) src_rs_start,
+ SELF, (vir_bytes) dst_rs_start, sizeof(struct rs_start));
+
+ return r;
+}
+
/*===========================================================================*
* copy_label *
*===========================================================================*/
-PRIVATE int copy_label(src_e, src_label, dst_label, dst_len)
+PUBLIC int copy_label(src_e, src_label, src_len, dst_label, dst_len)
endpoint_t src_e;
-struct rss_label *src_label;
+char *src_label;
+size_t src_len;
char *dst_label;
size_t dst_len;
{
int s, len;
- len = MIN(dst_len-1, src_label->l_len);
+ len = MIN(dst_len-1, src_len);
- s = sys_datacopy(src_e, (vir_bytes) src_label->l_addr,
+ s = sys_datacopy(src_e, (vir_bytes) src_label,
SELF, (vir_bytes) dst_label, len);
if (s != OK) return s;
}
/*===========================================================================*
- * do_up *
+ * build_cmd_dep *
*===========================================================================*/
-PUBLIC int do_up(m_ptr)
-message *m_ptr; /* request message pointer */
+PUBLIC void build_cmd_dep(struct rproc *rp)
{
-/* A request was made to start a new system service.
- */
- register struct rproc *rp; /* system process table */
- register struct rprocpub *rpub; /* public entry */
- 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;
- int r;
- endpoint_t ep;
- struct rproc *tmp_rp;
- struct rprocpub *tmp_rpub;
- struct rs_start rs_start;
-
- /* This call requires special privileges. */
- if (!caller_is_root(m_ptr->m_source)) return(EPERM);
+ struct rprocpub *rpub;
+ int arg_count;
+ int len;
+ char *cmd_ptr;
- /* 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 */
- if (!(rp->r_flags & RS_IN_USE)) /* check if available */
- break;
- }
- if (slot_nr >= NR_SYS_PROCS)
- {
- printf("RS: do_up: system process table full\n");
- return ENOMEM;
- }
rpub = rp->r_pub;
- /* 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);
-
- /* 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.
*/
+ strcpy(rp->r_args, rp->r_cmd); /* copy raw command */
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 */
+ rp->r_argv[arg_count++] = rp->r_args; /* start with path */
+ cmd_ptr = rp->r_args; /* do some parsing */
while(*cmd_ptr != '\0') { /* stop at end of string */
if (*cmd_ptr == ' ') { /* next argument */
*cmd_ptr = '\0'; /* terminate previous */
rp->r_argv[arg_count] = NULL; /* end with NULL pointer */
rp->r_argc = arg_count;
- /* Process name for the service. */
+ /* Build process name. */
cmd_ptr = strrchr(rp->r_argv[0], '/');
if (cmd_ptr)
cmd_ptr++;
len= RS_MAX_LABEL_LEN-1; /* truncate name */
memcpy(rpub->proc_name, cmd_ptr, len);
rpub->proc_name[len]= '\0';
- if(rs_verbose)
- printf("RS: do_up: using proc_name (from binary %s) '%s'\n",
- rp->r_argv[0], rpub->proc_name);
-
- if(rs_start.rss_label.l_len > 0) {
- /* RS_UP caller has supplied a custom label for this service. */
- int s = copy_label(m_ptr->m_source, &rs_start.rss_label,
- rpub->label, sizeof(rpub->label));
- if(s != OK)
- return s;
- if(rs_verbose)
- printf("RS: do_up: 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: do_up: 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: do_up: too many control labels\n");
- 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) {
- printf("RS: do_up: control labels:");
- for (i=0; i<rp->r_nr_control; i++)
- printf(" %s", rp->r_control[i]);
- printf("\n");
- }
- }
+/*===========================================================================*
+ * srv_fork *
+ *===========================================================================*/
+PUBLIC pid_t srv_fork()
+{
+ message m;
- /* 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 */
- tmp_rpub = tmp_rp->r_pub;
- if (strcmp(tmp_rpub->label, rpub->label) == 0)
- {
- printf("RS: found duplicate label '%s': slot %d\n",
- rpub->label, slot_nr);
- return EBUSY;
- }
- }
+ return(_syscall(PM_PROC_NR, SRV_FORK, &m));
+}
- 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;
+/*===========================================================================*
+ * srv_kill *
+ *===========================================================================*/
+PUBLIC int srv_kill(pid_t pid, int sig)
+{
+ message m;
- 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(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';
+ m.m1_i1 = pid;
+ m.m1_i2 = sig;
+ return(_syscall(PM_PROC_NR, SRV_KILL, &m));
+}
- rpub->sys_flags = DSRV_SF;
- rp->r_exec= NULL;
- if (rs_start.rss_flags & RSS_COPY) {
- int exst_cpy;
- struct rproc *rp2;
- struct rprocpub *rpub2;
- exst_cpy = 0;
-
- if(rs_start.rss_flags & RSS_REUSE) {
- int i;
+/*===========================================================================*
+ * update_period *
+ *===========================================================================*/
+PUBLIC void update_period(message *m_ptr)
+{
+ clock_t now = m_ptr->NOTIFY_TIMESTAMP;
+ short has_update_timed_out;
+ message m;
+ struct rprocpub *rpub;
- for(i = 0; i < NR_SYS_PROCS; i++) {
- rp2 = &rproc[i];
- rpub2 = rproc[i].r_pub;
- if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 &&
- (rpub2->sys_flags & SF_USE_COPY)) {
- /* We have found the same binary that's
- * already been copied */
- exst_cpy = 1;
- break;
- }
- }
- }
+ rpub = rupdate.rp->r_pub;
- if(!exst_cpy)
- s = read_exec(rp);
- else
- s = share_exec(rp, rp2);
+ /* See if a timeout has occurred. */
+ has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime);
- if (s != OK)
- return s;
+ /* If an update timed out, end the update process and notify
+ * the old version that the update has been canceled. From now on, the old
+ * version will continue executing.
+ */
+ if(has_update_timed_out) {
+ printf("RS: update failed: maximum prepare time reached\n");
+ end_update(EINTR);
- rpub->sys_flags |= SF_USE_COPY;
+ /* Prepare cancel request. */
+ m.m_type = RS_LU_PREPARE;
+ m.RS_LU_STATE = SEF_LU_STATE_NULL;
+ asynsend(rpub->endpoint, &m);
}
+}
- /* 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 */
+/*===========================================================================*
+ * end_update *
+ *===========================================================================*/
+PUBLIC void end_update(int result)
+{
+/* End the update process. There are two possibilities:
+ * 1) the update succeeded. In that case, cleanup the old version and mark the
+ * new version as no longer under update.
+ * 2) the update failed. In that case, cleanup the new version and mark the old
+ * version as no longer under update. Eventual late ready to update
+ * messages (if any) will simply be ignored and the service can
+ * continue executing. In addition, reset the check timestamp, so that if the
+ * service has a period, a status request will be forced in the next period.
+ */
+ struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
+ message m;
- /* Copy granted resources */
- if (rs_start.rss_nr_irq > NR_IRQ)
- {
- printf("RS: do_up: too many IRQs requested\n");
- 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];
- if(rs_verbose)
- printf("RS: do_up: IRQ %d\n", rp->r_priv.s_irq_tab[i]);
- }
+ old_rp = rupdate.rp;
+ new_rp = old_rp->r_new_rp;
- if (rs_start.rss_nr_io > NR_IO_RANGE)
- {
- printf("RS: do_up: too many I/O ranges requested\n");
- 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;
- if(rs_verbose)
- printf("RS: do_up: I/O [%x..%x]\n",
- rp->r_priv.s_io_tab[i].ior_base,
- rp->r_priv.s_io_tab[i].ior_limit);
- }
+ if(rs_verbose)
+ printf("RS: ending update from %s to %s with result: %d\n",
+ srv_to_string(old_rp), srv_to_string(new_rp), result);
- if (rs_start.rss_nr_pci_id > RS_NR_PCI_DEVICE)
- {
- printf("RS: do_up: too many PCI device IDs\n");
- return EINVAL;
- }
- rpub->pci_acl.rsp_nr_device = rs_start.rss_nr_pci_id;
- for (i= 0; i<rpub->pci_acl.rsp_nr_device; i++)
- {
- rpub->pci_acl.rsp_device[i].vid= rs_start.rss_pci_id[i].vid;
- rpub->pci_acl.rsp_device[i].did= rs_start.rss_pci_id[i].did;
- if(rs_verbose)
- printf("RS: do_up: PCI %04x/%04x\n",
- rpub->pci_acl.rsp_device[i].vid,
- rpub->pci_acl.rsp_device[i].did);
- }
- if (rs_start.rss_nr_pci_class > RS_NR_PCI_CLASS)
- {
- printf("RS: do_up: too many PCI class IDs\n");
- return EINVAL;
- }
- rpub->pci_acl.rsp_nr_class= rs_start.rss_nr_pci_class;
- for (i= 0; i<rpub->pci_acl.rsp_nr_class; i++)
- {
- rpub->pci_acl.rsp_class[i].class= rs_start.rss_pci_class[i].class;
- rpub->pci_acl.rsp_class[i].mask= rs_start.rss_pci_class[i].mask;
- if(rs_verbose)
- printf("RS: do_up: PCI class %06x mask %06x\n",
- rpub->pci_acl.rsp_class[i].class,
- rpub->pci_acl.rsp_class[i].mask);
- }
+ /* Decide which version has to die out and which version has to survive. */
+ surviving_rp = (result == OK ? new_rp : old_rp);
+ exiting_rp = (result == OK ? old_rp : new_rp);
- /* 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<RS_SYS_CALL_MASK_SIZE; i++)
- rp->r_call_mask[i]= rs_start.rss_system[i];
- }
- else
- {
- printf(
- "RS: do_up: internal inconsistency: bad size of r_call_mask\n");
- memset(rp->r_call_mask, '\0', sizeof(rp->r_call_mask));
- }
+ /* End update. */
+ rupdate.flags &= ~RS_UPDATING;
+ rupdate.rp = NULL;
+ old_rp->r_new_rp = NULL;
+ new_rp->r_old_rp = NULL;
+ old_rp->r_check_tm = 0;
- /* Initialize some fields. */
- rpub->period = rs_start.rss_period;
- rpub->dev_nr = rs_start.rss_major;
- rpub->dev_style = STYLE_DEV;
- rp->r_restarts = -1; /* will be incremented */
- rp->r_set_resources= 1; /* set resources */
+ /* Make the version that has to survive as active. */
+ activate_service(surviving_rp, exiting_rp);
- if (sizeof(rpub->vm_call_mask) == sizeof(rs_start.rss_vm) &&
- sizeof(rpub->vm_call_mask[0]) == sizeof(rs_start.rss_vm[0]))
- {
- int basic_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C };
- 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);
- }
- else
- {
- printf("RS: internal inconsistency: bad size of vm_call_mask\n");
- memset(rpub->vm_call_mask, '\0', sizeof(rpub->vm_call_mask));
- }
+ /* Send a late reply if necessary. */
+ late_reply(old_rp, result);
- /* All information was gathered. Now try to start the system service. */
- r = start_service(rp, 0, &ep);
- m_ptr->RS_ENDPOINT = ep;
- return r;
-}
+ /* Unpublish and cleanup the version that has to die out and mark the other
+ * version as no longer updating.
+ */
+ surviving_rp->r_flags &= ~RS_UPDATING;
+ unpublish_process(exiting_rp);
+ cleanup_service(exiting_rp);
+ if(rs_verbose)
+ printf("RS: service %s ended the update\n", srv_to_string(surviving_rp));
+}
/*===========================================================================*
- * do_down *
+ * kill_service_debug *
*===========================================================================*/
-PUBLIC int do_down(message *m_ptr)
+PUBLIC int kill_service_debug(file, line, rp, errstr, err)
+char *file;
+int line;
+struct rproc *rp;
+char *errstr;
+int err;
{
- register struct rproc *rp;
- register struct rprocpub *rpub;
- size_t len;
- int s, proc;
- char label[RS_MAX_LABEL_LEN];
+/* Crash a system service and don't let it restart. */
+ struct rprocpub *rpub;
- /* This call requires special privileges. */
- if (!caller_is_root(m_ptr->m_source)) return(EPERM);
+ if(errstr && !shutting_down) {
+ printf("RS: %s (error %d)\n", errstr, err);
+ }
+ rp->r_flags |= RS_EXITING; /* expect exit */
+ crash_service_debug(file, line, rp); /* simulate crash */
- len= m_ptr->RS_CMD_LEN;
- if (len >= sizeof(label))
- return EINVAL; /* Too long */
+ return err;
+}
- 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';
+/*===========================================================================*
+ * crash_service_debug *
+ *===========================================================================*/
+PUBLIC int crash_service_debug(file, line, rp)
+char *file;
+int line;
+struct rproc *rp;
+{
+/* Simluate a crash in a system service. */
+ struct rprocpub *rpub;
- for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if (rp->r_flags & RS_IN_USE && strcmp(rpub->label, label) == 0) {
- /* Core system services should never go down. */
- if (rpub->sys_flags & SF_CORE_SRV) return(EPERM);
+ rpub = rp->r_pub;
- if(rs_verbose)
- printf("RS: stopping '%s' (%d)\n", label, rp->r_pid);
- stop_service(rp,RS_EXITING);
- if (rp->r_pid == -1)
- {
- /* Process is already gone, release slot. */
- free_slot(rp);
- return(OK);
- }
+ if(rs_verbose)
+ printf("RS: %s %skilled at %s:%d\n", srv_to_string(rp),
+ rp->r_flags & RS_EXITING ? "lethally " : "", file, line);
- /* Late reply - send a reply when process dies. */
- rp->r_flags |= RS_LATEREPLY;
- rp->r_caller = m_ptr->m_source;
- return EDONTREPLY;
- }
- }
- if(rs_verbose) printf("RS: do_down: '%s' not found\n", label);
- return(ESRCH);
+ return sys_kill(rpub->endpoint, SIGKILL);
}
-
/*===========================================================================*
- * do_restart *
+ * cleanup_service_debug *
*===========================================================================*/
-PUBLIC int do_restart(message *m_ptr)
+PUBLIC void cleanup_service_debug(file, line, rp)
+char *file;
+int line;
+struct rproc *rp;
{
- register struct rproc *rp;
- register struct rprocpub *rpub;
- size_t len;
- int s, proc, r;
- char label[RS_MAX_LABEL_LEN];
- endpoint_t ep;
+/* Ask PM to exit the service and free slot. */
+ struct rprocpub *rpub;
- len= m_ptr->RS_CMD_LEN;
- if (len >= sizeof(label))
- return EINVAL; /* Too long */
+ rpub = rp->r_pub;
- 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';
+ if(rs_verbose)
+ printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp),
+ file, line);
- /* This call requires special privileges. */
- if (! (caller_can_control(m_ptr->m_source, label) ||
- caller_is_root(m_ptr->m_source))) {
+ if(rp->r_pid == -1) {
+ printf("RS: warning: attempt to kill pid -1!\n");
+ }
+ else {
+ srv_kill(rp->r_pid, SIGKILL);
+ }
+
+ free_slot(rp);
+}
+
+/*===========================================================================*
+ * create_service *
+ *===========================================================================*/
+PUBLIC int create_service(rp)
+struct rproc *rp;
+{
+/* Create the given system service. */
+ int child_proc_nr_e, child_proc_nr_n; /* child process slot */
+ pid_t child_pid; /* child's process id */
+ char *file_only;
+ int s, use_copy, slot_nr;
+ bitchunk_t *vm_mask;
+ message m;
+ extern char **environ;
+ char * null_env = NULL;
+ struct rprocpub *rpub;
+
+ rpub = rp->r_pub;
+ use_copy= (rpub->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 && (rpub->sys_flags & SF_NEED_COPY)) {
+ printf("RS: unable to start service '%s' without an in-memory copy\n",
+ rpub->label);
+ free_slot(rp);
return(EPERM);
}
- for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if ((rp->r_flags & RS_IN_USE) && strcmp(rpub->label, label) == 0) {
- if(rs_verbose) printf("RS: restarting '%s' (%d)\n", label, rp->r_pid);
- if (rp->r_pid >= 0)
- {
- if(rs_verbose)
- printf("RS: do_restart: '%s' is (still) running, pid = %d\n",
- rp->r_pid);
- return EBUSY;
- }
- rp->r_flags &= ~(RS_REFRESHING|RS_NOPINGREPLY);
- r = start_service(rp, 0, &ep);
- if (r != OK) printf("do_restart: start_service failed: %d\n", r);
- m_ptr->RS_ENDPOINT = ep;
- return(r);
+ /* Now fork and branch for parent and child process (and check for error). */
+ if(rs_verbose)
+ printf("RS: forking child with srv_fork()...\n");
+ child_pid= srv_fork();
+ if(child_pid == -1) {
+ printf("RS: srv_fork() failed (error %d)\n", errno);
+ free_slot(rp);
+ return(errno);
+ }
+
+ /* Get endpoint of the child. */
+ child_proc_nr_e = getnprocnr(child_pid);
+
+ /* There is now a child process. Update the system process table. */
+ child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
+ rp->r_flags = RS_IN_USE; /* mark slot in use */
+ rp->r_restarts += 1; /* raise nr of restarts */
+ 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 */
+ rpub->endpoint = child_proc_nr_e; /* set child endpoint */
+ rp->r_pid = child_pid; /* set 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 */
+ rp->r_backoff = 0; /* not to be restarted */
+ rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
+ rpub->in_use = TRUE; /* public entry is now in use */
+
+
+ /* Set resources when asked to. */
+ if (rp->r_set_resources) {
+ /* Initialize privilege structure. */
+ init_privs(rp, &rp->r_priv);
+ }
+
+ /* 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) {
+ panic("unable to set privilege structure: %d", s);
+ }
+
+ /* 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.
+ * If no copy exists, allocate one and free it right after exec completes.
+ */
+ if(use_copy) {
+ if(rs_verbose)
+ printf("RS: %s uses an in-memory copy\n",
+ srv_to_string(rp));
+ }
+ else {
+ if ((s = read_exec(rp)) != OK) {
+ return kill_service(rp, "read_exec failed", s);
}
}
- if(rs_verbose) {
- printf("RS: do_restart: '%s' not found\n", label);
+ if(rs_verbose)
+ printf("RS: execing child with srv_execve()...\n");
+ s = srv_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rp->r_argv,
+ environ);
+
+ if (s != OK) {
+ return kill_service(rp, "srv_execve failed", s);
}
-
- return(ESRCH);
-}
+ if(!use_copy) {
+ free_exec(rp);
+ }
+
+ /* 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 mapdriver()
+ * 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 big part of srv_fork() can go.
+ */
+ setuid(0);
+
+ if(rs_verbose)
+ printf("RS: %s created\n", srv_to_string(rp));
+ return OK;
+}
/*===========================================================================*
- * do_refresh *
+ * publish_service *
*===========================================================================*/
-PUBLIC int do_refresh(message *m_ptr)
+PUBLIC int publish_service(rp)
+struct rproc *rp; /* pointer to service slot */
{
- register struct rproc *rp;
- register struct rprocpub *rpub;
- size_t len;
- int s;
- char label[RS_MAX_LABEL_LEN];
-
- len= m_ptr->RS_CMD_LEN;
- if (len >= sizeof(label))
- return EINVAL; /* Too long */
+/* Publish service-wide properties of a service. */
+ int r;
+ struct rprocpub *rpub;
- 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';
+ rpub = rp->r_pub;
- /* This call requires special privileges. */
- if (! (caller_can_control(m_ptr->m_source, label) ||
- caller_is_root(m_ptr->m_source))) {
- return(EPERM);
+ /* Register label with DS. */
+ r = ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
+ if (r != OK) {
+ return kill_service(rp, "ds_publish_label call failed", r);
}
- for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if (rp->r_flags & RS_IN_USE && strcmp(rpub->label, label) == 0) {
- /* Only system processes not including RS can refresh. */
- if(!(rp->r_priv.s_flags & SYS_PROC) || rpub->endpoint == RS_PROC_NR) {
- return EPERM;
- }
+ if(rs_verbose)
+ printf("RS: %s service-wide properties published\n",
+ srv_to_string(rp));
- if(rs_verbose) {
- printf("RS: refreshing %s (%d)\n", rpub->label, rp->r_pid);
- }
- stop_service(rp,RS_REFRESHING);
- return(OK);
+ return OK;
+}
+
+/*===========================================================================*
+ * publish_process *
+ *===========================================================================*/
+PUBLIC int publish_process(rp)
+struct rproc *rp; /* pointer to service slot */
+{
+/* Publish process-wide properties of a service. */
+ int r;
+ struct rprocpub *rpub;
+ struct rs_pci pci_acl;
+
+ rpub = rp->r_pub;
+
+ /* If PCI properties are set, inform the PCI driver about the new service. */
+ if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
+ pci_acl = rpub->pci_acl;
+ strcpy(pci_acl.rsp_label, rpub->label);
+ pci_acl.rsp_endpoint= rpub->endpoint;
+
+ r = pci_set_acl(&pci_acl);
+ if (r != OK) {
+ return kill_service(rp, "pci_set_acl call failed", r);
}
}
- if(rs_verbose) {
- printf("RS: do_refresh: '%s' not found\n", label);
+
+ /* Tell VM about allowed calls, if any. */
+ if(rpub->vm_call_mask[0]) {
+ r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0]);
+ if (r != OK) {
+ return kill_service(rp, "vm_set_priv call failed", r);
+ }
}
-
- return(ESRCH);
+
+ if(rs_verbose)
+ printf("RS: %s process-wide properties published\n",
+ srv_to_string(rp));
+
+ return OK;
}
/*===========================================================================*
- * do_shutdown *
+ * unpublish_service *
*===========================================================================*/
-PUBLIC int do_shutdown(message *m_ptr)
+PUBLIC int unpublish_service(rp)
+struct rproc *rp; /* pointer to service slot */
{
- /* This call requires special privileges. */
- if (m_ptr != NULL && !caller_is_root(m_ptr->m_source)) return(EPERM);
+/* Unpublish service-wide properties of a service. */
+ struct rprocpub *rpub;
+ int r, result;
- /* Set flag so that RS server knows services shouldn't be restarted. */
- shutting_down = TRUE;
- return(OK);
-}
+ rpub = rp->r_pub;
+ result = OK;
+ /* Unregister label with DS. */
+ r = ds_delete_label(rpub->label);
+ if (r != OK && !shutting_down) {
+ printf("RS: ds_delete_label call failed (error %d)\n", r);
+ result = r;
+ }
+
+ /* No need to inform VFS, cleanup is performed on exit automatically. */
+
+ if(rs_verbose)
+ printf("RS: %s service-wide properties unpublished\n",
+ srv_to_string(rp));
+
+ return result;
+}
/*===========================================================================*
- * do_init_ready *
+ * unpublish_process *
*===========================================================================*/
-PUBLIC int do_init_ready(message *m_ptr)
+PUBLIC int unpublish_process(rp)
+struct rproc *rp; /* pointer to service slot */
{
- int who_p;
- struct rproc *rp;
+/* Unpublish process-wide properties of a service. */
struct rprocpub *rpub;
- int result;
+ int r, result;
- who_p = _ENDPOINT_P(m_ptr->m_source);
- rp = rproc_ptr[who_p];
rpub = rp->r_pub;
- result = m_ptr->RS_INIT_RESULT;
+ result = OK;
- /* Make sure the originating service was requested to initialize. */
- if(! (rp->r_flags & RS_INITIALIZING) ) {
- if(rs_verbose) {
- printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
- m_ptr->m_source);
+ /* If PCI properties are set, inform the PCI driver. */
+ if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
+ r = pci_del_acl(rpub->endpoint);
+ if (r != OK && !shutting_down) {
+ printf("RS: pci_del_acl call failed (error %d)\n", r);
+ result = r;
}
- return(EINVAL);
}
- /* Mark the slot as no longer initializing. */
- rp->r_flags &= ~RS_INITIALIZING;
- rp->r_check_tm = 0;
- getuptime(&rp->r_alive_tm);
+ /* No need to inform VM, cleanup is performed on exit automatically. */
- /* Check if something went wrong and the service failed to init.
- * In that case, kill it and make sure it won't be restarted.
- */
- if(result != OK) {
- if(rs_verbose)
- printf("RS: initialization failed for service %d: %d\n",
- rpub->endpoint, result);
- rp->r_flags |= RS_EXITING;
- kill(rp->r_pid, SIGKILL);
+ if(rs_verbose)
+ printf("RS: %s process-wide properties unpublished\n",
+ srv_to_string(rp));
+
+ return result;
+}
+
+/*===========================================================================*
+ * run_service *
+ *===========================================================================*/
+PUBLIC int run_service(rp, init_type)
+struct rproc *rp;
+int init_type;
+{
+/* Let a newly created service run. */
+ int s, use_copy;
+ struct rprocpub *rpub;
+
+ 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) {
+ return kill_service(rp, "unable to allow the service to run",s);
}
- else {
- if(rs_verbose)
- printf("RS: initialization succeeded for service %d\n",
- rpub->endpoint);
+
+ /* Initialize service. */
+ if((s = init_service(rp, init_type)) != OK) {
+ return kill_service(rp, "unable to initialize service", s);
}
- return(EDONTREPLY);
+ if(rs_verbose)
+ printf("RS: %s allowed to run\n", srv_to_string(rp));
+
+ return OK;
}
/*===========================================================================*
- * do_update *
+ * start_service *
*===========================================================================*/
-PUBLIC int do_update(message *m_ptr)
+PUBLIC int start_service(rp)
+struct rproc *rp;
{
- register struct rproc *rp;
- register struct rprocpub *rpub;
- size_t len;
- int s;
- char label[RS_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';
+/* Start a system service. */
+ int r, init_type;
+ struct rprocpub *rpub;
- /* This call requires special privileges. */
- if (! (caller_can_control(m_ptr->m_source, label) ||
- caller_is_root(m_ptr->m_source))) {
- return(EPERM);
- }
+ rpub = rp->r_pub;
- /* Retrieve live update state. */
- lu_state = m_ptr->RS_LU_STATE;
- if(lu_state == SEF_LU_STATE_NULL) {
- return(EINVAL);
+ /* Create. */
+ r = create_service(rp);
+ if(r != OK) {
+ return r;
}
- /* 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);
- }
+ /* Publish service properties. */
+ r = publish_process(rp);
+ if (r != OK) {
+ return r;
}
- else {
- prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
+ r = publish_service(rp);
+ if (r != OK) {
+ return r;
}
- /* 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);
+ /* Run. */
+ init_type = rp->r_restarts > 0 ? SEF_INIT_RESTART : SEF_INIT_FRESH;
+ r = run_service(rp, init_type);
+ if(r != OK) {
+ return r;
}
- /* Try to start the update process. */
- for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if (rp->r_flags & RS_IN_USE && strcmp(rpub->label, label) == 0) {
- /* Only system processes not including RS can update. */
- if(!(rp->r_priv.s_flags & SYS_PROC) || rpub->endpoint == RS_PROC_NR) {
- return EPERM;
- }
+ /* 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.
+ */
+ if(rs_verbose)
+ printf("RS: %s started with major %d\n", srv_to_string(rp),
+ rpub->dev_nr);
- if(rs_verbose) {
- printf("RS: updating %s (%d)\n", rpub->label, rp->r_pid);
- }
+ return OK;
+}
- rp->r_flags |= RS_UPDATING;
- rupdate.flags |= RS_UPDATING;
- getuptime(&rupdate.prepare_tm);
- rupdate.prepare_maxtime = prepare_maxtime;
- rupdate.rp = rp;
+/*===========================================================================*
+ * stop_service *
+ *===========================================================================*/
+PUBLIC void stop_service(struct rproc *rp,int how)
+{
+ struct rprocpub *rpub;
- m_ptr->m_type = RS_LU_PREPARE;
- asynsend(rpub->endpoint, m_ptr); /* request to update */
+ rpub = rp->r_pub;
- return(OK);
- }
+ /* 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.
+ */
+ if(rs_verbose)
+ printf("RS: %s signaled with SIGTERM\n", srv_to_string(rp));
+
+ rp->r_flags |= how; /* what to on exit? */
+ sys_kill(rpub->endpoint, SIGTERM); /* first try friendly */
+ getuptime(&rp->r_stop_tm); /* record current time */
+}
+
+/*===========================================================================*
+ * update_service *
+ *===========================================================================*/
+PUBLIC int update_service(src_rpp, dst_rpp)
+struct rproc **src_rpp;
+struct rproc **dst_rpp;
+{
+/* Update an existing service. */
+ int r;
+ struct rproc *src_rp;
+ struct rproc *dst_rp;
+ struct rprocpub *src_rpub;
+ struct rprocpub *dst_rpub;
+ int pid;
+ endpoint_t endpoint;
+
+ src_rp = *src_rpp;
+ dst_rp = *dst_rpp;
+ src_rpub = src_rp->r_pub;
+ dst_rpub = dst_rp->r_pub;
+
+ if(rs_verbose)
+ printf("RS: %s updating into %s\n",
+ srv_to_string(src_rp), srv_to_string(dst_rp));
+
+ /* Ask VM to swap the slots of the two processes and tell the kernel to
+ * do the same.
+ */
+ r = vm_update(src_rpub->endpoint, dst_rpub->endpoint);
+ if(r != OK) {
+ return r;
}
- if(rs_verbose) {
- printf("RS: do_update: '%s' not found\n", label);
+
+ /* Swap slots here as well. */
+ pid = src_rp->r_pid;
+ endpoint = src_rpub->endpoint;
+ swap_slot(&src_rp, &dst_rp);
+
+ /* Reassign pids and endpoints. */
+ src_rp->r_pid = dst_rp->r_pid;
+ src_rp->r_pub->endpoint = dst_rp->r_pub->endpoint;
+ rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)] = src_rp;
+ dst_rp->r_pid = pid;
+ dst_rp->r_pub->endpoint = endpoint;
+ rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp;
+
+ /* Adjust input pointers. */
+ *src_rpp = src_rp;
+ *dst_rpp = dst_rp;
+
+ if(rs_verbose)
+ printf("RS: %s updated into %s\n",
+ srv_to_string(src_rp), srv_to_string(dst_rp));
+
+ return OK;
+}
+
+/*===========================================================================*
+ * activate_service *
+ *===========================================================================*/
+PUBLIC void activate_service(struct rproc *rp, struct rproc *ex_rp)
+{
+/* Activate a service instance and deactivate another one if requested. */
+
+ if(ex_rp && (ex_rp->r_flags & RS_ACTIVE) ) {
+ ex_rp->r_flags &= ~RS_ACTIVE;
+ if(rs_verbose)
+ printf("RS: %s becomes inactive\n", srv_to_string(ex_rp));
}
- return(ESRCH);
+ if(! (rp->r_flags & RS_ACTIVE) ) {
+ rp->r_flags |= RS_ACTIVE;
+ if(rs_verbose)
+ printf("RS: %s becomes active\n", srv_to_string(rp));
+ }
}
/*===========================================================================*
- * do_upd_ready *
+ * terminate_service *
*===========================================================================*/
-PUBLIC int do_upd_ready(message *m_ptr)
+PUBLIC void terminate_service(struct rproc *rp)
{
- register struct rproc *rp;
- int who_p;
- clock_t now = m_ptr->NOTIFY_TIMESTAMP;
- int result;
+/* Handle a termination event for a system service. */
+ struct rproc **rps;
+ struct rprocpub *rpub;
+ int nr_rps;
+ int i, r;
- who_p = _ENDPOINT_P(m_ptr->m_source);
- rp = rproc_ptr[who_p];
- result = m_ptr->RS_LU_RESULT;
+ rpub = rp->r_pub;
- /* Make sure the originating service 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);
+ if(rs_verbose)
+ printf("RS: %s terminated\n", srv_to_string(rp));
+
+ /* Deal with failures during initialization. */
+ if(rp->r_flags & RS_INITIALIZING) {
+ printf("RS: service '%s' exited during initialization\n", rpub->label);
+ rp->r_flags |= RS_EXITING; /* don't restart. */
+
+ /* If updating, rollback. */
+ if(rp->r_flags & RS_UPDATING) {
+ message m;
+ struct rproc *old_rp, *new_rp;
+ printf("RS: update failed: state transfer failed. Rolling back...\n");
+ new_rp = rp;
+ old_rp = new_rp->r_old_rp;
+ new_rp->r_flags &= ~RS_INITIALIZING;
+ update_service(&new_rp, &old_rp); /* can't fail */
+ m.m_type = ERESTART;
+ reply(old_rp->r_pub->endpoint, &m);
+ end_update(ERESTART);
+ return;
}
- return(EINVAL);
}
- /* Check if something went wrong and the service 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",
- "service does not support live update");
- break;
+ if (rp->r_flags & RS_EXITING) {
+ /* If a core system service is exiting, we are in trouble. */
+ if (rp->r_pub->sys_flags & SF_CORE_SRV && !shutting_down) {
+ panic("core system service died: %s", srv_to_string(rp));
+ }
- case EINVAL:
- printf("RS: update failed: %s\n",
- "service does not support the required state");
- break;
+ /* See if a late reply has to be sent. */
+ r = (rp->r_caller_request == RS_DOWN ? OK : EDEADSRCDST);
+ late_reply(rp, r);
- case EBUSY:
- printf("RS: update failed: %s\n",
- "service is not able to prepare for the update now");
- break;
+ /* Unpublish the service. */
+ unpublish_service(rp);
+ unpublish_process(rp);
- case EGENERIC:
- printf("RS: update failed: %s\n",
- "a generic error occurred while preparing for the update");
- break;
+ /* Cleanup all the instances of the service. */
+ get_service_instances(rp, &rps, &nr_rps);
+ for(i=0;i<nr_rps;i++) {
+ cleanup_service(rps[i]);
+ }
+ }
+ else if(rp->r_flags & RS_REFRESHING) {
+ /* Restart service. */
+ restart_service(rp);
+ }
+ else {
+ /* If an update is in progress, end it. The old version
+ * that just exited will continue executing.
+ */
+ if(rp->r_flags & RS_UPDATING) {
+ if(! (rp->r_flags & RS_ACTIVE) ) {
+ return; /* ignore unexpected signals */
+ }
+ end_update(ERESTART);
+ }
- default:
- printf("RS: update failed: %s (%d)\n",
- "an unknown error occurred while preparing for the update\n",
- result);
- break;
+ /* Determine what to do. If this is the first unexpected
+ * exit, immediately restart this service. Otherwise use
+ * a binary exponential backoff.
+ */
+ if (rp->r_restarts > 0) {
+ rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2));
+ rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
+ if ((rpub->sys_flags & SF_USE_COPY) && rp->r_backoff > 1)
+ rp->r_backoff= 1;
+ return;
}
- return(OK);
+ /* Restart service. */
+ restart_service(rp);
}
+}
- /* 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);
+/*===========================================================================*
+ * restart_service *
+ *===========================================================================*/
+PUBLIC void restart_service(rp)
+struct rproc *rp;
+{
+/* Restart service via a recovery script or directly. */
+ struct rproc *replica_rp;
+ int r;
+
+ /* See if a late reply has to be sent. */
+ late_reply(rp, OK);
- return(EDONTREPLY);
+ if (rp->r_script[0] != '\0') {
+ /* Run a recovery script. */
+ run_script(rp);
+ }
+ else {
+ /* Unpublish the service. */
+ unpublish_service(rp);
+ unpublish_process(rp);
+
+ /* Clone slots. */
+ if((r = clone_slot(rp, &replica_rp)) != OK) {
+ kill_service(rp, "unable to clone service", r);
+ return;
+ }
+
+ if(rs_verbose)
+ printf("RS: %s restarting into %s\n",
+ srv_to_string(rp), srv_to_string(replica_rp));
+
+ /* Swap slots. */
+ swap_slot(&rp, &replica_rp);
+
+ /* Direct restart. */
+ if((r = start_service(replica_rp)) != OK) {
+ kill_service(rp, "unable to restart service", r);
+ return;
+ }
+
+ /* Link the two slots. */
+ rp->r_next_rp = replica_rp;
+ replica_rp->r_prev_rp = rp;
+
+ if(rs_verbose)
+ printf("RS: %s restarted into %s\n",
+ srv_to_string(rp), srv_to_string(replica_rp));
+ }
}
/*===========================================================================*
- * update_period *
+ * inherit_service_defaults *
*===========================================================================*/
-PRIVATE void update_period(message *m_ptr)
+PUBLIC void inherit_service_defaults(def_rp, rp)
+struct rproc *def_rp;
+struct rproc *rp;
{
- clock_t now = m_ptr->NOTIFY_TIMESTAMP;
- short has_update_timed_out;
- message m;
+ struct rprocpub *def_rpub;
struct rprocpub *rpub;
- rpub = rupdate.rp->r_pub;
-
- /* See if a timeout has occurred. */
- has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime);
+ def_rpub = def_rp->r_pub;
+ rpub = rp->r_pub;
- /* 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");
+ /* Device settings. These properties cannot change. */
+ rpub->dev_nr = def_rpub->dev_nr;
+ rpub->dev_style = def_rpub->dev_style;
- /* Prepare cancel request. */
- m.m_type = RS_LU_PREPARE;
- m.RS_LU_STATE = SEF_LU_STATE_NULL;
- asynsend(rpub->endpoint, &m);
+ /* Period. */
+ if(!rpub->period && def_rpub->period) {
+ rpub->period = def_rpub->period;
}
}
/*===========================================================================*
- * end_update *
+ * get_service_instances *
*===========================================================================*/
-PRIVATE void end_update(clock_t now)
+PUBLIC void get_service_instances(rp, rps, length)
+struct rproc *rp;
+struct rproc ***rps;
+int *length;
{
- /* 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.
- * We reset the check timestamp, so that if the service has a period a status
- * request will be forced in the next period.
- */
- rupdate.flags &= ~RS_UPDATING;
- rupdate.rp->r_flags &= ~RS_UPDATING;
- rupdate.rp->r_check_tm = 0;
+/* Retrieve all the service instances of a give service. */
+ static struct rproc *instances[5];
+ int nr_instances;
+
+ nr_instances = 0;
+ instances[nr_instances++] = rp;
+ if(rp->r_prev_rp) instances[nr_instances++] = rp->r_prev_rp;
+ if(rp->r_next_rp) instances[nr_instances++] = rp->r_next_rp;
+ if(rp->r_old_rp) instances[nr_instances++] = rp->r_old_rp;
+ if(rp->r_new_rp) instances[nr_instances++] = rp->r_new_rp;
+
+ *rps = instances;
+ *length = nr_instances;
}
/*===========================================================================*
- * do_exit *
+ * share_exec *
*===========================================================================*/
-PUBLIC void do_exit(message *m_ptr)
+PUBLIC void share_exec(rp_dst, rp_src)
+struct rproc *rp_dst, *rp_src;
{
- register struct rproc *rp;
- register struct rprocpub *rpub;
- pid_t exit_pid;
- int exit_status, r, slot_nr;
- endpoint_t ep;
- clock_t now = m_ptr->NOTIFY_TIMESTAMP;
-
- if(rs_verbose)
- printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
+ struct rprocpub *rpub_src;
+ struct rprocpub *rpub_dst;
- /* See which child exited and what the exit status is. This is done in a
- * loop because multiple children may have exited, all reported by one
- * 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 ) {
-
- if(rs_verbose) {
-#if 0
- printf("RS: pid %d, ", exit_pid);
-#endif
- if (WIFSIGNALED(exit_status)) {
-#if 0
- printf("killed, signal number %d\n", WTERMSIG(exit_status));
-#endif
- }
- else if (WIFEXITED(exit_status)) {
-#if 0
- printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
-#endif
- }
- }
+ rpub_src = rp_src->r_pub;
+ rpub_dst = rp_dst->r_pub;
- /* Read from the exec pipe */
- for (;;)
- {
- r= read(exec_pipe[0], &slot_nr, sizeof(slot_nr));
- if (r == -1)
- {
- break; /* No data */
- }
- if (r != sizeof(slot_nr))
- {
- panic("do_exit: unaligned read from exec pipe: %d", r);
- }
- printf("do_exit: got slot %d\n", slot_nr);
- if (slot_nr < 0 || slot_nr >= NR_SYS_PROCS)
- {
- panic("do_exit: bad slot number from exec pipe: %d", slot_nr);
- }
- rp= &rproc[slot_nr];
- rp->r_flags |= RS_EXITING;
- }
+ if(rs_verbose)
+ printf("RS: %s shares exec image with %s\n",
+ srv_to_string(rp_dst), srv_to_string(rp_src));
- /* Search the system process table to see who exited.
- * This should always succeed.
- */
- for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if ((rp->r_flags & RS_IN_USE) && rp->r_pid == exit_pid) {
- int proc;
- proc = _ENDPOINT_P(rpub->endpoint);
-
- rproc_ptr[proc] = NULL; /* invalidate */
- rp->r_pid= -1;
-
- /* If PCI properties are set, inform the PCI driver. */
- if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
- pci_del_acl(rpub->endpoint);
- }
-
- if ((rp->r_flags & RS_EXITING) || shutting_down) {
- /* 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. */
- free_slot(rp);
- }
- else if(rp->r_flags & RS_REFRESHING) {
- short is_updating = rp->r_flags & RS_UPDATING;
-
- /* Refresh */
- if (rp->r_script[0] != '\0')
- run_script(rp);
- else {
- start_service(rp, 0, &ep); /* direct restart */
- if(m_ptr)
- m_ptr->RS_ENDPOINT = ep;
- }
-
- /* If updating, end the update process. */
- if(is_updating) {
- end_update(now);
- printf("RS: update succeeded\n");
- }
- }
- else {
- /* Determine what to do. If this is the first unexpected
- * exit, immediately restart this service. Otherwise use
- * a binary exponential backoff.
- */
-#if 0
-rp->r_restarts= 0;
-#endif
- if (WIFSIGNALED(exit_status)) {
- switch(WTERMSIG(exit_status))
- {
- case SIGKILL: rp->r_flags |= RS_KILLED; break;
- default: rp->r_flags |= RS_SIGNALED; break;
- }
- }
- else
- rp->r_flags |= RS_CRASHED;
-
- if (rp->r_script[0] != '\0') {
- if(rs_verbose)
- printf("RS: running restart script for %s\n",
- rp->r_cmd);
- run_script(rp);
- } else if (rp->r_restarts > 0) {
- printf("RS: restarting %s, restarts %d\n",
- rp->r_cmd, rp->r_backoff);
- rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2));
- rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
- if ((rpub->sys_flags & SF_USE_COPY) && rp->r_backoff > 1)
- rp->r_backoff= 1;
- }
- else {
- printf("RS: restarting %s\n", rp->r_cmd);
- start_service(rp, 0, &ep); /* direct restart */
- if(m_ptr)
- m_ptr->RS_ENDPOINT = ep;
- /* Do this even if no I/O happens with the ioctl, in
- * order to disambiguate requests with DEV_IOCTL_S.
- */
- }
- }
- break;
- }
- }
- }
+ /* Share exec image from rp_src to rp_dst. */
+ rp_dst->r_exec_len = rp_src->r_exec_len;
+ rp_dst->r_exec = rp_src->r_exec;
}
/*===========================================================================*
- * do_period *
+ * read_exec *
*===========================================================================*/
-PUBLIC void do_period(m_ptr)
-message *m_ptr;
+PUBLIC int read_exec(rp)
+struct rproc *rp;
{
- register struct rproc *rp;
- register struct rprocpub *rpub;
- clock_t now = m_ptr->NOTIFY_TIMESTAMP;
- int s;
- endpoint_t ep;
- long period;
+ int e, r, fd;
+ char *e_name;
+ struct stat sb;
+
+ e_name= rp->r_argv[0];
+ if(rs_verbose)
+ printf("RS: service '%s' reads exec image from: %s\n", rp->r_pub->label,
+ e_name);
+
+ r= stat(e_name, &sb);
+ if (r != 0)
+ return -errno;
+
+ fd= open(e_name, O_RDONLY);
+ if (fd == -1)
+ return -errno;
- /* If an update is in progress, check its status. */
- if(rupdate.flags & RS_UPDATING) {
- update_period(m_ptr);
+ rp->r_exec_len= sb.st_size;
+ rp->r_exec= malloc(rp->r_exec_len);
+ if (rp->r_exec == NULL)
+ {
+ printf("RS: read_exec: unable to allocate %d bytes\n",
+ rp->r_exec_len);
+ close(fd);
+ return ENOMEM;
}
- /* Search system services table. Only check slots that are in use and not
- * updating.
- */
- for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
- rpub = rp->r_pub;
- if ((rp->r_flags & RS_IN_USE) && !(rp->r_flags & RS_UPDATING)) {
+ r= read(fd, rp->r_exec, rp->r_exec_len);
+ e= errno;
+ close(fd);
+ if (r == rp->r_exec_len)
+ return OK;
- /* Compute period. */
- period = rpub->period;
- if(rp->r_flags & RS_INITIALIZING) {
- period = RS_INIT_T;
- }
+ printf("RS: read_exec: read failed %d, errno %d\n", r, e);
- /* 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) {
- start_service(rp, 0, &ep);
- m_ptr->RS_ENDPOINT = ep;
- }
- }
-
- /* If the service was signaled with a SIGTERM and fails to respond,
- * kill the system service with a SIGKILL signal.
- */
- else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
- && rp->r_pid > 0) {
- kill(rp->r_pid, SIGKILL); /* terminate */
- }
-
- /* There seems to be no special conditions. If the service has a
- * period assigned check its status.
- */
- else if (period > 0) {
-
- /* Check if an answer to a status request is still pending. If
- * the service didn't respond within time, kill it to simulate
- * a crash. The failure will be detected and the service will
- * be restarted automatically.
- */
- if (rp->r_alive_tm < rp->r_check_tm) {
- if (now - rp->r_alive_tm > 2*period &&
- rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
- if(rs_verbose)
- printf("RS: service %d reported late\n",
- rpub->endpoint);
- rp->r_flags |= RS_NOPINGREPLY;
- if(rp->r_flags & RS_INITIALIZING) {
- rp->r_flags |= RS_EXITING; /* don't restart */
- }
- 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 > rpub->period) {
-#if 0
- if(rs_verbose)
- printf("RS: status request sent to %d\n", rpub->endpoint);
-#endif
- notify(rpub->endpoint); /* request status */
- rp->r_check_tm = now; /* mark time */
- }
- }
+ free_exec(rp);
+
+ if (r >= 0)
+ return EIO;
+ else
+ return -e;
+}
+
+/*===========================================================================*
+ * free_exec *
+ *===========================================================================*/
+PUBLIC void free_exec(rp)
+struct rproc *rp;
+{
+/* Free an exec image. */
+ int slot_nr, has_shared_exec;
+ struct rproc *other_rp;
+
+ /* Search for some other slot sharing the same exec image. */
+ has_shared_exec = FALSE;
+ for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+ other_rp = &rproc[slot_nr]; /* get pointer to slot */
+ if (other_rp->r_flags & RS_IN_USE && other_rp != rp
+ && other_rp->r_exec == rp->r_exec) { /* found! */
+ has_shared_exec = TRUE;
+ break;
}
}
- /* Reschedule a synchronous alarm for the next period. */
- if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
- panic("couldn't set alarm: %d", s);
+ /* If nobody uses our copy of the exec image, we can get rid of it. */
+ if(!has_shared_exec) {
+ if(rs_verbose)
+ printf("RS: %s frees exec image\n", srv_to_string(rp));
+ free(rp->r_exec);
+ }
+ else {
+ if(rs_verbose)
+ printf("RS: %s no longer sharing exec image with %s\n",
+ srv_to_string(rp), srv_to_string(other_rp));
+ }
+ rp->r_exec = NULL;
+ rp->r_exec_len = 0;
}
-
/*===========================================================================*
- * start_service *
+ * init_slot *
*===========================================================================*/
-PRIVATE int start_service(rp, flags, endpoint)
+PUBLIC int init_slot(rp, rs_start, source)
struct rproc *rp;
-int flags;
-endpoint_t *endpoint;
+struct rs_start *rs_start;
+endpoint_t source;
{
-/* Try to execute the given system service. Fork a new process. The child
- * process will be inhibited from running by the NO_PRIV flag. Only let the
- * child run once its privileges have been set by the parent.
- */
- int child_proc_nr_e, child_proc_nr_n; /* child process slot */
- pid_t child_pid; /* child's process id */
- char *file_only;
- int s, use_copy, slot_nr, init_type;
- bitchunk_t *vm_mask;
- message m;
- char * null_env = NULL;
+/* Initialize a slot as requested by the client. */
struct rprocpub *rpub;
+ 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 */
+ struct rproc *tmp_rp;
+ struct rprocpub *tmp_rpub;
+ int len; /* length of string */
+ 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;
+
+/* 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(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 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");
+ }
+ }
+
+ 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(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;
+
+ 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';
+
+ rpub->sys_flags = DSRV_SF;
+ rp->r_exec= NULL;
+ if (rs_start->rss_flags & RSS_COPY) {
+ int exst_cpy;
+ struct rproc *rp2;
+ struct rprocpub *rpub2;
+ exst_cpy = 0;
+
+ if(rs_start->rss_flags & RSS_REUSE) {
+ int i;
+
+ for(i = 0; i < NR_SYS_PROCS; i++) {
+ rp2 = &rproc[i];
+ rpub2 = rproc[i].r_pub;
+ if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 &&
+ (rpub2->sys_flags & SF_USE_COPY)) {
+ /* We have found the same binary that's
+ * already been copied */
+ exst_cpy = 1;
+ break;
+ }
+ }
+ }
- rpub = rp->r_pub;
- use_copy= (rpub->sys_flags & SF_USE_COPY);
+ s = OK;
+ if(!exst_cpy)
+ s = read_exec(rp);
+ else
+ share_exec(rp, rp2);
- /* See if we are not using a copy but we do need one to start the service. */
- if(!use_copy && (rpub->sys_flags & SF_NEED_COPY)) {
- printf("RS: unable to start service %s without an in-memory copy\n",
- rpub->label);
- free_slot(rp);
- return(EPERM);
- }
+ if (s != OK)
+ return s;
- /* Now fork and branch for parent and child process (and check for error). */
- if (use_copy) {
- if(rs_verbose) printf("RS: fork_nb..\n");
- child_pid= fork_nb();
- } else {
- if(rs_verbose) printf("RS: fork regular..\n");
- child_pid = fork();
+ rpub->sys_flags |= SF_USE_COPY;
}
- switch(child_pid) { /* see fork(2) */
- case -1: /* fork failed */
- printf("RS: warning, fork() failed: %d\n", errno); /* shouldn't happen */
- return(errno); /* return error */
-
- case 0: /* child process */
- /* Try to execute the binary that has an absolute path. If this fails,
- * e.g., because the root file system cannot be read, try to strip off
- * the path, and see if the command is in RS' current working dir.
- */
- nice(rp->r_nice); /* Nice before setuid, to allow negative
- * nice values.
- */
- setuid(rp->r_uid);
- cpf_reload(); /* Tell kernel about grant table */
- if (!use_copy)
- {
- execve(rp->r_argv[0], rp->r_argv, &null_env); /* POSIX execute */
- file_only = strrchr(rp->r_argv[0], '/') + 1;
- execve(file_only, rp->r_argv, &null_env); /* POSIX execute */
- }
- printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno);
- 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 */
-
- default: /* parent process */
-#if 0
- if(rs_verbose) printf("RS: parent forked, pid %d..\n", child_pid);
-#endif
- child_proc_nr_e = getnprocnr(child_pid); /* get child slot */
-#if 0
- if(rs_verbose) printf("RS: forked into %d..\n", child_proc_nr_e);
-#endif
- break; /* continue below */
- }
-
- /* 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 */
- rpub->endpoint = 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 */
- rp->r_backoff = 0; /* not to be restarted */
- rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
- rpub->in_use = TRUE; /* public entry is now in use */
-
- /* 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.
+ /* All dynamically created services get the same privilege flags, and
+ * allowed traps, and signal manager. 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 */
+ rp->r_priv.s_sig_mgr = DSRV_SM; /* signal manager */
- if (use_copy)
+ /* Copy granted resources */
+ if (rs_start->rss_nr_irq > NR_IRQ)
{
- extern char **environ;
-
- /* 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,
- environ);
- if (s != OK) {
- printf("RS: dev_execve call failed: %d\n", s);
- kill(child_pid, SIGKILL);
- rp->r_flags |= RS_EXITING; /* don't try again */
- return(s);
- }
+ printf("RS: init_slot: too many IRQs requested\n");
+ return EINVAL;
}
-
- /* Set resources when asked to. */
- if (rp->r_set_resources)
+ rp->r_priv.s_nr_irq= rs_start->rss_nr_irq;
+ for (i= 0; i<rp->r_priv.s_nr_irq; i++)
{
- /* Initialize privilege structure. */
- init_privs(rp, &rp->r_priv);
-
- /* Tell VM about allowed calls. */
- vm_mask = &rpub->vm_call_mask[0];
- if ((s = vm_set_priv(child_proc_nr_e, vm_mask)) < 0) {
- printf("RS: vm_set_priv call failed: %d\n", s);
- kill(child_pid, SIGKILL);
- rp->r_flags |= RS_EXITING;
- return (s);
- }
+ rp->r_priv.s_irq_tab[i]= rs_start->rss_irq[i];
+ if(rs_verbose)
+ printf("RS: init_slot: IRQ %d\n", rp->r_priv.s_irq_tab[i]);
}
- /* 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) {
- printf("RS: unable to set privileges: %d\n", s);
- kill(child_pid, SIGKILL); /* kill the service */
- rp->r_flags |= RS_EXITING; /* expect exit */
- return(s); /* return error */
+ if (rs_start->rss_nr_io > NR_IO_RANGE)
+ {
+ printf("RS: init_slot: too many I/O ranges requested\n");
+ return EINVAL;
}
-
- /* If PCI properties are set, inform the PCI driver about the new service. */
- if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
- init_pci(rp, child_proc_nr_e);
+ 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;
+ if(rs_verbose)
+ printf("RS: init_slot: I/O [%x..%x]\n",
+ rp->r_priv.s_io_tab[i].ior_base,
+ rp->r_priv.s_io_tab[i].ior_limit);
}
- /* Publish the new system service. */
- s = publish_service(rp);
- if (s != OK) {
- printf("RS: warning: publish_service failed: %d\n", s);
+ if (rs_start->rss_nr_pci_id > RS_NR_PCI_DEVICE)
+ {
+ printf("RS: init_slot: too many PCI device IDs\n");
+ return EINVAL;
}
-
- /* Allow the service to run.
- * XXX: We should let the service run/init 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.
- */
- if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_ALLOW, NULL)) != OK) {
- printf("RS: unable to allow the service to run: %d\n", s);
- kill(child_pid, SIGKILL); /* kill the service */
- rp->r_flags |= RS_EXITING; /* expect exit */
- return(s); /* return error */
+ rpub->pci_acl.rsp_nr_device = rs_start->rss_nr_pci_id;
+ for (i= 0; i<rpub->pci_acl.rsp_nr_device; i++)
+ {
+ rpub->pci_acl.rsp_device[i].vid= rs_start->rss_pci_id[i].vid;
+ rpub->pci_acl.rsp_device[i].did= rs_start->rss_pci_id[i].did;
+ if(rs_verbose)
+ printf("RS: init_slot: PCI %04x/%04x\n",
+ rpub->pci_acl.rsp_device[i].vid,
+ rpub->pci_acl.rsp_device[i].did);
}
-
- /* Initialize service. */
- init_type = rp->r_restarts > 0 ? SEF_INIT_RESTART : SEF_INIT_FRESH;
- if((s = init_service(rp, init_type)) != OK) {
- panic("unable to initialize service: %d", s);
+ if (rs_start->rss_nr_pci_class > RS_NR_PCI_CLASS)
+ {
+ printf("RS: init_slot: too many PCI class IDs\n");
+ return EINVAL;
}
-
- /* 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 mapdriver()
- * 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);
-
- /* Map the new service. */
- if (rpub->dev_nr > 0) { /* set driver map */
- if ((s=mapdriver(rpub->label,
- rpub->dev_nr, rpub->dev_style, !!use_copy /* force */)) < 0) {
- printf("RS: couldn't map driver (continuing): %d\n", errno);
- }
+ rpub->pci_acl.rsp_nr_class= rs_start->rss_nr_pci_class;
+ for (i= 0; i<rpub->pci_acl.rsp_nr_class; i++)
+ {
+ rpub->pci_acl.rsp_class[i].class= rs_start->rss_pci_class[i].class;
+ rpub->pci_acl.rsp_class[i].mask= rs_start->rss_pci_class[i].mask;
+ if(rs_verbose)
+ printf("RS: init_slot: PCI class %06x mask %06x\n",
+ rpub->pci_acl.rsp_class[i].class,
+ rpub->pci_acl.rsp_class[i].mask);
}
- if(rs_verbose)
- printf("RS: started '%s', major %d, pid %d, endpoint %d, proc %d\n",
- rp->r_cmd, rpub->dev_nr, child_pid,
- child_proc_nr_e, child_proc_nr_n);
+ /* Copy 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);
- /* 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.
- */
- if(endpoint) *endpoint = child_proc_nr_e; /* send back child endpoint */
+ /* Initialize some fields. */
+ rpub->period = rs_start->rss_period;
+ rpub->dev_nr = rs_start->rss_major;
+ rpub->dev_style = STYLE_DEV;
+ rp->r_restarts = -1; /* will be incremented */
+ rp->r_set_resources= 1; /* set resources */
+
+ /* Copy 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);
- return(OK);
+ return OK;
}
/*===========================================================================*
- * stop_service *
+ * clone_slot *
*===========================================================================*/
-PRIVATE void stop_service(struct rproc *rp,int how)
+PUBLIC int clone_slot(rp, clone_rpp)
+struct rproc *rp;
+struct rproc **clone_rpp;
{
- /* 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.
- */
- if(rs_verbose) printf("RS tries to stop %s (pid %d)\n", rp->r_cmd, rp->r_pid);
+ int r;
+ struct rproc *clone_rp;
+ struct rprocpub *rpub, *clone_rpub;
- rp->r_flags |= how; /* what to on exit? */
- if(rp->r_pid > 0) kill(rp->r_pid, SIGTERM); /* first try friendly */
- else if(rs_verbose) printf("RS: no process to kill\n");
- getuptime(&rp->r_stop_tm); /* record current time */
-}
+ /* Allocate a system service slot for the clone. */
+ r = alloc_slot(&clone_rp);
+ if(r != OK) {
+ printf("RS: clone_slot: unable to allocate a new slot: %d\n", r);
+ return r;
+ }
+
+ rpub = rp->r_pub;
+ clone_rpub = clone_rp->r_pub;
+
+ /* Shallow copy. */
+ *clone_rp = *rp;
+ *clone_rpub = *rpub;
+ /* Deep copy. */
+ clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */
+ clone_rp->r_pid = -1; /* no pid yet */
+ clone_rpub->endpoint = -1; /* no endpoint yet */
+ clone_rp->r_pub = clone_rpub; /* restore pointer to public entry */
+ build_cmd_dep(clone_rp); /* rebuild cmd dependencies */
+ if(clone_rpub->sys_flags & SF_USE_COPY) {
+ share_exec(clone_rp, rp); /* share exec image */
+ }
+
+ /* Force dynamic privilege id. */
+ clone_rp->r_priv.s_flags |= DYN_PRIV_ID;
+
+ *clone_rpp = clone_rp;
+ return OK;
+}
/*===========================================================================*
- * do_getsysinfo *
+ * swap_slot_pointer *
*===========================================================================*/
-PUBLIC int do_getsysinfo(m_ptr)
-message *m_ptr;
+PRIVATE void swap_slot_pointer(struct rproc **rpp, struct rproc *src_rp,
+ struct rproc *dst_rp)
{
- vir_bytes src_addr, dst_addr;
- int dst_proc;
- size_t len;
- int s;
-
- /* This call requires special privileges. */
- if (!caller_is_root(m_ptr->m_source)) return(EPERM);
-
- switch(m_ptr->m1_i1) {
- case SI_PROC_TAB:
- src_addr = (vir_bytes) rproc;
- len = sizeof(struct rproc) * NR_SYS_PROCS;
- break;
- case SI_PROCPUB_TAB:
- src_addr = (vir_bytes) rprocpub;
- len = sizeof(struct rprocpub) * 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);
+ if(*rpp == src_rp) {
+ *rpp = dst_rp;
+ }
+ else if(*rpp == dst_rp) {
+ *rpp = src_rp;
+ }
}
/*===========================================================================*
- * fork_nb *
+ * swap_slot *
*===========================================================================*/
-PRIVATE pid_t fork_nb()
+PUBLIC void swap_slot(src_rpp, dst_rpp)
+struct rproc **src_rpp;
+struct rproc **dst_rpp;
{
- message m;
-
- return(_syscall(PM_PROC_NR, FORK_NB, &m));
+/* Swap two service slots. */
+ struct rproc *src_rp;
+ struct rproc *dst_rp;
+ struct rprocpub *src_rpub;
+ struct rprocpub *dst_rpub;
+ struct rproc orig_src_rproc, orig_dst_rproc;
+ struct rprocpub orig_src_rprocpub, orig_dst_rprocpub;
+
+ src_rp = *src_rpp;
+ dst_rp = *dst_rpp;
+ src_rpub = src_rp->r_pub;
+ dst_rpub = dst_rp->r_pub;
+
+ /* Save existing data first. */
+ orig_src_rproc = *src_rp;
+ orig_src_rprocpub = *src_rpub;
+ orig_dst_rproc = *dst_rp;
+ orig_dst_rprocpub = *dst_rpub;
+
+ /* Swap slots. */
+ *src_rp = orig_dst_rproc;
+ *src_rpub = orig_dst_rprocpub;
+ *dst_rp = orig_src_rproc;
+ *dst_rpub = orig_src_rprocpub;
+
+ /* Restore public entries. */
+ src_rp->r_pub = orig_src_rproc.r_pub;
+ dst_rp->r_pub = orig_dst_rproc.r_pub;
+
+ /* Rebuild command dependencies. */
+ build_cmd_dep(src_rp);
+ build_cmd_dep(dst_rp);
+
+ /* Swap local slot pointers. */
+ swap_slot_pointer(&src_rp->r_prev_rp, src_rp, dst_rp);
+ swap_slot_pointer(&src_rp->r_next_rp, src_rp, dst_rp);
+ swap_slot_pointer(&src_rp->r_old_rp, src_rp, dst_rp);
+ swap_slot_pointer(&src_rp->r_new_rp, src_rp, dst_rp);
+ swap_slot_pointer(&dst_rp->r_prev_rp, src_rp, dst_rp);
+ swap_slot_pointer(&dst_rp->r_next_rp, src_rp, dst_rp);
+ swap_slot_pointer(&dst_rp->r_old_rp, src_rp, dst_rp);
+ swap_slot_pointer(&dst_rp->r_new_rp, src_rp, dst_rp);
+
+ /* Swap global slot pointers. */
+ swap_slot_pointer(&rupdate.rp, src_rp, dst_rp);
+ swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)],
+ src_rp, dst_rp);
+ swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)],
+ src_rp, dst_rp);
+
+ /* Adjust input pointers. */
+ *src_rpp = dst_rp;
+ *dst_rpp = src_rp;
}
/*===========================================================================*
- * share_exec *
+ * lookup_slot_by_label *
*===========================================================================*/
-PRIVATE int share_exec(rp_dst, rp_src)
-struct rproc *rp_dst, *rp_src;
+PUBLIC struct rproc* lookup_slot_by_label(char *label)
{
- struct rprocpub *rpub_src;
- struct rprocpub *rpub_dst;
-
- rpub_src = rp_src->r_pub;
- rpub_dst = rp_dst->r_pub;
+/* Lookup a service slot matching the given label. */
+ int slot_nr;
+ struct rproc *rp;
+ struct rprocpub *rpub;
- if(rs_verbose) {
- printf("RS: share_exec: sharing exec image from %s to %s\n",
- rpub_src->label, rpub_dst->label);
+ for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+ rp = &rproc[slot_nr];
+ if (!(rp->r_flags & RS_ACTIVE)) {
+ continue;
+ }
+ rpub = rp->r_pub;
+ if (strcmp(rpub->label, label) == 0) {
+ return rp;
+ }
}
- /* Share exec image from rp_src to rp_dst. */
- rp_dst->r_exec_len = rp_src->r_exec_len;
- rp_dst->r_exec = rp_src->r_exec;
-
- return OK;
+ return NULL;
}
/*===========================================================================*
- * read_exec *
+ * lookup_slot_by_pid *
*===========================================================================*/
-PRIVATE int read_exec(rp)
-struct rproc *rp;
+PUBLIC struct rproc* lookup_slot_by_pid(pid_t pid)
{
- int e, r, fd;
- char *e_name;
- struct stat sb;
+/* Lookup a service slot matching the given pid. */
+ int slot_nr;
+ struct rproc *rp;
- e_name= rp->r_argv[0];
- if(rs_verbose) {
- printf("RS: read_exec: copying exec image from: %s\n", e_name);
+ if(pid < 0) {
+ return NULL;
}
- r= stat(e_name, &sb);
- if (r != 0)
- 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)
- {
- printf("RS: read_exec: unable to allocate %d bytes\n",
- rp->r_exec_len);
- close(fd);
- return ENOMEM;
+ for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+ rp = &rproc[slot_nr];
+ if (!(rp->r_flags & RS_IN_USE)) {
+ continue;
+ }
+ if (rp->r_pid == pid) {
+ return rp;
+ }
}
- r= read(fd, rp->r_exec, rp->r_exec_len);
- e= errno;
- close(fd);
- if (r == rp->r_exec_len)
- return OK;
+ return NULL;
+}
- printf("RS: read_exec: read failed %d, errno %d\n", r, e);
+/*===========================================================================*
+ * alloc_slot *
+ *===========================================================================*/
+PUBLIC int alloc_slot(rpp)
+struct rproc **rpp;
+{
+/* Alloc a new system service slot. */
+ int slot_nr;
- free(rp->r_exec);
- rp->r_exec= NULL;
+ for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+ *rpp = &rproc[slot_nr]; /* get pointer to slot */
+ if (!((*rpp)->r_flags & RS_IN_USE)) /* check if available */
+ break;
+ }
+ if (slot_nr >= NR_SYS_PROCS) {
+ return ENOMEM;
+ }
- if (r >= 0)
- return EIO;
- else
- return -e;
+ return OK;
}
/*===========================================================================*
* free_slot *
*===========================================================================*/
-PRIVATE void free_slot(rp)
+PUBLIC void free_slot(rp)
struct rproc *rp;
{
- int slot_nr, has_shared_exec;
+/* Free a system service slot. */
struct rprocpub *rpub;
- struct rproc *other_rp;
rpub = rp->r_pub;
+ /* Send a late reply if there is any pending. */
+ late_reply(rp, OK);
+
/* Free memory if necessary. */
if(rpub->sys_flags & SF_USE_COPY) {
- /* Search for some other slot sharing the same exec image. */
- has_shared_exec = FALSE;
- for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
- other_rp = &rproc[slot_nr]; /* get pointer to slot */
- if (other_rp->r_flags & RS_IN_USE && other_rp != rp
- && other_rp->r_exec == rp->r_exec) { /* found! */
- has_shared_exec = TRUE;
- }
- }
-
- /* If nobody uses our copy of the exec image, we can get rid of it. */
- if(!has_shared_exec) {
- if(rs_verbose) {
- printf("RS: free_slot: free exec image from %s\n",
- rpub->label);
- }
- free(rp->r_exec);
- rp->r_exec = NULL;
- rp->r_exec_len = 0;
- }
+ free_exec(rp);
}
/* Mark slot as no longer in use.. */
rp->r_flags = 0;
+ rp->r_pid = -1;
rpub->in_use = FALSE;
rproc_ptr[_ENDPOINT_P(rpub->endpoint)] = NULL;
}
/*===========================================================================*
* run_script *
*===========================================================================*/
-PRIVATE void run_script(rp)
+PUBLIC int run_script(rp)
struct rproc *rp;
{
int r, endpoint;
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";
- else if (rp->r_flags & RS_SIGNALED)
- reason= "signaled";
- else
- {
- printf(
- "RS: run_script: can't find reason for termination of '%s'\n",
- rpub->label);
- return;
- }
+ else reason= "crashed";
sprintf(incarnation_str, "%d", rp->r_restarts);
if(rs_verbose) {
- printf("RS: calling script '%s'\n", rp->r_script);
- printf("RS: sevice name: '%s'\n", rpub->label);
- printf("RS: reason: '%s'\n", reason);
- printf("RS: incarnation: '%s'\n", incarnation_str);
+ printf("RS: %s:\n", srv_to_string(rp));
+ printf("RS: calling script '%s'\n", rp->r_script);
+ printf("RS: reason: '%s'\n", reason);
+ printf("RS: incarnation: '%s'\n", incarnation_str);
}
pid= fork();
switch(pid)
{
- case -1:
- printf("RS: run_script: fork failed: %s\n", strerror(errno));
- break;
+ case -1:
+ return kill_service(rp, "unable to fork script", errno);
case 0:
execle(rp->r_script, rp->r_script, rpub->label, reason,
incarnation_str, NULL, envp);
endpoint = getnprocnr(pid);
if ((r = sys_privctl(endpoint, SYS_PRIV_SET_USER, NULL))
!= OK) {
- printf("RS: run_script: can't set privileges: %d\n",r);
+ return kill_service(rp,"can't set script privileges",r);
}
- /* Allow the service to run. */
+ /* Allow the script to run. */
if ((r = sys_privctl(endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
- printf("RS: run_script: process can't run: %d\n",r);
+ return kill_service(rp,"can't let the script run",r);
}
- /* Do not wait for the child */
- break;
}
}
/*===========================================================================*
* get_next_label *
*===========================================================================*/
-PRIVATE char *get_next_label(ptr, label, caller_label)
+PUBLIC char *get_next_label(ptr, label, caller_label)
char *ptr;
char *label;
char *caller_label;
/*===========================================================================*
* add_forward_ipc *
*===========================================================================*/
-PRIVATE void add_forward_ipc(rp, privp)
+PUBLIC void add_forward_ipc(rp, privp)
struct rproc *rp;
struct priv *privp;
{
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;
- tmp_rpub = tmp_rp->r_pub;
- if (strcmp(tmp_rpub->label, label) == 0)
- break;
- }
- if (slot_nr >= NR_SYS_PROCS)
- {
- if (rs_verbose)
- printf(
- "add_forward_ipc: unable to find '%s'\n", label);
+ tmp_rp = lookup_slot_by_label(label);
+ if (!tmp_rp)
continue;
- }
+ tmp_rpub = tmp_rp->r_pub;
endpoint= tmp_rpub->endpoint;
}
/*===========================================================================*
* add_backward_ipc *
*===========================================================================*/
-PRIVATE void add_backward_ipc(rp, privp)
+PUBLIC void add_backward_ipc(rp, privp)
struct rproc *rp;
struct priv *privp;
{
/*===========================================================================*
* init_privs *
*===========================================================================*/
-PRIVATE void init_privs(rp, privp)
+PUBLIC 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,
- src_bit, call_nr;
- unsigned long mask;
-
- /* Clear s_k_call_mask */
- memset(privp->s_k_call_mask, '\0', sizeof(privp->s_k_call_mask));
-
- src_bits_per_word= 8*sizeof(rp->r_call_mask[0]);
- dst_bits_per_word= 8*sizeof(privp->s_k_call_mask[0]);
- for (src_word= 0; src_word < RS_SYS_CALL_MASK_SIZE; src_word++)
- {
- 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;
-#if 0
- if(rs_verbose)
- printf("RS: init_privs: system call %d\n", call_nr);
-#endif
- dst_word= call_nr / dst_bits_per_word;
- mask= (1UL << (call_nr % dst_bits_per_word));
- if (dst_word >= SYS_CALL_MASK_SIZE)
- {
- printf(
- "RS: init_privs: call number %d doesn't fit\n",
- call_nr);
- }
- privp->s_k_call_mask[dst_word] |= mask;
- }
- }
+ int i;
/* Clear s_ipc_to */
memset(&privp->s_ipc_to, '\0', sizeof(privp->s_ipc_to));
}
}
-/*===========================================================================*
- * init_pci *
- *===========================================================================*/
-PRIVATE void init_pci(rp, endpoint)
-struct rproc *rp;
-int endpoint;
-{
- /* Inform the PCI driver about the new service. */
- size_t len;
- int i, r;
- struct rs_pci rs_pci;
- struct rprocpub *rpub;
-
- rpub = rp->r_pub;
- rs_pci = rpub->pci_acl;
- strcpy(rs_pci.rsp_label, rpub->label);
- rs_pci.rsp_endpoint= endpoint;
-
- if(rs_verbose)
- printf("RS: init_pci: calling pci_set_acl\n");
-
- r= pci_set_acl(&rs_pci);
-
- if(rs_verbose)
- printf("RS: init_pci: after pci_set_acl\n");
-
- if (r != OK)
- {
- printf("RS: init_pci: pci_set_acl failed: %s\n",
- strerror(errno));
- return;
- }
-}
-
-/*===========================================================================*
- * do_lookup *
- *===========================================================================*/
-PUBLIC int do_lookup(m_ptr)
-message *m_ptr;
-{
- static char namebuf[100];
- int len, r;
- struct rproc *rrp;
- struct rprocpub *rrpub;
-
- 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;
- rrpub = rrp->r_pub;
- if (!strcmp(rrpub->label, namebuf)) {
- m_ptr->RS_ENDPOINT = rrpub->endpoint;
- return OK;
- }
- }
-
- return ESRCH;
-}
-
struct rproc;
/* exec.c */
-_PROTOTYPE( int dev_execve, (int proc_e,
+_PROTOTYPE( int srv_execve, (int proc_e,
char *exec, size_t exec_len, char *argv[], char **env));
/* main.c */
_PROTOTYPE( int main, (void));
-/* manager.c */
+/* request.c */
_PROTOTYPE( int do_up, (message *m));
_PROTOTYPE( int do_down, (message *m));
_PROTOTYPE( int do_refresh, (message *m));
_PROTOTYPE( int do_restart, (message *m));
-_PROTOTYPE( int do_lookup, (message *m));
_PROTOTYPE( int do_shutdown, (message *m));
_PROTOTYPE( void do_period, (message *m));
_PROTOTYPE( int do_init_ready, (message *m));
_PROTOTYPE( int do_update, (message *m));
_PROTOTYPE( int do_upd_ready, (message *m));
-_PROTOTYPE( void do_exit, (message *m));
+_PROTOTYPE( void do_sigchld, (void));
_PROTOTYPE( int do_getsysinfo, (message *m));
+_PROTOTYPE( int do_lookup, (message *m));
+
+/* manager.c */
+_PROTOTYPE( int caller_is_root, (endpoint_t endpoint) );
+_PROTOTYPE( int caller_can_control, (endpoint_t endpoint, char *label) );
+_PROTOTYPE( int check_call_permission, (endpoint_t caller, int call,
+ struct rproc *rp) );
+_PROTOTYPE( int copy_rs_start, (endpoint_t src_e, char *src_rs_start,
+ struct rs_start *rs_start) );
+_PROTOTYPE( int copy_label, (endpoint_t src_e, char *src_label, size_t src_len,
+ char *dst_label, size_t dst_len) );
+_PROTOTYPE( void build_cmd_dep, (struct rproc *rp) );
+_PROTOTYPE( int srv_fork, (void) );
+_PROTOTYPE( int srv_kill, (pid_t pid, int sig) );
+#define kill_service(rp, errstr, err) \
+ kill_service_debug(__FILE__, __LINE__, rp, errstr, err)
+_PROTOTYPE( int kill_service_debug, (char *file, int line, struct rproc *rp,
+ char *errstr, int err) );
+#define crash_service(rp) \
+ crash_service_debug(__FILE__, __LINE__, rp)
+_PROTOTYPE( int crash_service_debug, (char *file, int line, struct rproc *rp) );
+#define cleanup_service(rp) \
+ cleanup_service_debug(__FILE__, __LINE__, rp)
+_PROTOTYPE( void cleanup_service_debug, (char *file, int line,
+ struct rproc *rp) );
+_PROTOTYPE( int create_service, (struct rproc *rp) );
+_PROTOTYPE( int publish_service, (struct rproc *rp) );
+_PROTOTYPE( int publish_process, (struct rproc *rp) );
+_PROTOTYPE( int unpublish_service, (struct rproc *rp) );
+_PROTOTYPE( int unpublish_process, (struct rproc *rp) );
+_PROTOTYPE( int run_service, (struct rproc *rp, int init_type) );
+_PROTOTYPE( int start_service, (struct rproc *rp) );
+_PROTOTYPE( void stop_service, (struct rproc *rp,int how) );
+_PROTOTYPE( int update_service, (struct rproc **src_rpp,
+ struct rproc **dst_rpp) );
+_PROTOTYPE( void activate_service, (struct rproc *rp, struct rproc *ex_rp) );
+_PROTOTYPE( void terminate_service, (struct rproc *rp));
+_PROTOTYPE( void restart_service, (struct rproc *rp) );
+_PROTOTYPE( void inherit_service_defaults, (struct rproc *def_rp,
+ struct rproc *rp) );
+_PROTOTYPE( void get_service_instances, (struct rproc *rp, struct rproc ***rps,
+ int *length) );
+_PROTOTYPE( int read_exec, (struct rproc *rp) );
+_PROTOTYPE( void share_exec, (struct rproc *rp_src, struct rproc *rp_dst) );
+_PROTOTYPE( void free_exec, (struct rproc *rp) );
+_PROTOTYPE( int init_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( struct rproc* lookup_slot_by_pid, (pid_t pid) );
+_PROTOTYPE( int alloc_slot, (struct rproc **rpp) );
+_PROTOTYPE( void free_slot, (struct rproc *rp) );
+_PROTOTYPE( int run_script, (struct rproc *rp) );
+_PROTOTYPE( char *get_next_label, (char *ptr, char *label, char *caller_label));
+_PROTOTYPE( void add_forward_ipc, (struct rproc *rp, struct priv *privp) );
+_PROTOTYPE( void add_backward_ipc, (struct rproc *rp, struct priv *privp) );
+_PROTOTYPE( void init_privs, (struct rproc *rp, struct priv *privp) );
+_PROTOTYPE( void update_period, (message *m_ptr) );
+_PROTOTYPE( void end_update, (int result) );
/* utility.c */
_PROTOTYPE( int init_service, (struct rproc *rp, int type));
-_PROTOTYPE( int publish_service, (struct rproc *rp));
_PROTOTYPE(void fill_call_mask, ( int *calls, int tot_nr_calls,
- bitchunk_t *call_mask, int call_base, int is_init));
+ bitchunk_t *call_mask, int call_base, int is_init));
+_PROTOTYPE( char* srv_to_string, (struct rproc *rp));
+_PROTOTYPE( void reply, (endpoint_t who, message *m_ptr));
+_PROTOTYPE( void late_reply, (struct rproc *rp, int code));
+_PROTOTYPE( int rs_isokendpt, (endpoint_t endpoint, int *proc));
/* 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));
+ int dst_s, vir_bytes dst_vir, phys_bytes bytes));
+
+/* error.c */
+_PROTOTYPE( char * init_strerror, (int errnum) );
+_PROTOTYPE( char * lu_strerror, (int errnum) );
--- /dev/null
+/*
+ * Changes:
+ * Jan 22, 2010: Created (Cristiano Giuffrida)
+ */
+
+#include "inc.h"
+
+/*===========================================================================*
+ * do_up *
+ *===========================================================================*/
+PUBLIC int do_up(m_ptr)
+message *m_ptr; /* request message pointer */
+{
+/* A request was made to start a new system service. */
+ struct rproc *rp;
+ struct rprocpub *rpub;
+ int r;
+ struct rs_start rs_start;
+
+ /* Check if the call can be allowed. */
+ if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
+ return r;
+
+ /* Allocate a new system service slot. */
+ r = alloc_slot(&rp);
+ if(r != OK) {
+ printf("RS: do_up: unable to allocate a new slot: %d\n", r);
+ return r;
+ }
+ rpub = rp->r_pub;
+
+ /* Copy the request structure. */
+ r = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
+ if (r != OK) {
+ return r;
+ }
+
+ /* Initialize the slot as requested. */
+ r = init_slot(rp, &rs_start, m_ptr->m_source);
+ if(r != OK) {
+ printf("RS: do_up: unable to init the new slot: %d\n", r);
+ return r;
+ }
+
+ /* Check for duplicates */
+ if(lookup_slot_by_label(rpub->label)) {
+ printf("RS: service '%s' (%d) has duplicate label\n", rpub->label,
+ rpub->endpoint);
+ return EBUSY;
+ }
+
+ /* All information was gathered. Now try to start the system service. */
+ r = start_service(rp);
+ activate_service(rp, NULL);
+ if(r != OK) {
+ return r;
+ }
+
+ /* Late reply - send a reply when service completes initialization. */
+ rp->r_flags |= RS_LATEREPLY;
+ rp->r_caller = m_ptr->m_source;
+ rp->r_caller_request = RS_UP;
+
+ return EDONTREPLY;
+}
+
+/*===========================================================================*
+ * do_down *
+ *===========================================================================*/
+PUBLIC int do_down(message *m_ptr)
+{
+ register struct rproc *rp;
+ register struct rprocpub *rpub;
+ int s, proc;
+ char label[RS_MAX_LABEL_LEN];
+
+ /* Copy label. */
+ s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
+ m_ptr->RS_CMD_LEN, label, sizeof(label));
+ if(s != OK) {
+ return s;
+ }
+
+ /* Lookup slot by label. */
+ rp = lookup_slot_by_label(label);
+ if(!rp) {
+ if(rs_verbose)
+ printf("RS: do_down: service '%s' not found\n", label);
+ return(ESRCH);
+ }
+ rpub = rp->r_pub;
+
+ /* Check if the call can be allowed. */
+ if((s = check_call_permission(m_ptr->m_source, RS_DOWN, rp)) != OK)
+ return s;
+
+ /* Stop service. */
+ if (rp->r_flags & RS_TERMINATED) {
+ /* A recovery script is requesting us to bring down the service.
+ * The service is already gone, simply perform cleanup.
+ */
+ if(rs_verbose)
+ printf("RS: recovery script performs service down...\n");
+ unpublish_service(rp);
+ unpublish_process(rp);
+ cleanup_service(rp);
+ return(OK);
+ }
+ stop_service(rp,RS_EXITING);
+
+ /* Late reply - send a reply when service dies. */
+ rp->r_flags |= RS_LATEREPLY;
+ rp->r_caller = m_ptr->m_source;
+ rp->r_caller_request = RS_DOWN;
+
+ return EDONTREPLY;
+}
+
+/*===========================================================================*
+ * do_restart *
+ *===========================================================================*/
+PUBLIC int do_restart(message *m_ptr)
+{
+ struct rproc *rp;
+ int s, proc, 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,
+ m_ptr->RS_CMD_LEN, label, sizeof(label));
+ if(s != OK) {
+ return s;
+ }
+
+ /* Lookup slot by label. */
+ rp = lookup_slot_by_label(label);
+ if(!rp) {
+ if(rs_verbose)
+ printf("RS: do_restart: service '%s' not found\n", label);
+ return(ESRCH);
+ }
+
+ /* Check if the call can be allowed. */
+ if((r = check_call_permission(m_ptr->m_source, RS_RESTART, rp)) != OK)
+ return r;
+
+ /* We can only be asked to restart a service from a recovery script. */
+ if (! (rp->r_flags & RS_TERMINATED) ) {
+ if(rs_verbose)
+ printf("RS: %s is still running\n", srv_to_string(rp));
+ return EBUSY;
+ }
+
+ if(rs_verbose)
+ printf("RS: recovery script performs service restart...\n");
+
+ /* Restart the service, but make sure we don't call the script again. */
+ strcpy(script, rp->r_script);
+ rp->r_script[0] = '\0';
+ restart_service(rp);
+ strcpy(rp->r_script, script);
+
+ return OK;
+}
+
+
+/*===========================================================================*
+ * do_refresh *
+ *===========================================================================*/
+PUBLIC int do_refresh(message *m_ptr)
+{
+ register struct rproc *rp;
+ register struct rprocpub *rpub;
+ int s;
+ char label[RS_MAX_LABEL_LEN];
+
+ /* Copy label. */
+ s = copy_label(m_ptr->m_source, m_ptr->RS_CMD_ADDR,
+ m_ptr->RS_CMD_LEN, label, sizeof(label));
+ if(s != OK) {
+ return s;
+ }
+
+ /* Lookup slot by label. */
+ rp = lookup_slot_by_label(label);
+ if(!rp) {
+ if(rs_verbose)
+ printf("RS: do_refresh: service '%s' not found\n", label);
+ return(ESRCH);
+ }
+ rpub = rp->r_pub;
+
+ /* Check if the call can be allowed. */
+ if((s = check_call_permission(m_ptr->m_source, RS_REFRESH, rp)) != OK)
+ return s;
+
+ /* Refresh service. */
+ if(rs_verbose)
+ printf("RS: %s refreshing\n", srv_to_string(rp));
+ stop_service(rp,RS_REFRESHING);
+
+ return OK;
+}
+
+/*===========================================================================*
+ * do_shutdown *
+ *===========================================================================*/
+PUBLIC int do_shutdown(message *m_ptr)
+{
+ int slot_nr;
+ struct rproc *rp;
+ int r;
+
+ /* Check if the call can be allowed. */
+ if (m_ptr != NULL) {
+ if((r = check_call_permission(m_ptr->m_source, RS_SHUTDOWN, NULL)) != OK)
+ return r;
+ }
+
+ if(rs_verbose)
+ printf("RS: shutting down...\n");
+
+ /* Set flag to tell RS we are shutting down. */
+ shutting_down = TRUE;
+
+ /* Don't restart dead services. */
+ for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
+ rp = &rproc[slot_nr];
+ if (rp->r_flags & RS_IN_USE) {
+ rp->r_flags |= RS_EXITING;
+ }
+ }
+ return(OK);
+}
+
+/*===========================================================================*
+ * do_init_ready *
+ *===========================================================================*/
+PUBLIC int do_init_ready(message *m_ptr)
+{
+ int who_p;
+ struct rproc *rp;
+ struct rprocpub *rpub;
+ message m;
+ int result;
+
+ who_p = _ENDPOINT_P(m_ptr->m_source);
+ rp = rproc_ptr[who_p];
+ rpub = rp->r_pub;
+ result = m_ptr->RS_INIT_RESULT;
+
+ /* Make sure the originating service was requested to initialize. */
+ if(! (rp->r_flags & RS_INITIALIZING) ) {
+ if(rs_verbose)
+ printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
+ m_ptr->m_source);
+ return(EDONTREPLY);
+ }
+
+ /* Check if something went wrong and the service failed to init.
+ * In that case, kill the service.
+ */
+ if(result != OK) {
+ if(rs_verbose)
+ printf("RS: %s initialization error: %s\n", srv_to_string(rp),
+ init_strerror(result));
+ crash_service(rp); /* simulate crash */
+ return(EDONTREPLY);
+ }
+
+ /* XXX If the service is a driver, map it. This should be part
+ * of publish_service() but the synchronous nature of mapdriver would
+ * cause a deadlock. The temporary hack is to map the driver here
+ * after initialization is complete.
+ */
+ m.m_type = OK;
+ reply(rpub->endpoint, &m);
+ if (rpub->dev_nr > 0) {
+ if (mapdriver(rpub->label, rpub->dev_nr, rpub->dev_style, 1) != OK) {
+ return kill_service(rp, "couldn't map driver", errno);
+ }
+ }
+
+ /* Mark the slot as no longer initializing. */
+ rp->r_flags &= ~RS_INITIALIZING;
+ rp->r_check_tm = 0;
+ getuptime(&rp->r_alive_tm);
+
+ /* See if a late reply has to be sent. */
+ late_reply(rp, OK);
+
+ if(rs_verbose)
+ printf("RS: %s initialized\n", srv_to_string(rp));
+
+ /* If the service has completed initialization after a live
+ * update, end the update now.
+ */
+ if(rp->r_flags & RS_UPDATING) {
+ printf("RS: update succeeded\n");
+ end_update(OK);
+ }
+
+ /* If the service has completed initialization after a crash
+ * make the new instance active and cleanup the old replica.
+ */
+ if(rp->r_prev_rp) {
+ activate_service(rp, rp->r_prev_rp);
+ cleanup_service(rp->r_prev_rp);
+ rp->r_prev_rp = NULL;
+
+ if(rs_verbose)
+ printf("RS: %s completed restart\n", srv_to_string(rp));
+ }
+
+ return(EDONTREPLY);
+}
+
+/*===========================================================================*
+ * do_update *
+ *===========================================================================*/
+PUBLIC int do_update(message *m_ptr)
+{
+ struct rproc *rp;
+ struct rproc *new_rp;
+ struct rprocpub *rpub;
+ struct rprocpub *new_rpub;
+ struct rs_start rs_start;
+ int s;
+ char label[RS_MAX_LABEL_LEN];
+ int lu_state;
+ int prepare_maxtime;
+
+ /* Copy the request structure. */
+ s = copy_rs_start(m_ptr->m_source, m_ptr->RS_CMD_ADDR, &rs_start);
+ if (s != OK) {
+ return s;
+ }
+
+ /* Copy label. */
+ s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
+ rs_start.rss_label.l_len, label, sizeof(label));
+ if(s != OK) {
+ return s;
+ }
+
+ /* Lookup slot by label. */
+ rp = lookup_slot_by_label(label);
+ if(!rp) {
+ if(rs_verbose)
+ printf("RS: do_update: service '%s' not found\n", label);
+ return ESRCH;
+ }
+ rpub = rp->r_pub;
+
+ /* Check if the call can be allowed. */
+ if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
+ return s;
+
+ /* 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\n");
+ return EBUSY;
+ }
+
+ /* Allocate a system service slot for the new version. */
+ s = alloc_slot(&new_rp);
+ if(s != OK) {
+ printf("RS: do_update: unable to allocate a new slot: %d\n", s);
+ return s;
+ }
+
+ /* Initialize the slot as requested. */
+ s = init_slot(new_rp, &rs_start, m_ptr->m_source);
+ if(s != OK) {
+ printf("RS: do_update: unable to init the new slot: %d\n", s);
+ return s;
+ }
+
+ /* Let the new version inherit defaults from the old one. */
+ inherit_service_defaults(rp, new_rp);
+
+ /* Create new version of the service but don't let it run. */
+ s = create_service(new_rp);
+ if(s != OK) {
+ printf("RS: do_update: unable to create a new service: %d\n", s);
+ return s;
+ }
+
+ /* Publish process-wide properties. */
+ s = publish_process(new_rp);
+ if (s != OK) {
+ printf("RS: do_update: publish_process failed: %d\n", s);
+ return s;
+ }
+
+ /* Link old version to new version and mark both as updating. */
+ rp->r_new_rp = new_rp;
+ new_rp->r_old_rp = rp;
+ rp->r_flags |= RS_UPDATING;
+ rp->r_new_rp->r_flags |= RS_UPDATING;
+ rupdate.flags |= RS_UPDATING;
+ getuptime(&rupdate.prepare_tm);
+ rupdate.prepare_maxtime = prepare_maxtime;
+ rupdate.rp = rp;
+
+ if(rs_verbose)
+ printf("RS: %s updating\n", srv_to_string(rp));
+
+ /* Request to update. */
+ m_ptr->m_type = RS_LU_PREPARE;
+ asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
+
+ /* Late reply - send a reply when the new version completes initialization. */
+ rp->r_flags |= RS_LATEREPLY;
+ rp->r_caller = m_ptr->m_source;
+ rp->r_caller_request = RS_UPDATE;
+
+ return EDONTREPLY;
+}
+
+/*===========================================================================*
+ * do_upd_ready *
+ *===========================================================================*/
+PUBLIC int do_upd_ready(message *m_ptr)
+{
+ struct rproc *rp, *old_rp, *new_rp;
+ int who_p;
+ int result;
+ int r;
+
+ who_p = _ENDPOINT_P(m_ptr->m_source);
+ rp = rproc_ptr[who_p];
+ result = m_ptr->RS_LU_RESULT;
+
+ /* Make sure the originating service was requested to prepare for update. */
+ if(rp != rupdate.rp) {
+ 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 service failed to prepare
+ * for the update. In that case, end the update process. The old version will
+ * be replied to and continue executing.
+ */
+ if(result != OK) {
+ end_update(result);
+
+ printf("RS: update failed: %s\n", lu_strerror(result));
+ return OK;
+ }
+
+ /* Perform the update. */
+ old_rp = rp;
+ new_rp = rp->r_new_rp;
+ r = update_service(&old_rp, &new_rp);
+ if(r != OK) {
+ end_update(r);
+ printf("RS: update failed: error %d\n", r);
+ return r;
+ }
+
+ /* Let the new version run. */
+ r = run_service(new_rp, SEF_INIT_LU);
+ if(r != OK) {
+ update_service(&new_rp, &old_rp); /* rollback, can't fail. */
+ end_update(r);
+ printf("RS: update failed: error %d\n", r);
+ return r;
+ }
+
+ return(EDONTREPLY);
+}
+
+/*===========================================================================*
+ * do_period *
+ *===========================================================================*/
+PUBLIC void do_period(m_ptr)
+message *m_ptr;
+{
+ register struct rproc *rp;
+ register struct rprocpub *rpub;
+ clock_t now = m_ptr->NOTIFY_TIMESTAMP;
+ int s;
+ long period;
+
+ /* 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.
+ */
+ for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
+ rpub = rp->r_pub;
+ if ((rp->r_flags & RS_IN_USE) && !(rp->r_flags & RS_UPDATING)) {
+
+ /* Compute period. */
+ period = rpub->period;
+ if(rp->r_flags & RS_INITIALIZING) {
+ period = RS_INIT_T;
+ }
+
+ /* 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) {
+ restart_service(rp);
+ }
+ }
+
+ /* If the service was signaled with a SIGTERM and fails to respond,
+ * kill the system service with a SIGKILL signal.
+ */
+ else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
+ && rp->r_pid > 0) {
+ crash_service(rp); /* simulate crash */
+ rp->r_stop_tm = 0;
+ }
+
+ /* There seems to be no special conditions. If the service has a
+ * period assigned check its status.
+ */
+ else if (period > 0) {
+
+ /* Check if an answer to a status request is still pending. If
+ * the service didn't respond within time, kill it to simulate
+ * a crash. The failure will be detected and the service will
+ * be restarted automatically.
+ */
+ if (rp->r_alive_tm < rp->r_check_tm) {
+ if (now - rp->r_alive_tm > 2*period &&
+ rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
+ if(rs_verbose)
+ printf("RS: %s reported late\n",
+ srv_to_string(rp));
+ rp->r_flags |= RS_NOPINGREPLY;
+ crash_service(rp); /* 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 > rpub->period) {
+ notify(rpub->endpoint); /* request status */
+ rp->r_check_tm = now; /* mark time */
+ }
+ }
+ }
+ }
+
+ /* Reschedule a synchronous alarm for the next period. */
+ if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
+ panic("couldn't set alarm: %d", s);
+}
+
+/*===========================================================================*
+ * do_sigchld *
+ *===========================================================================*/
+PUBLIC void do_sigchld()
+{
+/* PM informed us that there are dead children to cleanup. Go get them. */
+ pid_t pid;
+ int status;
+ struct rproc *rp;
+ struct rproc **rps;
+ struct rprocpub *rpub;
+ int i, nr_rps;
+
+ if(rs_verbose)
+ printf("RS: got SIGCHLD signal, cleaning up dead children\n");
+
+ while ( (pid = waitpid(-1, &status, WNOHANG)) != 0 ) {
+ rp = lookup_slot_by_pid(pid);
+ if(rp != NULL) {
+ rpub = rp->r_pub;
+
+ if(rs_verbose)
+ printf("RS: %s exited via another signal manager\n",
+ srv_to_string(rp));
+
+ /* The slot is still there. This means RS is not the signal
+ * manager assigned to the process. Ignore the event but
+ * free slots for all the service instances and send a late
+ * reply if necessary.
+ */
+ get_service_instances(rp, &rps, &nr_rps);
+ for(i=0;i<nr_rps;i++) {
+ if(rupdate.flags & RS_UPDATING) {
+ rupdate.flags &= ~RS_UPDATING;
+ }
+ free_slot(rps[i]);
+ }
+ }
+ }
+}
+
+/*===========================================================================*
+ * 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;
+
+ /* Check if the call can be allowed. */
+ if((s = check_call_permission(m_ptr->m_source, 0, NULL)) != OK)
+ return s;
+
+ switch(m_ptr->m1_i1) {
+ case SI_PROC_TAB:
+ src_addr = (vir_bytes) rproc;
+ len = sizeof(struct rproc) * NR_SYS_PROCS;
+ break;
+ case SI_PROCPUB_TAB:
+ src_addr = (vir_bytes) rprocpub;
+ len = sizeof(struct rprocpub) * 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);
+}
+
+/*===========================================================================*
+ * do_lookup *
+ *===========================================================================*/
+PUBLIC int do_lookup(m_ptr)
+message *m_ptr;
+{
+ static char namebuf[100];
+ int len, r;
+ struct rproc *rrp;
+ struct rprocpub *rrpub;
+
+ 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';
+
+ rrp = lookup_slot_by_label(namebuf);
+ if(!rrp) {
+ return ESRCH;
+ }
+ rrpub = rrp->r_pub;
+ m_ptr->RS_ENDPOINT = rrpub->endpoint;
+
+ return OK;
+}
+
#define RUN_CMD "run"
#define RUN_SCRIPT "/etc/rs.single" /* Default script for 'run' */
#define PATH_CONFIG _PATH_SYSTEM_CONF /* Default config file */
+#define DEFAULT_LU_STATE 3 /* Default live update state */
+#define DEFAULT_LU_MAXTIME 0 /* Default lu max time */
/* Define names for arguments provided to this utility. The first few
* arguments are required and have a known index. Thereafter, some optional
#define ARG_REQUEST 0 /* request to perform */
#define ARG_PATH 1 /* system service */
#define ARG_LABEL 1 /* name of system service */
-#define ARG_LU_STATE 2 /* the state required to update */
-#define ARG_PREPARE_MAXTIME 3 /* max time to prepare for the update */
#define MIN_ARG_COUNT 1 /* require an action */
#define ARG_CONFIG "-config" /* name of the file with the resource
* configuration
*/
-#define ARG_PRINTEP "-printep" /* print endpoint number after start */
+
+#define ARG_LU_STATE "-state" /* the live update state required */
+#define ARG_LU_MAXTIME "-maxtime" /* max time to prepare for the update */
#define SERVICE_LOGIN "service" /* passwd file entry for services */
PRIVATE char *req_script;
PRIVATE char *req_ipc;
PRIVATE char *req_config = PATH_CONFIG;
-PRIVATE int req_printep;
PRIVATE int class_recurs; /* Nesting level of class statements */
-PRIVATE int req_lu_state;
-PRIVATE int req_prepare_maxtime;
+PRIVATE int req_lu_state = DEFAULT_LU_STATE;
+PRIVATE int req_lu_maxtime = DEFAULT_LU_MAXTIME;
/* Buffer to build "/command arg1 arg2 ..." string to pass to RS server. */
PRIVATE char command[4096];
fprintf(stderr, "Warning, %s\n", problem);
fprintf(stderr, "Usage:\n");
fprintf(stderr,
- " %s [-c -r] (up|run) <binary> [%s <args>] [%s <special>] [%s <ticks>]\n",
- app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD);
+ " %s [-c -r] (up|run|update) <binary> [%s <args>] [%s <special>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
+ app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD, ARG_SCRIPT, ARG_LABELNAME,
+ ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME);
fprintf(stderr, " %s down label\n", app_name);
fprintf(stderr, " %s refresh label\n", app_name);
fprintf(stderr, " %s restart label\n", app_name);
- fprintf(stderr, " %s update label state maxtime\n", app_name);
fprintf(stderr, " %s shutdown\n", app_name);
fprintf(stderr, "\n");
}
req_nr = RS_RQ_BASE + req_type;
}
- if (req_nr == RS_UP) {
+ if (req_nr == RS_UP || req_nr == RS_UPDATE) {
+ u32_t system_hz;
+
rs_start.rss_flags= RSS_IPC_VALID;
if (c_flag)
rs_start.rss_flags |= RSS_COPY;
exit(EINVAL);
}
+ /* Get HZ. */
+ if(getsysinfo_up(PM_PROC_NR,
+ SIU_SYSTEMHZ, sizeof(system_hz), &system_hz) < 0) {
+ system_hz = DEFAULT_HZ;
+ fprintf(stderr, "WARNING: reverting to default HZ %d\n",
+ system_hz);
+ }
+
/* Check optional arguments that come in pairs like "-args arglist". */
for (i=optind+MIN_ARG_COUNT+1; i<argc; i=i+2) {
if (! (i+1 < argc)) {
req_args = argv[i+1];
}
else if (strcmp(argv[i], ARG_PERIOD)==0) {
- u32_t system_hz;
- if(getsysinfo_up(PM_PROC_NR,
- SIU_SYSTEMHZ, sizeof(system_hz), &system_hz) < 0) {
- system_hz = DEFAULT_HZ;
- fprintf(stderr, "WARNING: reverting to default HZ %d\n",
- system_hz);
- }
-
req_period = strtol(argv[i+1], &hz, 10);
if (strcmp(hz,"HZ")==0) req_period *= system_hz;
if (req_period < 1) {
else if (strcmp(argv[i], ARG_CONFIG)==0) {
req_config = argv[i+1];
}
- else if (strcmp(argv[i], ARG_PRINTEP)==0) {
- req_printep = 1;
+ else if (strcmp(argv[i], ARG_LU_STATE)==0) {
+ errno=0;
+ req_lu_state = strtol(argv[i+1], &buff, 10);
+ if(errno || strcmp(buff, "")) {
+ print_usage(argv[ARG_NAME],
+ "bad live update state");
+ exit(EINVAL);
+ }
+ if(req_lu_state == SEF_LU_STATE_NULL) {
+ print_usage(argv[ARG_NAME],
+ "null live update state.");
+ exit(EINVAL);
+ }
+ }
+ else if (strcmp(argv[i], ARG_LU_MAXTIME)==0) {
+ errno=0;
+ req_lu_maxtime = strtol(argv[i+1], &hz, 10);
+ if(errno || (strcmp(hz, "") && strcmp(hz, "HZ"))
+ || req_lu_maxtime<0) {
+ print_usage(argv[ARG_NAME],
+ "bad live update max time");
+ exit(EINVAL);
+ }
+ if (strcmp(hz,"HZ")==0) req_lu_maxtime *= system_hz;
}
else {
print_usage(argv[ARG_NAME], "unknown optional argument given");
else if (req_nr == RS_SHUTDOWN) {
/* no extra arguments required */
}
- else if (req_nr == RS_UPDATE) {
- /* Check for mandatory arguments */
- if (argc - 1 < optind+ARG_LU_STATE) {
- print_usage(argv[ARG_NAME],
- "action requires at least a label and a live update state");
- exit(EINVAL);
- }
-
- /* Label. */
- req_label= argv[optind+ARG_LABEL];
-
- /* Live update state. */
- errno=0;
- req_lu_state=strtol(argv[optind+ARG_LU_STATE], &buff, 10);
- if(errno || strcmp(buff, "")) {
- print_usage(argv[ARG_NAME],
- "action requires a correct live update state");
- exit(EINVAL);
- }
- if(req_lu_state == SEF_LU_STATE_NULL) {
- print_usage(argv[ARG_NAME],
- "action requires a non-null live update state.");
- exit(EINVAL);
- }
-
- /* Prepare max time. */
- req_prepare_maxtime=0;
- if (argc - 1 >= optind+ARG_PREPARE_MAXTIME) {
- req_prepare_maxtime=strtol(argv[optind+ARG_PREPARE_MAXTIME],
- &buff, 10);
- if(errno || strcmp(buff, "") || req_prepare_maxtime<0) {
- print_usage(argv[ARG_NAME],
- "action requires a correct max time to prepare for the update");
- exit(EINVAL);
- }
- }
- }
/* Return the request number if no error were found. */
return(req_nr);
int call_nr;
} system_tab[]=
{
- { "EXIT", SYS_EXIT },
{ "PRIVCTL", SYS_PRIVCTL },
{ "TRACE", SYS_TRACE },
{ "KILL", SYS_KILL },
{ "DEVIO", SYS_DEVIO },
{ "SDEVIO", SYS_SDEVIO },
{ "VDEVIO", SYS_VDEVIO },
- { "SETALARM", SYS_SETALARM },
- { "TIMES", SYS_TIMES },
- { "GETINFO", SYS_GETINFO },
- { "SAFECOPYFROM", SYS_SAFECOPYFROM },
- { "SAFECOPYTO", SYS_SAFECOPYTO },
- { "SAFEMAP", SYS_SAFEMAP },
- { "SAFEREVMAP", SYS_SAFEREVMAP },
- { "SAFEUNMAP", SYS_SAFEUNMAP },
- { "VSAFECOPY", SYS_VSAFECOPY },
- { "SETGRANT", SYS_SETGRANT },
{ "READBIOS", SYS_READBIOS },
- { "PROFBUF", SYS_PROFBUF },
{ "STIME", SYS_STIME },
{ "VMCTL", SYS_VMCTL },
- { "SYSCTL", SYS_SYSCTL },
{ NULL, 0 }
};
PRIVATE void do_system(config_t *cpe)
{
- int i, call_nr, word, bits_per_word;
- unsigned long mask;
-
- bits_per_word= sizeof(rs_start.rss_system[0])*8;
+ int i, call_nr;
/* Process a list of 'system' calls that are allowed */
for (; cpe; cpe= cpe->next)
cpe->file, cpe->line);
}
- /* Get call number */
- for (i= 0; system_tab[i].label != NULL; i++)
- {
- if (strcmp(cpe->word, system_tab[i].label) == 0)
+ for (i = 0; system_tab[i].label != NULL; i++)
+ if (!strcmp(cpe->word, system_tab[i].label))
break;
- }
if (system_tab[i].label == NULL)
- {
fatal("do_system: unknown call '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
- }
- call_nr= system_tab[i].call_nr;
-
- /* Subtract KERNEL_CALL */
- if (call_nr < KERNEL_CALL)
- {
- fatal(
- "do_system: bad call number %d in system tab for '%s'",
- call_nr, system_tab[i].label);
- }
- call_nr -= KERNEL_CALL;
-
- word= call_nr / bits_per_word;
- mask= (1UL << (call_nr % bits_per_word));
-
- if (word >= RS_SYS_CALL_MASK_SIZE)
- {
- fatal(
- "RS_SYS_CALL_MASK_SIZE is too small (%d needed)",
- word+1);
- }
- rs_start.rss_system[word] |= mask;
+ SET_BIT(rs_start.rss_system, system_tab[i].call_nr - KERNEL_CALL);
}
}
*/
request = parse_arguments(argc, argv);
- if(req_path) {
- /* Obtain binary name. */
- progname = strrchr(req_path, '/');
- assert(progname); /* an absolute path was required */
- progname++; /* skip last slash */
- }
-
/* Arguments seem fine. Try to perform the request. Only valid requests
* should end up here. The default is used for not yet supported requests.
*/
+ result = OK;
switch(request) {
+ case RS_UPDATE:
+ m.RS_LU_STATE = req_lu_state;
+ m.RS_LU_PREPARE_MAXTIME = req_lu_maxtime;
+ /* fall through */
case RS_UP:
/* Build space-separated command string to be passed to RS server. */
+ progname = strrchr(req_path, '/');
+ assert(progname); /* an absolute path was required */
+ progname++; /* skip last slash */
strcpy(command, req_path);
command[strlen(req_path)] = ' ';
strcpy(command+strlen(req_path)+1, req_args);
}
m.RS_CMD_ADDR = (char *) &rs_start;
-
- /* Build request message and send the request. */
- if (_syscall(RS_PROC_NR, request, &m) == -1)
- failure();
- else if(req_printep)
- printf("%d\n", m.RS_ENDPOINT);
- result = m.m_type;
break;
-
case RS_DOWN:
case RS_REFRESH:
case RS_RESTART:
m.RS_CMD_ADDR = req_label;
m.RS_CMD_LEN = strlen(req_label);
- if (_syscall(RS_PROC_NR, request, &m) == -1)
- failure();
break;
case RS_SHUTDOWN:
- if (_syscall(RS_PROC_NR, request, &m) == -1)
- failure();
- break;
- case RS_UPDATE:
- m.RS_CMD_ADDR = req_label;
- m.RS_CMD_LEN = strlen(req_label);
- m.RS_LU_STATE = req_lu_state;
- m.RS_LU_PREPARE_MAXTIME = req_prepare_maxtime;
- if (_syscall(RS_PROC_NR, request, &m) == -1)
- failure();
break;
default:
print_usage(argv[ARG_NAME], "request is not yet supported");
result = EGENERIC;
}
+
+ /* Build request message and send the request. */
+ if(result == OK) {
+ if (_syscall(RS_PROC_NR, request, &m) == -1)
+ failure();
+ result = m.m_type;
+ }
+
return(result);
}
* Calls are unordered lists, converted by RS to bitmasks
* once at runtime.
*/
-#define FS_KC SYS_KILL, SYS_VIRCOPY, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, \
- SYS_UMAP, SYS_GETINFO, SYS_EXIT, SYS_TIMES, SYS_SETALARM, \
- SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL, \
- SYS_SAFEMAP, SYS_SAFEREVMAP, SYS_SAFEUNMAP
-#define DRV_KC FS_KC, SYS_SEGCTL, SYS_IRQCTL, SYS_INT86, SYS_DEVIO, \
- SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL
+#define FS_KC SYS_BASIC_CALLS, SYS_TRACE, SYS_UMAP, SYS_VIRCOPY, SYS_KILL
+#define DRV_KC SYS_BASIC_CALLS, SYS_TRACE, SYS_UMAP, SYS_VIRCOPY, SYS_SEGCTL, \
+ SYS_IRQCTL, SYS_INT86, SYS_DEVIO, SYS_SDEVIO, SYS_VDEVIO
PRIVATE int
pm_kc[] = { SYS_ALL_C, SYS_NULL_C },
rs_kc[] = { SYS_ALL_C, SYS_NULL_C },
ds_kc[] = { SYS_ALL_C, SYS_NULL_C },
vm_kc[] = { SYS_ALL_C, SYS_NULL_C },
- tty_kc[] = { DRV_KC, SYS_PHYSCOPY, SYS_ABORT, SYS_IOPENABLE,
+ tty_kc[] = { DRV_KC, SYS_KILL, SYS_PHYSCOPY, SYS_ABORT, SYS_IOPENABLE,
SYS_READBIOS, SYS_NULL_C },
mem_kc[] = { DRV_KC, SYS_PHYSCOPY, SYS_IOPENABLE, SYS_NULL_C},
log_kc[] = { DRV_KC, SYS_NULL_C },
VM_PUSH_SIG, VM_WILLEXIT, VM_ADDDMA, VM_DELDMA, VM_GETDMA,
VM_NOTIFY_SIG, SYS_NULL_C },
vfs_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C },
- rs_vmc[] = { VM_BASIC_CALLS, VM_RS_SET_PRIV, SYS_NULL_C },
+ rs_vmc[] = { VM_BASIC_CALLS, VM_RS_SET_PRIV, VM_RS_UPDATE, SYS_NULL_C },
ds_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C },
vm_vmc[] = { SYS_NULL_C },
tty_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C },
* at boot time.
*/
PUBLIC struct boot_image_priv boot_image_priv_table[] = {
- /*endpoint, label, flags, traps, ipcto, kcalls, vmcalls */
- { RS_PROC_NR, "rs", RSYS_F, RSYS_T, RSYS_M, rs_kc, rs_vmc },
- { VM_PROC_NR, "vm", VM_F, SRV_T, SRV_M, vm_kc, vm_vmc },
- { PM_PROC_NR, "pm", SRV_F, SRV_T, SRV_M, pm_kc, pm_vmc },
- { VFS_PROC_NR, "vfs", SRV_F, SRV_T, SRV_M, vfs_kc, vfs_vmc },
- { DS_PROC_NR, "ds", SRV_F, SRV_T, SRV_M, ds_kc, ds_vmc },
- { TTY_PROC_NR, "tty", SRV_F, SRV_T, SRV_M, tty_kc, tty_vmc },
- { MEM_PROC_NR, "memory", SRV_F, SRV_T, SRV_M, mem_kc, mem_vmc },
- { LOG_PROC_NR, "log", SRV_F, SRV_T, SRV_M, log_kc, log_vmc },
- { MFS_PROC_NR, "fs_imgrd", SRV_F, SRV_T, SRV_M, mfs_kc, mfs_vmc },
- { PFS_PROC_NR, "pfs", SRV_F, SRV_T, SRV_M, pfs_kc, pfs_vmc },
- { INIT_PROC_NR, "init", RUSR_F, RUSR_T, RUSR_M, rusr_kc, rusr_vmc },
- { NULL_BOOT_NR, "", 0, 0, 0, no_kc, no_vmc }
+/*endpoint, label, flags, traps, ipcto, sigmgr, kcalls, vmcalls */
+{RS_PROC_NR, "rs", RSYS_F, RSYS_T, RSYS_M, RSYS_SM, rs_kc, rs_vmc },
+{VM_PROC_NR, "vm", VM_F, SRV_T, SRV_M, SRV_SM, vm_kc, vm_vmc },
+{PM_PROC_NR, "pm", SRV_F, SRV_T, SRV_M, SRV_SM, pm_kc, pm_vmc },
+{VFS_PROC_NR, "vfs", SRV_F, SRV_T, SRV_M, SRV_SM, vfs_kc, vfs_vmc },
+{DS_PROC_NR, "ds", SRV_F, SRV_T, SRV_M, SRV_SM, ds_kc, ds_vmc },
+{TTY_PROC_NR, "tty", SRV_F, SRV_T, SRV_M, SRV_SM, tty_kc, tty_vmc },
+{MEM_PROC_NR, "memory", SRV_F, SRV_T, SRV_M, SRV_SM, mem_kc, mem_vmc },
+{LOG_PROC_NR, "log", SRV_F, SRV_T, SRV_M, SRV_SM, log_kc, log_vmc },
+{MFS_PROC_NR, "fs_imgrd", SRV_F, SRV_T, SRV_M, SRV_SM, mfs_kc, mfs_vmc },
+{PFS_PROC_NR, "pfs", SRV_F, SRV_T, SRV_M, SRV_SM, pfs_kc, pfs_vmc },
+{INIT_PROC_NR, "init", RUSR_F, RUSR_T, RUSR_M, RUSR_SM, rusr_kc, rusr_vmc },
+{NULL_BOOT_NR, "", 0, 0, 0, 0, no_kc, no_vmc }
};
/* Definition of the boot image sys table. */
int flags; /* privilege flags */
short trap_mask; /* allowed system call traps */
int ipc_to; /* send mask protection */
+ endpoint_t sig_mgr; /* signal manager */
int *k_calls; /* allowed kernel calls */
int *vm_calls; /* allowed vm calls */
};
/* Definition of an entry of the system process table. */
struct rproc {
struct rprocpub *r_pub; /* pointer to the corresponding public entry */
+ struct rproc *r_old_rp; /* pointer to the slot with the old version */
+ struct rproc *r_new_rp; /* pointer to the slot with the new version */
+ struct rproc *r_prev_rp; /* pointer to the slot with the prev replica */
+ struct rproc *r_next_rp; /* pointer to the slot with the next replica */
pid_t r_pid; /* process id, -1 if the process is not there */
int r_restarts; /* number of restarts (initially zero) */
clock_t r_alive_tm; /* timestamp of last heartbeat */
clock_t r_stop_tm; /* timestamp of SIGTERM signal */
endpoint_t r_caller; /* RS_LATEREPLY caller */
+ int r_caller_request; /* RS_LATEREPLY caller request */
char r_cmd[MAX_COMMAND_LEN]; /* raw command plus arguments */
- char r_script[MAX_SCRIPT_LEN]; /* name of the restart script executable */
+ char r_args[MAX_COMMAND_LEN]; /* null-separated raw command plus arguments */
char *r_argv[MAX_NR_ARGS+2]; /* parsed arguments vector */
int r_argc; /* number of arguments */
+ char r_script[MAX_SCRIPT_LEN]; /* name of the restart script executable */
char *r_exec; /* Executable image */
size_t r_exec_len; /* Length of image */
uid_t r_uid;
int r_nice;
- u32_t r_call_mask[RS_SYS_CALL_MASK_SIZE];
char r_ipc_list[MAX_IPC_LIST];
int r_nr_control;
char r_control[RS_NR_CONTROL][RS_MAX_LABEL_LEN];
#include "inc.h"
-#include <minix/ds.h>
-
/*===========================================================================*
* init_service *
*===========================================================================*/
return r;
}
-/*===========================================================================*
- * publish_service *
- *===========================================================================*/
-PUBLIC int publish_service(rp)
-struct rproc *rp; /* pointer to process slot */
-{
-/* A new system service has been started. Publish the necessary information. */
- int s;
- struct rprocpub *rpub;
-
- rpub = rp->r_pub;
-
- /* Register its label with DS. */
- s= ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
- if (s != OK) {
- return s;
- }
- if (rs_verbose) {
- printf("RS: publish_service: DS label registration done: %s -> %d\n",
- rpub->label, rpub->endpoint);
- }
-
- return(OK);
-}
-
/*===========================================================================*
* fill_call_mask *
*===========================================================================*/
}
}
+/*===========================================================================*
+ * srv_to_string *
+ *===========================================================================*/
+PUBLIC char* srv_to_string(rp)
+struct rproc *rp; /* pointer to process slot */
+{
+ struct rprocpub *rpub;
+ int slot_nr;
+ char *srv_string;
+ static char srv_string_pool[3][RS_MAX_LABEL_LEN + (DEBUG ? 256 : 64)];
+ static int srv_string_pool_index = 0;
+
+ rpub = rp->r_pub;
+ slot_nr = rp - rproc;
+ srv_string = srv_string_pool[srv_string_pool_index];
+ srv_string_pool_index = (srv_string_pool_index + 1) % 3;
+
+#define srv_str(cmd) ((cmd) == NULL || (cmd)[0] == '\0' ? "_" : (cmd))
+#define srv_ep_str(rp) (itoa((rp)->r_pub->endpoint))
+#define srv_active_str(rp) ((rp)->r_flags & RS_ACTIVE ? "*" : " ")
+#define srv_version_str(rp) ((rp)->r_new_rp || (rp)->r_next_rp ? "-" : \
+ ((rp)->r_old_rp || (rp)->r_prev_rp ? "+" : " "))
+
+#if DEBUG
+ sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d, cmd %s, script %s, proc %s, major %d, style %d, flags 0x%03x, sys_flags 0x%02x)",
+ rpub->label, srv_active_str(rp), srv_version_str(rp),
+ slot_nr, rpub->endpoint, rp->r_pid, srv_str(rp->r_cmd),
+ srv_str(rp->r_script), srv_str(rpub->proc_name), rpub->dev_nr,
+ rpub->dev_style, rp->r_flags, rpub->sys_flags);
+#else
+ sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d)",
+ rpub->label, srv_active_str(rp), srv_version_str(rp),
+ slot_nr, rpub->endpoint, rp->r_pid);
+#endif
+
+ return srv_string;
+}
+
+/*===========================================================================*
+ * reply *
+ *===========================================================================*/
+PUBLIC void reply(who, m_ptr)
+endpoint_t who; /* replyee */
+message *m_ptr; /* reply message */
+{
+ int r; /* send status */
+
+ r = sendnb(who, m_ptr); /* send the message */
+ if (r != OK)
+ printf("RS: unable to send reply to %d: %d\n", who, r);
+}
+
+/*===========================================================================*
+ * late_reply *
+ *===========================================================================*/
+PUBLIC void late_reply(rp, code)
+struct rproc *rp; /* pointer to process slot */
+int code; /* status code */
+{
+/* If a caller is waiting for a reply, unblock it. */
+ struct rprocpub *rpub;
+
+ rpub = rp->r_pub;
+
+ if(rp->r_flags & RS_LATEREPLY) {
+ message m;
+ m.m_type = code;
+ if(rs_verbose)
+ printf("RS: %s late reply %d to %d for request %d\n",
+ srv_to_string(rp), code, rp->r_caller, rp->r_caller_request);
+
+ reply(rp->r_caller, &m);
+ rp->r_flags &= ~RS_LATEREPLY;
+ }
+}
+
+/*===========================================================================*
+ * rs_isokendpt *
+ *===========================================================================*/
+PUBLIC int rs_isokendpt(int endpoint, int *proc)
+{
+ *proc = _ENDPOINT_P(endpoint);
+ if(*proc < -NR_TASKS || *proc >= NR_PROCS)
+ return EINVAL;
+
+ return OK;
+}
+
DT(0, 0, 0, 0, DMAP_MUTABLE, "") /*14 = not used */
DT(1, gen_opcl, gen_io, LOG_PROC_NR, 0, "") /*15 = /dev/klog */
DT(0, no_dev, 0, NONE, DMAP_MUTABLE, "") /*16 = /dev/random*/
- DT(0, 0, 0, 0, DMAP_MUTABLE, "") /*17 = not used */
+ DT(0, no_dev, 0, 0, DMAP_MUTABLE, "") /*17 = /dev/hello */
+ DT(0, 0, 0, 0, DMAP_MUTABLE, "") /*18 = not used */
#endif /* IBM_PC */
};
/* Check for special control messages first. */
if (is_notify(call_nr)) {
- if (who_p == PM_PROC_NR)
- {
- /* Signaled by PM, ignore. */
- }
- else if (who_p == CLOCK)
+ if (who_p == CLOCK)
{
/* Alarm timer expired. Used only for select().
* Check it.
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
break;
case PM_FORK:
- case PM_FORK_NB:
+ case PM_SRV_FORK:
pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID);
- m_out.m_type = (call_nr == PM_FORK) ? PM_FORK_REPLY : PM_FORK_NB_REPLY;
+ m_out.m_type = (call_nr == PM_FORK) ? PM_FORK_REPLY : PM_SRV_FORK_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
break;
no_sys, /* 99 = (cprofile) */
/* THE MINIX3 ABI ENDS HERE */
no_sys, /* 100 = (exec_newmem) */
- no_sys, /* 101 = (fork_nb) */
+ no_sys, /* 101 = (srv_fork) */
no_sys, /* 102 = (exec_restart) */
no_sys, /* 103 = (procstat) */
no_sys, /* 104 = (getprocnr) */
no_sys, /* 108 = (adddma) */
no_sys, /* 109 = (deldma) */
no_sys, /* 110 = (getdma) */
+ no_sys, /* 111 = (srv_kill) */
};
/* This should not fail with "array size is negative": */
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
return OK;
}
-PUBLIC void _exit(int code)
-{
- sys_exit(SELF);
-}
-
-PUBLIC void __exit(int code)
-{
- sys_exit(SELF);
-}
-
-#define _SYSTEM 1
+#define _POSIX_SOURCE 1
+#define _MINIX 1
+#define _SYSTEM 1
#include <minix/callnr.h>
#include <minix/com.h>
#include "../../kernel/config.h"
#include "../../kernel/proc.h"
+#include <signal.h>
+
/* Table of calls and a macro to test for being in range. */
struct {
int (*vmc_func)(message *); /* Call handles message. */
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
+FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
/*===========================================================================*
* main *
{
message msg;
int result, who_e;
+ sigset_t sigset;
/* SEF local startup. */
sef_local_startup();
SANITYCHECK(SCL_DETAIL);
if(msg.m_type & NOTIFY_MESSAGE) {
- switch(msg.m_source) {
- case SYSTEM:
- /* Kernel wants to have memory ranges
- * verified, and/or pagefaults handled.
- */
- do_memory();
- break;
- case HARDWARE:
- do_pagefaults();
- break;
- case PM_PROC_NR:
- /* PM sends a notify() on shutdown, which
- * is OK and we ignore.
- */
- break;
- default:
- /* No-one else should send us notifies. */
- printf("VM: ignoring notify() from %d\n",
- msg.m_source);
- break;
- }
+ /* Unexpected notify(). */
+ printf("VM: ignoring notify() from %d\n", msg.m_source);
continue;
}
who_e = msg.m_source;
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_restart_fail);
+ sef_setcb_init_restart(sef_cb_init_fail);
/* No live update support for now. */
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
/* Let SEF perform startup. */
sef_startup();
}
/* Calls from RS */
CALLMAP(VM_RS_SET_PRIV, do_rs_set_priv);
+ CALLMAP(VM_RS_UPDATE, do_rs_update);
/* Generic calls. */
CALLMAP(VM_REMAP, do_remap);
return(OK);
}
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+PRIVATE void sef_cb_signal_handler(int signo)
+{
+ /* Check for known kernel signals, ignore anything else. */
+ switch(signo) {
+ /* There is a pending memory request from the kernel. */
+ case SIGKMEM:
+ do_memory();
+ break;
+ /* There is a pending page fault request from the kernel. */
+ case SIGKPF:
+ do_pagefaults();
+ break;
+ }
+}
+
/*===========================================================================*
* map_service *
*===========================================================================*/
physr_start_iter(vrs->phys, &iter, offset_s, AVL_EQUAL);
prs = physr_get_iter(&iter);
if(!prs)
- panic("map_memory: no aligned phys region: %d", 0);
+ panic("do_map_memory: no aligned phys region: %d", 0);
/* flag: 0 -> read-only
* 1 -> writable
int r;
if(vm_isokendpt(sour, &p) != OK)
- panic("handle_memory: endpoint wrong: %d", sour);
+ panic("map_memory: bad endpoint: %d", sour);
vms = &vmproc[p];
if(vm_isokendpt(dest, &p) != OK)
- panic("handle_memory: endpoint wrong: %d", dest);
+ panic("map_memory: bad endpoint: %d", dest);
vmd = &vmproc[p];
vrs = map_lookup(vms, virt_s);
map_handle_memory(vms, vrs, offset_s, length, 0);
/* Prepare work. */
- #define map_printregion(x, y) (x = x)
- #define printf(x, y, z) (z = z)
- printf("before clean with offset, length: %d, %d\n", offset_s, length);
- map_printregion(vms, vrs);
clean_phys_regions(vrs, offset_s, length);
- printf("after clean with offset, length: %d, %d\n", offset_s, length);
- map_printregion(vms, vrs);
-
- printf("before clean with offset, length: %d, %d\n", offset_d, length);
- map_printregion(vmd, vrd);
clean_phys_regions(vrd, offset_d, length);
- printf("after clean with offset, length: %d, %d\n", offset_d, length);
- map_printregion(vmd, vrd);
-
rm_phys_regions(vrd, offset_d, length);
- printf("after rm with offset, length: %d, %d\n", offset_d, length);
- map_printregion(vmd, vrd);
/* Map memory. */
r = do_map_memory(vms, vmd, vrs, vrd, offset_s, offset_d, length, flag);
- printf("after map (dst) with offset, length: %d, %d\n", offset_d, length);
- map_printregion(vmd, vrd);
- #undef map_printregion
- #undef printf
return r;
}
/* Use information on the destination process to unmap. */
if(vm_isokendpt(dest, &p) != OK)
- panic("handle_memory: endpoint wrong: %d", dest);
+ panic("unmap_memory: bad endpoint: %d", dest);
vmd = &vmproc[p];
vrd = map_lookup(vmd, virt_d);
physr_start_iter(vrd->phys, &iter, off, AVL_EQUAL);
pr = physr_get_iter(&iter);
if(!pr)
- panic("map_memory: no aligned phys region: %d", 0);
+ panic("unmap_memory: no aligned phys region: %d", 0);
/* Copy the phys block now rather than doing COW. */
end = off + length;
/* rs.c */
_PROTOTYPE(int do_rs_set_priv, (message *m));
+_PROTOTYPE(int do_rs_update, (message *m));
/* queryexit.c */
_PROTOTYPE(int do_query_exit, (message *m));
#include "glo.h"
#include "proto.h"
#include "util.h"
+#include "region.h"
+
+#define LU_DEBUG 0
/*===========================================================================*
* do_rs_set_priv *
return OK;
}
+/*===========================================================================*
+ * do_rs_update *
+ *===========================================================================*/
+PUBLIC int do_rs_update(message *m_ptr)
+{
+ endpoint_t src_e, dst_e;
+ struct vmproc *src_vmp, *dst_vmp;
+ struct vmproc orig_src_vmproc, orig_dst_vmproc;
+ int src_p, dst_p, r;
+ struct vir_region *vr;
+
+ src_e = m_ptr->VM_RS_SRC_ENDPT;
+ dst_e = m_ptr->VM_RS_DST_ENDPT;
+
+ /* Let the kernel do the update first. */
+ r = sys_update(src_e, dst_e);
+ if(r != OK) {
+ return r;
+ }
+
+ /* Lookup slots for source and destination process. */
+ if(vm_isokendpt(src_e, &src_p) != OK) {
+ printf("do_rs_update: bad src endpoint %d\n", src_e);
+ return EINVAL;
+ }
+ src_vmp = &vmproc[src_p];
+ if(vm_isokendpt(dst_e, &dst_p) != OK) {
+ printf("do_rs_update: bad dst endpoint %d\n", dst_e);
+ return EINVAL;
+ }
+ dst_vmp = &vmproc[dst_p];
+
+#if LU_DEBUG
+ printf("do_rs_update: updating %d (%d, %d) into %d (%d, %d)\n",
+ src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
+ dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
+
+ printf("do_rs_update: map_printmap for source before updating:\n");
+ map_printmap(src_vmp);
+ printf("do_rs_update: map_printmap for destination before updating:\n");
+ map_printmap(dst_vmp);
+#endif
+
+ /* Save existing data. */
+ orig_src_vmproc = *src_vmp;
+ orig_dst_vmproc = *dst_vmp;
+
+ /* Swap slots. */
+ *src_vmp = orig_dst_vmproc;
+ *dst_vmp = orig_src_vmproc;
+
+ /* Preserve endpoints and slot numbers. */
+ src_vmp->vm_endpoint = orig_src_vmproc.vm_endpoint;
+ src_vmp->vm_slot = orig_src_vmproc.vm_slot;
+ dst_vmp->vm_endpoint = orig_dst_vmproc.vm_endpoint;
+ dst_vmp->vm_slot = orig_dst_vmproc.vm_slot;
+
+ /* Preserve vir_region's parents. */
+ for(vr = src_vmp->vm_regions; vr; vr = vr->next) {
+ vr->parent = src_vmp;
+ }
+ for(vr = dst_vmp->vm_regions; vr; vr = vr->next) {
+ vr->parent = dst_vmp;
+ }
+
+ /* Adjust page tables. */
+ vm_assert(src_vmp->vm_flags & VMF_HASPT);
+ vm_assert(dst_vmp->vm_flags & VMF_HASPT);
+ pt_bind(&src_vmp->vm_pt, src_vmp);
+ pt_bind(&dst_vmp->vm_pt, dst_vmp);
+ if((r=sys_vmctl(SELF, VMCTL_FLUSHTLB, 0)) != OK) {
+ panic("do_rs_update: VMCTL_FLUSHTLB failed: %d", r);
+ }
+
+#if LU_DEBUG
+ printf("do_rs_update: updated %d (%d, %d) into %d (%d, %d)\n",
+ src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
+ dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
+
+ printf("do_rs_update: map_printmap for source after updating:\n");
+ map_printmap(src_vmp);
+ printf("do_rs_update: map_printmap for destination after updating:\n");
+ map_printmap(dst_vmp);
+#endif
+
+ return OK;
+}
+
r = ds_publish_str(key_str, string, 0);
assert(r == OK);
- r = ds_retrieve_str(key_str, buf, 0);
+ r = ds_retrieve_str(key_str, buf, sizeof(buf)-1);
assert(r == OK && strcmp(string, buf) == 0);
r = ds_delete_str(key_str);
/* Publish a long string. */
r = ds_publish_str(key_str, longstring, 0);
- assert(r == EINVAL);
+ assert(r == OK);
+
+ r = ds_retrieve_str(key_str, buf, sizeof(buf)-1);
+ assert(r == OK && strcmp(string, buf) != 0
+ && strncmp(longstring, buf, sizeof(buf)-1) == 0);
+
+ r = ds_delete_str(key_str);
+ assert(r == OK);
printf("DSTEST: STRING test successful!\n");
}
printf("U32: %d\n", num);
break;
case DSF_TYPE_STR:
- r = ds_retrieve_str(key, string, 0);
+ r = ds_retrieve_str(key, string, sizeof(string)-1);
if(r != OK)
printf("error in ds_retrieve_str.\n");
printf("STR: %s\n", string);
service dstest
{
system
- UMAP
- PRIVCTL
- SAFEMAP
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service subs
{
system
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service requestor
{
system
- SAFECOPYFROM
- SAFECOPYTO
- SAFEMAP
- SAFEREVMAP
- SAFEUNMAP
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service grantor
{
system
- SAFECOPYFROM
- SAFECOPYTO
- SAFEMAP
- SAFEREVMAP
- SAFEUNMAP
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service requestor
{
system
- SAFECOPYFROM
- SAFECOPYTO
- SAFEMAP
- SAFEREVMAP
- SAFEUNMAP
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service grantor
{
system
- SAFECOPYFROM
- SAFECOPYTO
- SAFEMAP
- SAFEREVMAP
- SAFEUNMAP
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service requestor
{
system
- SAFECOPYFROM
- SAFECOPYTO
- SAFEMAP
- SAFEREVMAP
- SAFEUNMAP
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};
service grantor
{
system
- SAFECOPYFROM
- SAFECOPYTO
- SAFEMAP
- SAFEREVMAP
- SAFEUNMAP
- UMAP
- PRIVCTL
- SETGRANT
- GETINFO
- SYSCTL
+ PRIVCTL # 4
+ UMAP # 14
;
uid 0;
};