From 383ed329bffdec853bdb4c9c03e56ed3b86455da Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Thu, 17 Oct 2019 23:08:43 -0500 Subject: hscript: Implement diskid key (except execution) --- hscript/disk.cc | 45 +++++++++++++++++++++- hscript/disk.hh | 18 ++++++++- hscript/script.cc | 25 +++++++++++- tests/fixtures/0076-diskid-basic.installfile | 6 +++ tests/fixtures/0077-diskid-missing-id.installfile | 6 +++ .../fixtures/0078-diskid-diskid-loop0.installfile | 6 +++ tests/fixtures/0079-diskid-enoent.installfile | 6 +++ tests/fixtures/0080-diskid-tmp.installfile | 6 +++ tests/fixtures/0081-diskid-duplicate.installfile | 7 ++++ tests/spec/validator.rb | 34 ++++++++++++++++ 10 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/0076-diskid-basic.installfile create mode 100644 tests/fixtures/0077-diskid-missing-id.installfile create mode 100644 tests/fixtures/0078-diskid-diskid-loop0.installfile create mode 100644 tests/fixtures/0079-diskid-enoent.installfile create mode 100644 tests/fixtures/0080-diskid-tmp.installfile create mode 100644 tests/fixtures/0081-diskid-duplicate.installfile diff --git a/hscript/disk.cc b/hscript/disk.cc index f0466eb..cbd9517 100644 --- a/hscript/disk.cc +++ b/hscript/disk.cc @@ -16,7 +16,7 @@ #include #include #include /* mount */ -#include /* mkdir */ +#include /* mkdir, stat */ #include /* S_* */ #include /* access */ #include "disk.hh" @@ -24,6 +24,49 @@ using namespace Horizon::Keys; +Key *DiskId::parseFromData(const std::string &data, int lineno, int *errors, + int *warnings) { + std::string block, ident; + std::string::size_type block_end = data.find_first_of(' '); + if(block_end == std::string::npos) { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(lineno), + "diskid: expected an identification string", + "valid format for diskid is: [block] [id-string]"); + return nullptr; + } + + block = data.substr(0, block_end); + ident = data.substr(block_end + 1); + return new DiskId(lineno, block, ident); +} + +bool DiskId::validate(ScriptOptions options) const { + /* We only validate if running in an Installation Environment. */ + if(!options.test(InstallEnvironment)) return true; + + /* Unlike 'mount', 'diskid' *does* require that the block device exist + * before installation begins. This test is always valid. */ + struct stat blk_stat; + const char *block_c = _block.c_str(); + if(access(block_c, F_OK) != 0 || stat(block_c, &blk_stat) != 0) { + output_error("installfile:" + std::to_string(line), + "diskid: error opening device " + _block, + strerror(errno)); + return false; + } + if(!S_ISBLK(blk_stat.st_mode)) { + output_error("installfile:" + std::to_string(line), + "diskid: " + _block + " is not a valid block device"); + return false; + } + return true; +} + +bool DiskId::execute(ScriptOptions options) const { + return false; +} + Key *Mount::parseFromData(const std::string &data, int lineno, int *errors, int *warnings) { std::string dev, where, opt; diff --git a/hscript/disk.hh b/hscript/disk.hh index d849e2f..02ecb98 100644 --- a/hscript/disk.hh +++ b/hscript/disk.hh @@ -19,6 +19,21 @@ namespace Horizon { namespace Keys { class DiskId : public Key { +private: + const std::string _block; + const std::string _ident; + + DiskId(int _line, const std::string &my_block, const std::string &my_i) : + Key(_line), _block(my_block), _ident(my_i) {} +public: + /*! Retrieve the block device that this key identifies. */ + const std::string device() const { return this->_block; } + /*! Retrieve the identification for the block device. */ + const std::string ident() const { return this->_ident; } + + static Key *parseFromData(const std::string &, int, int*, int*); + bool validate(ScriptOptions) const override; + bool execute(ScriptOptions) const override; }; class DiskLabel : public Key { @@ -60,8 +75,7 @@ public: /*! Retrieve the mount options for this mount, if any. */ const std::string options() const { return this->_opts; } - static Key *parseFromData(const std::string &data, int lineno, int *errors, - int *warnings); + static Key *parseFromData(const std::string &, int, int*, int*); bool validate(ScriptOptions) const override; bool execute(ScriptOptions) const override; }; diff --git a/hscript/script.cc b/hscript/script.cc index f45c5f2..83957f8 100644 --- a/hscript/script.cc +++ b/hscript/script.cc @@ -86,6 +86,9 @@ struct Script::ScriptPrivate { /*! APK repositories */ std::vector< std::unique_ptr > repos; + /*! Disk identification keys */ + std::vector< std::unique_ptr > diskids; + /*! Store +key_obj+ representing the key +key_name+. * @param key_name The name of the key that is being stored. * @param obj The Key object associated with the key. @@ -164,6 +167,10 @@ struct Script::ScriptPrivate { std::unique_ptr repo(dynamic_cast(obj)); this->repos.push_back(std::move(repo)); return true; + } else if(key_name == "diskid") { + std::unique_ptr diskid(dynamic_cast(obj)); + this->diskids.push_back(std::move(diskid)); + return true; } else { return false; } @@ -318,13 +325,29 @@ const Script *Script::load(std::istream &sstream, const ScriptOptions opts) { bool Script::validate() const { int failures = 0; - std::set seen_mounts; + std::set seen_diskids, seen_mounts; std::map seen_iface; if(!this->internal->network->validate(this->opts)) failures++; if(!this->internal->hostname->validate(this->opts)) failures++; if(!this->internal->rootpw->validate(this->opts)) failures++; + for(auto &diskid : this->internal->diskids) { + if(!diskid->validate(this->opts)) { + failures++; + continue; + } + + /* Runner.Validate.diskid.Unique */ + if(seen_diskids.find(diskid->device()) != seen_diskids.end()) { + failures++; + output_error("installfile:" + std::to_string(diskid->lineno()), + "diskid: device " + diskid->device() + + " has already been identified"); + } + seen_diskids.insert(diskid->device()); + } + for(auto &mount : this->internal->mounts) { if(!mount->validate(this->opts)) { failures++; diff --git a/tests/fixtures/0076-diskid-basic.installfile b/tests/fixtures/0076-diskid-basic.installfile new file mode 100644 index 0000000..329e70c --- /dev/null +++ b/tests/fixtures/0076-diskid-basic.installfile @@ -0,0 +1,6 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +diskid /dev/sda SEAGATE diff --git a/tests/fixtures/0077-diskid-missing-id.installfile b/tests/fixtures/0077-diskid-missing-id.installfile new file mode 100644 index 0000000..d98623c --- /dev/null +++ b/tests/fixtures/0077-diskid-missing-id.installfile @@ -0,0 +1,6 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +diskid /dev/nvme0n1 diff --git a/tests/fixtures/0078-diskid-diskid-loop0.installfile b/tests/fixtures/0078-diskid-diskid-loop0.installfile new file mode 100644 index 0000000..a653295 --- /dev/null +++ b/tests/fixtures/0078-diskid-diskid-loop0.installfile @@ -0,0 +1,6 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +diskid /dev/loop0 Loop diff --git a/tests/fixtures/0079-diskid-enoent.installfile b/tests/fixtures/0079-diskid-enoent.installfile new file mode 100644 index 0000000..52bca60 --- /dev/null +++ b/tests/fixtures/0079-diskid-enoent.installfile @@ -0,0 +1,6 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +diskid /path/doesnt/exist Test diff --git a/tests/fixtures/0080-diskid-tmp.installfile b/tests/fixtures/0080-diskid-tmp.installfile new file mode 100644 index 0000000..0aab4cd --- /dev/null +++ b/tests/fixtures/0080-diskid-tmp.installfile @@ -0,0 +1,6 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +diskid /tmp This will error because it isn't a block device diff --git a/tests/fixtures/0081-diskid-duplicate.installfile b/tests/fixtures/0081-diskid-duplicate.installfile new file mode 100644 index 0000000..1fe96b1 --- /dev/null +++ b/tests/fixtures/0081-diskid-duplicate.installfile @@ -0,0 +1,7 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +diskid /dev/sda SEAGATE +diskid /dev/sda WD diff --git a/tests/spec/validator.rb b/tests/spec/validator.rb index cdcd38b..d54006d 100644 --- a/tests/spec/validator.rb +++ b/tests/spec/validator.rb @@ -450,6 +450,40 @@ RSpec.describe 'HorizonScript Validation Utility', :type => :aruba do expect(last_command_started).to have_output(/error: .*repository/) end end + context "for 'diskid' key" do + it "succeeds with basic disk identification" do + use_fixture '0076-diskid-basic.installfile' + run_validate + expect(last_command_started).to have_output(PARSER_SUCCESS) + expect(last_command_started).to have_output(VALIDATOR_SUCCESS) + end + it "requires an identification string" do + use_fixture '0077-diskid-missing-id.installfile' + run_validate + expect(last_command_started).to have_output(/error: .*diskid.*expected/) + end + it "succeeds with present disk" do + use_fixture '0078-diskid-diskid-loop0.installfile' + run_validate ' -i' + expect(last_command_started).to have_output(PARSER_SUCCESS) + expect(last_command_started).to have_output(VALIDATOR_SUCCESS) + end + it "fails with non-present disk" do + use_fixture '0079-diskid-enoent.installfile' + run_validate ' -i' + expect(last_command_started).to have_output(/No such file or directory/) + end + it "fails with non-disk file" do + use_fixture '0080-diskid-tmp.installfile' + run_validate ' -i' + expect(last_command_started).to have_output(/error: .*diskid.*block/) + end + it "fails with a duplicate identification device" do + use_fixture '0081-diskid-duplicate.installfile' + run_validate + expect(last_command_started).to have_output(/error: .*diskid.*already/) + end + end end context "unique keys" do # Runner.Validate.network. -- cgit v1.2.3-60-g2f50