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=ed850824ff4bfe049813ac462709b8aa910e556a;hp=9e7ddca91e75b355dd43feba1e711072f033440d;hb=bc983c987eb3f92eceb373ba4e1c2076b0b3ca88;hpb=1cfc78c91965df340cdde100ad6cb3ed50b28927 diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 9e7ddca91..ed850824f 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -17,22 +17,43 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include #include -#include -#include #include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include - +#include +#include +#ifdef HAVE_VALGRIND_VALGRIND_H +#include +#endif + +#include "alloc-util.h" +#include "architecture.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" -#include "util.h" +#include "fs-util.h" +//#include "ioprio.h" #include "log.h" -#include "signal-util.h" +#include "macro.h" +#include "missing.h" #include "process-util.h" +#include "signal-util.h" +//#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" int get_process_state(pid_t pid) { const char *p; @@ -43,7 +64,10 @@ int get_process_state(pid_t pid) { 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; @@ -87,8 +111,11 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } if (max_length == 0) { size_t len = 0, allocated = 0; @@ -168,6 +195,39 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return 0; } +#if 0 /// UNNEEDED by elogind +void rename_process(const char name[8]) { + assert(name); + + /* This is a like a poor man's setproctitle(). It changes the + * comm field, argv[0], and also the glibc's internally used + * name of the process. For the first one a limit of 16 chars + * applies, to the second one usually one of 10 (i.e. length + * of "/sbin/init"), to the third one one of 7 (i.e. length of + * "systemd"). If you pass a longer string it will be + * truncated */ + + prctl(PR_SET_NAME, name); + + if (program_invocation_name) + strncpy(program_invocation_name, name, strlen(program_invocation_name)); + + if (saved_argc > 0) { + int i; + + if (saved_argv[0]) + strncpy(saved_argv[0], name, strlen(saved_argv[0])); + + for (i = 1; i < saved_argc; i++) { + if (!saved_argv[i]) + break; + + memzero(saved_argv[i], strlen(saved_argv[i])); + } + } +} +#endif // 0 + int is_kernel_thread(pid_t pid) { const char *p; size_t count; @@ -175,15 +235,18 @@ int is_kernel_thread(pid_t pid) { bool eof; FILE *f; - if (pid == 0) + if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */ return 0; - assert(pid > 0); + assert(pid > 1); p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } count = fread(&c, 1, 1, f); eof = feof(f); @@ -197,17 +260,21 @@ int is_kernel_thread(pid_t pid) { return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind int get_process_capeff(pid_t pid, char **capeff) { const char *p; + int r; assert(capeff); assert(pid >= 0); p = procfs_file_alloca(pid, "status"); - return get_status_field(p, "\nCapEff:", capeff); + r = get_proc_field(p, "CapEff", WHITESPACE, capeff); + if (r == -ENOENT) + return -ESRCH; + + return r; } #endif // 0 @@ -218,8 +285,10 @@ static int get_process_link_contents(const char *proc_file, char **name) { assert(name); r = readlink_malloc(proc_file, name); + if (r == -ENOENT) + return -ESRCH; if (r < 0) - return r == -ENOENT ? -ESRCH : r; + return r; return 0; } @@ -243,6 +312,7 @@ int get_process_exe(pid_t pid, char **name) { return 0; } +#if 0 /// UNNEEDED by elogind static int get_process_id(pid_t pid, const char *field, uid_t *uid) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; @@ -256,8 +326,11 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } FOREACH_LINE(line, f, return -errno) { char *l; @@ -281,8 +354,6 @@ int get_process_uid(pid_t pid, uid_t *uid) { return get_process_id(pid, "Uid:", uid); } -/// UNNEEDED by elogind -#if 0 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); @@ -321,8 +392,11 @@ int get_process_environ(pid_t pid, char **env) { p = procfs_file_alloca(pid, "environ"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } while ((c = fgetc(f)) != EOF) { if (!GREEDY_REALLOC(outcome, allocated, sz + 5)) @@ -334,15 +408,20 @@ int get_process_environ(pid_t pid, char **env) { sz += cescape_char(c, outcome + sz); } + if (!outcome) { + outcome = strdup(""); + if (!outcome) + return -ENOMEM; + } else outcome[sz] = '\0'; + *env = outcome; outcome = NULL; return 0; } -#endif // 0 -int get_parent_of_pid(pid_t pid, pid_t *_ppid) { +int get_process_ppid(pid_t pid, pid_t *_ppid) { int r; _cleanup_free_ char *line = NULL; long unsigned ppid; @@ -358,6 +437,8 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { p = procfs_file_alloca(pid, "stat"); r = read_one_line_file(p, &line); + if (r == -ENOENT) + return -ESRCH; if (r < 0) return r; @@ -384,6 +465,7 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { return 0; } +#endif // 0 int wait_for_terminate(pid_t pid, siginfo_t *status) { siginfo_t dummy; @@ -452,6 +534,17 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod return -EPROTO; } +void sigkill_wait(pid_t *pid) { + if (!pid) + return; + if (*pid <= 1) + return; + + if (kill(*pid, SIGKILL) > 0) + (void) wait_for_terminate(*pid, NULL); +} + +#if 0 /// UNNEEDED by elogind int kill_and_sigcont(pid_t pid, int sig) { int r; @@ -462,6 +555,7 @@ int kill_and_sigcont(pid_t pid, int sig) { return r; } +#endif // 0 int getenv_for_pid(pid_t pid, const char *field, char **_value) { _cleanup_fclose_ FILE *f = NULL; @@ -478,8 +572,11 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { path = procfs_file_alloca(pid, "environ"); f = fopen(path, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } l = strlen(field); r = 0; @@ -520,9 +617,12 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { bool pid_is_unwaited(pid_t pid) { /* Checks whether a PID is still valid at all, including a zombie */ - if (pid <= 0) + if (pid < 0) return false; + if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */ + return true; + if (kill(pid, 0) >= 0) return true; @@ -534,12 +634,141 @@ bool pid_is_alive(pid_t pid) { /* Checks whether a PID is still valid and not a zombie */ - if (pid <= 0) + if (pid < 0) return false; + if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */ + return true; + r = get_process_state(pid); - if (r == -ENOENT || r == 'Z') + if (r == -ESRCH || r == 'Z') return false; return true; } + +#if 0 /// UNNEEDED by elogind +int pid_from_same_root_fs(pid_t pid) { + const char *root; + + if (pid < 0) + return 0; + + root = procfs_file_alloca(pid, "root"); + + return files_same(root, "/proc/1/root"); +} +#endif // 0 + +bool is_main_thread(void) { + static thread_local int cached = 0; + + if (_unlikely_(cached == 0)) + cached = getpid() == gettid() ? 1 : -1; + + return cached > 0; +} + +#if 0 /// UNNEEDED by elogind +noreturn void freeze(void) { + + /* Make sure nobody waits for us on a socket anymore */ + close_all_fds(NULL, 0); + + sync(); + + for (;;) + pause(); +} + +bool oom_score_adjust_is_valid(int oa) { + return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX; +} + +unsigned long personality_from_string(const char *p) { + int architecture; + + if (!p) + return PERSONALITY_INVALID; + + /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for + * the same register size. */ + + architecture = architecture_from_string(p); + if (architecture < 0) + return PERSONALITY_INVALID; + + if (architecture == native_architecture()) + return PER_LINUX; +#ifdef SECONDARY_ARCHITECTURE + if (architecture == SECONDARY_ARCHITECTURE) + return PER_LINUX32; +#endif + + return PERSONALITY_INVALID; +} + +const char* personality_to_string(unsigned long p) { + int architecture = _ARCHITECTURE_INVALID; + + if (p == PER_LINUX) + architecture = native_architecture(); +#ifdef SECONDARY_ARCHITECTURE + else if (p == PER_LINUX32) + architecture = SECONDARY_ARCHITECTURE; +#endif + + if (architecture < 0) + return NULL; + + return architecture_to_string(architecture); +} + +void valgrind_summary_hack(void) { +#ifdef HAVE_VALGRIND_VALGRIND_H + if (getpid() == 1 && RUNNING_ON_VALGRIND) { + pid_t pid; + pid = raw_clone(SIGCHLD, NULL); + if (pid < 0) + log_emergency_errno(errno, "Failed to fork off valgrind helper: %m"); + else if (pid == 0) + exit(EXIT_SUCCESS); + else { + log_info("Spawned valgrind helper as PID "PID_FMT".", pid); + (void) wait_for_terminate(pid, NULL); + } + } +#endif +} + +static const char *const ioprio_class_table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); + +static const char *const sigchld_code_table[] = { + [CLD_EXITED] = "exited", + [CLD_KILLED] = "killed", + [CLD_DUMPED] = "dumped", + [CLD_TRAPPED] = "trapped", + [CLD_STOPPED] = "stopped", + [CLD_CONTINUED] = "continued", +}; + +DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); + +static const char* const sched_policy_table[] = { + [SCHED_OTHER] = "other", + [SCHED_BATCH] = "batch", + [SCHED_IDLE] = "idle", + [SCHED_FIFO] = "fifo", + [SCHED_RR] = "rr" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); +#endif // 0