diff options
author | Shawn Landden <shawn@churchofgit.com> | 2013-11-30 16:09:26 -0800 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2013-11-30 22:20:20 -0500 |
commit | e93c33d4aadb41427f215d43545e7fadc6bcec6f (patch) | |
tree | 6964e793e232cce6d03349d73a83fe23da45e252 /src/shared | |
parent | f74294c1dabb41faaaa0e03777f0dd33b979eed6 (diff) |
systemctl: add "systemctl cat"
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/fileio.c | 73 | ||||
-rw-r--r-- | src/shared/fileio.h | 1 | ||||
-rw-r--r-- | src/shared/util.c | 2 |
3 files changed, 75 insertions, 1 deletions
diff --git a/src/shared/fileio.c b/src/shared/fileio.c index 733b320388..ac1b409a1c 100644 --- a/src/shared/fileio.c +++ b/src/shared/fileio.c @@ -20,6 +20,7 @@ ***/ #include <unistd.h> +#include <sys/sendfile.h> #include "fileio.h" #include "util.h" #include "strv.h" @@ -117,6 +118,77 @@ int read_one_line_file(const char *fn, char **line) { return 0; } +ssize_t sendfile_full(int out_fd, const char *fn) { + _cleanup_fclose_ FILE *f; + struct stat st; + int r; + ssize_t s; + + size_t n, l; + _cleanup_free_ char *buf = NULL; + + assert(out_fd > 0); + assert(fn); + + f = fopen(fn, "r"); + if (!f) + return -errno; + + r = fstat(fileno(f), &st); + if (r < 0) + return -errno; + + s = sendfile(out_fd, fileno(f), NULL, st.st_size); + if (s < 0) + if (errno == EINVAL || errno == ENOSYS) { + /* continue below */ + } else + return -errno; + else + return s; + + /* sendfile() failed, fall back to read/write */ + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + n = st.st_size > 0 ? st.st_size : LINE_MAX; + l = 0; + + while (true) { + char *t; + size_t k; + + t = realloc(buf, n); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + r = write(out_fd, buf, l); + if (r < 0) + return -errno; + + return (ssize_t) l; +} + int read_full_file(const char *fn, char **contents, size_t *size) { _cleanup_fclose_ FILE *f = NULL; size_t n, l; @@ -168,7 +240,6 @@ int read_full_file(const char *fn, char **contents, size_t *size) { buf[l] = 0; *contents = buf; - buf = NULL; if (size) *size = l; diff --git a/src/shared/fileio.h b/src/shared/fileio.h index 59e41502b1..06c2887157 100644 --- a/src/shared/fileio.h +++ b/src/shared/fileio.h @@ -31,6 +31,7 @@ int write_string_file_atomic(const char *fn, const char *line); int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); +ssize_t sendfile_full(int out_fd, const char *fn); int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(const char *fname, const char *separator, char ***l); diff --git a/src/shared/util.c b/src/shared/util.c index 206fc803d0..305a6c2fb6 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -5791,6 +5791,8 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need) { size_t a; void *q; + assert(allocated); + if (*allocated >= need) return *p; |