chiark / gitweb /
nspawn: add new --personality= switch to make it easier to run 32bit containers on...
[elogind.git] / src / shared / util.c
index f9cbb2073c9a535e3bb41de0f5cd828809b3ae73..99658f097571f847db178d1402623bd27fd3031e 100644 (file)
@@ -58,6 +58,7 @@
 #include <limits.h>
 #include <langinfo.h>
 #include <locale.h>
+#include <sys/personality.h>
 #include <libgen.h>
 #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]));
                 }
         }
 }
@@ -2900,24 +2929,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,
@@ -3893,7 +3904,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;
@@ -5610,7 +5621,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) {
@@ -5792,7 +5803,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;
 }
@@ -5838,20 +5849,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;
 
@@ -5929,6 +5926,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;
@@ -6020,7 +6046,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;
 
@@ -6030,6 +6058,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;
@@ -6093,57 +6136,20 @@ 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) {
-        unsigned long tries = TMP_MAX;
-        char *s;
-        int r;
+        _cleanup_umask_ mode_t u;
+        int fd;
 
         assert(pattern);
 
-        /* This is much like like mkostemp() but avoids using any
-         * static variables, thus is async signal safe */
+        u = umask(077);
 
-        s = endswith(pattern, "XXXXXX");
-        if (!s)
-                return -EINVAL;
-
-        while (tries--) {
-                unsigned i;
-                int fd;
-
-                r = dev_urandom(s, 6);
-                if (r < 0)
-                        return r;
-
-                for (i = 0; i < 6; i++)
-                        s[i] = ALPHANUMERICAL[(unsigned) s[i] % (sizeof(ALPHANUMERICAL)-1)];
-
-                fd = open(pattern, flags|O_EXCL|O_CREAT|O_NOCTTY|O_NOFOLLOW, 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) {
@@ -6169,3 +6175,50 @@ int open_tmpfile(const char *path, int flags) {
         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 parse_personality(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;
+}