X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=f7335cf279770bbc0d8f243b06205d1d53c23b33;hp=97c9497df671f3f87b3312473baa7369ad192d82;hb=ec202eae8e84a4c99f054f771cb832046cb8769f;hpb=28383ba18963cdedd98ced271b3425f7321119b7 diff --git a/src/shared/util.c b/src/shared/util.c index 97c9497df..f7335cf27 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -59,6 +59,7 @@ #include #include #include +#undef basename #include "macro.h" #include "util.h" @@ -85,7 +86,7 @@ static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; size_t page_size(void) { - static __thread size_t pgsz = 0; + static thread_local size_t pgsz = 0; long r; if (_likely_(pgsz > 0)) @@ -373,17 +374,21 @@ char *split(const char *c, size_t *l, const char *separator, char **state) { /* Split a string into words, but consider strings enclosed in '' and * "" as words even if they include spaces. */ char *split_quoted(const char *c, size_t *l, char **state) { - char *current, *e; + const char *current, *e; bool escaped = false; - current = *state ? *state : (char*) c; + assert(c); + assert(l); + assert(state); - if (!*current || *c == 0) - return NULL; + current = *state ? *state : c; current += strspn(current, WHITESPACE); - if (*current == '\'') { + if (*current == 0) + return NULL; + + else if (*current == '\'') { current ++; for (e = current; *e; e++) { @@ -396,7 +401,8 @@ char *split_quoted(const char *c, size_t *l, char **state) { } *l = e-current; - *state = *e == 0 ? e : e+1; + *state = (char*) (*e == 0 ? e : e+1); + } else if (*current == '\"') { current ++; @@ -410,7 +416,8 @@ char *split_quoted(const char *c, size_t *l, char **state) { } *l = e-current; - *state = *e == 0 ? e : e+1; + *state = (char*) (*e == 0 ? e : e+1); + } else { for (e = current; *e; e++) { if (escaped) @@ -421,7 +428,7 @@ char *split_quoted(const char *c, size_t *l, char **state) { break; } *l = e-current; - *state = e; + *state = (char*) e; } return (char*) current; @@ -491,7 +498,7 @@ int get_starttime_of_pid(pid_t pid, unsigned long long *st) { f = fopen(p, "re"); if (!f) - return -errno; + return errno == ENOENT ? -ESRCH : -errno; if (!fgets(line, sizeof(line), f)) { if (ferror(f)) @@ -557,6 +564,7 @@ char *truncate_nl(char *s) { int get_process_comm(pid_t pid, char **name) { const char *p; + int r; assert(name); assert(pid >= 0); @@ -566,7 +574,11 @@ int get_process_comm(pid_t pid, char **name) { else p = procfs_file_alloca(pid, "comm"); - return read_one_line_file(p, name); + r = read_one_line_file(p, name); + if (r == -ENOENT) + return -ESRCH; + + return r; } int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { @@ -723,7 +735,7 @@ int get_process_exe(pid_t pid, char **name) { r = readlink_malloc(p, name); if (r < 0) - return r; + return r == -ENOENT ? -ESRCH : r; d = endswith(*name, " (deleted)"); if (d) @@ -2490,7 +2502,7 @@ int getttyname_malloc(int fd, char **r) { assert(r); k = ttyname_r(fd, path, sizeof(path)); - if (k != 0) + if (k > 0) return -k; char_array_0(path); @@ -2525,10 +2537,8 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { char line[LINE_MAX], *p; unsigned long ttynr; const char *fn; - int k; assert(pid >= 0); - assert(d); if (pid == 0) fn = "/proc/self/stat"; @@ -2539,10 +2549,8 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { if (!f) return -errno; - if (!fgets(line, sizeof(line), f)) { - k = feof(f) ? -EIO : -errno; - return k; - } + if (!fgets(line, sizeof(line), f)) + return feof(f) ? -EIO : -errno; p = strrchr(line, ')'); if (!p) @@ -2562,7 +2570,9 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { if (major(ttynr) == 0 && minor(ttynr) == 0) return -ENOENT; - *d = (dev_t) ttynr; + if (d) + *d = (dev_t) ttynr; + return 0; } @@ -3952,8 +3962,8 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { if (!t) return -ENOMEM; - fn = path_get_file_name(path); - k = fn-path; + fn = basename(path); + k = fn - path; memcpy(t, path, k); t[k] = '.'; stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); @@ -4138,7 +4148,7 @@ int symlink_atomic(const char *from, const char *to) { if (!t) return -ENOMEM; - fn = path_get_file_name(to); + fn = basename(to); k = fn-to; memcpy(t, to, k); t[k] = '.'; @@ -4570,7 +4580,7 @@ char *strjoin(const char *x, ...) { } bool is_main_thread(void) { - static __thread int cached = 0; + static thread_local int cached = 0; if (_unlikely_(cached == 0)) cached = getpid() == gettid() ? 1 : -1; @@ -4788,7 +4798,7 @@ static const char *const __signal_table[] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); const char *signal_to_string(int signo) { - static __thread char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; + static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; const char *name; name = __signal_to_string(signo); @@ -4926,15 +4936,15 @@ int fd_inc_sndbuf(int fd, size_t n) { socklen_t l = sizeof(value); r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && - l == sizeof(value) && - (size_t) value >= n*2) + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) return 0; + /* If we have the privileges we will ignore the kernel limit. */ + value = (int) n; - r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)); - if (r < 0) - return -errno; + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) + return -errno; return 1; } @@ -4944,16 +4954,15 @@ int fd_inc_rcvbuf(int fd, size_t n) { socklen_t l = sizeof(value); r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && - l == sizeof(value) && - (size_t) value >= n*2) + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) return 0; - value = (int) n; - r = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)); - if (r < 0) - return -errno; + /* If we have the privileges we will ignore the kernel limit. */ + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) + return -errno; return 1; } @@ -5210,10 +5219,10 @@ int make_console_stdio(void) { } int get_home_dir(char **_h) { - char *h; + struct passwd *p; const char *e; + char *h; uid_t u; - struct passwd *p; assert(_h); @@ -5256,6 +5265,53 @@ int get_home_dir(char **_h) { return 0; } +int get_shell(char **_s) { + struct passwd *p; + const char *e; + char *s; + uid_t u; + + assert(_s); + + /* Take the user specified one */ + e = getenv("SHELL"); + if (e) { + s = strdup(e); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + s = strdup("/bin/sh"); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_shell)) + return -EINVAL; + + s = strdup(p->pw_shell); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; +} + bool filename_is_safe(const char *p) { if (isempty(p)) @@ -5370,7 +5426,7 @@ bool is_locale_utf8(void) { goto out; } - if(streq(set, "UTF-8")) { + if (streq(set, "UTF-8")) { cached_answer = true; goto out; } @@ -5707,56 +5763,6 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *sear return search_and_fopen_internal(path, mode, s, _f); } -int create_tmp_dir(char template[], char** dir_name) { - int r = 0; - char *d = NULL, *dt; - - assert(dir_name); - - RUN_WITH_UMASK(0077) { - d = mkdtemp(template); - } - if (!d) { - log_error("Can't create directory %s: %m", template); - return -errno; - } - - dt = strjoin(d, "/tmp", NULL); - if (!dt) { - r = log_oom(); - goto fail3; - } - - RUN_WITH_UMASK(0000) { - r = mkdir(dt, 0777); - } - if (r < 0) { - log_error("Can't create directory %s: %m", dt); - r = -errno; - goto fail2; - } - log_debug("Created temporary directory %s", dt); - - r = chmod(dt, 0777 | S_ISVTX); - if (r < 0) { - log_error("Failed to chmod %s: %m", dt); - r = -errno; - goto fail1; - } - log_debug("Set sticky bit on %s", dt); - - *dir_name = dt; - - return 0; -fail1: - rmdir(dt); -fail2: - free(dt); -fail3: - rmdir(template); - return r; -} - char *strextend(char **x, ...) { va_list ap; size_t f, l; @@ -5832,10 +5838,18 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need) { size_t a; void *q; + assert(p); + assert(allocated); + if (*allocated >= need) return *p; a = MAX(64u, need * 2); + + /* check for overflows */ + if (a < need) + return NULL; + q = realloc(*p, a); if (!q) return NULL; @@ -5845,6 +5859,25 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need) { return q; } +void* greedy_realloc0(void **p, size_t *allocated, size_t need) { + size_t prev; + uint8_t *q; + + assert(p); + assert(allocated); + + prev = *allocated; + + q = greedy_realloc(p, allocated, need); + if (!q) + return NULL; + + if (*allocated > prev) + memset(&q[prev], 0, *allocated - prev); + + return q; +} + bool id128_is_valid(const char *s) { size_t i, l; @@ -5944,7 +5977,7 @@ int shall_restore_state(void) { return 1; FOREACH_WORD_QUOTED(w, l, line, state) - if (l == 23 && memcmp(w, "systemd.restore_state=0", 23)) + if (l == 23 && strneq(w, "systemd.restore_state=0", 23)) return 0; return 1; @@ -5964,3 +5997,94 @@ int proc_cmdline(char **ret) { return 1; } + +int container_get_leader(const char *machine, pid_t *pid) { + _cleanup_free_ char *s = NULL, *class = NULL; + const char *p; + pid_t leader; + int r; + + assert(machine); + assert(pid); + + p = strappenda("/run/systemd/machines/", machine); + r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); + if (r == -ENOENT) + return -EHOSTDOWN; + if (r < 0) + return r; + if (!s) + return -EIO; + + if (!streq_ptr(class, "container")) + return -EIO; + + r = parse_pid(s, &leader); + if (r < 0) + return r; + if (leader <= 1) + return -EIO; + + *pid = leader; + return 0; +} + +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1; + const char *pidns, *mntns, *root; + int rfd; + + assert(pid >= 0); + assert(pidns_fd); + assert(mntns_fd); + assert(root_fd); + + mntns = procfs_file_alloca(pid, "ns/mnt"); + mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (mntnsfd < 0) + return -errno; + + pidns = procfs_file_alloca(pid, "ns/pid"); + pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (pidnsfd < 0) + return -errno; + + root = procfs_file_alloca(pid, "root"); + rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (rfd < 0) + return -errno; + + *pidns_fd = pidnsfd; + *mntns_fd = mntnsfd; + *root_fd = rfd; + pidnsfd = -1; + mntnsfd = -1; + + return 0; +} + +int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) { + assert(pidns_fd >= 0); + assert(mntns_fd >= 0); + assert(root_fd >= 0); + + if (setns(pidns_fd, CLONE_NEWPID) < 0) + return -errno; + + if (setns(mntns_fd, CLONE_NEWNS) < 0) + return -errno; + + if (fchdir(root_fd) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (setresgid(0, 0, 0) < 0) + return -errno; + + if (setresuid(0, 0, 0) < 0) + return -errno; + + return 0; +}