assert(u);
assert(u->load_state == UNIT_STUB);
- s->timeout_start_usec = u->manager->default_timeout_start_usec;
- s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
- s->timeout_abort_usec = u->manager->default_timeout_abort_usec;
- s->timeout_abort_set = u->manager->default_timeout_abort_set;
- s->restart_usec = u->manager->default_restart_usec;
+ s->timeout_start_usec = u->manager->defaults.timeout_start_usec;
+ s->timeout_stop_usec = u->manager->defaults.timeout_stop_usec;
+ s->timeout_abort_usec = u->manager->defaults.timeout_abort_usec;
+ s->timeout_abort_set = u->manager->defaults.timeout_abort_set;
+ s->restart_usec = u->manager->defaults.restart_usec;
s->restart_max_delay_usec = USEC_INFINITY;
s->runtime_max_usec = USEC_INFINITY;
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -EBADF;
s->stdin_fd = s->stdout_fd = s->stderr_fd = -EBADF;
s->guess_main_pid = true;
-
+ s->main_pid = PIDREF_NULL;
+ s->control_pid = PIDREF_NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
s->exec_context.keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
static void service_unwatch_control_pid(Service *s) {
assert(s);
- if (s->control_pid <= 0)
+ if (!pidref_is_set(&s->control_pid))
return;
- unit_unwatch_pid(UNIT(s), TAKE_PID(s->control_pid));
+ unit_unwatch_pidref(UNIT(s), &s->control_pid);
+ pidref_done(&s->control_pid);
}
static void service_unwatch_main_pid(Service *s) {
assert(s);
- if (s->main_pid <= 0)
+ if (!pidref_is_set(&s->main_pid))
return;
- unit_unwatch_pid(UNIT(s), TAKE_PID(s->main_pid));
+ unit_unwatch_pidref(UNIT(s), &s->main_pid);
+ pidref_done(&s->main_pid);
}
static void service_unwatch_pid_file(Service *s) {
s->pid_file_pathspec = mfree(s->pid_file_pathspec);
}
-static int service_set_main_pid(Service *s, pid_t pid) {
+static int service_set_main_pidref(Service *s, PidRef *pidref) {
assert(s);
- if (pid <= 1)
+ /* Takes ownership of the specified pidref on success, but not on failure. */
+
+ if (!pidref_is_set(pidref))
+ return -ESRCH;
+
+ if (pidref->pid <= 1)
return -EINVAL;
- if (pid == getpid_cached())
+ if (pidref->pid == getpid_cached())
return -EINVAL;
- if (s->main_pid == pid && s->main_pid_known)
+ if (pidref_equal(&s->main_pid, pidref) && s->main_pid_known) {
+ pidref_done(pidref);
return 0;
+ }
- if (s->main_pid != pid) {
+ if (!pidref_equal(&s->main_pid, pidref)) {
service_unwatch_main_pid(s);
- exec_status_start(&s->main_exec_status, pid);
+ exec_status_start(&s->main_exec_status, pidref->pid);
}
- s->main_pid = pid;
+ s->main_pid = TAKE_PIDREF(*pidref);
s->main_pid_known = true;
- s->main_pid_alien = pid_is_my_child(pid) == 0;
+ s->main_pid_alien = pid_is_my_child(s->main_pid.pid) == 0;
if (s->main_pid_alien)
- log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
+ log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", s->main_pid.pid);
return 0;
}
+static int service_set_main_pid(Service *s, pid_t pid) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ int r;
+
+ assert(s);
+
+ r = pidref_set_pid(&pidref, pid);
+ if (r < 0)
+ return r;
+
+ return service_set_main_pidref(s, &pidref);
+}
+
void service_release_socket_fd(Service *s) {
assert(s);
usec_t service_restart_usec_next(Service *s) {
unsigned n_restarts_next;
- usec_t value;
assert(s);
s->restart_usec == 0 ||
s->restart_max_delay_usec == USEC_INFINITY ||
s->restart_usec >= s->restart_max_delay_usec)
- value = s->restart_usec;
- else if (n_restarts_next > s->restart_steps)
- value = s->restart_max_delay_usec;
- else {
- /* Enforced in service_verify() and above */
- assert(s->restart_max_delay_usec > s->restart_usec);
-
- /* r_i / r_0 = (r_n / r_0) ^ (i / n)
- * where,
- * r_0 : initial restart usec (s->restart_usec),
- * r_i : i-th restart usec (value),
- * r_n : maximum restart usec (s->restart_max_delay_usec),
- * i : index of the next step (n_restarts_next - 1)
- * n : num maximum steps (s->restart_steps) */
- value = (usec_t) (s->restart_usec * powl((long double) s->restart_max_delay_usec / s->restart_usec,
- (long double) (n_restarts_next - 1) / s->restart_steps));
- }
-
- log_unit_debug(UNIT(s), "Next restart interval calculated as: %s", FORMAT_TIMESPAN(value, 0));
- return value;
+ return s->restart_usec;
+
+ if (n_restarts_next > s->restart_steps)
+ return s->restart_max_delay_usec;
+
+ /* Enforced in service_verify() and above */
+ assert(s->restart_max_delay_usec > s->restart_usec);
+
+ /* r_i / r_0 = (r_n / r_0) ^ (i / n)
+ * where,
+ * r_0 : initial restart usec (s->restart_usec),
+ * r_i : i-th restart usec (value),
+ * r_n : maximum restart usec (s->restart_max_delay_usec),
+ * i : index of the next step (n_restarts_next - 1)
+ * n : num maximum steps (s->restart_steps) */
+ return (usec_t) (s->restart_usec * powl((long double) s->restart_max_delay_usec / s->restart_usec,
+ (long double) (n_restarts_next - 1) / s->restart_steps));
}
static void service_extend_event_source_timeout(Service *s, sd_event_source *source, usec_t extended) {
exit_status_set_free(&s->restart_force_status);
exit_status_set_free(&s->success_status);
- /* This will leak a process, but at least no memory or any of
- * our resources */
+ /* This will leak a process, but at least no memory or any of our resources */
service_unwatch_main_pid(s);
service_unwatch_control_pid(s);
service_unwatch_pid_file(s);
}
static int service_arm_timer(Service *s, bool relative, usec_t usec) {
- int r;
-
assert(s);
- if (s->timer_event_source) {
- r = (relative ? sd_event_source_set_time_relative : sd_event_source_set_time)(s->timer_event_source, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = (relative ? sd_event_add_time_relative : sd_event_add_time)(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- service_dispatch_timer, s);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(s->timer_event_source, "service-timer");
-
- return 0;
+ return unit_arm_timer(UNIT(s), &s->timer_event_source, relative, usec, service_dispatch_timer);
}
static int service_verify(Service *s) {
if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
s->exec_context.std_output == EXEC_OUTPUT_INHERIT)
- s->exec_context.std_error = UNIT(s)->manager->default_std_error;
+ s->exec_context.std_error = UNIT(s)->manager->defaults.std_error;
if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT)
- s->exec_context.std_output = UNIT(s)->manager->default_std_output;
+ s->exec_context.std_output = UNIT(s)->manager->defaults.std_output;
}
static int service_setup_bus_name(Service *s) {
* delegation is on, in that case it we assume the payload knows better what to do and can process
* things in a more focused way. */
if (s->oom_policy < 0)
- s->oom_policy = s->cgroup_context.delegate ? OOM_CONTINUE : UNIT(s)->manager->default_oom_policy;
+ s->oom_policy = s->cgroup_context.delegate ? OOM_CONTINUE : UNIT(s)->manager->defaults.oom_policy;
/* Let the kernel do the killing if that's requested. */
s->cgroup_context.memory_oom_group = s->oom_policy == OOM_KILL;
prefix, oom_policy_to_string(s->oom_policy),
prefix, signal_to_string(s->reload_signal));
- if (s->control_pid > 0)
+ if (pidref_is_set(&s->control_pid))
fprintf(f,
"%sControl PID: "PID_FMT"\n",
- prefix, s->control_pid);
+ prefix, s->control_pid.pid);
- if (s->main_pid > 0)
+ if (pidref_is_set(&s->main_pid))
fprintf(f,
"%sMain PID: "PID_FMT"\n"
"%sMain PID Known: %s\n"
"%sMain PID Alien: %s\n",
- prefix, s->main_pid,
+ prefix, s->main_pid.pid,
prefix, yes_no(s->main_pid_known),
prefix, yes_no(s->main_pid_alien));
cgroup_context_dump(UNIT(s), f, prefix);
}
-static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
+static int service_is_suitable_main_pid(Service *s, PidRef *pid, int prio) {
Unit *owner;
assert(s);
- assert(pid_is_valid(pid));
+ assert(pidref_is_set(pid));
/* Checks whether the specified PID is suitable as main PID for this service. returns negative if not, 0 if the
* PID is questionnable but should be accepted if the source of configuration is trusted. > 0 if the PID is
* good */
- if (pid == getpid_cached() || pid == 1)
- return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the manager, refusing.", pid);
+ if (pid->pid == getpid_cached() || pid->pid == 1)
+ return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the manager, refusing.", pid->pid);
- if (pid == s->control_pid)
- return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the control process, refusing.", pid);
+ if (pidref_equal(pid, &s->control_pid))
+ return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the control process, refusing.", pid->pid);
- if (!pid_is_alive(pid))
- return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(ESRCH), "New main PID "PID_FMT" does not exist or is a zombie.", pid);
+ if (!pid_is_alive(pid->pid))
+ return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(ESRCH), "New main PID "PID_FMT" does not exist or is a zombie.", pid->pid);
- owner = manager_get_unit_by_pid(UNIT(s)->manager, pid);
+ owner = manager_get_unit_by_pidref(UNIT(s)->manager, pid);
if (owner == UNIT(s)) {
- log_unit_debug(UNIT(s), "New main PID "PID_FMT" belongs to service, we are happy.", pid);
+ log_unit_debug(UNIT(s), "New main PID "PID_FMT" belongs to service, we are happy.", pid->pid);
return 1; /* Yay, it's definitely a good PID */
}
}
static int service_load_pid_file(Service *s, bool may_warn) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
bool questionable_pid_file = false;
_cleanup_free_ char *k = NULL;
_cleanup_close_ int fd = -EBADF;
int r, prio;
- pid_t pid;
assert(s);
"Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
s->pid_file);
- r = parse_pid(k, &pid);
+ r = pidref_set_pidstr(&pidref, k);
if (r < 0)
return log_unit_full_errno(UNIT(s), prio, r, "Failed to parse PID from file %s: %m", s->pid_file);
- if (s->main_pid_known && pid == s->main_pid)
+ if (s->main_pid_known && pidref_equal(&pidref, &s->main_pid))
return 0;
- r = service_is_suitable_main_pid(s, pid, prio);
+ r = service_is_suitable_main_pid(s, &pidref, prio);
if (r < 0)
return r;
if (r == 0) {
if (st.st_uid != 0)
return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(EPERM),
- "New main PID "PID_FMT" does not belong to service, and PID file is not owned by root. Refusing.", pid);
+ "New main PID "PID_FMT" does not belong to service, and PID file is not owned by root. Refusing.", pidref.pid);
- log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, but we'll accept it since PID file is owned by root.", pid);
+ log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, but we'll accept it since PID file is owned by root.", pidref.pid);
}
if (s->main_pid_known) {
- log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
+ log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid.pid, pidref.pid);
service_unwatch_main_pid(s);
s->main_pid_known = false;
} else
- log_unit_debug(UNIT(s), "Main PID loaded: "PID_FMT, pid);
+ log_unit_debug(UNIT(s), "Main PID loaded: "PID_FMT, pidref.pid);
- r = service_set_main_pid(s, pid);
+ r = service_set_main_pidref(s, &pidref);
if (r < 0)
return r;
- r = unit_watch_pid(UNIT(s), pid, false);
+ r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
if (r < 0) /* FIXME: we need to do something here */
- return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid);
+ return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", s->main_pid.pid);
return 1;
}
static void service_search_main_pid(Service *s) {
- pid_t pid = 0;
+ _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
int r;
assert(s);
- /* If we know it anyway, don't ever fall back to unreliable
- * heuristics */
+ /* If we know it anyway, don't ever fall back to unreliable heuristics */
if (s->main_pid_known)
return;
if (!s->guess_main_pid)
return;
- assert(s->main_pid <= 0);
+ assert(!pidref_is_set(&s->main_pid));
if (unit_search_main_pid(UNIT(s), &pid) < 0)
return;
- log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
- if (service_set_main_pid(s, pid) < 0)
+ log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid.pid);
+ if (service_set_main_pidref(s, &pid) < 0)
return;
- r = unit_watch_pid(UNIT(s), pid, false);
+ r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
if (r < 0)
/* FIXME: we need to do something here */
- log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", s->main_pid.pid);
}
static void service_set_state(Service *s, ServiceState state) {
if (r < 0)
return r;
- if (s->main_pid > 0 &&
- pid_is_unwaited(s->main_pid) &&
+ if (pidref_is_set(&s->main_pid) &&
+ pid_is_unwaited(s->main_pid.pid) &&
(IN_SET(s->deserialized_state,
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
- r = unit_watch_pid(UNIT(s), s->main_pid, false);
+ r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
if (r < 0)
return r;
}
- if (s->control_pid > 0 &&
- pid_is_unwaited(s->control_pid) &&
+ if (pidref_is_set(&s->control_pid) &&
+ pid_is_unwaited(s->control_pid.pid) &&
IN_SET(s->deserialized_state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
- r = unit_watch_pid(UNIT(s), s->control_pid, false);
+ r = unit_watch_pidref(UNIT(s), &s->control_pid, /* exclusive= */ false);
if (r < 0)
return r;
}
ExecCommand *c,
usec_t timeout,
ExecFlags flags,
- pid_t *ret_pid) {
+ PidRef *ret_pid) {
_cleanup_(exec_params_clear) ExecParameters exec_params = {
.flags = flags,
};
_cleanup_(sd_event_source_unrefp) sd_event_source *exec_fd_source = NULL;
_cleanup_strv_free_ char **final_env = NULL, **our_env = NULL;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
size_t n_env = 0;
pid_t pid;
int r;
return -ENOMEM;
}
- if (s->main_pid > 0)
- if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
+ if (pidref_is_set(&s->main_pid))
+ if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid.pid) < 0)
return -ENOMEM;
if (MANAGER_IS_USER(UNIT(s)->manager))
s->exec_fd_event_source = TAKE_PTR(exec_fd_source);
s->exec_fd_hot = false;
- r = unit_watch_pid(UNIT(s), pid, true);
+ r = pidref_set_pid(&pidref, pid);
if (r < 0)
return r;
- *ret_pid = pid;
+ r = unit_watch_pidref(UNIT(s), &pidref, /* exclusive= */ true);
+ if (r < 0)
+ return r;
+ *ret_pid = TAKE_PIDREF(pidref);
return 0;
}
/* Returns 0 if the pid is dead, > 0 if it is good, < 0 if we don't know */
- /* If we know the pid file, then let's just check if it is
- * still valid */
+ /* If we know the pid file, then let's just check if it is still valid */
if (s->main_pid_known) {
- /* If it's an alien child let's check if it is still
- * alive ... */
- if (s->main_pid_alien && s->main_pid > 0)
- return pid_is_alive(s->main_pid);
+ /* If it's an alien child let's check if it is still alive ... */
+ if (s->main_pid_alien && pidref_is_set(&s->main_pid))
+ return pid_is_alive(s->main_pid.pid);
- /* .. 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;
+ /* .. otherwise assume we'll get a SIGCHLD for it, which we really should wait for to collect
+ * exit status and code */
+ return pidref_is_set(&s->main_pid);
}
/* We don't know the pid */
* make this function as similar as possible to main_pid_good() and cgroup_good(), we pretend that < 0 also
* means: we can't figure it out. */
- return s->control_pid > 0;
+ return pidref_is_set(&s->control_pid);
}
static int cgroup_good(Service *s) {
}
if (allow_restart) {
+ usec_t restart_usec_next;
+
/* We make two state changes here: one that maps to the high-level UNIT_INACTIVE/UNIT_FAILED
* state (i.e. a state indicating deactivation), and then one that that maps to the
* high-level UNIT_STARTING state (i.e. a state indicating activation). We do this so that
if (s->restart_mode != SERVICE_RESTART_MODE_DIRECT)
service_set_state(s, restart_state);
- r = service_arm_timer(s, /* relative= */ true, service_restart_usec_next(s));
- if (r < 0)
- goto fail;
+ restart_usec_next = service_restart_usec_next(s);
+
+ r = service_arm_timer(s, /* relative= */ true, restart_usec_next);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to install restart timer: %m");
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ false);
+ return;
+ }
+
+ log_unit_debug(UNIT(s), "Next restart interval calculated as: %s", FORMAT_TIMESPAN(restart_usec_next, 0));
service_set_state(s, SERVICE_AUTO_RESTART);
} else {
/* Reset TTY ownership if necessary */
exec_context_revert_tty(&s->exec_context);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run install restart timer: %m");
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
}
static void service_enter_stop_post(Service *s, ServiceResult f) {
s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_STOP_POST;
+ pidref_done(&s->control_pid);
r = service_spawn(s,
s->control_command,
s->timeout_stop_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT|EXEC_CONTROL_CGROUP,
&s->control_pid);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-post' task: %m");
+ service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+ return;
+ }
service_set_state(s, SERVICE_STOP_POST);
} else
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-post' task: %m");
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
static int state_to_kill_operation(Service *s, ServiceState state) {
UNIT(s),
&s->kill_context,
kill_operation,
- s->main_pid,
- s->control_pid,
+ &s->main_pid,
+ &s->control_pid,
s->main_pid_alien);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
goto fail;
+ }
if (r > 0) {
r = service_arm_timer(s, /* relative= */ true,
kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
goto fail;
+ }
service_set_state(s, state);
} else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
else if (IN_SET(state, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM) && s->kill_context.send_sigkill)
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
else
- service_enter_dead(s, SERVICE_SUCCESS, true);
+ service_enter_dead(s, SERVICE_SUCCESS, /* allow_restart= */ true);
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
-
if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
else
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
}
static void service_enter_stop_by_notify(Service *s) {
+ int r;
+
assert(s);
(void) unit_enqueue_rewatch_pids(UNIT(s));
- service_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
+ r = service_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+ return;
+ }
/* The service told us it's stopping, so it's as if we SIGTERM'd it. */
service_set_state(s, SERVICE_STOP_SIGTERM);
s->control_command = s->exec_command[SERVICE_EXEC_STOP];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_STOP;
+ pidref_done(&s->control_pid);
r = service_spawn(s,
s->control_command,
s->timeout_stop_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT|EXEC_CONTROL_CGROUP,
&s->control_pid);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop' task: %m");
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+ return;
+ }
service_set_state(s, SERVICE_STOP);
} else
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop' task: %m");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
static bool service_good(Service *s) {
}
static void service_enter_running(Service *s, ServiceResult f) {
+ int r;
+
assert(s);
if (s->result == SERVICE_SUCCESS)
service_enter_stop_by_notify(s);
else {
service_set_state(s, SERVICE_RUNNING);
- service_arm_timer(s, /* relative= */ false, service_running_timeout(s));
+
+ r = service_arm_timer(s, /* relative= */ false, service_running_timeout(s));
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+ service_enter_running(s, SERVICE_FAILURE_RESOURCES);
+ return;
+ }
}
} else if (s->remain_after_exit)
s->control_command = s->exec_command[SERVICE_EXEC_START_POST];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_START_POST;
+ pidref_done(&s->control_pid);
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
&s->control_pid);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-post' task: %m");
+ service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+ return;
+ }
service_set_state(s, SERVICE_START_POST);
} else
service_enter_running(s, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-post' task: %m");
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
static void service_kill_control_process(Service *s) {
assert(s);
- if (s->control_pid <= 0)
+ if (!pidref_is_set(&s->control_pid))
return;
- r = kill_and_sigcont(s->control_pid, SIGKILL);
+ r = pidref_kill_and_sigcont(&s->control_pid, SIGKILL);
if (r < 0) {
_cleanup_free_ char *comm = NULL;
- (void) get_process_comm(s->control_pid, &comm);
+ (void) get_process_comm(s->control_pid.pid, &comm);
log_unit_debug_errno(UNIT(s), r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m",
- s->control_pid, strna(comm));
+ s->control_pid.pid, strna(comm));
}
}
}
static void service_enter_start(Service *s) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
ExecCommand *c;
usec_t timeout;
- pid_t pid;
int r;
assert(s);
c,
timeout,
EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS|EXEC_SETENV_MONITOR_RESULT,
- &pid);
- if (r < 0)
+ &pidref);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start' task: %m");
goto fail;
+ }
if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE)) {
/* For simple services we immediately start
* the START_POST binaries. */
- (void) service_set_main_pid(s, pid);
+ (void) service_set_main_pidref(s, &pidref);
service_enter_start_post(s);
} else if (s->type == SERVICE_FORKING) {
/* For forking services we wait until the start
* process exited. */
- s->control_pid = pid;
+ pidref_done(&s->control_pid);
+ s->control_pid = TAKE_PIDREF(pidref);
service_set_state(s, SERVICE_START);
} else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD, SERVICE_EXEC)) {
/* For D-Bus services we know the main pid right away, but wait for the bus name to appear on the
* bus. 'notify' and 'exec' services are similar. */
- (void) service_set_main_pid(s, pid);
+ (void) service_set_main_pidref(s, &pidref);
service_set_state(s, SERVICE_START);
} else
assert_not_reached();
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'start' task: %m");
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
s->timeout_start_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN|EXEC_SETENV_MONITOR_RESULT|EXEC_WRITE_CREDENTIALS,
&s->control_pid);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-pre' task: %m");
goto fail;
+ }
service_set_state(s, SERVICE_START_PRE);
} else
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-pre' task: %m");
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
}
static void service_enter_condition(Service *s) {
goto fail;
s->control_command_id = SERVICE_EXEC_CONDITION;
+ pidref_done(&s->control_pid);
r = service_spawn(s,
s->control_command,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
&s->control_pid);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'exec-condition' task: %m");
goto fail;
+ }
service_set_state(s, SERVICE_CONDITION);
} else
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'exec-condition' task: %m");
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
}
static void service_enter_restart(Service *s) {
/* Any units that are bound to this service must also be restarted. We use JOB_START for ourselves
* but then set JOB_RESTART_DEPENDENCIES which will enqueue JOB_RESTART for those dependency jobs. */
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(s), JOB_RESTART_DEPENDENCIES, NULL, &error, NULL);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ log_unit_warning(UNIT(s), "Failed to schedule restart job: %s", bus_error_message(&error, r));
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ false);
+ return;
+ }
/* Count the jobs we enqueue for restarting. This counter is maintained as long as the unit isn't
* fully stopped, i.e. as long as it remains up or remains in auto-start states. The user can reset
/* Notify clients about changed restart counter */
unit_add_to_dbus_queue(UNIT(s));
- return;
-
-fail:
- log_unit_warning(UNIT(s), "Failed to schedule restart job: %s", bus_error_message(&error, r));
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
}
static void service_enter_reload_by_notify(Service *s) {
assert(s);
- service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+ s->reload_result = SERVICE_FAILURE_RESOURCES;
+ service_enter_running(s, SERVICE_SUCCESS);
+ return;
+ }
+
service_set_state(s, SERVICE_RELOAD_NOTIFY);
/* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
if (r < 0)
- log_unit_warning(UNIT(s), "Failed to schedule propagation of reload: %s", bus_error_message(&error, r));
+ log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r));
}
static void service_enter_reload(Service *s) {
usec_t ts = now(CLOCK_MONOTONIC);
- if (s->type == SERVICE_NOTIFY_RELOAD && s->main_pid > 0) {
- r = kill_and_sigcont(s->main_pid, s->reload_signal);
+ if (s->type == SERVICE_NOTIFY_RELOAD && pidref_is_set(&s->main_pid)) {
+ r = pidref_kill_and_sigcont(&s->main_pid, s->reload_signal);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m");
goto fail;
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_RELOAD;
+ pidref_done(&s->control_pid);
r = service_spawn(s,
s->control_command,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
&s->control_pid);
if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'reload' task: %m");
goto fail;
}
service_set_state(s, SERVICE_RELOAD);
} else if (killed) {
- service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+ goto fail;
+ }
+
service_set_state(s, SERVICE_RELOAD_SIGNAL);
} else {
service_enter_running(s, SERVICE_SUCCESS);
else
timeout = s->timeout_stop_usec;
+ pidref_done(&s->control_pid);
+
r = service_spawn(s,
s->control_command,
timeout,
(IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_START) ? EXEC_SETENV_MONITOR_RESULT : 0)|
(IN_SET(s->control_command_id, SERVICE_EXEC_START_POST, SERVICE_EXEC_RELOAD, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_CONTROL_CGROUP : 0),
&s->control_pid);
- if (r < 0)
- goto fail;
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m");
-
- if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START_POST, SERVICE_STOP))
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
- else if (s->state == SERVICE_STOP_POST)
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
- else if (s->state == SERVICE_RELOAD) {
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
- } else
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn next control task: %m");
+
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START_POST, SERVICE_STOP))
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+ else if (s->state == SERVICE_STOP_POST)
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
+ else if (s->state == SERVICE_RELOAD) {
+ s->reload_result = SERVICE_FAILURE_RESOURCES;
+ service_enter_running(s, SERVICE_SUCCESS);
+ } else
+ service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+ }
}
static void service_run_next_main(Service *s) {
- pid_t pid;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
assert(s);
s->main_command,
s->timeout_start_usec,
EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_SETENV_MONITOR_RESULT|EXEC_WRITE_CREDENTIALS,
- &pid);
- if (r < 0)
- goto fail;
-
- (void) service_set_main_pid(s, pid);
-
- return;
+ &pidref);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to spawn next main task: %m");
+ service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+ return;
+ }
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run next main task: %m");
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+ (void) service_set_main_pidref(s, &pidref);
}
static int service_start(Unit *u) {
(void) serialize_item(f, "result", service_result_to_string(s->result));
(void) serialize_item(f, "reload-result", service_result_to_string(s->reload_result));
- if (s->control_pid > 0)
- (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid);
+ if (pidref_is_set(&s->control_pid))
+ (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid.pid);
- if (s->main_pid_known && s->main_pid > 0)
- (void) serialize_item_format(f, "main-pid", PID_FMT, s->main_pid);
+ if (s->main_pid_known && pidref_is_set(&s->main_pid))
+ (void) serialize_item_format(f, "main-pid", PID_FMT, s->main_pid.pid);
(void) serialize_bool(f, "main-pid-known", s->main_pid_known);
(void) serialize_bool(f, "bus-name-good", s->bus_name_good);
s->reload_result = f;
} else if (streq(key, "control-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u, "Failed to parse control-pid value: %s", value);
- else
- s->control_pid = pid;
+ pidref_done(&s->control_pid);
+ r = pidref_set_pidstr(&s->control_pid, value);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to initialize control PID '%s' from serialization, ignoring.", value);
} else if (streq(key, "main-pid")) {
pid_t pid;
log_unit_debug(UNIT(s), "Setting watch for PID file %s", s->pid_file_pathspec->path);
r = path_spec_watch(s->pid_file_pathspec, service_dispatch_inotify_io);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to set a watch for PID file %s: %m", s->pid_file_pathspec->path);
+ service_unwatch_pid_file(s);
+ return r;
+ }
/* the pidfile might have appeared just before we set the watch */
log_unit_debug(UNIT(s), "Trying to read PID file %s in case it changed", s->pid_file_pathspec->path);
service_retry_pid_file(s);
return 0;
-fail:
- log_unit_error_errno(UNIT(s), r, "Failed to set a watch for PID file %s: %m", s->pid_file_pathspec->path);
- service_unwatch_pid_file(s);
- return r;
}
static int service_demand_pid_file(Service *s) {
/* Oneshot services and non-SERVICE_EXEC_START commands should not be
* considered daemons as they are typically not long running. */
- if (s->type == SERVICE_ONESHOT || (s->control_pid == pid && s->control_command_id != SERVICE_EXEC_START))
+ if (s->type == SERVICE_ONESHOT || (s->control_pid.pid == pid && s->control_command_id != SERVICE_EXEC_START))
clean_mode = EXIT_CLEAN_COMMAND;
else
clean_mode = EXIT_CLEAN_DAEMON;
else
assert_not_reached();
- if (s->main_pid == pid) {
+ if (s->main_pid.pid == pid) {
/* Clean up the exec_fd event source. We want to do this here, not later in
* service_set_state(), because service_enter_stop_post() calls service_spawn().
* The source owns its end of the pipe, so this will close that too. */
if (service_load_pid_file(s, false) > 0)
return;
- s->main_pid = 0;
+ pidref_done(&s->main_pid);
exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
if (s->main_command) {
service_enter_start_post(s);
}
- } else if (s->control_pid == pid) {
+ } else if (s->control_pid.pid == pid) {
const char *kind;
bool success;
- s->control_pid = 0;
+ pidref_done(&s->control_pid);
if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
return false;
}
- if (notify_access == NOTIFY_MAIN && pid != s->main_pid) {
- if (s->main_pid != 0)
- log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
+ if (notify_access == NOTIFY_MAIN && pid != s->main_pid.pid) {
+ if (pidref_is_set(&s->main_pid))
+ log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid.pid);
else
log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid);
return false;
}
- if (notify_access == NOTIFY_EXEC && pid != s->main_pid && pid != s->control_pid) {
- if (s->main_pid != 0 && s->control_pid != 0)
+ if (notify_access == NOTIFY_EXEC && pid != s->main_pid.pid && pid != s->control_pid.pid) {
+ if (pidref_is_set(&s->main_pid) && pidref_is_set(&s->control_pid))
log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT" and control PID "PID_FMT,
- pid, s->main_pid, s->control_pid);
- else if (s->main_pid != 0)
- log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
- else if (s->control_pid != 0)
- log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for control PID "PID_FMT, pid, s->control_pid);
+ pid, s->main_pid.pid, s->control_pid.pid);
+ else if (pidref_is_set(&s->main_pid))
+ log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid.pid);
+ else if (pidref_is_set(&s->control_pid))
+ log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for control PID "PID_FMT, pid, s->control_pid.pid);
else
log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID and control PID which are currently not known", pid);
_cleanup_free_ char *cc = NULL;
cc = strv_join(tags, ", ");
- log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", ucred->pid, isempty(cc) ? "n/a" : cc);
+ log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", ucred->pid, empty_to_na(cc));
}
/* Interpret MAINPID= */
e = strv_find_startswith(tags, "MAINPID=");
if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY)) {
- pid_t new_main_pid;
+ _cleanup_(pidref_done) PidRef new_main_pid = PIDREF_NULL;
- if (parse_pid(e, &new_main_pid) < 0)
- log_unit_warning(u, "Failed to parse MAINPID= field in notification message, ignoring: %s", e);
- else if (!s->main_pid_known || new_main_pid != s->main_pid) {
+ r = pidref_set_pidstr(&new_main_pid, e);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to parse MAINPID=%s field in notification message, ignoring: %m", e);
+ else if (!s->main_pid_known || !pidref_equal(&new_main_pid, &s->main_pid)) {
- r = service_is_suitable_main_pid(s, new_main_pid, LOG_WARNING);
+ r = service_is_suitable_main_pid(s, &new_main_pid, LOG_WARNING);
if (r == 0) {
/* The new main PID is a bit suspicious, which is OK if the sender is privileged. */
if (ucred->uid == 0) {
- log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, but we'll accept it as the request to change it came from a privileged process.", new_main_pid);
+ log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, but we'll accept it as the request to change it came from a privileged process.", new_main_pid.pid);
r = 1;
} else
- log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, refusing.", new_main_pid);
+ log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, refusing.", new_main_pid.pid);
}
if (r > 0) {
- (void) service_set_main_pid(s, new_main_pid);
+ (void) service_set_main_pidref(s, &new_main_pid);
- r = unit_watch_pid(UNIT(s), new_main_pid, false);
+ r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
if (r < 0)
- log_unit_warning_errno(UNIT(s), r, "Failed to watch new main PID "PID_FMT" for service: %m", new_main_pid);
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch new main PID "PID_FMT" for service: %m", s->main_pid.pid);
notify_dbus = true;
}
/* If the service is running but we have no main PID yet, get it from the owner of the D-Bus name */
- return !pid_is_valid(s->main_pid) &&
+ return !pidref_is_set(&s->main_pid) &&
IN_SET(s->state,
SERVICE_START,
SERVICE_START_POST,
}
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
const sd_bus_error *e;
Unit *u = ASSERT_PTR(userdata);
uint32_t pid;
return 1;
}
- if (!pid_is_valid(pid)) {
- log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "GetConnectionUnixProcessID() returned invalid PID");
+ r = pidref_set_pid(&pidref, pid);
+ if (r < 0) {
+ log_debug_errno(r, "GetConnectionUnixProcessID() returned invalid PID: %m");
return 1;
}
- log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, (pid_t) pid);
+ log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid);
- (void) service_set_main_pid(s, pid);
- (void) unit_watch_pid(UNIT(s), pid, false);
+ (void) service_set_main_pidref(s, &pidref);
+ (void) unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
return 1;
}
s->flush_n_restarts = false;
}
-static int service_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return unit_kill_common(u, who, signo, code, value, s->main_pid, s->control_pid, error);
+static PidRef* service_main_pid(Unit *u) {
+ return &ASSERT_PTR(SERVICE(u))->main_pid;
}
-static int service_main_pid(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return s->main_pid;
-}
-
-static int service_control_pid(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return s->control_pid;
+static PidRef* service_control_pid(Unit *u) {
+ return &ASSERT_PTR(SERVICE(u))->control_pid;
}
static bool service_needs_console(Unit *u) {
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
r = service_arm_timer(s, /* relative= */ true, s->exec_context.timeout_clean_usec);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(u, r, "Failed to install timer: %m");
goto fail;
+ }
r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(u, r, "Failed to spawn cleaning task: %m");
goto fail;
+ }
service_set_state(s, SERVICE_CLEANING);
-
return 0;
fail:
- log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m");
s->clean_result = SERVICE_FAILURE_RESOURCES;
s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
return r;
.can_reload = service_can_reload,
- .kill = service_kill,
.clean = service_clean,
.can_clean = service_can_clean,