#include "helpfun.h" unsigned long run_in_host = 0; enum { RUN_IN_HOST = 0, RUN_IN_CONTAINER }; int is_pid_1_has_environ(const char *field) { bool done = false; FILE *f = NULL; int r = 0; size_t l; assert(field); f = fopen("/proc/1/environ", "re"); if (!f) return 0; (void)__fsetlocking(f, FSETLOCKING_BYCALLER); l = strlen(field); do { char line[BUF_LEN]; size_t i; for (i = 0; i < sizeof(line) - 1; i++) { int c; c = getc(f); if ((c == EOF)) { done = true; break; } else if (c == 0) break; line[i] = c; } line[i] = 0; if (strneq(line, field, l) && line[l] == '=') { r = 1; goto out; } } while (!done); out: fclose(f); return r; } int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { char status[BUF_LEN] = {0}; char *t, *f; size_t len; int r; assert(terminator); assert(filename); assert(pattern); assert(field); int fd = open(filename, O_RDONLY); if (fd < 0) return -errno; r = read(fd, &status, BUF_LEN - 1); if (r < 0) return r; t = status; do { bool pattern_ok; do { t = strstr(t, pattern); if (!t) return -ENOENT; /* Check that pattern occurs in beginning of line. */ pattern_ok = (t == status || t[-1] == '\n'); t += strlen(pattern); } while (!pattern_ok); t += strspn(t, " \t"); if (!*t) return -ENOENT; } while (*t != ':'); t++; if (*t) { t += strspn(t, " \t"); /* Also skip zeros, because when this is used for * capabilities, we don't want the zeros. This way the * same capability set always maps to the same string, * irrespective of the total capability set size. For * other numbers it shouldn't matter. */ t += strspn(t, "0"); /* Back off one char if there's nothing but whitespace and zeros */ if (!*t || isspace(*t)) t--; } len = strcspn(t, terminator); f = strndup(t, len); if (!f) return -ENOMEM; *field = f; return 0; } static int detect_container_by_pid_2(void) { char *s = NULL; int r; r = get_proc_field("/proc/2/status", "PPid", WHITESPACE, &s); if (r >= 0) { if (streq(s, "0")) r = RUN_IN_HOST; else r = RUN_IN_CONTAINER; } else if (r == -ENOENT) r = RUN_IN_CONTAINER; else { printf("Failed to read /proc/2/status: %d\n", r); r = RUN_IN_HOST; } free(s); return r; } int check_in_host(void) { int r; if (is_pid_1_has_environ("container")) r = RUN_IN_CONTAINER; else r = detect_container_by_pid_2(); return r == RUN_IN_HOST; } static const char *user_mode_str(int user_mode) { switch (user_mode) { case 1: return "USER MODE"; case 0: return "SYSTEM MODE"; default: return "UNKNOWN MODE"; } } std::string state_str(int __state) { std::vector states; if (__state == TASK_RUNNING) states.push_back("TASK_RUNNING"); // if (__state & TASK_RUNNING) states.push_back("TASK_RUNNING"); if (__state & TASK_INTERRUPTIBLE) states.push_back("TASK_INTERRUPTIBLE"); if (__state & TASK_UNINTERRUPTIBLE) states.push_back("TASK_UNINTERRUPTIBLE"); if (__state & __TASK_STOPPED) states.push_back("__TASK_STOPPED"); if (__state & __TASK_TRACED) states.push_back("__TASK_TRACED"); if (__state & TASK_PARKED) states.push_back("TASK_PARKED"); if (__state & TASK_DEAD) states.push_back("TASK_DEAD"); if (__state == TASK_KILLABLE) states.push_back("TASK_KILLABLE"); if (__state == TASK_STOPPED) states.push_back("TASK_STOPPED"); if (__state == TASK_IDLE) states.push_back("TASK_IDLE"); std::string result; for (const auto &state : states) { if (!result.empty()) result += " | "; result += state; } return result; }