diff --git a/README.md b/README.md index 15e967d6..48e1f12a 100644 --- a/README.md +++ b/README.md @@ -435,6 +435,8 @@ hook point in the boot process, useful to insert some pre-bootstrap mechanisms, like generating configuration files, restoring HW device state, etc. Available hook points are: +**Bootstrap Hooks** + * `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is mounted -- very early @@ -449,6 +451,20 @@ state, etc. Available hook points are: * `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d` has been launched +**Runtime Hooks** + +* `HOOK_SVC_RECONF`: Called when the user has changed something in the + `/etc/finit.d` directory and issued `SIGHUP`. The hook is called when + all modified/removed services have been stopped. When the hook has + completed, Finit continues to start all modified and new services. + +* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel + change. The hook is called when services not matching the new + runlevel have been been stopped. When the hook has completed, Finit + continues to start all services in the new runlevel. + +**Shutdown Hooks** + * `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all services are sent `SIGTERM` diff --git a/plugin.h b/plugin.h index 9d914367..ba77013a 100644 --- a/plugin.h +++ b/plugin.h @@ -41,11 +41,18 @@ * Predefined hook points for easier plugin debugging */ typedef enum { + /* Bootstrap hooks */ HOOK_ROOTFS_UP = 0, HOOK_BASEFS_UP, HOOK_NETWORK_UP, - HOOK_SYSTEM_UP, HOOK_SVC_UP, + HOOK_SYSTEM_UP, + + /* Runtime hooks */ + HOOK_SVC_RECONF, + HOOK_RUNLEVEL_CHANGE, + + /* Shutdown hooks */ HOOK_SHUTDOWN, HOOK_MAX_NUM } hook_point_t; diff --git a/svc.c b/svc.c index adab3945..974d5437 100644 --- a/svc.c +++ b/svc.c @@ -286,17 +286,32 @@ void svc_runlevel(int newlevel) prevlevel = runlevel; runlevel = newlevel; - utmp_save(prevlevel, newlevel); _d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel); + utmp_save(prevlevel, newlevel); + _d("Stopping services services not allowed in new runlevel ..."); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { - /* Inetd services have slightly different semantics */ + if (!ISSET(svc->runlevels, runlevel)) { #ifndef INETD_DISABLED - if (svc->type == SVC_TYPE_INETD) { - if (!ISSET(svc->runlevels, runlevel)) + if (svc->type == SVC_TYPE_INETD) inetd_stop(&svc->inetd); else +#endif + svc_stop(svc); + } + } + + /* Prev runlevel services stopped, call hooks before starting new runlevel ... */ + _d("All services have been stoppped, calling runlevel change hooks ..."); + plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */ + + _d("Starting services services new to this runlevel ..."); + for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { +#ifndef INETD_DISABLED + /* Inetd services have slightly different semantics */ + if (svc->type == SVC_TYPE_INETD) { + if (ISSET(svc->runlevels, runlevel)) inetd_start(&svc->inetd); continue; @@ -901,13 +916,26 @@ int svc_reload(svc_t *svc) */ void svc_reload_dynamic(void) { + int num = 0; svc_t *svc; - _d("Checking if any dynamically loaded services need to be reloaded ..."); + _d("Stopping disabled/removed services ..."); + for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { + if (svc->mtime && svc->dirty != 0) { + svc_stop(svc); + num++; + } + } + + if (!num) + return; + + _d("All disabled/removed services have been stoppped, calling reconf hooks ..."); + plugin_run_hooks(HOOK_SVC_RECONF); /* Reconfigure HW/VLANs/etc here */ + + _d("Starting enabled/added services ..."); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (svc->mtime && svc->dirty > 0) { - _d("Service %s id %d modified, must stop-start for changes to take effect!", svc->cmd, svc->id); - svc_stop(svc); /* This will reset the restart_counter as well! */ svc_dance(svc); svc->dirty = 0; }