diff --git a/mkinitrd/Makefile b/mkinitrd/Makefile index 4b1ff79b..87fe53f0 100644 --- a/mkinitrd/Makefile +++ b/mkinitrd/Makefile @@ -7,7 +7,7 @@ CXXFLAGS?=$(OPTLEVEL) SORTIXKERNEL=../kernel -CPPFLAGS:=$(CPPFLAGS) -I$(SORTIXKERNEL)/include -I. +CPPFLAGS:=$(CPPFLAGS) -DVERSIONSTR=\"$(VERSION)\" -I$(SORTIXKERNEL)/include -I. CXXFLAGS:=$(CXXFLAGS) -Wall -Wextra -fno-exceptions -fno-rtti BINARIES=mkinitrd initrdfs diff --git a/mkinitrd/mkinitrd.cpp b/mkinitrd/mkinitrd.cpp index 43f23146..8a533b05 100644 --- a/mkinitrd/mkinitrd.cpp +++ b/mkinitrd/mkinitrd.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014. This file is part of Sortix. @@ -22,20 +22,26 @@ *******************************************************************************/ -#include #include +#include + +#include #include #include #include #include -#include #include +#include #include #include -#include #include + #include +#if !defined(VERSIONSTR) +#define VERSIONSTR "unknown version" +#endif + #include "crc32.h" #include "rules.h" @@ -158,14 +164,19 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, virt_path = ""; struct stat st; - if ( lstat(real_path, &st) ) { perror(real_path); return NULL; } + if ( lstat(real_path, &st) != 0 ) + { + error(0, errno, "stat: %s", real_path); + return NULL; + } Node* cached = LookupCache(st.st_dev, st.st_ino); if ( cached ) return cached->nlink++, cached->refcount++, cached; Node* node = (Node*) calloc(1, sizeof(Node)); - if ( !node ) { return NULL; } + if ( !node ) + return NULL; node->nlink = 1; node->refcount = 1; @@ -175,7 +186,12 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, node->mtime = st.st_mtim.tv_sec; char* real_path_clone = strdup(real_path); - if ( !real_path_clone ) { perror("strdup"); free(node); return NULL; } + if ( !real_path_clone ) + { + error(0, errno, "strdup"); + free(node); + return NULL; + } node->path = real_path_clone; @@ -191,7 +207,12 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, } DIR* dir = opendir(real_path); - if ( !dir ) { perror(real_path); FreeNode(node); return NULL; } + if ( !dir ) + { + error(0, errno, "opendir: %s", real_path); + FreeNode(node); + return NULL; + } size_t real_path_len = strlen(real_path); size_t virt_path_len = strlen(virt_path); @@ -204,7 +225,12 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, 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; } + if ( !virt_subpath ) + { + error(0, errno, "malloc"); + successful = false; + break; + } stpcpy(stpcpy(stpcpy(virt_subpath, virt_path), "/"), entry->d_name); if ( strcmp(entry->d_name, ".") != 0 && @@ -217,7 +243,13 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, 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; } + if ( !real_subpath ) + { + free(virt_subpath); + error(0, errno, "malloc"); + successful = false; + break; + } stpcpy(stpcpy(stpcpy(real_subpath, real_path), "/"), entry->d_name); Node* child = NULL; @@ -229,7 +261,11 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, child = RecursiveSearch(real_subpath, virt_subpath, ino, node); free(real_subpath); free(virt_subpath); - if ( !child ) { successful = false; break; } + if ( !child ) + { + successful = false; + break; + } if ( node->direntsused == node->direntslength ) { @@ -237,13 +273,23 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, 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; } + if ( !newdirents ) + { + error(0, errno, "realloc"); + successful = false; + break; + } node->dirents = newdirents; node->direntslength = newlength; } char* nameclone = strdup(entry->d_name); - if ( !nameclone ) { perror("strdup"); successful = false; break; } + if ( !nameclone ) + { + error(0, errno, "strdup"); + successful = false; + break; + } DirEntry* entry = node->dirents + node->direntsused++; @@ -262,7 +308,7 @@ Node* RecursiveSearch(const char* real_path, const char* virt_path, bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname, Node* node) -{ { +{ if ( node->written ) return true; @@ -276,15 +322,18 @@ bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname, const size_t NAME_SIZE = 1024UL; char name[NAME_SIZE]; ssize_t namelen = readlink(node->path, name, NAME_SIZE); - if ( namelen < 0 ) { goto ioreadlink; } + if ( namelen < 0 ) + return error(0, errno, "readlink: %s", node->path), false; filesize = (uint32_t) namelen; - if ( pwriteall(fd, name, filesize, dataoff) < filesize ) goto ioread; + if ( pwriteall(fd, name, filesize, dataoff) < filesize ) + return error(0, errno, "read: %s", node->path), false; dataoff += filesize; } else if ( S_ISREG(node->mode) ) // Regular file { int nodefd = open(node->path, O_RDONLY); - if ( nodefd < 0 ) { goto ioopen; } + if ( nodefd < 0 ) + return error(0, errno, "open: %s", node->path), false; const size_t BUFFER_SIZE = 16UL * 1024UL; uint8_t buffer[BUFFER_SIZE]; ssize_t amount; @@ -293,13 +342,14 @@ bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname, if ( pwriteall(fd, buffer, amount, dataoff) < (size_t) amount ) { close(nodefd); - goto iowrite; + return error(0, errno, "write: %s", outputname), false; } dataoff += amount; filesize += amount; } close(nodefd); - if ( amount < 0 ) { goto ioread; } + if ( amount < 0 ) + return error(0, errno, "read: %s", node->path), false; } else if ( S_ISDIR(node->mode) ) // Directory { @@ -317,13 +367,13 @@ bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname, 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; + return error(0, errno, "write: %s", outputname), false; size_t padding = dirent.reclen - (entsize + (namelen+1)); for ( size_t i = 0; i < padding; i++ ) { uint8_t nul = 0; if ( pwrite(fd, &nul, 1, dataoff+entsize+namelen+1+i) != 1 ) - goto iowrite; + return error(0, errno, "write: %s", outputname), false; } filesize += dirent.reclen; dataoff += dirent.reclen; @@ -342,41 +392,33 @@ bool WriteNode(struct initrd_superblock* sb, int fd, const char* outputname, uint32_t inodepos = sb->inodeoffset + node->ino * sb->inodesize; uint32_t inodesize = sizeof(inode); - if ( pwriteall(fd, &inode, inodesize, inodepos) < inodesize ) goto iowrite; + if ( pwriteall(fd, &inode, inodesize, inodepos) < inodesize ) + return error(0, errno, "write: %s", outputname), false; uint32_t increment = dataoff - origfssize; sb->fssize += increment; return node->written = 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 ( !WriteNode(sb, fd, outputname, node) ) + return false; - if ( !S_ISDIR(node->mode) ) { return true; } + 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; } + if ( !strcmp(name, ".") || !strcmp(name, ".." ) ) + continue; + if ( !WriteNodeRecursive(sb, fd, outputname, child) ) + return false; } return true; @@ -397,7 +439,8 @@ bool Format(const char* outputname, int fd, uint32_t inodecount, Node* root) uint32_t inodebytecount = sb.inodesize * sb.inodecount; sb.fssize += inodebytecount; - if ( !WriteNodeRecursive(&sb, fd, outputname, root) ) { return false; } + if ( !WriteNodeRecursive(&sb, fd, outputname, root) ) + return false; uint32_t crcsize = sizeof(uint32_t); sb.sumalgorithm = INITRD_ALGO_CRC32; @@ -412,8 +455,10 @@ bool Format(const char* outputname, int fd, uint32_t inodecount, Node* root) 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; } + if ( !CRC32File(&crc, outputname, fd, 0, checksize) ) + return false; + if ( pwriteall(fd, &crc, crcsize, checksize) < crcsize ) + return false; return true; } @@ -426,101 +471,169 @@ bool Format(const char* pathname, uint32_t inodecount, Node* root) return result; } -void Usage(FILE* fp, const char* argv0) +static void compact_arguments(int* argc, char*** argv) { - fprintf(fp, "Usage: %s -o [-f ]\n", argv0); + for ( int i = 0; i < *argc; i++ ) + { + while ( i < *argc && !(*argv)[i] ) + { + for ( int n = i; n < *argc; n++ ) + (*argv)[n] = (*argv)[n+1]; + (*argc)--; + } + } +} + +bool get_option_variable(const char* option, char** varptr, + const char* arg, int argc, char** argv, int* ip, + const char* argv0) +{ + size_t option_len = strlen(option); + if ( strncmp(option, arg, option_len) != 0 ) + return false; + if ( arg[option_len] == '=' ) + { + *varptr = strdup(arg + option_len + 1); + return true; + } + if ( arg[option_len] != '\0' ) + return false; + if ( *ip + 1 == argc ) + { + fprintf(stderr, "%s: expected operand after `%s'\n", argv0, option); + exit(1); + } + *varptr = strdup(argv[++*ip]), argv[*ip] = NULL; + return true; +} + +#define GET_OPTION_VARIABLE(str, varptr) \ + get_option_variable(str, varptr, arg, argc, argv, &i, argv0) + +static void help(FILE* fp, const char* argv0) +{ + fprintf(fp, "Usage: %s [OPTION]... ROOT -o OUTPUT\n", argv0); fprintf(fp, "Creates a init ramdisk for the Sortix kernel.\n"); + fprintf(fp, "\n"); + fprintf(fp, "Mandatory arguments to long options are mandatory for short options too.\n"); + fprintf(fp, " --filter=FILE import filter rules from FILE\n"); + fprintf(fp, " -o, --output=FILE write result to FILE\n"); + fprintf(fp, " --help display this help and exit\n"); + fprintf(fp, " --version output version information and exit\n"); } -void Help(FILE* fp, const char* argv0) +static void version(FILE* fp, const char* argv0) { - Usage(fp, argv0); -} - -void Version(FILE* fp, const char* argv0) -{ - (void) argv0; - 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"); + fprintf(fp, "%s (Sortix) %s\n", argv0, VERSIONSTR); + fprintf(fp, "License GPLv3+: GNU GPL version 3 or later .\n"); + fprintf(fp, "This is free software: you are free to change and redistribute it.\n"); + fprintf(fp, "There is NO WARRANTY, to the extent permitted by law.\n"); } int main(int argc, char* argv[]) { + char* arg_filter = NULL; + char* arg_output = NULL; + const char* argv0 = argv[0]; - if ( argc < 2 ) { Usage(stdout, argv0); exit(0); } - const char* dest = NULL; for ( int i = 1; i < argc; i++ ) { - 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 ( argsleft < 1 ) - { - fprintf(stderr, "No output file specified\n"); - Usage(stderr, argv0); - exit(1); - } - dest = argv[++i]; argv[i] = NULL; + if ( arg[0] != '-' || !arg[1] ) continue; - } - if ( !strcmp(arg, "-f") || !strcmp(arg, "--filter") ) + argv[i] = NULL; + if ( !strcmp(arg, "--") ) + break; + if ( arg[1] != '-' ) { - if ( argsleft < 1 ) + while ( char c = *++arg ) switch ( c ) { - fprintf(stderr, "No filter rule file specified\n"); - Usage(stderr, argv0); + case 'o': + free(arg_output); + if ( *(arg+1) ) + arg_output = strdup(arg + 1); + else + { + if ( i + 1 == argc ) + { + error(0, 0, "option requires an argument -- 'o'"); + fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); + exit(125); + } + arg_output = strdup(argv[i+1]); + argv[++i] = NULL; + } + arg = "o"; + break; + default: + fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c); + help(stderr, argv0); exit(1); } - const char* path = argv[++i]; argv[i] = NULL; - FILE* fp = fopen(path, "r"); + } + else if ( !strcmp(arg, "--help") ) + help(stdout, argv0), exit(0); + else if ( !strcmp(arg, "--version") ) + version(stdout, argv0), exit(0); + + else if ( GET_OPTION_VARIABLE("--filter", &arg_filter) ) + { + FILE* fp = fopen(arg_filter, "r"); if ( !fp ) - error(1, errno, "%s", path); - if ( !path_filter.AddRulesFromFile(fp, stderr, path) ) + error(1, errno, "%s", arg_filter); + if ( !path_filter.AddRulesFromFile(fp, stderr, arg_filter) ) exit(1); fclose(fp); - continue; + free(arg_filter); + arg_filter = NULL; } - fprintf(stderr, "%s: unknown option: %s\n", argv0, arg); - Usage(stderr, argv0); + else if ( GET_OPTION_VARIABLE("--output", &arg_output) ) { } + else + { + fprintf(stderr, "%s: unknown option: %s\n", argv0, arg); + help(stderr, argv0); + exit(1); + } + } + + if ( argc < 2 ) + { + help(stdout, argv0); exit(1); } - const char* rootstr = NULL; - int args = 0; - for ( int i = 1; i < argc; i++ ) - { - if ( !argv[i] ) { continue; } - args++; - rootstr = argv[i]; - } + compact_arguments(&argc, &argv); - 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 ) + if ( argc < 2 ) { - fprintf(stderr, "%s: %s\n", argv0, errmsg), - Usage(stderr, argv0); + fprintf(stderr, "%s: No root specified\n", argv0), + help(stderr, argv0); exit(1); } + if ( 2 < argc ) + { + fprintf(stderr, "%s: Too many roots specified\n", argv0), + help(stderr, argv0); + exit(1); + } + + if ( !arg_output ) + { + fprintf(stderr, "%s: No output file specified\n", argv0), + help(stderr, argv0); + exit(1); + } + + const char* rootstr = argv[1]; + uint32_t inodecount = 1; Node* root = RecursiveSearch(rootstr, "/", &inodecount); - if ( !root ) { exit(1); } + if ( !root ) + exit(1); - if ( !Format(dest, inodecount, root) ) { exit(1); } + if ( !Format(arg_output, inodecount, root) ) + exit(1); FreeNode(root); diff --git a/system/Makefile b/system/Makefile index 7d4b8e2d..474c29c6 100644 --- a/system/Makefile +++ b/system/Makefile @@ -102,7 +102,7 @@ initrd: echo exclude /etc/$(OTHER_PLATFORM_1) >> $(INITRD_FILTER) echo exclude /include/$(OTHER_PLATFORM_1) >> $(INITRD_FILTER) echo exclude /tix/$(OTHER_PLATFORM_1) >> $(INITRD_FILTER) - mkinitrd $(ROOT)/ -o $(INITRD) -f $(INITRD_FILTER) + mkinitrd $(ROOT)/ -o $(INITRD) --filter $(INITRD_FILTER) rm -f $(INITRD_FILTER) gzip -v $(INITRD)