X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=b33f1203e672f5c99fe6904e36d30484dc910b90;hp=f452431c6701a2ea56398de2c62116d7b513475b;hb=833fce2857bcf9cba316d3f8c37af8997b6a80ab;hpb=b89446bb33fbe6b9820efdbea62433657757a03f diff --git a/src/shared/util.c b/src/shared/util.c index f452431c6..b33f1203e 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #undef basename @@ -513,6 +514,31 @@ char *truncate_nl(char *s) { return s; } +int get_process_state(pid_t pid) { + const char *p; + char state; + int r; + _cleanup_free_ char *line = NULL; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + if (sscanf(p, " %c", &state) != 1) + return -EIO; + + return (unsigned char) state; +} + int get_process_comm(pid_t pid, char **name) { const char *p; int r; @@ -761,28 +787,31 @@ char *strappend(const char *s, const char *suffix) { return strnappend(s, suffix, suffix ? strlen(suffix) : 0); } -int readlink_malloc(const char *p, char **r) { +int readlink_malloc(const char *p, char **ret) { size_t l = 100; + int r; assert(p); - assert(r); + assert(ret); for (;;) { char *c; ssize_t n; - if (!(c = new(char, l))) + c = new(char, l); + if (!c) return -ENOMEM; - if ((n = readlink(p, c, l-1)) < 0) { - int ret = -errno; + n = readlink(p, c, l-1); + if (n < 0) { + r = -errno; free(c); - return ret; + return r; } if ((size_t) n < l-1) { c[n] = 0; - *r = c; + *ret = c; return 0; } @@ -2337,7 +2366,7 @@ void rename_process(const char name[8]) { if (!saved_argv[i]) break; - memset(saved_argv[i], 0, strlen(saved_argv[i])); + memzero(saved_argv[i], strlen(saved_argv[i])); } } } @@ -2497,9 +2526,11 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { } int get_ctty(pid_t pid, dev_t *_devnr, char **r) { - int k; - char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *s, *b, *p; + char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL; + _cleanup_free_ char *s = NULL; + const char *p; dev_t devnr; + int k; assert(r); @@ -2517,14 +2548,8 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { /* This is an ugly hack */ if (major(devnr) == 136) { - if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; + asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)); + goto finish; } /* Probably something like the ptys which have no @@ -2532,14 +2557,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { * vaguely useful. */ b = strdup(fn + 5); - if (!b) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; + goto finish; } if (startswith(s, "/dev/")) @@ -2550,8 +2568,8 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { p = s; b = strdup(p); - free(s); +finish: if (!b) return -ENOMEM; @@ -2900,24 +2918,6 @@ int status_printf(const char *status, bool ellipse, bool ephemeral, const char * return r; } -int status_welcome(void) { - _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; - int r; - - r = parse_env_file("/etc/os-release", NEWLINE, - "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color, - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/os-release: %s", strerror(-r)); - - return status_printf(NULL, false, false, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); -} - char *replace_env(const char *format, char **env) { enum { WORD, @@ -3835,12 +3835,13 @@ char* hostname_cleanup(char *s, bool lowercase) { } int pipe_eof(int fd) { - int r; struct pollfd pollfd = { .fd = fd, .events = POLLIN|POLLHUP, }; + int r; + r = poll(&pollfd, 1, 0); if (r < 0) return -errno; @@ -3892,7 +3893,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { t[k] = '.'; stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); - fd = mkostemp(t, O_WRONLY|O_CLOEXEC); + fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); if (fd < 0) { free(t); return -errno; @@ -5609,7 +5610,7 @@ static int search_and_fopen_internal(const char *path, const char *mode, char ** assert(mode); assert(_f); - if (!path_strv_canonicalize_uniq(search)) + if (!path_strv_canonicalize_absolute_uniq(search, NULL)) return -ENOMEM; STRV_FOREACH(i, search) { @@ -5791,7 +5792,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need) { return NULL; if (*allocated > prev) - memset(&q[prev], 0, *allocated - prev); + memzero(&q[prev], *allocated - prev); return q; } @@ -5837,20 +5838,6 @@ bool id128_is_valid(const char *s) { return true; } -void parse_user_at_host(char *arg, char **user, char **host) { - assert(arg); - assert(user); - assert(host); - - *host = strchr(arg, '@'); - if (*host == NULL) - *host = arg; - else { - *host[0]++ = '\0'; - *user = arg; - } -} - int split_pair(const char *s, const char *sep, char **l, char **r) { char *x, *a, *b; @@ -5905,7 +5892,7 @@ int proc_cmdline(char **ret) { int r; if (detect_container(NULL) > 0) { - char *buf, *p; + char *buf = NULL, *p; size_t sz = 0; r = read_full_file("/proc/1/cmdline", &buf, &sz); @@ -5928,6 +5915,35 @@ int proc_cmdline(char **ret) { return 1; } +int parse_proc_cmdline(int (*parse_word)(const char *word)) { + _cleanup_free_ char *line = NULL; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return 0; + + FOREACH_WORD_QUOTED(w, l, line, state) { + _cleanup_free_ char *word; + + word = strndup(w, l); + if (!word) + return log_oom(); + + r = parse_word(word); + if (r < 0) { + log_error("Failed on cmdline argument %s: %s", word, strerror(-r)); + return r; + } + } + + return 0; +} + int container_get_leader(const char *machine, pid_t *pid) { _cleanup_free_ char *s = NULL, *class = NULL; const char *p; @@ -6019,7 +6035,9 @@ int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) { return 0; } -bool pid_valid(pid_t pid) { +bool pid_is_unwaited(pid_t pid) { + /* Checks whether a PID is still valid at all, including a zombie */ + if (pid <= 0) return false; @@ -6029,6 +6047,21 @@ bool pid_valid(pid_t pid) { return errno != ESRCH; } +bool pid_is_alive(pid_t pid) { + int r; + + /* Checks whether a PID is still valid and not a zombie */ + + if (pid <= 0) + return false; + + r = get_process_state(pid); + if (r == -ENOENT || r == 'Z') + return false; + + return true; +} + int getpeercred(int fd, struct ucred *ucred) { socklen_t n = sizeof(struct ucred); struct ucred u; @@ -6092,68 +6125,108 @@ int getpeersec(int fd, char **ret) { return 0; } -int writev_safe(int fd, const struct iovec *w, int j) { - for (int i = 0; i < j; i++) { - size_t written = 0; - - while (written < w[i].iov_len) { - ssize_t r; - - r = write(fd, (char*) w[i].iov_base + written, w[i].iov_len - written); - if (r < 0 && errno != -EINTR) - return -errno; - - written += r; - } - } - - return 0; -} - +/* This is much like like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { - char *s = pattern + strlen(pattern) - 6; - uint64_t tries = TMP_MAX; - int randfd, fd, i; - - assert(streq(s, "XXXXXX")); - - randfd = open("/dev/urandom", O_RDONLY); - if (randfd < 0) - return -ENOSYS; + _cleanup_umask_ mode_t u; + int fd; - while (tries--) { - fd = read(randfd, s, 6); - if (fd == 0) - return -ENOSYS; + assert(pattern); - for (i = 0; i < 6; i++) - s[i] = ALPHANUMERICAL[(unsigned) s[i] % strlen(ALPHANUMERICAL)]; + u = umask(077); - fd = open(pattern, flags|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR); - if (fd >= 0) - return fd; - if (!IN_SET(errno, EEXIST, EINTR)) - return -errno; - } + fd = mkostemp(pattern, flags); + if (fd < 0) + return -errno; - return -EEXIST; + return fd; } int open_tmpfile(const char *path, int flags) { - int fd; char *p; + int fd; + + assert(path); #ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR); if (fd >= 0) return fd; #endif + + /* Fall back to unguessable name + unlinking */ p = strappenda(path, "/systemd-tmp-XXXXXX"); - fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(p, flags); if (fd < 0) return fd; unlink(p); return fd; } + +int fd_warn_permissions(const char *path, int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st.st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid() == 1 && (st.st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + +unsigned long personality_from_string(const char *p) { + + /* Parse a personality specifier. We introduce 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. We try to reuse the ABI identifiers + * used by libseccomp. */ + +#if defined(__x86_64__) + + if (streq(p, "x86")) + return PER_LINUX32; + + if (streq(p, "x86-64")) + return PER_LINUX; + +#elif defined(__i386__) + + if (streq(p, "x86")) + return PER_LINUX; +#endif + + /* personality(7) documents that 0xffffffffUL is used for + * querying the current personality, hence let's use that here + * as error indicator. */ + return 0xffffffffUL; +} + +const char* personality_to_string(unsigned long p) { + +#if defined(__x86_64__) + + if (p == PER_LINUX32) + return "x86"; + + if (p == PER_LINUX) + return "x86-64"; + +#elif defined(__i386__) + + if (p == PER_LINUX) + return "x86"; +#endif + + return NULL; +}