Factor out mapping/unmapping of files
authorH. Peter Anvin <hpa@zytor.com>
Mon, 7 Jan 2008 04:37:48 +0000 (20:37 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 7 Jan 2008 04:37:48 +0000 (20:37 -0800)
Factor out file map/unmap; this will make porting to non-Unix
operating systems and/or support nonfile inputs easier.

Makefile
linux.c
mapfile.c [new file with mode: 0644]
wraplinux.h

index 94640f6..cacc763 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -33,9 +33,9 @@ reloc/reloc.elf: $(RELOC_OBJS) reloc/reloc.ld
        $(LD_FOR_TARGET) $(LDFLAGS_FOR_TARGET) -T reloc/reloc.ld \
                -o $@ $(RELOC_OBJS)
 
-reloc.o: reloc.S reloc/reloc.bin 
+reloc.o: reloc.S reloc/reloc.bin
 
-wraplinux: main.o linux.o reloc.o elf.o nbi.o segment.o xmalloc.o
+wraplinux: main.o linux.o reloc.o elf.o nbi.o segment.o mapfile.o xmalloc.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 clean:
diff --git a/linux.c b/linux.c
index e87809c..31f1a42 100644 (file)
--- a/linux.c
+++ b/linux.c
@@ -25,8 +25,6 @@
 #include <string.h>
 #include <fcntl.h>
 #include <sysexits.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include "segment.h"
 #include "setup.h"
@@ -107,7 +105,6 @@ int wrap_kernel(const char *kernel_file, const char *cmdline,
   int kernel_fd = -1;
   char *kernel = NULL;
   size_t kernel_len = 0;
-  struct stat st;
   struct segment srel, ssup, scmd, skrn;
   struct startup_info *info = (void *)reloc;
   struct setup_header *hdr;
@@ -132,14 +129,13 @@ int wrap_kernel(const char *kernel_file, const char *cmdline,
     goto err;
   }
 
-  if (fstat(kernel_fd, &st)) {
+  kernel = mapfile(kernel_fd, &kernel_len, 1);
+  if (!kernel) {
     fprintf(stderr, "%s: %s: %s\n", program, kernel_file, strerror(errno));
-    rv = EX_DATAERR;
+    rv = EX_NOINPUT;
     goto err;
   }
 
-  kernel_len = st.st_size;
-
   if (kernel_len < 1024) {
     fprintf(stderr, "%s: %s: kernel file too small\n", program, kernel_file);
     rv = EX_NOINPUT;
@@ -147,15 +143,6 @@ int wrap_kernel(const char *kernel_file, const char *cmdline,
     goto err;
   }
 
-  kernel = mmap(NULL, kernel_len, PROT_READ|PROT_WRITE, MAP_PRIVATE,
-               kernel_fd, 0);
-  if (kernel == MAP_FAILED) {
-    fprintf(stderr, "%s: %s: %s\n", program, kernel_file, strerror(errno));
-    rv = EX_NOINPUT;
-    kernel = NULL;
-    goto err;
-  }
-
   /* Pick apart the header... */
 
   hdr = (struct setup_header *)(kernel + 0x1f1);
@@ -218,8 +205,11 @@ int wrap_kernel(const char *kernel_file, const char *cmdline,
   for (ip = initrd_list; ip; ip = ip->next)
     ninitrd++;
 
-  if (ninitrd)
+  if (ninitrd) {
     ird = xcalloc(ninitrd, sizeof *ird);
+    for (i = 0; i < ninitrd; i++)
+      ird[i].fd = -1;
+  }
 
   initrd_len = 0;
   for (ip = initrd_list, i = 0; ip; ip = ip->next, i++) {
@@ -230,22 +220,13 @@ int wrap_kernel(const char *kernel_file, const char *cmdline,
       goto err;
     }
 
-    if (fstat(ird[i].fd, &st)) {
+    ird[i].seg.data = mapfile(ird[i].fd, &ird[i].seg.length, 0);
+    if (!ird[i].seg.data) {
       fprintf(stderr, "%s: %s: %s", program, ip->str, strerror(errno));
       rv = EX_NOINPUT;
       goto err;
     }
 
-    ird[i].seg.length = st.st_size;
-    ird[i].seg.data = mmap(NULL, ird[i].seg.length, PROT_READ,
-                          MAP_SHARED, ird[i].fd, 0);
-    if (ird[i].seg.data == MAP_FAILED) {
-      fprintf(stderr, "%s: %s: %s", program, ip->str, strerror(errno));
-      rv = EX_NOINPUT;
-      ird[i].seg.data = NULL;
-      goto err;
-    }
-
     /* We need to pad the space between initrds to a 4-byte boundary.
        This is safe because an mmap is always padded with zero
        to a page boundary... */
@@ -341,19 +322,11 @@ int wrap_kernel(const char *kernel_file, const char *cmdline,
 
  err:
   if (ird) {
-    for (i = 0; i < ninitrd; i++) {
-      if (ird[i].seg.data)
-       munmap((void *)ird[i].seg.data, ird[i].seg.length);
-      if (ird[i].fd > 0)
-      close(ird[i].fd);
-    }
+    for (i = 0; i < ninitrd; i++)
+      unmapfile(ird[i].fd, (void *)ird[i].seg.data, ird[i].seg.length);
     free(ird);
   }
 
-  if (kernel)
-    munmap(kernel, kernel_len);
-  if (kernel_fd >= 0)
-    close(kernel_fd);
-
+  unmapfile(kernel_fd, kernel, kernel_len);
   return rv;
 }
diff --git a/mapfile.c b/mapfile.c
new file mode 100644 (file)
index 0000000..0f26ca6
--- /dev/null
+++ b/mapfile.c
@@ -0,0 +1,52 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * mapfile.c
+ *
+ * Memory-map a file, and/or read it into a memory buffer.
+ * If the "writable" flag is set, return a writable memory
+ * buffer, *not* one which writes back to the file!
+ *
+ * Note: if this is modified to use a buffer, always round the buffer
+ * size up to at least a dword boundary.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+void *mapfile(int fd, size_t *len, int writable)
+{
+  struct stat st;
+  void *ptr;
+
+  if (fstat(fd, &st))
+    return NULL;
+
+  *len = st.st_size;
+
+  if (writable)
+    ptr = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+  else
+    ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+  return (ptr == MAP_FAILED) ? NULL : ptr;
+}
+
+void unmapfile(int fd, void *ptr, size_t len)
+{
+  if (ptr)
+    munmap(ptr, len);
+  if (fd >= 0)
+    close(fd);
+}
index f348e0b..2037343 100644 (file)
@@ -29,10 +29,15 @@ struct string_list {
   const char *str;
 };
 
+/* linux.c */
 int wrap_kernel(const char *kernel, const char *cmdline,
                const struct string_list *initrd_list, FILE *out);
 
-/* xmalloc.h */
+/* mapfile.c */
+void *mapfile(int fd, size_t *len, int writable);
+void unmapfile(int fd, void *ptr, size_t len);
+
+/* xmalloc.c */
 void *xmalloc(size_t);
 void *xcalloc(size_t, size_t);
 int xasprintf(char **strp, const char *fmt, ...);