]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
process-util: add new pid{ref,}_get_start_time() helper
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Nov 2023 17:09:30 +0000 (18:09 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 2 Jan 2024 16:57:34 +0000 (17:57 +0100)
This also adds a test case that test pidref_safe_fork(), pidref_wait()
and related calls.

src/basic/process-util.c
src/basic/process-util.h
src/test/test-process-util.c

index 664222ec842e890a4f6f9d74e52ce9c97a6bac1a..63b2a128152f8848ea5afd068fd82486a596cc31 100644 (file)
@@ -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;
index 83ebda6faba4e0f099e4f3129028fde88d16688b..de6a2bd2038cfff6897375c48dfbbb64a1c9aa2f 100644 (file)
@@ -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);
index 957e2141ef2a7b5c5620027d9fccf020e98a6e00..027b2a401eb1d2a3dda7662938818effbfb29d09 100644 (file)
@@ -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;