Remove mkinitrd(8).
This commit is contained in:
parent
6ac0061380
commit
4533a2ade2
4
Makefile
4
Makefile
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
mkinitrd
|
||||
initrdfs
|
|
@ -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
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 .
|
|
@ -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;
|
||||
}
|
317
mkinitrd/rules.c
317
mkinitrd/rules.c
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -344,8 +344,6 @@ carray
|
|||
.It
|
||||
kblayout-compiler
|
||||
.It
|
||||
mkinitrd
|
||||
.It
|
||||
sf
|
||||
.It
|
||||
tix
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue