Implemented a new initrd format with better inode support.

This enables useful features such as directories, CRC32 checksums, and other
useful features. The initrdfs in the kernel is now hooked up against the new
API, although the kernel's current limited FS support is a problem for now.
To work around that, directories are not supported at runtime, although the
internal API understands them wonderfully. This will be fixed when the
kernel gets a real VFS.
This commit is contained in:
Jonas 'Sortie' Termansen 2012-03-23 19:36:51 +01:00
parent 887abdfe87
commit c39473157a
15 changed files with 1188 additions and 772 deletions

View File

@ -69,7 +69,7 @@ everything-all-archs:
# Initializing RamDisk
$(INITRD): suball
(cd $(INITRDDIR) && ../mkinitrd/mkinitrd * -o ../$(INITRD))
mkinitrd/mkinitrd initrd -o $(INITRD)
# Statistics
linecount:

3
mkinitrd/.gitignore vendored
View File

@ -1,3 +1,2 @@
mkinitrd
lsinitrd
catinitrd
initrdfs

View File

@ -1,12 +1,15 @@
SORTIXKERNEL=../sortix
LIBMAXSI=../libmaxsi
CPPFLAGS=-I../sortix/include
CXXFLAGS=-Wall
BINARIES=mkinitrd lsinitrd catinitrd
BINARIES=mkinitrd initrdfs
all: $(BINARIES)
%: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
%: %.cpp crc32.cpp $(LIBMAXSI)/ioleast.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $< crc32.cpp $(LIBMAXSI)/ioleast.cpp -o $@
clean:
rm -f $(BINARIES)

View File

@ -1,223 +0,0 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
catinitrd.cpp
Output files in a Sortix ramdisk.
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#include <unistd.h>
#include <sortix/initrd.h>
bool writeall(int fd, const void* p, size_t size)
{
const uint8_t* buffer = (const uint8_t*) p;
size_t bytesWritten = 0;
while ( bytesWritten < size )
{
ssize_t written = write(fd, buffer + bytesWritten, size - bytesWritten);
if ( written < 0 ) { return false; }
bytesWritten += written;
}
return true;
}
bool readall(int fd, void* p, size_t size)
{
uint8_t* buffer = (uint8_t*) p;
size_t bytesread = 0;
while ( bytesread < size )
{
ssize_t justread = read(fd, buffer + bytesread, size - bytesread);
if ( justread <= 0 ) { return false; }
bytesread += justread;
}
return true;
}
void usage(int argc, char* argv[])
{
printf("usage: %s [OPTIONS] <ramdisk> [files]\n", argv[0]);
printf("Options:\n");
printf(" -q Surpress normal output\n");
printf(" -v Be verbose\n");
printf(" --usage Display this screen\n");
printf(" --help Display this screen\n");
printf(" --version Display version information\n");
}
void version()
{
printf("catinitrd 0.1\n");
printf("Copyright (C) 2011 Jonas 'Sortie' Termansen\n");
printf("This is free software; see the source for copying conditions. There is NO\n");
printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
printf("website: http://www.maxsi.org/software/sortix/\n");
}
bool verbose = false;
int main(int argc, char* argv[])
{
if ( argc < 2 ) { usage(argc, argv); return 0; }
const char* src = NULL;
for ( int i = 1; i < argc; i++ )
{
if ( strcmp(argv[i], "-q") == 0 )
{
verbose = false;
argv[i] = NULL;
}
else if ( strcmp(argv[i], "-v") == 0 )
{
verbose = true;
argv[i] = NULL;
}
else if ( strcmp(argv[i], "--usage") == 0 )
{
usage(argc, argv);
return 0;
}
else if ( strcmp(argv[i], "--help") == 0 )
{
usage(argc, argv);
return 0;
}
else if ( strcmp(argv[i], "--version") == 0 )
{
version();
return 0;
}
else if ( src == NULL )
{
src = argv[i];
argv[i] = NULL;
}
}
int fd = open(src, O_RDONLY);
if ( fd < 0 ) { error(0, errno, "%s", src); return 1; }
Sortix::InitRD::Header header;
if ( !readall(fd, &header, sizeof(header)) )
{
error(0, errno, "read: %s", src);
close(fd);
return 1;
}
if ( strcmp(header.magic, "sortix-initrd-1") != 0 )
{
error(0, 0, "not a sortix ramdisk: %s", src);
close(fd);
return 1;
}
int result = 0;
for ( int i = 1; i < argc; i++ )
{
if ( argv[i] == NULL ) { continue; }
bool found = false;
for ( uint32_t n = 0; n < header.numfiles; n++ )
{
off_t fileheaderpos = sizeof(header) + n * sizeof(Sortix::InitRD::FileHeader);
if ( lseek(fd, fileheaderpos, SEEK_SET ) < 0 )
{
error(0, errno, "seek: %s", src);
close(fd);
return 1;
}
Sortix::InitRD::FileHeader fileheader;
if ( !readall(fd, &fileheader, sizeof(fileheader)) )
{
error(0, errno, "read: %s", src);
close(fd);
return 1;
}
if ( strcmp(argv[i], fileheader.name) != 0 ) { continue; }
found = true;
if ( lseek(fd, fileheader.offset, SEEK_SET ) < 0 )
{
error(0, errno, "seek: %s", src);
close(fd);
return 1;
}
const size_t BUFFER_SIZE = 16384UL;
uint8_t buffer[BUFFER_SIZE];
uint32_t filesize = fileheader.size;
uint32_t readsofar = 0;
while ( readsofar < filesize )
{
uint32_t left = filesize-readsofar;
size_t toread = (left < BUFFER_SIZE) ? left : BUFFER_SIZE;
ssize_t bytesread = read(fd, buffer, toread);
if ( bytesread <= 0 )
{
error(0, errno, "read: %s", src);
close(fd);
return 1;
}
if ( !writeall(1, buffer, bytesread) )
{
error(0, errno, "write: <stdout>");
close(fd);
return 1;
}
readsofar += bytesread;
}
}
if ( !found )
{
result |= 1;
error(0, ENOENT, "%s", argv[i]);
}
}
close(fd);
return result;
}

94
mkinitrd/crc32.cpp Normal file
View File

