process-util: change pid_is_alive() to not eat up errors, and add pidref_is_alive()

Let's no eat up errors, but propagate unexpected ones.
This commit is contained in:
Lennart Poettering
2023-10-17 12:12:05 +02:00
parent 8b51341545
commit becdfcb9f1
6 changed files with 52 additions and 26 deletions

View File

@@ -1043,13 +1043,13 @@ bool pid_is_unwaited(pid_t pid) {
return errno != ESRCH;
}
bool pid_is_alive(pid_t pid) {
int pid_is_alive(pid_t pid) {
int r;
/* Checks whether a PID is still valid and not a zombie */
if (pid < 0)
return false;
return -ESRCH;
if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
return true;
@@ -1058,10 +1058,31 @@ bool pid_is_alive(pid_t pid) {
return true;
r = get_process_state(pid);
if (IN_SET(r, -ESRCH, 'Z'))
if (r == -ESRCH)
return false;
if (r < 0)
return r;
return true;
return r != 'Z';
}
int pidref_is_alive(const PidRef *pidref) {
int r, result;
if (!pidref_is_set(pidref))
return -ESRCH;
result = pid_is_alive(pidref->pid);
if (result < 0)
return result;
r = pidref_verify(pidref);
if (r == -ESRCH)
return false;
if (r < 0)
return r;
return result;
}
int pid_from_same_root_fs(pid_t pid) {

View File

@@ -86,7 +86,8 @@ int pidref_is_kernel_thread(const PidRef *pid);
int getenv_for_pid(pid_t pid, const char *field, char **_value);
bool pid_is_alive(pid_t pid);
int pid_is_alive(pid_t pid);
int pidref_is_alive(const PidRef *pidref);
bool pid_is_unwaited(pid_t pid);
int pid_is_my_child(pid_t pid);
int pid_from_same_root_fs(pid_t pid);

View File

@@ -1053,6 +1053,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
static int service_is_suitable_main_pid(Service *s, PidRef *pid, int prio) {
Unit *owner;
int r;
assert(s);
assert(pidref_is_set(pid));
@@ -1067,8 +1068,11 @@ static int service_is_suitable_main_pid(Service *s, PidRef *pid, int prio) {
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->pid))
r = pidref_is_alive(pid);
if (r == 0)
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);
if (r < 0)
return log_unit_full_errno(UNIT(s), prio, r, "Failed to check if main PID "PID_FMT" exists or is a zombie.", pid->pid);
owner = manager_get_unit_by_pidref(UNIT(s)->manager, pid);
if (owner == UNIT(s)) {
@@ -1827,7 +1831,7 @@ static int main_pid_good(Service *s) {
/* 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);
return pidref_is_alive(&s->main_pid);
/* .. otherwise assume we'll get a SIGCHLD for it, which we really should wait for to collect
* exit status and code */

View File

@@ -139,7 +139,7 @@ sd_bus_creds* bus_creds_new(void) {
}
_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
sd_bus_creds *c;
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
int r;
assert_return(pid >= 0, -EINVAL);
@@ -154,19 +154,18 @@ _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t m
return -ENOMEM;
r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
if (r < 0) {
sd_bus_creds_unref(c);
if (r < 0)
return r;
}
/* Check if the process existed at all, in case we haven't
* figured that out already */
if (!pid_is_alive(pid)) {
sd_bus_creds_unref(c);
r = pid_is_alive(pid);
if (r < 0)
return r;
if (r == 0)
return -ESRCH;
}
*ret = c;
*ret = TAKE_PTR(c);
return 0;
}
@@ -1089,12 +1088,13 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->mask |= SD_BUS_CREDS_TTY;
}
/* In case only the exe path was to be read we cannot
* distinguish the case where the exe path was unreadable
* because the process was a kernel thread, or when the
* process didn't exist at all. Hence, let's do a final check,
* to be sure. */
if (!pid_is_alive(pid))
/* In case only the exe path was to be read we cannot distinguish the case where the exe path was
* unreadable because the process was a kernel thread, or when the process didn't exist at
* all. Hence, let's do a final check, to be sure. */
r = pid_is_alive(pid);
if (r < 0)
return r;
if (r == 0)
return -ESRCH;
if (tid > 0 && tid != pid && !pid_is_unwaited(tid))

View File

@@ -224,11 +224,11 @@ TEST(pid_is_alive) {
} else {
int status;
waitpid(pid, &status, 0);
assert_se(!pid_is_alive(pid));
assert_se(waitpid(pid, &status, 0) == pid);
assert_se(pid_is_alive(pid) == 0);
}
assert_se(pid_is_alive(getpid_cached()));
assert_se(!pid_is_alive(-1));
assert_se(pid_is_alive(getpid_cached()) > 0);
assert_se(pid_is_alive(-1) < 0);
}
TEST(personality) {

View File

@@ -207,7 +207,7 @@ static int process_one_password_file(const char *filename) {
if (not_after > 0 && now(CLOCK_MONOTONIC) > not_after)
return 0;
if (pid > 0 && !pid_is_alive(pid))
if (pid > 0 && pid_is_alive(pid) <= 0)
return 0;
switch (arg_action) {