X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fservice.c;h=0b657679f7391fe4f630ba1f0e48f2dd46f10af8;hp=728ca0b0180ece820552ad496eff21c227a09b41;hb=3611581ebdabbe3a1d6a9b5310a0b59792279d7d;hpb=da19d5c19f60ec80e1733b1e994311c59c6eda73 diff --git a/src/service.c b/src/service.c index 728ca0b01..0b657679f 100644 --- a/src/service.c +++ b/src/service.c @@ -65,7 +65,7 @@ static const struct { { "boot.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT }, #endif -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_FRUGALWARE) +#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_FRUGALWARE) || defined(TARGET_ANGSTROM) /* Debian style rcS.d */ { "rcS.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT }, #endif @@ -160,12 +160,16 @@ static int service_set_main_pid(Service *s, pid_t pid) { if (pid == getpid()) return -EINVAL; - if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) + s->main_pid = pid; + s->main_pid_known = true; + + if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) { log_warning("%s: Supervising process %lu which is not our child. We'll most likely not notice when it exits.", s->meta.id, (unsigned long) pid); - s->main_pid = pid; - s->main_pid_known = true; + s->main_pid_alien = true; + } else + s->main_pid_alien = false; exec_status_start(&s->main_exec_status, pid); @@ -242,7 +246,7 @@ static char *sysv_translate_name(const char *name) { if (!(r = new(char, strlen(name) + sizeof(".service")))) return NULL; -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) +#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) if (endswith(name, ".sh")) /* Drop Debian-style .sh suffix */ strcpy(stpcpy(r, name) - 3, ".service"); @@ -276,24 +280,24 @@ static int sysv_translate_facility(const char *name, const char *filename, char /* 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 */ + /* 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, "x-display-manager", SPECIAL_DISPLAY_MANAGER_SERVICE, "null", NULL, -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) +#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) "mail-transport-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, #endif @@ -368,7 +372,7 @@ static int sysv_fix_order(Service *s) { /* For each pair of services where at least one lacks a LSB * header, we use the start priority value to order things. */ - LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) { + LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) { Service *t; UnitDependency d; bool special_s, special_t; @@ -466,6 +470,7 @@ static int service_load_sysv_path(Service *s, const char *path) { LSB_DESCRIPTION } state = NORMAL; char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description; + struct stat st; assert(s); assert(path); @@ -477,12 +482,26 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } + zero(st); + if (fstat(fileno(f), &st) < 0) { + r = -errno; + goto finish; + } + free(s->sysv_path); if (!(s->sysv_path = strdup(path))) { r = -ENOMEM; goto finish; } + s->sysv_mtime = timespec_load(&st.st_mtim); + + if (null_or_empty(&st)) { + u->meta.load_state = UNIT_MASKED; + r = 0; + goto finish; + } + while (!feof(f)) { char l[LINE_MAX], *t; @@ -824,7 +843,7 @@ static int service_load_sysv_path(Service *s, const char *path) { /* Special setting for all SysV services */ s->type = SERVICE_FORKING; - s->remain_after_exit = true; + s->remain_after_exit = !s->pid_file; s->restart = SERVICE_RESTART_NO; s->exec_context.std_output = (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY) @@ -883,7 +902,7 @@ static int service_load_sysv_name(Service *s, const char *name) { /* For SysV services we strip the boot.*, rc.* and *.sh * prefixes/suffixes. */ -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) +#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) if (endswith(name, ".sh.service")) return -ENOENT; #endif @@ -910,7 +929,7 @@ static int service_load_sysv_name(Service *s, const char *name) { r = service_load_sysv_path(s, path); -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) +#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) if (r >= 0 && s->meta.load_state == UNIT_STUB) { /* Try Debian style *.sh source'able init scripts */ strcat(path, ".sh"); @@ -1002,7 +1021,7 @@ static int fsck_fix_order(Service *s) { /* For each pair of services where both have an fsck priority * we order things based on it. */ - LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) { + LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) { Service *t; UnitDependency d; @@ -1189,8 +1208,12 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { if (s->main_pid > 0) fprintf(f, - "%sMain PID: %lu\n", - prefix, (unsigned long) s->main_pid); + "%sMain PID: %lu\n" + "%sMain PID Known: %s\n" + "%sMain PID Alien: %s\n", + prefix, (unsigned long) s->main_pid, + prefix, yes_no(s->main_pid_known), + prefix, yes_no(s->main_pid_alien)); if (s->pid_file) fprintf(f, @@ -1256,8 +1279,11 @@ static int service_load_pid_file(Service *s) { assert(s); + if (s->main_pid_known) + return 0; + if (!s->pid_file) - return -ENOENT; + return 0; if ((r = read_one_line_file(s->pid_file, &k)) < 0) return r; @@ -1470,7 +1496,7 @@ static void service_set_state(Service *s, ServiceState state) { /* For the inactive states unit_notify() will trim the cgroup, * but for exit we have to do that ourselves... */ - if (state == SERVICE_EXITED) + if (state == SERVICE_EXITED && s->meta.manager->n_reloading <= 0) cgroup_bonding_trim_list(s->meta.cgroup_bondings, true); if (old_state != state) @@ -1592,8 +1618,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); @@ -1738,8 +1764,18 @@ static int main_pid_good(Service *s) { /* If we know the pid file, then lets just check if it is * still valid */ - if (s->main_pid_known) + if (s->main_pid_known) { + + /* If it's an alien child let's check if it is still + * alive ... */ + if (s->main_pid_alien) + return kill(s->main_pid, 0) >= 0 || errno != ESRCH; + + /* .. otherwise assume we'll get a SIGCHLD for it, + * which we really should wait for to collect exit + * status and code */ return s->main_pid > 0; + } /* We don't know the pid */ return -EAGAIN; @@ -1848,12 +1884,11 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { 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; + wait_for_exit = !s->main_pid_alien; } if (s->control_pid > 0) { 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 wait_for_exit = true; @@ -2277,6 +2312,7 @@ static int service_start(Unit *u) { s->failure = false; s->main_pid_known = false; + s->main_pid_alien = false; s->forbid_restart = false; service_enter_start_pre(s); @@ -2550,7 +2586,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (s->main_pid == pid) { s->main_pid = 0; - exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id); + exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status); /* If this is not a forking service than the main * process got started and hence we copy the exit @@ -2629,7 +2665,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_pid = 0; if (s->control_command) { - exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id); + exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); if (s->control_command->ignore) success = true; @@ -2688,16 +2724,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case SERVICE_START_POST: - if (success && s->pid_file && !s->main_pid_known) { - int r; - - /* Hmm, let's see if we can - * load the pid now after the - * start-post scripts got - * executed. */ - - if ((r = service_load_pid_file(s)) < 0) - log_warning("%s: failed to load PID file %s: %s", s->meta.id, s->pid_file, strerror(-r)); + if (success) { + service_load_pid_file(s); + service_search_main_pid(s); } s->reload_failure = !success; @@ -2848,6 +2877,7 @@ static void service_cgroup_notify_event(Unit *u) { case SERVICE_STOP_SIGTERM: case SERVICE_STOP_SIGKILL: + if (main_pid_good(s) <= 0 && !control_pid_good(s)) service_enter_stop_post(s, true); @@ -2947,6 +2977,9 @@ static int service_enumerate(Manager *m) { assert(m); + if (m->running_as != MANAGER_SYSTEM) + return 0; + zero(runlevel_services); STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path) @@ -3197,6 +3230,29 @@ static void service_reset_failed(Unit *u) { s->failure = false; } +static bool service_need_daemon_reload(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + +#ifdef HAVE_SYSV_COMPAT + if (s->sysv_path) { + struct stat st; + + zero(st); + if (stat(s->sysv_path, &st) < 0) + /* What, cannot access this anymore? */ + return true; + + if (s->sysv_mtime > 0 && + timespec_load(&st.st_mtim) != s->sysv_mtime) + return true; + } +#endif + + return false; +} + static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { Service *s = SERVICE(u); int r = 0; @@ -3214,15 +3270,17 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro return -ENOENT; } - if (s->control_pid > 0) - if (kill(s->control_pid, signo) < 0) - r = -errno; + if (who == KILL_CONTROL || who == KILL_ALL) + if (s->control_pid > 0) + if (kill(s->control_pid, signo) < 0) + r = -errno; - if (s->main_pid > 0) - if (kill(s->main_pid, signo) < 0) - r = -errno; + if (who == KILL_MAIN || who == KILL_ALL) + if (s->main_pid > 0) + if (kill(s->main_pid, signo) < 0) + r = -errno; - if (mode == KILL_CONTROL_GROUP) { + if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) { int q; if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) @@ -3242,7 +3300,7 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro } if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0) - if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) + if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) r = q; } @@ -3346,6 +3404,8 @@ const UnitVTable service_vtable = { .reset_failed = service_reset_failed, + .need_daemon_reload = service_need_daemon_reload, + .cgroup_notify_empty = service_cgroup_notify_event, .notify_message = service_notify_message,