X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=e987abc423bec6a13df0a624dedb5c7e6ec98e31;hp=ba86d206150cc92e0b43954d12dfb6d21404e1e6;hb=0c124f8b2c93d2c7d6eefca3bdc59b28250fc077;hpb=f32d2db140150b9d38684a699c9875b6e24ca27c diff --git a/src/shared/util.c b/src/shared/util.c index ba86d2061..e987abc42 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -174,6 +174,69 @@ char* first_word(const char *s, const char *word) { return (char*) p; } +static size_t cescape_char(char c, char *buf) { + char * buf_old = buf; + + switch (c) { + + case '\a': + *(buf++) = '\\'; + *(buf++) = 'a'; + break; + case '\b': + *(buf++) = '\\'; + *(buf++) = 'b'; + break; + case '\f': + *(buf++) = '\\'; + *(buf++) = 'f'; + break; + case '\n': + *(buf++) = '\\'; + *(buf++) = 'n'; + break; + case '\r': + *(buf++) = '\\'; + *(buf++) = 'r'; + break; + case '\t': + *(buf++) = '\\'; + *(buf++) = 't'; + break; + case '\v': + *(buf++) = '\\'; + *(buf++) = 'v'; + break; + case '\\': + *(buf++) = '\\'; + *(buf++) = '\\'; + break; + case '"': + *(buf++) = '\\'; + *(buf++) = '"'; + break; + case '\'': + *(buf++) = '\\'; + *(buf++) = '\''; + break; + + default: + /* For special chars we prefer octal over + * hexadecimal encoding, simply because glib's + * g_strescape() does the same */ + if ((c < ' ') || (c >= 127)) { + *(buf++) = '\\'; + *(buf++) = octchar((unsigned char) c >> 6); + *(buf++) = octchar((unsigned char) c >> 3); + *(buf++) = octchar((unsigned char) c); + } else + *(buf++) = c; + break; + } + + return buf - buf_old; +} + int close_nointr(int fd) { assert(fd >= 0); @@ -363,6 +426,46 @@ int safe_atou8(const char *s, uint8_t *ret) { return 0; } +int safe_atou16(const char *s, uint16_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long) (uint16_t) l != l) + return -ERANGE; + + *ret = (uint16_t) l; + return 0; +} + +int safe_atoi16(const char *s, int16_t *ret) { + char *x = NULL; + long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((long) (int16_t) l != l) + return -ERANGE; + + *ret = (int16_t) l; + return 0; +} + int safe_atollu(const char *s, long long unsigned *ret_llu) { char *x = NULL; unsigned long long l; @@ -757,19 +860,30 @@ int get_process_capeff(pid_t pid, char **capeff) { return get_status_field(p, "\nCapEff:", capeff); } +static int get_process_link_contents(const char *proc_file, char **name) { + int r; + + assert(proc_file); + assert(name); + + r = readlink_malloc(proc_file, name); + if (r < 0) + return r == -ENOENT ? -ESRCH : r; + + return 0; +} + int get_process_exe(pid_t pid, char **name) { const char *p; char *d; int r; assert(pid >= 0); - assert(name); p = procfs_file_alloca(pid, "exe"); - - r = readlink_malloc(p, name); + r = get_process_link_contents(p, name); if (r < 0) - return r == -ENOENT ? -ESRCH : r; + return r; d = endswith(*name, " (deleted)"); if (d) @@ -821,6 +935,59 @@ int get_process_gid(pid_t pid, gid_t *gid) { return get_process_id(pid, "Gid:", gid); } +int get_process_cwd(pid_t pid, char **cwd) { + const char *p; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "cwd"); + + return get_process_link_contents(p, cwd); +} + +int get_process_root(pid_t pid, char **root) { + const char *p; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "root"); + + return get_process_link_contents(p, root); +} + +int get_process_environ(pid_t pid, char **environ) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *outcome = NULL; + int c; + const char *p; + size_t allocated = 0, sz = 0; + + assert(pid >= 0); + assert(environ); + + p = procfs_file_alloca(pid, "environ"); + + f = fopen(p, "re"); + if (!f) + return -errno; + + while ((c = fgetc(f)) != EOF) { + if (!GREEDY_REALLOC(outcome, allocated, sz + 5)) + return -ENOMEM; + + if (c == '\0') + outcome[sz++] = '\n'; + else + sz += cescape_char(c, outcome + sz); + } + + outcome[sz] = '\0'; + *environ = outcome; + outcome = NULL; + + return 0; +} + char *strnappend(const char *s, const char *suffix, size_t b) { size_t a; char *r; @@ -893,6 +1060,28 @@ int readlink_malloc(const char *p, char **ret) { return readlinkat_malloc(AT_FDCWD, p, ret); } +int readlink_value(const char *p, char **ret) { + _cleanup_free_ char *link = NULL; + char *value; + int r; + + r = readlink_malloc(p, &link); + if (r < 0) + return r; + + value = basename(link); + if (!value) + return -ENOENT; + + value = strdup(value); + if (!value) + return -ENOMEM; + + *ret = value; + + return 0; +} + int readlink_and_make_absolute(const char *p, char **r) { _cleanup_free_ char *target = NULL; char *k; @@ -1178,63 +1367,7 @@ char *cescape(const char *s) { return NULL; for (f = s, t = r; *f; f++) - - switch (*f) { - - case '\a': - *(t++) = '\\'; - *(t++) = 'a'; - break; - case '\b': - *(t++) = '\\'; - *(t++) = 'b'; - break; - case '\f': - *(t++) = '\\'; - *(t++) = 'f'; - break; - case '\n': - *(t++) = '\\'; - *(t++) = 'n'; - break; - case '\r': - *(t++) = '\\'; - *(t++) = 'r'; - break; - case '\t': - *(t++) = '\\'; - *(t++) = 't'; - break; - case '\v': - *(t++) = '\\'; - *(t++) = 'v'; - break; - case '\\': - *(t++) = '\\'; - *(t++) = '\\'; - break; - case '"': - *(t++) = '\\'; - *(t++) = '"'; - break; - case '\'': - *(t++) = '\\'; - *(t++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((*f < ' ') || (*f >= 127)) { - *(t++) = '\\'; - *(t++) = octchar((unsigned char) *f >> 6); - *(t++) = octchar((unsigned char) *f >> 3); - *(t++) = octchar((unsigned char) *f); - } else - *(t++) = *f; - break; - } + t += cescape_char(*f, t); *t = 0; @@ -2783,7 +2916,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { if (k < 0) return k; - snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr)); + sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr)); k = readlink_malloc(fn, &s); if (k < 0) { @@ -2941,6 +3074,19 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev); } +static int file_is_priv_sticky(const char *p) { + struct stat st; + + assert(p); + + if (lstat(p, &st) < 0) + return -errno; + + return + (st.st_uid == 0 || st.st_uid == getuid()) && + (st.st_mode & S_ISVTX); +} + static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) { int fd, r; struct statfs s; @@ -3257,7 +3403,7 @@ char **replace_env_argv(char **argv, char **env) { if (e) { int r; - r = strv_split_quoted(&m, e); + r = strv_split_quoted(&m, e, true); if (r < 0) { ret[k] = NULL; strv_free(ret); @@ -3578,41 +3724,33 @@ char *unquote(const char *s, const char* quotes) { } char *normalize_env_assignment(const char *s) { - _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL; - char *eq, *r; + _cleanup_free_ char *value = NULL; + const char *eq; + char *p, *name; eq = strchr(s, '='); if (!eq) { - char *t; + char *r, *t; r = strdup(s); if (!r) return NULL; t = strstrip(r); - if (t == r) - return r; + if (t != r) + memmove(r, t, strlen(t) + 1); - memmove(r, t, strlen(t) + 1); return r; } - name = strndup(s, eq - s); - if (!name) - return NULL; - - p = strdup(eq + 1); - if (!p) - return NULL; + name = strndupa(s, eq - s); + p = strdupa(eq + 1); value = unquote(strstrip(p), QUOTES); if (!value) return NULL; - if (asprintf(&r, "%s=%s", strstrip(name), value) < 0) - r = NULL; - - return r; + return strjoin(strstrip(name), "=", value, NULL); } int wait_for_terminate(pid_t pid, siginfo_t *status) { @@ -4829,19 +4967,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) { return -ENOENT; } -int file_is_priv_sticky(const char *p) { - struct stat st; - - assert(p); - - if (lstat(p, &st) < 0) - return -errno; - - return - (st.st_uid == 0 || st.st_uid == getuid()) && - (st.st_mode & S_ISVTX); -} - static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", @@ -6397,6 +6522,10 @@ int getpeercred(int fd, struct ucred *ucred) { * to namespacing issues */ if (u.pid <= 0) return -ENODATA; + if (u.uid == (uid_t) -1) + return -ENODATA; + if (u.gid == (gid_t) -1) + return -ENODATA; *ucred = u; return 0;