mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Support filtering paths in the mkinitrd program.
This will allow initrds to omit certain files, such as other initrds, irrelevant files, iles for another platform, and so on. This will be useful when initrd contain entire system roots.
This commit is contained in:
parent
2bfaa81f76
commit
25a988442e
6 changed files with 405 additions and 26 deletions
3
Makefile
3
Makefile
|
@ -112,7 +112,8 @@ all-archs:
|
|||
|
||||
# Initializing RamDisk
|
||||
$(INITRD): suball
|
||||
mkinitrd/mkinitrd $(SYSROOT)/bin/$(HOST) -o $(INITRD)
|
||||
echo > "$(INITRD).filter"
|
||||
mkinitrd/mkinitrd --filter "$(INITRD).filter" "$(SYSROOT)/bin/$(HOST)" -o "$(INITRD)"
|
||||
|
||||
# Statistics
|
||||
linecount:
|
||||
|
|
|
@ -13,9 +13,11 @@ endif
|
|||
|
||||
ifeq ($(HOST),i486-sortix)
|
||||
CPU:=x86
|
||||
OTHER_PLATFORMS=x86-64-sortix
|
||||
endif
|
||||
ifeq ($(HOST),x86_64-sortix)
|
||||
CPU:=x64
|
||||
OTHER_PLATFORMS=i486-sortix
|
||||
endif
|
||||
|
||||
ifndef BUILDCC
|
||||
|
|
|
@ -2,14 +2,14 @@ SORTIXKERNEL=../sortix
|
|||
LIBC=../libc
|
||||
|
||||
CPPFLAGS=-I../sortix/include
|
||||
CXXFLAGS=-Wall
|
||||
CXXFLAGS=-g -Wall -Wextra
|
||||
|
||||
BINARIES=mkinitrd initrdfs
|
||||
|
||||
all: $(BINARIES)
|
||||
|
||||
%: %.cpp crc32.cpp $(LIBC)/ioleast.cpp
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $< crc32.cpp $(LIBC)/ioleast.cpp -o $@
|
||||
%: %.cpp crc32.cpp rules.cpp $(LIBC)/ioleast.cpp
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $< crc32.cpp rules.cpp $(LIBC)/ioleast.cpp -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(BINARIES)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
|||
#include <sortix/initrd.h>
|
||||
|
||||
#include "crc32.h"
|
||||
#include "rules.h"
|
||||
|
||||
#if !defined(sortix)
|
||||
__BEGIN_DECLS
|
||||
|
@ -131,6 +132,8 @@ size_t cacheused = 0;
|
|||
size_t cachelen = 0;
|
||||
CacheEntry* cache = NULL;
|
||||
|
||||
InclusionRules path_filter;
|
||||
|
||||
Node* LookupCache(dev_t dev, ino_t ino)
|
||||
{
|
||||
for ( size_t i = 0; i < cacheused; i++ )
|
||||
|
@ -158,10 +161,16 @@ bool AddToCache(Node* node, dev_t dev, ino_t ino)
|
|||
return true;
|
||||
}
|
||||
|
||||
Node* RecursiveSearch(const char* rootpath, uint32_t* ino, Node* parent = NULL)
|
||||
Node* RecursiveSearch(const char* real_path, const char* virt_path,
|
||||
uint32_t* ino, Node* parent = NULL)
|
||||
{
|
||||
printf("%s\n", virt_path);
|
||||
|
||||
if ( virt_path[0] == '/' && !virt_path[1] )
|
||||
virt_path = "";
|
||||
|
||||
struct stat st;
|
||||
if ( lstat(rootpath, &st) ) { perror(rootpath); return NULL; }
|
||||
if ( lstat(real_path, &st) ) { perror(real_path); return NULL; }
|
||||
|
||||
Node* cached = LookupCache(st.st_dev, st.st_ino);
|
||||
if ( cached ) { cached->refcount++; return cached; }
|
||||
|
@ -175,42 +184,61 @@ Node* RecursiveSearch(const char* rootpath, uint32_t* ino, Node* parent = NULL)
|
|||
node->ctime = st.st_ctime;
|
||||
node->mtime = st.st_mtime;
|
||||
|
||||
char* pathclone = strdup(rootpath);
|
||||
if ( !pathclone ) { perror("strdup"); free(node); return NULL; }
|
||||
char* real_path_clone = strdup(real_path);
|
||||
if ( !real_path_clone ) { perror("strdup"); free(node); return NULL; }
|
||||
|
||||
node->path = pathclone;
|
||||
node->path = real_path_clone;
|
||||
|
||||
if ( !S_ISDIR(st.st_mode) )
|
||||
{
|
||||
if ( !AddToCache(node, st.st_dev, st.st_ino) )
|
||||
{
|
||||
free(pathclone);
|
||||
free(real_path_clone);
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
DIR* dir = opendir(rootpath);
|
||||
if ( !dir ) { perror(rootpath); FreeNode(node); return NULL; }
|
||||
DIR* dir = opendir(real_path);
|
||||
if ( !dir ) { perror(real_path); FreeNode(node); return NULL; }
|
||||
|
||||
size_t rootpathlen = strlen(rootpath);
|
||||
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 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);
|
||||
|
||||
size_t virt_subpath_len = virt_path_len + 1 + namelen;
|
||||
char* virt_subpath = (char*) malloc(virt_subpath_len+1);
|
||||
if ( !virt_subpath ) { perror("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 &&
|
||||
!path_filter.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); perror("malloc"); successful = false; break; }
|
||||
stpcpy(stpcpy(stpcpy(real_subpath, real_path), "/"), 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 ( !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 )
|
||||
|
@ -410,7 +438,7 @@ bool Format(const char* pathname, uint32_t inodecount, Node* root)
|
|||
|
||||
void Usage(FILE* fp, const char* argv0)
|
||||
{
|
||||
fprintf(fp, "usage: %s <ROOT> -o <DEST>\n", argv0);
|
||||
fprintf(fp, "Usage: %s <ROOT> -o <DEST> [-f <PATH-FILTER>]\n", argv0);
|
||||
fprintf(fp, "Creates a init ramdisk for the Sortix kernel.\n");
|
||||
}
|
||||
|
||||
|
@ -422,8 +450,8 @@ void Help(FILE* fp, const char* argv0)
|
|||
void Version(FILE* fp, const char* argv0)
|
||||
{
|
||||
(void) argv0;
|
||||
fprintf(fp, "mkinitrd 0.3\n");
|
||||
fprintf(fp, "Copyright (C) 2012 Jonas 'Sortie' Termansen\n");
|
||||
fprintf(fp, "mkinitrd 0.4\n");
|
||||
fprintf(fp, "Copyright (C) 2012, 2013 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");
|
||||
|
@ -455,6 +483,23 @@ int main(int argc, char* argv[])
|
|||
dest = argv[++i]; argv[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
if ( !strcmp(arg, "-f") || !strcmp(arg, "--filter") )
|
||||
{
|
||||
if ( argsleft < 1 )
|
||||
{
|
||||
fprintf(stderr, "No filter rule file specified\n");
|
||||
Usage(stderr, argv0);
|
||||
exit(1);
|
||||
}
|
||||
const char* path = argv[++i]; argv[i] = NULL;
|
||||
FILE* fp = fopen(path, "r");
|
||||
if ( !fp )
|
||||
error(1, errno, "%s", path);
|
||||
if ( !path_filter.AddRulesFromFile(fp, stderr, path) )
|
||||
exit(1);
|
||||
fclose(fp);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "%s: unknown option: %s\n", argv0, arg);
|
||||
Usage(stderr, argv0);
|
||||
exit(1);
|
||||
|
@ -482,7 +527,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
uint32_t inodecount = 1;
|
||||
Node* root = RecursiveSearch(rootstr, &inodecount);
|
||||
Node* root = RecursiveSearch(rootstr, "/", &inodecount);
|
||||
if ( !root ) { exit(1); }
|
||||
|
||||
if ( !Format(dest, inodecount, root) ) { exit(1); }
|
||||
|
|
265
mkinitrd/rules.cpp
Normal file
265
mkinitrd/rules.cpp
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
rules.cpp
|
||||
Determines whether a given path is included in the filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rules.h"
|
||||
|
||||
static void error_fp(FILE* fp, int status, int errnum, const char* format, ...)
|
||||
{
|
||||
fprintf(fp, "%s: ", program_invocation_name);
|
||||
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vfprintf(fp, format, list);
|
||||
va_end(list);
|
||||
|
||||
if ( errnum )
|
||||
fprintf(fp, ": %s", strerror(errnum));
|
||||
fprintf(fp, "\n");
|
||||
if ( status )
|
||||
exit(status);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
InclusionRule::InclusionRule(const char* pattern, InclusionRuleType rule)
|
||||
{
|
||||
this->pattern = strdup(pattern);
|
||||
this->rule = rule;
|
||||
}
|
||||
|
||||
InclusionRule::~InclusionRule()
|
||||
{
|
||||
free(pattern);
|
||||
}
|
||||
|
||||
bool InclusionRule::MatchesPath(const char* path) const
|
||||
{
|
||||
return PathMatchesPattern(path, pattern);
|
||||
}
|
||||
|
||||
InclusionRules::InclusionRules()
|
||||
{
|
||||
rules = NULL;
|
||||
num_rules = num_rules_allocated = 0;
|
||||
default_inclusion = true;
|
||||
}
|
||||
|
||||
InclusionRules::~InclusionRules()
|
||||
{
|
||||
for ( size_t i = 0; i < num_rules; i++ )
|
||||
delete rules[i];
|
||||
delete[] rules;
|
||||
}
|
||||
|
||||
bool InclusionRules::IncludesPath(const char* path) const
|
||||
{
|
||||
bool determined = false;
|
||||
bool included = false;
|
||||
for ( size_t i = 0; i < num_rules; i++ )
|
||||
{
|
||||
InclusionRule* rule = rules[i];
|
||||
if ( !rule->MatchesPath(path) )
|
||||
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;
|
||||
return included;
|
||||
}
|
||||
|
||||
bool InclusionRules::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++ )
|
||||
delete rules[i];
|
||||
num_rules = new_num_rules;
|
||||
InclusionRule** new_rules = new InclusionRule*[new_length];
|
||||
for ( size_t i = 0; i < new_length && i < num_rules; i++ )
|
||||
new_rules[i] = rules[i];
|
||||
delete[] rules; rules = new_rules;
|
||||
num_rules_allocated = new_length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InclusionRules::AddRule(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(*line) ) line++;
|
||||
return line;
|
||||
}
|
||||
|
||||
static char* SkipWhitespace(char* line)
|
||||
{
|
||||
return (char*) SkipWhitespace((const char*) line);
|
||||
}
|
||||
|
||||
static bool IsLineComment(const char* line)
|
||||
{
|
||||
return !*line || *line == '#';
|
||||
}
|
||||
|
||||
static const char* IsLineCommand(const char* line, const char* command)
|
||||
{
|
||||
while ( *line && isspace(*line) ) line++;
|
||||
size_t cmdlen = strlen(command);
|
||||
if ( strncmp(line, command, cmdlen) != 0 )
|
||||
return NULL;
|
||||
if ( line[cmdlen] && !isspace(line[cmdlen]) )
|
||||
return NULL;
|
||||
while ( line[cmdlen] && isspace(line[cmdlen]) )
|
||||
cmdlen++;
|
||||
return line + cmdlen;
|
||||
}
|
||||
|
||||
bool InclusionRules::AddRulesFromFile(FILE* fp, FILE* err, 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_len && line[line_len-1] == '\n' )
|
||||
line[line_len-1] = '\0';
|
||||
line = SkipWhitespace(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, "true") )
|
||||
value = false;
|
||||
else
|
||||
{
|
||||
error_fp(err, 0, 0, "%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 )
|
||||
{
|
||||
error_fp(err, 0, 0, "%s:%zu: no parameter given", fpname,
|
||||
line_num);
|
||||
goto error_out;
|
||||
}
|
||||
const char* pattern = parameter;
|
||||
InclusionRuleType type = line[0] == 'e' ? RULE_EXCLUDE : RULE_INCLUDE;
|
||||
InclusionRule* rule = new InclusionRule(pattern, type);
|
||||
if ( !AddRule(rule) )
|
||||
goto error_out_errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_fp(err, 0, 0, "%s:%zu: line not understood: '%s'", fpname,
|
||||
line_num, line);
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
free(mem);
|
||||
if ( ferror(fp) )
|
||||
{
|
||||
error_out_errno:
|
||||
error_fp(err, 0, errno, "%s", fpname);
|
||||
error_out:
|
||||
ChangeRulesAmount(rules_at_start);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
66
mkinitrd/rules.h
Normal file
66
mkinitrd/rules.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
rules.h
|
||||
Determines whether a given path is included in the filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef RULES_H
|
||||
#define RULES_H
|
||||
|
||||
enum InclusionRuleType
|
||||
{
|
||||
RULE_INCLUDE,
|
||||
RULE_EXCLUDE,
|
||||
};
|
||||
|
||||
class InclusionRule
|
||||
{
|
||||
public:
|
||||
InclusionRule(const char* pattern, InclusionRuleType rule);
|
||||
~InclusionRule();
|
||||
bool MatchesPath(const char* path) const;
|
||||
|
||||
public:
|
||||
char* pattern;
|
||||
InclusionRuleType rule;
|
||||
|
||||
};
|
||||
|
||||
class InclusionRules
|
||||
{
|
||||
public:
|
||||
InclusionRules();
|
||||
~InclusionRules();
|
||||
bool IncludesPath(const char* path) const;
|
||||
bool AddRule(InclusionRule* rule);
|
||||
bool AddRulesFromFile(FILE* fp, FILE* err, const char* fpname);
|
||||
bool ChangeRulesAmount(size_t newnum);
|
||||
|
||||
public:
|
||||
InclusionRule** rules;
|
||||
size_t num_rules;
|
||||
size_t num_rules_allocated;
|
||||
bool default_inclusion;
|
||||
bool default_inclusion_determined;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue