From: Lennart Poettering Date: Thu, 23 Nov 2023 17:09:30 +0000 (+0100) Subject: process-util: add new pid{ref,}_get_start_time() helper X-Git-Tag: v256-rc1~1307^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3dee63b762805817fd7a1af02556e8bf44d558e1;p=thirdparty%2Fsystemd.git process-util: add new pid{ref,}_get_start_time() helper This also adds a test case that test pidref_safe_fork(), pidref_wait() and related calls. --- diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 664222ec842..63b2a128152 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -730,6 +730,82 @@ int get_process_ppid(pid_t pid, pid_t *ret) { return 0; } +int pid_get_start_time(pid_t pid, uint64_t *ret) { + _cleanup_free_ char *line = NULL; + const char *p; + int r; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r == -ENOENT) + return -ESRCH; + if (r < 0) + return r; + + /* Let's skip the pid and comm fields. The latter is enclosed in () but does not escape any () in its + * value, so let's skip over it manually */ + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + unsigned long llu; + + if (sscanf(p, " " + "%*c " /* state */ + "%*u " /* ppid */ + "%*u " /* pgrp */ + "%*u " /* session */ + "%*u " /* tty_nr */ + "%*u " /* tpgid */ + "%*u " /* flags */ + "%*u " /* minflt */ + "%*u " /* cminflt */ + "%*u " /* majflt */ + "%*u " /* cmajflt */ + "%*u " /* utime */ + "%*u " /* stime */ + "%*u " /* cutime */ + "%*u " /* cstime */ + "%*i " /* priority */ + "%*i " /* nice */ + "%*u " /* num_threads */ + "%*u " /* itrealvalue */ + "%lu ", /* starttime */ + &llu) != 1) + return -EIO; + + if (ret) + *ret = llu; + + return 0; +} + +int pidref_get_start_time(const PidRef *pid, uint64_t *ret) { + uint64_t t; + int r; + + if (!pidref_is_set(pid)) + return -ESRCH; + + r = pid_get_start_time(pid->pid, ret ? &t : NULL); + if (r < 0) + return r; + + r = pidref_verify(pid); + if (r < 0) + return r; + + if (ret) + *ret = t; + + return 0; +} + int get_process_umask(pid_t pid, mode_t *ret) { _cleanup_free_ char *m = NULL; const char *p; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 83ebda6faba..de6a2bd2038 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -54,6 +54,8 @@ int get_process_cwd(pid_t pid, char **ret); int get_process_root(pid_t pid, char **ret); int get_process_environ(pid_t pid, char **ret); int get_process_ppid(pid_t pid, pid_t *ret); +int pid_get_start_time(pid_t pid, uint64_t *ret); +int pidref_get_start_time(const PidRef* pid, uint64_t *ret); int get_process_umask(pid_t pid, mode_t *ret); int container_get_leader(const char *machine, pid_t *pid); diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 957e2141ef2..027b2a401eb 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -946,6 +946,27 @@ TEST(is_reaper_process) { } } +TEST(pid_get_start_time) { + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + + assert_se(pidref_set_self(&pidref) >= 0); + + uint64_t start_time; + assert_se(pidref_get_start_time(&pidref, &start_time) >= 0); + log_info("our starttime: %" PRIu64, start_time); + + _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL; + + assert_se(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &child) >= 0); + + uint64_t start_time2; + assert_se(pidref_get_start_time(&child, &start_time2) >= 0); + + log_info("child starttime: %" PRIu64, start_time2); + + assert_se(start_time2 >= start_time); +} + static int intro(void) { log_show_color(true); return EXIT_SUCCESS;