diff --git a/mkinitrd/Makefile b/mkinitrd/Makefile
new file mode 100644
index 00000000..b849e402
--- /dev/null
+++ b/mkinitrd/Makefile
@@ -0,0 +1,13 @@
+CPPFLAGS=-I..
+CXXFLAGS=-Wall
+
+BINARIES=mkinitrd lsinitrd catinitrd
+
+all: $(BINARIES)
+
+%: %.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+
+clean:
+ rm -f $(BINARIES)
+
diff --git a/mkinitrd/catinitrd.cpp b/mkinitrd/catinitrd.cpp
new file mode 100644
index 00000000..ed9c1005
--- /dev/null
+++ b/mkinitrd/catinitrd.cpp
@@ -0,0 +1,223 @@
+/******************************************************************************
+
+ COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
+
+ This file is part of Sortix.
+
+ Sortix 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, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along
+ with Sortix. If not, see .
+
+ catinitrd.cpp
+ Output files in a Sortix ramdisk.
+
+******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+bool writeall(int fd, const void* p, size_t size)
+{
+ const uint8_t* buffer = (const uint8_t*) p;
+
+ size_t bytesWritten = 0;
+
+ while ( bytesWritten < size )
+ {
+ ssize_t written = write(fd, buffer + bytesWritten, size - bytesWritten);
+ if ( written < 0 ) { return false; }
+ bytesWritten += written;
+ }
+
+ return true;
+}
+
+bool readall(int fd, void* p, size_t size)
+{
+ uint8_t* buffer = (uint8_t*) p;
+
+ size_t bytesread = 0;
+
+ while ( bytesread < size )
+ {
+ ssize_t justread = read(fd, buffer + bytesread, size - bytesread);
+ if ( justread <= 0 ) { return false; }
+ bytesread += justread;
+ }
+
+ return true;
+}
+
+void usage(int argc, char* argv[])
+{
+ printf("usage: %s [OPTIONS] [files]\n", argv[0]);
+ printf("Options:\n");
+ printf(" -q Surpress normal output\n");
+ printf(" -v Be verbose\n");
+ printf(" --usage Display this screen\n");
+ printf(" --help Display this screen\n");
+ printf(" --version Display version information\n");
+}
+
+void version()
+{
+ printf("catinitrd 0.1\n");
+ printf("Copyright (C) 2011 Jonas 'Sortie' Termansen\n");
+ printf("This is free software; see the source for copying conditions. There is NO\n");
+ printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+ printf("website: http://www.maxsi.org/software/sortix/\n");
+}
+
+bool verbose = false;
+
+int main(int argc, char* argv[])
+{
+ if ( argc < 2 ) { usage(argc, argv); return 0; }
+
+ const char* src = NULL;
+
+ for ( int i = 1; i < argc; i++ )
+ {
+ if ( strcmp(argv[i], "-q") == 0 )
+ {
+ verbose = false;
+ argv[i] = NULL;
+ }
+ else if ( strcmp(argv[i], "-v") == 0 )
+ {
+ verbose = true;
+ argv[i] = NULL;
+ }
+ else if ( strcmp(argv[i], "--usage") == 0 )
+ {
+ usage(argc, argv);
+ return 0;
+ }
+ else if ( strcmp(argv[i], "--help") == 0 )
+ {
+ usage(argc, argv);
+ return 0;
+ }
+ else if ( strcmp(argv[i], "--version") == 0 )
+ {
+ version();
+ return 0;
+ }
+ else if ( src == NULL )
+ {
+ src = argv[i];
+ argv[i] = NULL;
+ }
+ }
+
+ int fd = open(src, O_RDONLY);
+ if ( fd < 0 ) { error(0, errno, "%s", src); return 1; }
+
+ Sortix::InitRD::Header header;
+ if ( !readall(fd, &header, sizeof(header)) )
+ {
+ error(0, errno, "read: %s", src);
+ close(fd);
+ return 1;
+ }
+
+ if ( strcmp(header.magic, "sortix-initrd-1") != 0 )
+ {
+ error(0, 0, "not a sortix ramdisk: %s", src);
+ close(fd);
+ return 1;
+ }
+
+ int result = 0;
+
+ for ( int i = 1; i < argc; i++ )
+ {
+ if ( argv[i] == NULL ) { continue; }
+
+ bool found = false;
+
+ for ( uint32_t n = 0; n < header.numfiles; n++ )
+ {
+ off_t fileheaderpos = sizeof(header) + n * sizeof(Sortix::InitRD::FileHeader);
+ if ( lseek(fd, fileheaderpos, SEEK_SET ) < 0 )
+ {
+ error(0, errno, "seek: %s", src);
+ close(fd);
+ return 1;
+ }
+
+ Sortix::InitRD::FileHeader fileheader;
+ if ( !readall(fd, &fileheader, sizeof(fileheader)) )
+ {
+ error(0, errno, "read: %s", src);
+ close(fd);
+ return 1;
+ }
+
+ if ( strcmp(argv[i], fileheader.name) != 0 ) { continue; }
+
+ found = true;
+
+ if ( lseek(fd, fileheader.offset, SEEK_SET ) < 0 )
+ {
+ error(0, errno, "seek: %s", src);
+ close(fd);
+ return 1;
+ }
+
+ const size_t BUFFER_SIZE = 16384UL;
+ uint8_t buffer[BUFFER_SIZE];
+
+ uint32_t filesize = fileheader.size;
+ uint32_t readsofar = 0;
+ while ( readsofar < filesize )
+ {
+ uint32_t left = filesize-readsofar;
+ size_t toread = (left < BUFFER_SIZE) ? left : BUFFER_SIZE;
+ ssize_t bytesread = read(fd, buffer, toread);
+ if ( bytesread <= 0 )
+ {
+ error(0, errno, "read: %s", src);
+ close(fd);
+ return 1;
+ }
+
+ if ( !writeall(1, buffer, bytesread) )
+ {
+ error(0, errno, "write: ");
+ close(fd);
+ return 1;
+ }
+
+ readsofar += bytesread;
+ }
+ }
+
+ if ( !found )
+ {
+ result |= 1;
+ error(0, ENOENT, "%s", argv[i]);
+ }
+ }
+
+ close(fd);
+
+ return result;
+}
diff --git a/mkinitrd/lsinitrd.cpp b/mkinitrd/lsinitrd.cpp
new file mode 100644
index 00000000..3c523bce
--- /dev/null
+++ b/mkinitrd/lsinitrd.cpp
@@ -0,0 +1,155 @@
+/******************************************************************************
+
+ COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
+
+ This file is part of Sortix.
+
+ Sortix 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, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along
+ with Sortix. If not, see .
+
+ lsinitrd.cpp
+ Lists the files in a Sortix ramdisk.
+
+******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+bool readall(int fd, void* p, size_t size)
+{
+ uint8_t* buffer = (uint8_t*) p;
+
+ size_t bytesread = 0;
+
+ while ( bytesread < size )
+ {
+ ssize_t justread = read(fd, buffer + bytesread, size - bytesread);
+ if ( justread <= 0 ) { return false; }
+ bytesread += justread;
+ }
+
+ return true;
+}
+
+void usage(int argc, char* argv[])
+{
+ printf("usage: %s [OPTIONS] \n", argv[0]);
+ printf("Options:\n");
+ printf(" -q Surpress normal output\n");
+ printf(" -v Be verbose\n");
+ printf(" --usage Display this screen\n");
+ printf(" --help Display this screen\n");
+ printf(" --version Display version information\n");
+}
+
+void version()
+{
+ printf("lsinitrd 0.1\n");
+ printf("Copyright (C) 2011 Jonas 'Sortie' Termansen\n");
+ printf("This is free software; see the source for copying conditions. There is NO\n");
+ printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+ printf("website: http://www.maxsi.org/software/sortix/\n");
+}
+
+bool verbose = false;
+
+int listfiles(const char* filepath)
+{
+ int fd = open(filepath, O_RDONLY);
+ if ( fd < 0 ) { error(0, errno, "%s", filepath); return 1; }
+
+ Sortix::InitRD::Header header;
+ if ( !readall(fd, &header, sizeof(header)) )
+ {
+ error(0, errno, "read: %s", filepath);
+ close(fd);
+ return 1;
+ }
+
+ if ( strcmp(header.magic, "sortix-initrd-1") != 0 )
+ {
+ error(0, 0, "not a sortix ramdisk: %s", filepath);
+ close(fd);
+ return 1;
+ }
+
+ for ( uint32_t i = 0; i < header.numfiles; i++ )
+ {
+ Sortix::InitRD::FileHeader fileheader;
+ if ( !readall(fd, &fileheader, sizeof(fileheader)) )
+ {
+ error(0, errno, "read: %s", filepath);
+ close(fd);
+ return 1;
+ }
+
+ printf("%s\n", fileheader.name);
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ if ( argc < 2 ) { usage(argc, argv); return 0; }
+
+ for ( int i = 1; i < argc; i++ )
+ {
+ if ( strcmp(argv[i], "-q") == 0 )
+ {
+ verbose = false;
+ argv[i] = NULL;
+ }
+ else if ( strcmp(argv[i], "-v") == 0 )
+ {
+ verbose = true;
+ argv[i] = NULL;
+ }
+ else if ( strcmp(argv[i], "--usage") == 0 )
+ {
+ usage(argc, argv);
+ return 0;
+ }
+ else if ( strcmp(argv[i], "--help") == 0 )
+ {
+ usage(argc, argv);
+ return 0;
+ }
+ else if ( strcmp(argv[i], "--version") == 0 )
+ {
+ version();
+ return 0;
+ }
+ }
+
+ int result = 0;
+
+ for ( int i = 1; i < argc; i++ )
+ {
+ if ( argv[i] == NULL ) { continue; }
+
+ result |= listfiles(argv[i]);
+ }
+
+ return result;
+}
diff --git a/mkinitrd/mkinitrd.cpp b/mkinitrd/mkinitrd.cpp
new file mode 100644
index 00000000..fba94a78
--- /dev/null
+++ b/mkinitrd/mkinitrd.cpp
@@ -0,0 +1,263 @@
+/******************************************************************************
+
+ COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
+
+ This file is part of Sortix.
+
+ Sortix 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, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along
+ with Sortix. If not, see .
+
+ mkinitrd.cpp
+ Produces a simple ramdisk meant for bootstrapping the Sortix kernel.
+
+******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+bool writeall(int fd, const void* p, size_t size)
+{
+ const uint8_t* buffer = (const uint8_t*) p;
+
+ size_t bytesWritten = 0;
+
+ while ( bytesWritten < size )
+ {
+ ssize_t written = write(fd, buffer + bytesWritten, size - bytesWritten);
+ if ( written < 0 ) { return false; }
+ bytesWritten += written;
+ }
+
+ return true;
+}
+
+void usage(int argc, char* argv[])
+{
+ printf("usage: %s [OPTIONS] \n", argv[0]);
+ printf("Options:\n");
+ printf(" -o Write the ramdisk to this file\n");
+ printf(" -q Surpress normal output\n");
+ printf(" -v Be verbose\n");
+ printf(" --usage Display this screen\n");
+ printf(" --help Display this screen\n");
+ printf(" --version Display version information\n");
+}
+
+void version()
+{
+ printf("mkinitrd 0.1\n");
+ printf("Copyright (C) 2011 Jonas 'Sortie' Termansen\n");
+ printf("This is free software; see the source for copying conditions. There is NO\n");
+ printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+ printf("website: http://www.maxsi.org/software/sortix/\n");
+}
+
+bool verbose = false;
+
+int main(int argc, char* argv[])
+{
+ const char* dest = NULL;
+
+ if ( argc < 2 ) { usage(argc, argv); return 0; }
+
+ uint32_t numfiles = 0;
+
+ for ( int i = 1; i < argc; i++ )
+ {
+ if ( strcmp(argv[i], "-o") == 0 )
+ {
+ if ( i + 1 < argc )
+ {
+ dest = argv[i+1];
+ argv[i+1] = NULL;
+ }
+ argv[i] = NULL;
+ i++;
+ }
+ else if ( strcmp(argv[i], "-q") == 0 )
+ {
+ verbose = false;
+ argv[i] = NULL;
+ }
+ else if ( strcmp(argv[i], "-v") == 0 )
+ {
+ verbose = true;
+ argv[i] = NULL;
+ }
+ else if ( strcmp(argv[i], "--usage") == 0 )
+ {
+ usage(argc, argv);
+ return 0;
+ }
+ else if ( strcmp(argv[i], "--help") == 0 )
+ {
+ usage(argc, argv);
+ return 0;
+ }
+ else if ( strcmp(argv[i], "--version") == 0 )
+ {
+ version();
+ return 0;
+ }
+ else
+ {
+ numfiles++;
+ }
+ }
+
+ if ( dest == NULL )
+ {
+ fprintf(stderr, "%s: no output file specified\n", argv[0]);
+ return 0;
+ }
+
+ int fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ if ( fd < 0 )
+ {
+ error(0, errno, "%s", dest);
+ return 1;
+ }
+
+ // Write the initrd headers.
+ Sortix::InitRD::Header header;
+ memset(&header, 0, sizeof(header));
+ strcpy(header.magic, "sortix-initrd-1");
+ header.numfiles = numfiles;
+ if ( !writeall(fd, &header, sizeof(header)) )
+ {
+ error(0, errno, "write: %s", dest);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ uint32_t fileoffset = sizeof(header) + numfiles * sizeof(Sortix::InitRD::FileHeader);
+
+ uint32_t filenum = 0;
+ for ( int i = 1; i < argc; i++ )
+ {
+ const char* file = argv[i];
+
+ if ( file == NULL ) { continue; }
+
+ Sortix::InitRD::FileHeader fileheader;
+ memset(&fileheader, 0, sizeof(fileheader));
+
+ if ( sizeof(fileheader.name) - 1 < strlen(file) )
+ {
+ fprintf(stderr, "%s: file name is too long: %s\n", argv[0], file);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ int filefd = open(file, O_RDONLY);
+ if ( filefd < 0 )
+ {
+ error(0, errno, "%s", file);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ if ( verbose )
+ {
+ fprintf(stderr, "%s\n", file);
+ }
+
+ struct stat st;
+ if ( fstat(filefd, &st) != 0 )
+ {
+ error(0, errno, "stat: %s", file);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ uint32_t filesize = st.st_size;
+ fileheader.permissions = 0755;
+ fileheader.size = filesize;
+ fileheader.owner = 1;
+ fileheader.group = 1;
+ fileheader.offset = fileoffset;
+ strcpy(fileheader.name, file);
+
+ off_t fileheaderpos = sizeof(header) + filenum * sizeof(Sortix::InitRD::FileHeader);
+ if ( lseek(fd, fileheaderpos, SEEK_SET ) < 0 )
+ {
+ error(0, errno, "seek: %s", dest);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ if ( !writeall(fd, &fileheader, sizeof(fileheader)) )
+ {
+ error(0, errno, "write: %s", dest);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ if ( lseek(fd, fileoffset, SEEK_SET ) < 0 )
+ {
+ error(0, errno, "seek: %s", dest);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ const size_t BUFFER_SIZE = 16384UL;
+ uint8_t buffer[BUFFER_SIZE];
+
+ uint32_t readsofar = 0;
+ while ( readsofar < filesize )
+ {
+ uint32_t left = filesize-readsofar;
+ size_t toread = (left < BUFFER_SIZE) ? left : BUFFER_SIZE;
+ ssize_t bytesread = read(filefd, buffer, toread);
+ if ( bytesread <= 0 )
+ {
+ error(0, errno, "read: %s", file);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ if ( !writeall(fd, buffer, bytesread) )
+ {
+ error(0, errno, "write: %s", dest);
+ close(fd);
+ unlink(dest);
+ return 1;
+ }
+
+ readsofar += bytesread;
+ }
+
+ fileoffset += filesize;
+ filenum++;
+
+ close(filefd);
+ }
+
+ return 0;
+}
diff --git a/sortix/initrd.h b/sortix/initrd.h
new file mode 100644
index 00000000..39171156
--- /dev/null
+++ b/sortix/initrd.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+
+ COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
+
+ This file is part of Sortix.
+
+ Sortix 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, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along
+ with Sortix. If not, see .
+
+ initrd.h
+ Declares the structure of the Sortix ramdisk.
+
+******************************************************************************/
+
+#ifndef SORTIX_INITRD_H
+#define SORTIX_INITRD_H
+
+namespace Sortix
+{
+ namespace InitRD
+ {
+ struct Header;
+ struct FileHeader;
+
+ struct Header
+ {
+ char magic[16]; // Contains "sortix-initrd-1"
+ uint32_t numfiles;
+ // FileHeader[numfiles];
+ };
+
+ struct FileHeader
+ {
+ mode_t permissions;
+ uid_t owner;
+ gid_t group;
+ uint32_t size;
+ uint32_t offset; // where the physical data is located.
+ char name[128];
+ };
+ }
+}
+
+#endif