X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=service.c;h=70299dd065f472d1f0a52435b982f41d8632a990;hp=ae7fc36a5c4bedd54ac35516443316139e139c0f;hb=35355baba1feec37bf9f22e3a0e18f495fcf6014;hpb=bd982a8baeabbaf4a09a382a64acc243ef7104c5 diff --git a/service.c b/service.c index ae7fc36a5..70299dd06 100644 --- a/service.c +++ b/service.c @@ -30,7 +30,7 @@ static const char* const state_string_table[_SERVICE_STATE_MAX] = { [SERVICE_DEAD] = "dead", [SERVICE_START_PRE] = "start-pre", [SERVICE_START] = "start", - [SERVICE_START_POST] = "post", + [SERVICE_START_POST] = "start-post", [SERVICE_RUNNING] = "running", [SERVICE_RELOAD] = "reload", [SERVICE_STOP] = "stop", @@ -101,17 +101,18 @@ static int service_init(Unit *u) { s->state = SERVICE_DEAD; /* Load a .service file */ - r = unit_load_fragment(u); - - /* Load a classic init script as a fallback */ - if (r == -ENOENT) - r = service_load_sysv(s); - - if (r < 0) { + if ((r = unit_load_fragment(u)) < 0) { service_done(u); return r; } + /* Load a classic init script as a fallback, if we couldn*t find anything */ + if (r == 0) + if ((r = service_load_sysv(s)) <= 0) { + service_done(u); + return r < 0 ? r : -ENOENT; + } + /* Load dropin directory data */ if ((r = unit_load_dropin(u)) < 0) { service_done(u); @@ -198,6 +199,73 @@ static int service_load_pid_file(Service *s) { return 0; } +static int service_get_sockets(Service *s, Set **_set) { + Set *set; + Iterator i; + char *t; + int r; + + assert(s); + assert(_set); + + /* Collects all Socket objects that belong to this + * service. Note that a service might have multiple sockets + * via multiple names. */ + + if (!(set = set_new(NULL, NULL))) + return -ENOMEM; + + SET_FOREACH(t, UNIT(s)->meta.names, i) { + char *k; + Unit *p; + + /* Look for all socket objects that go by any of our + * units and collect their fds */ + + if (!(k = unit_name_change_suffix(t, ".socket"))) { + r = -ENOMEM; + goto fail; + } + + p = manager_get_unit(UNIT(s)->meta.manager, k); + free(k); + + if (!p) continue; + + if ((r = set_put(set, p)) < 0) + goto fail; + } + + *_set = set; + return 0; + +fail: + set_free(set); + return r; +} + + +static int service_notify_sockets(Service *s) { + Iterator i; + Set *set; + Socket *socket; + int r; + + assert(s); + + /* Notifies all our sockets when we die */ + + if ((r = service_get_sockets(s, &set)) < 0) + return r; + + SET_FOREACH(socket, set, i) + socket_notify_service_dead(socket); + + set_free(set); + + return 0; +} + static void service_set_state(Service *s, ServiceState state) { ServiceState old_state; assert(s); @@ -252,7 +320,18 @@ static void service_set_state(Service *s, ServiceState state) { state != SERVICE_STOP_POST) s->control_command = NULL; - log_debug("%s changing %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); + if (state == SERVICE_DEAD || + state == SERVICE_STOP || + state == SERVICE_STOP_SIGTERM || + state == SERVICE_STOP_SIGKILL || + state == SERVICE_STOP_POST || + state == SERVICE_FINAL_SIGTERM || + state == SERVICE_FINAL_SIGKILL || + state == SERVICE_MAINTAINANCE || + state == SERVICE_AUTO_RESTART) + service_notify_sockets(s); + + log_debug("%s changed %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]); } @@ -262,33 +341,21 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { int r; int *rfds = NULL; unsigned rn_fds = 0; - char *t; + Set *set; + Socket *socket; assert(s); assert(fds); assert(n_fds); - SET_FOREACH(t, UNIT(s)->meta.names, i) { - char *k; - Unit *p; + if ((r = service_get_sockets(s, &set)) < 0) + return r; + + SET_FOREACH(socket, set, i) { int *cfds; unsigned cn_fds; - /* Look for all socket objects that go by any of our - * units and collect their fds */ - - if (!(k = unit_name_change_suffix(t, ".socket"))) { - r = -ENOMEM; - goto fail; - } - - p = manager_get_unit(UNIT(s)->meta.manager, k); - free(k); - - if (!p) - continue; - - if ((r = socket_collect_fds(SOCKET(p), &cfds, &cn_fds)) < 0) + if ((r = socket_collect_fds(socket, &cfds, &cn_fds)) < 0) goto fail; if (!cfds) @@ -318,10 +385,15 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { *fds = rfds; *n_fds = rn_fds; + + set_free(set); + return 0; fail: + set_free(set); free(rfds); + return r; } @@ -400,13 +472,14 @@ static void service_enter_stop_post(Service *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_STOP_POST); - } else + + service_set_state(s, SERVICE_STOP_POST); + + if (!s->control_command) service_enter_dead(s, true, true); return; @@ -447,9 +520,11 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { if (r < 0) goto fail; + } - service_set_state(s, state); - } else + service_set_state(s, state); + + if (s->main_pid <= 0 && s->control_pid <= 0) service_enter_dead(s, true, true); return; @@ -473,13 +548,13 @@ static void service_enter_stop(Service *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_STOP); - } else + service_set_state(s, SERVICE_STOP); + + if (!s->control_command) service_enter_signal(s, SERVICE_STOP_SIGTERM, true); return; @@ -493,13 +568,14 @@ static void service_enter_start_post(Service *s) { int r; assert(s); - if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_START_POST); - } else + + service_set_state(s, SERVICE_START_POST); + + if (!s->control_command) service_set_state(s, SERVICE_RUNNING); return; @@ -521,6 +597,8 @@ static void service_enter_start(Service *s) { if ((r = service_spawn(s, s->exec_command[SERVICE_EXEC_START], s->type == SERVICE_FORKING, true, &pid)) < 0) goto fail; + service_set_state(s, SERVICE_START); + if (s->type == SERVICE_SIMPLE) { /* For simple services we immediately start * the START_POST binaries. */ @@ -536,7 +614,6 @@ static void service_enter_start(Service *s) { s->control_pid = pid; s->control_command = s->exec_command[SERVICE_EXEC_START]; - service_set_state(s, SERVICE_START); } else assert_not_reached("Unknown service type"); @@ -552,13 +629,13 @@ static void service_enter_start_pre(Service *s) { assert(s); - if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_START_PRE); - } else + service_set_state(s, SERVICE_START_PRE); + + if (!s->control_command) service_enter_start(s); return; @@ -590,13 +667,13 @@ static void service_enter_reload(Service *s) { assert(s); - if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_RELOAD); - } else + service_set_state(s, SERVICE_RELOAD); + + if (!s->control_command) service_set_state(s, SERVICE_RUNNING); return;