@ -0,0 +1,94 @@
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
COPYRIGHT(C) KRZYSZTOF DABROWSKI 1999, 2000.
COPYRIGHT(C) ElysiuM deeZine 1999, 2000.
Based on implementation by Finn Yannick Jacobs.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
crc32.cpp
Calculates a CRC32 Checksum on binary data.
*******************************************************************************/
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <error.h>
#include "crc32.h"
void GenerateCRC32Table(uint32_t tabel[256])
{
uint32_t poly = 0xEDB88320U;
for ( uint32_t i = 0; i < 256; i++ )
{
uint32_t crc = i;
for ( uint32_t j = 8; 0 < j; j-- )
{
if ( crc & 1 ) { crc = (crc >> 1) ^ poly; }
else { crc >>= 1; }
}
tabel[i] = crc;
}
}
uint32_t ContinueCRC32(uint32_t tabel[256], uint32_t crc, uint8_t* block,
size_t size)
{
for ( size_t i = 0; i < size; i++ )
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ tabel[(crc ^ *block++) & 0xFF];
}
return crc;
}
uint32_t FinishCRC32(uint32_t crc)
{
return crc ^ 0xFFFFFFFF;
}
uint32_t CRC32(uint8_t* block, size_t size)
{
uint32_t tabel[256];
GenerateCRC32Table(tabel);
return FinishCRC32(ContinueCRC32(tabel, CRC32_START_SEED, block, size));
}
bool CRC32File(uint32_t* result, const char* name, int fd, off_t offset,
off_t length)
{
uint32_t tabel[256];
GenerateCRC32Table(tabel);
uint32_t crc = CRC32_START_SEED;
const size_t BUFFER_SIZE = 16UL * 1024UL;
uint8_t buffer[BUFFER_SIZE];
off_t sofar = 0;
ssize_t amount;
while ( sofar < length &&
0 < (amount = pread(fd, buffer, BUFFER_SIZE, offset + sofar)) )
{
if ( length - sofar < amount ) { amount = length - sofar; }
crc = ContinueCRC32(tabel, crc, buffer, amount);
sofar += amount;
}
if ( amount < 0 ) { error(0, errno, "read: %s", name); return false; }
if ( sofar < length ) { error(0, EIO, "read: %s", name); return false; }
crc = FinishCRC32(crc);
*result = crc;
return true;
}

40
mkinitrd/crc32.h Normal file
View File

@ -0,0 +1,40 @@
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
COPYRIGHT(C) KRZYSZTOF DABROWSKI 1999, 2000.
COPYRIGHT(C) ElysiuM deeZine 1999, 2000.
Based on implementation by Finn Yannick Jacobs.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
crc32.h
Calculates a CRC32 Checksum on binary data.
*******************************************************************************/
#ifndef CRC32_H
#define CRC32_H
const uint32_t CRC32_START_SEED = 0xFFFFFFFF;
void GenerateCRC32Table(uint32_t tabel[256]);
uint32_t ContinueCRC32(uint32_t tabel[256], uint32_t crc, uint8_t* block,
size_t size);
uint32_t FinishCRC32(uint32_t crc);
uint32_t CRC32(uint8_t* block, size_t size);
bool CRC32File(uint32_t* result, const char* name, int fd, off_t offset,
off_t length);
#endif

349
mkinitrd/initrdfs.cpp Normal file
View File

