Clean up initrd extraction code.
This commit is contained in:
parent
a334ede4c4
commit
ae73391a10
|
@ -18,7 +18,7 @@
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
initrd.cpp
|
initrd.cpp
|
||||||
Provides low-level access to a Sortix init ramdisk.
|
Extracts the initrd into the initial memory filesystem.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
@ -53,239 +53,137 @@
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace InitRD {
|
namespace InitRD {
|
||||||
|
|
||||||
addralloc_t initrd_addr_alloc;
|
// TODO: The initrd is not being properly verified.
|
||||||
uint8_t* initrd = NULL;
|
// TODO: The initrd is not handled in an endian-neutral manner.
|
||||||
size_t initrdsize;
|
|
||||||
const initrd_superblock_t* sb;
|
|
||||||
|
|
||||||
__attribute__((unused))
|
struct initrd_context
|
||||||
static uint32_t HostModeToInitRD(mode_t mode)
|
|
||||||
{
|
{
|
||||||
uint32_t result = mode & 0777; // Lower 9 bits per POSIX and tradition.
|
uint8_t* initrd;
|
||||||
if ( S_ISVTX & mode ) { result |= INITRD_S_ISVTX; }
|
size_t initrd_size;
|
||||||
if ( S_ISSOCK(mode) ) { result |= INITRD_S_IFSOCK; }
|
initrd_superblock_t* sb;
|
||||||
if ( S_ISLNK(mode) ) { result |= INITRD_S_IFLNK; }
|
Ref<Descriptor> links;
|
||||||
if ( S_ISREG(mode) ) { result |= INITRD_S_IFREG; }
|
ioctx_t ioctx;
|
||||||
if ( S_ISBLK(mode) ) { result |= INITRD_S_IFBLK; }
|
};
|
||||||
if ( S_ISDIR(mode) ) { result |= INITRD_S_IFDIR; }
|
|
||||||
if ( S_ISCHR(mode) ) { result |= INITRD_S_IFCHR; }
|
static mode_t initrd_mode_to_host_mode(uint32_t mode)
|
||||||
if ( S_ISFIFO(mode) ) { result |= INITRD_S_IFIFO; }
|
{
|
||||||
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((unused))
|
static initrd_inode_t* initrd_get_inode(struct initrd_context* ctx, uint32_t inode)
|
||||||
static mode_t InitRDModeToHost(uint32_t mode)
|
|
||||||
{
|
{
|
||||||
mode_t result = mode & 0777; // Lower 9 bits per POSIX and tradition.
|
if ( ctx->sb->inodecount <= inode )
|
||||||
if ( INITRD_S_ISVTX & mode ) { result |= S_ISVTX; }
|
return errno = EINVAL, (initrd_inode_t*) NULL;
|
||||||
if ( INITRD_S_ISSOCK(mode) ) { result |= S_IFSOCK; }
|
uint32_t pos = ctx->sb->inodeoffset + ctx->sb->inodesize * inode;
|
||||||
if ( INITRD_S_ISLNK(mode) ) { result |= S_IFLNK; }
|
return (initrd_inode_t*) (ctx->initrd + pos);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Root()
|
static uint8_t* initrd_inode_get_data(struct initrd_context* ctx, initrd_inode_t* inode, size_t* size)
|
||||||
{
|
{
|
||||||
return sb->root;
|
return *size = inode->size, ctx->initrd + inode->dataoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const initrd_inode_t* GetInode(uint32_t inode)
|
static uint32_t initrd_directory_open(struct initrd_context* ctx, initrd_inode_t* inode, const char* name)
|
||||||
{
|
{
|
||||||
if ( sb->inodecount <= inode ) { errno = EINVAL; return NULL; }
|
if ( !INITRD_S_ISDIR(inode->mode) )
|
||||||
uint32_t pos = sb->inodeoffset + sb->inodesize * inode;
|
return errno = ENOTDIR, 0;
|
||||||
return (const initrd_inode_t*) (initrd + pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Stat(uint32_t ino, struct stat* st)
|
|
||||||
{
|
|
||||||
const initrd_inode_t* inode = GetInode(ino);
|
|
||||||
if ( !inode ) { return false; }
|
|
||||||
st->st_ino = ino;
|
|
||||||
st->st_mode = HostModeToInitRD(inode->mode);
|
|
||||||
st->st_nlink = inode->nlink;
|
|
||||||
st->st_uid = inode->uid;
|
|
||||||
st->st_gid = inode->gid;
|
|
||||||
st->st_size = inode->size;
|
|
||||||
st->st_atim = timespec_make(inode->mtime, 0);
|
|
||||||
st->st_ctim = timespec_make(inode->ctime, 0);
|
|
||||||
st->st_mtim = timespec_make(inode->mtime, 0);
|
|
||||||
st->st_blksize = 1;
|
|
||||||
st->st_blocks = inode->size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* Open(uint32_t ino, size_t* size)
|
|
||||||
{
|
|
||||||
const initrd_inode_t* inode = GetInode(ino);
|
|
||||||
if ( !inode ) { return NULL; }
|
|
||||||
*size = inode->size;
|
|
||||||
return initrd + inode->dataoffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Traverse(uint32_t ino, const char* name)
|
|
||||||
{
|
|
||||||
const initrd_inode_t* inode = GetInode(ino);
|
|
||||||
if ( !inode ) { return 0; }
|
|
||||||
if ( !INITRD_S_ISDIR(inode->mode) ) { errno = ENOTDIR; return 0; }
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
while ( offset < inode->size )
|
while ( offset < inode->size )
|
||||||
{
|
{
|
||||||
uint32_t pos = inode->dataoffset + offset;
|
uint32_t pos = inode->dataoffset + offset;
|
||||||
const initrd_dirent* dirent = (const initrd_dirent*) (initrd + pos);
|
initrd_dirent* dirent = (initrd_dirent*) (ctx->initrd + pos);
|
||||||
if ( dirent->namelen && !strcmp(dirent->name, name) )
|
if ( dirent->namelen && !strcmp(dirent->name, name) )
|
||||||
{
|
|
||||||
return dirent->inode;
|
return dirent->inode;
|
||||||
}
|
|
||||||
offset += dirent->reclen;
|
offset += dirent->reclen;
|
||||||
}
|
}
|
||||||
errno = ENOENT;
|
return errno = ENOENT, 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GetFilename(uint32_t dir, size_t index)
|
static const char* initrd_directory_get_filename(struct initrd_context* ctx, initrd_inode_t* inode, size_t index)
|
||||||
{
|
{
|
||||||
const initrd_inode_t* inode = GetInode(dir);
|
if ( !INITRD_S_ISDIR(inode->mode) )
|
||||||
if ( !inode ) { return 0; }
|
return errno = ENOTDIR, (const char*) NULL;
|
||||||
if ( !INITRD_S_ISDIR(inode->mode) ) { errno = ENOTDIR; return 0; }
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
while ( offset < inode->size )
|
while ( offset < inode->size )
|
||||||
{
|
{
|
||||||
uint32_t pos = inode->dataoffset + offset;
|
uint32_t pos = inode->dataoffset + offset;
|
||||||
const initrd_dirent* dirent = (const initrd_dirent*) (initrd + pos);
|
initrd_dirent* dirent = (initrd_dirent*) (ctx->initrd + pos);
|
||||||
if ( index-- == 0 ) { return dirent->name; }
|
if ( index-- == 0 )
|
||||||
|
return dirent->name;
|
||||||
offset += dirent->reclen;
|
offset += dirent->reclen;
|
||||||
}
|
}
|
||||||
errno = EINVAL;
|
return errno = EINVAL, (const char*) NULL;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetNumFiles(uint32_t dir)
|
static size_t initrd_directory_get_num_files(struct initrd_context* ctx, initrd_inode_t* inode)
|
||||||
{
|
{
|
||||||
const initrd_inode_t* inode = GetInode(dir);
|
if ( !INITRD_S_ISDIR(inode->mode) )
|
||||||
if ( !inode ) { return 0; }
|
return errno = ENOTDIR, 0;
|
||||||
if ( !INITRD_S_ISDIR(inode->mode) ) { errno = ENOTDIR; return 0; }
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
size_t numentries = 0;
|
size_t numentries = 0;
|
||||||
while ( offset < inode->size )
|
while ( offset < inode->size )
|
||||||
{
|
{
|
||||||
uint32_t pos = inode->dataoffset + offset;
|
uint32_t pos = inode->dataoffset + offset;
|
||||||
const initrd_dirent* dirent = (const initrd_dirent*) (initrd + pos);
|
const initrd_dirent* dirent = (const initrd_dirent*) (ctx->initrd + pos);
|
||||||
numentries++;
|
numentries++;
|
||||||
offset += dirent->reclen;
|
offset += dirent->reclen;
|
||||||
}
|
}
|
||||||
return numentries;
|
return numentries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckSum()
|
static bool ExtractNode(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> node);
|
||||||
|
|
||||||
|
static bool ExtractFile(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> file)
|
||||||
{
|
{
|
||||||
uint32_t amount = sb->fssize - sb->sumsize;
|
size_t filesize;
|
||||||
uint8_t* filesum = initrd + amount;
|
uint8_t* data = initrd_inode_get_data(ctx, inode, &filesize);
|
||||||
if ( sb->sumalgorithm != INITRD_ALGO_CRC32 )
|
if ( !data )
|
||||||
|
return false;
|
||||||
|
if ( file->truncate(&ctx->ioctx, filesize) != 0 )
|
||||||
|
return false;
|
||||||
|
size_t sofar = 0;
|
||||||
|
while ( sofar < filesize )
|
||||||
{
|
{
|
||||||
Log::PrintF("Warning: InitRD checksum algorithm not supported\n");
|
ssize_t numbytes = file->write(&ctx->ioctx, data + sofar, filesize - sofar);
|
||||||
return;
|
if ( numbytes <= 0 )
|
||||||
}
|
return false;
|
||||||
uint32_t crc32 = *((uint32_t*) filesum);
|
sofar += numbytes;
|
||||||
uint32_t filecrc32 = CRC32::Hash(initrd, amount);
|
|
||||||
uint32_t doublecheck = CRC32::Hash(initrd, amount);
|
|
||||||
if ( filecrc32 != doublecheck )
|
|
||||||
{
|
|
||||||
// Yes, this has happened. This seems like the goto place for such bugs
|
|
||||||
// to trigger, so I added a more accurate warning.
|
|
||||||
Panic("Calculating InitRD checksum two times gave different results: "
|
|
||||||
"this likely means the kernel have a corruption bug, possibly "
|
|
||||||
"caused by building libc and kernel with different settings or "
|
|
||||||
"a bug in the scheduler/interrupt handler or who knows. "
|
|
||||||
"It is also possible that the laws of logic has changed.");
|
|
||||||
}
|
|
||||||
if ( crc32 != filecrc32 )
|
|
||||||
{
|
|
||||||
PanicF("InitRD had checksum %X, expected %X: this means the ramdisk "
|
|
||||||
"may have been corrupted by the bootloader.", filecrc32, crc32);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init(addr_t phys, size_t size)
|
static bool ExtractDir(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> dir)
|
||||||
{
|
{
|
||||||
assert(!initrd);
|
size_t numfiles = initrd_directory_get_num_files(ctx, inode);
|
||||||
|
|
||||||
// Allocate the needed kernel virtual address space.
|
|
||||||
if ( !AllocateKernelAddress(&initrd_addr_alloc, size) )
|
|
||||||
PanicF("Can't allocate 0x%zx bytes of kernel address space for the "
|
|
||||||
"init ramdisk", size );
|
|
||||||
|
|
||||||
// Map the physical frames onto our address space.
|
|
||||||
addr_t mapat = initrd_addr_alloc.from;
|
|
||||||
for ( size_t i = 0; i < size; i += Page::Size() )
|
|
||||||
if ( !Memory::Map(phys + i, mapat + i, PROT_KREAD) )
|
|
||||||
Panic("Unable to map the init ramdisk into virtual memory");
|
|
||||||
Memory::Flush();
|
|
||||||
|
|
||||||
initrd = (uint8_t*) mapat;
|
|
||||||
initrdsize = size;
|
|
||||||
|
|
||||||
if ( size < sizeof(*sb) ) { PanicF("initrd is too small"); }
|
|
||||||
sb = (const initrd_superblock_t*) initrd;
|
|
||||||
|
|
||||||
if ( !String::StartsWith(sb->magic, "sortix-initrd") )
|
|
||||||
{
|
|
||||||
Panic("Invalid magic value in initrd. This means the ramdisk may have "
|
|
||||||
"been corrupted by the bootloader, or that an incompatible file "
|
|
||||||
"has been passed to the kernel.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( strcmp(sb->magic, "sortix-initrd-1") == 0 )
|
|
||||||
{
|
|
||||||
Panic("Sortix initrd format version 1 is no longer supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( strcmp(sb->magic, "sortix-initrd-2") != 0 )
|
|
||||||
{
|
|
||||||
Panic("The initrd has a format that isn't supported. Perhaps it is "
|
|
||||||
"too new? Try downgrade or regenerate the initrd.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( size < sb->fssize )
|
|
||||||
{
|
|
||||||
PanicF("The initrd said it is %u bytes, but the kernel was only passed "
|
|
||||||
"%zu bytes by the bootloader, which is not enough.", sb->fssize,
|
|
||||||
size);
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckSum();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node, Ref<Descriptor> links);
|
|
||||||
static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file);
|
|
||||||
static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node, Ref<Descriptor> links);
|
|
||||||
|
|
||||||
static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir, Ref<Descriptor> links)
|
|
||||||
{
|
|
||||||
size_t numfiles = GetNumFiles(ino);
|
|
||||||
for ( size_t i = 0; i < numfiles; i++ )
|
for ( size_t i = 0; i < numfiles; i++ )
|
||||||
{
|
{
|
||||||
const char* name = GetFilename(ino, i);
|
const char* name = initrd_directory_get_filename(ctx, inode, i);
|
||||||
if ( !name )
|
if ( !name )
|
||||||
return false;
|
return false;
|
||||||
if ( IsDotOrDotDot(name) )
|
if ( IsDotOrDotDot(name) )
|
||||||
continue;
|
continue;
|
||||||
uint32_t childino = Traverse(ino, name);
|
uint32_t childino = initrd_directory_open(ctx, inode, name);
|
||||||
if ( !childino )
|
if ( !childino )
|
||||||
return false;
|
return false;
|
||||||
initrd_inode_t* child = (initrd_inode_t*) GetInode(childino);
|
initrd_inode_t* child = (initrd_inode_t*) initrd_get_inode(ctx, childino);
|
||||||
mode_t mode = InitRDModeToHost(child->mode);
|
mode_t mode = initrd_mode_to_host_mode(child->mode);
|
||||||
if ( INITRD_S_ISDIR(child->mode) )
|
if ( INITRD_S_ISDIR(child->mode) )
|
||||||
{
|
{
|
||||||
if ( dir->mkdir(ctx, name, mode) && errno != EEXIST )
|
if ( dir->mkdir(&ctx->ioctx, name, mode) && errno != EEXIST )
|
||||||
return false;
|
return false;
|
||||||
Ref<Descriptor> desc = dir->open(ctx, name, O_SEARCH | O_DIRECTORY, 0);
|
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name, O_SEARCH | O_DIRECTORY, 0);
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return false;
|
return false;
|
||||||
if ( !ExtractNode(ctx, childino, desc, links) )
|
if ( !ExtractNode(ctx, child, desc) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( INITRD_S_ISREG(child->mode) )
|
if ( INITRD_S_ISREG(child->mode) )
|
||||||
|
@ -293,21 +191,21 @@ static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir, Ref<Desc
|
||||||
assert(child->nlink != 0);
|
assert(child->nlink != 0);
|
||||||
char link_path[sizeof(childino) * 3];
|
char link_path[sizeof(childino) * 3];
|
||||||
snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino);
|
snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino);
|
||||||
Ref<Descriptor> existing(links->open(ctx, link_path, O_READ, 0));
|
Ref<Descriptor> existing(ctx->links->open(&ctx->ioctx, link_path, O_READ, 0));
|
||||||
if ( !existing || dir->link(ctx, name, existing) != 0 )
|
if ( !existing || dir->link(&ctx->ioctx, name, existing) != 0 )
|
||||||
{
|
{
|
||||||
Ref<Descriptor> desc(dir->open(ctx, name, O_WRITE | O_CREATE, mode));
|
Ref<Descriptor> desc(dir->open(&ctx->ioctx, name, O_WRITE | O_CREATE, mode));
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return false;
|
return false;
|
||||||
if ( !ExtractNode(ctx, childino, desc, links) )
|
if ( !ExtractNode(ctx, child, desc) )
|
||||||
return false;
|
return false;
|
||||||
if ( 2 <= child->nlink )
|
if ( 2 <= child->nlink )
|
||||||
links->link(ctx, link_path, desc);
|
ctx->links->link(&ctx->ioctx, link_path, desc);
|
||||||
}
|
}
|
||||||
if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) )
|
if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) )
|
||||||
{
|
{
|
||||||
size_t filesize;
|
size_t filesize;
|
||||||
const uint8_t* data = Open(childino, &filesize);
|
const uint8_t* data = initrd_inode_get_data(ctx, child, &filesize);
|
||||||
uintptr_t from = (uintptr_t) data;
|
uintptr_t from = (uintptr_t) data;
|
||||||
uintptr_t size = filesize;
|
uintptr_t size = filesize;
|
||||||
uintptr_t from_aligned = Page::AlignUp(from);
|
uintptr_t from_aligned = Page::AlignUp(from);
|
||||||
|
@ -325,60 +223,91 @@ static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir, Ref<Desc
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file)
|
static bool ExtractNode(struct initrd_context* ctx, initrd_inode_t* inode, Ref<Descriptor> node)
|
||||||
{
|
{
|
||||||
size_t filesize;
|
if ( node->chmod(&ctx->ioctx, initrd_mode_to_host_mode(inode->mode)) < 0 )
|
||||||
const uint8_t* data = Open(ino, &filesize);
|
|
||||||
if ( !data )
|
|
||||||
return false;
|
return false;
|
||||||
if ( file->truncate(ctx, filesize) != 0 )
|
if ( node->chown(&ctx->ioctx, inode->uid, inode->gid) < 0 )
|
||||||
return false;
|
|
||||||
size_t sofar = 0;
|
|
||||||
while ( sofar < filesize )
|
|
||||||
{
|
|
||||||
ssize_t numbytes = file->write(ctx, data + sofar, filesize - sofar);
|
|
||||||
if ( numbytes <= 0 )
|
|
||||||
return false;
|
|
||||||
sofar += numbytes;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node, Ref<Descriptor> links)
|
|
||||||
{
|
|
||||||
const initrd_inode_t* inode = GetInode(ino);
|
|
||||||
if ( !inode )
|
|
||||||
return false;
|
|
||||||
if ( node->chmod(ctx, InitRDModeToHost(inode->mode)) < 0 )
|
|
||||||
return false;
|
|
||||||
if ( node->chown(ctx, inode->uid, inode->gid) < 0 )
|
|
||||||
return false;
|
return false;
|
||||||
if ( INITRD_S_ISDIR(inode->mode) )
|
if ( INITRD_S_ISDIR(inode->mode) )
|
||||||
if ( !ExtractDir(ctx, ino, node, links) )
|
if ( !ExtractDir(ctx, inode, node) )
|
||||||
return false;
|
return false;
|
||||||
if ( INITRD_S_ISREG(inode->mode) )
|
if ( INITRD_S_ISREG(inode->mode) )
|
||||||
if ( !ExtractFile(ctx, ino, node) )
|
if ( !ExtractFile(ctx, inode, node) )
|
||||||
return false;
|
return false;
|
||||||
struct timespec ctime = timespec_make((time_t) inode->ctime, 0);
|
struct timespec ctime = timespec_make((time_t) inode->ctime, 0);
|
||||||
struct timespec mtime = timespec_make((time_t) inode->mtime, 0);
|
struct timespec mtime = timespec_make((time_t) inode->mtime, 0);
|
||||||
if ( node->utimens(ctx, &mtime, &ctime, &mtime) < 0 )
|
if ( node->utimens(&ctx->ioctx, &mtime, &ctime, &mtime) < 0 )
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
|
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
|
||||||
{
|
{
|
||||||
Init(physaddr, size);
|
// Allocate the needed kernel virtual address space.
|
||||||
|
addralloc_t initrd_addr_alloc;
|
||||||
|
if ( !AllocateKernelAddress(&initrd_addr_alloc, size) )
|
||||||
|
PanicF("Can't allocate 0x%zx bytes of kernel address space for the "
|
||||||
|
"init ramdisk", size );
|
||||||
|
|
||||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
// Map the physical frames onto our address space.
|
||||||
if ( desc->mkdir(&ctx, ".initrd-links", 0777) != 0 )
|
addr_t mapat = initrd_addr_alloc.from;
|
||||||
|
for ( size_t i = 0; i < size; i += Page::Size() )
|
||||||
|
if ( !Memory::Map(physaddr + i, mapat + i, PROT_KREAD) )
|
||||||
|
PanicF("Unable to map the init ramdisk into virtual memory");
|
||||||
|
Memory::Flush();
|
||||||
|
|
||||||
|
struct initrd_context ctx;
|
||||||
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
|
ctx.initrd = (uint8_t*) mapat;
|
||||||
|
ctx.initrd_size = size;
|
||||||
|
SetupKernelIOCtx(&ctx.ioctx);
|
||||||
|
|
||||||
|
if ( size < sizeof(*ctx.sb) )
|
||||||
|
PanicF("initrd is too small");
|
||||||
|
ctx.sb = (initrd_superblock_t*) ctx.initrd;
|
||||||
|
|
||||||
|
if ( !String::StartsWith(ctx.sb->magic, "sortix-initrd") )
|
||||||
|
PanicF("Invalid magic value in initrd. This means the ramdisk may have "
|
||||||
|
"been corrupted by the bootloader, or that an incompatible file "
|
||||||
|
"has been passed to the kernel.");
|
||||||
|
|
||||||
|
if ( strcmp(ctx.sb->magic, "sortix-initrd-1") == 0 )
|
||||||
|
PanicF("Sortix initrd format version 1 is no longer supported.");
|
||||||
|
|
||||||
|
if ( strcmp(ctx.sb->magic, "sortix-initrd-2") != 0 )
|
||||||
|
PanicF("The initrd has a format that isn't supported. Perhaps it is "
|
||||||
|
"too new? Try downgrade or regenerate the initrd.");
|
||||||
|
|
||||||
|
if ( size < ctx.sb->fssize )
|
||||||
|
PanicF("The initrd said it is %u bytes, but the kernel was only passed "
|
||||||
|
"%zu bytes by the bootloader, which is not enough.",
|
||||||
|
ctx.sb->fssize, size);
|
||||||
|
|
||||||
|
uint32_t amount = ctx.sb->fssize - ctx.sb->sumsize;
|
||||||
|
uint8_t* filesum = ctx.initrd + amount;
|
||||||
|
if ( ctx.sb->sumalgorithm != INITRD_ALGO_CRC32 )
|
||||||
|
{
|
||||||
|
Log::PrintF("Warning: InitRD checksum algorithm not supported\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t crc32 = *((uint32_t*) filesum);
|
||||||
|
uint32_t filecrc32 = CRC32::Hash(ctx.initrd, amount);
|
||||||
|
if ( crc32 != filecrc32 )
|
||||||
|
{
|
||||||
|
PanicF("InitRD had checksum %X, expected %X: this means the ramdisk "
|
||||||
|
"may have been corrupted by the bootloader.", filecrc32, crc32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( desc->mkdir(&ctx.ioctx, ".initrd-links", 0777) != 0 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Ref<Descriptor> links(desc->open(&ctx, ".initrd-links", O_READ | O_DIRECTORY, 0));
|
if ( !(ctx.links = desc->open(&ctx.ioctx, ".initrd-links", O_READ | O_DIRECTORY, 0)) )
|
||||||
if ( !links )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( !ExtractNode(&ctx, sb->root, desc, links) )
|
if ( !ExtractNode(&ctx, initrd_get_inode(&ctx, ctx.sb->root), desc) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -387,20 +316,21 @@ bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
|
||||||
uint8_t dirent_data[sizeof(struct kernel_dirent) + sizeof(uintmax_t) * 3];
|
uint8_t dirent_data[sizeof(struct kernel_dirent) + sizeof(uintmax_t) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
while ( 0 < links->readdirents(&ctx, &dirent, sizeof(dirent_data), 1) &&
|
while ( 0 < ctx.links->readdirents(&ctx.ioctx, &dirent, sizeof(dirent_data), 1) &&
|
||||||
((const char*) dirent.d_name)[0] )
|
((const char*) dirent.d_name)[0] )
|
||||||
{
|
{
|
||||||
if ( ((const char*) dirent.d_name)[0] == '.' )
|
if ( ((const char*) dirent.d_name)[0] == '.' )
|
||||||
continue;
|
continue;
|
||||||
links->unlink(&ctx, dirent.d_name);
|
ctx.links->unlink(&ctx.ioctx, dirent.d_name);
|
||||||
links->lseek(&ctx, 0, SEEK_SET);
|
ctx.links->lseek(&ctx.ioctx, 0, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
desc->rmdir(&ctx, ".initrd-links");
|
ctx.links.Reset();
|
||||||
|
|
||||||
|
desc->rmdir(&ctx.ioctx, ".initrd-links");
|
||||||
|
|
||||||
// Unmap the pages and return the physical frames for reallocation.
|
// Unmap the pages and return the physical frames for reallocation.
|
||||||
addr_t mapat = initrd_addr_alloc.from;
|
for ( size_t i = 0; i < initrd_addr_alloc.size; i += Page::Size() )
|
||||||
for ( size_t i = 0; i < initrdsize; i += Page::Size() )
|
|
||||||
{
|
{
|
||||||
if ( !Memory::LookUp(mapat + i, NULL, NULL) )
|
if ( !Memory::LookUp(mapat + i, NULL, NULL) )
|
||||||
continue;
|
continue;
|
||||||
|
@ -409,8 +339,6 @@ bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
|
||||||
}
|
}
|
||||||
Memory::Flush();
|
Memory::Flush();
|
||||||
|
|
||||||
initrdsize = 0;
|
|
||||||
|
|
||||||
// Free the used virtual address space.
|
// Free the used virtual address space.
|
||||||
FreeKernelAddress(&initrd_addr_alloc);
|
FreeKernelAddress(&initrd_addr_alloc);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue