summaryrefslogtreecommitdiff
path: root/src/shared/util.c
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2014-08-14 11:28:47 -0400
committerAnthony G. Basile <blueness@gentoo.org>2014-08-14 11:28:47 -0400
commit28744043fbaca39dfc9fd1666a8557fd6d8a690f (patch)
treef0cf30fe98f3e7e535be23c3954973ef02c58e49 /src/shared/util.c
parent819fb6029dde2af3acf23b0fa25c1851b26ce102 (diff)
src/shared: import many code cleanups from upstream
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'src/shared/util.c')
-rw-r--r--src/shared/util.c339
1 files changed, 195 insertions, 144 deletions
diff --git a/src/shared/util.c b/src/shared/util.c
index 5ff767b6a7..d551f87e60 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -68,6 +68,7 @@
#include "exit-status.h"
#include "hashmap.h"
#include "fileio.h"
+#include "virt.h"
int saved_argc = 0;
char **saved_argv = NULL;
@@ -128,32 +129,23 @@ int close_nointr(int fd) {
assert(fd >= 0);
r = close(fd);
-
- /* Just ignore EINTR; a retry loop is the wrong
- * thing to do on Linux.
- *
- * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
- * https://bugzilla.gnome.org/show_bug.cgi?id=682819
- * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
- * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
- */
- if (_unlikely_(r < 0 && errno == EINTR))
- return 0;
- else if (r >= 0)
+ if (r >= 0)
return r;
+ else if (errno == EINTR)
+ /*
+ * Just ignore EINTR; a retry loop is the wrong
+ * thing to do on Linux.
+ *
+ * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+ * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+ * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+ * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+ */
+ return 0;
else
return -errno;
}
-void close_nointr_nofail(int fd) {
- PROTECT_ERRNO;
-
- /* like close_nointr() but cannot fail, and guarantees errno
- * is unchanged */
-
- assert_se(close_nointr(fd) == 0);
-}
-
int safe_close(int fd) {
/*
@@ -490,6 +482,7 @@ _pure_ static bool ignore_file_allow_backup(const char *filename) {
endswith(filename, ".rpmorig") ||
endswith(filename, ".dpkg-old") ||
endswith(filename, ".dpkg-new") ||
+ endswith(filename, ".dpkg-tmp") ||
endswith(filename, ".swp");
}
@@ -497,55 +490,11 @@ bool ignore_file(const char *filename) {
assert(filename);
if (endswith(filename, "~"))
- return false;
+ return true;
return ignore_file_allow_backup(filename);
}
-void random_bytes(void *p, size_t n) {
- static bool srand_called = false;
- _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;
-
- k = loop_read(fd, p, n, true);
- if (k < 0 || (size_t) k != n)
- goto fallback;
-
- return;
-
-fallback:
-
- if (!srand_called) {
-
-#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... */
-
- void *auxv;
-
- auxv = (void*) getauxval(AT_RANDOM);
- if (auxv)
- srand(*(unsigned*) auxv);
- else
-#endif
- srand(time(NULL) + gettid());
-
- 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();
-}
-
int open_terminal(const char *name, int mode) {
int fd, r;
unsigned c = 0;
@@ -582,18 +531,74 @@ int open_terminal(const char *name, int mode) {
r = isatty(fd);
if (r < 0) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -errno;
}
if (!r) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -ENOTTY;
}
return fd;
}
+int dev_urandom(void *p, size_t n) {
+ _cleanup_close_ int fd;
+ ssize_t k;
+
+ 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);
+ 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;
+
+ 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
+ * auxv, so let's try to make use of that to seed the
+ * pseudo-random generator. It's better than
+ * nothing... */
+
+ 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();
+}
+
_pure_ static int is_temporary_fs(struct statfs *s) {
assert(s);
@@ -601,6 +606,41 @@ _pure_ static int is_temporary_fs(struct statfs *s) {
F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
+ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
+ uint8_t *p = buf;
+ ssize_t n = 0;
+
+ assert(fd >= 0);
+ assert(buf);
+
+ while (nbytes > 0) {
+ ssize_t k;
+
+ k = read(fd, p, nbytes);
+ if (k < 0 && errno == EINTR)
+ continue;
+
+ if (k < 0 && errno == EAGAIN && do_poll) {
+
+ /* We knowingly ignore any return value here,
+ * and expect that any error/EOF is reported
+ * via read() */
+
+ fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
+ continue;
+ }
+
+ if (k <= 0)
+ return n > 0 ? n : (k < 0 ? -errno : 0);
+
+ p += k;
+ nbytes -= k;
+ n += k;
+ }
+
+ return n;
+}
+
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
assert(path);
@@ -680,8 +720,7 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
return false;
}
-int execute_command(const char *command, char *const argv[])
-{
+int execute_command(const char *command, char *const argv[]) {
pid_t pid;
int status;
@@ -759,28 +798,20 @@ int flush_fd(int fd) {
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
FILE *f;
char *t;
- const char *fn;
- size_t k;
int fd;
assert(path);
assert(_f);
assert(_temp_path);
- t = new(char, strlen(path) + 1 + 6 + 1);
+ t = tempfn_xxxxxx(path);
if (!t)
return -ENOMEM;
- fn = path_get_file_name(path);
- k = fn-path;
- memcpy(t, path, k);
- t[k] = '.';
- stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
-
#if HAVE_DECL_MKOSTEMP
- fd = mkostemp(t, O_WRONLY|O_CLOEXEC);
+ fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
#else
- fd = mkstemp(t);
+ fd = mkstemp_safe(t);
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
if (fd < 0) {
@@ -801,55 +832,6 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
return 0;
}
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
- uint8_t *p;
- 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;
-
- return n > 0 ? n : -errno;
- }
-
- /* We knowingly ignore the revents value here,
- * and expect that any error/EOF is reported
- * via read()/write()
- */
-
- continue;
- }
-
- return n > 0 ? n : (k < 0 ? -errno : 0);
- }
-
- p += k;
- nbytes -= k;
- n += k;
- }
-
- return n;
-}
-
char *strjoin(const char *x, ...) {
va_list ap;
size_t l;
@@ -908,7 +890,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;
@@ -984,7 +966,7 @@ static const char* const sched_policy_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
-static const char* const rlimit_table[] = {
+static const char* const rlimit_table[_RLIMIT_MAX] = {
[RLIMIT_CPU] = "LimitCPU",
[RLIMIT_FSIZE] = "LimitFSIZE",
[RLIMIT_DATA] = "LimitDATA",
@@ -1053,7 +1035,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);
@@ -1068,26 +1050,46 @@ const char *signal_to_string(int signo) {
return buf;
}
+int fd_wait_for_event(int fd, int event, usec_t t) {
+
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = event,
+ };
+
+ struct timespec ts;
+ int r;
+
+ r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
+ if (r < 0)
+ return -errno;
+
+ if (r == 0)
+ return 0;
+
+ return pollfd.revents;
+}
+
int fd_inc_sndbuf(int fd, size_t n) {
int r, value;
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;
}
bool in_initrd(void) {
- static __thread int saved = -1;
+ static int saved = -1;
struct statfs s;
if (saved >= 0)
@@ -1136,9 +1138,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int proc_cmdline(char **ret) {
int r;
- /* disable containers for now
if (detect_container(NULL) > 0) {
- char *buf, *p;
+ char *buf = NULL, *p;
size_t sz = 0;
r = read_full_file("/proc/1/cmdline", &buf, &sz);
@@ -1149,11 +1150,10 @@ int proc_cmdline(char **ret) {
if (*p == 0)
*p = ' ';
- *p = 0;
+ *p = 0;
*ret = buf;
return 1;
}
- */
r = read_one_line_file("/proc/cmdline", ret);
if (r < 0)
@@ -1185,3 +1185,54 @@ int getpeercred(int fd, struct ucred *ucred) {
*ucred = u;
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;
+}
+
+/* This is much like like mkstemp() but is subject to umask(). */
+int mkstemp_safe(char *pattern) {
+ _cleanup_umask_ mode_t u;
+ int fd;
+
+ assert(pattern);
+
+ u = umask(077);
+
+ fd = mkstemp(pattern);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+char *tempfn_xxxxxx(const char *p) {
+ const char *fn;
+ char *t;
+ size_t k;
+
+ assert(p);
+
+ t = new(char, strlen(p) + 1 + 6 + 1);
+ if (!t)
+ return NULL;
+
+ fn = basename(p);
+ k = fn - p;
+
+ strcpy(stpcpy(stpcpy(mempcpy(t, p, k), "."), fn), "XXXXXX");
+
+ return t;
+}