@ -0,0 +1,349 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
initrdfs.cpp
Provides access to filesystems in the Sortix kernel initrd format.
*******************************************************************************/
#include <sys/types.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sortix/initrd.h>
#include "crc32.h"
#if !defined(sortix)
__BEGIN_DECLS
size_t preadall(int fd, void* buf, size_t count, off_t off);
size_t preadleast(int fd, void* buf, size_t least, size_t max, off_t off);
size_t pwriteall(int fd, const void* buf, size_t count, off_t off);
size_t pwriteleast(int fd, const void* buf, size_t least, size_t max, off_t off);
size_t readall(int fd, void* buf, size_t count);
size_t readleast(int fd, void* buf, size_t least, size_t max);
size_t writeall(int fd, const void* buf, size_t count);
size_t writeleast(int fd, const void* buf, size_t least, size_t max);
__END_DECLS
#endif
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)
{
return preadall(fd, dest, sizeof(*dest), 0) == sizeof(*dest);
}
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 ReadChecksum(int fd, initrd_superblock_t* sb, uint8_t* dest)
{
uint32_t offset = sb->fssize - sb->sumsize;
return preadall(fd, dest, sb->sumsize, offset) == sb->sumsize;
}
uint8_t* GetChecksum(int fd, initrd_superblock_t* sb)
{
uint8_t* checksum = (uint8_t*) malloc(sb->sumsize);
if ( !checksum ) { return NULL; }
if ( !ReadChecksum(fd, sb, checksum) ) { free(checksum); return NULL; }
return checksum;
}
bool ReadInode(int fd, initrd_superblock_t* sb, uint32_t ino,
initrd_inode_t* dest)
{
uint32_t inodepos = sb->inodeoffset + sb->inodesize * ino;
return preadall(fd, dest, sizeof(*dest), inodepos) == sizeof(*dest);
}
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)
{
if ( inode->size < size ) { errno = EINVAL; return false; }
return preadall(fd, dest, size, inode->dataoffset) == size;
}
uint8_t* GetInodeData(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) ) { free(buf); return NULL; }
return buf;
}
uint8_t* GetInodeData(int fd, initrd_superblock_t* sb, initrd_inode_t* inode)
{
return GetInodeData(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);
if ( dirent->namelen && !strcmp(dirent->name, name) )
{
result = dirent->inode;
break;
}
offset += dirent->reclen;
}
free(direntries);
if ( !result ) { errno = ENOENT; }
return result;
}
bool CheckSumCRC32(const char* name, int fd, initrd_superblock_t* sb)
{
uint32_t* checksump = (uint32_t*) GetChecksum(fd, sb);
if ( !checksump ) { return false; }
uint32_t checksum = *checksump;
free(checksump);
uint32_t amount = sb->fssize - sb->sumsize;
uint32_t filesum;
if ( !CRC32File(&filesum, name, fd, 0, amount) ) { return false; }
if ( checksum != filesum ) { errno = EILSEQ; return false; }
return true;
}
bool CheckSum(const char* name, int fd, initrd_superblock_t* sb)
{
switch ( sb->sumalgorithm )
{
case INITRD_ALGO_CRC32: return CheckSumCRC32(name, fd, sb);
default:
fprintf(stderr, "Warning: unsupported checksum algorithm: %s\n", name);
return true;
}
}
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) ) { return false; }
if ( writeall(1, buffer, count) != count ) { return false; }
sofar += count;
}
return true;
}
void Usage(FILE* fp, const char* argv0)
{
fprintf(fp, "usage: %s [--check] <INITRD> (ls | cat) <PATH>\n", argv0);
fprintf(fp, "Accesses data in a Sortix kernel init ramdisk.\n");
}
void Help(FILE* fp, const char* argv0)
{
Usage(fp, argv0);
}
void Version(FILE* fp, const char* argv0)
{
fprintf(fp, "initrdfs 0.2\n");
fprintf(fp, "Copyright (C) 2012 Jonas 'Sortie' Termansen\n");
fprintf(fp, "This is free software; see the source for copying conditions. There is NO\n");
fprintf(fp, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
fprintf(fp, "website: http://www.maxsi.org/software/sortix/\n");
}
int main(int argc, char* argv[])
{
bool all = false;
bool check = false;
const char* argv0 = argv[0];
if ( argc < 2 ) { Usage(stdout, argv0); exit(0); }
for ( int i = 1; i < argc; i++ )
{
const char* arg = argv[i];
if ( arg[0] != '-' ) { continue; }
argv[i] = NULL;
if ( !strcmp(arg, "--") ) { break; }
if ( !strcmp(arg, "--help") ) { Help(stdout, argv0); exit(0); }
if ( !strcmp(arg, "--usage") ) { Usage(stdout, argv0); exit(0); }
if ( !strcmp(arg, "--version") ) { Version(stdout, argv0); exit(0); }
if ( !strcmp(arg, "-a") ) { all = true; continue; }
if ( !strcmp(arg, "--check") ) { check = true; continue; }
fprintf(stderr, "%s: unknown option: %s\n", argv0, arg);
Usage(stderr, argv0);
exit(1);
}
const char* initrd = NULL;
const char* cmd = NULL;
const char* path = NULL;
int args = 0;
for ( int i = 1; i < argc; i++ )
{
if ( !argv[i] ) { continue; }
switch ( ++args )
{
case 1: initrd = argv[i]; break;
case 2: cmd = argv[i]; break;
case 3: path = argv[i]; break;
}
}
const char* errmsg = NULL;
if ( !errmsg && !initrd ) { errmsg = "no initrd specified"; }
if ( !errmsg && !cmd ) { errmsg = "no command specified"; }
if ( !errmsg && !path ) { errmsg = "no path specified"; }
if ( !errmsg && 3 < args ) { errmsg = "too many arguments"; }
if ( errmsg )
{
fprintf(stderr, "%s: %s\n", argv0, errmsg),
Usage(stderr, argv0);
exit(1);
}
int fd = open(initrd, O_RDONLY);
if ( fd < 0 ) { error(1, errno, "open: %s", initrd); }
initrd_superblock_t* sb = GetSuperBlock(fd);
if ( !sb ) { error(1, errno, "read: %s", initrd); }
if ( check && !CheckSum(initrd, fd, sb) )
{
error(1, errno, "checksum error: %s", initrd);
}
if ( path[0] != '/' ) { error(1, ENOENT, "%s", path); }
initrd_inode_t* root = GetInode(fd, sb, sb->root);
if ( !root ) { error(1, errno, "read: %s", initrd); }
initrd_inode_t* inode = ResolvePath(fd, sb, root, path+1);
if ( !inode ) { error(1, errno, "%s", path); }
free(root);
if ( !strcmp(cmd, "cat") )
{
if ( !PrintFile(fd, sb, inode) ) { error(1, errno, "%s", path); }
}
else if ( !strcmp(cmd, "ls") )
{
initrd_inode_t* dir = inode;
if ( !ListDirectory(fd, sb, dir, all) ) { error(1, errno, "%s", path); }
}
else
{
fprintf(stderr, "%s: unrecognized command: %s", argv0, cmd);
exit(1);
}
free(inode);
free(sb);
close(fd);
return 0;
}

View File

@ -1,155 +0,0 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
lsinitrd.cpp
Lists the files in a Sortix ramdisk.
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#include <unistd.h>
#include <sortix/initrd.h>
bool readall(int fd, void* p, size_t size)
{
uint8_t* buffer = (uint8_t*) p;
size_t bytesread = 0;
while ( bytesread < size )
{
ssize_t justread = read(fd, buffer + bytesread, size - bytesread);
if ( justread <= 0 ) { return false; }
bytesread += justread;
}
return true;
}
void usage(int argc, char* argv[])
{
printf("usage: %s [OPTIONS] <ramdisks>\n", argv[0]);
printf("Options:\n");
printf(" -q Surpress normal output\n");
printf(" -v Be verbose\n");
printf(" --usage Display this screen\n");
printf(" --help Display this screen\n");
printf(" --version Display version information\n");
}
void version()
{
printf("lsinitrd 0.1\n");
printf("Copyright (C) 2011 Jonas 'Sortie' Termansen\n");
printf("This is free software; see the source for copying conditions. There is NO\n");
printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
printf("website: http://www.maxsi.org/software/sortix/\n");
}
bool verbose = false;
int listfiles(const char* filepath)
{
int fd = open(filepath, O_RDONLY);
if ( fd < 0 ) { error(0, errno, "%s", filepath); return 1; }
Sortix::InitRD::Header header;
if ( !readall(fd, &header, sizeof(header)) )
{
error(0, errno, "read: %s", filepath);
close(fd);
return 1;
}
if ( strcmp(header.magic, "sortix-initrd-1") != 0 )
{
error(0, 0, "not a sortix ramdisk: %s", filepath);
close(fd);
return 1;
}
for ( uint32_t i = 0; i < header.numfiles; i++ )
{
Sortix::InitRD::FileHeader fileheader;
if ( !readall(fd, &fileheader, sizeof(fileheader)) )
{
error(0, errno, "read: %s", filepath);
close(fd);
return 1;
}
printf("%s\n", fileheader.name);
}
close(fd);
return 0;
}
int main(int argc, char* argv[])
{
if ( argc < 2 ) { usage(argc, argv); return 0; }
for ( int i = 1; i < argc; i++ )
{
if ( strcmp(argv[i], "-q") == 0 )
{
verbose = false;
argv[i] = NULL;
}
else if ( strcmp(argv[i], "-v") == 0 )
{
verbose = true;
argv[i] = NULL;
}
else if ( strcmp(argv[i], "--usage") == 0 )
{
usage(argc, argv);
return 0;
}
else if ( strcmp(argv[i], "--help") == 0 )
{
usage(argc, argv);
return 0;
}
else if ( strcmp(argv[i], "--version") == 0 )
{
version();
return 0;
}
}
int result = 0;
for ( int i = 1; i < argc; i++ )
{
if ( argv[i] == NULL ) { continue; }
result |= listfiles(argv[i]);
}
return result;
}

View File

@ -1,6 +1,6 @@
/******************************************************************************
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
@ -18,271 +18,408 @@
with Sortix. If not, see <http://www.gnu.org/licenses/>.
mkinitrd.cpp
Produces a simple ramdisk meant for bootstrapping the Sortix kernel.
Produces a simple ramdisk filesystem readable by the Sortix kernel.
******************************************************************************/
*******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sortix/initrd.h>
bool writeall(int fd, const void* p, size_t size)
#include "crc32.h"
#if !defined(sortix)
__BEGIN_DECLS
size_t preadall(int fd, void* buf, size_t count, off_t off);
size_t preadleast(int fd, void* buf, size_t least, size_t max, off_t off);
size_t pwriteall(int fd, const void* buf, size_t count, off_t off);
size_t pwriteleast(int fd, const void* buf, size_t least, size_t max, off_t off);
size_t readall(int fd, void* buf, size_t count);
size_t readleast(int fd, void* buf, size_t least, size_t max);
size_t writeall(int fd, const void* buf, size_t count);
size_t writeleast(int fd, const void* buf, size_t least, size_t max);
__END_DECLS
#endif
uint32_t HostModeToInitRD(mode_t mode)
{
const uint8_t* buffer = (const uint8_t*) p;
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;
}
size_t bytesWritten = 0;
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;
}
while ( bytesWritten < size )
struct Node;
struct DirEntry;
struct DirEntry
{
char* name;
Node* node;
};
struct Node
{
char* path;
uint32_t ino;
uint32_t nlink;
size_t direntsused;
size_t direntslength;
DirEntry* dirents;
mode_t mode;
time_t ctime;
time_t mtime;
};
void FreeNode(Node* node)
{
if ( 1 < node->nlink ) { node->nlink--; return; }
for ( size_t i = 0; i < node->direntsused; i++ )
{
ssize_t written = write(fd, buffer + bytesWritten, size - bytesWritten);
if ( written < 0 ) { return false; }
bytesWritten += written;
DirEntry* entry = node->dirents + i;
if ( strcmp(entry->name, ".") != 0 && strcmp(entry->name, "..") != 0 )
{
FreeNode(entry->node);
}
free(entry->name);
}
free(node->dirents);
free(node->path);
free(node);
}
Node* RecursiveSearch(const char* rootpath, uint32_t* ino, Node* parent = NULL)
{
struct stat st;
if ( lstat(rootpath, &st) ) { perror(rootpath); return NULL; }
Node* node = (Node*) calloc(1, sizeof(Node));
if ( !node ) { return NULL; }
node->mode = st.st_mode;
node->ino = (*ino)++;
node->ctime = st.st_ctime;
node->mtime = st.st_mtime;
char* pathclone = strdup(rootpath);
if ( !pathclone ) { perror("strdup"); free(node); return NULL; }
node->path = pathclone;
if ( !S_ISDIR(st.st_mode) ) { return node; }
DIR* dir = opendir(rootpath);
if ( !dir ) { perror(rootpath); FreeNode(node); return NULL; }
size_t rootpathlen = strlen(rootpath);
bool successful = true;
struct dirent* entry;
while ( (entry = readdir(dir)) )
{
size_t namelen = strlen(entry->d_name);
size_t subpathlen = namelen + 1 + rootpathlen;
char* subpath = (char*) malloc(subpathlen+1);
if ( !subpath ) { perror("malloc"); successful = false; break; }
stpcpy(stpcpy(stpcpy(subpath, rootpath), "/"), entry->d_name);
Node* child = NULL;
if ( !strcmp(entry->d_name, ".") ) { child = node; }
if ( !strcmp(entry->d_name, "..") ) { child = parent ? parent : node; }
if ( !child ) { child = RecursiveSearch(subpath, ino, node); }
free(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(DirEntry) * newlength;
DirEntry* newdirents = (DirEntry*) realloc(node->dirents, newsize);
if ( !newdirents ) { perror("realloc"); successful = false; break; }
node->dirents = newdirents;
node->direntslength = newlength;
}
char* nameclone = strdup(entry->d_name);
if ( !nameclone ) { perror("strdup"); successful = false; break; }
DirEntry* entry = node->dirents + node->direntsused++;
entry->name = nameclone;
entry->node = child;
}
closedir(dir);
if ( !successful ) { FreeNode(node); return NULL; }
return node;
}
bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname,
Node* node)
{ {
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 ) { goto ioreadlink; }
filesize = (uint32_t) namelen;
if ( pwriteall(fd, name, filesize, dataoff) < filesize ) goto ioread;
dataoff += filesize;
}
else if ( S_ISREG(node->mode) ) // Regular file
{
int nodefd = open(node->path, O_RDONLY);
if ( nodefd < 0 ) { goto ioopen; }
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);
goto iowrite;
}
dataoff += amount;
filesize += amount;
}
close(nodefd);
if ( amount < 0 ) { goto ioread; }
}
else if ( S_ISDIR(node->mode) ) // Directory
{
for ( size_t i = 0; i < node->direntsused; i++ )
{
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 % 4; // Align entries.
size_t entsize = sizeof(dirent);
ssize_t hdramt = pwriteall(fd, &dirent, entsize, dataoff);
ssize_t nameamt = pwriteall(fd, name, namelen+1, dataoff + entsize);
if ( hdramt < (ssize_t) entsize || nameamt < (ssize_t) (namelen+1) )
goto iowrite;
filesize += dirent.reclen;
dataoff += dirent.reclen;
}
}
struct initrd_inode inode;
inode.mode = HostModeToInitRD(node->mode);
inode.uid = 1;
inode.gid = 1;
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);
if ( pwriteall(fd, &inode, inodesize, inodepos) < inodesize ) goto iowrite;
uint32_t increment = dataoff - origfssize;
sb->fssize += increment;
return true;
}
ioreadlink:
error(0, errno, "readlink: %s", node->path);
return false;
ioopen:
error(0, errno, "open: %s", node->path);
return false;
ioread:
error(0, errno, "read: %s", node->path);
return false;
iowrite:
error(0, errno, "write: %s", outputname);
return false;
}
bool WriteNodeRecursive(struct initrd_superblock* sb, int fd,
const char* outputname, 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++ )
{
DirEntry* entry = node->dirents + i;
const char* name = entry->name;
Node* child = entry->node;
if ( !strcmp(name, ".") || !strcmp(name, ".." ) ) { continue; }
if ( !WriteNodeRecursive(sb, fd, outputname, child) ) { return false; }
}
return true;
}
uint8_t ContinueChecksum(uint8_t checksum, const void* p, size_t size)
bool Format(const char* outputname, int fd, uint32_t inodecount, Node* root)
{
const uint8_t* buffer = (const uint8_t*) p;
while ( size-- )
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(initrd_inode);
sb.inodeoffset = sizeof(sb);
sb.inodecount = inodecount;
sb.root = root->ino;
uint32_t inodebytecount = sb.inodesize * sb.inodecount;
sb.fssize += inodebytecount;
if ( !WriteNodeRecursive(&sb, fd, outputname, root) ) { return false; }
uint32_t crcsize = sizeof(uint32_t);
sb.sumalgorithm = INITRD_ALGO_CRC32;
sb.sumsize = crcsize;
sb.fssize += sb.sumsize;
if ( pwriteall(fd, &sb, sizeof(sb), 0) < sizeof(sb) )
{
checksum += *buffer++;
error(0, errno, "write: %s", outputname);
return false;
}
return checksum;
uint32_t checksize = sb.fssize - sb.sumsize;
uint32_t crc;
if ( !CRC32File(&crc, outputname, fd, 0, checksize) ) { return false; }
if ( pwriteall(fd, &crc, crcsize, checksize) < crcsize ) { return false; }
return true;
}
void usage(int argc, char* argv[])
bool Format(const char* pathname, uint32_t inodecount, Node* root)
{
printf("usage: %s [OPTIONS] <files>\n", argv[0]);
printf("Options:\n");
printf(" -o <file> Write the ramdisk to this file\n");
printf(" -q Surpress normal output\n");
printf(" -v Be verbose\n");
printf(" --usage Display this screen\n");
printf(" --help Display this screen\n");
printf(" --version Display version information\n");
int fd = open(pathname, O_RDWR | O_CREAT | O_TRUNC, 0666);
bool result = Format(pathname, fd, inodecount, root);
close(fd);
return result;
}
void version()
void Usage(FILE* fp, const char* argv0)
{
printf("mkinitrd 0.1\n");
printf("Copyright (C) 2011 Jonas 'Sortie' Termansen\n");
printf("This is free software; see the source for copying conditions. There is NO\n");
printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
printf("website: http://www.maxsi.org/software/sortix/\n");
fprintf(fp, "usage: %s <ROOT> -o <DEST>\n", argv0);
fprintf(fp, "Creates a init ramdisk for the Sortix kernel.\n");
}
bool verbose = false;
void Help(FILE* fp, const char* argv0)
{
Usage(fp, argv0);
}
void Version(FILE* fp, const char* argv0)
{
fprintf(fp, "mkinitrd 0.2\n");
fprintf(fp, "Copyright (C) 2012 Jonas 'Sortie' Termansen\n");
fprintf(fp, "This is free software; see the source for copying conditions. There is NO\n");
fprintf(fp, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
fprintf(fp, "website: http://www.maxsi.org/software/sortix/\n");
}
int main(int argc, char* argv[])
{
const char* argv0 = argv[0];
if ( argc < 2 ) { Usage(stdout, argv0); exit(0); }
const char* dest = NULL;
if ( argc < 2 ) { usage(argc, argv); return 0; }
uint32_t numfiles = 0;
for ( int i = 1; i < argc; i++ )
{
if ( strcmp(argv[i], "-o") == 0 )
int argsleft = argc - i - 1;
const char* arg = argv[i];
if ( arg[0] != '-' ) { continue; }
argv[i] = NULL;
if ( !strcmp(arg, "--") ) { break; }
if ( !strcmp(arg, "--help") ) { Help(stdout, argv0); exit(0); }
if ( !strcmp(arg, "--usage") ) { Usage(stdout, argv0); exit(0); }
if ( !strcmp(arg, "--version") ) { Version(stdout, argv0); exit(0); }
if ( !strcmp(arg, "-o") || !strcmp(arg, "--output") )
{
if ( i + 1 < argc )
if ( argsleft < 1 )
{
dest = argv[i+1];
argv[i+1] = NULL;
fprintf(stderr, "No output file specified\n");
Usage(stderr, argv0);
exit(1);
}
argv[i] = NULL;
i++;
}
else if ( strcmp(argv[i], "-q") == 0 )
{
verbose = false;
argv[i] = NULL;
}
else if ( strcmp(argv[i], "-v") == 0 )
{
verbose = true;
argv[i] = NULL;
}
else if ( strcmp(argv[i], "--usage") == 0 )
{
usage(argc, argv);
return 0;
}
else if ( strcmp(argv[i], "--help") == 0 )
{
usage(argc, argv);
return 0;
}
else if ( strcmp(argv[i], "--version") == 0 )
{
version();
return 0;
}
else
{
numfiles++;
dest = argv[++i]; argv[i] = NULL;
continue;
}
fprintf(stderr, "%s: unknown option: %s\n", argv0, arg);
Usage(stderr, argv0);
exit(1);
}
if ( dest == NULL )
{
fprintf(stderr, "%s: no output file specified\n", argv[0]);
return 0;
}
int fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if ( fd < 0 )
{
error(0, errno, "%s", dest);
return 1;
}
// Keep track of the file checksum.
Sortix::InitRD::Trailer trailer;
trailer.sum = 0;
// Write the initrd headers.
Sortix::InitRD::Header header;
memset(&header, 0, sizeof(header));
strcpy(header.magic, "sortix-initrd-1");
header.numfiles = numfiles;
trailer.sum = ContinueChecksum(trailer.sum, &header, sizeof(header));
if ( !writeall(fd, &header, sizeof(header)) )
{
error(0, errno, "write: %s", dest);
close(fd);
unlink(dest);
return 1;
}
uint32_t fileoffset = sizeof(header) + numfiles * sizeof(Sortix::InitRD::FileHeader);
uint32_t filenum = 0;
const char* rootstr = NULL;
int args = 0;
for ( int i = 1; i < argc; i++ )
{
const char* file = argv[i];
if ( file == NULL ) { continue; }
Sortix::InitRD::FileHeader fileheader;
memset(&fileheader, 0, sizeof(fileheader));
if ( sizeof(fileheader.name) - 1 < strlen(file) )
{
fprintf(stderr, "%s: file name is too long: %s\n", argv[0], file);
close(fd);
unlink(dest);
return 1;
}
int filefd = open(file, O_RDONLY);
if ( filefd < 0 )
{
error(0, errno, "%s", file);
close(fd);
unlink(dest);
return 1;
}
if ( verbose )
{
fprintf(stderr, "%s\n", file);
}
struct stat st;
if ( fstat(filefd, &st) != 0 )
{
error(0, errno, "stat: %s", file);
close(fd);
unlink(dest);
return 1;
}
uint32_t filesize = st.st_size;
fileheader.permissions = 0755;
fileheader.size = filesize;
fileheader.owner = 1;
fileheader.group = 1;
fileheader.offset = fileoffset;
strcpy(fileheader.name, file);
off_t fileheaderpos = sizeof(header) + filenum * sizeof(Sortix::InitRD::FileHeader);
if ( lseek(fd, fileheaderpos, SEEK_SET ) < 0 )
{
error(0, errno, "seek: %s", dest);
close(fd);
unlink(dest);
return 1;
}
trailer.sum = ContinueChecksum(trailer.sum, &fileheader, sizeof(fileheader));
if ( !writeall(fd, &fileheader, sizeof(fileheader)) )
{
error(0, errno, "write: %s", dest);
close(fd);
unlink(dest);
return 1;
}
if ( lseek(fd, fileoffset, SEEK_SET ) < 0 )
{
error(0, errno, "seek: %s", dest);
close(fd);
unlink(dest);
return 1;
}
const size_t BUFFER_SIZE = 16384UL;
uint8_t buffer[BUFFER_SIZE];
uint32_t readsofar = 0;
while ( readsofar < filesize )
{
uint32_t left = filesize-readsofar;
size_t toread = (left < BUFFER_SIZE) ? left : BUFFER_SIZE;
ssize_t bytesread = read(filefd, buffer, toread);
if ( bytesread <= 0 )
{
error(0, errno, "read: %s", file);
close(fd);
unlink(dest);
return 1;
}
trailer.sum = ContinueChecksum(trailer.sum, &buffer, bytesread);
if ( !writeall(fd, buffer, bytesread) )
{
error(0, errno, "write: %s", dest);
close(fd);
unlink(dest);
return 1;
}
readsofar += bytesread;
}
fileoffset += filesize;
filenum++;
close(filefd);
if ( !argv[i] ) { continue; }
args++;
rootstr = argv[i];
}
if ( !writeall(fd, &trailer, sizeof(trailer)) )
const char* errmsg = NULL;
if ( !errmsg && args < 1 ) { errmsg = "no root specified"; }
if ( !errmsg && 1 < args ) { errmsg = "too many roots"; }
if ( !errmsg && !dest ) { errmsg = "no destination specified"; }
if ( errmsg )
{
error(0, errno, "write: %s", dest);
close(fd);
unlink(dest);
return 1;
fprintf(stderr, "%s: %s\n", argv0, errmsg),
Usage(stderr, argv0);
exit(1);
}
uint32_t inodecount = 1;
Node* root = RecursiveSearch(rootstr, &inodecount);
if ( !root ) { exit(1); }
if ( !Format(dest, inodecount, root) ) { exit(1); }
FreeNode(root);
return 0;
}

View File

@ -1,6 +1,6 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
@ -141,11 +141,13 @@ namespace Sortix
typedef Device DevDirectory;
public:
DevInitFSDir();
DevInitFSDir(uint32_t dir);
virtual ~DevInitFSDir();
private:
size_t position;
uint32_t dir;
uint32_t numfiles;
public:
virtual void Rewind();
@ -153,9 +155,11 @@ namespace Sortix
};
DevInitFSDir::DevInitFSDir()
DevInitFSDir::DevInitFSDir(uint32_t dir)
{
position = 0;
this->position = 0;
this->dir = dir;
this->numfiles = InitRD::GetNumFiles(dir);
}
DevInitFSDir::~DevInitFSDir()
@ -170,17 +174,20 @@ namespace Sortix
int DevInitFSDir::Read(sortix_dirent* dirent, size_t available)
{
if ( available <= sizeof(sortix_dirent) ) { return -1; }
if ( InitRD::GetNumFiles() <= position )
if ( numfiles <= position )
{
dirent->d_namelen = 0;
dirent->d_name[0] = 0;
return 0;
}
const char* name = InitRD::GetFilename(position);
const char* name = InitRD::GetFilename(dir, position);
size_t namelen = String::Length(name);
size_t needed = sizeof(sortix_dirent) + namelen + 1;
// Oh right, the kernel is stupid and doesn't support dot and dotdot.
if ( name[0] == '.' ) { position++; return Read(dirent, available); }
if ( available < needed )
{
dirent->d_namelen = needed;
@ -210,13 +217,16 @@ namespace Sortix
if ( !path[0] || (path[0] == '/' && !path[1]) )
{
if ( lowerflags != O_SEARCH ) { Error::Set(EISDIR); return NULL; }
return new DevInitFSDir();
return new DevInitFSDir(InitRD::Root());
}
if ( *path++ != '/' ) { Error::Set(ENOENT); return NULL; }
const byte* buffer = InitRD::Open(path, &buffersize);
if ( !buffer ) { Error::Set(ENOENT); return NULL; }
uint32_t ino = InitRD::Traverse(InitRD::Root(), path);
if ( !ino ) { return NULL; }
const byte* buffer = InitRD::Open(ino, &buffersize);
if ( !buffer ) { return NULL; }
if ( lowerflags == O_SEARCH ) { Error::Set(ENOTDIR); return NULL; }
if ( lowerflags != O_RDONLY ) { Error::Set(EROFS); return NULL; }

View File

@ -1,6 +1,6 @@
/******************************************************************************
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
@ -14,46 +14,89 @@
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
initrd.h
Declares the structure of the Sortix ramdisk.
The Sortix init ramdisk filesystem format.
******************************************************************************/
*******************************************************************************/
#ifndef SORTIX_INITRD_H
#define SORTIX_INITRD_H
namespace Sortix
#include <features.h>
__BEGIN_DECLS
#define INITRD_ALGO_CRC32 0
#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
/* Intentionally not part of Sortix. */
/*#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
{
namespace InitRD
{
struct Header;
struct FileHeader;
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;
struct Header
{
char magic[16]; // Contains "sortix-initrd-1"
uint32_t numfiles;
// FileHeader[numfiles];
};
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;
struct FileHeader
{
mode_t permissions;
uid_t owner;
gid_t group;
uint32_t size;
uint32_t offset; // where the physical data is located.
char name[128];
};
typedef struct initrd_dirent
{
uint32_t inode;
uint16_t reclen;
uint16_t namelen;
char name[0];
} initrd_dirent_t;
struct Trailer
{
uint8_t sum; // sum of all bytes but the trailer.
};
}
}
__END_DECLS
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
@ -59,17 +59,25 @@ struct stat
#define S_IWUSR 0200
#define S_IRUSR 0400
#define S_IRWXU 0700
#define S_IFDIR 0040000
#define S_IFBLK 0060000
#define S_IFREG 0100000
#define S_IFLNK 0200000 /* not the same as in Linux */
/* TODO: Define the other useful values and implement their features. */
#define S_ISBLK(m) ((m) & S_IFBLK)
#define S_ISDIR(m) ((m) & S_IFDIR)
#define S_ISREG(m) ((m) & S_IFREG)
#define S_ISLNK(m) ((m) & S_IFLNK)
/* TODO: Define the other useful macros and implement their features. */
#define S_IFMT 0xF000
#define S_IFSOCK 0xC000
#define S_IFLNK 0xA000
#define S_IFREG 0x8000
#define S_IFBLK 0x6000
#define S_IFDIR 0x4000
#define S_IFCHR 0x2000
#define S_IFIFO 0x1000
/* Intentionally not part of Sortix. */
/*#define S_ISUID 0x0800 */
/*#define S_ISGID 0x0400 */
#define S_ISVTX 0x0200
#define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK)
#define S_ISLNK(mode) ((mode & S_IFMT) == S_IFLNK)
#define S_ISREG(mode) ((mode & S_IFMT) == S_IFREG)
#define S_ISBLK(mode) ((mode & S_IFMT) == S_IFBLK)
#define S_ISDIR(mode) ((mode & S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) ((mode & S_IFMT) == S_IFCHR)
#define S_ISFIFO(mode) ((mode & S_IFMT) == S_IFIFO)
__END_DECLS

View File

@ -1,6 +1,6 @@
/******************************************************************************
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
@ -14,119 +14,222 @@
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
initrd.cpp
Declares the structure of the Sortix ramdisk.
Provides low-level access to a Sortix init ramdisk.
******************************************************************************/
*******************************************************************************/
#include <sortix/kernel/platform.h>
#include <sortix/kernel/memorymanagement.h>
#include <sortix/stat.h>
#include <sortix/initrd.h>
#include "initrd.h"
#include <libmaxsi/error.h>
#include <libmaxsi/memory.h>
#include <libmaxsi/string.h>
#include <libmaxsi/crc32.h>
#include "initrd.h"
#include "syscall.h"
#include <sortix/kernel/memorymanagement.h>
#include <sortix/kernel/log.h> // DEBUG
using namespace Maxsi;
namespace Sortix
namespace Sortix {
namespace InitRD {
uint8_t* initrd;
size_t initrdsize;
const initrd_superblock_t* sb;
static uint32_t HostModeToInitRD(mode_t mode)
{
namespace InitRD
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;
}
static 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;
}
uint32_t Root()
{
return sb->root;
}
static const initrd_inode_t* GetInode(uint32_t inode)
{
if ( sb->inodecount <= inode ) { Error::Set(EINVAL); return NULL; }
uint32_t pos = sb->inodeoffset + sb->inodesize * inode;
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_atime = inode->mtime;
st->st_ctime = inode->ctime;
st->st_mtime = inode->mtime;
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) ) { Error::Set(ENOTDIR); return 0; }
uint32_t offset = 0;
while ( offset < inode->size )
{
byte* initrd;
size_t initrdsize;
#ifdef JSSORTIX
// JSVM never tells JSSortix how big the initrd is!
const bool CHECK_CHECKSUM = false;
#else
const bool CHECK_CHECKSUM = true;
#endif
size_t GetNumFiles()
uint32_t pos = inode->dataoffset + offset;
const initrd_dirent* dirent = (const initrd_dirent*) (initrd + pos);
if ( dirent->namelen && !String::Compare(dirent->name, name) )
{
Header* header = (Header*) initrd;
return header->numfiles;
}
const char* GetFilename(size_t index)
{
Header* header = (Header*) initrd;
if ( index >= header->numfiles ) { return NULL; }
FileHeader* fhtbl = (FileHeader*) (initrd + sizeof(Header));
FileHeader* fileheader = &(fhtbl[index]);
return fileheader->name;
return dirent->inode;
}
offset += dirent->reclen;
}
Error::Set(ENOENT);
return 0;
}
uint8_t ContinueChecksum(uint8_t checksum, const void* p, size_t size)
{
const uint8_t* buffer = (const uint8_t*) p;
while ( size-- )
{
checksum += *buffer++;
}
return checksum;
}
void CheckSum()
{
Trailer* trailer = (Trailer*) (initrd + initrdsize - sizeof(Trailer));
uint8_t checksum = ContinueChecksum(0, initrd, initrdsize - sizeof(Trailer));
if ( trailer->sum != checksum )
{
PanicF("InitRD Checksum failed: the ramdisk may have been "
"corrupted by the bootloader: Got %u instead of %u "
"when checking the ramdisk at 0x%p + 0x%zx bytes\n",
checksum, trailer->sum, initrd, initrdsize);
}
}
const char* GetFilename(uint32_t dir, size_t index)
{
const initrd_inode_t* inode = GetInode(dir);
if ( !inode ) { return 0; }
if ( !INITRD_S_ISDIR(inode->mode) ) { Error::Set(ENOTDIR); return 0; }
uint32_t offset = 0;
while ( offset < inode->size )
{
uint32_t pos = inode->dataoffset + offset;
const initrd_dirent* dirent = (const initrd_dirent*) (initrd + pos);
if ( index-- == 0 ) { return dirent->name; }
offset += dirent->reclen;
}
Error::Set(EINVAL);
return NULL;
}
void Init(addr_t phys, size_t size)
{
// First up, map the initrd onto the kernel's address space.
addr_t virt = Memory::GetInitRD();
size_t amount = 0;
while ( amount < size )
{
if ( !Memory::MapKernel(phys + amount, virt + amount) )
{
Panic("Unable to map the init ramdisk into virtual memory");
}
amount += 0x1000UL;
}
size_t GetNumFiles(uint32_t dir)
{
const initrd_inode_t* inode = GetInode(dir);
if ( !inode ) { return 0; }
if ( !INITRD_S_ISDIR(inode->mode) ) { Error::Set(ENOTDIR); return 0; }
uint32_t offset = 0;
size_t numentries = 0;
while ( offset < inode->size )
{
uint32_t pos = inode->dataoffset + offset;
const initrd_dirent* dirent = (const initrd_dirent*) (initrd + pos);
numentries++;
offset += dirent->reclen;
}
return numentries;
}
Memory::Flush();
initrd = (byte*) virt;
initrdsize = size;
if ( size < sizeof(Header) ) { PanicF("initrd.cpp: initrd is too small"); }
Header* header = (Header*) initrd;
if ( String::Compare(header->magic, "sortix-initrd-1") != 0 ) { PanicF("initrd.cpp: invalid magic value in the initrd"); }
size_t sizeneeded = sizeof(Header) + header->numfiles * sizeof(FileHeader);
if ( size < sizeneeded ) { PanicF("initrd.cpp: initrd is too small"); }
// TODO: We need to do more validation here!
if ( CHECK_CHECKSUM ) { CheckSum(); }
}
byte* Open(const char* filepath, size_t* size)
{
Header* header = (Header*) initrd;
FileHeader* fhtbl = (FileHeader*) (initrd + sizeof(Header));
for ( uint32_t i = 0; i < header->numfiles; i++ )
{
FileHeader* fileheader = &(fhtbl[i]);
if ( String::Compare(filepath, fileheader->name) != 0 ) { continue; }
*size = fileheader->size;
return initrd + fileheader->offset;
}
return NULL;
}
void CheckSum()
{
uint32_t amount = sb->fssize - sb->sumsize;
uint8_t* filesum = initrd + amount;
if ( sb->sumalgorithm != INITRD_ALGO_CRC32 )
{
Log::PrintF("Warning: InitRD checksum algorithm not supported\n");
return;
}
uint32_t crc32 = *((uint32_t*) filesum);
uint32_t filecrc32 = CRC32::Hash(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);
}
}
void Init(addr_t phys, size_t size)
{
// First up, map the initrd onto the kernel's address space.
addr_t virt = Memory::GetInitRD();
size_t amount = 0;
while ( amount < size )
{
if ( !Memory::MapKernel(phys + amount, virt + amount) )
{
Panic("Unable to map the init ramdisk into virtual memory");
}
amount += 0x1000UL;
}
Memory::Flush();
initrd = (uint8_t*) virt;
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 ( String::Compare(sb->magic, "sortix-initrd-1") == 0 )
{
Panic("Sortix initrd format version 1 is no longer supported.");
}
if ( String::Compare(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();
}
} // namespace InitRD
} // namespace Sortix

