summaryrefslogtreecommitdiffstats
path: root/usr/kinit/readfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/kinit/readfile.c')
-rw-r--r--usr/kinit/readfile.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/usr/kinit/readfile.c b/usr/kinit/readfile.c
new file mode 100644
index 0000000..7a16b4a
--- /dev/null
+++ b/usr/kinit/readfile.c
@@ -0,0 +1,86 @@
+/*
+ * Read the entire contents of a file into malloc'd storage. This
+ * is mostly useful for things like /proc files where we can't just
+ * fstat() to get the length and then mmap().
+ *
+ * Returns the number of bytes read, or -1 on error.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "kinit.h"
+
+ssize_t freadfile(FILE *f, char **pp)
+{
+ size_t bs; /* Decent starting point... */
+ size_t bf; /* Bytes free */
+ size_t bu = 0; /* Bytes used */
+ char *buffer, *nb;
+ size_t rv;
+ int old_errno = errno;
+
+ bs = BUFSIZ; /* A guess as good as any */
+ bf = bs;
+ buffer = malloc(bs);
+
+ if (!buffer)
+ return -1;
+
+ for (;;) {
+ errno = 0;
+
+ while (bf && (rv = _fread(buffer + bu, bf, f))) {
+ bu += rv;
+ bf -= rv;
+ }
+
+ if (errno && errno != EINTR && errno != EAGAIN) {
+ /* error */
+ free(buffer);
+ return -1;
+ }
+
+ if (bf) {
+ /* Hit EOF, no error */
+
+ /* Try to free superfluous memory */
+ if ((nb = realloc(buffer, bu + 1)))
+ buffer = nb;
+
+ /* Null-terminate result for good measure */
+ buffer[bu] = '\0';
+
+ *pp = buffer;
+ errno = old_errno;
+ return bu;
+ }
+
+ /* Double the size of the buffer */
+ bf += bs;
+ bs += bs;
+ if (!(nb = realloc(buffer, bs))) {
+ /* out of memory error */
+ free(buffer);
+ return -1;
+ }
+ buffer = nb;
+ }
+}
+
+ssize_t readfile(const char *filename, char **pp)
+{
+ FILE *f = fopen(filename, "r");
+ ssize_t rv;
+
+ if (!f)
+ return -1;
+
+ rv = freadfile(f, pp);
+
+ fclose(f);
+
+ return rv;
+}