summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hscript/disk.cc106
-rw-r--r--hscript/disk.hh25
-rw-r--r--hscript/script.cc25
-rw-r--r--tests/fixtures/0076-diskid-basic.installfile2
-rw-r--r--tests/fixtures/0122-disklabel-apm.installfile7
-rw-r--r--tests/fixtures/0123-disklabel-mbr.installfile7
-rw-r--r--tests/fixtures/0124-disklabel-gpt.installfile7
-rw-r--r--tests/fixtures/0125-disklabel-duplicate.installfile8
-rw-r--r--tests/fixtures/0126-disklabel-loop0.installfile6
-rw-r--r--tests/fixtures/0127-disklabel-enoent.installfile6
-rw-r--r--tests/fixtures/0128-disklabel-invalid-type.installfile7
-rw-r--r--tests/fixtures/0129-disklabel-without-label.installfile7
-rw-r--r--tests/spec/validator_spec.rb48
13 files changed, 242 insertions, 19 deletions
diff --git a/hscript/disk.cc b/hscript/disk.cc
index 137d3cf..875d84f 100644
--- a/hscript/disk.cc
+++ b/hscript/disk.cc
@@ -28,6 +28,34 @@
using namespace Horizon::Keys;
+
+#ifdef HAS_INSTALL_ENV
+/*! Determine if _block is a valid block device.
+ * @param key The key associated with this test.
+ * @param line The line number where the key exists.
+ * @param _block The path to test.
+ * @returns true if _block is valid, false otherwise.
+ * @note Will output_error if an error occurs.
+ */
+bool is_block_device(const std::string &key, int line, const std::string &_block) {
+ 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),
+ key + ": error opening device " + _block,
+ strerror(errno));
+ return false;
+ }
+ if(!S_ISBLK(blk_stat.st_mode)) {
+ output_error("installfile:" + std::to_string(line),
+ key + ": " + _block + " is not a valid block device");
+ return false;
+ }
+ return true;
+}
+#endif /* HAS_INSTALL_ENV */
+
+
Key *DiskId::parseFromData(const std::string &data, int lineno, int *errors,
int *warnings) {
std::string block, ident;
@@ -46,26 +74,15 @@ Key *DiskId::parseFromData(const std::string &data, int lineno, int *errors,
}
bool DiskId::validate(ScriptOptions options) const {
- /* We only validate if running in an Installation Environment. */
- if(!options.test(InstallEnvironment)) return true;
-
#ifdef HAS_INSTALL_ENV
- /* 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;
+ /* We only validate if running in an Installation Environment. */
+ if(options.test(InstallEnvironment)) {
+ /* Unlike 'mount', 'diskid' *does* require that the block device exist
+ * before installation begins. This test is always valid. */
+ return is_block_device("diskid", this->lineno(), _block);
}
#endif /* HAS_INSTALL_ENV */
+
return true;
}
@@ -117,6 +134,61 @@ bool DiskId::execute(ScriptOptions options) const {
return match;
}
+
+Key *DiskLabel::parseFromData(const std::string &data, int lineno, int *errors,
+ int *warnings) {
+ std::string block, label;
+ std::string::size_type sep = data.find_first_of(' ');
+ LabelType type;
+
+ /* REQ: Runner.Validate.disklabel.Validity */
+ if(sep == std::string::npos || data.length() == sep + 1) {
+ if(errors) *errors += 1;
+ output_error("installfile:" + std::to_string(lineno),
+ "disklabel: expected a label type",
+ "valid format for disklabel is: [disk] [type]");
+ return nullptr;
+ }
+
+ block = data.substr(0, sep);
+ label = data.substr(sep + 1);
+ std::transform(label.begin(), label.end(), label.begin(), ::tolower);
+ /* REQ: Runner.Validate.disklabel.LabelType */
+ if(label == "apm") {
+ type = APM;
+ } else if(label == "mbr") {
+ type = MBR;
+ } else if(label == "gpt") {
+ type = GPT;
+ } else {
+ if(errors) *errors += 1;
+ output_error("installfile:" + std::to_string(lineno),
+ "disklabel: '" + label + "' is not a valid label type",
+ "valid label types are: apm, mbr, gpt");
+ return nullptr;
+ }
+
+ return new DiskLabel(lineno, block, type);
+}
+
+bool DiskLabel::validate(ScriptOptions options) const {
+#ifdef HAS_INSTALL_ENV
+ /* REQ: Runner.Validate.disklabel.Block */
+ if(options.test(InstallEnvironment)) {
+ /* disklabels are created before any others, so we can check now */
+ return is_block_device("disklabel", this->lineno(), _block);
+ }
+#endif /* HAS_INSTALL_ENV */
+
+ return true;
+}
+
+bool DiskLabel::execute(ScriptOptions) const {
+ /* TODO XXX NOTIMPLEMENTED */
+ 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 02ecb98..f8a9574 100644
--- a/hscript/disk.hh
+++ b/hscript/disk.hh
@@ -37,6 +37,31 @@ public:
};
class DiskLabel : public Key {
+public:
+ /*! The type of disklabel. */
+ enum LabelType {
+ /*! Apple Partition Map (APM) */
+ APM,
+ /*! Master Boot Record (MBR) */
+ MBR,
+ /*! GUID Partition Table (GPT) */
+ GPT
+ };
+private:
+ const std::string _block;
+ const LabelType _type;
+
+ DiskLabel(int _line, const std::string &_b, const LabelType &_t) :
+ Key(_line), _block(_b), _type(_t) {}
+public:
+ /*! Retrieve the block device that this key identifies. */
+ const std::string device() const { return this->_block; }
+ /*! Retrieve the type of disklabel for the block device. */
+ const LabelType type() const { return this->_type; }
+
+ static Key *parseFromData(const std::string &, int, int*, int*);
+ bool validate(ScriptOptions) const override;
+ bool execute(ScriptOptions) const override;
};
class Partition : public Key {
diff --git a/hscript/script.cc b/hscript/script.cc
index 785e40e..ee638bb 100644
--- a/hscript/script.cc
+++ b/hscript/script.cc
@@ -103,6 +103,8 @@ struct Script::ScriptPrivate {
/*! Disk identification keys */
std::vector< std::unique_ptr<DiskId> > diskids;
+ /*! Disklabel configuration keys */
+ std::vector< std::unique_ptr<DiskLabel> > disklabels;
/*! Target system's mountpoints. */
std::vector< std::unique_ptr<Mount> > mounts;
@@ -157,6 +159,10 @@ struct Script::ScriptPrivate {
std::unique_ptr<DiskId> diskid(dynamic_cast<DiskId *>(obj));
this->diskids.push_back(std::move(diskid));
return true;
+ } else if(key_name == "disklabel") {
+ std::unique_ptr<DiskLabel> l(dynamic_cast<DiskLabel *>(obj));
+ this->disklabels.push_back(std::move(l));
+ return true;
} else if(key_name == "mount") {
std::unique_ptr<Mount> mount(dynamic_cast<Mount *>(obj));
this->mounts.push_back(std::move(mount));
@@ -496,7 +502,7 @@ const Script *Script::load(std::istream &sstream,
bool Script::validate() const {
int failures = 0;
- std::set<std::string> seen_diskids, seen_mounts;
+ std::set<std::string> seen_diskids, seen_labels, seen_mounts;
std::map<const std::string, int> seen_iface;
/* REQ: Runner.Validate.network */
@@ -698,6 +704,23 @@ bool Script::validate() const {
seen_diskids.insert(diskid->device());
}
+ /* REQ: Runner.Validate.disklabel */
+ for(auto &label : this->internal->disklabels) {
+ if(!label->validate(this->opts)) {
+ failures++;
+ continue;
+ }
+
+ /* REQ: Runner.Validate.disklabel.Unique */
+ if(seen_labels.find(label->device()) != seen_labels.end()) {
+ failures++;
+ output_error("installfile:" + std::to_string(label->lineno()),
+ "disklabel: device " + label->device() +
+ " already has a label queued");
+ }
+ seen_labels.insert(label->device());
+ }
+
/* REQ: Runner.Validate.mount */
for(auto &mount : this->internal->mounts) {
if(!mount->validate(this->opts)) {
diff --git a/tests/fixtures/0076-diskid-basic.installfile b/tests/fixtures/0076-diskid-basic.installfile
index 329e70c..611428c 100644
--- a/tests/fixtures/0076-diskid-basic.installfile
+++ b/tests/fixtures/0076-diskid-basic.installfile
@@ -3,4 +3,4 @@ hostname test.machine
pkginstall adelie-base
rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
mount /dev/sda1 /
-diskid /dev/sda SEAGATE
+diskid /dev/sda ST1000
diff --git a/tests/fixtures/0122-disklabel-apm.installfile b/tests/fixtures/0122-disklabel-apm.installfile
new file mode 100644
index 0000000..8acb90b
--- /dev/null
+++ b/tests/fixtures/0122-disklabel-apm.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 ST1000
+disklabel /dev/sda apm
diff --git a/tests/fixtures/0123-disklabel-mbr.installfile b/tests/fixtures/0123-disklabel-mbr.installfile
new file mode 100644
index 0000000..f865628
--- /dev/null
+++ b/tests/fixtures/0123-disklabel-mbr.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 ST1000
+disklabel /dev/sda mbr
diff --git a/tests/fixtures/0124-disklabel-gpt.installfile b/tests/fixtures/0124-disklabel-gpt.installfile
new file mode 100644
index 0000000..d793970
--- /dev/null
+++ b/tests/fixtures/0124-disklabel-gpt.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 ST1000
+disklabel /dev/sda gpt
diff --git a/tests/fixtures/0125-disklabel-duplicate.installfile b/tests/fixtures/0125-disklabel-duplicate.installfile
new file mode 100644
index 0000000..2a2b7e2
--- /dev/null
+++ b/tests/fixtures/0125-disklabel-duplicate.installfile
@@ -0,0 +1,8 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+diskid /dev/sda ST1000
+disklabel /dev/sda apm
+disklabel /dev/sda gpt
diff --git a/tests/fixtures/0126-disklabel-loop0.installfile b/tests/fixtures/0126-disklabel-loop0.installfile
new file mode 100644
index 0000000..cead2fd
--- /dev/null
+++ b/tests/fixtures/0126-disklabel-loop0.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+disklabel /dev/loop0 apm
diff --git a/tests/fixtures/0127-disklabel-enoent.installfile b/tests/fixtures/0127-disklabel-enoent.installfile
new file mode 100644
index 0000000..9a5835c
--- /dev/null
+++ b/tests/fixtures/0127-disklabel-enoent.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+disklabel /tmp gpt
diff --git a/tests/fixtures/0128-disklabel-invalid-type.installfile b/tests/fixtures/0128-disklabel-invalid-type.installfile
new file mode 100644
index 0000000..b4c14b2
--- /dev/null
+++ b/tests/fixtures/0128-disklabel-invalid-type.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 ST1000
+disklabel /dev/sda sun
diff --git a/tests/fixtures/0129-disklabel-without-label.installfile b/tests/fixtures/0129-disklabel-without-label.installfile
new file mode 100644
index 0000000..5c6455c
--- /dev/null
+++ b/tests/fixtures/0129-disklabel-without-label.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 ST1000
+disklabel /dev/sda
diff --git a/tests/spec/validator_spec.rb b/tests/spec/validator_spec.rb
index 3ed43ea..624eaa2 100644
--- a/tests/spec/validator_spec.rb
+++ b/tests/spec/validator_spec.rb
@@ -548,6 +548,54 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do
expect(last_command_started).to have_output(/error: .*diskid.*already/)
end
end
+ context "for 'disklabel' key" do
+ it "requires a label type" do
+ use_fixture '0129-disklabel-without-label.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*disklabel.*expected/)
+ end
+ it "succeeds with a APM disk label" do
+ use_fixture '0122-disklabel-apm.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "succeeds with a MBR disk label" do
+ use_fixture '0123-disklabel-mbr.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "succeeds with a GPT disk label" do
+ use_fixture '0124-disklabel-gpt.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "fails with a duplicate disk" do
+ use_fixture '0125-disklabel-duplicate.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*disklabel.*already/)
+ end
+ it "succeeds with present disk" do
+ use_fixture '0126-disklabel-loop0.installfile'
+ run_validate ' -i'
+ skip "This build does not support this test" if last_command_started.stdout =~ /runtime environment only/
+ 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 '0127-disklabel-enoent.installfile'
+ run_validate ' -i'
+ skip "This build does not support this test" if last_command_started.stdout =~ /runtime environment only/
+ expect(last_command_started).to have_output(/error: .*disklabel.*block/)
+ end
+ it "requires a valid label type" do
+ use_fixture '0128-disklabel-invalid-type.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*disklabel.*type/)
+ end
+ end
end
context "unique keys" do
# Runner.Validate.network.