@@ -1798,7 +1798,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
17981798 char * dev = NULL ;
17991799 int respawn = 0 ;
18001800 int levels = 0 ;
1801- int forking = 0 , manual = 0 , nowarn = 0 ;
1801+ int forking = 0 , manual = 0 , remain = 0 , nowarn = 0 ;
18021802 int restart_max = SVC_RESPAWN_MAX ;
18031803 int restart_tmo = 0 ;
18041804 unsigned oncrash_action = SVC_ONCRASH_IGNORE ;
@@ -1866,6 +1866,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
18661866 forking = 1 ;
18671867 else if (MATCH_CMD (cmd , "manual:yes" , arg ))
18681868 manual = 1 ;
1869+ else if (MATCH_CMD (cmd , "remain:yes" , arg ))
1870+ remain = 1 ;
18691871 else if (MATCH_CMD (cmd , "restart:" , arg )) {
18701872 if (MATCH_CMD (arg , "always" , arg ))
18711873 restart_max = -1 ;
@@ -2171,6 +2173,18 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
21712173 memset (svc -> ifstmt , 0 , sizeof (svc -> ifstmt ));
21722174 svc -> manual = manual ;
21732175 svc -> nowarn = nowarn ;
2176+
2177+ /*
2178+ * remain:yes is not supported for bootstrap-only tasks. These
2179+ * tasks are deleted immediately after completion and their post:
2180+ * scripts never run. This is by design.
2181+ */
2182+ if (remain && svc_is_runtask (svc ) && !ISOTHER (levels , INIT_LEVEL )) {
2183+ logit (LOG_WARNING , "%s: remain:yes ignored for bootstrap-only tasks" ,
2184+ svc_ident (svc , NULL , 0 ));
2185+ remain = 0 ;
2186+ }
2187+ svc -> remain = remain ;
21742188 svc -> respawn = respawn ;
21752189 svc -> forking = forking ;
21762190 svc -> restart_max = restart_max ;
@@ -2859,8 +2873,12 @@ int service_step(svc_t *svc)
28592873 if (svc_is_removed (svc ) && svc_has_cleanup (svc )) {
28602874 svc_set_state (svc , SVC_CLEANUP_STATE );
28612875 service_cleanup_script (svc );
2862- } else
2876+ } else {
2877+ /* Unblock remain tasks after post script so they can restart */
2878+ if (svc_is_remain (svc ))
2879+ svc_unblock (svc );
28632880 svc_set_state (svc , SVC_HALTED_STATE );
2881+ }
28642882 }
28652883 break ;
28662884
@@ -2876,9 +2894,16 @@ int service_step(svc_t *svc)
28762894 break ;
28772895
28782896 case SVC_DONE_STATE :
2879- if (svc_is_changed (svc ))
2897+ /* Remain tasks: always run post script when stopped, even if config changed */
2898+ if (svc_is_runtask (svc ) && svc_is_remain (svc ) && svc_is_stopped (svc )) {
2899+ if (svc_has_post (svc )) {
2900+ svc_set_state (svc , SVC_TEARDOWN_STATE );
2901+ service_post_script (svc );
2902+ } else
2903+ svc_set_state (svc , SVC_HALTED_STATE );
2904+ } else if (svc_is_changed (svc ))
28802905 svc_set_state (svc , SVC_HALTED_STATE );
2881- if (svc_is_runtask (svc ) && svc_is_manual (svc ) && enabled )
2906+ else if (svc_is_runtask (svc ) && svc_is_manual (svc ) && enabled )
28822907 svc_set_state (svc , SVC_WAITING_STATE );
28832908 break ;
28842909
@@ -3180,6 +3205,29 @@ void service_runtask_clean(void)
31803205 if (!svc_is_runtask (svc ))
31813206 continue ;
31823207
3208+ /* Remain tasks stay in DONE state if still valid in new runlevel */
3209+ if (svc_is_remain (svc ) && svc -> state == SVC_DONE_STATE ) {
3210+ if (svc_in_runlevel (svc , runlevel ) && !svc_is_changed (svc ))
3211+ continue ; /* Keep once flag, stay in DONE */
3212+
3213+ /* Config changed or leaving runlevel: stop, run post, restart */
3214+ svc -> once = 0 ;
3215+ svc_stop (svc );
3216+ service_step (svc );
3217+ continue ;
3218+ }
3219+
3220+ /*
3221+ * On reload (SIGHUP), only remain tasks (handled above) should
3222+ * have their once flag cleared and be restarted. Regular run/task
3223+ * that already ran in this runlevel must not run again.
3224+ *
3225+ * On runlevel change, continue below to reset once flag so tasks
3226+ * can run again in the new runlevel.
3227+ */
3228+ if (sm_in_reload ())
3229+ continue ;
3230+
31833231 /* run/task declared with <!> */
31843232 if (svc -> sighup )
31853233 svc -> once = 1 ;
0 commit comments