Remove mkinitrd(8).

This commit is contained in:
Jonas 'Sortie' Termansen 2023-07-16 14:56:31 +02:00
parent 6ac0061380
commit 4533a2ade2
16 changed files with 3 additions and 2393 deletions

View File

@ -27,7 +27,6 @@ init \
kblayout \
kblayout-compiler \
login \
mkinitrd \
ping \
regress \
rw \
@ -101,7 +100,6 @@ sysmerge-wait: sysroot
clean-build-tools:
$(MAKE) -C carray clean
$(MAKE) -C kblayout-compiler clean
$(MAKE) -C mkinitrd clean
$(MAKE) -C sf clean
$(MAKE) -C tix clean
@ -109,7 +107,6 @@ clean-build-tools:
build-tools:
$(MAKE) -C carray
$(MAKE) -C kblayout-compiler
$(MAKE) -C mkinitrd
$(MAKE) -C sf
$(MAKE) -C tix
@ -117,7 +114,6 @@ build-tools:
install-build-tools:
$(MAKE) -C carray install
$(MAKE) -C kblayout-compiler install
$(MAKE) -C mkinitrd install
$(MAKE) -C sf install
$(MAKE) -C tix install

View File

@ -1,92 +0,0 @@
/*
* Copyright (c) 2012, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* sortix/initrd.h
* The Sortix init ramdisk filesystem format.
*/
#ifndef _INCLUDE_SORTIX_INITRD_H
#define _INCLUDE_SORTIX_INITRD_H
#include <stdint.h>
#define INITRD_ALGO_CRC32 0
#define INITRD_ALGO_NONE 1
#define INITRD_S_IXOTH 01
#define INITRD_S_IWOTH 02
#define INITRD_S_IROTH 03
#define INITRD_S_IRWXO 07
#define INITRD_S_IXGRP 010
#define INITRD_S_IWGRP 020
#define INITRD_S_IRGRP 040
#define INITRD_S_IRWXG 070
#define INITRD_S_IXUSR 0100
#define INITRD_S_IWUSR 0200
#define INITRD_S_IRUSR 0400
#define INITRD_S_IRWXU 0700
#define INITRD_S_IFMT 0xF000
#define INITRD_S_IFSOCK 0xC000
#define INITRD_S_IFLNK 0xA000
#define INITRD_S_IFREG 0x8000
#define INITRD_S_IFBLK 0x6000
#define INITRD_S_IFDIR 0x4000
#define INITRD_S_IFCHR 0x2000
#define INITRD_S_IFIFO 0x1000
#define INITRD_S_ISUID 0x0800
#define INITRD_S_ISGID 0x0400
#define INITRD_S_ISVTX 0x0200
#define INITRD_S_ISSOCK(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFSOCK)
#define INITRD_S_ISLNK(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFLNK)
#define INITRD_S_ISREG(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFREG)
#define INITRD_S_ISBLK(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFBLK)
#define INITRD_S_ISDIR(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFDIR)
#define INITRD_S_ISCHR(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFCHR)
#define INITRD_S_ISFIFO(mode) ((mode & INITRD_S_IFMT) == INITRD_S_IFIFO)
typedef struct initrd_superblock
{
char magic[16]; /* "sortix-initrd-2" */
uint32_t fssize;
uint32_t revision;
uint32_t inodesize;
uint32_t inodecount;
uint32_t inodeoffset;
uint32_t root;
uint32_t sumalgorithm;
uint32_t sumsize;
} initrd_superblock_t;
typedef struct initrd_inode
{
uint32_t mode;
uint32_t uid;
uint32_t gid;
uint32_t nlink;
uint64_t ctime;
uint64_t mtime;
uint32_t dataoffset;
uint32_t size;
} initrd_inode_t;
typedef struct initrd_dirent
{
uint32_t inode;
uint16_t reclen;
uint16_t namelen;
char name[0];
} initrd_dirent_t;
#endif

View File

