diff --git a/commands/dhcpd/dhcpd.c b/commands/dhcpd/dhcpd.c index 05b315a41..bd43077ae 100644 --- a/commands/dhcpd/dhcpd.c +++ b/commands/dhcpd/dhcpd.c @@ -673,10 +673,13 @@ int main(int argc, char **argv) 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); @@ -1403,6 +1406,9 @@ int main(int argc, char **argv) } } } - 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; } diff --git a/commands/scripts/DESCRIBE.sh b/commands/scripts/DESCRIBE.sh index 2edba7d95..93b1be347 100755 --- a/commands/scripts/DESCRIBE.sh +++ b/commands/scripts/DESCRIBE.sh @@ -190,6 +190,9 @@ do 16,0) des="pseudo random number generator" dev=urandom ;; + 17,0) + des="hello" dev=hello + ;; BAD,BAD) des= dev= ;; diff --git a/commands/scripts/MAKEDEV.sh b/commands/scripts/MAKEDEV.sh index 915f0f127..a35149864 100755 --- a/commands/scripts/MAKEDEV.sh +++ b/commands/scripts/MAKEDEV.sh @@ -23,7 +23,7 @@ case $#:$1 in 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 <&2 ex=1 diff --git a/commands/scripts/readclock.sh b/commands/scripts/readclock.sh index f53e0d259..97c94c3ef 100644 --- a/commands/scripts/readclock.sh +++ b/commands/scripts/readclock.sh @@ -2,4 +2,4 @@ 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 diff --git a/docs/UPDATING b/docs/UPDATING index 609cb3dd4..59261ce8a 100644 --- a/docs/UPDATING +++ b/docs/UPDATING @@ -1,27 +1,3 @@ -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. @@ -64,3 +40,34 @@ 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 + diff --git a/drivers/Makefile b/drivers/Makefile index c3e9eeeaf..b72054051 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -32,6 +32,7 @@ all install depend clean: cd ./log && $(MAKE) $@ cd ./bios_wini && $(MAKE) $@ cd ./filter && $(MAKE) $@ + cd ./hello && $(MAKE) $@ cd ./random && $(MAKE) $@ cd ./readclock && $(MAKE) $@ cd ./dp8390 && $(MAKE) $@ diff --git a/drivers/amddev/amddev.c b/drivers/amddev/amddev.c index fa2f65c68..16bd92acb 100644 --- a/drivers/amddev/amddev.c +++ b/drivers/amddev/amddev.c @@ -16,6 +16,7 @@ Driver for the AMD Device Exclusion Vector (DEV) #include #include #include +#include #include #include #include @@ -57,12 +58,12 @@ static void init_map(unsigned int ix); 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) { @@ -79,13 +80,7 @@ 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); @@ -109,6 +104,9 @@ PRIVATE void sef_local_startup() 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(); } @@ -156,6 +154,47 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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; @@ -419,47 +458,6 @@ static void del_range(u32_t busaddr, u32_t size) } } -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; diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index e168642ce..47ed78d3c 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -202,7 +202,6 @@ PRIVATE struct driver w_dtab = { 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 */ @@ -213,7 +212,7 @@ PRIVATE struct driver w_dtab = { /* 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) ); @@ -257,9 +256,6 @@ PRIVATE void sef_local_startup() 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(); @@ -267,14 +263,8 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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); } diff --git a/drivers/at_wini/liveupdate.c b/drivers/at_wini/liveupdate.c index 188736886..a048c22b4 100644 --- a/drivers/at_wini/liveupdate.c +++ b/drivers/at_wini/liveupdate.c @@ -19,7 +19,7 @@ EXTERN int w_command; /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -43,9 +43,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/atl2/atl2.c b/drivers/atl2/atl2.c index cd41be48d..8e8f6f2d4 100644 --- a/drivers/atl2/atl2.c +++ b/drivers/atl2/atl2.c @@ -6,7 +6,6 @@ #include "../drivers.h" -#include #include #include #include @@ -1122,33 +1121,6 @@ PRIVATE void atl2_getname(message *m, int instance) 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 * *===========================================================================*/ @@ -1275,6 +1247,36 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * *===========================================================================*/ @@ -1289,6 +1291,9 @@ PRIVATE void sef_local_startup(void) /* No support for live update yet. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -1319,14 +1324,6 @@ int main(int argc, char **argv) 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(); diff --git a/drivers/audio/framework/audio_fw.c b/drivers/audio/framework/audio_fw.c index 0d275ed83..e4d83e71e 100644 --- a/drivers/audio/framework/audio_fw.c +++ b/drivers/audio/framework/audio_fw.c @@ -53,7 +53,6 @@ FORWARD _PROTOTYPE( int msg_ioctl, (message *m_ptr) ); 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) ); @@ -78,7 +77,8 @@ PRIVATE int device_available = 0;/*todo*/ /* 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; @@ -104,9 +104,6 @@ PUBLIC void main(void) 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); @@ -191,6 +188,9 @@ PRIVATE void sef_local_startup() 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(); } @@ -248,10 +248,38 @@ PRIVATE int init_driver(void) { 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; @@ -627,29 +655,6 @@ PRIVATE void msg_status(message *m_ptr) 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) { diff --git a/drivers/audio/framework/liveupdate.c b/drivers/audio/framework/liveupdate.c index 62ee35236..58aa449ec 100644 --- a/drivers/audio/framework/liveupdate.c +++ b/drivers/audio/framework/liveupdate.c @@ -44,7 +44,7 @@ PRIVATE void load_state_info(void) /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -75,9 +75,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/bios_wini/bios_wini.c b/drivers/bios_wini/bios_wini.c index be34a68a9..4088f607f 100644 --- a/drivers/bios_wini/bios_wini.c +++ b/drivers/bios_wini/bios_wini.c @@ -80,7 +80,6 @@ PRIVATE struct driver w_dtab = { 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 */ diff --git a/drivers/dec21140A/dec21140A.c b/drivers/dec21140A/dec21140A.c index 40c19876e..cf5589dbe 100644 --- a/drivers/dec21140A/dec21140A.c +++ b/drivers/dec21140A/dec21140A.c @@ -64,25 +64,10 @@ static char str_DevName[] = "dec21140A:eth#?"; 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 * @@ -93,13 +78,9 @@ int main(int argc, char *argv[]) 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) { @@ -125,9 +106,6 @@ int main(int argc, char *argv[]) } } break; - case PM_PROC_NR: - exit(0); - break; default: printf("ignoring notify from %d\n", m.m_source); break; @@ -152,6 +130,51 @@ int main(int argc, char *argv[]) } } +/*===========================================================================* + * 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; diff --git a/drivers/dp8390/dp8390.c b/drivers/dp8390/dp8390.c index 7e65e741a..08d458876 100644 --- a/drivers/dp8390/dp8390.c +++ b/drivers/dp8390/dp8390.c @@ -134,7 +134,6 @@ _PROTOTYPE( static void dp_reset, (dpeth_t *dep) ); _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, @@ -232,6 +231,7 @@ PRIVATE int handle_hw_intr(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; @@ -257,17 +257,6 @@ int main(int argc, char *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; @@ -310,6 +299,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -350,6 +342,27 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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; im_type = DL_STOP; - m->DL_PORT = port; - do_stop(m); - } - } - } -} - PRIVATE void handle_hw_intr(void) { dpeth_t *dep; @@ -582,6 +564,7 @@ PRIVATE void handle_hw_intr(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 char **env_argv; /* @@ -619,9 +602,6 @@ PUBLIC int main(int argc, char **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); @@ -669,6 +649,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -706,4 +689,24 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 **/ diff --git a/drivers/e1000/e1000.c b/drivers/e1000/e1000.c index cd14b4d90..117784a99 100644 --- a/drivers/e1000/e1000.c +++ b/drivers/e1000/e1000.c @@ -42,7 +42,6 @@ _PROTOTYPE( PRIVATE void e1000_readv_s, (message *mp, int from_int) ); _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) ); @@ -63,6 +62,7 @@ _PROTOTYPE( PRIVATE void mess_reply, (message *req, message *reply) ); /* 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; @@ -94,11 +94,7 @@ int main(int argc, char *argv[]) case HARDWARE: e1000_interrupt(&m); break; - - case PM_PROC_NR: - e1000_signal(); - break; - + case CLOCK: break; } @@ -129,6 +125,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -172,6 +171,19 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * *===========================================================================*/ @@ -851,27 +863,6 @@ message *mp; } } -/*===========================================================================* - * 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 * *===========================================================================*/ diff --git a/drivers/filter/main.c b/drivers/filter/main.c index d13e2db83..6d62a85df 100644 --- a/drivers/filter/main.c +++ b/drivers/filter/main.c @@ -76,6 +76,7 @@ static char *buf_array, *buffer; /* contiguous buffer */ /* 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; @@ -368,28 +369,6 @@ static int parse_arguments(int argc, char *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 * *===========================================================================*/ @@ -413,9 +392,6 @@ int main(int argc, char *argv[]) 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; @@ -461,6 +437,9 @@ PRIVATE void sef_local_startup(void) /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -489,3 +468,21 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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); +} + diff --git a/drivers/filter/util.c b/drivers/filter/util.c index a0f8144cf..ba43eb8eb 100644 --- a/drivers/filter/util.c +++ b/drivers/filter/util.c @@ -96,13 +96,10 @@ static void got_alarm(int sig) *===========================================================================*/ 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. - */ + u32_t system_hz; - signal(SIGALRM, got_alarm); - alarm(secs); - - pause(); + /* Sleep for the given number of seconds. */ + system_hz = sys_hz(); + tickdelay(system_hz * secs); } + diff --git a/drivers/floppy/floppy.c b/drivers/floppy/floppy.c index 9e0d1d49e..6457591b6 100644 --- a/drivers/floppy/floppy.c +++ b/drivers/floppy/floppy.c @@ -264,7 +264,6 @@ FORWARD _PROTOTYPE( void f_reset, (void) ); 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) ); @@ -278,7 +277,6 @@ PRIVATE struct driver f_dtab = { 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, @@ -292,7 +290,8 @@ static phys_bytes floppy_buf_phys; /* 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; @@ -326,6 +325,9 @@ PRIVATE void sef_local_startup(void) 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(); } @@ -365,12 +367,25 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * *===========================================================================*/ @@ -745,7 +760,7 @@ PRIVATE int dma_setup( /* 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); } @@ -834,20 +849,6 @@ PRIVATE void stop_motor(timer_t *tp) 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 * *===========================================================================*/ diff --git a/drivers/floppy/liveupdate.c b/drivers/floppy/liveupdate.c index 0d4d1421a..870a9049a 100644 --- a/drivers/floppy/liveupdate.c +++ b/drivers/floppy/liveupdate.c @@ -22,7 +22,7 @@ EXTERN int last_transfer_opcode; /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -43,9 +43,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/fxp/fxp.c b/drivers/fxp/fxp.c index 59430bb5b..d7e943db3 100644 --- a/drivers/fxp/fxp.c +++ b/drivers/fxp/fxp.c @@ -250,7 +250,6 @@ _PROTOTYPE( static void fxp_check_ints, (fxp_t *fp) ); _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) ); @@ -292,6 +291,7 @@ PRIVATE void handle_hw_intr(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; @@ -317,17 +317,6 @@ int main(int argc, char *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; @@ -368,6 +357,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -415,6 +407,34 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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]; ifxp_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 * *===========================================================================*/ @@ -2604,31 +2624,6 @@ resspeed: ; } -/*===========================================================================* - * fxp_stop * - *===========================================================================*/ -static void fxp_stop() -{ - int i; - port_t port; - fxp_t *fp; - - for (i= 0, fp= &fxp_table[0]; ifxp_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 * *===========================================================================*/ diff --git a/drivers/hello/Makefile b/drivers/hello/Makefile new file mode 100644 index 000000000..addbc5f6c --- /dev/null +++ b/drivers/hello/Makefile @@ -0,0 +1,44 @@ +# +# 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 diff --git a/drivers/hello/hello.c b/drivers/hello/hello.c new file mode 100644 index 000000000..129bceba5 --- /dev/null +++ b/drivers/hello/hello.c @@ -0,0 +1,214 @@ +#include "../drivers.h" +#include "../libdriver/driver.h" +#include +#include +#include +#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; +} + diff --git a/drivers/hello/hello.h b/drivers/hello/hello.h new file mode 100644 index 000000000..5725b3d0c --- /dev/null +++ b/drivers/hello/hello.h @@ -0,0 +1,7 @@ +#ifndef __HELLO_H +#define __HELLO_H + +/** The Hello, World! message. */ +#define HELLO_MESSAGE "Hello, World!\n" + +#endif /* __HELLO_H */ diff --git a/drivers/lance/lance.c b/drivers/lance/lance.c index 9b12b2d7f..26d5456c8 100644 --- a/drivers/lance/lance.c +++ b/drivers/lance/lance.c @@ -121,7 +121,6 @@ _PROTOTYPE( static void do_stop, (message *mp) ); _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 */ @@ -264,6 +263,7 @@ phys_bytes lance_buf_phys; /* 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; /*===========================================================================* @@ -317,17 +317,6 @@ void main( int argc, char **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); } @@ -373,6 +362,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -410,7 +402,34 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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; idr_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; @@ -380,16 +372,6 @@ message *mp; 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 * *============================================================================*/ diff --git a/drivers/libdriver/driver.h b/drivers/libdriver/driver.h index 565be666a..f2956929f 100644 --- a/drivers/libdriver/driver.h +++ b/drivers/libdriver/driver.h @@ -37,7 +37,6 @@ struct driver { 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) ); @@ -63,7 +62,6 @@ _PROTOTYPE( int do_nop, (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) ); diff --git a/drivers/log/liveupdate.c b/drivers/log/liveupdate.c index 793b415d7..474c36655 100644 --- a/drivers/log/liveupdate.c +++ b/drivers/log/liveupdate.c @@ -36,7 +36,7 @@ PRIVATE void load_state_info(void) /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -62,9 +62,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/log/log.c b/drivers/log/log.c index 524253da8..1d553f219 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -29,7 +29,6 @@ FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, u64_t position, 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) ); @@ -44,7 +43,6 @@ PRIVATE struct driver log_dtab = { 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 */ @@ -57,9 +55,10 @@ extern int device_caller; /* 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 * @@ -90,6 +89,9 @@ PRIVATE void sef_local_startup() 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(); } @@ -118,6 +120,17 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * *===========================================================================*/ @@ -395,20 +408,6 @@ message *m_ptr; 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 * *============================================================================*/ diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index 3edf77907..8eaad90e2 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -64,7 +64,6 @@ PRIVATE struct driver m_dtab = { 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, @@ -121,15 +120,9 @@ PRIVATE void sef_local_startup() 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); diff --git a/drivers/memory/ramdisk/rc b/drivers/memory/ramdisk/rc index a03e4a914..6e23c4a13 100644 --- a/drivers/memory/ramdisk/rc +++ b/drivers/memory/ramdisk/rc @@ -5,7 +5,7 @@ exec >/dev/log exec 2>/dev/log exec or_mode != OR_M_ENABLED) + continue; + /* TODO: send a signal to the card to shut it down */ + } + exit(0); +} + /***************************************************************************** * check_int_events * * * @@ -432,25 +443,6 @@ static int do_hard_int(void) { } } - - -/***************************************************************************** - * 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]; ior_mode != OR_M_ENABLED) - continue; - /* TODO: send a signal to the card to shut it down */ - } - exit(0); -} - /***************************************************************************** * or_reset * * * diff --git a/drivers/pci/main.c b/drivers/pci/main.c index 982aff1e5..f96349dac 100644 --- a/drivers/pci/main.c +++ b/drivers/pci/main.c @@ -55,14 +55,7 @@ int main(void) } 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; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 3ac5bcd7a..5c8485c6e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -365,7 +365,7 @@ endpoint_t proc; 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; diff --git a/drivers/printer/liveupdate.c b/drivers/printer/liveupdate.c index b65d61b01..de040947e 100644 --- a/drivers/printer/liveupdate.c +++ b/drivers/printer/liveupdate.c @@ -11,7 +11,7 @@ EXTERN int is_status_msg_expected; /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -34,9 +34,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/printer/printer.c b/drivers/printer/printer.c index 92447c37c..152310a7d 100644 --- a/drivers/printer/printer.c +++ b/drivers/printer/printer.c @@ -111,12 +111,10 @@ FORWARD _PROTOTYPE( void prepare_output, (void) ); 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; @@ -140,9 +138,6 @@ PUBLIC void main(void) 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); @@ -171,53 +166,20 @@ PUBLIC void main(void) *===========================================================================*/ 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 * *===========================================================================*/ diff --git a/drivers/random/main.c b/drivers/random/main.c index 4e383a677..773e37848 100644 --- a/drivers/random/main.c +++ b/drivers/random/main.c @@ -40,7 +40,6 @@ PRIVATE struct driver r_dtab = { 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, diff --git a/drivers/readclock/readclock.c b/drivers/readclock/readclock.c index 140aca50d..c5c30a073 100644 --- a/drivers/readclock/readclock.c +++ b/drivers/readclock/readclock.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -229,32 +228,15 @@ void errmsg(char *s) /* */ /***********************************************************************/ -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; diff --git a/drivers/rtl8139/liveupdate.c b/drivers/rtl8139/liveupdate.c index 19e064132..d6af2684f 100644 --- a/drivers/rtl8139/liveupdate.c +++ b/drivers/rtl8139/liveupdate.c @@ -39,7 +39,7 @@ PRIVATE void load_state_info(void) /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -69,9 +69,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/rtl8139/rtl8139.c b/drivers/rtl8139/rtl8139.c index fddf454b1..fe3f87fab 100644 --- a/drivers/rtl8139/rtl8139.c +++ b/drivers/rtl8139/rtl8139.c @@ -171,7 +171,6 @@ _PROTOTYPE( static void rl_getstat_s, (message *mp) ); _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) ); @@ -195,7 +194,8 @@ PRIVATE u32_t system_hz; /* 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; @@ -243,17 +243,6 @@ int main(int argc, char *argv[]) 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); @@ -299,6 +288,9 @@ PRIVATE void sef_local_startup() 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(); } @@ -351,6 +343,26 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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]; ire_mode != REM_ENABLED) + continue; + rl_outb(rep->re_base_port, RL_CR, 0); + } + exit(0); +} + /*===========================================================================* * check_int_events * *===========================================================================*/ @@ -370,23 +382,6 @@ static void check_int_events(void) } } -/*===========================================================================* - * rtl8139_stop * - *===========================================================================*/ -static void rtl8139_stop() -{ - int i; - re_t *rep; - - for (i= 0, rep= &re_table[0]; ire_mode != REM_ENABLED) - continue; - rl_outb(rep->re_base_port, RL_CR, 0); - } - exit(0); -} - /*===========================================================================* * rtl8139_dump * *===========================================================================*/ diff --git a/drivers/rtl8169/rtl8169.c b/drivers/rtl8169/rtl8169.c index deacc912a..0dd7992b7 100644 --- a/drivers/rtl8169/rtl8169.c +++ b/drivers/rtl8169/rtl8169.c @@ -259,7 +259,6 @@ _PROTOTYPE( static void rl_getstat_s, (message *mp) ); _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) ); @@ -280,6 +279,7 @@ u32_t system_hz; /* 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; @@ -321,17 +321,6 @@ int main(int argc, char *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); } @@ -364,6 +353,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -409,6 +401,26 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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; @@ -466,23 +478,6 @@ static void check_int_events(void) } } -/*===========================================================================* - * 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; diff --git a/drivers/sb16/sb16_dsp.c b/drivers/sb16/sb16_dsp.c index 26722e661..7e9a1bf41 100644 --- a/drivers/sb16/sb16_dsp.c +++ b/drivers/sb16/sb16_dsp.c @@ -79,7 +79,7 @@ PRIVATE int reviveProcNr; /* 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; @@ -108,8 +108,6 @@ PUBLIC void main() case HARDWARE: dsp_hardware_msg(); continue; /* don't reply */ - case SYSTEM: - continue; /* don't reply */ default: r = EINVAL; } diff --git a/drivers/sb16/sb16_dsp_liveupdate.c b/drivers/sb16/sb16_dsp_liveupdate.c index 83f915c56..94a3583b9 100644 --- a/drivers/sb16/sb16_dsp_liveupdate.c +++ b/drivers/sb16/sb16_dsp_liveupdate.c @@ -12,7 +12,7 @@ EXTERN int is_status_msg_expected; /*===========================================================================* * sef_cb_lu_prepare * *===========================================================================*/ -PUBLIC void sef_cb_lu_prepare(int state) +PUBLIC int sef_cb_lu_prepare(int state) { int is_ready; @@ -35,9 +35,7 @@ PUBLIC void sef_cb_lu_prepare(int state) } /* Tell SEF if we are ready. */ - if(is_ready) { - sef_lu_ready(OK); - } + return is_ready ? OK : ENOTREADY; } /*===========================================================================* diff --git a/drivers/tty/console.c b/drivers/tty/console.c index 8e1cbcb30..816bd6283 100644 --- a/drivers/tty/console.c +++ b/drivers/tty/console.c @@ -1063,8 +1063,7 @@ PUBLIC void kputc(int c) /*===========================================================================* * 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 */ diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index dbe450806..3cbec48e6 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -100,7 +100,6 @@ unsigned long rs_irq_set = 0; 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) ); @@ -144,6 +143,7 @@ PUBLIC u32_t system_hz; /* 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 * @@ -203,16 +203,6 @@ PUBLIC int main(void) /* 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; @@ -328,6 +318,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -355,21 +348,21 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) } /*===========================================================================* - * 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; + } } /*===========================================================================* diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index e60978109..71d0bd410 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -165,7 +165,7 @@ _PROTOTYPE( void rs_interrupt, (message *m) ); /* 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) ); diff --git a/etc/rs.inet b/etc/rs.inet index c0d1058c9..9ebb3af62 100755 --- a/etc/rs.inet +++ b/etc/rs.inet @@ -56,12 +56,13 @@ disabled() 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 + diff --git a/etc/system.conf b/etc/system.conf index 7123e51b4..d99d97d02 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -10,13 +10,6 @@ service floppy IRQCTL # 19 DEVIO # 21 VDEVIO # 23 - SETALARM # 24 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - PROFBUF # 38 - SYSCTL # 44 ; }; @@ -26,14 +19,6 @@ service dp8390 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; @@ -45,14 +30,6 @@ service dpeth IRQCTL # 19 DEVIO # 21 SDEVIO # 22 - SETALARM # 24 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - SETGRANT # 34 - PROFBUF # 38 - SYSCTL # 44 ; uid 0; }; @@ -63,14 +40,6 @@ service lance 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; @@ -82,15 +51,6 @@ service rtl8139 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; @@ -121,15 +81,6 @@ service fxp 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; @@ -143,61 +94,26 @@ service fxp 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 ; @@ -212,13 +128,6 @@ service pci system PRIVCTL # 4 DEVIO # 21 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - SETGRANT # 34 - PROFBUF # 38 - SYSCTL # 44 ; uid 0; }; @@ -240,15 +149,7 @@ service at_wini 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 @@ -261,58 +162,25 @@ service bios_wini 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 ; @@ -333,13 +201,6 @@ service printer IRQCTL # 19 DEVIO # 21 VDEVIO # 23 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - SETGRANT # 34 - PROFBUF # 38 - SYSCTL # 44 ; }; @@ -350,16 +211,7 @@ service orinoco 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; @@ -372,13 +224,6 @@ service es1370 UMAP # 14 IRQCTL # 19 DEVIO # 21 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - SETGRANT # 34 - PROFBUF # 38 - SYSCTL # 44 ; pci device 1274/5000; }; @@ -386,16 +231,9 @@ service es1370 service es1371 { system - SAFECOPYFROM - SAFECOPYTO - UMAP - SETGRANT - TIMES # 25 - GETINFO + UMAP # 14 IRQCTL # 19 DEVIO # 21 - PROFBUF # 38 - SYSCTL ; pci device 1274/1371; }; @@ -405,12 +243,6 @@ service amddev pci device 1022/1103; system UMAP # 14 - TIMES # 25 - GETINFO # 26 - SETGRANT # 34 - PROFBUF # 38 - REGDEV # 40 - SYSCTL # 44 ; uid 0; }; @@ -419,14 +251,7 @@ service ipc { system UMAP # 14 - VIRCOPY # 15 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - SETGRANT # 34 - PROFBUF # 38 - SYSCTL # 44 + VIRCOPY # 15 ; uid 0; ipc @@ -456,14 +281,6 @@ service osscore 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 @@ -481,15 +298,6 @@ service rtl8169 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; @@ -507,15 +315,6 @@ service rtl8169 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 @@ -533,13 +332,6 @@ service e1000 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; @@ -554,13 +346,6 @@ service atl2 system UMAP # 14 IRQCTL # 19 - SETALARM # 24 - TIMES # 25 - GETINFO # 26 - SAFECOPYFROM # 31 - SAFECOPYTO # 32 - SETGRANT # 34 - SYSCTL # 44 ; pci device 1969/2048; ipc @@ -575,15 +360,6 @@ service dec21140A 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 @@ -591,3 +367,17 @@ service dec21140A pci inet ; }; + +service hello +{ + system + IRQCTL # 19 + DEVIO # 21 + ; + ipc + SYSTEM PM RS LOG TTY DS VM VFS + pci inet amddev + ; + uid 0; +}; + diff --git a/include/errno.h b/include/errno.h index 3a252cae6..9903f8639 100644 --- a/include/errno.h +++ b/include/errno.h @@ -74,7 +74,7 @@ extern int errno; /* place where the error numbers go */ #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 */ diff --git a/include/minix/callnr.h b/include/minix/callnr.h index a4d28ef0a..3dcd8311f 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -1,4 +1,4 @@ -#define NCALLS 111 /* number of system calls allowed */ +#define NCALLS 112 /* number of system calls allowed */ #define EXIT 1 #define FORK 2 @@ -93,7 +93,7 @@ #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 */ @@ -109,6 +109,7 @@ * 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. diff --git a/include/minix/com.h b/include/minix/com.h index 3642e3fac..3a13fcb55 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -19,6 +19,7 @@ * 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. @@ -305,7 +306,7 @@ # 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() */ @@ -358,9 +359,20 @@ # 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 */ @@ -631,6 +643,10 @@ #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 * *===========================================================================*/ @@ -689,7 +705,6 @@ # 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 * @@ -732,7 +747,7 @@ #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 */ @@ -745,7 +760,7 @@ #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) @@ -755,7 +770,7 @@ /* 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 */ @@ -776,7 +791,7 @@ /* 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 */ @@ -813,6 +828,8 @@ * Miscellaneous field names * *===========================================================================*/ +#define COMMON_RQ_BASE 0xE00 + /* PM field names */ /* BRK */ #define PMBRK_ADDR m1_p1 @@ -835,6 +852,10 @@ #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 * *===========================================================================*/ @@ -974,8 +995,12 @@ #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. */ diff --git a/include/minix/dmap.h b/include/minix/dmap.h index 11598ad84..5e44b4a06 100644 --- a/include/minix/dmap.h +++ b/include/minix/dmap.h @@ -45,4 +45,6 @@ enum dev_style { STYLE_DEV, STYLE_NDEV, STYLE_TTY, STYLE_CLONE }; #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 */ diff --git a/include/minix/ds.h b/include/minix/ds.h index fd9f42296..e33743a00 100644 --- a/include/minix/ds.h +++ b/include/minix/ds.h @@ -29,7 +29,6 @@ /* 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 */ diff --git a/include/minix/rs.h b/include/minix/rs.h index ae784485a..a508de847 100644 --- a/include/minix/rs.h +++ b/include/minix/rs.h @@ -22,7 +22,6 @@ Interface to the reincarnation server #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 @@ -55,7 +54,7 @@ struct rs_start 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; diff --git a/include/minix/safecopies.h b/include/minix/safecopies.h index 0f237844b..4f0c92c8f 100644 --- a/include/minix/safecopies.h +++ b/include/minix/safecopies.h @@ -4,6 +4,7 @@ #include #include +#include #include typedef struct { @@ -47,13 +48,6 @@ struct vscp_vec { 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) diff --git a/include/minix/sef.h b/include/minix/sef.h index 7c07adf07..9883f92b9 100644 --- a/include/minix/sef.h +++ b/include/minix/sef.h @@ -8,6 +8,7 @@ /* 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 @@ -29,30 +30,27 @@ typedef struct { } 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 */ @@ -79,15 +77,15 @@ _PROTOTYPE( int sef_cb_init_restart_fail, (int type, sef_init_info_t *info) ); && (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 @@ -113,31 +111,30 @@ _PROTOTYPE( void sef_cb_ping_reply_pong, (message *m_ptr) ); #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. */ @@ -145,13 +142,13 @@ _PROTOTYPE( int sef_cb_lu_state_isvalid_standard, (int state) ); #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 */ @@ -173,5 +170,47 @@ _PROTOTYPE( int sef_cb_lu_state_isvalid_standard, (int 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 */ diff --git a/include/minix/syslib.h b/include/minix/syslib.h index a11b82159..bfad9ff6e 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -40,7 +40,8 @@ _PROTOTYPE( int sys_exec, (endpoint_t proc_ep, char *ptr, _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. */ @@ -49,6 +50,7 @@ _PROTOTYPE( int sys_trace, (int req, endpoint_t proc_ep, long addr, long *data_p #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)); diff --git a/include/minix/vm.h b/include/minix/vm.h index 3755dfa96..121acd014 100644 --- a/include/minix/vm.h +++ b/include/minix/vm.h @@ -25,8 +25,16 @@ _PROTOTYPE( int vm_unmap_phys, (endpoint_t who, void *vaddr, size_t len)); _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 */ diff --git a/include/signal.h b/include/signal.h index 5d701e659..642b41ff7 100644 --- a/include/signal.h +++ b/include/signal.h @@ -63,10 +63,26 @@ typedef unsigned long sigset_t; /* 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 @@ -79,7 +95,6 @@ typedef void _PROTOTYPE( (*__sighandler_t), (int) ); #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 { diff --git a/kernel/arch/i386/exception.c b/kernel/arch/i386/exception.c index 7e9538300..b1e22a85c 100644 --- a/kernel/arch/i386/exception.c +++ b/kernel/arch/i386/exception.c @@ -91,7 +91,7 @@ void pagefault( struct proc *pr, pr->p_nextpagefault = pagefaults; pagefaults = pr; - mini_notify(proc_addr(HARDWARE), VM_PROC_NR); + send_sig(VM_PROC_NR, SIGKPF); return; } diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 1a6b2e11a..2da9f1732 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -577,7 +578,7 @@ PRIVATE void vm_suspend(struct proc *caller, struct proc *target, /* 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; } diff --git a/kernel/config.h b/kernel/config.h index ef6f2897e..02834ea72 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -18,7 +18,8 @@ #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 */ @@ -42,6 +43,7 @@ #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 diff --git a/kernel/interrupt.c b/kernel/interrupt.c index a61331a52..328a404fb 100644 --- a/kernel/interrupt.c +++ b/kernel/interrupt.c @@ -56,7 +56,7 @@ PUBLIC void put_irq_handler( irq_hook_t* hook, int irq, irq_handler_t handler) 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. @@ -78,25 +78,30 @@ PUBLIC void rm_irq_handler( irq_hook_t* hook ) { 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. */ } /*===========================================================================* @@ -115,6 +120,13 @@ PUBLIC void irq_handle(int irq) 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, diff --git a/kernel/main.c b/kernel/main.c index 450f5a704..daf0989c2 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -114,6 +114,7 @@ PUBLIC void main() 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 { diff --git a/kernel/priv.h b/kernel/priv.h index b4bd9c886..42e626986 100644 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -41,8 +41,9 @@ struct priv { 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 */ @@ -150,4 +151,8 @@ EXTERN struct priv *ppriv_addr[NR_SYS_PROCS]; /* direct slot pointers */ #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 */ diff --git a/kernel/proc.h b/kernel/proc.h index 8f67988ad..319dadd5e 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -45,8 +45,8 @@ struct proc { 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 */ diff --git a/kernel/system.c b/kernel/system.c index e7e4bea5c..deb2dae1b 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -15,7 +15,7 @@ * 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 @@ -176,17 +176,19 @@ PUBLIC void system_init(void) /* 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 */ @@ -347,27 +349,38 @@ int sig_nr; /* signal to be sent */ * - 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); } } } @@ -385,7 +398,7 @@ struct proc *rp; rp->p_misc_flags &= ~MF_SIG_DELAY; - cause_sig(proc_nr(rp), SIGNDELAY); + cause_sig(proc_nr(rp), SIGKNDELAY); } #if _MINIX_CHIP == _CHIP_INTEL diff --git a/kernel/system.h b/kernel/system.h index 951b4ea6a..8c31c504f 100644 --- a/kernel/system.h +++ b/kernel/system.h @@ -8,6 +8,7 @@ * 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) @@ -53,9 +54,9 @@ _PROTOTYPE( int do_newmap, (struct proc * caller, message *m_ptr) ); #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) ); @@ -73,6 +74,16 @@ _PROTOTYPE( int do_runctl, (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) diff --git a/kernel/system/Makefile b/kernel/system/Makefile index 8ddd1af7a..026947159 100644 --- a/kernel/system/Makefile +++ b/kernel/system/Makefile @@ -27,10 +27,12 @@ OBJECTS = \ 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 \ diff --git a/kernel/system/do_abort.c b/kernel/system/do_abort.c index 935568b2b..60676515b 100644 --- a/kernel/system/do_abort.c +++ b/kernel/system/do_abort.c @@ -19,7 +19,7 @@ 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; diff --git a/kernel/system/do_clear.c b/kernel/system/do_clear.c new file mode 100644 index 000000000..31682b36d --- /dev/null +++ b/kernel/system/do_clear.c @@ -0,0 +1,75 @@ +/* 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 + +#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 */ + diff --git a/kernel/system/do_endksig.c b/kernel/system/do_endksig.c index 1b09b894c..cd1acaf62 100644 --- a/kernel/system/do_endksig.c +++ b/kernel/system/do_endksig.c @@ -15,8 +15,8 @@ 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; @@ -28,9 +28,10 @@ PUBLIC int do_endksig(struct proc * caller, message * m_ptr) 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); diff --git a/kernel/system/do_exit.c b/kernel/system/do_exit.c index 277333a0f..2970a7eb5 100644 --- a/kernel/system/do_exit.c +++ b/kernel/system/do_exit.c @@ -1,91 +1,27 @@ /* 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 +#include #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; + int sig_nr = SIGABRT; - /* 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 */ - } - } + cause_sig(caller->p_nr, sig_nr); /* send a signal to the caller */ - /* 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; - - /* 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(EDONTREPLY); /* don't reply */ } #endif /* USE_EXIT */ diff --git a/kernel/system/do_getksig.c b/kernel/system/do_getksig.c index 7c05c83b8..1416113db 100644 --- a/kernel/system/do_getksig.c +++ b/kernel/system/do_getksig.c @@ -17,21 +17,20 @@ *===========================================================================*/ 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); } diff --git a/kernel/system/do_kill.c b/kernel/system/do_kill.c index 04758a860..c6ace6842 100644 --- a/kernel/system/do_kill.c +++ b/kernel/system/do_kill.c @@ -16,13 +16,11 @@ *===========================================================================*/ 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; @@ -33,10 +31,9 @@ PUBLIC int do_kill(struct proc * caller, message * m_ptr) 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); } diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index 11568811d..0fcdaba67 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -111,6 +111,9 @@ PUBLIC int do_privctl(struct proc * caller, message * m_ptr) 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 */ @@ -123,8 +126,9 @@ PUBLIC int do_privctl(struct proc * caller, message * m_ptr) /* 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) { diff --git a/kernel/system/do_runctl.c b/kernel/system/do_runctl.c index d3ba0890d..fb0a70558 100644 --- a/kernel/system/do_runctl.c +++ b/kernel/system/do_runctl.c @@ -19,7 +19,7 @@ PUBLIC int do_runctl(struct proc * caller, message * m_ptr) /* 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; diff --git a/kernel/system/do_safemap.c b/kernel/system/do_safemap.c index f442293bc..32dc2ebe9 100644 --- a/kernel/system/do_safemap.c +++ b/kernel/system/do_safemap.c @@ -13,11 +13,13 @@ #include +#include #include #include #include "../system.h" +#include struct map_info_s { int flag; @@ -161,7 +163,7 @@ PUBLIC int map_invoke_vm(struct proc * caller, /* 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; diff --git a/kernel/system/do_update.c b/kernel/system/do_update.c new file mode 100644 index 000000000..ef43407cd --- /dev/null +++ b/kernel/system/do_update.c @@ -0,0 +1,165 @@ +/* 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 + +#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 */ + diff --git a/lib/libc/ansi/errlist.c b/lib/libc/ansi/errlist.c index 605a2f7ca..1bdec1a22 100644 --- a/lib/libc/ansi/errlist.c +++ b/lib/libc/ansi/errlist.c @@ -48,7 +48,7 @@ const char *_sys_errlist[] = { "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 */ diff --git a/lib/libc/other/Makefile.inc b/lib/libc/other/Makefile.inc index 04e56303d..56f6da8f9 100644 --- a/lib/libc/other/Makefile.inc +++ b/lib/libc/other/Makefile.inc @@ -33,6 +33,7 @@ SRCS+= \ _sysuname.c \ _vm_dmacalls.c \ _vm_set_priv.c \ + _vm_update.c \ _vm_query_exit.c \ asynchio.c \ basename.c \ diff --git a/lib/libc/other/_vm_update.c b/lib/libc/other/_vm_update.c new file mode 100644 index 000000000..12b623115 --- /dev/null +++ b/lib/libc/other/_vm_update.c @@ -0,0 +1,12 @@ +#include +#define vm_update _vm_update +#include + +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); +} diff --git a/lib/libc/syscall/Makefile.inc b/lib/libc/syscall/Makefile.inc index b67470550..f4993c4f1 100644 --- a/lib/libc/syscall/Makefile.inc +++ b/lib/libc/syscall/Makefile.inc @@ -74,6 +74,7 @@ SRCS+= \ vm_remap.S \ vm_unmap.S \ vm_set_priv.S \ + vm_update.S \ vm_query_exit.S \ mount.S \ nanosleep.S \ diff --git a/lib/libc/syscall/vm_update.S b/lib/libc/syscall/vm_update.S new file mode 100644 index 000000000..3f8c7149c --- /dev/null +++ b/lib/libc/syscall/vm_update.S @@ -0,0 +1,7 @@ +.text +.extern __vm_update +.globl _vm_update +.balign 2 + +_vm_update: + jmp __vm_update diff --git a/lib/libsys/Makefile b/lib/libsys/Makefile index dc408dbc1..0965e732a 100644 --- a/lib/libsys/Makefile +++ b/lib/libsys/Makefile @@ -29,10 +29,12 @@ SRCS= \ 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 \ @@ -53,6 +55,7 @@ SRCS= \ sys_physcopy.c \ sys_readbios.c \ sys_runctl.c \ + sys_update.c \ sys_safecopy.c \ sys_safemap.c \ sys_sysctl.c \ diff --git a/lib/libsys/ds.c b/lib/libsys/ds.c index 491a61785..948579a87 100644 --- a/lib/libsys/ds.c +++ b/lib/libsys/ds.c @@ -49,16 +49,8 @@ int ds_publish_u32(const char *ds_name, u32_t value, int flags) 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; @@ -70,7 +62,7 @@ int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags) 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); @@ -78,6 +70,19 @@ int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags) 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; @@ -97,7 +102,6 @@ int ds_publish_map(const char *ds_name, void *vaddr, size_t length, int flags) m.DS_FLAGS = DSF_TYPE_MAP | flags; r = do_invoke_ds(DS_PUBLISH, ds_name); - cpf_revoke(gid); return r; } @@ -136,17 +140,8 @@ int ds_retrieve_u32(const char *ds_name, u32_t *value) 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; @@ -158,7 +153,7 @@ int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length) 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); @@ -166,6 +161,20 @@ int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length) 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) { diff --git a/lib/libsys/sef.c b/lib/libsys/sef.c index 50e1eeb48..7dd784940 100644 --- a/lib/libsys/sef.c +++ b/lib/libsys/sef.c @@ -5,8 +5,8 @@ /* 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 @@ -22,19 +22,22 @@ PUBLIC _PROTOTYPE( char* sef_debug_header, (void) ); 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. */ @@ -63,7 +66,7 @@ PUBLIC void sef_startup() } } else { - panic("unable to receive init request"); + panic("got an unexpected message type %d", m.m_type); } } #endif @@ -74,7 +77,7 @@ PUBLIC void sef_startup() *===========================================================================*/ 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) { @@ -108,6 +111,15 @@ PUBLIC int sef_receive(endpoint_t src, message *m_ptr) } #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. */ @@ -117,6 +129,46 @@ PUBLIC int sef_receive(endpoint_t src, message *m_ptr) 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 * *===========================================================================*/ diff --git a/lib/libsys/sef_init.c b/lib/libsys/sef_init.c index 4b1671a02..1c7904a7d 100644 --- a/lib/libsys/sef_init.c +++ b/lib/libsys/sef_init.c @@ -4,9 +4,9 @@ /* 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, @@ -67,11 +67,9 @@ PUBLIC int do_sef_init_request(message *m_ptr) 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; } @@ -79,7 +77,7 @@ PUBLIC int do_sef_init_request(message *m_ptr) /*===========================================================================* * 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; @@ -88,7 +86,7 @@ PUBLIC void sef_setcb_init_fresh(sef_cb_init_fresh_t 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; @@ -97,44 +95,36 @@ PUBLIC void sef_setcb_init_lu(sef_cb_init_lu_t 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); -} - -/*===========================================================================* - * sef_cb_init_restart_fail * - *===========================================================================*/ -PUBLIC int sef_cb_init_restart_fail(int UNUSED(type), - sef_init_info_t *UNUSED(info)) -{ - return(ENOSYS); + panic("Simulating a crash at initialization time..."); + + return OK; } diff --git a/lib/libsys/sef_liveupdate.c b/lib/libsys/sef_liveupdate.c index 4bf894492..553447f61 100644 --- a/lib/libsys/sef_liveupdate.c +++ b/lib/libsys/sef_liveupdate.c @@ -11,19 +11,22 @@ PRIVATE struct sef_cbs { 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; @@ -34,6 +37,7 @@ 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) { @@ -53,11 +57,12 @@ PUBLIC void do_sef_lu_before_receive() /* 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); } } @@ -67,19 +72,28 @@ PUBLIC void do_sef_lu_before_receive() 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. @@ -96,10 +110,10 @@ PUBLIC int do_sef_lu_request(message *m_ptr) /*===========================================================================* * 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(); @@ -109,28 +123,33 @@ PUBLIC void sef_lu_ready(int result) 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 @@ -181,19 +200,20 @@ PUBLIC void sef_setcb_lu_state_dump(sef_cb_lu_state_dump_t cb) } /*===========================================================================* - * 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; } /*===========================================================================* @@ -221,19 +241,44 @@ PUBLIC void sef_cb_lu_state_dump_null(int UNUSED(state)) } /*===========================================================================* - * 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)) { - sef_lu_ready(OK); + return OK; +} + +/*===========================================================================* + * sef_cb_lu_prepare_never_ready * + *===========================================================================*/ +PUBLIC int sef_cb_lu_prepare_never_ready(int UNUSED(state)) +{ +#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; } /*===========================================================================* diff --git a/lib/libsys/sef_ping.c b/lib/libsys/sef_ping.c index 648ccb1c8..6c30a6172 100644 --- a/lib/libsys/sef_ping.c +++ b/lib/libsys/sef_ping.c @@ -31,7 +31,7 @@ PUBLIC int do_sef_ping_request(message *m_ptr) #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); @@ -49,15 +49,15 @@ PUBLIC void sef_setcb_ping_reply(sef_cb_ping_reply_t cb) /*===========================================================================* * 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); } diff --git a/lib/libsys/sef_signal.c b/lib/libsys/sef_signal.c new file mode 100644 index 000000000..9d88938d9 --- /dev/null +++ b/lib/libsys/sef_signal.c @@ -0,0 +1,196 @@ +#include "syslib.h" +#include +#include +#include + +/* 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; + } +} + diff --git a/lib/libsys/sys_clear.c b/lib/libsys/sys_clear.c new file mode 100644 index 000000000..68a6a720b --- /dev/null +++ b/lib/libsys/sys_clear.c @@ -0,0 +1,15 @@ +#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)); +} diff --git a/lib/libsys/sys_exit.c b/lib/libsys/sys_exit.c index bc1acad8a..88e95acd4 100644 --- a/lib/libsys/sys_exit.c +++ b/lib/libsys/sys_exit.c @@ -3,15 +3,10 @@ /*===========================================================================* * 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)); } diff --git a/lib/libsys/sys_update.c b/lib/libsys/sys_update.c new file mode 100644 index 000000000..c93845b62 --- /dev/null +++ b/lib/libsys/sys_update.c @@ -0,0 +1,11 @@ +#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); +} diff --git a/man/man2/intro.2 b/man/man2/intro.2 index a7d1f4639..e16b2039d 100644 --- a/man/man2/intro.2 +++ b/man/man2/intro.2 @@ -229,7 +229,7 @@ A directory with entries other than \*(lq.\*(rq and \*(lq..\*(rq 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 diff --git a/servers/ds/inc.h b/servers/ds/inc.h index 6f433e727..c1bf05ace 100644 --- a/servers/ds/inc.h +++ b/servers/ds/inc.h @@ -3,8 +3,9 @@ /* 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 #include diff --git a/servers/ds/main.c b/servers/ds/main.c index 64f7c521b..1efe80585 100644 --- a/servers/ds/main.c +++ b/servers/ds/main.c @@ -16,8 +16,6 @@ PRIVATE endpoint_t who_e; /* caller's proc number */ 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) ); @@ -47,18 +45,9 @@ PUBLIC int main(int argc, char **argv) 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) { @@ -108,7 +97,7 @@ PRIVATE void 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. */ @@ -116,34 +105,6 @@ PRIVATE void sef_local_startup() 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 * *===========================================================================*/ diff --git a/servers/ds/store.c b/servers/ds/store.c index 2adf376fe..76e1efde4 100644 --- a/servers/ds/store.c +++ b/servers/ds/store.c @@ -129,10 +129,13 @@ PRIVATE endpoint_t ds_getprocep(char *s) 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); } /*===========================================================================* @@ -237,7 +240,7 @@ PRIVATE int map_service(struct rprocpub *rpub) /* 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. */ @@ -286,10 +289,16 @@ PUBLIC int do_publish(message *m_ptr) { 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; @@ -324,9 +333,6 @@ PUBLIC int do_publish(message *m_ptr) 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. */ @@ -351,6 +357,9 @@ PUBLIC int do_publish(message *m_ptr) 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. */ @@ -377,7 +386,7 @@ PUBLIC int do_publish(message *m_ptr) /* 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. */ @@ -416,8 +425,6 @@ PUBLIC int do_retrieve(message *m_ptr) 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, @@ -631,9 +638,15 @@ PUBLIC int do_delete(message *m_ptr) { 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; @@ -643,14 +656,14 @@ PUBLIC int do_delete(message *m_ptr) 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; @@ -658,7 +671,7 @@ PUBLIC int do_delete(message *m_ptr) /* 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); diff --git a/servers/ds/store.h b/servers/ds/store.h index 6653318ff..1ef271729 100644 --- a/servers/ds/store.h +++ b/servers/ds/store.h @@ -20,7 +20,6 @@ struct data_store { union { unsigned u32; - char string[DS_MAX_STRLEN]; struct { void *data; size_t length; diff --git a/servers/hgfs/main.c b/servers/hgfs/main.c index 89e1e3c64..78c212d6b 100644 --- a/servers/hgfs/main.c +++ b/servers/hgfs/main.c @@ -13,13 +13,10 @@ #include #include +#include -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) }, @@ -32,13 +29,17 @@ PRIVATE struct optset optset_table[] = { { 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; { @@ -86,34 +87,46 @@ sef_init_info_t *info; return OK; } +/*===========================================================================* + * sef_cb_signal_handler * + *===========================================================================*/ +PRIVATE void sef_cb_signal_handler(int signo) +{ + sigset_t set; + int r; + + /* Only check for termination signal, ignore anything else. */ + if (signo != SIGTERM) return; + + if (state.mounted) { + dprintf(("HGFS: got SIGTERM, still mounted\n")); + } + else { + dprintf(("HGFS: got SIGTERM, shutting down\n")); + + /* Pass on the cleanup request to the HGFS library. */ + hgfs_cleanup(); + exit(0); + } +} + /*===========================================================================* * sef_local_startup * *===========================================================================*/ PRIVATE void sef_local_startup() { -/* Specify initialization routines and start the SEF framework. - */ - - sef_setcb_init_fresh(init); - sef_setcb_init_restart(init); + /* Register init callbacks. */ + sef_setcb_init_fresh(sef_cb_init_fresh); + sef_setcb_init_restart(sef_cb_init_fresh); /* No live update support yet. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + sef_startup(); } -/*===========================================================================* - * cleanup * - *===========================================================================*/ -PRIVATE void cleanup() -{ -/* Clean up any resources in use by this file server. Called at shutdown time. - */ - - /* Pass on the cleanup request to the HGFS library. */ - hgfs_cleanup(); -} - /*===========================================================================* * main * *===========================================================================*/ @@ -135,10 +148,6 @@ char *argv[]; 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; } @@ -160,8 +169,6 @@ char *argv[]; send_reply(err); } - cleanup(); - return 0; } @@ -199,34 +206,3 @@ int err; /* resulting error code */ 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; -} diff --git a/servers/inet/inet.c b/servers/inet/inet.c index 4ee2cec23..364c251ee 100644 --- a/servers/inet/inet.c +++ b/servers/inet/inet.c @@ -189,7 +189,7 @@ PRIVATE void 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_fresh); /* No live update support for now. */ @@ -205,10 +205,11 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) /* 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"); @@ -257,9 +258,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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. */ diff --git a/servers/inet/mnx_eth.c b/servers/inet/mnx_eth.c index 2f9055095..0ffd969be 100644 --- a/servers/inet/mnx_eth.c +++ b/servers/inet/mnx_eth.c @@ -462,7 +462,9 @@ PUBLIC void eth_rec(message *m) } 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)) @@ -899,12 +901,6 @@ int tasknr; 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) diff --git a/servers/ipc/inc.h b/servers/ipc/inc.h index 38138a411..7a2829b27 100644 --- a/servers/ipc/inc.h +++ b/servers/ipc/inc.h @@ -1,5 +1,6 @@ -#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 #include @@ -25,6 +26,7 @@ #include #include #include +#include _PROTOTYPE( int do_shmget, (message *) ); _PROTOTYPE( int do_shmat, (message *) ); diff --git a/servers/ipc/main.c b/servers/ipc/main.c index 2800a74c9..e88b700a9 100644 --- a/servers/ipc/main.c +++ b/servers/ipc/main.c @@ -26,6 +26,7 @@ PRIVATE int verbose = 0; /* 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[]) { @@ -49,14 +50,6 @@ 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(); @@ -114,6 +107,9 @@ PRIVATE void sef_local_startup() /* No live update support for now. */ + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + /* Let SEF perform startup. */ sef_startup(); } @@ -133,3 +129,16 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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"); +} + diff --git a/servers/is/dmp_ds.c b/servers/is/dmp_ds.c index 8d6769078..89802e9ab 100644 --- a/servers/is/dmp_ds.c +++ b/servers/is/dmp_ds.c @@ -29,7 +29,7 @@ PUBLIC void data_store_dmp() 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); diff --git a/servers/is/dmp_pm.c b/servers/is/dmp_pm.c index b566f5595..4022f086d 100644 --- a/servers/is/dmp_pm.c +++ b/servers/is/dmp_pm.c @@ -82,14 +82,14 @@ PUBLIC void sigaction_dmp() 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; imp_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(" -"); diff --git a/servers/is/dmp_rs.c b/servers/is/dmp_rs.c index aa81fca05..96341456c 100644 --- a/servers/is/dmp_rs.c +++ b/servers/is/dmp_rs.c @@ -43,7 +43,7 @@ PUBLIC void rproc_dmp() 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"); } @@ -56,9 +56,9 @@ PUBLIC void rproc_dmp() 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'; diff --git a/servers/is/main.c b/servers/is/main.c index 773798004..f65c648e9 100644 --- a/servers/is/main.c +++ b/servers/is/main.c @@ -19,13 +19,13 @@ int callnr; /* system call number */ 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 * @@ -50,17 +50,6 @@ PUBLIC int main(int argc, char **argv) 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; @@ -98,6 +87,9 @@ PRIVATE void sef_local_startup() 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(); } @@ -108,14 +100,6 @@ PRIVATE void sef_local_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*/); @@ -124,17 +108,12 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) } /*===========================================================================* - * 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*/); diff --git a/servers/iso9660fs/main.c b/servers/iso9660fs/main.c index c948445aa..74abfe568 100644 --- a/servers/iso9660fs/main.c +++ b/servers/iso9660fs/main.c @@ -68,7 +68,7 @@ PRIVATE void 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. */ diff --git a/servers/mfs/main.c b/servers/mfs/main.c index 426114e09..835432594 100644 --- a/servers/mfs/main.c +++ b/servers/mfs/main.c @@ -16,6 +16,7 @@ FORWARD _PROTOTYPE(void cch_check, (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) ); /*===========================================================================* * main * @@ -44,13 +45,6 @@ PUBLIC int main(int argc, char *argv[]) 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); @@ -79,7 +73,6 @@ PUBLIC int main(int argc, char *argv[]) } } - /*===========================================================================* * sef_local_startup * *===========================================================================*/ @@ -87,10 +80,13 @@ PRIVATE void 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(); } @@ -128,6 +124,17 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * @@ -143,15 +150,7 @@ message *m_in; /* pointer to message */ 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 @@ -161,8 +160,7 @@ message *m_in; /* pointer to message */ 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)); } diff --git a/servers/pfs/main.c b/servers/pfs/main.c index aa36d28c1..16b1ffdd8 100644 --- a/servers/pfs/main.c +++ b/servers/pfs/main.c @@ -1,5 +1,6 @@ #include "fs.h" #include +#include #include #include #include @@ -12,6 +13,7 @@ FORWARD _PROTOTYPE(void get_work, (message *m_in) ); /* 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 * @@ -40,7 +42,6 @@ PUBLIC int main(int argc, char *argv[]) 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) { @@ -71,10 +72,13 @@ PRIVATE void 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(); } @@ -109,6 +113,16 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * @@ -124,24 +138,13 @@ message *m_in; /* pointer to message */ 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 ); } diff --git a/servers/pm/exec.c b/servers/pm/exec.c index d464ad21c..77198ce6b 100644 --- a/servers/pm/exec.c +++ b/servers/pm/exec.c @@ -152,9 +152,8 @@ int result; { 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); diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index cb87baaf1..dc29656da 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -8,7 +8,7 @@ * * 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 @@ -91,8 +91,8 @@ PUBLIC int do_fork() 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; @@ -123,9 +123,9 @@ PUBLIC int do_fork() } /*===========================================================================* - * 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 */ @@ -137,8 +137,8 @@ PUBLIC int do_fork_nb() 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 @@ -192,7 +192,7 @@ PUBLIC int do_fork_nb() 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; @@ -214,10 +214,19 @@ PUBLIC int do_fork_nb() *===========================================================================*/ 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 */ } @@ -280,7 +289,6 @@ int dump_core; /* flag indicating whether to dump core */ 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"); @@ -303,8 +311,8 @@ int dump_core; /* flag indicating whether to dump core */ * 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, @@ -363,8 +371,8 @@ int dump_core; /* flag indicating whether to dump core */ 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. */ @@ -667,12 +675,3 @@ register struct mproc *rmp; /* tells which process is exiting */ procs_in_use--; } -PUBLIC void _exit(int code) -{ - sys_exit(SELF); -} - -PUBLIC void __exit(int code) -{ - sys_exit(SELF); -} diff --git a/servers/pm/main.c b/servers/pm/main.c index e5cef3ad7..a11480338 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -39,6 +39,7 @@ 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) ); @@ -51,6 +52,7 @@ extern int unmap_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) ); +FORWARD _PROTOTYPE( int sef_cb_signal_manager, (endpoint_t target, int signo) ); /*===========================================================================* * main * @@ -80,19 +82,14 @@ PUBLIC int 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) @@ -104,7 +101,7 @@ PUBLIC int main() 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: @@ -133,29 +130,9 @@ PUBLIC int main() 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); } @@ -167,10 +144,13 @@ PRIVATE void 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_manager(sef_cb_signal_manager); + /* Let SEF perform startup. */ sef_startup(); } @@ -203,6 +183,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) SIGBUS, SIGSEGV }; register struct mproc *rmp; register char *sig_ptr; + register int signo; message mess; /* Initialize process table, including timers. */ @@ -246,7 +227,6 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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); @@ -268,11 +248,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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. */ @@ -288,9 +264,6 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) } } - /* 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) @@ -317,6 +290,20 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * *===========================================================================*/ @@ -360,6 +347,36 @@ int result; /* result of call (usually OK or error #) */ 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 * *===========================================================================*/ @@ -485,7 +502,7 @@ PRIVATE void handle_fs_reply() break; - case PM_FORK_NB_REPLY: + case PM_SRV_FORK_REPLY: /* Nothing to do */ break; diff --git a/servers/pm/mproc.h b/servers/pm/mproc.h index 7da8d8b0a..ae614b228 100644 --- a/servers/pm/mproc.h +++ b/servers/pm/mproc.h @@ -38,7 +38,6 @@ EXTERN struct mproc { /* 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 */ diff --git a/servers/pm/proto.h b/servers/pm/proto.h index 2d3d32811..8ff58eac3 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -29,7 +29,7 @@ _PROTOTYPE( void exec_restart, (struct mproc *rmp, int result) ); /* 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) ); @@ -66,7 +66,8 @@ _PROTOTYPE( int do_cprofile, (void) ); /* 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, diff --git a/servers/pm/signal.c b/servers/pm/signal.c index f4d3c6ca0..33ca55d62 100644 --- a/servers/pm/signal.c +++ b/servers/pm/signal.c @@ -12,7 +12,7 @@ * 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 @@ -34,8 +34,8 @@ #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 * @@ -48,6 +48,7 @@ PUBLIC int 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, @@ -67,20 +68,12 @@ PUBLIC int do_sigaction() 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); @@ -200,67 +193,42 @@ PUBLIC int do_kill() } /*===========================================================================* - * 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; +/* Perform the srv_kill(pid, signo) system call. */ - 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 */ + /* 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; } @@ -268,54 +236,52 @@ sigset_t sig_map; 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 */ } } @@ -388,11 +354,34 @@ int ksig; /* non-zero means signal comes from kernel */ 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. */ @@ -403,12 +392,6 @@ int ksig; /* non-zero means signal comes from kernel */ 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 @@ -418,7 +401,6 @@ int ksig; /* non-zero means signal comes from kernel */ 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 @@ -449,6 +431,16 @@ int ksig; /* non-zero means signal comes from kernel */ } /* 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, @@ -482,12 +474,17 @@ int ksig; /* non-zero means signal comes from kernel */ /* 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. */ @@ -500,6 +497,12 @@ int ksig; /* non-zero means signal comes from kernel */ 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 @@ -627,7 +630,7 @@ struct mproc *rmp; /* which process */ 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) { diff --git a/servers/pm/table.c b/servers/pm/table.c index 5fd8bf94c..0e3e0eafd 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -113,7 +113,7 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = { 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 */ @@ -123,6 +123,7 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = { 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]; diff --git a/servers/rs/Makefile b/servers/rs/Makefile index 1bd073636..20b8d6dde 100644 --- a/servers/rs/Makefile +++ b/servers/rs/Makefile @@ -19,7 +19,7 @@ LDFLAGS = -i 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) @@ -27,7 +27,7 @@ $(UTIL): $(UTIL_OBJ) $(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) diff --git a/servers/rs/const.h b/servers/rs/const.h index c060553b4..dc70af845 100644 --- a/servers/rs/const.h +++ b/servers/rs/const.h @@ -3,6 +3,12 @@ #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 */ @@ -14,23 +20,17 @@ /* 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 */ @@ -77,6 +77,11 @@ ( 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 */ diff --git a/servers/rs/error.c b/servers/rs/error.c new file mode 100644 index 000000000..088dea463 --- /dev/null +++ b/servers/rs/error.c @@ -0,0 +1,58 @@ +/* + * 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); +} diff --git a/servers/rs/exec.c b/servers/rs/exec.c index 7755bb5db..741cf50be 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -21,7 +21,7 @@ FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX], 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; @@ -56,16 +56,6 @@ int dev_execve(int proc_e, char *exec, size_t exec_len, char **argv, 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); @@ -144,6 +134,7 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, if (r != OK) { printf("do_exec: read_header failed\n"); + error= r; goto fail; } need_restart= 1; diff --git a/servers/rs/glo.h b/servers/rs/glo.h index c2eb506f1..c907f5e8c 100644 --- a/servers/rs/glo.h +++ b/servers/rs/glo.h @@ -25,19 +25,13 @@ extern struct boot_image_dev boot_image_dev_table[]; /* 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. */ @@ -51,5 +45,8 @@ EXTERN struct rupdate rupdate; /* Enable/disable verbose output. */ EXTERN long rs_verbose; +/* Set when we are shutting down. */ +EXTERN int shutting_down; + #endif /* RS_GLO_H */ diff --git a/servers/rs/inc.h b/servers/rs/inc.h index 70ff1b8c3..5c8e9d858 100644 --- a/servers/rs/inc.h +++ b/servers/rs/inc.h @@ -9,10 +9,16 @@ #include #include +#include +#include +#include #include #include #include #include +#include +#include +#include #include #include @@ -26,6 +32,9 @@ #include #include #include +#include +#include +#include #include #include /* For priv.h */ diff --git a/servers/rs/main.c b/servers/rs/main.c index d300f49b2..b1bb20390 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -16,7 +16,6 @@ #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, @@ -26,9 +25,7 @@ FORWARD _PROTOTYPE(void boot_image_info_lookup, ( endpoint_t endpoint, 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; @@ -40,6 +37,8 @@ EXTERN int unmap_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) ); +FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) ); +FORWARD _PROTOTYPE( int sef_cb_signal_manager, (endpoint_t target, int signo) ); /*===========================================================================* * main * @@ -63,15 +62,15 @@ PUBLIC int main(void) /* 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) */ @@ -84,13 +83,11 @@ PUBLIC int main(void) 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); } } @@ -104,7 +101,7 @@ PUBLIC int main(void) (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; } @@ -124,7 +121,7 @@ PUBLIC int main(void) 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; } @@ -146,6 +143,10 @@ PRIVATE void sef_local_startup() /* 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(); } @@ -156,7 +157,6 @@ PRIVATE void sef_local_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; @@ -179,8 +179,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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) { @@ -290,11 +291,12 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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, @@ -329,10 +331,8 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) /* 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, @@ -343,6 +343,10 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 */ @@ -350,8 +354,8 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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; } @@ -409,7 +413,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) /* - 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); @@ -427,7 +431,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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; @@ -455,32 +459,6 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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. @@ -495,6 +473,70 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) 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 * *===========================================================================*/ @@ -643,28 +685,16 @@ endpoint_t endpoint; 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 * *===========================================================================*/ @@ -676,17 +706,3 @@ message *m_in; /* pointer to message */ 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); -} - diff --git a/servers/rs/manager.c b/servers/rs/manager.c index 01a4f256c..39dc03fcd 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -6,50 +6,11 @@ */ #include "inc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* 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; @@ -67,7 +28,7 @@ endpoint_t endpoint; /* caller endpoint */ /*===========================================================================* * caller_can_control * *===========================================================================*/ -PRIVATE int caller_can_control(endpoint, label) +PUBLIC int caller_can_control(endpoint, label) endpoint_t endpoint; char *label; { @@ -78,13 +39,8 @@ 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++; @@ -106,27 +62,92 @@ char *label; } } - 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; @@ -136,66 +157,24 @@ size_t dst_len; } /*===========================================================================* - * 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; + struct rprocpub *rpub; + int arg_count; + int len; + char *cmd_ptr; - /* This call requires special privileges. */ - if (!caller_is_root(m_ptr->m_source)) return(EPERM); - - /* 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 */ @@ -209,7 +188,7 @@ message *m_ptr; /* request message pointer */ 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++; @@ -220,613 +199,34 @@ message *m_ptr; /* request message pointer */ 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; im_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; ir_nr_control; i++) - printf(" %s", rp->r_control[i]); - printf("\n"); - } - } - - /* 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; - } - } - - 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; - - 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'; - - 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; - } - } - } - - if(!exst_cpy) - s = read_exec(rp); - else - s = share_exec(rp, rp2); - - if (s != OK) - return s; - - rpub->sys_flags |= SF_USE_COPY; - } - - /* 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 */ - - /* 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; ir_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]); - } - - 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; ir_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_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; ipci_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; ipci_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); - } - - /* 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; ir_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)); - } - - /* 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 */ - - 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)); - } - - /* All information was gathered. Now try to start the system service. */ - r = start_service(rp, 0, &ep); - m_ptr->RS_ENDPOINT = ep; - return r; -} - - -/*===========================================================================* - * do_down * - *===========================================================================*/ -PUBLIC int do_down(message *m_ptr) -{ - register struct rproc *rp; - register struct rprocpub *rpub; - size_t len; - int s, proc; - char label[RS_MAX_LABEL_LEN]; - - /* This call requires special privileges. */ - if (!caller_is_root(m_ptr->m_source)) return(EPERM); - - 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'; - - for (rp=BEG_RPROC_ADDR; rpr_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); - - 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); - } - - /* 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); -} - - -/*===========================================================================* - * do_restart * - *===========================================================================*/ -PUBLIC int do_restart(message *m_ptr) -{ - register struct rproc *rp; - register struct rprocpub *rpub; - size_t len; - int s, proc, r; - char label[RS_MAX_LABEL_LEN]; - endpoint_t ep; - - 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'; - - /* This call requires special privileges. */ - if (! (caller_can_control(m_ptr->m_source, label) || - caller_is_root(m_ptr->m_source))) { - return(EPERM); - } - - for (rp=BEG_RPROC_ADDR; rpr_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); - } - } - if(rs_verbose) { - printf("RS: do_restart: '%s' not found\n", label); - } - - return(ESRCH); -} - - -/*===========================================================================* - * do_refresh * - *===========================================================================*/ -PUBLIC int do_refresh(message *m_ptr) -{ - 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 */ - - 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'; - - /* This call requires special privileges. */ - if (! (caller_can_control(m_ptr->m_source, label) || - caller_is_root(m_ptr->m_source))) { - return(EPERM); - } - - for (rp=BEG_RPROC_ADDR; rpr_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: refreshing %s (%d)\n", rpub->label, rp->r_pid); - } - stop_service(rp,RS_REFRESHING); - return(OK); - } - } - if(rs_verbose) { - printf("RS: do_refresh: '%s' not found\n", label); - } - - return(ESRCH); } /*===========================================================================* - * do_shutdown * + * srv_fork * *===========================================================================*/ -PUBLIC int do_shutdown(message *m_ptr) +PUBLIC pid_t srv_fork() { - /* This call requires special privileges. */ - if (m_ptr != NULL && !caller_is_root(m_ptr->m_source)) return(EPERM); + message m; - /* Set flag so that RS server knows services shouldn't be restarted. */ - shutting_down = TRUE; - return(OK); -} - - -/*===========================================================================* - * do_init_ready * - *===========================================================================*/ -PUBLIC int do_init_ready(message *m_ptr) -{ - int who_p; - struct rproc *rp; - struct rprocpub *rpub; - 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(EINVAL); - } - - /* Mark the slot as no longer initializing. */ - rp->r_flags &= ~RS_INITIALIZING; - rp->r_check_tm = 0; - getuptime(&rp->r_alive_tm); - - /* 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); - } - else { - if(rs_verbose) - printf("RS: initialization succeeded for service %d\n", - rpub->endpoint); - } - - return(EDONTREPLY); + return(_syscall(PM_PROC_NR, SRV_FORK, &m)); } /*===========================================================================* - * do_update * + * srv_kill * *===========================================================================*/ -PUBLIC int do_update(message *m_ptr) +PUBLIC int srv_kill(pid_t pid, int sig) { - 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; + message m; - /* 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'; - - /* This call requires special privileges. */ - if (! (caller_can_control(m_ptr->m_source, label) || - caller_is_root(m_ptr->m_source))) { - return(EPERM); - } - - /* Retrieve live update state. */ - lu_state = m_ptr->RS_LU_STATE; - if(lu_state == SEF_LU_STATE_NULL) { - return(EINVAL); - } - - /* Retrieve prepare max time. */ - prepare_maxtime = m_ptr->RS_LU_PREPARE_MAXTIME; - if(prepare_maxtime) { - if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) { - return(EINVAL); - } - } - else { - prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME; - } - - /* Make sure we are not already updating. */ - if(rupdate.flags & RS_UPDATING) { - if(rs_verbose) { - printf("RS: do_update: an update is already in progress"); - } - return(EBUSY); - } - - /* Try to start the update process. */ - for (rp=BEG_RPROC_ADDR; rpr_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; - } - - if(rs_verbose) { - printf("RS: updating %s (%d)\n", rpub->label, rp->r_pid); - } - - rp->r_flags |= RS_UPDATING; - rupdate.flags |= RS_UPDATING; - getuptime(&rupdate.prepare_tm); - rupdate.prepare_maxtime = prepare_maxtime; - rupdate.rp = rp; - - m_ptr->m_type = RS_LU_PREPARE; - asynsend(rpub->endpoint, m_ptr); /* request to update */ - - return(OK); - } - } - if(rs_verbose) { - printf("RS: do_update: '%s' not found\n", label); - } - - return(ESRCH); -} - -/*===========================================================================* - * do_upd_ready * - *===========================================================================*/ -PUBLIC int do_upd_ready(message *m_ptr) -{ - register struct rproc *rp; - int who_p; - clock_t now = m_ptr->NOTIFY_TIMESTAMP; - int result; - - who_p = _ENDPOINT_P(m_ptr->m_source); - rp = rproc_ptr[who_p]; - result = m_ptr->RS_LU_RESULT; - - /* Make sure the originating 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); - } - 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; - - case EINVAL: - printf("RS: update failed: %s\n", - "service does not support the required state"); - break; - - case EBUSY: - printf("RS: update failed: %s\n", - "service is not able to prepare for the update now"); - break; - - case EGENERIC: - printf("RS: update failed: %s\n", - "a generic error occurred while preparing for the update"); - break; - - default: - printf("RS: update failed: %s (%d)\n", - "an unknown error occurred while preparing for the update\n", - result); - break; - } - - return(OK); - } - - /* Kill the process now and mark it for refresh, the new version will - * be automatically restarted. - */ - rp->r_flags &= ~RS_EXITING; - rp->r_flags |= RS_REFRESHING; - kill(rp->r_pid, SIGKILL); - - return(EDONTREPLY); + m.m1_i1 = pid; + m.m1_i2 = sig; + return(_syscall(PM_PROC_NR, SRV_KILL, &m)); } /*===========================================================================* * update_period * *===========================================================================*/ -PRIVATE void update_period(message *m_ptr) +PUBLIC void update_period(message *m_ptr) { clock_t now = m_ptr->NOTIFY_TIMESTAMP; short has_update_timed_out; @@ -838,10 +238,13 @@ PRIVATE void update_period(message *m_ptr) /* See if a timeout has occurred. */ has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime); - /* If an update timed out, end the update process and notify the service. */ + /* If 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) { - end_update(now); printf("RS: update failed: maximum prepare time reached\n"); + end_update(EINTR); /* Prepare cancel request. */ m.m_type = RS_LU_PREPARE; @@ -853,285 +256,138 @@ PRIVATE void update_period(message *m_ptr) /*===========================================================================* * end_update * *===========================================================================*/ -PRIVATE void end_update(clock_t now) +PUBLIC void end_update(int result) { - /* 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; -} +/* 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; -/*===========================================================================* - * do_exit * - *===========================================================================*/ -PUBLIC void do_exit(message *m_ptr) -{ - 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; + old_rp = rupdate.rp; + new_rp = old_rp->r_new_rp; if(rs_verbose) - printf("RS: got SIGCHLD signal, doing wait to get exited child.\n"); + printf("RS: ending update from %s to %s with result: %d\n", + srv_to_string(old_rp), srv_to_string(new_rp), result); - /* 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. + /* 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); + + /* 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; + + /* Make the version that has to survive as active. */ + activate_service(surviving_rp, exiting_rp); + + /* Send a late reply if necessary. */ + late_reply(old_rp, result); + + /* Unpublish and cleanup the version that has to die out and mark the other + * version as no longer updating. */ - while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) { + surviving_rp->r_flags &= ~RS_UPDATING; + unpublish_process(exiting_rp); + cleanup_service(exiting_rp); - 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 - } - } - - /* 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; - } - - /* Search the system process table to see who exited. - * This should always succeed. - */ - for (rp=BEG_RPROC_ADDR; rpr_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; - } - } - } + if(rs_verbose) + printf("RS: service %s ended the update\n", srv_to_string(surviving_rp)); } /*===========================================================================* - * do_period * + * kill_service_debug * *===========================================================================*/ -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; - endpoint_t ep; - 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; rpr_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) { - 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 */ - } - } - } - } - - /* Reschedule a synchronous alarm for the next period. */ - if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) - panic("couldn't set alarm: %d", s); -} - - -/*===========================================================================* - * start_service * - *===========================================================================*/ -PRIVATE int start_service(rp, flags, endpoint) +PUBLIC int kill_service_debug(file, line, rp, errstr, err) +char *file; +int line; struct rproc *rp; -int flags; -endpoint_t *endpoint; +char *errstr; +int err; { -/* 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. - */ +/* Crash a system service and don't let it restart. */ + struct rprocpub *rpub; + + 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 */ + + return err; +} + +/*===========================================================================* + * 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; + + rpub = rp->r_pub; + + if(rs_verbose) + printf("RS: %s %skilled at %s:%d\n", srv_to_string(rp), + rp->r_flags & RS_EXITING ? "lethally " : "", file, line); + + return sys_kill(rpub->endpoint, SIGKILL); +} + +/*===========================================================================* + * cleanup_service_debug * + *===========================================================================*/ +PUBLIC void cleanup_service_debug(file, line, rp) +char *file; +int line; +struct rproc *rp; +{ +/* Ask PM to exit the service and free slot. */ + struct rprocpub *rpub; + + rpub = rp->r_pub; + + if(rs_verbose) + printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp), + file, line); + + 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, init_type; + int s, use_copy, slot_nr; bitchunk_t *vm_mask; message m; + extern char **environ; char * null_env = NULL; struct rprocpub *rpub; @@ -1140,68 +396,35 @@ endpoint_t *endpoint; /* 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", + printf("RS: unable to start service '%s' without an in-memory copy\n", rpub->label); free_slot(rp); return(EPERM); } /* 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(); + 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); } - 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 */ + /* Get endpoint of the child. */ + child_proc_nr_e = getnprocnr(child_pid); - 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. - */ + /* 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 | flags; /* mark slot in use */ + rp->r_flags = RS_IN_USE; /* 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_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 */ @@ -1209,84 +432,44 @@ endpoint_t *endpoint; 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. - */ - - if (use_copy) - { - 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); - } - } /* Set resources when asked to. */ - if (rp->r_set_resources) - { + if (rp->r_set_resources) { /* 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); - } } /* 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 */ + || (s = sys_getpriv(&rp->r_priv, child_proc_nr_e)) != OK) { + panic("unable to set privilege structure: %d", s); } - /* 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); - } - - /* Publish the new system service. */ - s = publish_service(rp); - if (s != OK) { - printf("RS: warning: publish_service failed: %d\n", s); - } - - /* 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. + /* 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 ((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 */ + 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: execing child with srv_execve()...\n"); + s = srv_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rp->r_argv, + environ); - /* 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 (s != OK) { + return kill_service(rp, "srv_execve failed", s); + } + if(!use_copy) { + free_exec(rp); } /* The purpose of non-blocking forks is to avoid involving VFS in the forking @@ -1297,100 +480,506 @@ endpoint_t *endpoint; * 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. + * towards MFS instances, this hack and the big part of srv_fork() can go. */ - if (use_copy) - setuid(0); + 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); + if(rs_verbose) + printf("RS: %s created\n", srv_to_string(rp)); + + return OK; +} + +/*===========================================================================* + * publish_service * + *===========================================================================*/ +PUBLIC int publish_service(rp) +struct rproc *rp; /* pointer to service slot */ +{ +/* Publish service-wide properties of a service. */ + int r; + struct rprocpub *rpub; + + rpub = rp->r_pub; + + /* 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); + } + + if(rs_verbose) + printf("RS: %s service-wide properties published\n", + srv_to_string(rp)); + + 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); + } + } + + /* 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); } } 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); + printf("RS: %s process-wide properties published\n", + srv_to_string(rp)); + + return OK; +} + +/*===========================================================================* + * unpublish_service * + *===========================================================================*/ +PUBLIC int unpublish_service(rp) +struct rproc *rp; /* pointer to service slot */ +{ +/* Unpublish service-wide properties of a service. */ + struct rprocpub *rpub; + int r, result; + + 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; +} + +/*===========================================================================* + * unpublish_process * + *===========================================================================*/ +PUBLIC int unpublish_process(rp) +struct rproc *rp; /* pointer to service slot */ +{ +/* Unpublish process-wide properties of a service. */ + struct rprocpub *rpub; + int r, result; + + rpub = rp->r_pub; + result = OK; + + /* 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; + } + } + + /* No need to inform VM, cleanup is performed on exit automatically. */ + + 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); + } + + /* Initialize service. */ + if((s = init_service(rp, init_type)) != OK) { + return kill_service(rp, "unable to initialize service", s); + } + + if(rs_verbose) + printf("RS: %s allowed to run\n", srv_to_string(rp)); + + return OK; +} + +/*===========================================================================* + * start_service * + *===========================================================================*/ +PUBLIC int start_service(rp) +struct rproc *rp; +{ +/* Start a system service. */ + int r, init_type; + struct rprocpub *rpub; + + rpub = rp->r_pub; + + /* Create. */ + r = create_service(rp); + if(r != OK) { + return r; + } + + /* Publish service properties. */ + r = publish_process(rp); + if (r != OK) { + return r; + } + r = publish_service(rp); + if (r != OK) { + return r; + } + + /* Run. */ + init_type = rp->r_restarts > 0 ? SEF_INIT_RESTART : SEF_INIT_FRESH; + r = run_service(rp, init_type); + if(r != OK) { + return r; + } /* 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 */ + if(rs_verbose) + printf("RS: %s started with major %d\n", srv_to_string(rp), + rpub->dev_nr); - return(OK); + return OK; } /*===========================================================================* * stop_service * *===========================================================================*/ -PRIVATE void stop_service(struct rproc *rp,int how) +PUBLIC void stop_service(struct rproc *rp,int how) { + struct rprocpub *rpub; + + rpub = rp->r_pub; + /* 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); + if(rs_verbose) + printf("RS: %s signaled with SIGTERM\n", srv_to_string(rp)); 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"); + sys_kill(rpub->endpoint, SIGTERM); /* first try friendly */ getuptime(&rp->r_stop_tm); /* record current time */ } - /*===========================================================================* - * do_getsysinfo * + * update_service * *===========================================================================*/ -PUBLIC int do_getsysinfo(m_ptr) -message *m_ptr; +PUBLIC int update_service(src_rpp, dst_rpp) +struct rproc **src_rpp; +struct rproc **dst_rpp; { - vir_bytes src_addr, dst_addr; - int dst_proc; - size_t len; - int s; +/* 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; - /* This call requires special privileges. */ - if (!caller_is_root(m_ptr->m_source)) return(EPERM); + src_rp = *src_rpp; + dst_rp = *dst_rpp; + src_rpub = src_rp->r_pub; + dst_rpub = dst_rp->r_pub; - 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); + 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; } - 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); + /* 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; } /*===========================================================================* - * fork_nb * + * activate_service * *===========================================================================*/ -PRIVATE pid_t fork_nb() +PUBLIC void activate_service(struct rproc *rp, struct rproc *ex_rp) { - message m; +/* Activate a service instance and deactivate another one if requested. */ - return(_syscall(PM_PROC_NR, FORK_NB, &m)); + 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)); + } + + if(! (rp->r_flags & RS_ACTIVE) ) { + rp->r_flags |= RS_ACTIVE; + if(rs_verbose) + printf("RS: %s becomes active\n", srv_to_string(rp)); + } +} + +/*===========================================================================* + * terminate_service * + *===========================================================================*/ +PUBLIC void terminate_service(struct rproc *rp) +{ +/* Handle a termination event for a system service. */ + struct rproc **rps; + struct rprocpub *rpub; + int nr_rps; + int i, r; + + rpub = rp->r_pub; + + 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; + } + } + + 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)); + } + + /* See if a late reply has to be sent. */ + r = (rp->r_caller_request == RS_DOWN ? OK : EDEADSRCDST); + late_reply(rp, r); + + /* Unpublish the service. */ + unpublish_service(rp); + unpublish_process(rp); + + /* Cleanup all the instances of the service. */ + get_service_instances(rp, &rps, &nr_rps); + for(i=0;ir_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); + } + + /* 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; + } + + /* Restart service. */ + restart_service(rp); + } +} + +/*===========================================================================* + * 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); + + 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)); + } +} + +/*===========================================================================* + * inherit_service_defaults * + *===========================================================================*/ +PUBLIC void inherit_service_defaults(def_rp, rp) +struct rproc *def_rp; +struct rproc *rp; +{ + struct rprocpub *def_rpub; + struct rprocpub *rpub; + + def_rpub = def_rp->r_pub; + rpub = rp->r_pub; + + /* Device settings. These properties cannot change. */ + rpub->dev_nr = def_rpub->dev_nr; + rpub->dev_style = def_rpub->dev_style; + + /* Period. */ + if(!rpub->period && def_rpub->period) { + rpub->period = def_rpub->period; + } +} + +/*===========================================================================* + * get_service_instances * + *===========================================================================*/ +PUBLIC void get_service_instances(rp, rps, length) +struct rproc *rp; +struct rproc ***rps; +int *length; +{ +/* 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; } /*===========================================================================* * share_exec * *===========================================================================*/ -PRIVATE int share_exec(rp_dst, rp_src) +PUBLIC void share_exec(rp_dst, rp_src) struct rproc *rp_dst, *rp_src; { struct rprocpub *rpub_src; @@ -1399,22 +988,19 @@ struct rproc *rp_dst, *rp_src; rpub_src = rp_src->r_pub; rpub_dst = rp_dst->r_pub; - if(rs_verbose) { - printf("RS: share_exec: sharing exec image from %s to %s\n", - rpub_src->label, rpub_dst->label); - } + if(rs_verbose) + printf("RS: %s shares exec image with %s\n", + srv_to_string(rp_dst), srv_to_string(rp_src)); /* 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; } /*===========================================================================* * read_exec * *===========================================================================*/ -PRIVATE int read_exec(rp) +PUBLIC int read_exec(rp) struct rproc *rp; { int e, r, fd; @@ -1422,9 +1008,9 @@ struct rproc *rp; struct stat sb; e_name= rp->r_argv[0]; - if(rs_verbose) { - printf("RS: read_exec: copying exec image from: %s\n", e_name); - } + 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) @@ -1452,8 +1038,7 @@ struct rproc *rp; printf("RS: read_exec: read failed %d, errno %d\n", r, e); - free(rp->r_exec); - rp->r_exec= NULL; + free_exec(rp); if (r >= 0) return EIO; @@ -1462,43 +1047,489 @@ struct rproc *rp; } /*===========================================================================* - * free_slot * + * free_exec * *===========================================================================*/ -PRIVATE void free_slot(rp) +PUBLIC void free_exec(rp) struct rproc *rp; { +/* Free an exec image. */ int slot_nr, has_shared_exec; - struct rprocpub *rpub; 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; + } + } + + /* 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; +} + +/*===========================================================================* + * init_slot * + *===========================================================================*/ +PUBLIC int init_slot(rp, rs_start, source) +struct rproc *rp; +struct rs_start *rs_start; +endpoint_t source; +{ +/* Initialize a slot as requested by the client. */ + struct rprocpub *rpub; + int 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; irss_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; ir_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; + } + } + } + + s = OK; + if(!exst_cpy) + s = read_exec(rp); + else + share_exec(rp, rp2); + + if (s != OK) + return s; + + rpub->sys_flags |= SF_USE_COPY; + } + + /* 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 */ + + /* Copy granted resources */ + if (rs_start->rss_nr_irq > NR_IRQ) + { + printf("RS: init_slot: too many IRQs requested\n"); + return EINVAL; + } + rp->r_priv.s_nr_irq= rs_start->rss_nr_irq; + for (i= 0; ir_priv.s_nr_irq; i++) + { + 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]); + } + + if (rs_start->rss_nr_io > NR_IO_RANGE) + { + printf("RS: init_slot: too many I/O ranges requested\n"); + return EINVAL; + } + rp->r_priv.s_nr_io_range= rs_start->rss_nr_io; + for (i= 0; ir_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); + } + + if (rs_start->rss_nr_pci_id > RS_NR_PCI_DEVICE) + { + printf("RS: init_slot: too many PCI device IDs\n"); + return EINVAL; + } + rpub->pci_acl.rsp_nr_device = rs_start->rss_nr_pci_id; + for (i= 0; ipci_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); + } + if (rs_start->rss_nr_pci_class > RS_NR_PCI_CLASS) + { + printf("RS: init_slot: too many PCI class IDs\n"); + return EINVAL; + } + rpub->pci_acl.rsp_nr_class= rs_start->rss_nr_pci_class; + for (i= 0; ipci_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); + } + + /* 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); + + /* 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; +} + +/*===========================================================================* + * clone_slot * + *===========================================================================*/ +PUBLIC int clone_slot(rp, clone_rpp) +struct rproc *rp; +struct rproc **clone_rpp; +{ + int r; + struct rproc *clone_rp; + struct rprocpub *rpub, *clone_rpub; + + /* 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; +} + +/*===========================================================================* + * swap_slot_pointer * + *===========================================================================*/ +PRIVATE void swap_slot_pointer(struct rproc **rpp, struct rproc *src_rp, + struct rproc *dst_rp) +{ + if(*rpp == src_rp) { + *rpp = dst_rp; + } + else if(*rpp == dst_rp) { + *rpp = src_rp; + } +} + +/*===========================================================================* + * swap_slot * + *===========================================================================*/ +PUBLIC void swap_slot(src_rpp, dst_rpp) +struct rproc **src_rpp; +struct rproc **dst_rpp; +{ +/* 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; +} + +/*===========================================================================* + * lookup_slot_by_label * + *===========================================================================*/ +PUBLIC struct rproc* lookup_slot_by_label(char *label) +{ +/* Lookup a service slot matching the given label. */ + int slot_nr; + struct rproc *rp; + struct rprocpub *rpub; + + 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; + } + } + + return NULL; +} + +/*===========================================================================* + * lookup_slot_by_pid * + *===========================================================================*/ +PUBLIC struct rproc* lookup_slot_by_pid(pid_t pid) +{ +/* Lookup a service slot matching the given pid. */ + int slot_nr; + struct rproc *rp; + + if(pid < 0) { + return NULL; + } + + 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; + } + } + + return NULL; +} + +/*===========================================================================* + * alloc_slot * + *===========================================================================*/ +PUBLIC int alloc_slot(rpp) +struct rproc **rpp; +{ +/* Alloc a new system service slot. */ + int slot_nr; + + 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; + } + + return OK; +} + +/*===========================================================================* + * free_slot * + *===========================================================================*/ +PUBLIC void free_slot(rp) +struct rproc *rp; +{ +/* Free a system service slot. */ + struct rprocpub *rpub; + + 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; } @@ -1506,7 +1537,7 @@ struct rproc *rp; /*===========================================================================* * run_script * *===========================================================================*/ -PRIVATE void run_script(rp) +PUBLIC int run_script(rp) struct rproc *rp; { int r, endpoint; @@ -1521,34 +1552,21 @@ struct rproc *rp; 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); @@ -1560,14 +1578,12 @@ struct rproc *rp; 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; } } @@ -1575,7 +1591,7 @@ struct rproc *rp; /*===========================================================================* * 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; @@ -1617,7 +1633,7 @@ 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; { @@ -1659,23 +1675,10 @@ 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; } @@ -1695,7 +1698,7 @@ struct priv *privp; /*===========================================================================* * add_backward_ipc * *===========================================================================*/ -PRIVATE void add_backward_ipc(rp, privp) +PUBLIC void add_backward_ipc(rp, privp) struct rproc *rp; struct priv *privp; { @@ -1746,42 +1749,11 @@ 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)); @@ -1802,77 +1774,3 @@ struct priv *privp; } } -/*===========================================================================* - * 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; rrpr_flags & RS_IN_USE)) - continue; - rrpub = rrp->r_pub; - if (!strcmp(rrpub->label, namebuf)) { - m_ptr->RS_ENDPOINT = rrpub->endpoint; - return OK; - } - } - - return ESRCH; -} - diff --git a/servers/rs/proto.h b/servers/rs/proto.h index 09b3a9f17..d73314e8b 100644 --- a/servers/rs/proto.h +++ b/servers/rs/proto.h @@ -4,35 +4,101 @@ 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) ); diff --git a/servers/rs/request.c b/servers/rs/request.c new file mode 100755 index 000000000..66ea117c3 --- /dev/null +++ b/servers/rs/request.c @@ -0,0 +1,694 @@ +/* + * 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; rpr_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;im_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; +} + diff --git a/servers/rs/service.c b/servers/rs/service.c index d34aa8a04..1664f69be 100644 --- a/servers/rs/service.c +++ b/servers/rs/service.c @@ -49,6 +49,8 @@ PRIVATE char *known_requests[] = { #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 @@ -60,8 +62,6 @@ PRIVATE char *known_requests[] = { #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 */ @@ -75,7 +75,9 @@ PRIVATE char *known_requests[] = { #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 */ @@ -95,10 +97,9 @@ PRIVATE long req_period; 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]; @@ -113,12 +114,12 @@ PRIVATE void print_usage(char *app_name, char *problem) fprintf(stderr, "Warning, %s\n", problem); fprintf(stderr, "Usage:\n"); fprintf(stderr, - " %s [-c -r] (up|run) [%s ] [%s ] [%s ]\n", - app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD); + " %s [-c -r] (up|run|update) [%s ] [%s ] [%s ] [%s ] [%s ] [%s ] [%s ] [%s