View File

@ -1,6 +1,6 @@
/******************************************************************************
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
@ -14,26 +14,29 @@
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
initrd.h
Declares the structure of the Sortix ramdisk.
Provides low-level access to a Sortix init ramdisk.
******************************************************************************/
*******************************************************************************/
#ifndef SORTIX_INITRD_KERNEL_H
#define SORTIX_INITRD_KERNEL_H
namespace Sortix
{
namespace InitRD
{
void Init(addr_t phys, size_t size);
byte* Open(const char* filepath, size_t* size);
const char* GetFilename(size_t index);
size_t GetNumFiles();
}
}
namespace Sortix {
namespace InitRD {
void Init(addr_t phys, size_t size);
uint32_t Root();
bool Stat(uint32_t inode, struct stat* st);
uint8_t* Open(uint32_t inode, size_t* size);
uint32_t Traverse(uint32_t inode, const char* name);
const char* GetFilename(uint32_t dir, size_t index);
size_t GetNumFiles(uint32_t dir);
} // namespace InitRD
} // namespace Sortix
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
@ -197,6 +197,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// time to load the initial user-space programs and start execution of
// the actual operating system.
uint32_t inode;
byte* program;
size_t programsize;
@ -214,7 +215,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
idle->addrspace = idleaddrspace;
Memory::SwitchAddressSpace(idleaddrspace);
Scheduler::SetDummyThreadOwner(idle);
program = InitRD::Open("idle", &programsize);
inode = InitRD::Traverse(InitRD::Root(), "idle");
if ( inode == NULL ) { PanicF("initrd did not contain 'idle'"); }
program = InitRD::Open(inode, &programsize);
if ( program == NULL ) { PanicF("initrd did not contain 'idle'"); }
addr_t idlestart = ELF::Construct(idle, program, programsize);
if ( !idlestart ) { Panic("could not construct ELF image for idle process"); }
@ -228,7 +231,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
init->addrspace = initaddrspace;
Memory::SwitchAddressSpace(initaddrspace);
Scheduler::SetDummyThreadOwner(init);
program = InitRD::Open("init", &programsize);
inode = InitRD::Traverse(InitRD::Root(), "init");
if ( inode == NULL ) { PanicF("initrd did not contain 'init'"); }
program = InitRD::Open(inode, &programsize);
if ( program == NULL ) { PanicF("initrd did not contain 'init'"); }
addr_t initstart = ELF::Construct(init, program, programsize);
if ( !initstart ) { Panic("could not construct ELF image for init process"); }