@ -31,7 +31,6 @@
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#include <sortix/initrd.h>
#include <sortix/mman.h>
#include <sortix/stat.h>
#include <sortix/tar.h>
@ -51,17 +50,12 @@
namespace Sortix {
// TODO: The initrd is not being properly verified.
// TODO: The initrd is not handled in an endian-neutral manner.
struct initrd_context
{
uint8_t* initrd;
size_t initrd_size;
addr_t initrd_unmap_start;
addr_t initrd_unmap_end;
struct initrd_superblock* sb;
Ref<Descriptor> links;
ioctx_t ioctx;
};
@ -81,262 +75,6 @@ static void UnmapInitrdPage(struct initrd_context* ctx, addr_t vaddr)
Page::Put(addr, PAGE_USAGE_WASNT_ALLOCATED);
}
static mode_t initrd_mode_to_host_mode(uint32_t mode)
{
mode_t result = mode & 0777;
if ( INITRD_S_ISVTX & mode ) result |= S_ISVTX;
if ( INITRD_S_ISSOCK(mode) ) result |= S_IFSOCK;
if ( INITRD_S_ISLNK(mode) ) result |= S_IFLNK;
if ( INITRD_S_ISREG(mode) ) result |= S_IFREG;
if ( INITRD_S_ISBLK(mode) ) result |= S_IFBLK;
if ( INITRD_S_ISDIR(mode) ) result |= S_IFDIR;
if ( INITRD_S_ISCHR(mode) ) result |= S_IFCHR;
if ( INITRD_S_ISFIFO(mode) ) result |= S_IFIFO;
return result;
}
static struct initrd_inode* initrd_get_inode(struct initrd_context* ctx,
uint32_t inode)
{
if ( ctx->sb->inodecount <= inode )
return errno = EINVAL, (struct initrd_inode*) NULL;
uint32_t pos = ctx->sb->inodeoffset + ctx->sb->inodesize * inode;
return (struct initrd_inode*) (ctx->initrd + pos);
}
static uint8_t* initrd_inode_get_data(struct initrd_context* ctx,
struct initrd_inode* inode,
size_t* size)
{
return *size = inode->size, ctx->initrd + inode->dataoffset;
}
static uint32_t initrd_directory_open(struct initrd_context* ctx,
struct initrd_inode* inode,
const char* name)
{
if ( !INITRD_S_ISDIR(inode->mode) )
return errno = ENOTDIR, 0;
uint32_t offset = 0;
while ( offset < inode->size )
{
uint32_t pos = inode->dataoffset + offset;
struct initrd_dirent* dirent =
(struct initrd_dirent*) (ctx->initrd + pos);
if ( dirent->namelen && !strcmp(dirent->name, name) )
return dirent->inode;
offset += dirent->reclen;
}
return errno = ENOENT, 0;
}
static const char* initrd_directory_get_filename(struct initrd_context* ctx,
struct initrd_inode* inode,
size_t index)
{
if ( !INITRD_S_ISDIR(inode->mode) )
return errno = ENOTDIR, (const char*) NULL;
uint32_t offset = 0;
while ( offset < inode->size )
{
uint32_t pos = inode->dataoffset + offset;
struct initrd_dirent* dirent =
(struct initrd_dirent*) (ctx->initrd + pos);
if ( index-- == 0 )
return dirent->name;
offset += dirent->reclen;
}
return errno = EINVAL, (const char*) NULL;
}
static size_t initrd_directory_get_num_files(struct initrd_context* ctx,
struct initrd_inode* inode)
{
if ( !INITRD_S_ISDIR(inode->mode) )
return errno = ENOTDIR, 0;
uint32_t offset = 0;
size_t numentries = 0;
while ( offset < inode->size )
{
uint32_t pos = inode->dataoffset + offset;
const struct initrd_dirent* dirent =
(const struct initrd_dirent*) (ctx->initrd + pos);
numentries++;
offset += dirent->reclen;
}
return numentries;
}
static void ExtractNode(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> node);
static void ExtractFile(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> file)
{
size_t filesize;
uint8_t* data = initrd_inode_get_data(ctx, inode, &filesize);
if ( file->truncate(&ctx->ioctx, filesize) != 0 )
PanicF("initrd: truncate: %m");
size_t sofar = 0;
while ( sofar < filesize )
{
size_t left = filesize - sofar;
size_t chunk = 1024 * 1024;
size_t count = left < chunk ? left : chunk;
ssize_t numbytes = file->write(&ctx->ioctx, data + sofar, count);
if ( numbytes <= 0 )
PanicF("initrd: write: %m");
sofar += numbytes;
}
}
static void ExtractDir(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> dir)
{
size_t numfiles = initrd_directory_get_num_files(ctx, inode);
for ( size_t i = 0; i < numfiles; i++ )
{
const char* name = initrd_directory_get_filename(ctx, inode, i);
if ( !name )
PanicF("initrd_directory_get_filename: %m");
if ( IsDotOrDotDot(name) )
continue;
uint32_t childino = initrd_directory_open(ctx, inode, name);
if ( !childino )
PanicF("initrd_directory_open: %s: %m", name);
struct initrd_inode* child =
(struct initrd_inode*) initrd_get_inode(ctx, childino);
if ( !child )
PanicF("initrd_get_inode(%u): %s: %m", childino, name);
mode_t mode = initrd_mode_to_host_mode(child->mode);
if ( INITRD_S_ISDIR(child->mode) )
{
if ( dir->mkdir(&ctx->ioctx, name, mode) && errno != EEXIST )
PanicF("initrd: mkdir: %s: %m", name);
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name,
O_SEARCH | O_DIRECTORY, 0);
if ( !desc )
PanicF("initrd: %s: %m", name);
ExtractNode(ctx, child, desc);
}
if ( INITRD_S_ISREG(child->mode) )
{
assert(child->nlink != 0);
char link_path[sizeof(childino) * 3];
snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino);
Ref<Descriptor> existing(ctx->links->open(&ctx->ioctx, link_path,
O_READ, 0));
if ( !existing || dir->link(&ctx->ioctx, name, existing) != 0 )
{
Ref<Descriptor> desc(dir->open(&ctx->ioctx, name,
O_WRITE | O_CREATE, mode));
if ( !desc )
PanicF("initrd: %s: %m", name);
ExtractNode(ctx, child, desc);
if ( 2 <= child->nlink )
ctx->links->link(&ctx->ioctx, link_path, desc);
}
if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) )
{
size_t filesize;
const uint8_t* data =
initrd_inode_get_data(ctx, child, &filesize);
uintptr_t from = (uintptr_t) data;
uintptr_t size = filesize;
uintptr_t from_aligned = Page::AlignUp(from);
uintptr_t from_distance = from_aligned - from;
if ( from_distance <= size )
{
uintptr_t size_aligned =
Page::AlignDown(size - from_distance);
for ( size_t i = 0; i < size_aligned; i += Page::Size() )
UnmapInitrdPage(ctx, from_aligned + i);
Memory::Flush();
}
}
}
if ( INITRD_S_ISLNK(child->mode) )
{
size_t filesize;
uint8_t* data = initrd_inode_get_data(ctx, child, &filesize);
char* oldname = new char[filesize + 1];
if ( !oldname )
PanicF("initrd: malloc: %m");
memcpy(oldname, data, filesize);
oldname[filesize] = '\0';
int ret = dir->symlink(&ctx->ioctx, oldname, name);
delete[] oldname;
if ( ret < 0 )
PanicF("initrd: symlink: %s", name);
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name,
O_READ | O_SYMLINK_NOFOLLOW, 0);
if ( desc )
ExtractNode(ctx, child, desc);
}
}
}
static void ExtractNode(struct initrd_context* ctx,
struct initrd_inode* inode,
Ref<Descriptor> node)
{
if ( node->chmod(&ctx->ioctx, initrd_mode_to_host_mode(inode->mode)) < 0 )
PanicF("initrd: chmod: %m");
if ( node->chown(&ctx->ioctx, inode->uid, inode->gid) < 0 )
PanicF("initrd: chown: %m");
if ( INITRD_S_ISDIR(inode->mode) )
ExtractDir(ctx, inode, node);
if ( INITRD_S_ISREG(inode->mode) )
ExtractFile(ctx, inode, node);
struct timespec times[2];
times[0] = timespec_make((time_t) inode->mtime, 0);
times[1] = timespec_make((time_t) inode->mtime, 0);
if ( node->utimens(&ctx->ioctx, times) < 0 )
PanicF("initrd: utimens: %m");
}
static void ExtractInitrd(Ref<Descriptor> desc, struct initrd_context* ctx)
{
ctx->sb = (struct initrd_superblock*) ctx->initrd;
if ( ctx->initrd_size < ctx->sb->fssize )
Panic("Initrd header does not match its size");
if ( desc->mkdir(&ctx->ioctx, ".initrd-links", 0777) != 0 )
PanicF("initrd: .initrd-links: %m");
if ( !(ctx->links = desc->open(&ctx->ioctx, ".initrd-links",
O_READ | O_DIRECTORY, 0)) )
PanicF("initrd: .initrd-links: %m");
struct initrd_inode* root = initrd_get_inode(ctx, ctx->sb->root);
if ( !root )
PanicF("initrd: initrd_get_inode(%u): %m", ctx->sb->root);
ExtractNode(ctx, root, desc);
union
{
struct dirent dirent;
uint8_t dirent_data[sizeof(struct dirent) + sizeof(uintmax_t) * 3];
};
while ( 0 < ctx->links->readdirents(&ctx->ioctx, &dirent, sizeof(dirent_data)) &&
((const char*) dirent.d_name)[0] )
{
if ( ((const char*) dirent.d_name)[0] == '.' )
continue;
ctx->links->unlinkat(&ctx->ioctx, dirent.d_name, AT_REMOVEFILE);
ctx->links->lseek(&ctx->ioctx, 0, SEEK_SET);
}
ctx->links.Reset();
desc->unlinkat(&ctx->ioctx, ".initrd-links", AT_REMOVEDIR);
}
struct TAR
{
unsigned char* tar_file;
@ -614,9 +352,10 @@ static void ExtractModule(struct multiboot_mod_list* module,
else if ( !strncmp(cmdline, "--create-to ", strlen("--create-to ")) ||
!strncmp(cmdline, "--create-to=", strlen("--create-to=")) )
ExtractTo(desc, ctx, cmdline + strlen("--create-to "), O_EXCL);
else if ( sizeof(struct initrd_superblock) <= ctx->initrd_size &&
// TODO: After releasing Sortix 1.1, remove this nice error message.
else if ( strlen("sortix-initrd-2") <= ctx->initrd_size &&
!memcmp(ctx->initrd, "sortix-initrd-2", strlen("sortix-initrd-2")) )
ExtractInitrd(desc, ctx);
Panic("The sortix-initrd-2 format is no longer supported");
else if ( sizeof(struct tar) <= ctx->initrd_size &&
!memcmp(ctx->initrd + offsetof(struct tar, magic), "ustar", 5) )
ExtractTar(desc, ctx);
@ -640,7 +379,6 @@ static void ExtractModule(struct multiboot_mod_list* module,
UnmapInitrdPage(ctx, mapat + i);
Memory::Flush();
// Free the used virtual address space.
FreeKernelAddress(&initrd_addr_alloc);
}

2
mkinitrd/.gitignore vendored
View File

@ -1,2 +0,0 @@
mkinitrd
initrdfs

View File

@ -1,35 +0,0 @@
include ../build-aux/platform.mak
include ../build-aux/compiler.mak
include ../build-aux/version.mak
include ../build-aux/dirs.mak
OPTLEVEL?=$(DEFAULT_OPTLEVEL)
CFLAGS?=$(OPTLEVEL)
SORTIXKERNEL=../kernel
CPPFLAGS:=$(CPPFLAGS) -DVERSIONSTR=\"$(VERSION)\" -I$(SORTIXKERNEL)/include -I.
CFLAGS:=$(CFLAGS) -Wall -Wextra
ifeq ($(HOST_IS_SORTIX),0)
CPPFLAGS+=-D_GNU_SOURCE
endif
BINARIES=mkinitrd initrdfs
all: $(BINARIES)
.PHONY: all install clean
%: %.c rules.c serialize.c
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $< rules.c serialize.c -o $@
clean:
rm -f $(BINARIES)
install: all
mkdir -p $(DESTDIR)$(SBINDIR)
install $(BINARIES) $(DESTDIR)$(SBINDIR)
mkdir -p $(DESTDIR)$(MANDIR)/man8
cp initrdfs.8 $(DESTDIR)$(MANDIR)/man8/initrdfs.8
cp mkinitrd.8 $(DESTDIR)$(MANDIR)/man8/mkinitrd.8

View File

@ -1,67 +0,0 @@
.Dd October 7, 2015
.Dt INITRDFS 8
.Os
.Sh NAME
.Nm initrdfs
.Nd view initialization ramdisk
.Sh SYNOPSIS
.Nm
.Ar initrd
cat
.Ar path ...
.Nm
.Ar initrd
extract
.Op Fl C Ar destination
.Ar path ...
.Nm
.Ar initrd
ls
.Op Fl a
.Ar path ...
.Sh DESCRIPTION
.Nm
opens a
.Xr initrd 7
made with
.Xr mkinitrd 8
and lets you view the stored directories and files.
.Pp
The options are as follows:
.Bl -tag -width "12345678"
.It Fl a
.Sy ( ls )
Include directory entries whose names begin with a
dot
.Pq Sq \&. .
.It Fl C Ar destination
.Sy ( extract )
Extract to the specified
.Ar destination
rather than the default current directory.
.El
.Pp
.Nm
supports these commands:
.Bl -tag -width "12345678"
.It Sy cat
Show the contents of each
.Ar path .
.It Sy extract
Extract each
.Ar path
recursively to the current directory.
.It Sy ls
List each directory
.Ar path .
.El
.Sh EXIT STATUS
.Nm
will exit 0 on success and non-zero otherwise.
.Sh SEE ALSO
.Xr initrd 7 ,
.Xr mkinitrd 8
.Sh BUGS
.Nm
is feature limited and doesn't let you view all the contained meta information.
It's also not a filesystem driver.

View File

@ -1,395 +0,0 @@
/*
* Copyright (c) 2012, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* initrdfs.c
* Provides access to filesystems in the Sortix kernel initrd format.
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <ioleast.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sortix/initrd.h>
#include "serialize.h"
char* Substring(const char* str, size_t start, size_t length)
{
char* result = (char*) malloc(length+1);
strncpy(result, str + start, length);
result[length] = 0;
return result;
}
bool ReadSuperBlock(int fd, initrd_superblock_t* dest)
{
if ( preadall(fd, dest, sizeof(*dest), 0) != sizeof(*dest) )
return false;
import_initrd_superblock(dest);
return true;
}
initrd_superblock_t* GetSuperBlock(int fd)
{
size_t sbsize = sizeof(initrd_superblock_t);
initrd_superblock_t* sb = (initrd_superblock_t*) malloc(sbsize);
if ( !sb ) { return NULL; }
if ( !ReadSuperBlock(fd, sb) ) { free(sb); return NULL; }
return sb;
}
bool ReadInode(int fd, initrd_superblock_t* sb, uint32_t ino,
initrd_inode_t* dest)
{
uint32_t inodepos = sb->inodeoffset + sb->inodesize * ino;
if ( preadall(fd, dest, sizeof(*dest), inodepos) != sizeof(*dest) )
return false;
import_initrd_inode(dest);
return true;
}
initrd_inode_t* GetInode(int fd, initrd_superblock_t* sb, uint32_t ino)
{
initrd_inode_t* inode = (initrd_inode_t*) malloc(sizeof(initrd_inode_t));
if ( !inode ) { return NULL; }
if ( !ReadInode(fd, sb, ino, inode) ) { free(inode); return NULL; }
return inode;
}
initrd_inode_t* CloneInode(const initrd_inode_t* src)
{
initrd_inode_t* result = (initrd_inode_t*) malloc(sizeof(*src));
if ( !result ) { return NULL; }
memcpy(result, src, sizeof(*src));
return result;
}
bool ReadInodeData(int fd, initrd_superblock_t* sb, initrd_inode_t* inode,
uint8_t* dest, size_t size, off_t offset)
{
(void) sb;
if ( offset < 0 )
return errno = EINVAL, false;
if ( inode->size < (uintmax_t) offset )
return errno = EINVAL, false;
size_t available = inode->size - offset;
if ( inode->size < available )
return errno = EINVAL, false;
return preadall(fd, dest, size, inode->dataoffset + offset) == size;
}
uint8_t* GetInodeDataSize(int fd, initrd_superblock_t* sb,
initrd_inode_t* inode, size_t size)
{
uint8_t* buf = (uint8_t*) malloc(size);
if ( !buf )
return NULL;
if ( !ReadInodeData(fd, sb, inode, buf, size, 0) )
{
free(buf);
return NULL;
}
return buf;
}
uint8_t* GetInodeData(int fd, initrd_superblock_t* sb, initrd_inode_t* inode)
{
return GetInodeDataSize(fd, sb, inode, inode->size);
}
uint32_t Traverse(int fd, initrd_superblock_t* sb, initrd_inode_t* inode,
const char* name)
{
if ( !INITRD_S_ISDIR(inode->mode) ) { errno = ENOTDIR; return 0; }
uint8_t* direntries = GetInodeData(fd, sb, inode);
if ( !direntries ) { return 0; }
uint32_t result = 0;
uint32_t offset = 0;
while ( offset < inode->size )
{
initrd_dirent_t* dirent = (initrd_dirent_t*) (direntries + offset);
import_initrd_dirent(dirent);
if ( dirent->namelen && !strcmp(dirent->name, name) )
{
result = dirent->inode;
export_initrd_dirent(dirent);
break;
}
offset += dirent->reclen;
export_initrd_dirent(dirent);
}
free(direntries);
if ( !result ) { errno = ENOENT; }
return result;
}
initrd_inode_t* ResolvePath(int fd, initrd_superblock_t* sb,
initrd_inode_t* inode, const char* path)
{
if ( !path[0] ) { return CloneInode(inode); }
if ( path[0] == '/' )
{
if ( !INITRD_S_ISDIR(inode->mode) ) { errno = ENOTDIR; return NULL; }
return ResolvePath(fd, sb, inode, path+1);
}
size_t elemlen = strcspn(path, "/");
char* elem = Substring(path, 0, elemlen);
uint32_t ino = Traverse(fd, sb, inode, elem);
free(elem);
if ( !ino ) { return NULL; }
initrd_inode_t* child = GetInode(fd, sb, ino);
if ( !child ) { return NULL; }
if ( !path[elemlen] ) { return child; }
initrd_inode_t* result = ResolvePath(fd, sb, child, path + elemlen);
free(child);
return result;
}
bool ListDirectory(int fd, initrd_superblock_t* sb, initrd_inode_t* dir,
bool all)
{
if ( !INITRD_S_ISDIR(dir->mode) ) { errno = ENOTDIR; return false; }
uint8_t* direntries = GetInodeData(fd, sb, dir);
if ( !direntries ) { return false; }
uint32_t offset = 0;
while ( offset < dir->size )
{
initrd_dirent_t* dirent = (initrd_dirent_t*) (direntries + offset);
if ( dirent->namelen && (all || dirent->name[0] != '.'))
{
printf("%s\n", dirent->name);
}
offset += dirent->reclen;
}
free(direntries);
return true;
}
bool PrintFile(int fd, initrd_superblock_t* sb, initrd_inode_t* inode)
{
if ( INITRD_S_ISDIR(inode->mode ) ) { errno = EISDIR; return false; }
uint32_t sofar = 0;
while ( sofar < inode->size )
{
const size_t BUFFER_SIZE = 16UL * 1024UL;
uint8_t buffer[BUFFER_SIZE];
uint32_t available = inode->size - sofar;
uint32_t count = available < BUFFER_SIZE ? available : BUFFER_SIZE;
if ( !ReadInodeData(fd, sb, inode, buffer, count, 0) ) { return false; }
if ( writeall(1, buffer, count) != count ) { return false; }
sofar += count;
}
return true;
}
void Extract(int fd,
const char* fd_path,
initrd_superblock_t* sb,
initrd_inode_t* inode,
const char* out_path,
bool verbose)
{
if ( verbose )
printf("%s\n", out_path);
if ( INITRD_S_ISLNK(inode->mode) )
{
char* buffer = (char*) malloc(inode->size + 1);
if ( !buffer )
err(1, "malloc");
if ( !ReadInodeData(fd, sb, inode, (uint8_t*) buffer, inode->size, 0) )
err(1, "%s", fd_path);
buffer[inode->size] = '\0';
// TODO: What if it already exists.
if ( symlink(buffer, out_path) < 0 )
err(1, "%s", out_path);
return;
}
else if ( INITRD_S_ISREG(inode->mode) )
{
int out_fd = open(out_path, O_WRONLY | O_CREAT | O_TRUNC, 0200);
if ( out_fd < 0 )
err(1, "%s", out_path);
uint32_t sofar = 0;
while ( sofar < inode->size )
{
const size_t BUFFER_SIZE = 16UL * 1024UL;
uint8_t buffer[BUFFER_SIZE];
uint32_t available = inode->size - sofar;
uint32_t count = available < BUFFER_SIZE ? available : BUFFER_SIZE;
if ( !ReadInodeData(fd, sb, inode, buffer, count, sofar) )
err(1, "%s", fd_path);
if ( writeall(out_fd, buffer, count) != count )
err(1, "%s", out_path);
sofar += count;
}
if ( fchmod(out_fd, inode->mode & 07777) < 0 )
err(1, "%s", out_path);
close(out_fd);
return;
}
else if ( !INITRD_S_ISDIR(inode->mode) )
errx(1, "%s: Unsupported kind of file", out_path);
bool made = true;
if ( mkdir(out_path, 0700) < 0 )
{
if ( errno != EEXIST )
err(1, "%s", out_path);
made = false;
}
uint8_t* direntries = GetInodeData(fd, sb, inode);
if ( !direntries )
err(1, "%s", out_path);
uint32_t offset = 0;
while ( offset < inode->size )
{
initrd_dirent_t* dirent = (initrd_dirent_t*) (direntries + offset);
offset += dirent->reclen;
if ( !dirent->namelen ) // TODO: Possible?
continue;
if ( !strcmp(dirent->name, ".") || !strcmp(dirent->name, "..") )
continue;
char* child_path;
if ( asprintf(&child_path, "%s/%s", out_path, dirent->name) < 0 )
err(1, "asprintf");
initrd_inode_t* child_inode = ResolvePath(fd, sb, inode, dirent->name);
if ( !child_inode )
err(1, "%s: %s", fd_path, out_path);
Extract(fd, fd_path, sb, child_inode, child_path, verbose);
free(child_path);
}
free(direntries);
// TODO: Time of check to time of use race condition, a concurrent rename
// and we may assign the permissions to the wrong file, potentially
// exploitable.
if ( made && chmod(out_path, inode->mode & 07777) < 0 )
err(1, " %s", out_path);
}
static void compact_arguments(int* argc, char*** argv)
{
for ( int i = 0; i < *argc; i++ )
{
while ( i < *argc && !(*argv)[i] )
{
for ( int n = i; n < *argc; n++ )
(*argv)[n] = (*argv)[n+1];
(*argc)--;
}
}
}
int main(int argc, char* argv[])
{
bool all = false;
const char* destination = ".";
bool verbose = false;
for ( int i = 1; i < argc; i++ )
{
const char* arg = argv[i];
if ( arg[0] != '-' || !arg[1] )
continue;
argv[i] = NULL;
if ( !strcmp(arg, "--") )
break;
if ( arg[1] != '-' )
{
char c;
while ( (c = *++arg) ) switch ( c )
{
case 'a': all = true; break;
case 'C':
if ( !*(destination = arg + 1) )
{
if ( i + 1 == argc )
errx(1, "option requires an argument -- 'C'");
destination = argv[i+1];
argv[++i] = NULL;
}
arg = "C";
break;
case 'v': verbose = true; break;
default:
errx(1, "unknown option -- '%c'", c);
}
}
else
errx(1, "unknown option: %s", arg);
}
compact_arguments(&argc, &argv);
if ( argc == 1 )
errx(1, "No initrd specified");
const char* initrd = argv[1];
if ( argc == 2 )
errx(1, "No command specified");
const char* cmd = argv[2];
int fd = open(initrd, O_RDONLY);
if ( fd < 0 )
err(1, "open: %s", initrd);
initrd_superblock_t* sb = GetSuperBlock(fd);
if ( !sb )
err(1, "read: %s", initrd);
initrd_inode_t* root = GetInode(fd, sb, sb->root);
if ( !root )
err(1, "read: %s", initrd);
for ( int i = 3; i < argc; i++ )
{
const char* path = argv[i];
if ( path[0] != '/' )
{
errno = ENOENT;
errx(1, "%s", path);
}
initrd_inode_t* inode = ResolvePath(fd, sb, root, path+1);
if ( !inode )
err(1, "%s", path);
if ( !strcmp(cmd, "cat") )
{
if ( !PrintFile(fd, sb, inode) )
err(1, "%s", path);
}
else if ( !strcmp(cmd, "ls") )
{
if ( !ListDirectory(fd, sb, inode, all) )
err(1, "%s", path);
}
else if ( !strcmp(cmd, "extract") )
Extract(fd, initrd, sb, inode, destination, verbose);
else
errx(1, "unrecognized command: %s", cmd);
free(inode);
}
return 0;
}

View File

@ -1,150 +0,0 @@
/*
* Copyright (c) 2012, 2013, 2015 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ioleast.h
* Versions of {,p}{read,write} that don't return until it has returned as much
* data as requested, end of file, or an error occurs. This is sometimes needed
* as read(2) and write(2) is not always guaranteed to fill up the entire
* buffer or write it all.
*/
#ifndef SORTIX_COMPATIBILITY_INCLUDE_IOLEAST_H
#define SORTIX_COMPATIBILITY_INCLUDE_IOLEAST_H
#if defined(__sortix__) || defined(__sortix_libc__)
#include_next <ioleast.h>
#else
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#if !defined(EEOF) && defined(EIO)
#define EEOF EIO
#endif
__attribute__((unused)) static inline
size_t readleast(int fd, void* buf_ptr, size_t least, size_t max)
{
assert(least <= max);
unsigned char* buf = (unsigned char*) buf_ptr;
size_t done = 0;
do
{
ssize_t amount = read(fd, buf + done, max - done);
if ( amount < 0 )
return done;
if ( !amount && done < least )
return errno = EEOF, done;
if ( !amount )
break;
done += amount;
} while ( done < least );
return done;
}
__attribute__((unused)) static inline
size_t writeleast(int fd, const void* buf_ptr, size_t least, size_t max)
{
assert(least <= max);
const unsigned char* buf = (const unsigned char*) buf_ptr;
size_t done = 0;
do
{
ssize_t amount = write(fd, buf + done, max - done);
if ( amount < 0 )
return done;
if ( !amount && done < least )
return errno = EEOF, done;
if ( !amount )
break;
done += amount;
} while ( done < least );
return done;
}
__attribute__((unused)) static inline
size_t preadleast(int fd, void* buf_ptr, size_t least, size_t max, off_t off)
{
assert(least <= max);
unsigned char* buf = (unsigned char*) buf_ptr;
size_t done = 0;
do
{
ssize_t amount = pread(fd, buf + done, max - done, off + done);
if ( amount < 0 )
return done;
if ( !amount && done < least )
return errno = EEOF, done;
if ( !amount )
break;
done += amount;
} while ( done < least );
return done;
}
__attribute__((unused)) static inline
size_t pwriteleast(int fd, const void* buf_ptr, size_t least, size_t max, off_t off)
{
assert(least <= max);
const unsigned char* buf = (const unsigned char*) buf_ptr;
size_t done = 0;
do
{
ssize_t amount = pwrite(fd, buf + done, max - done, off + done);
if ( amount < 0 )
return done;
if ( !amount && done < least )
return errno = EEOF, done;
if ( !amount )
break;
done += amount;
} while ( done < least );
return done;
}
__attribute__((unused)) static inline
size_t readall(int fd, void* buf, size_t count)
{
return readleast(fd, buf, count, count);
}
__attribute__((unused)) static inline
size_t writeall(int fd, const void* buf, size_t count)
{
return writeleast(fd, buf, count, count);
}
__attribute__((unused)) static inline
size_t preadall(int fd, void* buf, size_t count, off_t off)
{
return preadleast(fd, buf, count, count, off);
}
__attribute__((unused)) static inline
size_t pwriteall(int fd, const void* buf, size_t count, off_t off)
{
return pwriteleast(fd, buf, count, count, off);
}
#endif
#endif

View File

@ -1,126 +0,0 @@
.Dd October 7, 2015
.Dt MKINITRD 8
.Os
.Sh NAME
.Nm mkinitrd
.Nd make initialization ramdisk
.Sh SYNOPSIS
.Nm mkinitrd
.Op Fl \-filter Ns "=" Ns Ar rules-file
.Op Fl \-format Ns "=" Ns Ar format
.Op Fl \-manifest Ns "=" Ns Ar manifest-file
.Fl o Ar destination
.Ar directory ...
.Sh DESCRIPTION
.Nm
produces a
.Xr initrd 7
for the Sortix
.Xr kernel 7
at the
.Ar destination .
It is an archive in the
.In sortix/initrd.h
format of files and directories.
.Pp
Every specified
.Ar directory
is used as a root directory and is recursively searched for files and
directories matching the filter.
If multiple directories are specified, the directories are merged together.
In case two files with the same path conflict, precedence is given to the file
in the root directory specified first.
.Pp
Hardlinks are detected and preserved to avoid data duplication.
Inode times are truncated to second precision due to format limitations.
Inodes are stored with uid 0 and gid 0 of the root user.
The format is not compressed but can be compressed externally if it is
decompressed during bootloading.
.Pp
.Xr initrdfs 8
can be used to view the files produced by
.Nm .
.Pp
The options are as follows:
.Bl -tag -width "12345678"
.It Fl \-filter Ns "=" Ns Ar rule-file
Include only files and directories during the recursive search that matches
rules in the
.Ar rule-file
in the format specified under
.Sx FILTER RULES .
.It Fl \-format Ns "=" Ns Ar format
Produce the archive in the specified format.
This is for forward compatibility and only
.Sy sortix-initrd-2
is supported.
.Sy default
is an alias for the newest format
.Sy sortix-initrd-2 .
.Nm
will default to a newer format when one is introduced and this allows
.Nm
to support old callers during the transitional period.
.It Fl \-manifest Ns "=" Ns Ar manifest-file
Include only files and directories during the recursive search whose path
exactly matches a line in the
.Ar manifest-file .
.It Fl o , Fl \-output Ns "=" Ns Ar destination
Store the produced
.Xr initrd 7
at the specified
.Ar destination .
.El
.Sh FILTER RULES
The rule format is line based and leading whitespace is skipped.
Lines starting with a
.Li #
character are ignored as comments.
The first word on a line must be one of the following commands and the rest of
the line is its parameter.
Trailing whitespace is not ignored.
.Bl -tag -width "12345678"
.It Sy default Ar boolean
The
.Ar boolean
parameter is either
.Sy true
or
.Sy false
and determines whether a file or directory is included if no other rules match
it.
This defaults to
.Sy true .
.It Sy include Ar path
Include the file or directory if it matches
.Ar path .
.It Sy exclude Ar path
Exclude the file or directory if it matches
.Ar path .
.El
.Pp
The rules are checked on the paths relative to the root directories during the
recursive descent.
The last rule to match a path decides whether it is included or not.
Directory are not descended into if they are excluded.
The pattern patch is simple and matches paths exactly.
.Sh EXIT STATUS
.Nm
will exit 0 on success and non-zero otherwise.
.Sh EXAMPLES
.Bd -literal
# By default include everything except these directories:
exclude /dev
exclude /src/sysroot
exclude /tmp
.Ed
.Sh SEE ALSO
.Xr initrd 7 ,
.Xr kernel 7 ,
.Xr initrdfs 8 ,
.Xr update-initrd 8
.Sh BUGS
The path pattern matching should be upgraded to use
.Xr fnmatch 3 .
The initrd format does not losslessly represent the Sortix
.Li struct stat .

View File

@ -1,776 +0,0 @@
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* mkinitrd.c
* Produces a simple ramdisk filesystem readable by the Sortix kernel.
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <dirent.h>
#include <endian.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <ioleast.h>
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sortix/initrd.h>
#define DEFAULT_FORMAT "sortix-initrd-2"
#include "rules.h"
#include "serialize.h"
uint32_t HostModeToInitRD(mode_t mode)
{
uint32_t result = mode & 0777; // Lower 9 bits per POSIX and tradition.
if ( S_ISVTX & mode ) { result |= INITRD_S_ISVTX; }
if ( S_ISSOCK(mode) ) { result |= INITRD_S_IFSOCK; }
if ( S_ISLNK(mode) ) { result |= INITRD_S_IFLNK; }
if ( S_ISREG(mode) ) { result |= INITRD_S_IFREG; }
if ( S_ISBLK(mode) ) { result |= INITRD_S_IFBLK; }
if ( S_ISDIR(mode) ) { result |= INITRD_S_IFDIR; }
if ( S_ISCHR(mode) ) { result |= INITRD_S_IFCHR; }
if ( S_ISFIFO(mode) ) { result |= INITRD_S_IFIFO; }
return result;
}
mode_t InitRDModeToHost(uint32_t mode)
{
mode_t result = mode & 0777; // Lower 9 bits per POSIX and tradition.
if ( INITRD_S_ISVTX & mode ) { result |= S_ISVTX; }
if ( INITRD_S_ISSOCK(mode) ) { result |= S_IFSOCK; }
if ( INITRD_S_ISLNK(mode) ) { result |= S_IFLNK; }
if ( INITRD_S_ISREG(mode) ) { result |= S_IFREG; }
if ( INITRD_S_ISBLK(mode) ) { result |= S_IFBLK; }
if ( INITRD_S_ISDIR(mode) ) { result |= S_IFDIR; }
if ( INITRD_S_ISCHR(mode) ) { result |= S_IFCHR; }
if ( INITRD_S_ISFIFO(mode) ) { result |= S_IFIFO; }
return result;
}
struct Node;
struct DirEntry;
struct DirEntry
{
char* name;
struct Node* node;
};
int DirEntryCompare(const struct DirEntry* a, const struct DirEntry* b)
{
return strcmp(a->name, b->name);
}
int DirEntryCompareIndirect(const void* a_ptr, const void* b_ptr)
{
const struct DirEntry* a = (const struct DirEntry*) a_ptr;
const struct DirEntry* b = (const struct DirEntry*) b_ptr;
return DirEntryCompare(a, b);
}
struct Node
{
char* path;
uint32_t ino;
uint32_t nlink;
size_t direntsused;
size_t direntslength;
struct DirEntry* dirents;
mode_t mode;
time_t ctime;
time_t mtime;
bool written;
size_t refcount;
};
void FreeNode(struct Node* node)
{
if ( !node )
return;
if ( 1 < node->nlink ) { node->nlink--; return; }
for ( size_t i = 0; i < node->direntsused; i++ )
{
struct DirEntry* entry = node->dirents + i;
if ( !entry->name )
continue;
if ( strcmp(entry->name, ".") != 0 && strcmp(entry->name, "..") != 0 )
{
if ( --entry->node->refcount == 0 )
FreeNode(entry->node);
}
free(entry->name);
}
free(node->dirents);
free(node->path);
free(node);
}
struct CacheEntry
{
ino_t ino;
dev_t dev;
struct Node* node;
};
static size_t cacheused = 0;
static size_t cachelen = 0;
static struct CacheEntry* cache = NULL;
struct Node* LookupCache(dev_t dev, ino_t ino)
{
for ( size_t i = 0; i < cacheused; i++ )
if ( cache[i].dev == dev && cache[i].ino == ino )
return cache[i].node;
return NULL;
}
bool AddToCache(struct Node* node, dev_t dev, ino_t ino)
{
if ( cacheused == cachelen )
{
size_t newcachelen = cachelen ? 2 * cachelen : 256;
size_t newcachesize = newcachelen * sizeof(struct CacheEntry);
struct CacheEntry* newcache =
(struct CacheEntry*) realloc(cache, newcachesize);
if ( !newcache )
return false;
cache = newcache;
cachelen = newcachelen;
}
size_t index = cacheused++;
cache[index].ino = ino;
cache[index].dev = dev;
cache[index].node = node;
return true;
}
struct Node* RecursiveSearch(const char* real_path, const char* virt_path,
uint32_t* ino, struct Node* parent)
{
printf("%s\n", virt_path);
fflush(stdout);
if ( virt_path[0] == '/' && !virt_path[1] )
virt_path = "";
struct stat st;
if ( lstat(real_path, &st) != 0 )
{
warn("stat: %s", real_path);
return NULL;
}
if ( !S_ISDIR(st.st_mode) && 2 <= st.st_nlink )
{
struct Node* cached = LookupCache(st.st_dev, st.st_ino);
if ( cached )
return cached->nlink++, cached->refcount++, cached;
}
struct Node* node = (struct Node*) calloc(1, sizeof(struct Node));
if ( !node )
return NULL;
node->nlink = 1;
node->refcount = 1;
node->mode = st.st_mode;
node->ino = (*ino)++;
node->ctime = st.st_ctim.tv_sec;
node->mtime = st.st_mtim.tv_sec;
char* real_path_clone = strdup(real_path);
if ( !real_path_clone )
{
warn("strdup");
free(node);
return NULL;
}
node->path = real_path_clone;
if ( !S_ISDIR(st.st_mode))
{
if ( 2 <= st.st_nlink && !AddToCache(node, st.st_dev, st.st_ino) )
{
free(real_path_clone);
free(node);
return NULL;
}
return node;
}
DIR* dir = opendir(real_path);
if ( !dir )
{
warn("opendir: %s", real_path);
FreeNode(node);
return NULL;
}
size_t real_path_len = strlen(real_path);
size_t virt_path_len = strlen(virt_path);
bool successful = true;
struct dirent* entry;
while ( (entry = readdir(dir)) )
{
size_t namelen = strlen(entry->d_name);
size_t virt_subpath_len = virt_path_len + 1 + namelen;
char* virt_subpath = (char*) malloc(virt_subpath_len+1);
if ( !virt_subpath )
{
warn("malloc");
successful = false;
break;
}
stpcpy(stpcpy(stpcpy(virt_subpath, virt_path), "/"), entry->d_name);
if ( strcmp(entry->d_name, ".") != 0 &&
strcmp(entry->d_name, "..") != 0 &&
!IncludesPath(virt_subpath) )
{
free(virt_subpath);
continue;
}
size_t real_subpath_len = real_path_len + 1 + namelen;
char* real_subpath = (char*) malloc(real_subpath_len+1);
if ( !real_subpath )
{
free(virt_subpath);
warn("malloc");
successful = false;
break;
}
stpcpy(stpcpy(stpcpy(real_subpath, real_path), "/"), entry->d_name);
struct Node* child = NULL;
if ( !strcmp(entry->d_name, ".") )
child = node;
if ( !strcmp(entry->d_name, "..") )
child = parent ? parent : node;
if ( !child )
child = RecursiveSearch(real_subpath, virt_subpath, ino, node);
free(real_subpath);
free(virt_subpath);
if ( !child )
{
successful = false;
break;
}
if ( node->direntsused == node->direntslength )
{
size_t oldlength = node->direntslength;
size_t newlength = oldlength ? 2 * oldlength : 8;
size_t newsize = sizeof(struct DirEntry) * newlength;
struct DirEntry* newdirents = (struct DirEntry*) realloc(node->dirents, newsize);
if ( !newdirents )
{
warn("realloc");
successful = false;
break;
}
node->dirents = newdirents;
node->direntslength = newlength;
}
char* nameclone = strdup(entry->d_name);
if ( !nameclone )
{
warn("strdup");
successful = false;
break;
}
struct DirEntry* entry = node->dirents + node->direntsused++;
entry->name = nameclone;
entry->node = child;
}
closedir(dir);
if ( !successful )
{
FreeNode(node);
return NULL;
}
qsort(node->dirents, node->direntsused, sizeof(struct DirEntry),
DirEntryCompareIndirect);
return node;
}
struct Node* MergeNodes(struct Node* a, struct Node* b)
{
if ( !S_ISDIR(a->mode) || !S_ISDIR(b->mode) )
{
FreeNode(b);
return a;
}
size_t dirents_used = 0;
size_t dirents_length = a->direntsused + b->direntsused;
struct DirEntry* dirents = (struct DirEntry*)
malloc(sizeof(struct DirEntry) * dirents_length);
if ( !dirents )
{
warn("malloc");
FreeNode(a);
FreeNode(b);
return NULL;
}
bool failure = false;
size_t ai = 0;
size_t bi = 0;
while ( ai != a->direntsused || bi != b->direntsused )
{
if ( bi == b->direntsused ||
(ai != a->direntsused &&
bi != b->direntsused &&
DirEntryCompare(&a->dirents[ai], &b->dirents[bi]) < 0) )
{
dirents[dirents_used++] = a->dirents[ai];
a->dirents[ai].name = NULL;
a->dirents[ai].node = NULL;
ai++;
continue;
}
if ( ai == a->direntsused ||
(ai != a->direntsused &&
bi != b->direntsused &&
DirEntryCompare(&a->dirents[ai], &b->dirents[bi]) > 0) )
{
dirents[dirents_used++] = b->dirents[bi];
for ( size_t i = 0; i < b->dirents[bi].node->direntsused; i++ )
{
if ( strcmp(b->dirents[bi].node->dirents[i].name, "..") != 0 )
continue;
b->dirents[bi].node->dirents[i].node = a;
}
b->dirents[bi].name = NULL;
b->dirents[bi].node = NULL;
bi++;
continue;
}
const char* name = a->dirents[ai].name;
dirents[dirents_used].name = a->dirents[ai].name;
if ( !strcmp(name, ".") || !strcmp(name, "..") )
dirents[dirents_used].node = a->dirents[ai].node;
else
{
dirents[dirents_used].node =
MergeNodes(a->dirents[ai].node, b->dirents[bi].node);
if ( !dirents[dirents_used].node )
failure = true;
}
dirents_used++;
a->dirents[ai].name = NULL;
a->dirents[ai].node = NULL;
ai++;
free(b->dirents[bi].name);
b->dirents[bi].name = NULL;
b->dirents[bi].node = NULL;
bi++;
}
free(a->dirents);
a->dirents = dirents;
a->direntsused = dirents_used;
a->direntslength = dirents_length;
b->direntsused = 0;
FreeNode(b);
if ( failure )
return FreeNode(b), (struct Node*) NULL;
return a;
}
bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname,
struct Node* node)
{
if ( node->written )
return true;
uint32_t filesize = 0;
uint32_t origfssize = sb->fssize;
uint32_t dataoff = origfssize;
uint32_t filestart = dataoff;
if ( S_ISLNK(node->mode) ) // Symbolic link
{
const size_t NAME_SIZE = 1024UL;
char name[NAME_SIZE];
ssize_t namelen = readlink(node->path, name, NAME_SIZE);
if ( namelen < 0 )
return warn("readlink: %s", node->path), false;
filesize = (uint32_t) namelen;
if ( pwriteall(fd, name, filesize, dataoff) < filesize )
return warn("read: %s", node->path), false;
dataoff += filesize;
}
else if ( S_ISREG(node->mode) ) // Regular file
{
int nodefd = open(node->path, O_RDONLY);
if ( nodefd < 0 )
return warn("open: %s", node->path), false;
const size_t BUFFER_SIZE = 16UL * 1024UL;
uint8_t buffer[BUFFER_SIZE];
ssize_t amount;
while ( 0 < (amount = read(nodefd, buffer, BUFFER_SIZE)) )
{
if ( pwriteall(fd, buffer, amount, dataoff) < (size_t) amount )
{
close(nodefd);
return warn("write: %s", outputname), false;
}
dataoff += amount;
filesize += amount;
}
close(nodefd);
if ( amount < 0 )
return warn("read: %s", node->path), false;
}
else if ( S_ISDIR(node->mode) ) // Directory
{
for ( size_t i = 0; i < node->direntsused; i++ )
{
struct DirEntry* entry = node->dirents + i;
const char* name = entry->name;
size_t namelen = strlen(entry->name);
struct initrd_dirent dirent;
dirent.inode = entry->node->ino;
dirent.namelen = (uint16_t) namelen;
dirent.reclen = sizeof(dirent) + dirent.namelen + 1;
dirent.reclen = (dirent.reclen+3)/4*4; // Align entries.
size_t entsize = sizeof(dirent);
export_initrd_dirent(&dirent);
assert((dataoff & (alignof(dirent)-1)) == 0 );
ssize_t hdramt = pwriteall(fd, &dirent, entsize, dataoff);
import_initrd_dirent(&dirent);
ssize_t nameamt = pwriteall(fd, name, namelen+1, dataoff + entsize);
if ( hdramt < (ssize_t) entsize || nameamt < (ssize_t) (namelen+1) )
return warn("write: %s", outputname), false;
size_t padding = dirent.reclen - (entsize + (namelen+1));
for ( size_t n = 0; n < padding; n++ )
{
uint8_t nul = 0;
if ( pwrite(fd, &nul, 1, dataoff+entsize+namelen+1+n) != 1 )
return warn("write: %s", outputname), false;
}
filesize += dirent.reclen;
dataoff += dirent.reclen;
}
}
struct initrd_inode inode;
inode.mode = HostModeToInitRD(node->mode);
inode.uid = 0;
inode.gid = 0;
inode.nlink = node->nlink;
inode.ctime = (uint64_t) node->ctime;
inode.mtime = (uint64_t) node->mtime;
inode.dataoffset = filestart;
inode.size = filesize;
uint32_t inodepos = sb->inodeoffset + node->ino * sb->inodesize;
uint32_t inodesize = sizeof(inode);
export_initrd_inode(&inode);
assert((inodepos & (alignof(inode)-1)) == 0 );
if ( pwriteall(fd, &inode, inodesize, inodepos) < inodesize )
return warn("write: %s", outputname), false;
import_initrd_inode(&inode);
uint32_t increment = dataoff - origfssize;
sb->fssize += increment;
sb->fssize = (sb->fssize+7)/8*8; // Align upwards.
return node->written = true;
}
bool WriteNodeRecursive(struct initrd_superblock* sb, int fd,
const char* outputname, struct Node* node)
{
if ( !WriteNode(sb, fd, outputname, node) )
return false;
if ( !S_ISDIR(node->mode) )
return true;
for ( size_t i = 0; i < node->direntsused; i++ )
{
struct DirEntry* entry = node->dirents + i;
const char* name = entry->name;
struct Node* child = entry->node;
if ( !strcmp(name, ".") || !strcmp(name, ".." ) )
continue;
if ( !WriteNodeRecursive(sb, fd, outputname, child) )
return false;
}
return true;
}
bool FormatFD(const char* outputname, int fd, uint32_t inodecount,
struct Node* root)
{
struct initrd_superblock sb;
memset(&sb, 0, sizeof(sb));
strncpy(sb.magic, "sortix-initrd-2", sizeof(sb.magic));
sb.revision = 0;
sb.fssize = sizeof(sb);
sb.inodesize = sizeof(struct initrd_inode);
sb.inodeoffset = sizeof(sb);
sb.inodecount = inodecount;
sb.root = root->ino;
uint32_t inodebytecount = sb.inodesize * sb.inodecount;
sb.fssize += inodebytecount;
sb.fssize = (sb.fssize+7)/8*8; // Align upwards.
if ( !WriteNodeRecursive(&sb, fd, outputname, root) )
return false;
sb.sumalgorithm = INITRD_ALGO_NONE;
sb.sumsize = 0;
sb.fssize = (sb.fssize+3)/4*4; // Align upwards.
sb.fssize += sb.sumsize;
export_initrd_superblock(&sb);
if ( pwriteall(fd, &sb, sizeof(sb), 0) < sizeof(sb) )
{
warn("write: %s", outputname);
return false;
}
import_initrd_superblock(&sb);
if ( ftruncate(fd, sb.fssize) < 0 )
{
warn("truncate: %s", outputname);
return false;
}
return true;
}
bool Format(const char* pathname, uint32_t inodecount, struct Node* root)
{
int fd = open(pathname, O_RDWR | O_CREAT | O_TRUNC, 0666);
bool result = FormatFD(pathname, fd, inodecount, root);
close(fd);
return result;
}
static void compact_arguments(int* argc, char*** argv)
{
for ( int i = 0; i < *argc; i++ )
{
while ( i < *argc && !(*argv)[i] )
{
for ( int n = i; n < *argc; n++ )
(*argv)[n] = (*argv)[n+1];
(*argc)--;
}
}
}
bool get_option_variable(const char* option, char** varptr,
const char* arg, int argc, char** argv, int* ip,
const char* argv0)
{
size_t option_len = strlen(option);
if ( strncmp(option, arg, option_len) != 0 )
return false;
if ( arg[option_len] == '=' )
{
*varptr = strdup(arg + option_len + 1);
return true;
}
if ( arg[option_len] != '\0' )
return false;
if ( *ip + 1 == argc )
{
fprintf(stderr, "%s: expected operand after `%s'\n", argv0, option);
exit(1);
}
*varptr = strdup(argv[++*ip]), argv[*ip] = NULL;
return true;
}
#define GET_OPTION_VARIABLE(str, varptr) \
get_option_variable(str, varptr, arg, argc, argv, &i, argv0)
static void help(FILE* fp, const char* argv0)
{
fprintf(fp, "Usage: %s [OPTION]... ROOT... -o OUTPUT\n", argv0);
fprintf(fp, "Creates a init ramdisk for the Sortix kernel.\n");
fprintf(fp, "\n");
fprintf(fp, "Mandatory arguments to long options are mandatory for short options too.\n");
fprintf(fp, " --filter=FILE import filter rules from FILE\n");
fprintf(fp, " --format=FORMAT format version [%s]\n", DEFAULT_FORMAT);
fprintf(fp, " -o, --output=FILE write result to FILE\n");
fprintf(fp, " --help display this help and exit\n");
fprintf(fp, " --version output version information and exit\n");
}
static void version(FILE* fp, const char* argv0)
{
fprintf(fp, "%s (Sortix) %s\n", argv0, VERSIONSTR);
}
int main(int argc, char* argv[])
{
char* arg_filter = NULL;
char* arg_format = strdup(DEFAULT_FORMAT);
char* arg_manifest = NULL;
char* arg_output = NULL;
const char* argv0 = argv[0];
for ( int i = 1; i < argc; i++ )
{
const char* arg = argv[i];
if ( arg[0] != '-' || !arg[1] )
continue;
argv[i] = NULL;
if ( !strcmp(arg, "--") )
break;
if ( arg[1] != '-' )
{
char c;
while ( (c = *++arg) ) switch ( c )
{
case 'o':
free(arg_output);
if ( *(arg+1) )
arg_output = strdup(arg + 1);
else
{
if ( i + 1 == argc )
{
warnx("option requires an argument -- 'o'");
fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
exit(125);
}
arg_output = strdup(argv[i+1]);
argv[++i] = NULL;
}
arg = "o";
break;
default:
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
help(stderr, argv0);
exit(1);
}
}
else if ( !strcmp(arg, "--help") )
help(stdout, argv0), exit(0);
else if ( !strcmp(arg, "--version") )
version(stdout, argv0), exit(0);
else if ( GET_OPTION_VARIABLE("--filter", &arg_filter) )
{
FILE* fp = fopen(arg_filter, "r");
if ( !fp )
err(1, "%s", arg_filter);
if ( !AddRulesFromFile(fp, arg_filter) )
exit(1);
fclose(fp);
free(arg_filter);
arg_filter = NULL;
}
else if ( GET_OPTION_VARIABLE("--manifest", &arg_manifest) )
{
FILE* fp = fopen(arg_manifest, "r");
if ( !fp )
err(1, "%s", arg_manifest);
if ( !AddManifestFromFile(fp, arg_manifest) )
exit(1);
fclose(fp);
free(arg_manifest);
arg_manifest = NULL;
}
else if ( GET_OPTION_VARIABLE("--format", &arg_format) ) { }
else if ( GET_OPTION_VARIABLE("--output", &arg_output) ) { }
else
{
fprintf(stderr, "%s: unknown option: %s\n", argv0, arg);
help(stderr, argv0);
exit(1);
}
}
if ( argc < 2 )
{
help(stdout, argv0);
exit(1);
}
compact_arguments(&argc, &argv);
if ( argc < 2 )
{
fprintf(stderr, "%s: No root specified\n", argv0),
help(stderr, argv0);
exit(1);
}
if ( !arg_output )
{
fprintf(stderr, "%s: No output file specified\n", argv0),
help(stderr, argv0);
exit(1);
}
const char* format = arg_format;
if ( !strcmp(format, "default") )
format = DEFAULT_FORMAT;
if ( strcmp(format, "sortix-initrd-2") != 0 )
{
fprintf(stderr, "%s: Unsupported format `%s'\n", argv0, format);
fprintf(stderr, "Try `%s --help' for more information.\n", argv0);
exit(1);
}
uint32_t inodecount = 1;
struct Node* root = NULL;
for ( int i = 1; i < argc; i++ )
{
struct Node* node = RecursiveSearch(argv[i], "/", &inodecount, NULL);
if ( !node )
exit(1);
if ( root )
root = MergeNodes(root, node);
else
root = node;
if ( !root )
exit(1);
}
if ( !Format(arg_output, inodecount, root) )
exit(1);
FreeNode(root);
return 0;
}

View File

@ -1,317 +0,0 @@
/*
* Copyright (c) 2013, 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* rules.c
* Determines whether a given path is included in the filesystem.
*/
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <libgen.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "rules.h"
static struct InclusionRule** rules;
static size_t num_rules;
static size_t num_rules_allocated;
static bool default_inclusion = true;
static bool default_inclusion_determined;
static char** manifest;
static size_t manifest_used;
static size_t manifest_length;
static const char* SkipCharacters(const char* str, char c)
{
while ( *str == c)
str++;
return str;
}
// /usr/bin/foobar match /usr = true
// /usr/bin/foobar match usr = false
// ///usr////bin//foobar match //usr// = true
// ///usr////bin//foobar match //usr//./evince = false
// TODO: Should this support . and .. too?
static bool PathMatchesPattern(const char* path, const char* pattern)
{
bool last_was_slash = false;
while ( true )
{
if ( !*pattern )
return !*path || last_was_slash;
if ( (last_was_slash = *pattern == '/') )
{
if ( *path == '/' )
{
path = SkipCharacters(path, '/');
pattern = SkipCharacters(pattern, '/');
continue;
}
return false;
}
if ( *pattern++ != *path++ )
return false;
}
}
static int search_path(const void* a_ptr, const void* b_ptr)
{
const char* key = (const char*) a_ptr;
char* path = *(char**) b_ptr;
return strcmp(key, path);
}
bool IncludesPath(const char* path)
{
bool determined = false;
bool included = false;
for ( size_t i = 0; i < num_rules; i++ )
{
struct InclusionRule* rule = rules[i];
if ( !PathMatchesPattern(path, rule->pattern) )
continue;
switch ( rules[i]->rule )
{
case RULE_INCLUDE:
included = true;
determined = true;
break;
case RULE_EXCLUDE:
included = false;
determined = true;
break;
}
}
if ( !determined )
included = default_inclusion;
if ( !included )
return false;
if ( manifest_used &&
!bsearch(path, manifest, manifest_used, sizeof(char*), search_path) )
return false;
return true;
}
bool ChangeRulesAmount(size_t new_length)
{
size_t new_num_rules = new_length < num_rules ? new_length : num_rules;
for ( size_t i = new_num_rules; i < num_rules; i++ )
{
free(rules[i]->pattern);
free(rules[i]);
}
num_rules = new_num_rules;
struct InclusionRule** new_rules = (struct InclusionRule**)
malloc(sizeof(struct InclusionRule*) * new_length);
for ( size_t i = 0; i < new_length && i < num_rules; i++ )
new_rules[i] = rules[i];
free(rules); rules = new_rules;
num_rules_allocated = new_length;
return true;
}
bool AddRule(struct InclusionRule* rule)
{
if ( num_rules == num_rules_allocated )
{
size_t new_length = num_rules_allocated ? 2 * num_rules_allocated : 32;
if ( !ChangeRulesAmount(new_length) )
return false;
}
rules[num_rules++] = rule;
return true;
}
static const char* SkipWhitespace(const char* line)
{
while ( *line && isspace((unsigned char) *line) )
line++;
return line;
}
static bool IsLineComment(const char* line)
{
return !*line || *line == '#';
}
static const char* IsLineCommand(const char* line, const char* command)
{
while ( *line && isspace((unsigned char) *line) )
line++;
size_t cmdlen = strlen(command);
if ( strncmp(line, command, cmdlen) != 0 )
return NULL;
if ( line[cmdlen] && !isspace((unsigned char) line[cmdlen]) )
return NULL;
while ( line[cmdlen] && isspace((unsigned char) line[cmdlen]) )
cmdlen++;
return line + cmdlen;
}
bool AddRulesFromFile(FILE* fp, const char* fpname)
{
size_t rules_at_start = num_rules;
size_t line_size;
size_t line_num = 0;
char* mem = NULL;
ssize_t line_len;
while ( 0 < (line_len = getline(&mem, &line_size, fp)) )
{
char* line = mem;
line_num++;
if ( line[line_len-1] == '\n' )
line[--line_len] = '\0';
line = (char*) SkipWhitespace((char*) line);
if ( IsLineComment(line) )
continue;
const char* parameter;
if ( (parameter = IsLineCommand(line, "default")) )
{
bool value;
if ( !strcmp(parameter, "true") )
value = true;
else if ( !strcmp(parameter, "false") )
value = false;
else
{
warnx("%s:%zu: not a boolean '%s'", fpname, line_num, parameter);
goto error_out;
}
if ( !default_inclusion_determined )
default_inclusion = value,
default_inclusion_determined = true;
else
default_inclusion = default_inclusion || value;
}
else if ( (parameter = IsLineCommand(line, "exclude")) ||
(parameter = IsLineCommand(line, "include")) )
{
if ( !*parameter )
{
warnx("%s:%zu: no parameter given", fpname, line_num);
goto error_out;
}
const char* pattern = parameter;
enum InclusionRuleType type = line[0] == 'e' ? RULE_EXCLUDE : RULE_INCLUDE;
struct InclusionRule* rule =
(struct InclusionRule*) malloc(sizeof(struct InclusionRule));
rule->pattern = strdup(pattern);
rule->rule = type;
if ( !AddRule(rule) )
goto error_out_errno;
}
else
{
warnx("%s:%zu: line not understood: '%s'", fpname, line_num, line);
goto error_out;
}
}
if ( ferror(fp) )
{
error_out_errno:
warn("%s", fpname);
error_out:
free(mem);
ChangeRulesAmount(rules_at_start);
return false;
}
free(mem);
return true;
}
int compare_path(const void* a_ptr, const void* b_ptr)
{
const char* a = *(const char* const*) a_ptr;
const char* b = *(const char* const*) b_ptr;
return strcmp(a, b);
}
bool AddManifestPath(const char* path)
{
if ( manifest_used == manifest_length )
{
size_t new_length = 2 * manifest_length;
if ( new_length == 0 )
new_length = 64;
size_t new_size = new_length * sizeof(char*);
char** new_manifest = (char**) realloc(manifest, new_size);
if ( !new_manifest )
{
warn("malloc");
return false;
}
manifest = new_manifest;
manifest_length = new_length;
}
char* copy = strdup(path);
if ( !copy )
{
warn("malloc");
return false;
}
manifest[manifest_used++] = copy;
return true;
}
bool AddManifestFromFile(FILE* fp, const char* fpname)
{
char* line = NULL;
size_t line_size = 0;
ssize_t line_len;
while ( 0 < (line_len = getline(&line, &line_size, fp)) )
{
if ( line[line_len-1] == '\n' )
line[--line_len] = '\0';
if ( !AddManifestPath(line) )
return false;
}
free(line);
if ( ferror(fp) )
{
warn("%s", fpname);
return false;
}
if ( !AddManifestPath("/") ||
!AddManifestPath("/tix") ||
!AddManifestPath("/tix/manifest") )
return false;
char* fpname_copy = strdup(fpname);
if ( !fpname_copy )
{
warn("malloc");
return false;
}
const char* fpname_basename = basename(fpname_copy);
char* manifest_path;
if ( asprintf(&manifest_path, "/tix/manifest/%s", fpname_basename) < 0 )
{
free(fpname_copy);
warn("malloc");
return false;
}
free(fpname_copy);
if ( !AddManifestPath(manifest_path) )
return free(manifest_path), false;
free(manifest_path);
qsort(manifest, manifest_used, sizeof(char*), compare_path);
return true;
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* rules.h
* Determines whether a given path is included in the filesystem.
*/
#ifndef RULES_H
#define RULES_H
enum InclusionRuleType
{
RULE_INCLUDE,
RULE_EXCLUDE,
};
struct InclusionRule
{
char* pattern;
enum InclusionRuleType rule;
};
bool IncludesPath(const char* path);
bool AddRule(struct InclusionRule* rule);
bool AddRulesFromFile(FILE* fp, const char* fpname);
bool AddManifestFromFile(FILE* fp, const char* fpname);
bool AddManifestPath(const char* path);
bool ChangeRulesAmount(size_t newnum);
#endif

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* serialize.c
* Import and export binary data structures
*/
#include <endian.h>
#include <sortix/initrd.h>
#include "serialize.h"
void import_initrd_superblock(struct initrd_superblock* obj)
{
obj->fssize = le32toh(obj->fssize);
obj->revision = le32toh(obj->revision);
obj->inodesize = le32toh(obj->inodesize);
obj->inodecount = le32toh(obj->inodecount);
obj->inodeoffset = le32toh(obj->inodeoffset);
obj->root = le32toh(obj->root);
obj->sumalgorithm = le32toh(obj->sumalgorithm);
obj->sumsize = le32toh(obj->sumsize);
}
void export_initrd_superblock(struct initrd_superblock* obj)
{
obj->fssize = htole32(obj->fssize);
obj->revision = htole32(obj->revision);
obj->inodesize = htole32(obj->inodesize);
obj->inodecount = htole32(obj->inodecount);
obj->inodeoffset = htole32(obj->inodeoffset);
obj->root = htole32(obj->root);
obj->sumalgorithm = htole32(obj->sumalgorithm);
obj->sumsize = htole32(obj->sumsize);
}
void import_initrd_inode(struct initrd_inode* obj)
{
obj->mode = le32toh(obj->mode);
obj->uid = le32toh(obj->uid);
obj->nlink = le32toh(obj->nlink);
obj->ctime = le64toh(obj->ctime);
obj->mtime = le64toh(obj->mtime);
obj->dataoffset = le32toh(obj->dataoffset);
obj->size = le32toh(obj->size);
}
void export_initrd_inode(struct initrd_inode* obj)
{
obj->mode = htole32(obj->mode);
obj->uid = htole32(obj->uid);
obj->nlink = htole32(obj->nlink);
obj->ctime = htole64(obj->ctime);
obj->mtime = htole64(obj->mtime);
obj->dataoffset = htole32(obj->dataoffset);
obj->size = htole32(obj->size);
}
void import_initrd_dirent(struct initrd_dirent* obj)
{
obj->inode = le32toh(obj->inode);
obj->reclen = le16toh(obj->reclen);
obj->namelen = le16toh(obj->namelen);
}
void export_initrd_dirent(struct initrd_dirent* obj)
{
obj->inode = htole32(obj->inode);
obj->reclen = htole16(obj->reclen);
obj->namelen = htole16(obj->namelen);
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* serialize.h
* Import and export binary data structures
*/
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include <sortix/initrd.h>
void import_initrd_superblock(struct initrd_superblock* obj);
void export_initrd_superblock(struct initrd_superblock* obj);
void import_initrd_inode(struct initrd_inode* obj);
void export_initrd_inode(struct initrd_inode* obj);
void import_initrd_dirent(struct initrd_dirent* obj);
void export_initrd_dirent(struct initrd_dirent* obj);
#endif

View File

@ -344,8 +344,6 @@ carray
.It
kblayout-compiler
.It
mkinitrd
.It
sf
.It
tix

View File

@ -80,10 +80,6 @@ The format of each multiboot module is automatically detected by default:
.Pp
.Bl -bullet -compact
.It
Initialization ramdisks produced by
.Xr mkinitrd 8
are extracted in the root directory.
.It
.Xr tar 7
archives in the ustar format are extracted into the root directory.
The bootloader must already have decompressed the archive.