From 49aa47c7fb6c6cf85f2780080e89181974efdc3b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Apr 2013 14:50:05 +0200 Subject: [PATCH 1/1] util: make generation of profcs PID paths nicer --- src/shared/macro.h | 4 + src/shared/util.c | 169 ++++++++++++++++++++++--------------------- src/test/test-util.c | 46 ++++++++++++ 3 files changed, 137 insertions(+), 82 deletions(-) diff --git a/src/shared/macro.h b/src/shared/macro.h index cca41a3f6..9bf81dc3c 100644 --- a/src/shared/macro.h +++ b/src/shared/macro.h @@ -66,12 +66,16 @@ #error "Wut? Pointers are neither 4 nor 8 bytes long?" #endif +#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p)) +#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p)) #define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p)) static inline size_t ALIGN_TO(size_t l, size_t ali) { return ((l + ali - 1) & ~(ali - 1)); } +#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p)) + #define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) /* diff --git a/src/shared/util.c b/src/shared/util.c index 53caa7f9e..a55b27f87 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -80,15 +80,14 @@ char **saved_argv = NULL; static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; -#define PROCFS_PATH_LEN (sizeof("/proc/")-1 + DECIMAL_STR_MAX(pid_t)) - -#define FORMAT_PROCFS_PATH(buffer, path, pid) \ - do { \ - assert_cc(sizeof(buffer) == (PROCFS_PATH_LEN + 1 + sizeof(path))); \ - snprintf(buffer, sizeof(buffer) - 1, "/proc/%lu/%s", (unsigned long) pid, path); \ - char_array_0(buffer); \ - } while(0) - +#define procfs_file_alloca(pid, field) \ + ({ \ + pid_t _pid_ = (pid); \ + char *_r_; \ + _r_ = alloca(sizeof("/proc/") -1 + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ + sprintf(_r_, "/proc/%lu/" field, (unsigned long) _pid_); \ + _r_; \ + }) size_t page_size(void) { static __thread size_t pgsz = 0; @@ -468,15 +467,20 @@ char *split_quoted(const char *c, size_t *l, char **state) { int get_parent_of_pid(pid_t pid, pid_t *_ppid) { int r; _cleanup_fclose_ FILE *f = NULL; - char fn[sizeof("/proc/")-1 + DECIMAL_STR_MAX(pid_t) + sizeof("/stat")], line[LINE_MAX], *p; + char line[LINE_MAX]; long unsigned ppid; + const char *p; - assert(pid > 0); + assert(pid >= 0); assert(_ppid); - assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); + if (pid == 0) { + *_ppid = getppid(); + return 0; + } - f = fopen(fn, "re"); + p = procfs_file_alloca(pid, "stat"); + f = fopen(p, "re"); if (!f) return -errno; @@ -511,14 +515,18 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { int get_starttime_of_pid(pid_t pid, unsigned long long *st) { _cleanup_fclose_ FILE *f = NULL; - char fn[sizeof("/proc/")-1 + DECIMAL_STR_MAX(pid_t) + sizeof("/stat")], line[LINE_MAX], *p; + char line[LINE_MAX]; + const char *p; - assert(pid > 0); + assert(pid >= 0); assert(st); - assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); + if (pid == 0) + p = "/proc/self/stat"; + else + p = procfs_file_alloca(pid, "stat"); - f = fopen(fn, "re"); + f = fopen(p, "re"); if (!f) return -errno; @@ -585,60 +593,60 @@ char *truncate_nl(char *s) { } int get_process_comm(pid_t pid, char **name) { - int r; + const char *p; assert(name); + assert(pid >= 0); if (pid == 0) - r = read_one_line_file("/proc/self/comm", name); - else { - char path[PROCFS_PATH_LEN + sizeof("/comm")]; - FORMAT_PROCFS_PATH(path, "comm", pid); - r = read_one_line_file(path, name); - } + p = "/proc/self/comm"; + else + p = procfs_file_alloca(pid, "comm"); - return r; + return read_one_line_file(p, name); } int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { + _cleanup_fclose_ FILE *f = NULL; char *r = NULL, *k; + const char *p; int c; - FILE *f; assert(line); + assert(pid >= 0); if (pid == 0) - f = fopen("/proc/self/cmdline", "re"); - else { - char path[PROCFS_PATH_LEN + sizeof("/cmdline")]; - FORMAT_PROCFS_PATH(path, "cmdline", pid); - f = fopen(path, "re"); - } + p = "/proc/self/cmdline"; + else + p = procfs_file_alloca(pid, "cmdline"); + f = fopen(p, "re"); if (!f) return -errno; + if (max_length == 0) { - size_t len = 1; + size_t len = 0, allocated = 0; + while ((c = getc(f)) != EOF) { - k = realloc(r, len+1); - if (k == NULL) { + + if (!GREEDY_REALLOC(r, allocated, len+2)) { free(r); - fclose(f); return -ENOMEM; } - r = k; - r[len-1] = isprint(c) ? c : ' '; - r[len] = 0; - len++; + + r[len++] = isprint(c) ? c : ' '; } + + if (len > 0) + r[len-1] = 0; + } else { bool space = false; size_t left; + r = new(char, max_length); - if (!r) { - fclose(f); + if (!r) return -ENOMEM; - } k = r; left = max_length; @@ -671,8 +679,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * *k = 0; } - fclose(f); - /* Kernel threads have no argv[] */ if (r == NULL || r[0] == 0) { char *t; @@ -699,7 +705,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * } int is_kernel_thread(pid_t pid) { - char path[PROCFS_PATH_LEN + sizeof("/cmdline")]; + const char *p; size_t count; char c; bool eof; @@ -708,9 +714,10 @@ int is_kernel_thread(pid_t pid) { if (pid == 0) return 0; - FORMAT_PROCFS_PATH(path, "cmdline", pid); - f = fopen(path, "re"); + assert(pid > 0); + p = procfs_file_alloca(pid, "cmdline"); + f = fopen(p, "re"); if (!f) return -errno; @@ -726,26 +733,25 @@ int is_kernel_thread(pid_t pid) { return 0; } + int get_process_exe(pid_t pid, char **name) { - int r; + const char *p; + assert(pid >= 0); assert(name); if (pid == 0) - r = readlink_malloc("/proc/self/exe", name); - else { - char path[PROCFS_PATH_LEN + sizeof("/exe")]; - FORMAT_PROCFS_PATH(path, "exe", pid); - r = readlink_malloc(path, name); - } + p = "/proc/self/exe"; + else + p = procfs_file_alloca(pid, "exe"); - return r; + return readlink_malloc(p, name); } static int get_process_id(pid_t pid, const char *field, uid_t *uid) { _cleanup_fclose_ FILE *f = NULL; - char path[PROCFS_PATH_LEN + sizeof("/status")]; char line[LINE_MAX]; + const char *p; assert(field); assert(uid); @@ -753,8 +759,8 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { if (pid == 0) return getuid(); - FORMAT_PROCFS_PATH(path, "status", pid); - f = fopen(path, "re"); + p = procfs_file_alloca(pid, "status"); + f = fopen(p, "re"); if (!f) return -errno; @@ -781,6 +787,7 @@ int get_process_uid(pid_t pid, uid_t *uid) { } int get_process_gid(pid_t pid, gid_t *gid) { + assert_cc(sizeof(uid_t) == sizeof(gid_t)); return get_process_id(pid, "Gid:", gid); } @@ -2566,27 +2573,29 @@ int getttyname_harder(int fd, char **r) { } int get_ctty_devnr(pid_t pid, dev_t *d) { - int k; - char line[LINE_MAX], *p, *fn; + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX], *p; unsigned long ttynr; - FILE *f; + const char *fn; + int k; - if (asprintf(&fn, "/proc/%lu/stat", (unsigned long) (pid <= 0 ? getpid() : pid)) < 0) - return -ENOMEM; + assert(pid >= 0); + assert(d); + + if (pid == 0) + fn = "/proc/self/stat"; + else + fn = procfs_file_alloca(pid, "stat"); f = fopen(fn, "re"); - free(fn); if (!f) return -errno; if (!fgets(line, sizeof(line), f)) { k = feof(f) ? -EIO : -errno; - fclose(f); return k; } - fclose(f); - p = strrchr(line, ')'); if (!p) return -EIO; @@ -5031,19 +5040,21 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) { } int getenv_for_pid(pid_t pid, const char *field, char **_value) { - char path[sizeof("/proc/")-1 + DECIMAL_STR_MAX(pid_t) + sizeof("/environ")], *value = NULL; + _cleanup_fclose_ FILE *f = NULL; + char *value = NULL; int r; - FILE *f; bool done = false; size_t l; + const char *path; + assert(pid >= 0); assert(field); assert(_value); if (pid == 0) - pid = getpid(); - - snprintf(path, sizeof(path), "/proc/%lu/environ", (unsigned long) pid); + path = "/proc/self/environ"; + else + path = procfs_file_alloca(pid, "environ"); f = fopen(path, "re"); if (!f) @@ -5072,10 +5083,8 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { if (memcmp(line, field, l) == 0 && line[l] == '=') { value = strdup(line + l + 1); - if (!value) { - r = -ENOMEM; - break; - } + if (!value) + return -ENOMEM; r = 1; break; @@ -5083,11 +5092,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { } while (!done); - fclose(f); - - if (r >= 0) - *_value = value; - + *_value = value; return r; } diff --git a/src/test/test-util.c b/src/test/test-util.c index eaf7e22d0..83959c095 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -348,6 +348,51 @@ static void test_u64log2(void) { assert(u64log2(1024*1024+5) == 20); } +static void test_get_process_comm(void) { + _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL; + unsigned long long b; + pid_t e; + uid_t u; + gid_t g; + dev_t h; + int r; + + assert_se(get_process_comm(1, &a) >= 0); + log_info("pid1 comm: '%s'", a); + + assert_se(get_starttime_of_pid(1, &b) >= 0); + log_info("pid1 starttime: '%llu'", b); + + assert_se(get_process_cmdline(1, 0, true, &c) >= 0); + log_info("pid1 cmdline: '%s'", c); + + assert_se(get_process_cmdline(1, 8, false, &d) >= 0); + log_info("pid1 cmdline truncated: '%s'", d); + + assert_se(get_parent_of_pid(1, &e) >= 0); + log_info("pid1 ppid: '%llu'", (unsigned long long) e); + assert_se(e == 0); + + assert_se(is_kernel_thread(1) == 0); + + r = get_process_exe(1, &f); + assert_se(r >= 0 || r == -EACCES); + log_info("pid1 exe: '%s'", strna(f)); + + assert_se(get_process_uid(1, &u) == 0); + log_info("pid1 uid: '%llu'", (unsigned long long) u); + assert_se(u == 0); + + assert_se(get_process_gid(1, &g) == 0); + log_info("pid1 gid: '%llu'", (unsigned long long) g); + assert_se(g == 0); + + assert(get_ctty_devnr(1, &h) == -ENOENT); + + getenv_for_pid(1, "PATH", &i); + log_info("pid1 $PATH: '%s'", strna(i)); +} + int main(int argc, char *argv[]) { test_streq_ptr(); test_first_word(); @@ -374,6 +419,7 @@ int main(int argc, char *argv[]) { test_bus_path_escape(); test_hostname_is_valid(); test_u64log2(); + test_get_process_comm(); return 0; } -- 2.30.2