chiark / gitweb /
util: simplify get_ctty()
[elogind.git] / src / shared / util.c
index 20aec2a5c9cafa236b76806dd21b84b934a11ee6..b33f1203e672f5c99fe6904e36d30484dc910b90 100644 (file)
 #include <limits.h>
 #include <langinfo.h>
 #include <locale.h>
+#include <sys/personality.h>
 #include <libgen.h>
 #undef basename
 
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
 #include "macro.h"
 #include "util.h"
 #include "ioprio.h"
@@ -86,7 +91,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))
@@ -355,8 +360,23 @@ int safe_atod(const char *s, double *ret_d) {
         return 0;
 }
 
+static size_t strcspn_escaped(const char *s, const char *reject) {
+        bool escaped = false;
+        size_t n;
+
+        for (n=0; s[n]; n++) {
+                if (escaped)
+                        escaped = false;
+                else if (s[n] == '\\')
+                        escaped = true;
+                else if (strchr(reject, s[n]))
+                        return n;
+        }
+        return n;
+}
+
 /* Split a string into words. */
-char *split(const char *c, size_t *l, const char *separator, char **state) {
+char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state) {
         char *current;
 
         current = *state ? *state : (char*) c;
@@ -365,70 +385,19 @@ char *split(const char *c, size_t *l, const char *separator, char **state) {
                 return NULL;
 
         current += strspn(current, separator);
-        *l = strcspn(current, separator);
-        *state = current+*l;
-
-        return (char*) current;
-}
-
-/* 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) {
-        const char *current, *e;
-        bool escaped = false;
-
-        assert(c);
-        assert(l);
-        assert(state);
-
-        current = *state ? *state : c;
-
-        current += strspn(current, WHITESPACE);
-
-        if (*current == 0)
+        if (!*current)
                 return NULL;
 
-        else if (*current == '\'') {
-                current ++;
-
-                for (e = current; *e; e++) {
-                        if (escaped)
-                                escaped = false;
-                        else if (*e == '\\')
-                                escaped = true;
-                        else if (*e == '\'')
-                                break;
-                }
-
-                *l = e-current;
-                *state = (char*) (*e == 0 ? e : e+1);
-
-        } else if (*current == '\"') {
-                current ++;
-
-                for (e = current; *e; e++) {
-                        if (escaped)
-                                escaped = false;
-                        else if (*e == '\\')
-                                escaped = true;
-                        else if (*e == '\"')
-                                break;
-                }
-
-                *l = e-current;
-                *state = (char*) (*e == 0 ? e : e+1);
-
+        if (quoted && strchr("\'\"", *current)) {
+                char quotechar = *(current++);
+                *l = strcspn_escaped(current, (char[]){quotechar, '\0'});
+                *state = current+*l+1;
+        } else if (quoted) {
+                *l = strcspn_escaped(current, separator);
+                *state = current+*l;
         } else {
-                for (e = current; *e; e++) {
-                        if (escaped)
-                                escaped = false;
-                        else if (*e == '\\')
-                                escaped = true;
-                        else if (strchr(WHITESPACE, *e))
-                                break;
-                }
-                *l = e-current;
-                *state = (char*) e;
+                *l = strcspn(current, separator);
+                *state = current+*l;
         }
 
         return (char*) current;
@@ -436,8 +405,7 @@ char *split_quoted(const char *c, size_t *l, char **state) {
 
 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
         int r;
-        _cleanup_fclose_ FILE *f = NULL;
-        char line[LINE_MAX];
+        _cleanup_free_ char *line = NULL;
         long unsigned ppid;
         const char *p;
 
@@ -450,14 +418,9 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
         }
 
         p = procfs_file_alloca(pid, "stat");
-        f = fopen(p, "re");
-        if (!f)
-                return -errno;
-
-        if (!fgets(line, sizeof(line), f)) {
-                r = feof(f) ? -EIO : -errno;
+        r = read_one_line_file(p, &line);
+        if (r < 0)
                 return r;
-        }
 
         /* Let's skip the pid and comm fields. The latter is enclosed
          * in () but does not escape any () in its value, so let's
@@ -484,28 +447,17 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
 }
 
 int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
-        _cleanup_fclose_ FILE *f = NULL;
-        char line[LINE_MAX];
+        int r;
+        _cleanup_free_ char *line = NULL;
         const char *p;
 
         assert(pid >= 0);
         assert(st);
 
-        if (pid == 0)
-                p = "/proc/self/stat";
-        else
-                p = procfs_file_alloca(pid, "stat");
-
-        f = fopen(p, "re");
-        if (!f)
-                return errno == ENOENT ? -ESRCH : -errno;
-
-        if (!fgets(line, sizeof(line), f)) {
-                if (ferror(f))
-                        return -errno;
-
-                return -EIO;
-        }
+        p = procfs_file_alloca(pid, "stat");
+        r = read_one_line_file(p, &line);
+        if (r < 0)
+                return r;
 
         /* Let's skip the pid and comm fields. The latter is enclosed
          * in () but does not escape any () in its value, so let's
@@ -562,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;
@@ -569,10 +546,7 @@ int get_process_comm(pid_t pid, char **name) {
         assert(name);
         assert(pid >= 0);
 
-        if (pid == 0)
-                p = "/proc/self/comm";
-        else
-                p = procfs_file_alloca(pid, "comm");
+        p = procfs_file_alloca(pid, "comm");
 
         r = read_one_line_file(p, name);
         if (r == -ENOENT)
@@ -590,10 +564,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
         assert(line);
         assert(pid >= 0);
 
-        if (pid == 0)
-                p = "/proc/self/cmdline";
-        else
-                p = procfs_file_alloca(pid, "cmdline");
+        p = procfs_file_alloca(pid, "cmdline");
 
         f = fopen(p, "re");
         if (!f)
@@ -712,10 +683,7 @@ int get_process_capeff(pid_t pid, char **capeff) {
         assert(capeff);
         assert(pid >= 0);
 
-        if (pid == 0)
-                p = "/proc/self/status";
-        else
-                p = procfs_file_alloca(pid, "status");
+        p = procfs_file_alloca(pid, "status");
 
         return get_status_field(p, "\nCapEff:", capeff);
 }
@@ -728,10 +696,7 @@ int get_process_exe(pid_t pid, char **name) {
         assert(pid >= 0);
         assert(name);
 
-        if (pid == 0)
-                p = "/proc/self/exe";
-        else
-                p = procfs_file_alloca(pid, "exe");
+        p = procfs_file_alloca(pid, "exe");
 
         r = readlink_malloc(p, name);
         if (r < 0)
@@ -822,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;
                 }
 
@@ -2098,45 +2066,31 @@ int close_pipe(int p[]) {
 }
 
 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
-        uint8_t *p;
+        uint8_t *p = buf;
         ssize_t n = 0;
 
         assert(fd >= 0);
         assert(buf);
 
-        p = buf;
-
         while (nbytes > 0) {
                 ssize_t k;
 
-                if ((k = read(fd, p, nbytes)) <= 0) {
-
-                        if (k < 0 && errno == EINTR)
-                                continue;
-
-                        if (k < 0 && errno == EAGAIN && do_poll) {
-                                struct pollfd pollfd = {
-                                        .fd = fd,
-                                        .events = POLLIN,
-                                };
-
-                                if (poll(&pollfd, 1, -1) < 0) {
-                                        if (errno == EINTR)
-                                                continue;
+                k = read(fd, p, nbytes);
+                if (k < 0 && errno == EINTR)
+                        continue;
 
-                                        return n > 0 ? n : -errno;
-                                }
+                if (k < 0 && errno == EAGAIN && do_poll) {
 
-                                /* We knowingly ignore the revents value here,
-                                 * and expect that any error/EOF is reported
-                                 * via read()/write()
-                                 */
+                        /* We knowingly ignore any return value here,
+                         * and expect that any error/EOF is reported
+                         * via read() */
 
-                                continue;
-                        }
+                        fd_wait_for_event(fd, POLLIN, (usec_t) -1);
+                        continue;
+                }
 
