summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-05-02 15:42:21 -0400
committerIan Moffett <ian@osmora.org>2025-05-02 16:34:04 -0400
commit0331c642f92dce988446ea2ac6b69f82212f71ab (patch)
tree35ef26c38eebc2b9cbfbda516ed8dc8a1f8fabac
parent1b79c42492ea902af29f3157b5c38c89078dc3b8 (diff)
kernel: initramfs: Add initial OMAR port
CPIO is very outdated and its implementations varies on different hosts, best to use OSMORA Archive Format (OMAR) instead! Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r--.gitignore1
-rw-r--r--Makefile.in12
-rwxr-xr-xbootstrap5
-rw-r--r--builddeps/limine.conf2
-rw-r--r--configure.ac1
-rw-r--r--sys/fs/initramfs.c108
-rw-r--r--tools/omar/Makefile12
-rw-r--r--tools/omar/README9
-rw-r--r--tools/omar/omar.155
-rw-r--r--tools/omar/omar.c447
10 files changed, 593 insertions, 59 deletions
diff --git a/.gitignore b/.gitignore
index 001bc03..c93d8a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,5 +12,6 @@
/base
/sys/include/machine
/lib/libc/include/machine/
+/tools/omar/bin/
/share/misc/hwdoc
autom4te.cache
diff --git a/Makefile.in b/Makefile.in
index 9014e2d..457173e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -15,6 +15,11 @@ override QEMU_FLAGS = @QEMU_FLAGS@
override KERNEL_DEFINES = $ -DHYRA_VERSION="\"$(HYRA_VERSION)\""\
-DHYRA_BUILDDATE="\"@HYRA_BUILDDATE@\""\
-DHYRA_ARCH="\"@ARCH@\"" $(shell cat sys/arch/$(ARCH)/conf/GENERIC | tools/kconf/kconf)
+######################
+# Initramfs config
+######################
+override RAMFS_TOOL = @RAMFS_TOOL@
+override RAMFS_LOC = ramfs.omar
######################
# Toolchain
@@ -106,9 +111,8 @@ run:
.PHONY: ramfs
ramfs:
- cd base/; find . -name "*" | cpio --create --format=odc \
- --no-absolute-filenames > ../ramfs.cpio
- $(PROMPT) " RAMFS " $(shell pwd)/ramfs.cpio
+ $(RAMFS_TOOL) -i base/ -o ramfs.omar
+ $(PROMPT) " RAMFS " $(shell pwd)/ramfs.omar
.PHONY: clean
clean:
@@ -120,7 +124,7 @@ iso:
mkdir -p iso_root/boot/
mkdir -p iso_root/EFI/BOOT/
cp stand/limine/$(BOOT_FW) iso_root/EFI/BOOT/
- mv ramfs.cpio iso_root/boot/
+ mv $(RAMFS_LOC) iso_root/boot/
cp builddeps/limine.conf stand/limine/limine-bios.sys \
stand/limine/limine-bios-cd.bin stand/limine/limine-uefi-cd.bin iso_root/
cp base/boot/* iso_root/boot/
diff --git a/bootstrap b/bootstrap
index bea5ccf..511d49b 100755
--- a/bootstrap
+++ b/bootstrap
@@ -47,9 +47,14 @@ build_kconf() {
$MAKE -C tools/kconf/
}
+build_omar() {
+ $MAKE -C tools/omar/
+}
+
build() {
build_limine
build_kconf
+ build_omar
}
echo "----------------------------------"
diff --git a/builddeps/limine.conf b/builddeps/limine.conf
index f1907ea..308ad26 100644
--- a/builddeps/limine.conf
+++ b/builddeps/limine.conf
@@ -9,5 +9,5 @@ resolution: 1280x720
/Hyra
protocol: limine
kernel_path: boot():/boot/hyra-kernel
- module_path: boot():/boot/ramfs.cpio
+ module_path: boot():/boot/ramfs.omar
diff --git a/configure.ac b/configure.ac
index 9ec378e..fcad555 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,5 +56,6 @@ AC_SUBST(BOOT_FW, [$BOOT_FW])
AC_SUBST(ARCH, [$TARGET])
AC_SUBST(PROJECT_ROOT, [$PROJECT_ROOT])
AC_SUBST(TOOLCHAIN, [clang])
+AC_SUBST(RAMFS_TOOL, [tools/omar/bin/omar])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/sys/fs/initramfs.c b/sys/fs/initramfs.c
index fd746ef..b12a64b 100644
--- a/sys/fs/initramfs.c
+++ b/sys/fs/initramfs.c
@@ -33,12 +33,16 @@
#include <sys/errno.h>
#include <sys/limine.h>
#include <sys/panic.h>
+#include <sys/param.h>
#include <sys/vnode.h>
#include <fs/initramfs.h>
#include <vm/dynalloc.h>
#include <string.h>
-#define CPIO_TRAILER "TRAILER!!!"
+#define OMAR_EOF "RAMO"
+#define OMAR_REG 0
+#define OMAR_DIR 1
+#define BLOCK_SIZE 512
/*
* File or directory.
@@ -51,20 +55,18 @@ struct initramfs_node {
};
/*
- * ODC CPIO header
+ * The OMAR file header, describes the basics
+ * of a file.
+ *
+ * @magic: Header magic ("OMAR")
+ * @len: Length of the file
+ * @namelen: Length of the filename
*/
-struct cpio_hdr {
- char c_magic[6];
- char c_dev[6];
- char c_ino[6];
- char c_mode[6];
- char c_uid[6];
- char c_gid[6];
- char c_nlink[6];
- char c_rdev[6];
- char c_mtime[11];
- char c_namesize[6];
- char c_filesize[11];
+struct __packed omar_hdr {
+ char magic[4];
+ uint8_t type;
+ uint8_t namelen;
+ uint32_t len;
};
static volatile struct limine_module_request mod_req = {
@@ -92,21 +94,6 @@ get_module(const char *path, uint64_t *size) {
}
/*
- * Convert octal to base 10
- */
-static uint32_t
-oct2dec(const char *in, size_t sz)
-{
- size_t val = 0;
-
- for (size_t i = 0; i < sz; ++i) {
- val = val * 8 + (in[i] - '0');
- }
-
- return val;
-}
-
-/*
* Get a file from initramfs
*
* @path: Path of file to get.
@@ -115,41 +102,54 @@ oct2dec(const char *in, size_t sz)
static int
initramfs_get_file(const char *path, struct initramfs_node *res)
{
- const struct cpio_hdr *hdr;
struct initramfs_node node;
- uintptr_t addr;
- size_t namesize, filesize;
- mode_t mode;
+ const struct omar_hdr *hdr;
+ const char *p, *name;
+ char namebuf[256];
+ off_t off;
- addr = (uintptr_t)initramfs;
+ p = initramfs;
for (;;) {
- hdr = (void *)addr;
- namesize = oct2dec(hdr->c_namesize, sizeof(hdr->c_namesize));
- filesize = oct2dec(hdr->c_filesize, sizeof(hdr->c_filesize));
- mode = oct2dec(hdr->c_mode, sizeof(hdr->c_mode));
+ hdr = (struct omar_hdr *)p;
+ if (strncmp(hdr->magic, OMAR_EOF, sizeof(OMAR_EOF)) == 0) {
+ break;
+ }
- /* Make sure the magic is correct */
- if (strncmp(hdr->c_magic, "070707", 6) != 0) {
+ /* Ensure the file is valid */
+ if (strncmp(hdr->magic, "OMAR", 4) != 0) {
+ /* Bad magic */
+ return -EINVAL;
+ }
+ if (hdr->namelen > sizeof(namebuf) - 1) {
return -EINVAL;
}
- addr += sizeof(struct cpio_hdr);
- node.path = (const char *)addr;
+ name = (char *)p + sizeof(struct omar_hdr);
+ memcpy(namebuf, name, hdr->namelen);
+ namebuf[hdr->namelen] = '\0';
- /* Is this the requested file? */
- if (strcmp(node.path, path) == 0) {
- node.data = (void *)(addr + namesize);
- node.size = filesize;
- node.mode = mode;
+ /* Compute offset to next block */
+ if (hdr->type == OMAR_DIR) {
+ off = 512;
+ } else {
+ off = ALIGN_UP(sizeof(*hdr) + hdr->namelen + hdr->len, BLOCK_SIZE);
+ }
+
+ /* Skip header and name, right to the data */
+ p = (char *)hdr + sizeof(struct omar_hdr);
+ p += hdr->namelen;
+
+ if (strcmp(namebuf, path) == 0) {
+ node.mode = 0700;
+ node.size = hdr->len;
+ node.data = (void *)p;
*res = node;
return 0;
}
- /* Get next header and see if we are at the end */
- addr += (namesize + filesize);
- if (strcmp(node.path, CPIO_TRAILER) == 0) {
- break;
- }
+ hdr = (struct omar_hdr *)((char *)hdr + off);
+ p = (char *)hdr;
+ memset(namebuf, 0, sizeof(namebuf));
}
return -ENOENT;
@@ -256,9 +256,9 @@ initramfs_init(struct fs_info *fip)
struct mount *mp;
int status;
- initramfs = get_module("/boot/ramfs.cpio", &initramfs_size);
+ initramfs = get_module("/boot/ramfs.omar", &initramfs_size);
if (initramfs == NULL) {
- panic("failed to open initramfs cpio image\n");
+ panic("failed to open initramfs OMAR image\n");
}
status = vfs_alloc_vnode(&g_root_vnode, VDIR);
diff --git a/tools/omar/Makefile b/tools/omar/Makefile
new file mode 100644
index 0000000..ee30260
--- /dev/null
+++ b/tools/omar/Makefile
@@ -0,0 +1,12 @@
+CFILES = $(shell find . -name "*.c")
+CFLAGS = -pedantic
+CC = gcc
+
+.PHONY: all
+all:
+ mkdir -p bin/
+ $(CC) $(CFLAGS) $(CFILES) -o bin/omar
+
+.PHONY: clean
+clean:
+ rm -rf bin/
diff --git a/tools/omar/README b/tools/omar/README
new file mode 100644
index 0000000..3c74d78
--- /dev/null
+++ b/tools/omar/README
@@ -0,0 +1,9 @@
+------------------------------
+OMAR - OSMORA Archive Format
+------------------------------
+
+OMAR is a minimal, bullshit free archive format aimed to replace
+the old and outdated CPIO (copy in/out) format.
+
+OMAR is designed for readonly in-memory filesystems (such as initramfs),
+with simplicity, clarity and "getting it done" in mind.
diff --git a/tools/omar/omar.1 b/tools/omar/omar.1
new file mode 100644
index 0000000..e59be31
--- /dev/null
+++ b/tools/omar/omar.1
@@ -0,0 +1,55 @@
+.\" Copyright (c) 2025 Ian Marco Moffett and the Osmora Team.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright notice,
+.\" this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Hyra nor the names of its
+.\" contributors may be used to endorse or promote products derived from
+.\" this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.Dd Apr 29 2025
+.Dt OMAR 1
+.Os HYRA
+.Sh NAME
+.Nm omar - OSMORA Archive Format
+.Sh SYNOPSIS
+omar -i [input] -o [output]
+
+.Sh DESCRIPTION
+Prepare files for use in an initramfs
+
+.Ft -i
+ input path directory
+
+.Ft -o
+ output path
+
+Upon creation of the archive image, OMAR will
+produce pathnames through stdout with the following
+types in square brackets ([])
+
+.Ft f
+ Regular file
+
+.Ft d
+ Directory
+
+.Sh AUTHORS
+.An Ian Moffett Aq Mt ian@osmora.org
diff --git a/tools/omar/omar.c b/tools/omar/omar.c
new file mode 100644
index 0000000..129303e
--- /dev/null
+++ b/tools/omar/omar.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <assert.h>
+#include <dirent.h>
+#include <string.h>
+#include <libgen.h>
+
+/* OMAR magic constants */
+#define OMAR_MAGIC "OMAR"
+#define OMAR_EOF "RAMO"
+
+/* OMAR type constants */
+#define OMAR_REG 0
+#define OMAR_DIR 1
+
+/* OMAR modes */
+#define OMAR_ARCHIVE 0
+#define OMAR_EXTRACT 1
+
+#define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1))
+#define BLOCK_SIZE 512
+
+static int mode = OMAR_ARCHIVE;
+static int outfd;
+static const char *inpath = NULL;
+static const char *outpath = NULL;
+
+/*
+ * The OMAR file header, describes the basics
+ * of a file.
+ *
+ * @magic: Header magic ("OMAR")
+ * @len: Length of the file
+ * @namelen: Length of the filename
+ */
+struct omar_hdr {
+ char magic[4];
+ uint8_t type;
+ uint8_t namelen;
+ uint32_t len;
+} __attribute__((packed));
+
+static inline void
+help(void)
+{
+ printf("--------------------------------------\n");
+ printf("The OSMORA archive format\n");
+ printf("Usage: omar -i [input_dir] -o [output]\n");
+ printf("-h Show this help screen\n");
+ printf("-x Extract an OMAR archive\n");
+ printf("--------------------------------------\n");
+}
+
+/*
+ * Strip out root dir
+ *
+ * XXX: This is added code to work with Hyra
+ * initramfs.
+ */
+static const char *
+strip_root(const char *path)
+{
+ const char *p;
+
+ for (p = path; *p != '\0'; ++p) {
+ if (*p == '/') {
+ ++p;
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Recursive mkdir
+ */
+static void
+mkpath(const char *path)
+{
+ size_t len;
+ char buf[256];
+ char cwd[256];
+ char *p = NULL;
+
+ len = snprintf(buf, sizeof(buf), "%s", path);
+ if (buf[len - 1] == '/') {
+ buf[len - 1] = '\0';
+ }
+ for (p = (char *)buf + 1; *p != '\0'; ++p) {
+ if (*p == '/') {
+ *p = '\0';
+ mkdir(buf, 0700);
+ *p = '/';
+ }
+ }
+
+ mkdir(buf, 0700);
+}
+
+/*
+ * Push a file into the archive output
+ *
+ * @pathname: Full path name of file (NULL if EOF)
+ * @name: Name of file (for EOF, set to "EOF")
+ */
+static int
+file_push(const char *pathname, const char *name)
+{
+ struct omar_hdr hdr;
+ struct stat sb;
+ int infd, rem, error;
+ int pad_len;
+ size_t len;
+ char *buf;
+
+ hdr.type = OMAR_REG;
+
+ /* Attempt to open the input file if not EOF */
+ if (pathname != NULL) {
+ if ((infd = open(pathname, O_RDONLY)) < 0) {
+ perror("open");
+ return infd;
+ }
+
+ if ((error = fstat(infd, &sb)) < 0) {
+ return error;
+ }
+
+ if (S_ISDIR(sb.st_mode)) {
+ hdr.type = OMAR_DIR;
+ }
+ }
+
+ hdr.len = (pathname == NULL) ? 0 : sb.st_size;
+ hdr.namelen = strlen(name);
+
+ /*
+ * If we are at the end of the file, use the OMAR_EOF
+ * magic constant instant of the usual OMAR_MAGIC.
+ */
+ if (pathname == NULL) {
+ memcpy(hdr.magic, OMAR_EOF, sizeof(hdr.magic));
+ } else {
+ memcpy(hdr.magic, OMAR_MAGIC, sizeof(hdr.magic));
+ }
+
+ write(outfd, &hdr, sizeof(hdr));
+ write(outfd, name, hdr.namelen);
+
+ /* If we are at the end of file, we are done */
+ if (pathname == NULL) {
+ close(infd);
+ return 0;
+ }
+
+ /* Pad directories to zero */
+ if (hdr.type == OMAR_DIR) {
+ len = sizeof(hdr) + hdr.namelen;
+ rem = len & (BLOCK_SIZE - 1);
+ pad_len = BLOCK_SIZE - rem;
+
+ buf = malloc(pad_len);
+ memset(buf, 0, pad_len);
+ write(outfd, buf, pad_len);
+ free(buf);
+ return 0;
+ }
+
+ /* We need the file data now */
+ buf = malloc(hdr.len);
+ if (buf == NULL) {
+ printf("out of memory\n");
+ close(infd);
+ return -ENOMEM;
+ }
+ if (read(infd, buf, hdr.len) <= 0) {
+ perror("read");
+ close(infd);
+ return -EIO;
+ }
+
+ /*
+ * Write the actual file contents, if the file length is not
+ * a multiple of the block size, we'll need to pad out the rest
+ * to zero.
+ */
+ write(outfd, buf, hdr.len);
+ len = sizeof(hdr) + (hdr.namelen + hdr.len);
+ rem = len & (BLOCK_SIZE - 1);
+ if (rem != 0) {
+ /* Compute the padding length */
+ pad_len = BLOCK_SIZE - rem;
+
+ buf = realloc(buf, pad_len);
+ memset(buf, 0, pad_len);
+ write(outfd, buf, pad_len);
+ }
+ close(infd);
+ free(buf);
+ return 0;
+}
+
+/*
+ * Start creating an archive from the
+ * basepath of a directory.
+ */
+static int
+archive_create(const char *base, const char *dirname)
+{
+ DIR *dp;
+ struct dirent *ent;
+ struct omar_hdr hdr;
+ const char *p = NULL, *p1;
+ char pathbuf[256];
+ char namebuf[256];
+
+ dp = opendir(base);
+ if (dp == NULL) {
+ perror("opendir");
+ return -ENOENT;
+ }
+
+ while ((ent = readdir(dp)) != NULL) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+
+ snprintf(pathbuf, sizeof(pathbuf), "%s/%s", base, ent->d_name);
+ snprintf(namebuf, sizeof(namebuf), "%s/%s", dirname, ent->d_name);
+ p1 = strip_root(namebuf);
+
+ if (ent->d_type == DT_DIR) {
+ printf("%s [d]\n", p1);
+ file_push(pathbuf, p1);
+ archive_create(pathbuf, namebuf);
+ } else if (ent->d_type == DT_REG) {
+ printf("%s [f]\n", p1);
+ file_push(pathbuf, p1);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Extract a single file
+ *
+ * @data: Data to extract
+ * @len: Length of data
+ * @path: Path to output file
+ */
+static int
+extract_single(char *data, size_t len, const char *path)
+{
+ int fd;
+
+ if ((fd = open(path, O_WRONLY | O_CREAT, 0700)) < 0) {
+ return fd;
+ }
+
+ return write(fd, data, len) > 0 ? 0 : -1;
+}
+
+/*
+ * Extract an OMAR archive.
+ *
+ * XXX: The input file [-i] will be the OMAR archive to
+ * be extracted, the output directory [-o] will be
+ * where the files get extracted.
+ */
+static int
+archive_extract(void)
+{
+ char *buf, *name, *p;
+ struct stat sb;
+ struct omar_hdr *hdr;
+ int fd, error;
+ off_t off;
+ char namebuf[256];
+
+ if ((fd = open(inpath, O_RDONLY)) < 0) {
+ perror("open");
+ return fd;
+ }
+
+ if ((error = fstat(fd, &sb)) != 0) {
+ perror("fstat");
+ close(fd);
+ return error;
+ }
+
+ buf = malloc(sb.st_size);
+ if (buf == NULL) {
+ fprintf(stderr, "out of memory\n");
+ close(fd);
+ return -ENOMEM;
+ }
+
+ if (read(fd, buf, sb.st_size) <= 0) {
+ fprintf(stderr, "omar: no data read\n");
+ close(fd);
+ return -EIO;
+ }
+
+ hdr = (struct omar_hdr *)buf;
+ for (;;) {
+ if (memcmp(hdr->magic, OMAR_EOF, sizeof(OMAR_EOF)) == 0) {
+ printf("EOF!\n");
+ return 0;
+ }
+
+ /* Ensure the header is valid */
+ if (memcmp(hdr->magic, "OMAR", 4) != 0) {
+ fprintf(stderr, "bad magic\n");
+ break;
+ }
+
+ name = (char *)hdr + sizeof(struct omar_hdr);
+ memcpy(namebuf, name, hdr->namelen);
+ namebuf[hdr->namelen] = '\0';
+ printf("unpacking %s\n", namebuf);
+
+ if (hdr->type == OMAR_DIR) {
+ off = 512;
+ mkpath(namebuf);
+ } else {
+ off = ALIGN_UP(sizeof(hdr) + hdr->namelen + hdr->len, BLOCK_SIZE);
+ p = (char *)hdr + sizeof(struct omar_hdr);
+ p += hdr->namelen;
+ extract_single(p, hdr->len, namebuf);
+ }
+
+ hdr = (struct omar_hdr *)((char *)hdr + off);
+ memset(namebuf, 0, sizeof(namebuf));
+ }
+
+ free(buf);
+}
+
+int
+main(int argc, char **argv)
+{
+ int optc, retval;
+ int error, flags;
+
+ if (argc < 2) {
+ help();
+ return -1;
+ }
+
+ while ((optc = getopt(argc, argv, "xhi:o:")) != -1) {
+ switch (optc) {
+ case 'x':
+ mode = OMAR_EXTRACT;
+ break;
+ case 'i':
+ inpath = optarg;
+ break;
+ case 'o':
+ outpath = optarg;
+ break;
+ case 'h':
+ help();
+ return 0;
+ default:
+ help();
+ return -1;
+ }
+ }
+
+ if (inpath == NULL) {
+ fprintf(stderr, "omar: no input path\n");
+ help();
+ return -1;
+ }
+ if (outpath == NULL) {
+ fprintf(stderr, "omar: no output path\n");
+ help();
+ return -1;
+ }
+
+ /*
+ * Do our specific job based on the mode
+ * OMAR is set to be in.
+ */
+ switch (mode) {
+ case OMAR_ARCHIVE:
+ /* Begin archiving the file */
+ outfd = open(outpath, O_WRONLY | O_CREAT, 0700);
+ if (outfd < 0) {
+ printf("omar: failed to open output file\n");
+ return outfd;
+ }
+
+ retval = archive_create(inpath, basename((char *)inpath));
+ file_push(NULL, "EOF");
+ break;
+ case OMAR_EXTRACT:
+ /* Begin extracting the file */
+ if ((error = mkdir(outpath, 0700) != 0)) {
+ perror("mkdir");
+ return error;
+ }
+
+ retval = archive_extract();
+ break;
+ }
+ close(outfd);
+ return retval;
+}