X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=5cbbe8fb7d2886ffbbe36fab7cde07aba50fbe2c;hp=dc6528013bb0a7fded44e17a9e84e3eb5473b9f8;hb=0daa5666da6fab8864e313dd594a2648d882e0cf;hpb=1c8da044469acabcfc479ba3276954da53210830 diff --git a/src/shared/util.c b/src/shared/util.c index dc6528013..5cbbe8fb7 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -19,7 +19,6 @@ along with systemd; If not, see . ***/ -#include #include #include #include @@ -48,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -83,7 +81,6 @@ #include "missing.h" #include "log.h" #include "strv.h" -#include "label.h" #include "mkdir.h" #include "path-util.h" #include "exit-status.h" @@ -97,6 +94,9 @@ #include "def.h" #include "sparse-endian.h" +/* Put this test here for a lack of better place */ +assert_cc(EAGAIN == EWOULDBLOCK); + int saved_argc = 0; char **saved_argv = NULL; @@ -1692,6 +1692,7 @@ bool chars_intersect(const char *a, const char *b) { bool fstype_is_network(const char *fstype) { static const char table[] = + "afs\0" "cifs\0" "smbfs\0" "sshfs\0" @@ -2328,6 +2329,17 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { return n; } +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { + ssize_t n; + + n = loop_read(fd, buf, nbytes, do_poll); + if (n < 0) + return n; + if ((size_t) n != nbytes) + return -EIO; + return 0; +} + int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { const uint8_t *p = buf; @@ -2582,8 +2594,9 @@ char* dirname_malloc(const char *path) { int dev_urandom(void *p, size_t n) { static int have_syscall = -1; - int r, fd; - ssize_t k; + + _cleanup_close_ int fd = -1; + int r; /* Gathers some randomness from the kernel. This call will * never block, and will always return some data from the @@ -2618,22 +2631,14 @@ int dev_urandom(void *p, size_t n) { return -errno; } else /* too short read? */ - return -EIO; + return -ENODATA; } fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return errno == ENOENT ? -ENOSYS : -errno; - k = loop_read(fd, p, n, true); - safe_close(fd); - - if (k < 0) - return (int) k; - if ((size_t) k != n) - return -EIO; - - return 0; + return loop_read_exact(fd, p, n, true); } void initialize_srand(void) { @@ -2921,31 +2926,30 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { /* This is an ugly hack */ if (major(devnr) == 136) { - asprintf(&b, "pts/%u", minor(devnr)); - goto finish; - } + if (asprintf(&b, "pts/%u", minor(devnr)) < 0) + return -ENOMEM; + } else { + /* Probably something like the ptys which have no + * symlink in /dev/char. Let's return something + * vaguely useful. */ - /* Probably something like the ptys which have no - * symlink in /dev/char. Let's return something - * vaguely useful. */ + b = strdup(fn + 5); + if (!b) + return -ENOMEM; + } + } else { + if (startswith(s, "/dev/")) + p = s + 5; + else if (startswith(s, "../")) + p = s + 3; + else + p = s; - b = strdup(fn + 5); - goto finish; + b = strdup(p); + if (!b) + return -ENOMEM; } - if (startswith(s, "/dev/")) - p = s + 5; - else if (startswith(s, "../")) - p = s + 3; - else - p = s; - - b = strdup(p); - -finish: - if (!b) - return -ENOMEM; - *r = b; if (_devnr) *_devnr = devnr; @@ -4117,8 +4121,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) { if (null_or_empty_path(path)) { log_debug("%s is empty (a mask).", path); continue; - } else - log_debug("%s will be executed.", path); + } pid = fork(); if (pid < 0) { @@ -6001,7 +6004,7 @@ int on_ac_power(void) { d = opendir("/sys/class/power_supply"); if (!d) - return -errno; + return errno == ENOENT ? true : -errno; for (;;) { struct dirent *de; @@ -6666,7 +6669,7 @@ int getpeersec(int fd, char **ret) { if (isempty(s)) { free(s); - return -ENOTSUP; + return -EOPNOTSUPP; } *ret = s; @@ -8120,3 +8123,44 @@ void cmsg_close_all(struct msghdr *mh) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); } + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + struct stat buf; + int ret; + + ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE); + if (ret >= 0) + return 0; + + /* Even though renameat2() exists since Linux 3.15, btrfs added + * support for it later. If it is not implemented, fallback to another + * method. */ + if (errno != EINVAL) + return -errno; + + /* The link()/unlink() fallback does not work on directories. But + * renameat() without RENAME_NOREPLACE gives the same semantics on + * directories, except when newpath is an *empty* directory. This is + * good enough. */ + ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); + if (ret >= 0 && S_ISDIR(buf.st_mode)) { + ret = renameat(olddirfd, oldpath, newdirfd, newpath); + return ret >= 0 ? 0 : -errno; + } + + /* If it is not a directory, use the link()/unlink() fallback. */ + ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); + if (ret < 0) + return -errno; + + ret = unlinkat(olddirfd, oldpath, 0); + if (ret < 0) { + /* backup errno before the following unlinkat() alters it */ + ret = errno; + (void) unlinkat(newdirfd, newpath, 0); + errno = ret; + return -errno; + } + + return 0; +}