+                if (k <= 0)
                         return n > 0 ? n : (k < 0 ? -errno : 0);
-                }
 
                 p += k;
                 nbytes -= k;
@@ -2147,46 +2101,31 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
 }
 
 ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
-        const uint8_t *p;
+        const uint8_t *p = buf;
         ssize_t n = 0;
 
         assert(fd >= 0);
         assert(buf);
 
-        p = buf;
-
         while (nbytes > 0) {
                 ssize_t k;
 
                 k = write(fd, p, nbytes);
-                if (k <= 0) {
-
-                        if (k < 0 && errno == EINTR)
-                                continue;
-
-                        if (k < 0 && errno == EAGAIN && do_poll) {
-                                struct pollfd pollfd = {
-                                        .fd = fd,
-                                        .events = POLLOUT,
-                                };
+                if (k < 0 && errno == EINTR)
+                        continue;
 
-                                if (poll(&pollfd, 1, -1) < 0) {
-                                        if (errno == EINTR)
-                                                continue;
+                if (k < 0 && errno == EAGAIN && do_poll) {
 
-                                        return n > 0 ? n : -errno;
-                                }
+                        /* We knowingly ignore any return value here,
+                         * and expect that any error/EOF is reported
+                         * via write() */
 
-                                /* We knowingly ignore the revents value here,
-                                 * and expect that any error/EOF is reported
-                                 * via read()/write()
-                                 */
-
-                                continue;
-                        }
+                        fd_wait_for_event(fd, POLLOUT, (usec_t) -1);
+                        continue;
+                }
 
+                if (k <= 0)
                         return n > 0 ? n : (k < 0 ? -errno : 0);
-                }
 
                 p += k;
                 nbytes -= k;
@@ -2306,7 +2245,6 @@ bool is_device_path(const char *path) {
 
 int dir_is_empty(const char *path) {
         _cleanup_closedir_ DIR *d;
-        int r;
 
         d = opendir(path);
         if (!d)
@@ -2314,11 +2252,11 @@ int dir_is_empty(const char *path) {
 
         for (;;) {
                 struct dirent *de;
-                union dirent_storage buf;
 
-                r = readdir_r(d, &buf.de, &de);
-                if (r > 0)
-                        return -r;
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return -errno;
 
                 if (!de)
                         return 1;
@@ -2346,42 +2284,60 @@ char* dirname_malloc(const char *path) {
         return dir;
 }
 
-unsigned long long random_ull(void) {
+int dev_urandom(void *p, size_t n) {
         _cleanup_close_ int fd;
-        uint64_t ull;
-        ssize_t r;
+        ssize_t k;
 
         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0)
-                goto fallback;
-
-        r = loop_read(fd, &ull, sizeof(ull), true);
-        if (r != sizeof(ull))
-                goto fallback;
+                return errno == ENOENT ? -ENOSYS : -errno;
 
-        return ull;
+        k = loop_read(fd, p, n, true);
+        if (k < 0)
+                return (int) k;
+        if ((size_t) k != n)
+                return -EIO;
 
-fallback:
-        return random() * RAND_MAX + random();
+        return 0;
 }
 
-unsigned random_u(void) {
-        _cleanup_close_ int fd;
-        unsigned u;
-        ssize_t r;
+void random_bytes(void *p, size_t n) {
+        static bool srand_called = false;
+        uint8_t *q;
+        int r;
 
-        fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-        if (fd < 0)
-                goto fallback;
+        r = dev_urandom(p, n);
+        if (r >= 0)
+                return;
+
+        /* If some idiot made /dev/urandom unavailable to us, he'll
+         * get a PRNG instead. */
 
-        r = loop_read(fd, &u, sizeof(u), true);
-        if (r != sizeof(u))
-                goto fallback;
+        if (!srand_called) {
+                unsigned x = 0;
 
-        return u;
+#ifdef HAVE_SYS_AUXV_H
+                /* The kernel provides us with a bit of entropy in
+                 * auxv, so let's try to make use of that to seed the
+                 * pseudo-random generator. It's better than
+                 * nothing... */
 
-fallback:
-        return random() * RAND_MAX + random();
+                void *auxv;
+
+                auxv = (void*) getauxval(AT_RANDOM);
+                if (auxv)
+                        x ^= *(unsigned*) auxv;
+#endif
+
+                x ^= (unsigned) now(CLOCK_REALTIME);
+                x ^= (unsigned) gettid();
+
+                srand(x);
+                srand_called = true;
+        }
+
+        for (q = p; q < (uint8_t*) p + n; q ++)
+                *q = rand();
 }
 
 void rename_process(const char name[8]) {
@@ -2410,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]));
                 }
         }
 }
@@ -2533,24 +2489,17 @@ int getttyname_harder(int fd, char **r) {
 }
 
 int get_ctty_devnr(pid_t pid, dev_t *d) {
-        _cleanup_fclose_ FILE *f = NULL;
-        char line[LINE_MAX], *p;
+        int r;
+        _cleanup_free_ char *line = NULL;
+        const char *p;
         unsigned long ttynr;
-        const char *fn;
 
         assert(pid >= 0);
 
-        if (pid == 0)
-                fn = "/proc/self/stat";
-        else
-                fn = procfs_file_alloca(pid, "stat");
-
-        f = fopen(fn, "re");
-        if (!f)
-                return -errno;
-
-        if (!fgets(line, sizeof(line), f))
-                return feof(f) ? -EIO : -errno;
+        p = procfs_file_alloca(pid, "stat");
+        r = read_one_line_file(p, &line);
+        if (r < 0)
+                return r;
 
         p = strrchr(line, ')');
         if (!p)
@@ -2577,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);
 
@@ -2597,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
@@ -2612,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/"))
@@ -2630,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;
 
@@ -2660,14 +2598,15 @@ int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct
 
         for (;;) {
                 struct dirent *de;
-                union dirent_storage buf;
                 bool is_dir, keep_around;
                 struct stat st;
                 int r;
 
-                r = readdir_r(d, &buf.de, &de);
-                if (r != 0 && ret == 0) {
-                        ret = -r;
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0) {
+                        if (ret == 0)
+                                ret = -errno;
                         break;
                 }
 
@@ -2737,9 +2676,9 @@ int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct
 
 _pure_ static int is_temporary_fs(struct statfs *s) {
         assert(s);
-        return
-                F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
-                F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
+
+        return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
+               F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
 }
 
 int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
@@ -2979,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,
@@ -3469,7 +3390,7 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
         return -EPROTO;
 }
 
-_noreturn_ void freeze(void) {
+noreturn void freeze(void) {
 
         /* Make sure nobody waits for us on a socket anymore */
         close_all_fds(NULL, 0);
@@ -3914,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;
@@ -3931,13 +3853,16 @@ int pipe_eof(int fd) {
 }
 
 int fd_wait_for_event(int fd, int event, usec_t t) {
-        int r;
+
         struct pollfd pollfd = {
                 .fd = fd,
                 .events = event,
         };
 
-        r = poll(&pollfd, 1, t == (usec_t) -1 ? -1 : (int) (t / USEC_PER_MSEC));
+        struct timespec ts;
+        int r;
+
+        r = ppoll(&pollfd, 1, t == (usec_t) -1 ? NULL : timespec_store(&ts, t), NULL);
         if (r < 0)
                 return -errno;
 
@@ -3968,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;
@@ -4137,7 +4062,7 @@ int symlink_atomic(const char *from, const char *to) {
         _cleanup_free_ char *t;
         const char *fn;
         size_t k;
-        unsigned long long ull;
+        uint64_t u;
         unsigned i;
         int r;
 
@@ -4154,10 +4079,10 @@ int symlink_atomic(const char *from, const char *to) {
         t[k] = '.';
         x = stpcpy(t+k+1, fn);
 
-        ull = random_ull();
+        u = random_u64();
         for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(ull & 0xF);
-                ull >>= 4;
+                *(x++) = hexchar(u & 0xF);
+                u >>= 4;
         }
 
         *x = 0;
@@ -4485,13 +4410,11 @@ int get_files_in_directory(const char *path, char ***list) {
 
         for (;;) {
                 struct dirent *de;
-                union dirent_storage buf;
-                int k;
 
-                k = readdir_r(d, &buf.de, &de);
-                assert(k >= 0);
-                if (k > 0)
-                        return -k;
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return -errno;
                 if (!de)
                         break;
 
@@ -4580,7 +4503,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;
@@ -4798,7 +4721,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);
@@ -4936,15 +4859,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;
 }
@@ -4954,16 +4877,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;
 }
 
@@ -5088,10 +5010,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
         assert(field);
         assert(_value);
 
-        if (pid == 0)
-                path = "/proc/self/environ";
-        else
-                path = procfs_file_alloca(pid, "environ");
+        path = procfs_file_alloca(pid, "environ");
 
         f = fopen(path, "re");
         if (!f)
@@ -5155,7 +5074,7 @@ bool is_valid_documentation_url(const char *url) {
 }
 
 bool in_initrd(void) {
-        static __thread int saved = -1;
+        static int saved = -1;
         struct statfs s;
 
         if (saved >= 0)
@@ -5618,15 +5537,14 @@ int on_ac_power(void) {
 
         for (;;) {
                 struct dirent *de;
-                union dirent_storage buf;
                 _cleanup_close_ int fd = -1, device = -1;
                 char contents[6];
                 ssize_t n;
-                int k;
 
-                k = readdir_r(d, &buf.de, &de);
-                if (k != 0)
-                        return -k;
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return -errno;
 
                 if (!de)
                         break;
@@ -5692,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) {
@@ -5874,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;
 }
@@ -5920,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;
 
@@ -5988,8 +5892,20 @@ int proc_cmdline(char **ret) {
         int r;
 
         if (detect_container(NULL) > 0) {
-                *ret = NULL;
-                return 0;
+                char *buf = NULL, *p;
+                size_t sz = 0;
+
+                r = read_full_file("/proc/1/cmdline", &buf, &sz);
+                if (r < 0)
+                        return r;
+
+                for (p = buf; p + 1 < buf + sz; p++)
+                        if (*p == 0)
+                                *p = ' ';
+
+                *p  = 0;
+                *ret = buf;
+                return 1;
         }
 
         r = read_one_line_file("/proc/cmdline", ret);
@@ -5999,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;
@@ -6030,18 +5975,24 @@ int container_get_leader(const char *machine, pid_t *pid) {
         return 0;
 }
 
-int namespace_open(pid_t pid, int *namespace_fd, int *root_fd) {
-        _cleanup_close_ int nsfd = -1;
-        const char *ns, *root;
+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(namespace_fd);
+        assert(pidns_fd);
+        assert(mntns_fd);
         assert(root_fd);
 
-        ns = procfs_file_alloca(pid, "ns/mnt");
-        nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-        if (nsfd < 0)
+        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");
@@ -6049,18 +6000,24 @@ int namespace_open(pid_t pid, int *namespace_fd, int *root_fd) {
         if (rfd < 0)
                 return -errno;
 
-        *namespace_fd = nsfd;
+        *pidns_fd = pidnsfd;
+        *mntns_fd = mntnsfd;
         *root_fd = rfd;
-        nsfd = -1;
+        pidnsfd = -1;
+        mntnsfd = -1;
 
         return 0;
 }
 
-int namespace_enter(int namespace_fd, int root_fd) {
-        assert(namespace_fd >= 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(namespace_fd, CLONE_NEWNS) < 0)
+        if (setns(pidns_fd, CLONE_NEWPID) < 0)
+                return -errno;
+
+        if (setns(mntns_fd, CLONE_NEWNS) < 0)
                 return -errno;
 
         if (fchdir(root_fd) < 0)
@@ -6077,3 +6034,199 @@ int namespace_enter(int namespace_fd, int root_fd) {
 
         return 0;
 }
+
+bool pid_is_unwaited(pid_t pid) {
+        /* Checks whether a PID is still valid at all, including a zombie */
+
+        if (pid <= 0)
+                return false;
+
+        if (kill(pid, 0) >= 0)
+                return true;
+
+        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;
+        int r;
+
+        assert(fd >= 0);
+        assert(ucred);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
+        if (r < 0)
+                return -errno;
+
+        if (n != sizeof(struct ucred))
+                return -EIO;
+
+        /* Check if the data is actually useful and not suppressed due
+         * to namespacing issues */
+        if (u.pid <= 0)
+                return -ENODATA;
+
+        *ucred = u;
+        return 0;
+}
+
+int getpeersec(int fd, char **ret) {
+        socklen_t n = 64;
+        char *s;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        s = new0(char, n);
+        if (!s)
+                return -ENOMEM;
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+        if (r < 0) {
+                free(s);
+
+                if (errno != ERANGE)
+                        return -errno;
+
+                s = new0(char, n);
+                if (!s)
+                        return -ENOMEM;
+
+                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+                if (r < 0) {
+                        free(s);
+                        return -errno;
+                }
+        }
+
+        if (isempty(s)) {
+                free(s);
+                return -ENOTSUP;
+        }
+
+        *ret = s;
+        return 0;
+}
+
+/* This is much like like mkostemp() but is subject to umask(). */
+int mkostemp_safe(char *pattern, int flags) {
+        _cleanup_umask_ mode_t u;
+        int fd;
+
+        assert(pattern);
+
+        u = umask(077);
+
+        fd = mkostemp(pattern, flags);
+        if (fd < 0)
+                return -errno;
+
+        return fd;
+}
+
+int open_tmpfile(const char *path, int flags) {
+        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, 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;
+}