diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-11-23 18:09:30 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-01-02 17:57:34 +0100 |
commit | 3dee63b762805817fd7a1af02556e8bf44d558e1 (patch) | |
tree | f3f7cb5b5057dc45d16ececf04a6a31e0ff86dca /src | |
parent | process-util: add pidref_safe_fork() helper (diff) | |
download | systemd-3dee63b762805817fd7a1af02556e8bf44d558e1.tar.xz systemd-3dee63b762805817fd7a1af02556e8bf44d558e1.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/process-util.c | 76 | ||||
-rw-r--r-- | src/basic/process-util.h | 2 | ||||
-rw-r--r-- | src/test/test-process-util.c | 21 |
3 files changed, 99 insertions, 0 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 664222ec84..63b2a12815 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 83ebda6fab..de6a2bd203 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 957e2141ef..027b2a401e 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; |