fiss

Friedel's Initialization and Service Supervision
Log | Files | Refs | LICENSE

handle_exit.c (2458B)


      1 #include "service.h"
      2 
      3 #include <errno.h>
      4 #include <limits.h>
      5 #include <stdarg.h>
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <sys/stat.h>
      9 #include <unistd.h>
     10 
     11 
     12 static void do_finish(struct service* s) {
     13 	struct stat st;
     14 
     15 	if (fstatat(s->dir, "finish", &st, 0) != -1 && st.st_mode & S_IXUSR) {
     16 		if ((s->pid = fork_dup_cd_exec(s->dir, "./finish", null_fd, null_fd, null_fd)) == -1) {
     17 			fprint(1, "error: cannot execute ./finish: %r\n");
     18 			service_update_state(s, STATE_INACTIVE);
     19 		} else {
     20 			service_update_state(s, STATE_FINISHING);
     21 		}
     22 	} else if (s->fail_count == SV_FAIL_MAX) {
     23 		service_update_state(s, STATE_ERROR);
     24 		print("%s died\n", s->name);
     25 	} else {
     26 		service_update_state(s, s->restart == S_ONCE ? STATE_DONE : STATE_INACTIVE);
     27 	}
     28 }
     29 
     30 
     31 void service_handle_exit(struct service* s, bool signaled, int return_code) {
     32 	struct stat st;
     33 
     34 	s->pid          = 0;
     35 	s->stop_timeout = 0;
     36 
     37 	if (s->restart == S_ONCE)
     38 		s->restart = S_DOWN;
     39 
     40 	switch (s->state) {
     41 		case STATE_SETUP:
     42 			service_run(s);
     43 			break;
     44 		case STATE_ACTIVE_FOREGROUND:
     45 			if (signaled) {
     46 				s->last_exit   = EXIT_SIGNALED;
     47 				s->return_code = return_code;
     48 				s->fail_count++;
     49 
     50 				print("%s killed thought signal %d\n", s->name, s->return_code);
     51 			} else {
     52 				s->last_exit   = EXIT_NORMAL;
     53 				s->return_code = return_code;
     54 				if (s->return_code > 0)
     55 					s->fail_count++;
     56 				else
     57 					s->fail_count = 0;
     58 
     59 				print("%s exited with code %d\n", s->name, s->return_code);
     60 			}
     61 
     62 			do_finish(s);
     63 
     64 			break;
     65 		case STATE_ACTIVE_DUMMY:
     66 		case STATE_ACTIVE_BACKGROUND:
     67 		case STATE_STOPPING:
     68 			do_finish(s);
     69 			break;
     70 
     71 		case STATE_FINISHING:
     72 			if (s->fail_count == SV_FAIL_MAX) {
     73 				service_update_state(s, STATE_ERROR);
     74 				print("%s died\n", s->name);
     75 			} else {
     76 				service_update_state(s, s->restart == S_ONCE ? STATE_DONE : STATE_INACTIVE);
     77 			}
     78 			break;
     79 		case STATE_STARTING:
     80 			if (!signaled && return_code == 0) {
     81 				if (fstatat(s->dir, "stop", &st, 0) != -1 && st.st_mode & S_IXUSR) {
     82 					service_update_state(s, STATE_ACTIVE_BACKGROUND);
     83 				} else {
     84 					do_finish(s);
     85 				}
     86 			} else if (!signaled) {
     87 				s->last_exit   = EXIT_NORMAL;
     88 				s->return_code = return_code;
     89 
     90 				do_finish(s);
     91 			} else {    // signaled
     92 				s->last_exit   = EXIT_SIGNALED;
     93 				s->return_code = return_code;
     94 
     95 				do_finish(s);
     96 			}
     97 			break;
     98 
     99 		case STATE_ERROR:
    100 		case STATE_INACTIVE:
    101 		case STATE_DONE:
    102 			print("unexpected error: %s died but it's inactive\n", s->name);
    103 	}
    104 }