summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-11-23 18:09:30 +0100
committerLennart Poettering <lennart@poettering.net>2024-01-02 17:57:34 +0100
commit3dee63b762805817fd7a1af02556e8bf44d558e1 (patch)
treef3f7cb5b5057dc45d16ececf04a6a31e0ff86dca /src
parentprocess-util: add pidref_safe_fork() helper (diff)
downloadsystemd-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.c76
-rw-r--r--src/basic/process-util.h2
-rw-r--r--src/test/test-process-util.c21
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;