chiark / gitweb /
Get rid of write_safe
[elogind.git] / src / shared / util.c
index 5551714a366de924978cc72762491d7eedbafdc0..30512d16462bf5c528660a66a9ab8e10380ed402 100644 (file)
@@ -2037,45 +2037,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;
@@ -2086,46 +2072,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;
@@ -2284,25 +2255,37 @@ char* dirname_malloc(const char *path) {
         return dir;
 }
 
-void random_bytes(void *p, size_t n) {
-        static bool srand_called = false;
+int dev_urandom(void *p, size_t n) {
         _cleanup_close_ int fd;
         ssize_t k;
-        uint8_t *q;
 
         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0)
-                goto fallback;
+                return errno == ENOENT ? -ENOSYS : -errno;
 
         k = loop_read(fd, p, n, true);
-        if (k < 0 || (size_t) k != n)
-                goto fallback;
+        if (k < 0)
+                return (int) k;
+        if ((size_t) k != n)
+                return -EIO;
 
-        return;
+        return 0;
+}
 
-fallback:
+void random_bytes(void *p, size_t n) {
+        static bool srand_called = false;
+        uint8_t *q;
+        int r;
+
+        r = dev_urandom(p, n);
+        if (r >= 0)
+                return;
+
+        /* If some idiot made /dev/urandom unavailable to us, he'll
+         * get a PRNG instead. */
 
         if (!srand_called) {
+                unsigned x = 0;
 
 #ifdef HAVE_SYS_AUXV_H
                 /* The kernel provides us with a bit of entropy in
@@ -2314,16 +2297,16 @@ fallback:
 
                 auxv = (void*) getauxval(AT_RANDOM);
                 if (auxv)
-                        srand(*(unsigned*) auxv);
-                else
+                        x ^= *(unsigned*) auxv;
 #endif
-                        srand(time(NULL) + gettid());
 
+                x ^= (unsigned) now(CLOCK_REALTIME);
+                x ^= (unsigned) gettid();
+
+                srand(x);
                 srand_called = true;
         }
 
-        /* If some idiot made /dev/urandom unavailable to us, he'll
-         * get a PRNG instead. */
         for (q = p; q < (uint8_t*) p + n; q ++)
                 *q = rand();
 }
@@ -3852,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;
@@ -3869,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;
 
@@ -3906,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;
@@ -6105,3 +6092,66 @@ int getpeersec(int fd, char **ret) {
         *ret = s;
         return 0;
 }
+
+int mkostemp_safe(char *pattern, int flags) {
+        unsigned long tries = TMP_MAX;
+        char *s;
+        int r;
+        _cleanup_umask_ mode_t u;
+
+        assert(pattern);
+
+        u = umask(077);
+
+        /* This is much like like mkostemp() but avoids using any
+         * static variables, thus is async signal safe. Also, it's not
+         * subject to umask(). */
+
+        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;
+        }
+
+        return -EEXIST;
+}
+
+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;
+}