diff --git a/Makefile b/Makefile index a8f8308c..25d0cc6a 100644 --- a/Makefile +++ b/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: diff --git a/compiler.mak b/compiler.mak index a1dacefa..28cde99d 100644 --- a/compiler.mak +++ b/compiler.mak @@ -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 diff --git a/mkinitrd/Makefile b/mkinitrd/Makefile index 19cdef50..a6a61a89 100644 --- a/mkinitrd/Makefile +++ b/mkinitrd/Makefile @@ -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) diff --git a/mkinitrd/mkinitrd.cpp b/mkinitrd/mkinitrd.cpp index 30ed77cb..9c251b65 100644 --- a/mkinitrd/mkinitrd.cpp +++ b/mkinitrd/mkinitrd.cpp @@ -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 #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 -o \n", argv0); + fprintf(fp, "Usage: %s -o [-f ]\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); } diff --git a/mkinitrd/rules.cpp b/mkinitrd/rules.cpp new file mode 100644 index 00000000..d9364616 --- /dev/null +++ b/mkinitrd/rules.cpp @@ -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 . + + rules.cpp + Determines whether a given path is included in the filesystem. + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/mkinitrd/rules.h b/mkinitrd/rules.h new file mode 100644 index 00000000..b4ef0602 --- /dev/null +++ b/mkinitrd/rules.h @@ -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 . + + 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