X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=0e7d5c5fb3388e39236af01d73f73503b9ddafec;hb=d37a91e860ce953079870bdbd2526b2c04bb9ea5;hp=5551714a366de924978cc72762491d7eedbafdc0;hpb=bf85c24daaf63f72562bbe4c627ca8b963dfb964;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index 5551714a3..0e7d5c5fb 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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 (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; + 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 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 0; +} + +void random_bytes(void *p, size_t n) { + static bool srand_called = false; + uint8_t *q; + int r; - return; + r = dev_urandom(p, n); + if (r >= 0) + return; -fallback: + /* 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; @@ -6105,3 +6092,75 @@ int getpeersec(int fd, char **ret) { *ret = s; 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; +} + +int mkostemp_safe(char *pattern, int flags) { + unsigned long tries = TMP_MAX; + char *s; + int r; + + assert(pattern); + + /* This is much like like mkostemp() but avoids using any + * static variables, thus is async signal safe */ + + 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, 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) { + int fd; + char *p; + +#ifdef O_TMPFILE + fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + p = strappenda(path, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC); + if (fd < 0) + return fd; + + unlink(p); + return fd; +}