X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fservice.c;h=7f8d005f00882f21bfcba666cc347b3b1ed8dc9d;hp=243e5536a77b988e2ee6aa499ebd36e8ae3791c3;hb=530add9d622fcd0a4ea70e0657ed4596d40f1e8f;hpb=3185a36b05d53757a412f847d8c510978b9b00f0 diff --git a/src/service.c b/src/service.c index 243e5536a..7f8d005f0 100644 --- a/src/service.c +++ b/src/service.c @@ -35,13 +35,12 @@ #include "special.h" #include "bus-errors.h" #include "exit-status.h" - -#define COMMENTS "#;\n" -#define NEWLINES "\n\r" +#include "def.h" +#include "util.h" #ifdef HAVE_SYSV_COMPAT -#define DEFAULT_SYSV_TIMEOUT_USEC (3*USEC_PER_MINUTE) +#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE) typedef enum RunlevelType { RUNLEVEL_UP, @@ -116,11 +115,14 @@ static void service_init(Unit *u) { s->timer_watch.type = WATCH_INVALID; #ifdef HAVE_SYSV_COMPAT s->sysv_start_priority = -1; + s->sysv_start_priority_from_rcnd = -1; #endif s->socket_fd = -1; s->guess_main_pid = true; exec_context_init(&s->exec_context); + s->exec_context.std_output = u->meta.manager->default_std_output; + s->exec_context.std_error = u->meta.manager->default_std_error; RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5); @@ -273,12 +275,18 @@ static int sysv_translate_facility(const char *name, const char *filename, char static const char * const table[] = { /* LSB defined facilities */ "local_fs", SPECIAL_LOCAL_FS_TARGET, +#ifndef TARGET_MANDRIVA + /* Due to unfortunate name selection in Mandriva, + * $network is provided by network-up which is ordered + * after network which actually starts interfaces. + * To break the loop, just ignore it */ "network", SPECIAL_NETWORK_TARGET, +#endif "named", SPECIAL_NSS_LOOKUP_TARGET, "portmap", SPECIAL_RPCBIND_TARGET, "remote_fs", SPECIAL_REMOTE_FS_TARGET, "syslog", SPECIAL_SYSLOG_TARGET, - "time", SPECIAL_RTC_SET_TARGET, + "time", SPECIAL_TIME_SYNC_TARGET, /* common extensions */ "mail-transfer-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, @@ -333,7 +341,7 @@ static int sysv_translate_facility(const char *name, const char *filename, char /* Facilities starting with $ are most likely targets */ r = unit_name_build(n, NULL, ".target"); } else if (filename && streq(name, filename)) - /* Names equalling the file name of the services are redundant */ + /* Names equaling the file name of the services are redundant */ return 0; else /* Everything else we assume to be normal service names */ @@ -343,9 +351,7 @@ static int sysv_translate_facility(const char *name, const char *filename, char return -ENOMEM; finish: - - if (_r) - *_r = r; + *_r = r; return 1; } @@ -400,7 +406,7 @@ static int sysv_fix_order(Service *s) { /* FIXME: Maybe we should compare the name here lexicographically? */ - if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) + if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) return r; } @@ -532,7 +538,7 @@ static int service_load_sysv_path(Service *s, const char *path) { * data from the LSB header. */ if (start_priority < 0 || start_priority > 99) log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line); - else if (s->sysv_start_priority < 0) + else s->sysv_start_priority = start_priority; char_array_0(runlevels); @@ -650,16 +656,21 @@ static int service_load_sysv_path(Service *s, const char *path) { if (unit_name_to_type(m) == UNIT_SERVICE) r = unit_add_name(u, m); - else { - r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true); - - if (s->sysv_enabled) { - int k; - - if ((k = unit_add_dependency_by_name_inverse(u, UNIT_WANTS, m, NULL, true)) < 0) - r = k; - } - } + else + /* NB: SysV targets + * which are provided + * by a service are + * pulled in by the + * services, as an + * indication that the + * generic service is + * now available. This + * is strictly + * one-way. The + * targets do NOT pull + * in the SysV + * services! */ + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true); if (r < 0) log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r)); @@ -817,8 +828,8 @@ static int service_load_sysv_path(Service *s, const char *path) { s->restart = SERVICE_RESTART_NO; s->exec_context.std_output = (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY) - ? EXEC_OUTPUT_TTY : EXEC_OUTPUT_NULL; - s->exec_context.kill_mode = KILL_PROCESS_GROUP; + ? EXEC_OUTPUT_TTY : s->meta.manager->default_std_output; + s->exec_context.kill_mode = KILL_PROCESS; /* We use the long description only if * no short description is set. */ @@ -835,7 +846,7 @@ static int service_load_sysv_path(Service *s, const char *path) { if (description) { char *d; - if (!(d = strappend("LSB: ", description))) { + if (!(d = strappend(s->sysv_has_lsb ? "LSB: " : "SYSV: ", description))) { r = -ENOMEM; goto finish; } @@ -843,6 +854,12 @@ static int service_load_sysv_path(Service *s, const char *path) { u->meta.description = d; } + /* The priority that has been set in /etc/rcN.d/ hierarchies + * takes precedence over what is stored as default in the LSB + * header */ + if (s->sysv_start_priority_from_rcnd >= 0) + s->sysv_start_priority = s->sysv_start_priority_from_rcnd; + u->meta.load_state = UNIT_LOADED; r = 0; @@ -1007,7 +1024,7 @@ static int fsck_fix_order(Service *s) { else continue; - if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) + if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) return r; } @@ -1124,7 +1141,7 @@ static int service_load(Unit *u) { s->notify_access = NOTIFY_MAIN; if (s->type == SERVICE_DBUS || s->bus_name) - if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_TARGET, NULL, true)) < 0) + if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0) return r; if (s->meta.default_dependencies) @@ -1575,8 +1592,8 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { goto fail; } - memcpy(t, rfds, rn_fds); - memcpy(t+rn_fds, cfds, cn_fds); + memcpy(t, rfds, rn_fds * sizeof(int)); + memcpy(t+rn_fds, cfds, cn_fds * sizeof(int)); free(rfds); free(cfds); @@ -1653,7 +1670,7 @@ static int service_spawn( } if (set_notify_socket) - if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=@%s", s->meta.manager->notify_socket) < 0) { + if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", s->meta.manager->notify_socket) < 0) { r = -ENOMEM; goto fail; } @@ -1828,19 +1845,14 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; if (s->main_pid > 0) { - if (kill(s->exec_context.kill_mode == KILL_PROCESS_GROUP ? - -s->main_pid : - s->main_pid, sig) < 0 && errno != ESRCH) - + if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH) log_warning("Failed to kill main process %li: %m", (long) s->main_pid); else wait_for_exit = true; } if (s->control_pid > 0) { - if (kill(s->exec_context.kill_mode == KILL_PROCESS_GROUP ? - -s->control_pid : - s->control_pid, sig) < 0 && errno != ESRCH) + if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH) log_warning("Failed to kill control process %li: %m", (long) s->control_pid); else @@ -1863,13 +1875,14 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) goto fail; - if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, pid_set)) < 0) { + if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, true, pid_set)) < 0) { if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) log_warning("Failed to kill control group: %s", strerror(-r)); } else if (r > 0) wait_for_exit = true; set_free(pid_set); + pid_set = NULL; } } @@ -2494,16 +2507,26 @@ static const char *service_sub_state_to_string(Unit *u) { return service_state_to_string(SERVICE(u)->state); } -#ifdef HAVE_SYSV_COMPAT static bool service_check_gc(Unit *u) { Service *s = SERVICE(u); assert(s); - return !!s->sysv_path; -} + /* Never clean up services that still have a process around, + * even if the service is formally dead. */ + if (cgroup_good(s) > 0 || + main_pid_good(s) > 0 || + control_pid_good(s) > 0) + return true; + +#ifdef HAVE_SYSV_COMPAT + if (s->sysv_path) + return true; #endif + return false; +} + static bool service_check_snapshot(Unit *u) { Service *s = SERVICE(u); @@ -2765,7 +2788,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { break; case SERVICE_STOP_SIGKILL: - /* Uh, wie sent a SIGKILL and it is still not gone? + /* Uh, we sent a SIGKILL and it is still not gone? * Must be something we cannot kill, so let's just be * weirded out and continue */ @@ -2994,8 +3017,8 @@ static int service_enumerate(Manager *m) { if (de->d_name[0] == 'S') { if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) { - SERVICE(service)->sysv_start_priority = - MAX(a*10 + b, SERVICE(service)->sysv_start_priority); + SERVICE(service)->sysv_start_priority_from_rcnd = + MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd); SERVICE(service)->sysv_enabled = true; } @@ -3040,7 +3063,7 @@ static int service_enumerate(Manager *m) { /* We honour K links only for halt/reboot. For the normal * runlevels we assume the stop jobs will be implicitly added - * by the core logic. Also, we don't really distuingish here + * by the core logic. Also, we don't really distinguish here * between the runlevels 0 and 6 and just add them to the * special shutdown target. On SUSE the boot.d/ runlevel is * also used for shutdown, so we add links for that too to the @@ -3192,11 +3215,11 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro } if (s->control_pid > 0) - if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0) + if (kill(s->control_pid, signo) < 0) r = -errno; if (s->main_pid > 0) - if (kill(mode == KILL_PROCESS_GROUP ? -s->main_pid : s->main_pid, signo) < 0) + if (kill(s->main_pid, signo) < 0) r = -errno; if (mode == KILL_CONTROL_GROUP) { @@ -3218,7 +3241,7 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro goto finish; } - if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, pid_set)) < 0) + if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0) if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) r = q; } @@ -3315,9 +3338,7 @@ const UnitVTable service_vtable = { .active_state = service_active_state, .sub_state_to_string = service_sub_state_to_string, -#ifdef HAVE_SYSV_COMPAT .check_gc = service_check_gc, -#endif .check_snapshot = service_check_snapshot, .sigchld_event = service_sigchld_event,