X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbasic%2Fprocess-util.c;h=09bc12a80afb75346fd8f10df6cb831aa95e437c;hp=bcc5a45d8ebc633e46c6f149bd10fa8018561d16;hb=4a7059686430f596810f0c83e4897154828fd352;hpb=ab6b3ad1c10768be64343940878617b1ae438c43 diff --git a/src/basic/process-util.c b/src/basic/process-util.c index bcc5a45d8..09bc12a80 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -109,6 +109,15 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * assert(line); assert(pid >= 0); + /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing + * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most + * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If + * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a + * command line that resolves to the empty string will return the "comm" name of the process instead. + * + * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and + * comm_fallback is false). */ + p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); @@ -118,12 +127,22 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -errno; } - if (max_length == 0) { + if (max_length == 1) { + + /* If there's only room for one byte, return the empty string */ + r = new0(char, 1); + if (!r) + return -ENOMEM; + + *line = r; + return 0; + + } else if (max_length == 0) { size_t len = 0, allocated = 0; while ((c = getc(f)) != EOF) { - if (!GREEDY_REALLOC(r, allocated, len+2)) { + if (!GREEDY_REALLOC(r, allocated, len+3)) { free(r); return -ENOMEM; } @@ -135,14 +154,17 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * } r[len++] = c; - } else + } else if (len > 0) space = true; } if (len > 0) r[len] = 0; + else + r = mfree(r); } else { + bool dotdotdot = false; size_t left; r = new(char, max_length); @@ -154,28 +176,46 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * while ((c = getc(f)) != EOF) { if (isprint(c)) { + if (space) { - if (left <= 4) + if (left <= 2) { + dotdotdot = true; break; + } *(k++) = ' '; left--; space = false; } - if (left <= 4) + if (left <= 1) { + dotdotdot = true; break; + } *(k++) = (char) c; left--; - } else + } else if (k > r) space = true; } - if (left <= 4) { - size_t n = MIN(left-1, 3U); - memcpy(k, "...", n); - k[n] = 0; + if (dotdotdot) { + if (max_length <= 4) { + k = r; + left = max_length; + } else { + k = r + max_length - 4; + left = 4; + + /* Eat up final spaces */ + while (k > r && isspace(k[-1])) { + k--; + left++; + } + } + + strncpy(k, "...", left-1); + k[left-1] = 0; } else *k = 0; } @@ -194,7 +234,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (h < 0) return h; - r = strjoin("[", t, "]", NULL); + if (max_length == 0) + r = strjoin("[", t, "]"); + else { + size_t l; + + l = strlen(t); + + if (l + 3 <= max_length) + r = strjoin("[", t, "]"); + else if (max_length <= 6) { + + r = new(char, max_length); + if (!r) + return -ENOMEM; + + memcpy(r, "[...]", max_length-1); + r[max_length-1] = 0; + } else { + char *e; + + t[max_length - 6] = 0; + + /* Chop off final spaces */ + e = strchr(t, 0); + while (e > t && isspace(e[-1])) + e--; + *e = 0; + + r = strjoin("[", t, "...]"); + } + } if (!r) return -ENOMEM; } @@ -488,7 +558,7 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) { if (errno == EINTR) continue; - return -errno; + return negative_errno(); } return 0; @@ -561,8 +631,10 @@ int kill_and_sigcont(pid_t pid, int sig) { r = kill(pid, sig) < 0 ? -errno : 0; - if (r >= 0) - kill(pid, SIGCONT); + /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't + * affected by a process being suspended anyway. */ + if (r >= 0 && !IN_SET(SIGCONT, SIGKILL)) + (void) kill(pid, SIGCONT); return r; } @@ -610,7 +682,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { } line[i] = 0; - if (memcmp(line, field, l) == 0 && line[l] == '=') { + if (strneq(line, field, l) && line[l] == '=') { value = strdup(line + l + 1); if (!value) return -ENOMEM; @@ -742,7 +814,7 @@ void valgrind_summary_hack(void) { #ifdef HAVE_VALGRIND_VALGRIND_H if (getpid() == 1 && RUNNING_ON_VALGRIND) { pid_t pid; - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Failed to fork off valgrind helper: %m"); else if (pid == 0)