From cb176df60f745969ac2442aa6ab489447512c8fb Mon Sep 17 00:00:00 2001 From: Cristiano Giuffrida Date: Wed, 17 Mar 2010 01:15:29 +0000 Subject: [PATCH] New RS and new signal handling for system processes. UPDATING INFO: 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 KERNEL CHANGES: - Generic signal handling support. The kernel no longer assumes PM as a signal manager for every process. The signal manager of a given process can now be specified in its privilege slot. When a signal has to be delivered, the kernel performs the lookup and forwards the signal to the appropriate signal manager. PM is the default signal manager for user processes, RS is the default signal manager for system processes. To enable ptrace()ing for system processes, it is sufficient to change the default signal manager to PM. This will temporarily disable crash recovery, though. - sys_exit() is now split into sys_exit() (i.e. exit() for system processes, which generates a self-termination signal), and sys_clear() (i.e. used by PM to ask the kernel to clear a process slot when a process exits). - Added a new kernel call (i.e. sys_update()) to swap two process slots and implement live update. PM CHANGES: - Posix signal handling is no longer allowed for system processes. System signals are split into two fixed categories: termination and non-termination signals. When a non-termination signaled is processed, PM transforms the signal into an IPC message and delivers the message to the system process. When a termination signal is processed, PM terminates the process. - PM no longer assumes itself as the signal manager for system processes. It now makes sure that every system signal goes through the kernel before being actually processes. The kernel will then dispatch the signal to the appropriate signal manager which may or may not be PM. SYSLIB CHANGES: - Simplified SEF init and LU callbacks. - Added additional predefined SEF callbacks to debug crash recovery and live update. - Fixed a temporary ack in the SEF init protocol. SEF init reply is now completely synchronous. - Added SEF signal event type to provide a uniform interface for system processes to deal with signals. A sef_cb_signal_handler() callback is available for system processes to handle every received signal. A sef_cb_signal_manager() callback is used by signal managers to process system signals on behalf of the kernel. - Fixed a few bugs with memory mapping and DS. VM CHANGES: - Page faults and memory requests coming from the kernel are now implemented using signals. - Added a new VM call to swap two process slots and implement live update. - The call is used by RS at update time and in turn invokes the kernel call sys_update(). RS CHANGES: - RS has been reworked with a better functional decomposition. - Better kernel call masks. com.h now defines the set of very basic kernel calls every system service is allowed to use. This makes system.conf simpler and easier to maintain. In addition, this guarantees a higher level of isolation for system libraries that use one or more kernel calls internally (e.g. printf). - RS is the default signal manager for system processes. By default, RS intercepts every signal delivered to every system process. This makes crash recovery possible before bringing PM and friends in the loop. - RS now supports fast rollback when something goes wrong while initializing the new version during a live update. - Live update is now implemented by keeping the two versions side-by-side and swapping the process slots when the old version is ready to update. - Crash recovery is now implemented by keeping the two versions side-by-side and cleaning up the old version only when the recovery process is complete. DS CHANGES: - Fixed a bug when the process doing ds_publish() or ds_delete() is not known by DS. - Fixed the completely broken support for strings. String publishing is now implemented in the system library and simply wraps publishing of memory ranges. Ideally, we should adopt a similar approach for other data types as well. - Test suite fixed. DRIVER CHANGES: - The hello driver has been added to the Minix distribution to demonstrate basic live update and crash recovery functionalities. - Other drivers have been adapted to conform the new SEF interface. --- commands/dhcpd/dhcpd.c | 12 +- commands/scripts/DESCRIBE.sh | 3 + commands/scripts/MAKEDEV.sh | 8 +- commands/scripts/readclock.sh | 2 +- docs/UPDATING | 55 +- drivers/Makefile | 1 + drivers/amddev/amddev.c | 96 +- drivers/at_wini/at_wini.c | 12 +- drivers/at_wini/liveupdate.c | 6 +- drivers/atl2/atl2.c | 69 +- drivers/audio/framework/audio_fw.c | 63 +- drivers/audio/framework/liveupdate.c | 6 +- drivers/bios_wini/bios_wini.c | 1 - drivers/dec21140A/dec21140A.c | 79 +- drivers/dp8390/dp8390.c | 55 +- drivers/dpeth/dp.c | 45 +- drivers/e1000/e1000.c | 45 +- drivers/filter/main.c | 47 +- drivers/filter/util.c | 13 +- drivers/floppy/floppy.c | 43 +- drivers/floppy/liveupdate.c | 6 +- drivers/fxp/fxp.c | 69 +- drivers/hello/Makefile | 44 + drivers/hello/hello.c | 214 +++ drivers/hello/hello.h | 7 + drivers/lance/lance.c | 70 +- drivers/libdriver/driver.c | 18 - drivers/libdriver/driver.h | 2 - drivers/log/liveupdate.c | 6 +- drivers/log/log.c | 33 +- drivers/memory/memory.c | 7 - drivers/memory/ramdisk/rc | 2 +- drivers/orinoco/orinoco.c | 54 +- drivers/pci/main.c | 9 +- drivers/pci/pci.c | 2 +- drivers/printer/liveupdate.c | 6 +- drivers/printer/printer.c | 48 +- drivers/random/main.c | 1 - drivers/readclock/readclock.c | 18 - drivers/rtl8139/liveupdate.c | 6 +- drivers/rtl8139/rtl8139.c | 55 +- drivers/rtl8169/rtl8169.c | 53 +- drivers/sb16/sb16_dsp.c | 4 +- drivers/sb16/sb16_dsp_liveupdate.c | 6 +- drivers/tty/console.c | 3 +- drivers/tty/tty.c | 41 +- drivers/tty/tty.h | 2 +- etc/rs.inet | 7 +- etc/system.conf | 246 +-- include/errno.h | 2 +- include/minix/callnr.h | 5 +- include/minix/com.h | 41 +- include/minix/dmap.h | 2 + include/minix/ds.h | 1 - include/minix/rs.h | 3 +- include/minix/safecopies.h | 8 +- include/minix/sef.h | 99 +- include/minix/syslib.h | 4 +- include/minix/vm.h | 8 + include/signal.h | 21 +- kernel/arch/i386/exception.c | 2 +- kernel/arch/i386/memory.c | 3 +- kernel/config.h | 4 +- kernel/interrupt.c | 38 +- kernel/main.c | 1 + kernel/priv.h | 7 +- kernel/proc.h | 4 +- kernel/system.c | 39 +- kernel/system.h | 17 +- kernel/system/Makefile | 2 + kernel/system/do_abort.c | 2 +- kernel/system/do_clear.c | 75 + kernel/system/do_endksig.c | 7 +- kernel/system/do_exit.c | 78 +- kernel/system/do_getksig.c | 11 +- kernel/system/do_kill.c | 17 +- kernel/system/do_privctl.c | 6 +- kernel/system/do_runctl.c | 2 +- kernel/system/do_safemap.c | 4 +- kernel/system/do_update.c | 165 ++ lib/libc/ansi/errlist.c | 2 +- lib/libc/other/Makefile.inc | 1 + lib/libc/other/_vm_update.c | 12 + lib/libc/syscall/Makefile.inc | 1 + lib/libc/syscall/vm_update.S | 7 + lib/libsys/Makefile | 5 +- lib/libsys/ds.c | 57 +- lib/libsys/sef.c | 66 +- lib/libsys/sef_init.c | 46 +- lib/libsys/sef_liveupdate.c | 121 +- lib/libsys/sef_ping.c | 8 +- lib/libsys/sef_signal.c | 196 ++ lib/libsys/sys_clear.c | 15 + lib/libsys/sys_exit.c | 9 +- lib/libsys/sys_update.c | 11 + man/man2/intro.2 | 2 +- servers/ds/inc.h | 3 +- servers/ds/main.c | 47 +- servers/ds/store.c | 35 +- servers/ds/store.h | 1 - servers/hgfs/main.c | 90 +- servers/inet/inet.c | 9 +- servers/inet/mnx_eth.c | 8 +- servers/ipc/inc.h | 6 +- servers/ipc/main.c | 25 +- servers/is/dmp_ds.c | 2 +- servers/is/dmp_pm.c | 6 +- servers/is/dmp_rs.c | 6 +- servers/is/main.c | 37 +- servers/iso9660fs/main.c | 2 +- servers/mfs/main.c | 38 +- servers/pfs/main.c | 33 +- servers/pm/exec.c | 5 +- servers/pm/forkexit.c | 51 +- servers/pm/main.c | 101 +- servers/pm/mproc.h | 1 - servers/pm/proto.h | 5 +- servers/pm/signal.c | 193 +- servers/pm/table.c | 3 +- servers/rs/Makefile | 4 +- servers/rs/const.h | 35 +- servers/rs/error.c | 58 + servers/rs/exec.c | 13 +- servers/rs/glo.h | 13 +- servers/rs/inc.h | 9 + servers/rs/main.c | 172 +- servers/rs/manager.c | 2498 ++++++++++++-------------- servers/rs/proto.h | 80 +- servers/rs/request.c | 694 +++++++ servers/rs/service.c | 194 +- servers/rs/table.c | 39 +- servers/rs/type.h | 10 +- servers/rs/utility.c | 115 +- servers/vfs/dmap.c | 3 +- servers/vfs/main.c | 12 +- servers/vfs/table.c | 3 +- servers/vm/exit.c | 10 - servers/vm/main.c | 55 +- servers/vm/map_mem.c | 28 +- servers/vm/pagefaults.c | 1 + servers/vm/proto.h | 1 + servers/vm/rs.c | 91 + test/ds/dstest.c | 11 +- test/ds/subs.c | 2 +- test/ds/system.conf | 15 +- test/safecopy/system.conf | 24 +- test/safemap/system.conf | 24 +- test/safeperf/system.conf | 24 +- 148 files changed, 4587 insertions(+), 3295 deletions(-) create mode 100644 drivers/hello/Makefile create mode 100644 drivers/hello/hello.c create mode 100644 drivers/hello/hello.h create mode 100644 kernel/system/do_clear.c create mode 100644 kernel/system/do_update.c create mode 100644 lib/libc/other/_vm_update.c create mode 100644 lib/libc/syscall/vm_update.S create mode 100644 lib/libsys/sef_signal.c create mode 100644 lib/libsys/sys_clear.c create mode 100644 lib/libsys/sys_update.c create mode 100644 servers/rs/error.c create mode 100755 servers/rs/request.c 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. - */ - - signal(SIGALRM, got_alarm); - alarm(secs); + u32_t system_hz; - pause(); + /* Sleep for the given number of seconds. */ + system_hz = sys_hz(); + tickdelay(system_hz * secs); } + 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; - - /* Determine what process exited. User processes are handled here. */ - if (PM_PROC_NR == caller->p_endpoint) { - if (m_ptr->PR_ENDPT != SELF) { /* PM tries to exit self */ - if(!isokendpt(m_ptr->PR_ENDPT, &exit_e)) /* get exiting process */ - return EINVAL; - clear_proc(proc_addr(exit_e)); /* exit a user process */ - return(OK); /* report back to PM */ - } - } - - /* The PM or some other system process requested to be exited. */ - clear_proc(caller); - return(EDONTREPLY); -} - -/*===========================================================================* - * clear_proc * - *===========================================================================*/ -PRIVATE void clear_proc(rc) -register struct proc *rc; /* slot of process to clean up */ -{ - int i; - - /* Don't clear if already cleared. */ - if(isemptyp(rc)) return; - - /* Check the table with IRQ hooks to see if hooks should be released. */ - for (i=0; i < NR_IRQ_HOOKS; i++) { - if (rc->p_endpoint == irq_hooks[i].proc_nr_e) { - rm_irq_handler(&irq_hooks[i]); /* remove interrupt handler */ - irq_hooks[i].proc_nr_e = NONE; /* mark hook as free */ - } - } - - /* Remove the process' ability to send and receive messages */ - clear_endpoint(rc); - - - /* Turn off any alarm timers at the clock. */ - reset_timer(&priv(rc)->s_alarm_timer); - - /* Make sure that the exiting process is no longer scheduled, - * and mark slot as FREE. Also mark saved fpu contents as not significant. - */ - RTS_SETFLAGS(rc, RTS_SLOT_FREE); - rc->p_misc_flags &= ~MF_FPU_INITIALIZED; + int sig_nr = SIGABRT; - /* Release the process table slot. If this is a system process, also - * release its privilege structure. Further cleanup is not needed at - * this point. All important fields are reinitialized when the - * slots are assigned to another, new process. - */ - if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE; + cause_sig(caller->p_nr, sig_nr); /* send a signal to the caller */ -#if 0 - /* Clean up virtual memory */ - if (rc->p_misc_flags & MF_VM) { - vm_map_default(rc); - } -#endif + return(EDONTREPLY); /* don't reply */ } #endif /* USE_EXIT */ 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); -} + panic("Simulating a crash at initialization time..."); -/*===========================================================================* - * sef_cb_init_restart_fail * - *===========================================================================*/ -PUBLIC int sef_cb_init_restart_fail(int UNUSED(type), - sef_init_info_t *UNUSED(info)) -{ - return(ENOSYS); + return OK; } 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)) +{ + return OK; +} + +/*===========================================================================* + * sef_cb_lu_prepare_never_ready * + *===========================================================================*/ +PUBLIC int sef_cb_lu_prepare_never_ready(int UNUSED(state)) { - sef_lu_ready(OK); +#if SEF_LU_DEBUG + sef_lu_debug_begin(); + sef_lu_dprint("%s, cycle=%d. Simulating a service never ready to update...\n", + sef_debug_header(), sef_lu_debug_cycle); + sef_lu_debug_end(); +#endif + + return ENOTREADY; +} + +/*===========================================================================* + * sef_cb_lu_prepare_crash * + *===========================================================================*/ +PUBLIC int sef_cb_lu_prepare_crash(int UNUSED(state)) +{ + panic("Simulating a crash at update prepare time..."); + + return OK; } /*===========================================================================* 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; { @@ -87,31 +88,43 @@ sef_init_info_t *info; } /*===========================================================================* - * sef_local_startup * + * sef_cb_signal_handler * *===========================================================================*/ -PRIVATE void sef_local_startup() +PRIVATE void sef_cb_signal_handler(int signo) { -/* Specify initialization routines and start the SEF framework. - */ + sigset_t set; + int r; - sef_setcb_init_fresh(init); - sef_setcb_init_restart(init); + /* Only check for termination signal, ignore anything else. */ + if (signo != SIGTERM) return; - /* No live update support yet. */ + if (state.mounted) { + dprintf(("HGFS: got SIGTERM, still mounted\n")); + } + else { + dprintf(("HGFS: got SIGTERM, shutting down\n")); - sef_startup(); + /* Pass on the cleanup request to the HGFS library. */ + hgfs_cleanup(); + exit(0); + } } /*===========================================================================* - * cleanup * + * sef_local_startup * *===========================================================================*/ -PRIVATE void cleanup() +PRIVATE void sef_local_startup() { -/* Clean up any resources in use by this file server. Called at shutdown time. - */ + /* Register init callbacks. */ + sef_setcb_init_fresh(sef_cb_init_fresh); + sef_setcb_init_restart(sef_cb_init_fresh); + + /* No live update support yet. */ - /* Pass on the cleanup request to the HGFS library. */ - hgfs_cleanup(); + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); + + sef_startup(); } /*===========================================================================* @@ -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; - - while (TRUE) { - int r; - /* get an arbitrary pending signal */ - if((r=sys_getksig(&proc_nr_e, &sig_map)) != OK) - panic("sys_getksig failed: %d", r); - if (NONE == proc_nr_e) { /* stop if no more pending signals */ - break; - } else { - int proc_nr_p; - if(pm_isokendpt(proc_nr_e, &proc_nr_p) != OK) - panic("sys_getksig strange process: %d", proc_nr_e); - handle_ksig(proc_nr_e, sig_map); /* handle the received signal */ - /* If the process still exists to the kernel after the signal - * has been handled ... - */ - if ((mproc[proc_nr_p].mp_flags & (IN_USE | EXITING)) == IN_USE) - { - if((r=sys_endksig(proc_nr_e)) != OK) /* ... tell kernel it's done */ - panic("sys_endksig failed: %d", r); - } - } - } - return(SUSPEND); /* prevents sending reply */ +/* Perform the srv_kill(pid, signo) system call. */ + + /* Only RS is allowed to use srv_kill. */ + if (mp->mp_endpoint != RS_PROC_NR) + return EPERM; + + /* Pretend the signal comes from the kernel when RS wants to deliver a signal + * to a system process. RS sends a SIGKILL when it wants to perform cleanup. + * In that case, ksig == TRUE forces PM to exit the process immediately. + */ + return check_sig(m_in.pid, m_in.sig_nr, TRUE /* ksig */); } /*===========================================================================* - * handle_ksig * + * process_ksig * *===========================================================================*/ -PRIVATE void handle_ksig(proc_nr_e, sig_map) +PUBLIC int process_ksig(proc_nr_e, signo) int proc_nr_e; -sigset_t sig_map; +int signo; { register struct mproc *rmp; - int i, proc_nr; + int proc_nr; pid_t proc_id, id; if(pm_isokendpt(proc_nr_e, &proc_nr) != OK || proc_nr < 0) { - printf("PM: handle_ksig: %d?? not ok\n", proc_nr_e); + printf("PM: process_ksig: %d?? not ok\n", proc_nr_e); return; } rmp = &mproc[proc_nr]; if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) { #if 0 - printf("PM: handle_ksig: %d?? exiting / not in use\n", proc_nr_e); + printf("PM: process_ksig: %d?? exiting / not in use\n", proc_nr_e); #endif return; } @@ -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; - - /* This call requires special privileges. */ - if (!caller_is_root(m_ptr->m_source)) return(EPERM); + struct rprocpub *rpub; + int arg_count; + int len; + char *cmd_ptr; - /* See if there is a free entry in the table with system processes. */ - for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { - rp = &rproc[slot_nr]; /* get pointer to slot */ - if (!(rp->r_flags & RS_IN_USE)) /* check if available */ - break; - } - if (slot_nr >= NR_SYS_PROCS) - { - printf("RS: do_up: system process table full\n"); - return ENOMEM; - } rpub = rp->r_pub; - /* Ok, there is space. Get the request structure. */ - s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, - SELF, (vir_bytes) &rs_start, sizeof(rs_start)); - if (s != OK) return(s); - - /* Obtain command name and parameters. This is a space-separated string - * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional. - */ - if (rs_start.rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG); - s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_cmd, - SELF, (vir_bytes) rp->r_cmd, rs_start.rss_cmdlen); - if (s != OK) return(s); - rp->r_cmd[rs_start.rss_cmdlen] = '\0'; /* ensure it is terminated */ - if (rp->r_cmd[0] != '/') return(EINVAL); /* insist on absolute path */ - /* Build argument vector to be passed to execute call. The format of the * arguments vector is: path, arguments, NULL. */ + strcpy(rp->r_args, rp->r_cmd); /* copy raw command */ arg_count = 0; /* initialize arg count */ - rp->r_argv[arg_count++] = rp->r_cmd; /* start with path */ - cmd_ptr = rp->r_cmd; /* do some parsing */ + rp->r_argv[arg_count++] = rp->r_args; /* start with path */ + cmd_ptr = rp->r_args; /* do some parsing */ while(*cmd_ptr != '\0') { /* stop at end of string */ if (*cmd_ptr == ' ') { /* next argument */ *cmd_ptr = '\0'; /* terminate previous */ @@ -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,1285 +199,1337 @@ 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"); - } - } +/*===========================================================================* + * srv_fork * + *===========================================================================*/ +PUBLIC pid_t srv_fork() +{ + message m; - /* Check for duplicates */ - for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { - tmp_rp = &rproc[slot_nr]; /* get pointer to slot */ - if (!(tmp_rp->r_flags & RS_IN_USE)) /* check if available */ - continue; - if (tmp_rp == rp) - continue; /* Our slot */ - tmp_rpub = tmp_rp->r_pub; - if (strcmp(tmp_rpub->label, rpub->label) == 0) - { - printf("RS: found duplicate label '%s': slot %d\n", - rpub->label, slot_nr); - return EBUSY; - } - } + return(_syscall(PM_PROC_NR, SRV_FORK, &m)); +} - rp->r_script[0]= '\0'; - if (rs_start.rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG); - if (rs_start.rss_script != NULL) - { - s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_script, - SELF, (vir_bytes) rp->r_script, rs_start.rss_scriptlen); - if (s != OK) return(s); - rp->r_script[rs_start.rss_scriptlen] = '\0'; - } - rp->r_uid= rs_start.rss_uid; - rp->r_nice= rs_start.rss_nice; +/*===========================================================================* + * srv_kill * + *===========================================================================*/ +PUBLIC int srv_kill(pid_t pid, int sig) +{ + message m; - if (rs_start.rss_flags & RSS_IPC_VALID) - { - if (rs_start.rss_ipclen+1 > sizeof(rp->r_ipc_list)) - { - printf("rs: ipc list too long for '%s'\n", rpub->label); - return EINVAL; - } - s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_ipc, - SELF, (vir_bytes) rp->r_ipc_list, rs_start.rss_ipclen); - if (s != OK) return(s); - rp->r_ipc_list[rs_start.rss_ipclen]= '\0'; - } - else - rp->r_ipc_list[0]= '\0'; + m.m1_i1 = pid; + m.m1_i2 = sig; + return(_syscall(PM_PROC_NR, SRV_KILL, &m)); +} - rpub->sys_flags = DSRV_SF; - rp->r_exec= NULL; - if (rs_start.rss_flags & RSS_COPY) { - int exst_cpy; - struct rproc *rp2; - struct rprocpub *rpub2; - exst_cpy = 0; - - if(rs_start.rss_flags & RSS_REUSE) { - int i; +/*===========================================================================* + * update_period * + *===========================================================================*/ +PUBLIC void update_period(message *m_ptr) +{ + clock_t now = m_ptr->NOTIFY_TIMESTAMP; + short has_update_timed_out; + message m; + struct rprocpub *rpub; - for(i = 0; i < NR_SYS_PROCS; i++) { - rp2 = &rproc[i]; - rpub2 = rproc[i].r_pub; - if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 && - (rpub2->sys_flags & SF_USE_COPY)) { - /* We have found the same binary that's - * already been copied */ - exst_cpy = 1; - break; - } - } - } + rpub = rupdate.rp->r_pub; - if(!exst_cpy) - s = read_exec(rp); - else - s = share_exec(rp, rp2); + /* See if a timeout has occurred. */ + has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime); - if (s != OK) - return s; + /* If an update timed out, end the update process and notify + * the old version that the update has been canceled. From now on, the old + * version will continue executing. + */ + if(has_update_timed_out) { + printf("RS: update failed: maximum prepare time reached\n"); + end_update(EINTR); - rpub->sys_flags |= SF_USE_COPY; + /* Prepare cancel request. */ + m.m_type = RS_LU_PREPARE; + m.RS_LU_STATE = SEF_LU_STATE_NULL; + asynsend(rpub->endpoint, &m); } +} - /* All dynamically created services get the same privilege flags, and - * allowed traps. Other privilege settings can be specified at runtime. - * The privilege id is dynamically allocated by the kernel. - */ - rp->r_priv.s_flags = DSRV_F; /* privilege flags */ - rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */ +/*===========================================================================* + * end_update * + *===========================================================================*/ +PUBLIC void end_update(int result) +{ +/* End the update process. There are two possibilities: + * 1) the update succeeded. In that case, cleanup the old version and mark the + * new version as no longer under update. + * 2) the update failed. In that case, cleanup the new version and mark the old + * version as no longer under update. Eventual late ready to update + * messages (if any) will simply be ignored and the service can + * continue executing. In addition, reset the check timestamp, so that if the + * service has a period, a status request will be forced in the next period. + */ + struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp; + message m; - /* Copy granted resources */ - if (rs_start.rss_nr_irq > NR_IRQ) - { - printf("RS: do_up: too many IRQs requested\n"); - return EINVAL; - } - rp->r_priv.s_nr_irq= rs_start.rss_nr_irq; - for (i= 0; 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]); - } + old_rp = rupdate.rp; + new_rp = old_rp->r_new_rp; - if (rs_start.rss_nr_io > NR_IO_RANGE) - { - printf("RS: do_up: too many I/O ranges requested\n"); - return EINVAL; - } - rp->r_priv.s_nr_io_range= rs_start.rss_nr_io; - for (i= 0; 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_verbose) + printf("RS: ending update from %s to %s with result: %d\n", + srv_to_string(old_rp), srv_to_string(new_rp), result); - if (rs_start.rss_nr_pci_id > RS_NR_PCI_DEVICE) - { - printf("RS: do_up: too many PCI device IDs\n"); - return EINVAL; - } - rpub->pci_acl.rsp_nr_device = rs_start.rss_nr_pci_id; - for (i= 0; 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); - } + /* Decide which version has to die out and which version has to survive. */ + surviving_rp = (result == OK ? new_rp : old_rp); + exiting_rp = (result == OK ? old_rp : new_rp); - /* Copy 'system' call number bits */ - if (sizeof(rs_start.rss_system[0]) == sizeof(rp->r_call_mask[0]) && - sizeof(rs_start.rss_system) == sizeof(rp->r_call_mask)) - { - for (i= 0; 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)); - } + /* End update. */ + rupdate.flags &= ~RS_UPDATING; + rupdate.rp = NULL; + old_rp->r_new_rp = NULL; + new_rp->r_old_rp = NULL; + old_rp->r_check_tm = 0; - /* Initialize some fields. */ - rpub->period = rs_start.rss_period; - rpub->dev_nr = rs_start.rss_major; - rpub->dev_style = STYLE_DEV; - rp->r_restarts = -1; /* will be incremented */ - rp->r_set_resources= 1; /* set resources */ + /* Make the version that has to survive as active. */ + activate_service(surviving_rp, exiting_rp); - if (sizeof(rpub->vm_call_mask) == sizeof(rs_start.rss_vm) && - sizeof(rpub->vm_call_mask[0]) == sizeof(rs_start.rss_vm[0])) - { - int basic_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C }; - memcpy(rpub->vm_call_mask, rs_start.rss_vm, - sizeof(rpub->vm_call_mask)); - fill_call_mask(basic_vmc, NR_VM_CALLS, - rpub->vm_call_mask, VM_RQ_BASE, FALSE); - } - else - { - printf("RS: internal inconsistency: bad size of vm_call_mask\n"); - memset(rpub->vm_call_mask, '\0', sizeof(rpub->vm_call_mask)); - } + /* Send a late reply if necessary. */ + late_reply(old_rp, result); - /* All information was gathered. Now try to start the system service. */ - r = start_service(rp, 0, &ep); - m_ptr->RS_ENDPOINT = ep; - return r; -} + /* Unpublish and cleanup the version that has to die out and mark the other + * version as no longer updating. + */ + surviving_rp->r_flags &= ~RS_UPDATING; + unpublish_process(exiting_rp); + cleanup_service(exiting_rp); + if(rs_verbose) + printf("RS: service %s ended the update\n", srv_to_string(surviving_rp)); +} /*===========================================================================* - * do_down * + * kill_service_debug * *===========================================================================*/ -PUBLIC int do_down(message *m_ptr) +PUBLIC int kill_service_debug(file, line, rp, errstr, err) +char *file; +int line; +struct rproc *rp; +char *errstr; +int err; { - register struct rproc *rp; - register struct rprocpub *rpub; - size_t len; - int s, proc; - char label[RS_MAX_LABEL_LEN]; +/* Crash a system service and don't let it restart. */ + struct rprocpub *rpub; - /* This call requires special privileges. */ - if (!caller_is_root(m_ptr->m_source)) return(EPERM); + if(errstr && !shutting_down) { + printf("RS: %s (error %d)\n", errstr, err); + } + rp->r_flags |= RS_EXITING; /* expect exit */ + crash_service_debug(file, line, rp); /* simulate crash */ - len= m_ptr->RS_CMD_LEN; - if (len >= sizeof(label)) - return EINVAL; /* Too long */ + return err; +} - s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, - SELF, (vir_bytes) label, len); - if (s != OK) return(s); - label[len]= '\0'; +/*===========================================================================* + * crash_service_debug * + *===========================================================================*/ +PUBLIC int crash_service_debug(file, line, rp) +char *file; +int line; +struct rproc *rp; +{ +/* Simluate a crash in a system service. */ + struct rprocpub *rpub; - for (rp=BEG_RPROC_ADDR; 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); + rpub = rp->r_pub; - if(rs_verbose) - printf("RS: stopping '%s' (%d)\n", label, rp->r_pid); - stop_service(rp,RS_EXITING); - if (rp->r_pid == -1) - { - /* Process is already gone, release slot. */ - free_slot(rp); - return(OK); - } + if(rs_verbose) + printf("RS: %s %skilled at %s:%d\n", srv_to_string(rp), + rp->r_flags & RS_EXITING ? "lethally " : "", file, line); - /* Late reply - send a reply when process dies. */ - rp->r_flags |= RS_LATEREPLY; - rp->r_caller = m_ptr->m_source; - return EDONTREPLY; - } - } - if(rs_verbose) printf("RS: do_down: '%s' not found\n", label); - return(ESRCH); + return sys_kill(rpub->endpoint, SIGKILL); } - /*===========================================================================* - * do_restart * + * cleanup_service_debug * *===========================================================================*/ -PUBLIC int do_restart(message *m_ptr) +PUBLIC void cleanup_service_debug(file, line, rp) +char *file; +int line; +struct rproc *rp; { - register struct rproc *rp; - register struct rprocpub *rpub; - size_t len; - int s, proc, r; - char label[RS_MAX_LABEL_LEN]; - endpoint_t ep; +/* Ask PM to exit the service and free slot. */ + struct rprocpub *rpub; - len= m_ptr->RS_CMD_LEN; - if (len >= sizeof(label)) - return EINVAL; /* Too long */ + rpub = rp->r_pub; - s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, - SELF, (vir_bytes) label, len); - if (s != OK) return(s); - label[len]= '\0'; + if(rs_verbose) + printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp), + file, line); - /* This call requires special privileges. */ - if (! (caller_can_control(m_ptr->m_source, label) || - caller_is_root(m_ptr->m_source))) { + if(rp->r_pid == -1) { + printf("RS: warning: attempt to kill pid -1!\n"); + } + else { + srv_kill(rp->r_pid, SIGKILL); + } + + free_slot(rp); +} + +/*===========================================================================* + * create_service * + *===========================================================================*/ +PUBLIC int create_service(rp) +struct rproc *rp; +{ +/* Create the given system service. */ + int child_proc_nr_e, child_proc_nr_n; /* child process slot */ + pid_t child_pid; /* child's process id */ + char *file_only; + int s, use_copy, slot_nr; + bitchunk_t *vm_mask; + message m; + extern char **environ; + char * null_env = NULL; + struct rprocpub *rpub; + + rpub = rp->r_pub; + use_copy= (rpub->sys_flags & SF_USE_COPY); + + /* See if we are not using a copy but we do need one to start the service. */ + if(!use_copy && (rpub->sys_flags & SF_NEED_COPY)) { + printf("RS: unable to start service '%s' without an in-memory copy\n", + rpub->label); + free_slot(rp); return(EPERM); } - for (rp=BEG_RPROC_ADDR; 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); + /* Now fork and branch for parent and child process (and check for error). */ + if(rs_verbose) + printf("RS: forking child with srv_fork()...\n"); + child_pid= srv_fork(); + if(child_pid == -1) { + printf("RS: srv_fork() failed (error %d)\n", errno); + free_slot(rp); + return(errno); + } + + /* Get endpoint of the child. */ + child_proc_nr_e = getnprocnr(child_pid); + + /* There is now a child process. Update the system process table. */ + child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e); + rp->r_flags = RS_IN_USE; /* mark slot in use */ + rp->r_restarts += 1; /* raise nr of restarts */ + rp->r_old_rp = NULL; /* no old version yet */ + rp->r_new_rp = NULL; /* no new version yet */ + rp->r_prev_rp = NULL; /* no prev replica yet */ + rp->r_next_rp = NULL; /* no next replica yet */ + rpub->endpoint = child_proc_nr_e; /* set child endpoint */ + rp->r_pid = child_pid; /* set child pid */ + rp->r_check_tm = 0; /* not checked yet */ + getuptime(&rp->r_alive_tm); /* currently alive */ + rp->r_stop_tm = 0; /* not exiting yet */ + rp->r_backoff = 0; /* not to be restarted */ + rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */ + rpub->in_use = TRUE; /* public entry is now in use */ + + + /* Set resources when asked to. */ + if (rp->r_set_resources) { + /* Initialize privilege structure. */ + init_privs(rp, &rp->r_priv); + } + + /* Set and synch the privilege structure for the new service. */ + if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_SET_SYS, &rp->r_priv)) != OK + || (s = sys_getpriv(&rp->r_priv, child_proc_nr_e)) != OK) { + panic("unable to set privilege structure: %d", s); + } + + /* Copy the executable image into the child process. If this call + * fails, the child process may or may not be killed already. If it is + * not killed, it's blocked because of NO_PRIV. Kill it now either way. + * If no copy exists, allocate one and free it right after exec completes. + */ + if(use_copy) { + if(rs_verbose) + printf("RS: %s uses an in-memory copy\n", + srv_to_string(rp)); + } + else { + if ((s = read_exec(rp)) != OK) { + return kill_service(rp, "read_exec failed", s); } } - if(rs_verbose) { - printf("RS: do_restart: '%s' not found\n", label); + if(rs_verbose) + printf("RS: execing child with srv_execve()...\n"); + s = srv_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rp->r_argv, + environ); + + if (s != OK) { + return kill_service(rp, "srv_execve failed", s); } - - return(ESRCH); -} + if(!use_copy) { + free_exec(rp); + } + + /* The purpose of non-blocking forks is to avoid involving VFS in the forking + * process, because VFS may be blocked on a sendrec() to a MFS that is + * waiting for a endpoint update for a dead driver. We have just published + * that update, but VFS may still be blocked. As a result, VFS may not yet + * have received PM's fork message. Hence, if we call mapdriver() + * immediately, VFS may not know about the process and thus refuse to add the + * driver entry. The following temporary hack works around this by forcing + * blocking communication from PM to VFS. Once VFS has been made non-blocking + * towards MFS instances, this hack and the big part of srv_fork() can go. + */ + setuid(0); + + if(rs_verbose) + printf("RS: %s created\n", srv_to_string(rp)); + return OK; +} /*===========================================================================* - * do_refresh * + * publish_service * *===========================================================================*/ -PUBLIC int do_refresh(message *m_ptr) +PUBLIC int publish_service(rp) +struct rproc *rp; /* pointer to service slot */ { - register struct rproc *rp; - register struct rprocpub *rpub; - size_t len; - int s; - char label[RS_MAX_LABEL_LEN]; - - len= m_ptr->RS_CMD_LEN; - if (len >= sizeof(label)) - return EINVAL; /* Too long */ +/* Publish service-wide properties of a service. */ + int r; + struct rprocpub *rpub; - s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, - SELF, (vir_bytes) label, len); - if (s != OK) return(s); - label[len]= '\0'; + rpub = rp->r_pub; - /* This call requires special privileges. */ - if (! (caller_can_control(m_ptr->m_source, label) || - caller_is_root(m_ptr->m_source))) { - return(EPERM); + /* Register label with DS. */ + r = ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE); + if (r != OK) { + return kill_service(rp, "ds_publish_label call failed", r); } - for (rp=BEG_RPROC_ADDR; 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: %s service-wide properties published\n", + srv_to_string(rp)); - if(rs_verbose) { - printf("RS: refreshing %s (%d)\n", rpub->label, rp->r_pid); - } - stop_service(rp,RS_REFRESHING); - return(OK); + return OK; +} + +/*===========================================================================* + * publish_process * + *===========================================================================*/ +PUBLIC int publish_process(rp) +struct rproc *rp; /* pointer to service slot */ +{ +/* Publish process-wide properties of a service. */ + int r; + struct rprocpub *rpub; + struct rs_pci pci_acl; + + rpub = rp->r_pub; + + /* If PCI properties are set, inform the PCI driver about the new service. */ + if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) { + pci_acl = rpub->pci_acl; + strcpy(pci_acl.rsp_label, rpub->label); + pci_acl.rsp_endpoint= rpub->endpoint; + + r = pci_set_acl(&pci_acl); + if (r != OK) { + return kill_service(rp, "pci_set_acl call failed", r); } } - if(rs_verbose) { - printf("RS: do_refresh: '%s' not found\n", label); + + /* Tell VM about allowed calls, if any. */ + if(rpub->vm_call_mask[0]) { + r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0]); + if (r != OK) { + return kill_service(rp, "vm_set_priv call failed", r); + } } - - return(ESRCH); + + if(rs_verbose) + printf("RS: %s process-wide properties published\n", + srv_to_string(rp)); + + return OK; } /*===========================================================================* - * do_shutdown * + * unpublish_service * *===========================================================================*/ -PUBLIC int do_shutdown(message *m_ptr) +PUBLIC int unpublish_service(rp) +struct rproc *rp; /* pointer to service slot */ { - /* This call requires special privileges. */ - if (m_ptr != NULL && !caller_is_root(m_ptr->m_source)) return(EPERM); +/* Unpublish service-wide properties of a service. */ + struct rprocpub *rpub; + int r, result; - /* Set flag so that RS server knows services shouldn't be restarted. */ - shutting_down = TRUE; - return(OK); -} + rpub = rp->r_pub; + result = OK; + /* Unregister label with DS. */ + r = ds_delete_label(rpub->label); + if (r != OK && !shutting_down) { + printf("RS: ds_delete_label call failed (error %d)\n", r); + result = r; + } + + /* No need to inform VFS, cleanup is performed on exit automatically. */ + + if(rs_verbose) + printf("RS: %s service-wide properties unpublished\n", + srv_to_string(rp)); + + return result; +} /*===========================================================================* - * do_init_ready * + * unpublish_process * *===========================================================================*/ -PUBLIC int do_init_ready(message *m_ptr) +PUBLIC int unpublish_process(rp) +struct rproc *rp; /* pointer to service slot */ { - int who_p; - struct rproc *rp; +/* Unpublish process-wide properties of a service. */ struct rprocpub *rpub; - int result; + int r, result; - who_p = _ENDPOINT_P(m_ptr->m_source); - rp = rproc_ptr[who_p]; rpub = rp->r_pub; - result = m_ptr->RS_INIT_RESULT; + result = OK; - /* Make sure the originating service was requested to initialize. */ - if(! (rp->r_flags & RS_INITIALIZING) ) { - if(rs_verbose) { - printf("RS: do_init_ready: got unexpected init ready msg from %d\n", - m_ptr->m_source); + /* If PCI properties are set, inform the PCI driver. */ + if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) { + r = pci_del_acl(rpub->endpoint); + if (r != OK && !shutting_down) { + printf("RS: pci_del_acl call failed (error %d)\n", r); + result = r; } - return(EINVAL); } - /* Mark the slot as no longer initializing. */ - rp->r_flags &= ~RS_INITIALIZING; - rp->r_check_tm = 0; - getuptime(&rp->r_alive_tm); + /* No need to inform VM, cleanup is performed on exit automatically. */ - /* Check if something went wrong and the service failed to init. - * In that case, kill it and make sure it won't be restarted. - */ - if(result != OK) { - if(rs_verbose) - printf("RS: initialization failed for service %d: %d\n", - rpub->endpoint, result); - rp->r_flags |= RS_EXITING; - kill(rp->r_pid, SIGKILL); + if(rs_verbose) + printf("RS: %s process-wide properties unpublished\n", + srv_to_string(rp)); + + return result; +} + +/*===========================================================================* + * run_service * + *===========================================================================*/ +PUBLIC int run_service(rp, init_type) +struct rproc *rp; +int init_type; +{ +/* Let a newly created service run. */ + int s, use_copy; + struct rprocpub *rpub; + + rpub = rp->r_pub; + use_copy= (rpub->sys_flags & SF_USE_COPY); + + /* Allow the service to run. */ + if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) { + return kill_service(rp, "unable to allow the service to run",s); } - else { - if(rs_verbose) - printf("RS: initialization succeeded for service %d\n", - rpub->endpoint); + + /* Initialize service. */ + if((s = init_service(rp, init_type)) != OK) { + return kill_service(rp, "unable to initialize service", s); } - return(EDONTREPLY); + if(rs_verbose) + printf("RS: %s allowed to run\n", srv_to_string(rp)); + + return OK; } /*===========================================================================* - * do_update * + * start_service * *===========================================================================*/ -PUBLIC int do_update(message *m_ptr) +PUBLIC int start_service(rp) +struct rproc *rp; { - register struct rproc *rp; - register struct rprocpub *rpub; - size_t len; - int s; - char label[RS_MAX_LABEL_LEN]; - int lu_state; - int prepare_maxtime; - - /* Retrieve label. */ - len= m_ptr->RS_CMD_LEN; - if (len >= sizeof(label)) - return EINVAL; /* Too long */ - s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR, - SELF, (vir_bytes) label, len); - if (s != OK) return(s); - label[len]= '\0'; +/* Start a system service. */ + int r, init_type; + struct rprocpub *rpub; - /* This call requires special privileges. */ - if (! (caller_can_control(m_ptr->m_source, label) || - caller_is_root(m_ptr->m_source))) { - return(EPERM); - } + rpub = rp->r_pub; - /* Retrieve live update state. */ - lu_state = m_ptr->RS_LU_STATE; - if(lu_state == SEF_LU_STATE_NULL) { - return(EINVAL); + /* Create. */ + r = create_service(rp); + if(r != OK) { + return r; } - /* Retrieve prepare max time. */ - prepare_maxtime = m_ptr->RS_LU_PREPARE_MAXTIME; - if(prepare_maxtime) { - if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) { - return(EINVAL); - } + /* Publish service properties. */ + r = publish_process(rp); + if (r != OK) { + return r; } - else { - prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME; + r = publish_service(rp); + if (r != OK) { + return r; } - /* Make sure we are not already updating. */ - if(rupdate.flags & RS_UPDATING) { - if(rs_verbose) { - printf("RS: do_update: an update is already in progress"); - } - return(EBUSY); + /* Run. */ + init_type = rp->r_restarts > 0 ? SEF_INIT_RESTART : SEF_INIT_FRESH; + r = run_service(rp, init_type); + if(r != OK) { + return r; } - /* Try to start the update process. */ - for (rp=BEG_RPROC_ADDR; 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; - } + /* The system service now has been successfully started. The only thing + * that can go wrong now, is that execution fails at the child. If that's + * the case, the child will exit. + */ + if(rs_verbose) + printf("RS: %s started with major %d\n", srv_to_string(rp), + rpub->dev_nr); - if(rs_verbose) { - printf("RS: updating %s (%d)\n", rpub->label, rp->r_pid); - } + return OK; +} - rp->r_flags |= RS_UPDATING; - rupdate.flags |= RS_UPDATING; - getuptime(&rupdate.prepare_tm); - rupdate.prepare_maxtime = prepare_maxtime; - rupdate.rp = rp; +/*===========================================================================* + * stop_service * + *===========================================================================*/ +PUBLIC void stop_service(struct rproc *rp,int how) +{ + struct rprocpub *rpub; - m_ptr->m_type = RS_LU_PREPARE; - asynsend(rpub->endpoint, m_ptr); /* request to update */ + rpub = rp->r_pub; - return(OK); - } + /* Try to stop the system service. First send a SIGTERM signal to ask the + * system service to terminate. If the service didn't install a signal + * handler, it will be killed. If it did and ignores the signal, we'll + * find out because we record the time here and send a SIGKILL. + */ + if(rs_verbose) + printf("RS: %s signaled with SIGTERM\n", srv_to_string(rp)); + + rp->r_flags |= how; /* what to on exit? */ + sys_kill(rpub->endpoint, SIGTERM); /* first try friendly */ + getuptime(&rp->r_stop_tm); /* record current time */ +} + +/*===========================================================================* + * update_service * + *===========================================================================*/ +PUBLIC int update_service(src_rpp, dst_rpp) +struct rproc **src_rpp; +struct rproc **dst_rpp; +{ +/* Update an existing service. */ + int r; + struct rproc *src_rp; + struct rproc *dst_rp; + struct rprocpub *src_rpub; + struct rprocpub *dst_rpub; + int pid; + endpoint_t endpoint; + + src_rp = *src_rpp; + dst_rp = *dst_rpp; + src_rpub = src_rp->r_pub; + dst_rpub = dst_rp->r_pub; + + if(rs_verbose) + printf("RS: %s updating into %s\n", + srv_to_string(src_rp), srv_to_string(dst_rp)); + + /* Ask VM to swap the slots of the two processes and tell the kernel to + * do the same. + */ + r = vm_update(src_rpub->endpoint, dst_rpub->endpoint); + if(r != OK) { + return r; } - if(rs_verbose) { - printf("RS: do_update: '%s' not found\n", label); + + /* Swap slots here as well. */ + pid = src_rp->r_pid; + endpoint = src_rpub->endpoint; + swap_slot(&src_rp, &dst_rp); + + /* Reassign pids and endpoints. */ + src_rp->r_pid = dst_rp->r_pid; + src_rp->r_pub->endpoint = dst_rp->r_pub->endpoint; + rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)] = src_rp; + dst_rp->r_pid = pid; + dst_rp->r_pub->endpoint = endpoint; + rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp; + + /* Adjust input pointers. */ + *src_rpp = src_rp; + *dst_rpp = dst_rp; + + if(rs_verbose) + printf("RS: %s updated into %s\n", + srv_to_string(src_rp), srv_to_string(dst_rp)); + + return OK; +} + +/*===========================================================================* + * activate_service * + *===========================================================================*/ +PUBLIC void activate_service(struct rproc *rp, struct rproc *ex_rp) +{ +/* Activate a service instance and deactivate another one if requested. */ + + if(ex_rp && (ex_rp->r_flags & RS_ACTIVE) ) { + ex_rp->r_flags &= ~RS_ACTIVE; + if(rs_verbose) + printf("RS: %s becomes inactive\n", srv_to_string(ex_rp)); } - return(ESRCH); + if(! (rp->r_flags & RS_ACTIVE) ) { + rp->r_flags |= RS_ACTIVE; + if(rs_verbose) + printf("RS: %s becomes active\n", srv_to_string(rp)); + } } /*===========================================================================* - * do_upd_ready * + * terminate_service * *===========================================================================*/ -PUBLIC int do_upd_ready(message *m_ptr) +PUBLIC void terminate_service(struct rproc *rp) { - register struct rproc *rp; - int who_p; - clock_t now = m_ptr->NOTIFY_TIMESTAMP; - int result; +/* Handle a termination event for a system service. */ + struct rproc **rps; + struct rprocpub *rpub; + int nr_rps; + int i, r; - who_p = _ENDPOINT_P(m_ptr->m_source); - rp = rproc_ptr[who_p]; - result = m_ptr->RS_LU_RESULT; + rpub = rp->r_pub; - /* Make sure the originating service was requested to prepare for update. */ - if(! (rp->r_flags & RS_UPDATING) ) { - if(rs_verbose) { - printf("RS: do_upd_ready: got unexpected update ready msg from %d\n", - m_ptr->m_source); + if(rs_verbose) + printf("RS: %s terminated\n", srv_to_string(rp)); + + /* Deal with failures during initialization. */ + if(rp->r_flags & RS_INITIALIZING) { + printf("RS: service '%s' exited during initialization\n", rpub->label); + rp->r_flags |= RS_EXITING; /* don't restart. */ + + /* If updating, rollback. */ + if(rp->r_flags & RS_UPDATING) { + message m; + struct rproc *old_rp, *new_rp; + printf("RS: update failed: state transfer failed. Rolling back...\n"); + new_rp = rp; + old_rp = new_rp->r_old_rp; + new_rp->r_flags &= ~RS_INITIALIZING; + update_service(&new_rp, &old_rp); /* can't fail */ + m.m_type = ERESTART; + reply(old_rp->r_pub->endpoint, &m); + end_update(ERESTART); + return; } - return(EINVAL); } - /* Check if something went wrong and the service failed to prepare - * for the update. In that case, end the update process. - */ - if(result != OK) { - end_update(now); - switch(result) { - case EACCES: - printf("RS: update failed: %s\n", - "service does not support live update"); - break; + if (rp->r_flags & RS_EXITING) { + /* If a core system service is exiting, we are in trouble. */ + if (rp->r_pub->sys_flags & SF_CORE_SRV && !shutting_down) { + panic("core system service died: %s", srv_to_string(rp)); + } - case EINVAL: - printf("RS: update failed: %s\n", - "service does not support the required state"); - break; + /* See if a late reply has to be sent. */ + r = (rp->r_caller_request == RS_DOWN ? OK : EDEADSRCDST); + late_reply(rp, r); - case EBUSY: - printf("RS: update failed: %s\n", - "service is not able to prepare for the update now"); - break; + /* Unpublish the service. */ + unpublish_service(rp); + unpublish_process(rp); - case EGENERIC: - printf("RS: update failed: %s\n", - "a generic error occurred while preparing for the update"); - break; + /* Cleanup all the instances of the service. */ + get_service_instances(rp, &rps, &nr_rps); + for(i=0;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); + } - default: - printf("RS: update failed: %s (%d)\n", - "an unknown error occurred while preparing for the update\n", - result); - break; + /* Determine what to do. If this is the first unexpected + * exit, immediately restart this service. Otherwise use + * a binary exponential backoff. + */ + if (rp->r_restarts > 0) { + rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2)); + rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF); + if ((rpub->sys_flags & SF_USE_COPY) && rp->r_backoff > 1) + rp->r_backoff= 1; + return; } - return(OK); + /* Restart service. */ + restart_service(rp); } +} - /* Kill the process now and mark it for refresh, the new version will - * be automatically restarted. - */ - rp->r_flags &= ~RS_EXITING; - rp->r_flags |= RS_REFRESHING; - kill(rp->r_pid, SIGKILL); +/*===========================================================================* + * restart_service * + *===========================================================================*/ +PUBLIC void restart_service(rp) +struct rproc *rp; +{ +/* Restart service via a recovery script or directly. */ + struct rproc *replica_rp; + int r; + + /* See if a late reply has to be sent. */ + late_reply(rp, OK); - return(EDONTREPLY); + if (rp->r_script[0] != '\0') { + /* Run a recovery script. */ + run_script(rp); + } + else { + /* Unpublish the service. */ + unpublish_service(rp); + unpublish_process(rp); + + /* Clone slots. */ + if((r = clone_slot(rp, &replica_rp)) != OK) { + kill_service(rp, "unable to clone service", r); + return; + } + + if(rs_verbose) + printf("RS: %s restarting into %s\n", + srv_to_string(rp), srv_to_string(replica_rp)); + + /* Swap slots. */ + swap_slot(&rp, &replica_rp); + + /* Direct restart. */ + if((r = start_service(replica_rp)) != OK) { + kill_service(rp, "unable to restart service", r); + return; + } + + /* Link the two slots. */ + rp->r_next_rp = replica_rp; + replica_rp->r_prev_rp = rp; + + if(rs_verbose) + printf("RS: %s restarted into %s\n", + srv_to_string(rp), srv_to_string(replica_rp)); + } } /*===========================================================================* - * update_period * + * inherit_service_defaults * *===========================================================================*/ -PRIVATE void update_period(message *m_ptr) +PUBLIC void inherit_service_defaults(def_rp, rp) +struct rproc *def_rp; +struct rproc *rp; { - clock_t now = m_ptr->NOTIFY_TIMESTAMP; - short has_update_timed_out; - message m; + struct rprocpub *def_rpub; struct rprocpub *rpub; - rpub = rupdate.rp->r_pub; - - /* See if a timeout has occurred. */ - has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime); + def_rpub = def_rp->r_pub; + rpub = rp->r_pub; - /* If an update timed out, end the update process and notify the service. */ - if(has_update_timed_out) { - end_update(now); - printf("RS: update failed: maximum prepare time reached\n"); + /* Device settings. These properties cannot change. */ + rpub->dev_nr = def_rpub->dev_nr; + rpub->dev_style = def_rpub->dev_style; - /* Prepare cancel request. */ - m.m_type = RS_LU_PREPARE; - m.RS_LU_STATE = SEF_LU_STATE_NULL; - asynsend(rpub->endpoint, &m); + /* Period. */ + if(!rpub->period && def_rpub->period) { + rpub->period = def_rpub->period; } } /*===========================================================================* - * end_update * + * get_service_instances * *===========================================================================*/ -PRIVATE void end_update(clock_t now) +PUBLIC void get_service_instances(rp, rps, length) +struct rproc *rp; +struct rproc ***rps; +int *length; { - /* End the update process and mark the affected service as no longer under - * update. Eventual late ready to update message (if any) will simply be - * ignored and the service can continue executing. - * We reset the check timestamp, so that if the service has a period a status - * request will be forced in the next period. - */ - rupdate.flags &= ~RS_UPDATING; - rupdate.rp->r_flags &= ~RS_UPDATING; - rupdate.rp->r_check_tm = 0; +/* Retrieve all the service instances of a give service. */ + static struct rproc *instances[5]; + int nr_instances; + + nr_instances = 0; + instances[nr_instances++] = rp; + if(rp->r_prev_rp) instances[nr_instances++] = rp->r_prev_rp; + if(rp->r_next_rp) instances[nr_instances++] = rp->r_next_rp; + if(rp->r_old_rp) instances[nr_instances++] = rp->r_old_rp; + if(rp->r_new_rp) instances[nr_instances++] = rp->r_new_rp; + + *rps = instances; + *length = nr_instances; } /*===========================================================================* - * do_exit * + * share_exec * *===========================================================================*/ -PUBLIC void do_exit(message *m_ptr) +PUBLIC void share_exec(rp_dst, rp_src) +struct rproc *rp_dst, *rp_src; { - register struct rproc *rp; - register struct rprocpub *rpub; - pid_t exit_pid; - int exit_status, r, slot_nr; - endpoint_t ep; - clock_t now = m_ptr->NOTIFY_TIMESTAMP; - - if(rs_verbose) - printf("RS: got SIGCHLD signal, doing wait to get exited child.\n"); + struct rprocpub *rpub_src; + struct rprocpub *rpub_dst; - /* See which child exited and what the exit status is. This is done in a - * loop because multiple children may have exited, all reported by one - * SIGCHLD signal. The WNOHANG options is used to prevent blocking if, - * somehow, no exited child can be found. - */ - while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) { - - if(rs_verbose) { -#if 0 - printf("RS: pid %d, ", exit_pid); -#endif - if (WIFSIGNALED(exit_status)) { -#if 0 - printf("killed, signal number %d\n", WTERMSIG(exit_status)); -#endif - } - else if (WIFEXITED(exit_status)) { -#if 0 - printf("normal exit, status %d\n", WEXITSTATUS(exit_status)); -#endif - } - } + rpub_src = rp_src->r_pub; + rpub_dst = rp_dst->r_pub; - /* Read from the exec pipe */ - for (;;) - { - r= read(exec_pipe[0], &slot_nr, sizeof(slot_nr)); - if (r == -1) - { - break; /* No data */ - } - if (r != sizeof(slot_nr)) - { - panic("do_exit: unaligned read from exec pipe: %d", r); - } - printf("do_exit: got slot %d\n", slot_nr); - if (slot_nr < 0 || slot_nr >= NR_SYS_PROCS) - { - panic("do_exit: bad slot number from exec pipe: %d", slot_nr); - } - rp= &rproc[slot_nr]; - rp->r_flags |= RS_EXITING; - } + if(rs_verbose) + printf("RS: %s shares exec image with %s\n", + srv_to_string(rp_dst), srv_to_string(rp_src)); - /* Search the system process table to see who exited. - * This should always succeed. - */ - for (rp=BEG_RPROC_ADDR; 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; - } - } - } + /* Share exec image from rp_src to rp_dst. */ + rp_dst->r_exec_len = rp_src->r_exec_len; + rp_dst->r_exec = rp_src->r_exec; } /*===========================================================================* - * do_period * + * read_exec * *===========================================================================*/ -PUBLIC void do_period(m_ptr) -message *m_ptr; +PUBLIC int read_exec(rp) +struct rproc *rp; { - register struct rproc *rp; - register struct rprocpub *rpub; - clock_t now = m_ptr->NOTIFY_TIMESTAMP; - int s; - endpoint_t ep; - long period; + int e, r, fd; + char *e_name; + struct stat sb; + + e_name= rp->r_argv[0]; + if(rs_verbose) + printf("RS: service '%s' reads exec image from: %s\n", rp->r_pub->label, + e_name); + + r= stat(e_name, &sb); + if (r != 0) + return -errno; + + fd= open(e_name, O_RDONLY); + if (fd == -1) + return -errno; - /* If an update is in progress, check its status. */ - if(rupdate.flags & RS_UPDATING) { - update_period(m_ptr); + rp->r_exec_len= sb.st_size; + rp->r_exec= malloc(rp->r_exec_len); + if (rp->r_exec == NULL) + { + printf("RS: read_exec: unable to allocate %d bytes\n", + rp->r_exec_len); + close(fd); + return ENOMEM; } - /* Search system services table. Only check slots that are in use and not - * updating. - */ - for (rp=BEG_RPROC_ADDR; rpr_pub; - if ((rp->r_flags & RS_IN_USE) && !(rp->r_flags & RS_UPDATING)) { + r= read(fd, rp->r_exec, rp->r_exec_len); + e= errno; + close(fd); + if (r == rp->r_exec_len) + return OK; - /* Compute period. */ - period = rpub->period; - if(rp->r_flags & RS_INITIALIZING) { - period = RS_INIT_T; - } + printf("RS: read_exec: read failed %d, errno %d\n", r, e); - /* If the service is to be revived (because it repeatedly exited, - * and was not directly restarted), the binary backoff field is - * greater than zero. - */ - if (rp->r_backoff > 0) { - rp->r_backoff -= 1; - if (rp->r_backoff == 0) { - start_service(rp, 0, &ep); - m_ptr->RS_ENDPOINT = ep; - } - } - - /* If the service was signaled with a SIGTERM and fails to respond, - * kill the system service with a SIGKILL signal. - */ - else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T - && rp->r_pid > 0) { - kill(rp->r_pid, SIGKILL); /* terminate */ - } - - /* There seems to be no special conditions. If the service has a - * period assigned check its status. - */ - else if (period > 0) { - - /* Check if an answer to a status request is still pending. If - * the service didn't respond within time, kill it to simulate - * a crash. The failure will be detected and the service will - * be restarted automatically. - */ - if (rp->r_alive_tm < rp->r_check_tm) { - if (now - rp->r_alive_tm > 2*period && - rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) { - if(rs_verbose) - printf("RS: service %d reported late\n", - rpub->endpoint); - rp->r_flags |= RS_NOPINGREPLY; - if(rp->r_flags & RS_INITIALIZING) { - rp->r_flags |= RS_EXITING; /* don't restart */ - } - kill(rp->r_pid, SIGKILL); /* simulate crash */ - } - } - - /* No answer pending. Check if a period expired since the last - * check and, if so request the system service's status. - */ - else if (now - rp->r_check_tm > rpub->period) { -#if 0 - if(rs_verbose) - printf("RS: status request sent to %d\n", rpub->endpoint); -#endif - notify(rpub->endpoint); /* request status */ - rp->r_check_tm = now; /* mark time */ - } - } + free_exec(rp); + + if (r >= 0) + return EIO; + else + return -e; +} + +/*===========================================================================* + * free_exec * + *===========================================================================*/ +PUBLIC void free_exec(rp) +struct rproc *rp; +{ +/* Free an exec image. */ + int slot_nr, has_shared_exec; + struct rproc *other_rp; + + /* Search for some other slot sharing the same exec image. */ + has_shared_exec = FALSE; + for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { + other_rp = &rproc[slot_nr]; /* get pointer to slot */ + if (other_rp->r_flags & RS_IN_USE && other_rp != rp + && other_rp->r_exec == rp->r_exec) { /* found! */ + has_shared_exec = TRUE; + break; } } - /* Reschedule a synchronous alarm for the next period. */ - if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) - panic("couldn't set alarm: %d", s); + /* If nobody uses our copy of the exec image, we can get rid of it. */ + if(!has_shared_exec) { + if(rs_verbose) + printf("RS: %s frees exec image\n", srv_to_string(rp)); + free(rp->r_exec); + } + else { + if(rs_verbose) + printf("RS: %s no longer sharing exec image with %s\n", + srv_to_string(rp), srv_to_string(other_rp)); + } + rp->r_exec = NULL; + rp->r_exec_len = 0; } - /*===========================================================================* - * start_service * + * init_slot * *===========================================================================*/ -PRIVATE int start_service(rp, flags, endpoint) +PUBLIC int init_slot(rp, rs_start, source) struct rproc *rp; -int flags; -endpoint_t *endpoint; +struct rs_start *rs_start; +endpoint_t source; { -/* Try to execute the given system service. Fork a new process. The child - * process will be inhibited from running by the NO_PRIV flag. Only let the - * child run once its privileges have been set by the parent. - */ - int child_proc_nr_e, child_proc_nr_n; /* child process slot */ - pid_t child_pid; /* child's process id */ - char *file_only; - int s, use_copy, slot_nr, init_type; - bitchunk_t *vm_mask; - message m; - char * null_env = NULL; +/* Initialize a slot as requested by the client. */ struct rprocpub *rpub; + int slot_nr; /* local table entry */ + int arg_count; /* number of arguments */ + char *cmd_ptr; /* parse command string */ + char *label; /* unique name of command */ + enum dev_style dev_style; /* device style */ + struct rproc *tmp_rp; + struct rprocpub *tmp_rpub; + int len; /* length of string */ + int i; + int s; + int basic_kc[] = { SYS_BASIC_CALLS, SYS_NULL_C }; + int basic_vmc[] = { VM_BASIC_CALLS, SYS_NULL_C }; + + rpub = rp->r_pub; + +/* Obtain command name and parameters. This is a space-separated string + * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional. + */ + if (rs_start->rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG); + s=sys_datacopy(source, (vir_bytes) rs_start->rss_cmd, + SELF, (vir_bytes) rp->r_cmd, rs_start->rss_cmdlen); + if (s != OK) return(s); + rp->r_cmd[rs_start->rss_cmdlen] = '\0'; /* ensure it is terminated */ + if (rp->r_cmd[0] != '/') return(EINVAL); /* insist on absolute path */ + + /* Build cmd dependencies: argv and program name. */ + build_cmd_dep(rp); + + if(rs_start->rss_label.l_len > 0) { + /* RS_UP caller has supplied a custom label for this service. */ + int s = copy_label(source, rs_start->rss_label.l_addr, + rs_start->rss_label.l_len, rpub->label, sizeof(rpub->label)); + if(s != OK) + return s; + if(rs_verbose) + printf("RS: init_slot: using label (custom) '%s'\n", rpub->label); + } else { + /* Default label for the service. */ + label = rpub->proc_name; + len= strlen(label); + memcpy(rpub->label, label, len); + rpub->label[len]= '\0'; + if(rs_verbose) + printf("RS: init_slot: using label (from proc_name) '%s'\n", + rpub->label); + } + + if(rs_start->rss_nr_control > 0) { + int i, s; + if (rs_start->rss_nr_control > RS_NR_CONTROL) + { + printf("RS: init_slot: too many control labels\n"); + return EINVAL; + } + for (i=0; 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; + } + } + } - rpub = rp->r_pub; - use_copy= (rpub->sys_flags & SF_USE_COPY); + s = OK; + if(!exst_cpy) + s = read_exec(rp); + else + share_exec(rp, rp2); - /* See if we are not using a copy but we do need one to start the service. */ - if(!use_copy && (rpub->sys_flags & SF_NEED_COPY)) { - printf("RS: unable to start service %s without an in-memory copy\n", - rpub->label); - free_slot(rp); - return(EPERM); - } + if (s != OK) + return s; - /* Now fork and branch for parent and child process (and check for error). */ - if (use_copy) { - if(rs_verbose) printf("RS: fork_nb..\n"); - child_pid= fork_nb(); - } else { - if(rs_verbose) printf("RS: fork regular..\n"); - child_pid = fork(); + rpub->sys_flags |= SF_USE_COPY; } - switch(child_pid) { /* see fork(2) */ - case -1: /* fork failed */ - printf("RS: warning, fork() failed: %d\n", errno); /* shouldn't happen */ - return(errno); /* return error */ - - case 0: /* child process */ - /* Try to execute the binary that has an absolute path. If this fails, - * e.g., because the root file system cannot be read, try to strip off - * the path, and see if the command is in RS' current working dir. - */ - nice(rp->r_nice); /* Nice before setuid, to allow negative - * nice values. - */ - setuid(rp->r_uid); - cpf_reload(); /* Tell kernel about grant table */ - if (!use_copy) - { - execve(rp->r_argv[0], rp->r_argv, &null_env); /* POSIX execute */ - file_only = strrchr(rp->r_argv[0], '/') + 1; - execve(file_only, rp->r_argv, &null_env); /* POSIX execute */ - } - printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno); - slot_nr= rp-rproc; - s= write(exec_pipe[1], &slot_nr, sizeof(slot_nr)); - if (s != sizeof(slot_nr)) - printf("RS: write to exec pipe failed: %d/%d\n", s, errno); - exit(1); /* terminate child */ - - default: /* parent process */ -#if 0 - if(rs_verbose) printf("RS: parent forked, pid %d..\n", child_pid); -#endif - child_proc_nr_e = getnprocnr(child_pid); /* get child slot */ -#if 0 - if(rs_verbose) printf("RS: forked into %d..\n", child_proc_nr_e); -#endif - break; /* continue below */ - } - - /* Regardless of any following failures, there is now a child process. - * Update the system process table that is maintained by the RS server. - */ - child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e); - rp->r_flags = RS_IN_USE | flags; /* mark slot in use */ - rp->r_restarts += 1; /* raise nr of restarts */ - rpub->endpoint = child_proc_nr_e; /* set child details */ - rp->r_pid = child_pid; - rp->r_check_tm = 0; /* not checked yet */ - getuptime(&rp->r_alive_tm); /* currently alive */ - rp->r_stop_tm = 0; /* not exiting yet */ - rp->r_backoff = 0; /* not to be restarted */ - rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */ - rpub->in_use = TRUE; /* public entry is now in use */ - - /* If any of the calls below fail, the RS_EXITING flag is set. This implies - * that the process will be removed from RS's process table once it has - * terminated. The assumption is that it is not useful to try to restart the - * process later in these failure cases. + /* All dynamically created services get the same privilege flags, and + * allowed traps, and signal manager. Other privilege settings can be + * specified at runtime. The privilege id is dynamically allocated by + * the kernel. */ + rp->r_priv.s_flags = DSRV_F; /* privilege flags */ + rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */ + rp->r_priv.s_sig_mgr = DSRV_SM; /* signal manager */ - if (use_copy) + /* Copy granted resources */ + if (rs_start->rss_nr_irq > NR_IRQ) { - extern char **environ; - - /* Copy the executable image into the child process. If this call - * fails, the child process may or may not be killed already. If it is - * not killed, it's blocked because of NO_PRIV. Kill it now either way. - */ - s = dev_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rp->r_argv, - environ); - if (s != OK) { - printf("RS: dev_execve call failed: %d\n", s); - kill(child_pid, SIGKILL); - rp->r_flags |= RS_EXITING; /* don't try again */ - return(s); - } + printf("RS: init_slot: too many IRQs requested\n"); + return EINVAL; } - - /* Set resources when asked to. */ - if (rp->r_set_resources) + rp->r_priv.s_nr_irq= rs_start->rss_nr_irq; + for (i= 0; ir_priv.s_nr_irq; i++) { - /* Initialize privilege structure. */ - init_privs(rp, &rp->r_priv); - - /* Tell VM about allowed calls. */ - vm_mask = &rpub->vm_call_mask[0]; - if ((s = vm_set_priv(child_proc_nr_e, vm_mask)) < 0) { - printf("RS: vm_set_priv call failed: %d\n", s); - kill(child_pid, SIGKILL); - rp->r_flags |= RS_EXITING; - return (s); - } + rp->r_priv.s_irq_tab[i]= rs_start->rss_irq[i]; + if(rs_verbose) + printf("RS: init_slot: IRQ %d\n", rp->r_priv.s_irq_tab[i]); } - /* Set and synch the privilege structure for the new service. */ - if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_SET_SYS, &rp->r_priv)) != OK - || (s = sys_getpriv(&rp->r_priv, child_proc_nr_e)) != OK) { - printf("RS: unable to set privileges: %d\n", s); - kill(child_pid, SIGKILL); /* kill the service */ - rp->r_flags |= RS_EXITING; /* expect exit */ - return(s); /* return error */ + if (rs_start->rss_nr_io > NR_IO_RANGE) + { + printf("RS: init_slot: too many I/O ranges requested\n"); + return EINVAL; } - - /* If PCI properties are set, inform the PCI driver about the new service. */ - if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) { - init_pci(rp, child_proc_nr_e); + rp->r_priv.s_nr_io_range= rs_start->rss_nr_io; + for (i= 0; 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); } - /* Publish the new system service. */ - s = publish_service(rp); - if (s != OK) { - printf("RS: warning: publish_service failed: %d\n", s); + if (rs_start->rss_nr_pci_id > RS_NR_PCI_DEVICE) + { + printf("RS: init_slot: too many PCI device IDs\n"); + return EINVAL; } - - /* Allow the service to run. - * XXX: We should let the service run/init only after publishing information - * about the new system service, but this is not currently possible due to - * the blocking nature of mapdriver() that expects the service to be running. - * The current solution is not race-free. This hack can go once service - * publishing is made fully asynchronous in RS. - */ - if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_ALLOW, NULL)) != OK) { - printf("RS: unable to allow the service to run: %d\n", s); - kill(child_pid, SIGKILL); /* kill the service */ - rp->r_flags |= RS_EXITING; /* expect exit */ - return(s); /* return error */ + rpub->pci_acl.rsp_nr_device = rs_start->rss_nr_pci_id; + for (i= 0; 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); } - - /* Initialize service. */ - init_type = rp->r_restarts > 0 ? SEF_INIT_RESTART : SEF_INIT_FRESH; - if((s = init_service(rp, init_type)) != OK) { - panic("unable to initialize service: %d", s); + if (rs_start->rss_nr_pci_class > RS_NR_PCI_CLASS) + { + printf("RS: init_slot: too many PCI class IDs\n"); + return EINVAL; } - - /* The purpose of non-blocking forks is to avoid involving VFS in the forking - * process, because VFS may be blocked on a sendrec() to a MFS that is - * waiting for a endpoint update for a dead driver. We have just published - * that update, but VFS may still be blocked. As a result, VFS may not yet - * have received PM's fork message. Hence, if we call mapdriver() - * immediately, VFS may not know about the process and thus refuse to add the - * driver entry. The following temporary hack works around this by forcing - * blocking communication from PM to VFS. Once VFS has been made non-blocking - * towards MFS instances, this hack and the entire fork_nb() call can go. - */ - if (use_copy) - setuid(0); - - /* Map the new service. */ - if (rpub->dev_nr > 0) { /* set driver map */ - if ((s=mapdriver(rpub->label, - rpub->dev_nr, rpub->dev_style, !!use_copy /* force */)) < 0) { - printf("RS: couldn't map driver (continuing): %d\n", errno); - } + rpub->pci_acl.rsp_nr_class= rs_start->rss_nr_pci_class; + for (i= 0; 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); } - if(rs_verbose) - printf("RS: started '%s', major %d, pid %d, endpoint %d, proc %d\n", - rp->r_cmd, rpub->dev_nr, child_pid, - child_proc_nr_e, child_proc_nr_n); + /* Copy kernel call mask. Inherit basic kernel calls. */ + memcpy(rp->r_priv.s_k_call_mask, rs_start->rss_system, + sizeof(rp->r_priv.s_k_call_mask)); + fill_call_mask(basic_kc, NR_SYS_CALLS, + rp->r_priv.s_k_call_mask, KERNEL_CALL, FALSE); - /* The system service now has been successfully started. The only thing - * that can go wrong now, is that execution fails at the child. If that's - * the case, the child will exit. - */ - if(endpoint) *endpoint = child_proc_nr_e; /* send back child endpoint */ + /* Initialize some fields. */ + rpub->period = rs_start->rss_period; + rpub->dev_nr = rs_start->rss_major; + rpub->dev_style = STYLE_DEV; + rp->r_restarts = -1; /* will be incremented */ + rp->r_set_resources= 1; /* set resources */ + + /* Copy VM call mask. Inherit basic VM calls. */ + memcpy(rpub->vm_call_mask, rs_start->rss_vm, + sizeof(rpub->vm_call_mask)); + fill_call_mask(basic_vmc, NR_VM_CALLS, + rpub->vm_call_mask, VM_RQ_BASE, FALSE); - return(OK); + return OK; } /*===========================================================================* - * stop_service * + * clone_slot * *===========================================================================*/ -PRIVATE void stop_service(struct rproc *rp,int how) +PUBLIC int clone_slot(rp, clone_rpp) +struct rproc *rp; +struct rproc **clone_rpp; { - /* Try to stop the system service. First send a SIGTERM signal to ask the - * system service to terminate. If the service didn't install a signal - * handler, it will be killed. If it did and ignores the signal, we'll - * find out because we record the time here and send a SIGKILL. - */ - if(rs_verbose) printf("RS tries to stop %s (pid %d)\n", rp->r_cmd, rp->r_pid); + int r; + struct rproc *clone_rp; + struct rprocpub *rpub, *clone_rpub; - rp->r_flags |= how; /* what to on exit? */ - if(rp->r_pid > 0) kill(rp->r_pid, SIGTERM); /* first try friendly */ - else if(rs_verbose) printf("RS: no process to kill\n"); - getuptime(&rp->r_stop_tm); /* record current time */ -} + /* Allocate a system service slot for the clone. */ + r = alloc_slot(&clone_rp); + if(r != OK) { + printf("RS: clone_slot: unable to allocate a new slot: %d\n", r); + return r; + } + + rpub = rp->r_pub; + clone_rpub = clone_rp->r_pub; + + /* Shallow copy. */ + *clone_rp = *rp; + *clone_rpub = *rpub; + /* Deep copy. */ + clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */ + clone_rp->r_pid = -1; /* no pid yet */ + clone_rpub->endpoint = -1; /* no endpoint yet */ + clone_rp->r_pub = clone_rpub; /* restore pointer to public entry */ + build_cmd_dep(clone_rp); /* rebuild cmd dependencies */ + if(clone_rpub->sys_flags & SF_USE_COPY) { + share_exec(clone_rp, rp); /* share exec image */ + } + + /* Force dynamic privilege id. */ + clone_rp->r_priv.s_flags |= DYN_PRIV_ID; + + *clone_rpp = clone_rp; + return OK; +} /*===========================================================================* - * do_getsysinfo * + * swap_slot_pointer * *===========================================================================*/ -PUBLIC int do_getsysinfo(m_ptr) -message *m_ptr; +PRIVATE void swap_slot_pointer(struct rproc **rpp, struct rproc *src_rp, + struct rproc *dst_rp) { - vir_bytes src_addr, dst_addr; - int dst_proc; - size_t len; - int s; - - /* This call requires special privileges. */ - if (!caller_is_root(m_ptr->m_source)) return(EPERM); - - switch(m_ptr->m1_i1) { - case SI_PROC_TAB: - src_addr = (vir_bytes) rproc; - len = sizeof(struct rproc) * NR_SYS_PROCS; - break; - case SI_PROCPUB_TAB: - src_addr = (vir_bytes) rprocpub; - len = sizeof(struct rprocpub) * NR_SYS_PROCS; - break; - default: - return(EINVAL); - } - - dst_proc = m_ptr->m_source; - dst_addr = (vir_bytes) m_ptr->m1_p1; - if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len))) - return(s); - return(OK); + if(*rpp == src_rp) { + *rpp = dst_rp; + } + else if(*rpp == dst_rp) { + *rpp = src_rp; + } } /*===========================================================================* - * fork_nb * + * swap_slot * *===========================================================================*/ -PRIVATE pid_t fork_nb() +PUBLIC void swap_slot(src_rpp, dst_rpp) +struct rproc **src_rpp; +struct rproc **dst_rpp; { - message m; - - return(_syscall(PM_PROC_NR, FORK_NB, &m)); +/* Swap two service slots. */ + struct rproc *src_rp; + struct rproc *dst_rp; + struct rprocpub *src_rpub; + struct rprocpub *dst_rpub; + struct rproc orig_src_rproc, orig_dst_rproc; + struct rprocpub orig_src_rprocpub, orig_dst_rprocpub; + + src_rp = *src_rpp; + dst_rp = *dst_rpp; + src_rpub = src_rp->r_pub; + dst_rpub = dst_rp->r_pub; + + /* Save existing data first. */ + orig_src_rproc = *src_rp; + orig_src_rprocpub = *src_rpub; + orig_dst_rproc = *dst_rp; + orig_dst_rprocpub = *dst_rpub; + + /* Swap slots. */ + *src_rp = orig_dst_rproc; + *src_rpub = orig_dst_rprocpub; + *dst_rp = orig_src_rproc; + *dst_rpub = orig_src_rprocpub; + + /* Restore public entries. */ + src_rp->r_pub = orig_src_rproc.r_pub; + dst_rp->r_pub = orig_dst_rproc.r_pub; + + /* Rebuild command dependencies. */ + build_cmd_dep(src_rp); + build_cmd_dep(dst_rp); + + /* Swap local slot pointers. */ + swap_slot_pointer(&src_rp->r_prev_rp, src_rp, dst_rp); + swap_slot_pointer(&src_rp->r_next_rp, src_rp, dst_rp); + swap_slot_pointer(&src_rp->r_old_rp, src_rp, dst_rp); + swap_slot_pointer(&src_rp->r_new_rp, src_rp, dst_rp); + swap_slot_pointer(&dst_rp->r_prev_rp, src_rp, dst_rp); + swap_slot_pointer(&dst_rp->r_next_rp, src_rp, dst_rp); + swap_slot_pointer(&dst_rp->r_old_rp, src_rp, dst_rp); + swap_slot_pointer(&dst_rp->r_new_rp, src_rp, dst_rp); + + /* Swap global slot pointers. */ + swap_slot_pointer(&rupdate.rp, src_rp, dst_rp); + swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)], + src_rp, dst_rp); + swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)], + src_rp, dst_rp); + + /* Adjust input pointers. */ + *src_rpp = dst_rp; + *dst_rpp = src_rp; } /*===========================================================================* - * share_exec * + * lookup_slot_by_label * *===========================================================================*/ -PRIVATE int share_exec(rp_dst, rp_src) -struct rproc *rp_dst, *rp_src; +PUBLIC struct rproc* lookup_slot_by_label(char *label) { - struct rprocpub *rpub_src; - struct rprocpub *rpub_dst; - - rpub_src = rp_src->r_pub; - rpub_dst = rp_dst->r_pub; +/* Lookup a service slot matching the given label. */ + int slot_nr; + struct rproc *rp; + struct rprocpub *rpub; - if(rs_verbose) { - printf("RS: share_exec: sharing exec image from %s to %s\n", - rpub_src->label, rpub_dst->label); + for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { + rp = &rproc[slot_nr]; + if (!(rp->r_flags & RS_ACTIVE)) { + continue; + } + rpub = rp->r_pub; + if (strcmp(rpub->label, label) == 0) { + return rp; + } } - /* Share exec image from rp_src to rp_dst. */ - rp_dst->r_exec_len = rp_src->r_exec_len; - rp_dst->r_exec = rp_src->r_exec; - - return OK; + return NULL; } /*===========================================================================* - * read_exec * + * lookup_slot_by_pid * *===========================================================================*/ -PRIVATE int read_exec(rp) -struct rproc *rp; +PUBLIC struct rproc* lookup_slot_by_pid(pid_t pid) { - int e, r, fd; - char *e_name; - struct stat sb; +/* Lookup a service slot matching the given pid. */ + int slot_nr; + struct rproc *rp; - e_name= rp->r_argv[0]; - if(rs_verbose) { - printf("RS: read_exec: copying exec image from: %s\n", e_name); + if(pid < 0) { + return NULL; } - r= stat(e_name, &sb); - if (r != 0) - return -errno; - - fd= open(e_name, O_RDONLY); - if (fd == -1) - return -errno; - - rp->r_exec_len= sb.st_size; - rp->r_exec= malloc(rp->r_exec_len); - if (rp->r_exec == NULL) - { - printf("RS: read_exec: unable to allocate %d bytes\n", - rp->r_exec_len); - close(fd); - return ENOMEM; + for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { + rp = &rproc[slot_nr]; + if (!(rp->r_flags & RS_IN_USE)) { + continue; + } + if (rp->r_pid == pid) { + return rp; + } } - r= read(fd, rp->r_exec, rp->r_exec_len); - e= errno; - close(fd); - if (r == rp->r_exec_len) - return OK; + return NULL; +} - printf("RS: read_exec: read failed %d, errno %d\n", r, e); +/*===========================================================================* + * alloc_slot * + *===========================================================================*/ +PUBLIC int alloc_slot(rpp) +struct rproc **rpp; +{ +/* Alloc a new system service slot. */ + int slot_nr; - free(rp->r_exec); - rp->r_exec= NULL; + for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { + *rpp = &rproc[slot_nr]; /* get pointer to slot */ + if (!((*rpp)->r_flags & RS_IN_USE)) /* check if available */ + break; + } + if (slot_nr >= NR_SYS_PROCS) { + return ENOMEM; + } - if (r >= 0) - return EIO; - else - return -e; + return OK; } /*===========================================================================* * free_slot * *===========================================================================*/ -PRIVATE void free_slot(rp) +PUBLIC void free_slot(rp) struct rproc *rp; { - int slot_nr, has_shared_exec; +/* Free a system service slot. */ struct rprocpub *rpub; - struct rproc *other_rp; rpub = rp->r_pub; + /* Send a late reply if there is any pending. */ + late_reply(rp, OK); + /* Free memory if necessary. */ if(rpub->sys_flags & SF_USE_COPY) { - /* Search for some other slot sharing the same exec image. */ - has_shared_exec = FALSE; - for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) { - other_rp = &rproc[slot_nr]; /* get pointer to slot */ - if (other_rp->r_flags & RS_IN_USE && other_rp != rp - && other_rp->r_exec == rp->r_exec) { /* found! */ - has_shared_exec = TRUE; - } - } - - /* If nobody uses our copy of the exec image, we can get rid of it. */ - if(!has_shared_exec) { - if(rs_verbose) { - printf("RS: free_slot: free exec image from %s\n", - rpub->label); - } - free(rp->r_exec); - rp->r_exec = NULL; - rp->r_exec_len = 0; - } + free_exec(rp); } /* Mark slot as no longer in use.. */ rp->r_flags = 0; + rp->r_pid = -1; rpub->in_use = FALSE; rproc_ptr[_ENDPOINT_P(rpub->endpoint)] = NULL; } @@ -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