summaryrefslogtreecommitdiff
path: root/hscript
diff options
context:
space:
mode:
Diffstat (limited to 'hscript')
-rw-r--r--hscript/disk.cc202
-rw-r--r--hscript/disk.hh86
-rw-r--r--hscript/disk_lvm.cc78
-rw-r--r--hscript/key.cc2
-rw-r--r--hscript/key.hh23
-rw-r--r--hscript/meta.cc211
-rw-r--r--hscript/meta.hh80
-rw-r--r--hscript/network.cc176
-rw-r--r--hscript/network.hh40
-rw-r--r--hscript/script.cc58
-rw-r--r--hscript/script.hh6
-rw-r--r--hscript/script_i.hh78
-rw-r--r--hscript/script_l.hh35
-rw-r--r--hscript/script_v.cc111
-rw-r--r--hscript/user.cc119
-rw-r--r--hscript/user.hh53
16 files changed, 619 insertions, 739 deletions
diff --git a/hscript/disk.cc b/hscript/disk.cc
index 049410e..07499b8 100644
--- a/hscript/disk.cc
+++ b/hscript/disk.cc
@@ -36,24 +36,22 @@ 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 pos The location 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, long line,
+bool is_block_device(const std::string &key, const Horizon::ScriptLocation &pos,
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,
+ output_error(pos, 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");
+ output_error(pos, key + ": " + _block + " is not a valid block device");
return false;
}
return true;
@@ -61,21 +59,20 @@ bool is_block_device(const std::string &key, long line,
#endif /* HAS_INSTALL_ENV */
-Key *DiskId::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *DiskId::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
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",
+ output_error(pos, "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(script, lineno, block, ident);
+ return new DiskId(script, pos, block, ident);
}
bool DiskId::validate() const {
@@ -84,7 +81,7 @@ bool DiskId::validate() const {
if(script->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);
+ return is_block_device("diskid", where(), _block);
}
#endif /* HAS_INSTALL_ENV */
@@ -94,9 +91,8 @@ bool DiskId::validate() const {
bool DiskId::execute() const {
bool match = false;
- output_info("installfile:" + std::to_string(line),
- "diskid: Checking " + _block + " for identification string " +
- _ident);
+ output_info(pos, "diskid: Checking " + _block +
+ " for identification string " + _ident);
if(!script->options().test(InstallEnvironment)) return true;
@@ -107,8 +103,7 @@ bool DiskId::execute() const {
struct stat blk_stat;
const char *block_c = _block.c_str();
if(stat(block_c, &blk_stat) != 0) {
- output_error("installfile:" + std::to_string(line),
- "diskid: error opening device " + _block,
+ output_error(pos, "diskid: error opening device " + _block,
strerror(errno));
return false;
}
@@ -116,16 +111,14 @@ bool DiskId::execute() const {
udev = udev_new();
if(!udev) {
- output_error("installfile:" + std::to_string(line),
- "diskid: failed to communicate with udevd",
+ output_error(pos, "diskid: failed to communicate with udevd",
"cannot read disk information");
return false;
}
device = udev_device_new_from_devnum(udev, 'b', blk_stat.st_rdev);
if(!device) {
udev_unref(udev);
- output_error("installfile:" + std::to_string(line),
- "diskid: failed to retrieve disk from udevd",
+ output_error(pos, "diskid: failed to retrieve disk from udevd",
"cannot read disk information");
return false;
}
@@ -136,15 +129,13 @@ bool DiskId::execute() const {
std::string full_str(serial);
match = (full_str.find(_ident) != std::string::npos);
} else {
- output_error("installfile:" + std::to_string(line),
- "diskid: failed to retrieve disk identification",
+ output_error(pos, "diskid: failed to retrieve disk identification",
"cannot read disk information");
}
if(!match) {
- output_error("installfile:" + std::to_string(line),
- "diskid: device does not match expected identification "
- "string");
+ output_error(pos, "diskid: device does not match expected "
+ "identification string");
}
udev_device_unref(device);
@@ -155,8 +146,9 @@ bool DiskId::execute() const {
}
-Key *DiskLabel::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *DiskLabel::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
std::string block, label;
std::string::size_type sep = data.find_first_of(' ');
LabelType type;
@@ -164,8 +156,7 @@ Key *DiskLabel::parseFromData(const std::string &data, int lineno, int *errors,
/* 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",
+ output_error(pos, "disklabel: expected a label type",
"valid format for disklabel is: [disk] [type]");
return nullptr;
}
@@ -182,13 +173,12 @@ Key *DiskLabel::parseFromData(const std::string &data, int lineno, int *errors,
type = GPT;
} else {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "disklabel: '" + label + "' is not a valid label type",
+ output_error(pos, "disklabel: invalid label type '" + label + "'",
"valid label types are: apm, mbr, gpt");
return nullptr;
}
- return new DiskLabel(script, lineno, block, type);
+ return new DiskLabel(script, pos, block, type);
}
bool DiskLabel::validate() const {
@@ -196,7 +186,7 @@ bool DiskLabel::validate() const {
/* REQ: Runner.Validate.disklabel.Block */
if(script->options().test(InstallEnvironment)) {
/* disklabels are created before any others, so we can check now */
- return is_block_device("disklabel", this->lineno(), _block);
+ return is_block_device("disklabel", where(), _block);
}
#endif /* HAS_INSTALL_ENV */
@@ -217,8 +207,7 @@ bool DiskLabel::execute() const {
break;
}
- output_info("installfile:" + std::to_string(this->lineno()),
- "disklabel: creating new " + type_str + " disklabel on " +
+ output_info(pos, "disklabel: creating new " + type_str + " disklabel on " +
device());
if(script->options().test(Simulate)) {
@@ -233,8 +222,7 @@ bool DiskLabel::execute() const {
int res;
if(label == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "disklabel: Parted does not support label type " +
+ output_error(pos, "disklabel: Parted does not support label type " +
type_str + "!");
return false;
}
@@ -243,16 +231,14 @@ bool DiskLabel::execute() const {
ped_disk_clobber(pdevice);
PedDisk *disk = ped_disk_new_fresh(pdevice, label);
if(disk == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "disklabel: internal error creating new " +
+ output_error(pos, "disklabel: internal error creating new " +
type_str + " disklabel on " + _block);
return false;
}
res = ped_disk_commit(disk);
if(res != 1) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "disklabel: error creating disklabel on " + _block);
+ output_error(pos, "disklabel: error creating disklabel on " + _block);
}
return (res == 1);
#else
@@ -261,8 +247,8 @@ bool DiskLabel::execute() const {
}
-Key *Encrypt::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Encrypt::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
std::string::size_type sep = data.find(' ');
std::string dev, pass;
@@ -275,12 +261,11 @@ Key *Encrypt::parseFromData(const std::string &data, int lineno, int *errors,
if(dev.size() < 6 || dev.compare(0, 5, "/dev/")) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "encrypt: expected path to block device");
+ output_error(pos, "encrypt: expected path to block device");
return nullptr;
}
- return new Encrypt(script, lineno, dev, pass);
+ return new Encrypt(script, pos, dev, pass);
}
bool Encrypt::validate() const {
@@ -396,8 +381,9 @@ bool parse_size_string(const std::string &in_size, uint64_t *out_size,
}
-Key *Partition::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Partition::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
std::string block, pno, size_str, typecode;
std::string::size_type next_pos, last_pos;
int part_no;
@@ -408,8 +394,7 @@ Key *Partition::parseFromData(const std::string &data, int lineno, int *errors,
long spaces = std::count(data.cbegin(), data.cend(), ' ');
if(spaces < 2 || spaces > 3) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "partition: expected either 3 or 4 elements, got: " +
+ output_error(pos, "partition: expected either 3 or 4 elements, got: " +
std::to_string(spaces),
"syntax is: partition [block] [#] [size] ([type])");
return nullptr;
@@ -420,8 +405,7 @@ Key *Partition::parseFromData(const std::string &data, int lineno, int *errors,
if(block.compare(0, 4, "/dev")) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "partition: expected path to block device",
+ output_error(pos, "partition: expected path to block device",
"'" + block + "' is not a valid block device path");
return nullptr;
}
@@ -432,8 +416,7 @@ Key *Partition::parseFromData(const std::string &data, int lineno, int *errors,
part_no = std::stoi(pno);
} catch(const std::exception &) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "partition: expected partition number, got", pno);
+ output_error(pos, "partition: expected partition number, got", pno);
return nullptr;
}
last_pos = next_pos;
@@ -446,8 +429,7 @@ Key *Partition::parseFromData(const std::string &data, int lineno, int *errors,
}
if(!parse_size_string(size_str, &size, &size_type)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "partition: invalid size", size_str);
+ output_error(pos, "partition: invalid size", size_str);
return nullptr;
}
@@ -464,49 +446,44 @@ Key *Partition::parseFromData(const std::string &data, int lineno, int *errors,
type = PReP;
} else {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "partition: expected type code, got: " + typecode,
+ output_error(pos, "partition: expected type code, got: " + typecode,
"valid type codes are: boot esp bios prep");
return nullptr;
}
}
- return new Partition(script, lineno, block, part_no, size_type, size, type);
+ return new Partition(script, pos, block, part_no, size_type, size, type);
}
bool Partition::validate() const {
#ifdef HAS_INSTALL_ENV
if(script->options().test(InstallEnvironment)) {
/* REQ: Runner.Validate.partition.Block */
- return is_block_device("partition", this->lineno(), this->device());
+ return is_block_device("partition", where(), this->device());
}
#endif /* HAS_INSTALL_ENV */
return true;
}
bool Partition::execute() const {
- output_info("installfile:" + std::to_string(this->lineno()),
- "partition: creating partition #" + std::to_string(_partno) +
- " on " + _block);
+ output_info(pos, "partition: creating partition #" +
+ std::to_string(_partno) + " on " + _block);
if(script->options().test(Simulate)) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: Not supported in Simulation mode");
+ output_error(pos, "partition: Not supported in Simulation mode");
return true;
}
#ifdef HAS_INSTALL_ENV
PedDevice *dev = ped_device_get(this->device().c_str());
if(dev == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: error opening device " + this->device());
+ output_error(pos, "partition: error opening device " + this->device());
return false;
}
PedDisk *disk = ped_disk_new(dev);
if(disk == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: error reading device " + this->device());
+ output_error(pos, "partition: error reading device " + this->device());
return false;
}
@@ -516,8 +493,7 @@ bool Partition::execute() const {
if(last == -1) last = 0;
if(last != (this->partno() - 1)) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: consistency error on " + this->device(),
+ output_error(pos, "partition: consistency error on " + this->device(),
"Partition #" + std::to_string(this->partno()) +
" has been requested, but the disk has " +
std::to_string(last) + " partitions");
@@ -531,8 +507,7 @@ bool Partition::execute() const {
if(last > 0) {
before = ped_disk_get_partition(disk, last);
if(before == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: error reading partition table on " +
+ output_error(pos, "partition: error reading partition table on " +
this->device());
ped_disk_destroy(disk);
return false;
@@ -558,8 +533,7 @@ bool Partition::execute() const {
me = ped_partition_new(disk, PED_PARTITION_NORMAL, nullptr,
start, start + size);
if(me == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: error creating partition on " +
+ output_error(pos, "partition: error creating partition on " +
this->device());
ped_disk_destroy(disk);
return false;
@@ -585,8 +559,7 @@ bool Partition::execute() const {
int res = ped_disk_add_partition(disk, me, ped_constraint_any(dev));
if(res == 0) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: error adding partition to " +
+ output_error(pos, "partition: error adding partition to " +
this->device());
ped_disk_destroy(disk);
return false;
@@ -594,8 +567,7 @@ bool Partition::execute() const {
res = ped_disk_commit(disk);
if(res != 1) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "partition: error flushing changes to " +
+ output_error(pos, "partition: error flushing changes to " +
this->device());
ped_disk_destroy(disk);
return false;
@@ -612,12 +584,12 @@ const static std::set<std::string> valid_fses = {
};
-Key *Filesystem::parseFromData(const std::string &data, int lineno,
- int *errors, int *, const Script *script) {
+Key *Filesystem::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
if(std::count(data.begin(), data.end(), ' ') != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "fs: expected exactly two elements",
+ output_error(pos, "fs: expected exactly two elements",
"syntax is: fs [device] [fstype]");
return nullptr;
}
@@ -629,8 +601,7 @@ Key *Filesystem::parseFromData(const std::string &data, int lineno,
if(device.size() < 6 || device.compare(0, 5, "/dev/")) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "fs: element 1: expected device node",
+ output_error(pos, "fs: element 1: expected device node",
"'" + device + "' is not a valid device node");
return nullptr;
}
@@ -640,8 +611,7 @@ Key *Filesystem::parseFromData(const std::string &data, int lineno,
for(auto &&fs : valid_fses) fses += fs + " ";
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "fs: element 2: expected filesystem type",
+ output_error(pos, "fs: element 2: expected filesystem type",
"valid filesystems are: " + fses);
return nullptr;
}
@@ -662,7 +632,7 @@ Key *Filesystem::parseFromData(const std::string &data, int lineno,
type = XFS;
}
- return new Filesystem(script, lineno, device, type);
+ return new Filesystem(script, pos, device, type);
}
bool Filesystem::validate() const {
@@ -674,8 +644,7 @@ bool Filesystem::execute() const {
std::string cmd;
std::vector<std::string> args;
- output_info("installfile:" + std::to_string(line),
- "fs: creating new filesystem on " + _block);
+ output_info(pos, "fs: creating new filesystem on " + _block);
switch(_type) {
case Ext2:
@@ -724,8 +693,7 @@ bool Filesystem::execute() const {
#ifdef HAS_INSTALL_ENV
if(run_command(cmd, args) != 0) {
- output_error("installfile:" + std::to_string(line),
- "fs: failed to create filesystem");
+ output_error(pos, "fs: failed to create filesystem");
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -733,8 +701,8 @@ bool Filesystem::execute() const {
}
-Key *Mount::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Mount::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
std::string dev, where, opt;
std::string::size_type where_pos, opt_pos;
bool any_failure = false;
@@ -743,8 +711,7 @@ Key *Mount::parseFromData(const std::string &data, int lineno, int *errors,
if(spaces < 1 || spaces > 2) {
if(errors) *errors += 1;
/* Don't bother with any_failure, because this is immediately fatal. */
- output_error("installfile:" + std::to_string(lineno),
- "mount: expected either 2 or 3 elements, got: " +
+ output_error(pos, "mount: expected either 2 or 3 elements, got: " +
std::to_string(spaces), "");
return nullptr;
}
@@ -761,22 +728,20 @@ Key *Mount::parseFromData(const std::string &data, int lineno, int *errors,
if(dev.compare(0, 4, "/dev")) {
if(errors) *errors += 1;
any_failure = true;
- output_error("installfile:" + std::to_string(lineno),
- "mount: element 1: expected device node",
+ output_error(pos, "mount: element 1: expected device node",
"'" + dev + "' is not a valid device node");
}
if(where[0] != '/') {
if(errors) *errors += 1;
any_failure = true;
- output_error("installfile:" + std::to_string(lineno),
- "mount: element 2: expected absolute path",
+ output_error(pos, "mount: element 2: expected absolute path",
"'" + where + "' is not a valid absolute path");
}
if(any_failure) return nullptr;
- return new Mount(script, lineno, dev, where, opt);
+ return new Mount(script, pos, dev, where, opt);
}
bool Mount::validate() const {
@@ -799,7 +764,7 @@ bool Mount::execute() const {
else {
fstype = blkid_get_tag_value(nullptr, "TYPE", this->device().c_str());
if(fstype == nullptr) {
- output_error("installfile:" + std::to_string(this->lineno()),
+ output_error(pos,
"mount: cannot determine filesystem type for device",
this->device());
return false;
@@ -807,8 +772,7 @@ bool Mount::execute() const {
}
#endif /* HAS_INSTALL_ENV */
- output_info("installfile:" + std::to_string(this->lineno()),
- "mount: mounting " + this->device() + " on " +
+ output_info(pos, "mount: mounting " + this->device() + " on " +
this->mountpoint());
if(script->options().test(Simulate)) {
std::cout << "mount ";
@@ -826,22 +790,20 @@ bool Mount::execute() const {
if(!fs::exists(actual_mount, ec)) {
fs::create_directory(actual_mount, ec);
if(ec) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "mount: failed to create target directory for "
- + this->mountpoint(), ec.message());
+ output_error(pos, "mount: failed to create target directory "
+ "for " + this->mountpoint(), ec.message());
return false;
}
}
if(mount(this->device().c_str(), actual_mount.c_str(), fstype, 0,
this->options().c_str()) != 0) {
- output_warning("installfile:" + std::to_string(this->lineno()),
- "mount: error mounting " + this->mountpoint() +
+ output_warning(pos, "mount: error mounting " + this->mountpoint() +
"with options; retrying without", strerror(errno));
if(mount(this->device().c_str(), actual_mount.c_str(), fstype, 0,
nullptr) != 0) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "mount: error mounting " + this->mountpoint() +
- "without options", strerror(errno));
+ output_error(pos, "mount: error mounting " +
+ this->mountpoint() + "without options",
+ strerror(errno));
return false;
}
}
@@ -851,8 +813,7 @@ bool Mount::execute() const {
/* Handle fstab. We're guaranteed to have a /target since mount has
* already ran and /target is the first mount done.
*/
- output_info("installfile:" + std::to_string(this->lineno()),
- "mount: adding " + this->mountpoint() + " to /etc/fstab");
+ output_info(pos, "mount: adding " + this->mountpoint() + " to /etc/fstab");
char pass = (this->mountpoint() == "/" ? '1' : '0');
const std::string fstab_opts = (this->options().empty() ?
"defaults" : this->options());
@@ -872,8 +833,7 @@ bool Mount::execute() const {
if(this->mountpoint() == "/") {
fs::create_directory(script->targetDirectory() + "/etc", ec);
if(ec) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "mount: failed to create /etc for target",
+ output_error(pos, "mount: failed to create /etc for target",
ec.message());
return false;
}
@@ -883,16 +843,14 @@ bool Mount::execute() const {
#endif
ec);
if(ec) {
- output_warning("installfile:" + std::to_string(this->lineno()),
- "mount: failed to set permissions for target /etc",
- ec.message());
+ output_warning(pos, "mount: failed to set permissions for "
+ "target /etc", ec.message());
}
}
std::ofstream fstab_f(script->targetDirectory() + "/etc/fstab",
std::ios::app);
if(!fstab_f) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "mount: failure opening /etc/fstab for writing");
+ output_error(pos, "mount: failure opening /etc/fstab for writing");
return false;
}
fstab_f << this->device() << "\t" << this->mountpoint() << "\t"
diff --git a/hscript/disk.hh b/hscript/disk.hh
index e777c8f..2e3f18a 100644
--- a/hscript/disk.hh
+++ b/hscript/disk.hh
@@ -23,17 +23,17 @@ private:
const std::string _block;
const std::string _ident;
- DiskId(const Script *_s, int _line, const std::string &my_block,
- const std::string &my_i) :
- Key(_s, _line), _block(my_block), _ident(my_i) {}
+ DiskId(const Script *_s, const ScriptLocation &_p,
+ const std::string &my_block, const std::string &my_i) :
+ Key(_s, _p), _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*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
@@ -53,17 +53,17 @@ private:
const std::string _block;
const LabelType _type;
- DiskLabel(const Script *_s, int _line, const std::string &_b,
+ DiskLabel(const Script *_s, const ScriptLocation &_p, const std::string &_b,
const LabelType &_t) :
- Key(_s, _line), _block(_b), _type(_t) {}
+ Key(_s, _p), _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. */
LabelType type() const { return this->_type; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
@@ -100,9 +100,10 @@ private:
const uint64_t _size;
const PartitionType _type;
- Partition(const Script *_sc, int _line, const std::string &_b, const int _p,
- const SizeType _st, const uint64_t _s, const PartitionType _pt) :
- Key(_sc, _line), _block(_b), _partno(_p), _size_type(_st), _size(_s),
+ Partition(const Script *_sc, const ScriptLocation &_pos,
+ const std::string &_b, const int _p, const SizeType _st,
+ const uint64_t _s, const PartitionType _pt) :
+ Key(_sc, _pos), _block(_b), _partno(_p), _size_type(_st), _size(_s),
_type(_pt) {}
public:
/*! Retrieve the block device that this key identifies. */
@@ -116,8 +117,8 @@ public:
/*! Retrieve the Type Code of this partition, if any. */
PartitionType type() const { return this->_type; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
@@ -127,27 +128,27 @@ private:
const std::string _block;
const std::string _pw;
- Encrypt(const Script *_s, int _line, const std::string &_b,
- const std::string &_p) : Key(_s, _line), _block(_b), _pw(_p) {}
+ Encrypt(const Script *_s, const ScriptLocation &_pos, const std::string &_b,
+ const std::string &_p) : Key(_s, _pos), _block(_b), _pw(_p) {}
public:
/*! Retrieve the block device that this key encrypts. */
const std::string device() const { return this->_block; }
/*! Retrieve the passphrase used to encrypt the block device. */
const std::string passphrase() const { return this->_pw; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
class LVMPhysical : public StringKey {
private:
- LVMPhysical(const Script *_s, int _line, const std::string &_d) :
- StringKey(_s, _line, _d) {}
+ LVMPhysical(const Script *_s, const ScriptLocation &_p,
+ const std::string &_d) : StringKey(_s, _p, _d) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool execute() const override;
};
@@ -156,17 +157,17 @@ private:
const std::string _pv;
const std::string _vgname;
- LVMGroup(const Script *_s, int _line, const std::string &_p,
- const std::string &_v) :
- Key(_s, _line), _pv(_p), _vgname(_v) {}
+ LVMGroup(const Script *_s, const ScriptLocation &_pos,
+ const std::string &_p, const std::string &_v) :
+ Key(_s, _pos), _pv(_p), _vgname(_v) {}
public:
/*! Retrieve the physical volume where this volume group will reside. */
const std::string pv() const { return this->_pv; }
/*! Retrieve the name of this volume group. */
const std::string name() const { return this->_vgname; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
/*! Determine if the PV passed is a real one. */
bool test_pv() const;
@@ -180,9 +181,10 @@ private:
const SizeType _size_type;
const uint64_t _size;
- LVMVolume(const Script *_sc, int _line, const std::string &_v,
- const std::string &_n, SizeType _t, uint64_t _s) :
- Key(_sc, _line), _vg(_v), _lvname(_n), _size_type(_t), _size(_s) {}
+ LVMVolume(const Script *_sc, const ScriptLocation &_pos,
+ const std::string &_v, const std::string &_n, SizeType _t,
+ uint64_t _s) :
+ Key(_sc, _pos), _vg(_v), _lvname(_n), _size_type(_t), _size(_s) {}
public:
/*! Retrieve the volume group to which this volume belongs. */
const std::string vg() const { return this->_vg; }
@@ -193,8 +195,8 @@ public:
/*! Retrieve the size of this volume. */
uint64_t size() const { return this->_size; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
@@ -214,16 +216,17 @@ private:
const std::string _block;
FilesystemType _type;
- Filesystem(const Script *_s, int _line, const std::string &_b,
- FilesystemType _t) : Key(_s, _line), _block(_b), _type(_t) {}
+ Filesystem(const Script *_s, const ScriptLocation &_pos,
+ const std::string &_b, FilesystemType _t) :
+ Key(_s, _pos), _block(_b), _type(_t) {}
public:
/*! Retrieve the block device on which to create the filesystem. */
const std::string device() const { return this->_block; }
/*! Retreive the type of filesystem to create. */
FilesystemType fstype() const { return this->_type; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
@@ -234,9 +237,10 @@ private:
const std::string _mountpoint;
const std::string _opts;
- Mount(const Script *_s, int _line, const std::string &my_block,
- const std::string &my_mountpoint, const std::string &my_opts = "") :
- Key(_s, _line), _block(my_block), _mountpoint(my_mountpoint),
+ Mount(const Script *_s, const ScriptLocation &_pos,
+ const std::string &my_block, const std::string &my_mountpoint,
+ const std::string &my_opts = "") :
+ Key(_s, _pos), _block(my_block), _mountpoint(my_mountpoint),
_opts(my_opts) {}
public:
/*! Retrieve the block device to which this mount pertains. */
@@ -246,8 +250,8 @@ public:
/*! Retrieve the mount options for this mount, if any. */
const std::string options() const { return this->_opts; }
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
diff --git a/hscript/disk_lvm.cc b/hscript/disk_lvm.cc
index 077d533..e23f063 100644
--- a/hscript/disk_lvm.cc
+++ b/hscript/disk_lvm.cc
@@ -25,21 +25,20 @@ using namespace Horizon::Keys;
bool parse_size_string(const std::string &, uint64_t *, SizeType *);
-Key *LVMPhysical::parseFromData(const std::string &data, int lineno,
- int *errors, int *, const Script *script) {
+Key *LVMPhysical::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
if(data.size() < 6 || data.substr(0, 5) != "/dev/") {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_pv: expected an absolute path to a block device");
+ output_error(pos, "lvm_pv: expected an absolute path to a device");
return nullptr;
}
- return new LVMPhysical(script, lineno, data);
+ return new LVMPhysical(script, pos, data);
}
bool LVMPhysical::execute() const {
- output_info("installfile:" + std::to_string(line),
- "lvm_pv: creating physical volume on " + _value);
+ output_info(pos, "lvm_pv: creating physical volume on " + _value);
if(script->options().test(Simulate)) {
std::cout << "pvcreate --force " << _value << std::endl;
@@ -54,8 +53,7 @@ bool LVMPhysical::execute() const {
}
if(run_command("pvcreate", {"--force", _value}) != 0) {
- output_error("installfile:" + std::to_string(line),
- "lvm_pv: failed to create physical volume on " + _value);
+ output_error(pos, "lvm_pv: failed to create physical volume", _value);
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -116,13 +114,12 @@ bool is_valid_lvm_lv_name(const std::string &name) {
}
-Key *LVMGroup::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *LVMGroup::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
std::string::size_type space = data.find_first_of(' ');
if(space == std::string::npos || data.size() == space + 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_vg: expected exactly two elements",
+ output_error(pos, "lvm_vg: expected exactly two elements",
"syntax is lvm_vg [pv_block] [name-of-vg]");
return nullptr;
}
@@ -132,19 +129,17 @@ Key *LVMGroup::parseFromData(const std::string &data, int lineno, int *errors,
if(pv.length() < 6 || pv.substr(0, 5) != "/dev/") {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_vg: expected absolute path to block device");
+ output_error(pos, "lvm_vg: expected absolute path to block device");
return nullptr;
}
if(!is_valid_lvm_name(name)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_vg: invalid volume group name");
+ output_error(pos, "lvm_vg: invalid volume group name");
return nullptr;
}
- return new LVMGroup(script, lineno, pv, name);
+ return new LVMGroup(script, pos, pv, name);
}
bool LVMGroup::validate() const {
@@ -173,20 +168,19 @@ bool LVMGroup::test_pv() const {
/*! Determine if a named Volume Group currently exists on a LVM PV.
* @param vg The name of the Volume Group.
* @param pv The path to the LVM physical volume.
- * @param line The installfile line number.
+ * @param pos The location of the line.
* @param msgs Whether or not to print messages.
* @returns true if +vg+ appears on +pv+; false otherwise.
*/
bool does_vg_exist_on_pv(const std::string &vg, const std::string &pv,
- long line, bool msgs) {
+ const Horizon::ScriptLocation &pos, bool msgs) {
bool success = false;
const std::string pv_command("pvs --noheadings -o vg_name " + pv +
" 2>/dev/null");
FILE *pvs = popen(pv_command.c_str(), "r");
if(pvs == nullptr) {
- if(msgs) output_error("installfile:" + std::to_string(line),
- "lvm_vg: can't determine if vg is duplicate");
+ if(msgs) output_error(pos, "lvm_vg: can't determine if vg is duplicate");
return false;
}
@@ -201,9 +195,8 @@ bool does_vg_exist_on_pv(const std::string &vg, const std::string &pv,
* also, use vg.size() to avoid comparing the terminating \n */
if(static_cast<unsigned long>(read_bytes) != vg.size() + 3 ||
strncmp(buf + 2, vg.c_str(), vg.size())) {
- if(msgs) output_error("installfile:" + std::to_string(line),
- "lvm_vg: volume group already exists and is "
- "not using the specified physical volume");
+ if(msgs) output_error(pos, "lvm_vg: volume group already exists and "
+ "is not using the specified physical volume");
} else {
/* the VG already exists and uses the specified PV - we're good */
success = true;
@@ -215,8 +208,7 @@ bool does_vg_exist_on_pv(const std::string &vg, const std::string &pv,
#endif /* HAS_INSTALL_ENV */
bool LVMGroup::execute() const {
- output_info("installfile:" + std::to_string(line),
- "lvm_vg: creating volume group " + _vgname + " on " + _pv);
+ output_info(pos, "lvm_vg: creating volume group " + _vgname + " on " + _pv);
if(script->options().test(Simulate)) {
std::cout << "vgcreate " << _vgname << " " << _pv << std::endl;
@@ -226,16 +218,15 @@ bool LVMGroup::execute() const {
#ifdef HAS_INSTALL_ENV
/* REQ: Runner.Execute.lvm_vg.Duplicate */
if(fs::exists("/dev/" + _vgname)) {
- return does_vg_exist_on_pv(_vgname, _pv, line, true);
+ return does_vg_exist_on_pv(_vgname, _pv, pos, true);
}
if(run_command("vgcreate", {_vgname, _pv}) != 0) {
- if(does_vg_exist_on_pv(_vgname, _pv, line, true)) {
+ if(does_vg_exist_on_pv(_vgname, _pv, pos, true)) {
return true;
}
- output_error("installfile:" + std::to_string(line),
- "lvm_vg: failed to create volume group " + _vgname);
+ output_error(pos, "lvm_vg: failed to create volume group " + _vgname);
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -243,8 +234,9 @@ bool LVMGroup::execute() const {
}
-Key *LVMVolume::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *LVMVolume::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
std::string vg, name, size_str;
std::string::size_type name_start, size_start;
SizeType size_type;
@@ -253,8 +245,7 @@ Key *LVMVolume::parseFromData(const std::string &data, int lineno, int *errors,
long spaces = std::count(data.cbegin(), data.cend(), ' ');
if(spaces != 2) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_lv: expected 3 elements, got: " +
+ output_error(pos, "lvm_lv: expected 3 elements, got: " +
std::to_string(spaces),
"syntax is: lvm_lv [vg] [name] [size]");
return nullptr;
@@ -268,26 +259,23 @@ Key *LVMVolume::parseFromData(const std::string &data, int lineno, int *errors,
if(!is_valid_lvm_name(vg)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_lv: invalid volume group name");
+ output_error(pos, "lvm_lv: invalid volume group name");
return nullptr;
}
if(!is_valid_lvm_lv_name(name)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_lv: invalid volume name");
+ output_error(pos, "lvm_lv: invalid volume name");
return nullptr;
}
if(!parse_size_string(size_str, &size, &size_type)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "lvm_lv: invalid size", size_str);
+ output_error(pos, "lvm_lv: invalid size", size_str);
return nullptr;
}
- return new LVMVolume(script, lineno, vg, name, size_type, size);
+ return new LVMVolume(script, pos, vg, name, size_type, size);
}
bool LVMVolume::validate() const {
@@ -295,8 +283,7 @@ bool LVMVolume::validate() const {
}
bool LVMVolume::execute() const {
- output_info("installfile:" + std::to_string(line),
- "lvm_lv: creating volume " + _lvname + " on " + _vg);
+ output_info(pos, "lvm_lv: creating volume " + _lvname + " on " + _vg);
std::string param, size;
switch(_size_type) {
@@ -322,8 +309,7 @@ bool LVMVolume::execute() const {
#ifdef HAS_INSTALL_ENV
if(run_command("lvcreate", {param, size, "-n", _lvname, _vg}) != 0) {
- output_error("installfile:" + std::to_string(line),
- "lvm_lv: failed to create logical volume " + _lvname);
+ output_error(pos, "lvm_lv: failed to create logical volume " + _lvname);
return false;
}
#endif /* HAS_INSTALL_ENV */
diff --git a/hscript/key.cc b/hscript/key.cc
index a2d0342..49d095e 100644
--- a/hscript/key.cc
+++ b/hscript/key.cc
@@ -19,7 +19,7 @@ Horizon::Keys::Key::~Key() {
}
bool Horizon::Keys::BooleanKey::parse(const std::string &what,
- const std::string &where,
+ const ScriptLocation &where,
const std::string &key, bool *out) {
std::string lower(what.size(), 0);
std::transform(what.begin(), what.end(), lower.begin(), ::tolower);
diff --git a/hscript/key.hh b/hscript/key.hh
index 20a461e..5bccb89 100644
--- a/hscript/key.hh
+++ b/hscript/key.hh
@@ -28,14 +28,14 @@ protected:
/*! The script that owns this Key. */
const Script *script;
/*! The line number where this Key appeared. */
- long line;
- Key(const Script *_s, long _line) : script(_s), line(_line) {}
+ const ScriptLocation pos;
+ Key(const Script *_s, const ScriptLocation &_p) : script{_s}, pos{_p} {}
public:
virtual ~Key();
/*! Create the Key object with the specified data as the entire value.
* @param data The value associated with the key.
- * @param lineno The line number where the key occurs.
+ * @param pos The location where the key occurs.
* @param errors Output variable: if not nullptr, ++ on each error.
* @param warnings Output variable: if not nullptr, ++ on each warning.
* @returns nullptr if data is unparsable, otherwise a pointer to a Key.
@@ -43,8 +43,9 @@ public:
#define UNUSED __attribute__((unused))
/* LCOV_EXCL_START */
static Key *parseFromData(const std::string &data UNUSED,
- int lineno UNUSED, int *errors UNUSED,
- int *warnings UNUSED, const Script *s UNUSED) {
+ const ScriptLocation &pos UNUSED,
+ int *errors UNUSED, int *warnings UNUSED,
+ const Script *s UNUSED) {
return nullptr;
}
/* LCOV_EXCL_STOP */
@@ -58,7 +59,7 @@ public:
*/
virtual bool execute() const = 0;
- long lineno() const { return this->line; }
+ const ScriptLocation where() const { return this->pos; }
};
@@ -71,8 +72,8 @@ public:
class BooleanKey : public Key {
protected:
const bool value;
- BooleanKey(const Script *_s, int _line, bool my_value) : Key(_s, _line),
- value(my_value) {}
+ BooleanKey(const Script *_s, const ScriptLocation &_p, bool my_value) :
+ Key{_s, _p}, value{my_value} {}
/*! Parse a string into a boolean.
* @param what The string to attempt parsing.
@@ -81,7 +82,7 @@ protected:
* @param out Output variable: will contain the value.
* @returns true if value is parsed successfully, false otherwise.
*/
- static bool parse(const std::string &what, const std::string &where,
+ static bool parse(const std::string &what, const ScriptLocation &where,
const std::string &key, bool *out);
public:
/*! Determines if the Key is set or not.
@@ -98,8 +99,8 @@ public:
class StringKey : public Key {
protected:
const std::string _value;
- StringKey(const Script *_s, int _line, const std::string &my_str) :
- Key(_s, _line), _value(my_str) {}
+ StringKey(const Script *_s, const ScriptLocation &_p,
+ const std::string &my_str) : Key{_s, _p}, _value{my_str} {}
public:
/*! Retrieve the value of this key. */
diff --git a/hscript/meta.cc b/hscript/meta.cc
index d43e58e..fd3e69b 100644
--- a/hscript/meta.cc
+++ b/hscript/meta.cc
@@ -25,17 +25,16 @@
using namespace Horizon::Keys;
-Key *Hostname::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Hostname::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
std::string valid_chars("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.");
if(data.find_first_not_of(valid_chars) != std::string::npos) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "hostname: expected machine or DNS name",
+ output_error(pos, "hostname: expected machine or DNS name",
"'" + data + "' is not a valid hostname");
return nullptr;
}
- return new Hostname(script, lineno, data);
+ return new Hostname(script, pos, data);
}
bool Hostname::validate() const {
@@ -45,14 +44,12 @@ bool Hostname::validate() const {
if(!isalpha(this->_value[0])) {
any_failure = true;
- output_error("installfile:" + std::to_string(this->lineno()),
- "hostname: must start with alphabetical character");
+ output_error(pos, "hostname: must start with alphabetical character");
}
if(this->_value.size() > 320) {
any_failure = true;
- output_error("installfile:" + std::to_string(this->lineno()),
- "hostname: value too long",
+ output_error(pos, "hostname: value too long",
"valid host names must be less than 320 characters");
}
@@ -63,8 +60,7 @@ bool Hostname::validate() const {
}
if(next_dot - last_dot > 64) {
any_failure = true;
- output_error("installfile:" + std::to_string(this->lineno()),
- "hostname: component too long",
+ output_error(pos, "hostname: component too long",
"each component must be less than 64 characters");
}
last_dot = next_dot;
@@ -89,8 +85,7 @@ bool Hostname::execute() const {
}
/* Runner.Execute.hostname. */
- output_info("installfile:" + std::to_string(this->lineno()),
- "hostname: set hostname to '" + actual + "'");
+ output_info(pos, "hostname: set hostname to '" + actual + "'");
if(script->options().test(Simulate)) {
std::cout << "hostname " << actual << std::endl;
}
@@ -99,17 +94,15 @@ bool Hostname::execute() const {
/* no-op; we don't want to set the image builder's hostname */
} else {
if(sethostname(actual.c_str(), actual.size()) == -1) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "hostname: failed to set host name",
- std::string(strerror(errno)));
+ output_error(pos, "hostname: failed to set host name",
+ ::strerror(errno));
return false;
}
}
#endif /* HAS_INSTALL_ENV */
/* Runner.Execute.hostname.Write. */
- output_info("installfile:" + std::to_string(this->lineno()),
- "hostname: write '" + actual + "' to /etc/hostname");
+ output_info(pos, "hostname: write '" + actual + "' to /etc/hostname");
if(script->options().test(Simulate)) {
std::cout << "printf '%s' " << actual << " > "
<< script->targetDirectory() << "/etc/hostname" << std::endl;
@@ -119,8 +112,7 @@ bool Hostname::execute() const {
std::ofstream hostname_f(script->targetDirectory() + "/etc/hostname",
std::ios_base::trunc);
if(!hostname_f) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "hostname: could not open /etc/hostname for writing");
+ output_error(pos, "hostname: could not open /etc/hostname");
return false;
}
hostname_f << actual;
@@ -131,8 +123,7 @@ bool Hostname::execute() const {
* terminates the nodename. */
if(dot != std::string::npos && this->_value.length() > dot + 1) {
const std::string domain(this->_value.substr(dot + 1));
- output_info("installfile:" + std::to_string(this->lineno()),
- "hostname: set domain name '" + domain + "'");
+ output_info(pos, "hostname: set domain name '" + domain + "'");
if(script->options().test(Simulate)) {
std::cout << "mkdir -p " << script->targetDirectory()
<< "/etc/conf.d" << std::endl;
@@ -147,17 +138,15 @@ bool Hostname::execute() const {
fs::create_directory(script->targetDirectory() +
"/etc/conf.d", ec);
if(ec) {
- output_error("installfile:" + std::to_string(line),
- "hostname: could not create /etc/conf.d "
+ output_error(pos, "hostname: could not create /etc/conf.d "
"directory", ec.message());
}
}
std::ofstream net_conf_f(script->targetDirectory() +
"/etc/conf.d/net", std::ios_base::app);
if(!net_conf_f) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "hostname: could not open /etc/conf.d/net for "
- "writing");
+ output_error(pos, "hostname: could not open /etc/conf.d/net "
+ "for writing");
return false;
}
net_conf_f << "dns_domain_lo=\"" << domain << "\"" << std::endl;
@@ -179,29 +168,26 @@ static std::set<std::string> valid_arches = {
};
-Key *Arch::parseFromData(const std::string &data, int lineno, int *errors,
- int *warnings, const Script *script) {
+Key *Arch::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *warnings, const Script *script) {
if(data.find_first_not_of("abcdefghijklmnopqrstuvwyxz1234567890_") !=
std::string::npos) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "arch: expected CPU architecture name",
+ output_error(pos, "arch: expected CPU architecture name",
"'" + data + "' is not a valid CPU architecture name");
return nullptr;
}
if(valid_arches.find(data) == valid_arches.end()) {
if(warnings) *warnings += 1;
- output_warning("installfile:" + std::to_string(lineno),
- "arch: unknown CPU architecture '" + data + "'");
+ output_warning(pos, "arch: unknown CPU architecture '" + data + "'");
}
- return new Arch(script, lineno, data);
+ return new Arch(script, pos, data);
}
bool Arch::execute() const {
- output_info("installfile:" + std::to_string(line),
- "arch: setting system CPU architecture to " + value());
+ output_info(pos, "arch: setting system CPU architecture to " + value());
if(script->options().test(Simulate)) {
std::cout << "printf '" << this->value() << "\\" << "n'"
@@ -214,8 +200,7 @@ bool Arch::execute() const {
std::ofstream arch_f(script->targetDirectory() + "/etc/apk/arch",
std::ios_base::trunc);
if(!arch_f) {
- output_error("installfile:" + std::to_string(line),
- "arch: cannot write target CPU architecture information");
+ output_error(pos, "arch: could not write target CPU architecture");
return false;
}
@@ -228,9 +213,9 @@ bool Arch::execute() const {
static std::regex valid_pkg("[0-9A-Za-z+_.-]*((>?<|[<>]?=|[~>])[0-9A-Za-z-_.]+)?");
-Key *PkgInstall::parseFromData(const std::string &data, int lineno,
- int *errors, int *warnings,
- const Script *script) {
+Key *PkgInstall::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors,
+ int *warnings, const Script *script) {
std::string next_pkg;
std::istringstream stream(data);
std::set<std::string> all_pkgs;
@@ -238,21 +223,19 @@ Key *PkgInstall::parseFromData(const std::string &data, int lineno,
while(stream >> next_pkg) {
if(!std::regex_match(next_pkg, valid_pkg)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "pkginstall: expected package name",
+ output_error(pos, "pkginstall: expected package name",
"'" + next_pkg + "' is not a valid package or atom");
return nullptr;
}
if(all_pkgs.find(next_pkg) != all_pkgs.end()) {
if(warnings) *warnings += 1;
- output_warning("installfile:" + std::to_string(lineno),
- "pkginstall: package '" + next_pkg +
+ output_warning(pos, "pkginstall: package '" + next_pkg +
"' is already in the target package set");
continue;
}
all_pkgs.insert(next_pkg);
}
- return new PkgInstall(script, lineno, all_pkgs);
+ return new PkgInstall(script, pos, all_pkgs);
}
@@ -298,13 +281,12 @@ const std::set<std::string> valid_langs = {
};
-Key *Language::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Language::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
if(data.length() < 2 ||
valid_langs.find(data.substr(0, 2)) == valid_langs.end()) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "language: invalid language specified",
+ output_error(pos, "language: invalid language specified",
"language must be a valid ISO 639-1 language code");
return nullptr;
}
@@ -314,8 +296,7 @@ Key *Language::parseFromData(const std::string &data, int lineno, int *errors,
/* data[1] is . if language is C.UTF-8 */
if(data[2] != '_' && data[1] != '.') {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "language: invalid language specified",
+ output_error(pos, "language: invalid language specified",
"language must be a valid ISO 639-1 language code, "
"optionally followed by '_' and a country code");
return nullptr;
@@ -325,20 +306,17 @@ Key *Language::parseFromData(const std::string &data, int lineno, int *errors,
std::string::size_type dot = data.find_first_of('.');
if(dot != std::string::npos && data.substr(dot+1, 5) != "UTF-8") {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "language: invalid language specified",
+ output_error(pos, "language: invalid language specified",
"you cannot specify a non-UTF-8 codeset");
return nullptr;
}
}
- return new Language(script, lineno, data);
+ return new Language(script, pos, data);
}
bool Language::execute() const {
- output_info("installfile:" + std::to_string(this->lineno()),
- "language: setting default system language to " +
- this->value());
+ output_info(pos, "language: setting default system language to " + _value);
if(script->options().test(Simulate)) {
std::cout << "printf '#!/bin/sh\\" << "nexport LANG=\"%s\"\\" << "n' "
@@ -355,9 +333,7 @@ bool Language::execute() const {
std::ofstream lang_f(lang_path, std::ios_base::trunc);
error_code ec;
if(!lang_f) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "language: could not open /etc/profile.d/00-language.sh "
- "for writing");
+ output_error(pos, "language: could not open profile for writing");
return false;
}
lang_f << "#!/bin/sh" << std::endl << "export LANG=\""
@@ -366,9 +342,8 @@ bool Language::execute() const {
fs::permissions(lang_path, rwxr_xr_x, ec);
if(ec) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "language: could not set /etc/profile.d/00-language.sh "
- "as executable", ec.message());
+ output_error(pos, "language: could not set profile script "
+ "executable", ec.message());
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -378,16 +353,15 @@ bool Language::execute() const {
#include "util/keymaps.hh"
-Key *Keymap::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Keymap::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
if(valid_keymaps.find(data) == valid_keymaps.end()) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "keymap: invalid keymap specified");
+ output_error(pos, "keymap: invalid keymap specified");
return nullptr;
}
- return new Keymap(script, lineno, data);
+ return new Keymap(script, pos, data);
}
bool Keymap::validate() const {
@@ -407,8 +381,7 @@ XKBOPTIONS=\n\
BACKSPACE=guess"
);
- output_info("installfile:" + std::to_string(line),
- "keymap: setting system keyboard map to " + _value);
+ output_info(pos, "keymap: setting system keyboard map to " + _value);
if(script->options().test(Simulate)) {
std::cout << "cat >" << script->targetDirectory()
@@ -422,8 +395,7 @@ BACKSPACE=guess"
std::ofstream keyconf(script->targetDirectory() + "/etc/default/keyboard",
std::ios_base::trunc);
if(!keyconf) {
- output_error("installfile:" + std::to_string(line),
- "keymap: cannot write target keyboard configuration");
+ output_error(pos, "keymap: cannot write target keyboard configuration");
return false;
}
@@ -433,32 +405,29 @@ BACKSPACE=guess"
}
-Key *Firmware::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Firmware::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
bool value;
- if(!BooleanKey::parse(data, "installfile:" + std::to_string(lineno),
- "firmware", &value)) {
+ if(!BooleanKey::parse(data, pos, "firmware", &value)) {
if(errors) *errors += 1;
return nullptr;
}
if(value) {
#ifdef NON_LIBRE_FIRMWARE
- output_warning("installfile:" + std::to_string(lineno),
- "firmware: You have requested non-libre firmware. "
+ output_warning(pos, "firmware: You have requested non-libre firmware. "
"This may cause security issues, system instability, "
"and many other issues. You should not enable this "
"option unless your system absolutely requires it.");
#else
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "firmware: You have requested non-libre firmware, "
+ output_error(pos, "firmware: You have requested non-libre firmware, "
"but this version of Horizon does not support "
"non-libre firmware.", "Installation cannot proceed.");
return nullptr;
#endif
}
- return new Firmware(script, lineno, value);
+ return new Firmware(script, pos, value);
}
/* LCOV_EXCL_START */
@@ -469,36 +438,32 @@ bool Firmware::execute() const {
/* LCOV_EXCL_STOP */
-Key *Timezone::parseFromData(const std::string &data, int lineno, int *errors,
- int *warnings, const Script *script) {
+Key *Timezone::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *warnings, const Script *script) {
if(data.find_first_of(" .\\") != std::string::npos || data[0] == '/') {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "timezone: invalid timezone name");
+ output_error(pos, "timezone: invalid timezone name");
return nullptr;
}
if(access("/usr/share/zoneinfo", X_OK) != 0) {
if(warnings) *warnings += 1;
- output_warning("installfile:" + std::to_string(lineno),
- "timezone: can't determine validity of timezone",
+ output_warning(pos, "timezone: can't determine validity of timezone",
"zoneinfo data is missing or inaccessible");
} else {
std::string zi_path = "/usr/share/zoneinfo/" + data;
if(access(zi_path.c_str(), F_OK) != 0) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "timezone: unknown timezone '" + data + "'");
+ output_error(pos, "timezone: unknown timezone '" + data + "'");
return nullptr;
}
}
- return new Timezone(script, lineno, data);
+ return new Timezone(script, pos, data);
}
bool Timezone::execute() const {
- output_info("installfile:" + std::to_string(this->lineno()),
- "timezone: setting system timezone to " + this->value());
+ output_info(pos, "timezone: setting system timezone to " + this->value());
if(script->options().test(Simulate)) {
/* If the target doesn't have tzdata installed, copy the zoneinfo from
@@ -523,8 +488,7 @@ bool Timezone::execute() const {
fs::create_symlink(zi_path, target_lt, ec);
if(ec) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "timezone: failed to create symbolic link",
+ output_error(pos, "timezone: failed to create symbolic link",
ec.message());
return false;
}
@@ -534,8 +498,7 @@ bool Timezone::execute() const {
* file from the Horizon environment to the target. */
fs::copy_file(zi_path, target_lt, ec);
if(ec) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "timezone: failed to prepare target environment",
+ output_error(pos, "timezone: failed to prepare target environment",
ec.message());
return false;
}
@@ -547,15 +510,15 @@ bool Timezone::execute() const {
}
-Key *Repository::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Repository::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
if(data.empty() || (data[0] != '/' && data.compare(0, 4, "http"))) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "repository: must be absolute path or HTTP(S) URL");
+ output_error(pos, "repository: must be absolute path or HTTP(S) URL");
return nullptr;
}
- return new Repository(script, lineno, data);
+ return new Repository(script, pos, data);
}
bool Repository::validate() const {
@@ -565,8 +528,7 @@ bool Repository::validate() const {
bool Repository::execute() const {
/* Runner.Execute.repository. */
- output_info("installfile:" + std::to_string(this->lineno()),
- "repository: write '" + this->value() +
+ output_info(pos, "repository: write '" + this->value() +
"' to /etc/apk/repositories");
if(script->options().test(Simulate)) {
std::cout << "echo '" << this->value()
@@ -579,8 +541,7 @@ bool Repository::execute() const {
std::ofstream repo_f(script->targetDirectory() + "/etc/apk/repositories",
std::ios_base::app);
if(!repo_f) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "repository: could not open /etc/apk/repositories "
+ output_error(pos, "repository: could not open /etc/apk/repositories "
"for writing");
return false;
}
@@ -594,16 +555,16 @@ bool Repository::execute() const {
}
-Key *SigningKey::parseFromData(const std::string &data, int lineno,
+Key *SigningKey::parseFromData(const std::string &data,
+ const ScriptLocation &pos,
int *errors, int *, const Script *script) {
if(data.empty() || (data[0] != '/' && data.compare(0, 8, "https://"))) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "signingkey: must be absolute path or HTTPS URL");
+ output_error(pos, "signingkey: must be absolute path or HTTPS URL");
return nullptr;
}
- return new SigningKey(script, lineno, data);
+ return new SigningKey(script, pos, data);
}
bool SigningKey::validate() const {
@@ -617,8 +578,7 @@ bool SigningKey::execute() const {
const std::string target_dir(script->targetDirectory() + "/etc/apk/keys/");
const std::string target(target_dir + name);
- output_info("installfile:" + std::to_string(line),
- "signingkey: trusting " + name + " for repository signing");
+ output_info(pos, "signingkey: trusting " + name + " for APK signing");
if(script->options().test(Simulate)) {
std::cout << "mkdir -p " << target_dir << std::endl;
@@ -635,9 +595,8 @@ bool SigningKey::execute() const {
if(!fs::exists(target_dir)) {
fs::create_directory(target_dir, ec);
if(ec) {
- output_error("installfile:" + std::to_string(line),
- "signingkey: could not initialise target repository "
- "keys directory", ec.message());
+ output_error(pos, "signingkey: could not initialise target "
+ "repository keys directory", ec.message());
return false;
}
}
@@ -645,8 +604,7 @@ bool SigningKey::execute() const {
if(_value[0] == '/') {
fs::copy_file(_value, target, fs_overwrite, ec);
if(ec) {
- output_error("installfile:" + std::to_string(line),
- "signingkey: could not copy signing key to target",
+ output_error(pos, "signingkey: could not copy key to target",
ec.message());
return false;
}
@@ -657,26 +615,25 @@ bool SigningKey::execute() const {
return true; /* LCOV_EXCL_LINE */
}
-Key *SvcEnable::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *SvcEnable::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
const static std::string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.-_";
if(data.find_first_not_of(valid_chars) != std::string::npos) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "svcenable: invalid service name", data);
+ output_error(pos, "svcenable: invalid service name", data);
return nullptr;
}
- return new SvcEnable(script, lineno, data);
+ return new SvcEnable(script, pos, data);
}
bool SvcEnable::execute() const {
const std::string target = script->targetDirectory() +
"/etc/runlevels/default/" + _value;
const std::string initd = "/etc/init.d/" + _value;
- output_info("installfile:" + std::to_string(line),
- "svcenable: enabling service " + _value);
+ output_info(pos, "svcenable: enabling service " + _value);
if(script->options().test(Simulate)) {
std::cout << "ln -s " << initd << " " << target << std::endl;
@@ -686,14 +643,12 @@ bool SvcEnable::execute() const {
#ifdef HAS_INSTALL_ENV
error_code ec;
if(!fs::exists(script->targetDirectory() + initd, ec)) {
- output_warning("installfile:" + std::to_string(line),
- "svcenable: service '" + _value + "' may be missing");
+ output_warning(pos, "svcenable: missing service", _value);
}
fs::create_symlink(initd, target, ec);
if(ec) {
- output_error("installfile:" + std::to_string(line),
- "svcenable: could not enable service " + _value,
+ output_error(pos, "svcenable: could not enable service " + _value,
ec.message());
return false;
}
diff --git a/hscript/meta.hh b/hscript/meta.hh
index d522bdf..b885e99 100644
--- a/hscript/meta.hh
+++ b/hscript/meta.hh
@@ -22,34 +22,34 @@ namespace Keys {
class Hostname : public StringKey {
private:
- Hostname(const Script *_s, int _line, const std::string my_name) :
- StringKey(_s, _line, my_name) {}
+ Hostname(const Script *_s, const ScriptLocation &_pos,
+ const std::string my_name) : StringKey(_s, _pos, my_name) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool validate() const override;
bool execute() const override;
};
class Arch : public StringKey {
private:
- Arch(const Script *_s, int _line, const std::string &arch) :
- StringKey(_s, _line, arch) {}
+ Arch(const Script *_s, const ScriptLocation &_p, const std::string &arch) :
+ StringKey(_s, _p, arch) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool execute() const override;
};
class PkgInstall : public Key {
private:
const std::set<std::string> _pkgs;
- PkgInstall(const Script *_s, int _line,
- const std::set<std::string> my_pkgs) : Key(_s, _line),
+ PkgInstall(const Script *_s, const ScriptLocation &_pos,
+ const std::set<std::string> my_pkgs) : Key(_s, _pos),
_pkgs(my_pkgs) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
const std::set<std::string> packages() const { return _pkgs; }
bool validate() const override;
bool execute() const override;
@@ -57,74 +57,74 @@ public:
class Language : public StringKey {
private:
- Language(const Script *_s, int _line, const std::string &my_lang) :
- StringKey(_s, _line, my_lang) {}
+ Language(const Script *_s, const ScriptLocation &_pos,
+ const std::string &my_lang) : StringKey(_s, _pos, my_lang) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool execute() const override;
};
class Keymap : public StringKey {
private:
- Keymap(const Script *_s, int _line, const std::string &keymap) :
- StringKey(_s, _line, keymap) {}
+ Keymap(const Script *_s, const ScriptLocation &_pos,
+ const std::string &keymap) : StringKey(_s, _pos, keymap) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool validate() const override;
bool execute() const override;
};
class Firmware : public BooleanKey {
private:
- Firmware(const Script *_s, int _line, bool _value) :
- BooleanKey(_s, _line, _value) {}
+ Firmware(const Script *_s, const ScriptLocation &_pos, bool _value) :
+ BooleanKey(_s, _pos, _value) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool execute() const override;
};
class Timezone : public StringKey {
private:
- Timezone(const Script *_s, int _line, const std::string &my_zone) :
- StringKey(_s, _line, my_zone) {}
+ Timezone(const Script *_s, const ScriptLocation &_pos,
+ const std::string &my_zone) : StringKey(_s, _pos, my_zone) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool execute() const override;
};
class Repository : public StringKey {
private:
- Repository(const Script *_s, int _line, const std::string &my_url) :
- StringKey(_s, _line, my_url) {}
+ Repository(const Script *_s, const ScriptLocation &_pos,
+ const std::string &my_url) : StringKey(_s, _pos, my_url) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool validate() const override;
bool execute() const override;
};
class SigningKey : public StringKey {
private:
- SigningKey(const Script *_s, int _line, const std::string &_path) :
- StringKey(_s, _line, _path) {}
+ SigningKey(const Script *_s, const ScriptLocation &_pos,
+ const std::string &_path) : StringKey(_s, _pos, _path) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool validate() const override;
bool execute() const override;
};
class SvcEnable : public StringKey {
private:
- SvcEnable(const Script *_s, int _line, const std::string &_svc) :
- StringKey(_s, _line, _svc) {}
+ SvcEnable(const Script *_s, const ScriptLocation &_pos,
+ const std::string &_svc) : StringKey(_s, _pos, _svc) {}
public:
- static Key *parseFromData(const std::string &, int, int *, int *,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int *, int *, const Script *);
bool execute() const override;
};
diff --git a/hscript/network.cc b/hscript/network.cc
index 445ccbb..1e915b3 100644
--- a/hscript/network.cc
+++ b/hscript/network.cc
@@ -30,15 +30,14 @@
using namespace Horizon::Keys;
-Key *Network::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Network::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
bool value;
- if(!BooleanKey::parse(data, "installfile:" + std::to_string(lineno),
- "network", &value)) {
+ if(!BooleanKey::parse(data, pos, "network", &value)) {
if(errors) *errors += 1;
return nullptr;
}
- return new Network(script, lineno, value);
+ return new Network(script, pos, value);
}
bool Network::execute() const {
@@ -47,7 +46,8 @@ bool Network::execute() const {
}
-Key *NetConfigType::parseFromData(const std::string &data, int lineno,
+Key *NetConfigType::parseFromData(const std::string &data,
+ const ScriptLocation &pos,
int *errors, int *, const Script *script) {
std::string type = data;
ConfigSystem system;
@@ -60,13 +60,12 @@ Key *NetConfigType::parseFromData(const std::string &data, int lineno,
system = ENI;
} else {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netconfigtype: invalid or missing config type",
+ output_error(pos, "netconfigtype: invalid or missing config type",
"one of 'netifrc', 'eni' required");
return nullptr;
}
- return new NetConfigType(script, lineno, system);
+ return new NetConfigType(script, pos, system);
}
bool NetConfigType::validate() const {
@@ -80,8 +79,9 @@ bool NetConfigType::execute() const {
}
-Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *NetAddress::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
long elements = std::count(data.cbegin(), data.cend(), ' ') + 1;
std::string::size_type type_pos, addr_pos, prefix_pos, gw_pos, next_end;
std::string iface, type, addr, prefix, gw;
@@ -90,8 +90,7 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
if(elements < 2) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: missing address type",
+ output_error(pos, "netaddress: missing address type",
"one of 'dhcp', 'slaac', 'static' required");
return nullptr;
}
@@ -100,8 +99,7 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
iface = data.substr(0, type_pos);
if(iface.length() > IFNAMSIZ) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: interface name '" + iface + "' is invalid",
+ output_error(pos, "netaddress: invalid interface name '" + iface + "'",
"interface names must be 16 characters or less");
return nullptr;
}
@@ -117,27 +115,24 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
if(!type.compare("dhcp")) {
if(elements > 2) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: address type 'dhcp' does not "
+ output_error(pos, "netaddress: address type 'dhcp' does not "
"accept further elements");
return nullptr;
}
- return new NetAddress(script, lineno, iface, AddressType::DHCP, "", 0,
+ return new NetAddress(script, pos, iface, AddressType::DHCP, "", 0,
"");
} else if(!type.compare("slaac")) {
if(elements > 2) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: address type 'slaac' does not "
+ output_error(pos, "netaddress: address type 'slaac' does not "
"accept further elements");
return nullptr;
}
- return new NetAddress(script, lineno, iface, AddressType::SLAAC, "", 0,
+ return new NetAddress(script, pos, iface, AddressType::SLAAC, "", 0,
"");
} else if(type.compare("static")) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: invalid address type '" + type + "'",
+ output_error(pos, "netaddress: invalid address type '" + type + "'",
"one of 'dhcp', 'slaac', 'static' required");
return nullptr;
}
@@ -145,16 +140,14 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
/* static address */
if(elements < 4) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: address type 'static' requires at least "
- "an IP address and prefix length");
+ output_error(pos, "netaddress: address type 'static' requires at "
+ "least an IP address and prefix length");
return nullptr;
}
if(elements > 5) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: too many elements to address type 'static'");
+ output_error(pos, "netaddress: too many elements for static address");
return nullptr;
}
@@ -172,8 +165,7 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
/* IPv6 */
if(::inet_pton(AF_INET6, addr.c_str(), &addr_buf) != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: '" + addr + "' is not a valid IPv6 address",
+ output_error(pos, "netaddress: '" + addr + "' is not a valid IPv6 address",
"hint: a ':' was found, indicating this address is IPv6");
return nullptr;
}
@@ -182,16 +174,14 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
real_prefix = std::stoi(prefix);
} catch(const std::exception &) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: prefix length is not a number",
+ output_error(pos, "netaddress: prefix length is not a number",
"prefix must be a decimal value between 1 and 128");
return nullptr;
}
if(real_prefix < 1 || real_prefix > 128) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: invalid IPv6 prefix length: " + prefix,
+ output_error(pos, "netaddress: invalid IPv6 prefix length: " + prefix,
"prefix must be a decimal value between 1 and 128");
return nullptr;
}
@@ -199,21 +189,19 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
if(gw.size() > 0 &&
::inet_pton(AF_INET6, gw.c_str(), &addr_buf) != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: '" + gw +
+ output_error(pos, "netaddress: '" + gw +
"' is not a valid IPv6 gateway",
"an IPv6 address must have an IPv6 gateway");
return nullptr;
}
- return new NetAddress(script, lineno, iface, AddressType::Static, addr,
+ return new NetAddress(script, pos, iface, AddressType::Static, addr,
static_cast<uint8_t>(real_prefix), gw);
} else if(addr.find('.') != std::string::npos) {
/* IPv4 */
if(::inet_pton(AF_INET, addr.c_str(), &addr_buf) != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: '" + addr + "' is not a valid IPv4 address");
+ output_error(pos, "netaddress: invalid IPv4 address", addr);
return nullptr;
}
@@ -225,8 +213,7 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
real_prefix = std::stoi(prefix);
} catch(const std::exception &) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: can't parse prefix length/mask",
+ output_error(pos, "netaddress: can't parse prefix length/mask",
"a network mask or prefix length is required");
return nullptr;
}
@@ -234,29 +221,26 @@ Key *NetAddress::parseFromData(const std::string &data, int lineno, int *errors,
if(real_prefix < 1 || real_prefix > 32) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: invalid IPv4 prefix length: " + prefix,
- "prefix must be between 1 and 32");
+ output_error(pos, "netaddress: invalid IPv4 prefix length: " +
+ prefix, "prefix must be between 1 and 32");
return nullptr;
}
if(gw.size() > 0 &&
::inet_pton(AF_INET, gw.c_str(), &addr_buf) != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: '" + gw +
+ output_error(pos, "netaddress: '" + gw +
"' is not a valid IPv4 gateway",
"an IPv4 address must have an IPv4 gateway");
return nullptr;
}
- return new NetAddress(script, lineno, iface, AddressType::Static, addr,
+ return new NetAddress(script, pos, iface, AddressType::Static, addr,
static_cast<uint8_t>(real_prefix), gw);
} else {
/* IPvBad */
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netaddress: invalid address of unknown type",
+ output_error(pos, "netaddress: invalid address of unknown type",
"an IPv4 or IPv6 address is required");
return nullptr;
}
@@ -272,8 +256,7 @@ bool NetAddress::validate() const {
struct ifreq request;
int my_sock = ::socket(AF_INET, SOCK_STREAM, 0);
if(my_sock == -1) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "netaddress: can't open socket", ::strerror(errno));
+ output_error(pos, "netaddress: can't open socket", ::strerror(errno));
return false;
}
memset(&request, 0, sizeof(request));
@@ -281,12 +264,10 @@ bool NetAddress::validate() const {
errno = 0;
if(ioctl(my_sock, SIOCGIFFLAGS, &request) == -1) {
if(errno == ENODEV) {
- output_warning("installfile:" + std::to_string(this->lineno()),
- "netaddress: specified interface does not exist");
+ output_warning(pos, "netaddress: interface does not exist", _iface);
return true;
}
- output_error("installfile:" + std::to_string(this->lineno()),
- "netaddress: trouble communicating with interface",
+ output_error(pos, "netaddress: trouble communicating with interface",
::strerror(errno));
return false;
}
@@ -298,9 +279,8 @@ bool execute_address_netifrc(const NetAddress *addr) {
std::ofstream config("/tmp/horizon/netifrc/config_" + addr->iface(),
std::ios_base::app);
if(!config) {
- output_error("installfile:" + std::to_string(addr->lineno()),
- "netaddress: couldn't write network configuration for "
- + addr->iface());
+ output_error(addr->where(), "netaddress: couldn't write network "
+ "configuration for " + addr->iface());
return false;
}
@@ -321,9 +301,8 @@ bool execute_address_netifrc(const NetAddress *addr) {
std::ofstream route("/tmp/horizon/netifrc/routes_" + addr->iface(),
std::ios_base::app);
if(!route) {
- output_error("installfile:" + std::to_string(addr->lineno()),
- "netaddress: couldn't write route configuration for "
- + addr->iface());
+ output_error(addr->where(), "netaddress: couldn't write route "
+ "configuration for " + addr->iface());
return false;
}
route << "default via " << addr->gateway() << std::endl;
@@ -336,9 +315,8 @@ bool execute_address_eni(const NetAddress *addr) {
std::ofstream config("/tmp/horizon/eni/" + addr->iface(),
std::ios_base::app);
if(!config) {
- output_error("installfile:" + std::to_string(addr->lineno()),
- "netaddress: couldn't write network configuration for "
- + addr->iface());
+ output_error(addr->where(), "netaddress: couldn't write network "
+ "configuration for " + addr->iface());
return false;
}
@@ -375,8 +353,7 @@ bool execute_address_eni(const NetAddress *addr) {
}
bool NetAddress::execute() const {
- output_info("installfile:" + std::to_string(this->lineno()),
- "netaddress: adding configuration for " + _iface);
+ output_info(pos, "netaddress: adding configuration for " + _iface);
NetConfigType::ConfigSystem system = NetConfigType::Netifrc;
@@ -396,18 +373,17 @@ bool NetAddress::execute() const {
}
-Key *Nameserver::parseFromData(const std::string &data, int lineno,
- int *errors, int *, const Script *script) {
+Key *Nameserver::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
char addr_buf[16];
static const std::string valid_chars("1234567890ABCDEFabcdef:.");
if(data.find_first_not_of(valid_chars) != std::string::npos) {
if(errors) *errors += 0;
- output_error("installfile:" + std::to_string(lineno),
- "nameserver: expected an IP address");
+ output_error(pos, "nameserver: expected an IP address");
if(data.find_first_of("[]") != std::string::npos) {
- output_info("installfile:" + std::to_string(lineno),
- "nameserver: hint: you don't have to enclose IPv6 "
+ output_info(pos, "nameserver: hint: you don't have to enclose IPv6 "
"addresses in [] brackets");
}
return nullptr;
@@ -417,8 +393,7 @@ Key *Nameserver::parseFromData(const std::string &data, int lineno,
/* IPv6 */
if(::inet_pton(AF_INET6, data.c_str(), &addr_buf) != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "nameserver: '" + data + "' is not a valid IPv6 "
+ output_error(pos, "nameserver: '" + data + "' is not a valid IPv6 "
"address", "hint: a ':' was found, so an IPv6 "
"address was expected");
return nullptr;
@@ -427,14 +402,13 @@ Key *Nameserver::parseFromData(const std::string &data, int lineno,
/* IPv4 */
if(::inet_pton(AF_INET, data.c_str(), &addr_buf) != 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "nameserver: '" + data + "' is not a valid IPv4 "
+ output_error(pos, "nameserver: '" + data + "' is not a valid IPv4 "
"address");
return nullptr;
}
}
- return new Nameserver(script, lineno, data);
+ return new Nameserver(script, pos, data);
}
bool Nameserver::execute() const {
@@ -449,8 +423,7 @@ bool Nameserver::execute() const {
std::ofstream resolvconf(script->targetDirectory() + "/etc/resolv.conf",
std::ios_base::app);
if(!resolvconf) {
- output_error("installfile:" + std::to_string(line),
- "nameserver: couldn't write configuration to target");
+ output_error(pos, "nameserver: couldn't write configuration to target");
return false;
}
resolvconf << "nameserver " << _value << std::endl;
@@ -459,8 +432,8 @@ bool Nameserver::execute() const {
}
-Key *NetSSID::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *NetSSID::parseFromData(const std::string &data, const ScriptLocation &p,
+ int *errors, int *, const Script *script) {
std::string iface, ssid, secstr, passphrase;
SecurityType type;
std::string::size_type start, pos, next;
@@ -472,32 +445,28 @@ Key *NetSSID::parseFromData(const std::string &data, int lineno, int *errors,
if(start == std::string::npos) {
/* ok this is just ridiculous then */
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: at least three elements expected");
+ output_error(p, "netssid: at least three elements expected");
return nullptr;
}
iface = data.substr(0, start);
if(iface.length() > IFNAMSIZ) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: interface name '" + iface + "' is invalid",
+ output_error(p, "netssid: interface name '" + iface + "' is invalid",
"interface names must be 16 characters or less");
return nullptr;
}
if(data[start + 1] != '"') {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: malformed SSID", "SSIDs must be quoted");
+ output_error(p, "netssid: malformed SSID", "SSIDs must be quoted");
return nullptr;
}
pos = data.find_first_of('"', start + 2);
if(pos == std::string::npos) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: unterminated SSID");
+ output_error(p, "netssid: unterminated SSID");
return nullptr;
}
@@ -505,8 +474,7 @@ Key *NetSSID::parseFromData(const std::string &data, int lineno, int *errors,
if(data.length() < pos + 5) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: security type expected");
+ output_error(p, "netssid: security type expected");
return nullptr;
}
start = data.find_first_of(' ', pos + 1);
@@ -524,8 +492,7 @@ Key *NetSSID::parseFromData(const std::string &data, int lineno, int *errors,
type = SecurityType::WPA;
} else {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: unknown security type '" + secstr + "'",
+ output_error(p, "netssid: unknown security type '" + secstr + "'",
"expected one of 'none', 'wep', or 'wpa'");
return nullptr;
}
@@ -533,14 +500,13 @@ Key *NetSSID::parseFromData(const std::string &data, int lineno, int *errors,
if(type != SecurityType::None) {
if(pos == std::string::npos || data.length() < pos + 2) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "netssid: expected passphrase for security type '" +
+ output_error(p, "netssid: expected passphrase for security type '" +
secstr + "'");
return nullptr;
}
passphrase = data.substr(pos + 1);
}
- return new NetSSID(script, lineno, iface, ssid, type, passphrase);
+ return new NetSSID(script, p, iface, ssid, type, passphrase);
}
bool NetSSID::validate() const {
@@ -553,8 +519,7 @@ bool NetSSID::validate() const {
struct iwreq request;
int my_sock = ::socket(AF_INET, SOCK_STREAM, 0);
if(my_sock == -1) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "netssid: can't open socket", ::strerror(errno));
+ output_error(pos, "netssid: can't open socket", ::strerror(errno));
return false;
}
memset(&request, 0, sizeof(request));
@@ -565,16 +530,13 @@ bool NetSSID::validate() const {
switch(errno)
{
case EOPNOTSUPP:
- output_warning("installfile:" + std::to_string(this->lineno()),
- "netssid: specified interface is not wireless");
+ output_warning(pos, "netssid: specified interface is not wireless");
return true;
case ENODEV:
- output_warning("installfile:" + std::to_string(this->lineno()),
- "netssid: specified interface does not exist");
+ output_warning(pos, "netssid: specified interface does not exist");
return true;
default:
- output_error("installfile:" + std::to_string(this->lineno()),
- "netssid: error communicating with wireless device");
+ output_error(pos, "netssid: error communicating with device");
return false;
}
}
@@ -586,14 +548,12 @@ bool NetSSID::validate() const {
}
bool NetSSID::execute() const {
- output_info("installfile:" + std::to_string(this->lineno()),
- "netssid: configuring SSID " + _ssid);
+ output_info(pos, "netssid: configuring SSID " + _ssid);
std::ofstream conf("/tmp/horizon/wpa_supplicant.conf",
std::ios_base::app);
if(!conf) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "netssid: failed to write configuration");
+ output_error(pos, "netssid: failed to write configuration");
return false;
}
diff --git a/hscript/network.hh b/hscript/network.hh
index 415a337..18ffc34 100644
--- a/hscript/network.hh
+++ b/hscript/network.hh
@@ -21,11 +21,11 @@ namespace Keys {
class Network : public BooleanKey {
private:
- Network(const Script *_s, int _line, bool _value) :
- BooleanKey(_s, _line, _value) {}
+ Network(const Script *_s, const ScriptLocation &_p, bool _value) :
+ BooleanKey(_s, _p, _value) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &pos,
+ int*, int*, const Script *);
bool execute() const override;
};
@@ -38,11 +38,11 @@ public:
private:
ConfigSystem _sys;
- NetConfigType(const Script *_sc, int _line, const ConfigSystem _s) :
- Key(_sc, _line), _sys(_s) {}
+ NetConfigType(const Script *_sc, const ScriptLocation &_p,
+ const ConfigSystem _s) : Key(_sc, _p), _sys(_s) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the desired network configuration system. */
ConfigSystem type() const { return this->_sys; }
@@ -69,14 +69,14 @@ private:
const uint8_t _prefix;
const std::string _gw;
- NetAddress(const Script *_sc, const int _line, const std::string &_i,
+ NetAddress(const Script *sc, const ScriptLocation &p, const std::string &_i,
const AddressType &_t, const std::string &_a, const uint8_t _p,
- const std::string &_g) : Key(_sc, _line), _iface(_i), _type(_t),
+ const std::string &_g) : Key(sc, p), _iface(_i), _type(_t),
_address(_a), _prefix(_p), _gw(_g)
{}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the interface to which this 'netaddress' key is associated. */
const std::string iface() const { return this->_iface; }
@@ -95,11 +95,11 @@ public:
class Nameserver : public StringKey {
private:
- Nameserver(const Script *_s, int _line, const std::string &ns) :
- StringKey(_s, _line, ns) {}
+ Nameserver(const Script *_s, const ScriptLocation &_pos,
+ const std::string &ns) : StringKey(_s, _pos, ns) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &_pos,
+ int*, int*, const Script *);
bool execute() const override;
};
@@ -117,12 +117,12 @@ private:
const SecurityType _sec;
const std::string _pw;
- NetSSID(const Script *_sc, int _line, const std::string &_if,
+ NetSSID(const Script *_sc, const ScriptLocation &p, const std::string &_if,
const std::string &_s, SecurityType _t, const std::string &_p) :
- Key(_sc, _line), _iface(_if), _ssid(_s), _sec(_t), _pw(_p) {}
+ Key(_sc, p), _iface(_if), _ssid(_s), _sec(_t), _pw(_p) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the interface to which this 'netssid' key is associated. */
const std::string iface() const { return this->_iface; }
diff --git a/hscript/script.cc b/hscript/script.cc
index 5b261d2..f775629 100644
--- a/hscript/script.cc
+++ b/hscript/script.cc
@@ -20,6 +20,7 @@
#include "script.hh"
#include "script_i.hh"
+#include "script_l.hh"
#include "disk.hh"
#include "meta.hh"
#include "network.hh"
@@ -30,8 +31,9 @@
#define SCRIPT_LINE_MAX 512
-typedef Horizon::Keys::Key *(*key_parse_fn)(const std::string &, int, int*,
- int*, const Horizon::Script *);
+typedef Horizon::Keys::Key *(*key_parse_fn)(const std::string &,
+ const Horizon::ScriptLocation &,
+ int*, int*, const Horizon::Script*);
using namespace Horizon::Keys;
@@ -76,12 +78,12 @@ const std::map<std::string, key_parse_fn> valid_keys = {
namespace Horizon {
bool Script::ScriptPrivate::store_key(const std::string &key_name, Key *obj,
- int lineno, int *errors, int *warnings,
- const ScriptOptions &opts) {
+ const ScriptLocation &pos, int *errors,
+ int *warnings, const ScriptOptions &opts) {
if(key_name == "network") {
- return store_network(obj, lineno, errors, warnings, opts);
+ return store_network(obj, pos, errors, warnings, opts);
} else if(key_name == "netconfigtype") {
- return store_netconfig(obj, lineno, errors, warnings, opts);
+ return store_netconfig(obj, pos, errors, warnings, opts);
} else if(key_name == "netaddress") {
std::unique_ptr<NetAddress> addr(dynamic_cast<NetAddress *>(obj));
this->addresses.push_back(std::move(addr));
@@ -95,21 +97,21 @@ bool Script::ScriptPrivate::store_key(const std::string &key_name, Key *obj,
this->ssids.push_back(std::move(ssid));
return true;
} else if(key_name == "hostname") {
- return store_hostname(obj, lineno, errors, warnings, opts);
+ return store_hostname(obj, pos, errors, warnings, opts);
} else if(key_name == "pkginstall") {
- return store_pkginstall(obj, lineno, errors, warnings, opts);
+ return store_pkginstall(obj, pos, errors, warnings, opts);
} else if(key_name == "arch") {
- return store_arch(obj, lineno, errors, warnings, opts);
+ return store_arch(obj, pos, errors, warnings, opts);
} else if(key_name == "rootpw") {
- return store_rootpw(obj, lineno, errors, warnings, opts);
+ return store_rootpw(obj, pos, errors, warnings, opts);
} else if(key_name == "language") {
- return store_lang(obj, lineno, errors, warnings, opts);
+ return store_lang(obj, pos, errors, warnings, opts);
} else if(key_name == "keymap") {
- return store_keymap(obj, lineno, errors, warnings, opts);
+ return store_keymap(obj, pos, errors, warnings, opts);
} else if(key_name == "firmware") {
- return store_firmware(obj, lineno, errors, warnings, opts);
+ return store_firmware(obj, pos, errors, warnings, opts);
} else if(key_name == "timezone") {
- return store_timezone(obj, lineno, errors, warnings, opts);
+ return store_timezone(obj, pos, errors, warnings, opts);
} else if(key_name == "repository") {
std::unique_ptr<Repository> repo(dynamic_cast<Repository *>(obj));
this->repos.push_back(std::move(repo));
@@ -119,17 +121,17 @@ bool Script::ScriptPrivate::store_key(const std::string &key_name, Key *obj,
this->repo_keys.push_back(std::move(key));
return true;
} else if(key_name == "svcenable") {
- return store_svcenable(obj, lineno, errors, warnings, opts);
+ return store_svcenable(obj, pos, errors, warnings, opts);
} else if(key_name == "username") {
- return store_username(obj, lineno, errors, warnings, opts);
+ return store_username(obj, pos, errors, warnings, opts);
} else if(key_name == "useralias") {
- return store_useralias(obj, lineno, errors, warnings, opts);
+ return store_useralias(obj, pos, errors, warnings, opts);
} else if(key_name == "userpw") {
- return store_userpw(obj, lineno, errors, warnings, opts);
+ return store_userpw(obj, pos, errors, warnings, opts);
} else if(key_name == "usericon") {
- return store_usericon(obj, lineno, errors, warnings, opts);
+ return store_usericon(obj, pos, errors, warnings, opts);
} else if(key_name == "usergroups") {
- return store_usergroups(obj, lineno, errors, warnings, opts);
+ return store_usergroups(obj, pos, errors, warnings, opts);
} else if(key_name == "diskid") {
std::unique_ptr<DiskId> diskid(dynamic_cast<DiskId *>(obj));
this->diskids.push_back(std::move(diskid));
@@ -188,23 +190,22 @@ Script *Script::load(const std::string &path, const ScriptOptions &opts) {
return nullptr;
}
- return Script::load(file, opts);
+ return Script::load(file, opts, path);
}
-Script *Script::load(std::istream &sstream, const ScriptOptions &opts) {
+Script *Script::load(std::istream &sstream, const ScriptOptions &opts,
+ const std::string &name) {
#define PARSER_ERROR(err_str) \
errors++;\
- output_error("installfile:" + std::to_string(lineno),\
- err_str, "");\
+ output_error(pos, err_str, "");\
if(!opts.test(ScriptOptionFlags::KeepGoing)) {\
break;\
}
#define PARSER_WARNING(warn_str) \
warnings++;\
- output_warning("installfile:" + std::to_string(lineno),\
- warn_str, "");
+ output_warning(pos, warn_str, "");
using namespace Horizon::Keys;
@@ -223,6 +224,7 @@ Script *Script::load(std::istream &sstream, const ScriptOptions &opts) {
continue;
}
+ const ScriptLocation pos(name, lineno, false);
const std::string line(nextline);
std::string key;
std::string::size_type start, key_end, value_begin;
@@ -254,14 +256,14 @@ Script *Script::load(std::istream &sstream, const ScriptOptions &opts) {
continue;
}
- Key *key_obj = valid_keys.at(key)(line.substr(value_begin), lineno,
+ Key *key_obj = valid_keys.at(key)(line.substr(value_begin), pos,
&errors, &warnings, the_script);
if(!key_obj) {
PARSER_ERROR("value for key '" + key + "' was invalid")
continue;
}
- if(!the_script->internal->store_key(key, key_obj, lineno, &errors,
+ if(!the_script->internal->store_key(key, key_obj, pos, &errors,
&warnings, opts)) {
PARSER_ERROR("stopping due to prior errors")
continue;
diff --git a/hscript/script.hh b/hscript/script.hh
index c874bd3..9befb41 100644
--- a/hscript/script.hh
+++ b/hscript/script.hh
@@ -18,6 +18,8 @@
#include <memory>
#include <bitset>
+#include <hscript/script_l.hh>
+
namespace Horizon {
namespace Keys {
@@ -71,10 +73,12 @@ public:
/*! Load a HorizonScript from the specified stream.
* @param stream The stream to load from.
* @param options Options to use for parsing, validation, and execution.
+ * @param name The name of the stream to use in diagnostic messages.
* @return true if the Script could be loaded; false otherwise.
*/
static Script *load(std::istream &stream,
- const ScriptOptions &options = 0);
+ const ScriptOptions &options = 0,
+ const std::string &name = "installfile");
/*! Determines if the HorizonScript is valid. */
bool validate() const;
diff --git a/hscript/script_i.hh b/hscript/script_i.hh
index b91e60f..b6fc371 100644
--- a/hscript/script_i.hh
+++ b/hscript/script_i.hh
@@ -19,6 +19,8 @@
#include <string>
#include <vector>
+#include "script_l.hh"
+
#include "disk.hh"
#include "meta.hh"
#include "network.hh"
@@ -104,23 +106,26 @@ struct Script::ScriptPrivate {
/*! 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.
+ * @param pos The on-disk script position of the key.
* @param errors Output parameter: if given, incremented on error.
* @param warnings Output parameter: if given, incremented on warning.
* @param opts Script parsing options.
*/
- bool store_key(const std::string &key_name, Key *obj, int lineno,
- int *errors, int *warnings, const ScriptOptions &opts);
+ bool store_key(const std::string &key_name, Key *obj,
+ const ScriptLocation &pos, int *errors, int *warnings,
+ const ScriptOptions &opts);
#define DUPLICATE_ERROR(OBJ, KEY, OLD_VAL) \
std::string err_str("previous value was ");\
err_str += OLD_VAL;\
- err_str += " at installfile:" + std::to_string(OBJ->lineno());\
+ err_str += " at " + OBJ->where().name;\
+ err_str += ":" + std::to_string(OBJ->where().line);\
if(errors) *errors += 1;\
- output_error("installfile:" + std::to_string(line),\
- "duplicate value for key '" + std::string(KEY) + "'",\
+ output_error(pos, "duplicate value for key '" + std::string(KEY) + "'",\
err_str);
- bool store_network(Key* obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_network(Key* obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(network) {
DUPLICATE_ERROR(network, "network",
network->test() ? "true" : "false")
@@ -131,7 +136,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_netconfig(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_netconfig(Key *obj, const ScriptLocation &pos, int *errors,
+ int *, const ScriptOptions &) {
if(netconfig) {
DUPLICATE_ERROR(netconfig, "netconfigtype",
netconfig->type());
@@ -142,7 +148,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_hostname(Key* obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_hostname(Key* obj, const ScriptLocation &pos, int *errors,
+ int *, const ScriptOptions &) {
if(hostname) {
DUPLICATE_ERROR(hostname, "hostname", hostname->value())
return false;
@@ -152,14 +159,13 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_pkginstall(Key* obj, int line, int *, int *warnings,
- ScriptOptions opts) {
+ bool store_pkginstall(Key* obj, const ScriptLocation &pos, int *,
+ int *warnings, const ScriptOptions &opts) {
PkgInstall *install = dynamic_cast<PkgInstall *>(obj);
for(auto &pkg : install->packages()) {
if(opts.test(StrictMode) && packages.find(pkg) != packages.end()) {
if(warnings) *warnings += 1;
- output_warning("installfile:" + std::to_string(line),
- "pkginstall: package '" + pkg +
+ output_warning(pos, "pkginstall: package '" + pkg +
"' has already been specified");
continue;
}
@@ -169,7 +175,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_arch(Key* obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_arch(Key* obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(arch) {
DUPLICATE_ERROR(arch, "arch", arch->value())
return false;
@@ -179,7 +186,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_rootpw(Key* obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_rootpw(Key* obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(rootpw) {
DUPLICATE_ERROR(rootpw, "rootpw", "an encrypted passphrase")
return false;
@@ -189,7 +197,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_firmware(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_firmware(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
std::unique_ptr<Firmware> f(dynamic_cast<Firmware *>(obj));
#ifdef NON_LIBRE_FIRMWARE
if(firmware) {
@@ -205,7 +214,8 @@ struct Script::ScriptPrivate {
#endif
}
- bool store_lang(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_lang(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(lang) {
DUPLICATE_ERROR(lang, "language", lang->value())
return false;
@@ -215,7 +225,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_keymap(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_keymap(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(keymap) {
DUPLICATE_ERROR(keymap, "keymap", keymap->value())
return false;
@@ -225,7 +236,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_timezone(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_timezone(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(tzone) {
DUPLICATE_ERROR(tzone, "timezone", tzone->value())
return false;
@@ -235,13 +247,13 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_svcenable(Key *obj, int line, int *, int *warn, ScriptOptions) {
+ bool store_svcenable(Key *obj, const ScriptLocation &pos, int *, int *warn,
+ const ScriptOptions &) {
std::unique_ptr<SvcEnable> svc(dynamic_cast<SvcEnable *>(obj));
for(const auto &s : svcs_enable) {
if(s->value() == svc->value()) {
if(warn) *warn += 1;
- output_warning("installfile:" + std::to_string(line),
- "svcenable: service already enabled",
+ output_warning(pos, "svcenable: service already enabled",
s->value());
return true;
}
@@ -251,11 +263,11 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_username(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_username(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
if(accounts.size() >= 255) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(line),
- "username: too many users",
+ output_error(pos, "username: too many users",
"you may only specify 255 users");
return false;
}
@@ -275,14 +287,14 @@ struct Script::ScriptPrivate {
#define GET_USER_DETAIL(OBJ, KEY) \
if(accounts.find(OBJ->username()) == accounts.end()) {\
if(errors) *errors += 1;\
- output_error("installfile:" + std::to_string(line),\
- std::string(KEY) + ": account name " + OBJ->username() +\
- " is unknown");\
+ output_error(pos, std::string(KEY) + ": account name " +\
+ OBJ->username() + " is unknown");\
return false;\
}\
UserDetail *detail = (*accounts.find(OBJ->username())).second.get();
- bool store_useralias(Key* obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_useralias(Key* obj, const ScriptLocation &pos, int *errors,
+ int *, const ScriptOptions &) {
std::unique_ptr<UserAlias> alias(dynamic_cast<UserAlias *>(obj));
GET_USER_DETAIL(alias, "useralias")
/* REQ: Runner.Validate.useralias.Unique */
@@ -294,7 +306,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_userpw(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_userpw(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
std::unique_ptr<UserPassphrase> pw(dynamic_cast<UserPassphrase *>(obj));
GET_USER_DETAIL(pw, "userpw")
/* REQ: Runner.Validate.userpw.Unique */
@@ -307,7 +320,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_usericon(Key *obj, int line, int *errors, int *, ScriptOptions) {
+ bool store_usericon(Key *obj, const ScriptLocation &pos, int *errors, int *,
+ const ScriptOptions &) {
std::unique_ptr<UserIcon> icon(dynamic_cast<UserIcon *>(obj));
GET_USER_DETAIL(icon, "usericon")
/* REQ: Runner.Validate.usericon.Unique */
@@ -319,8 +333,8 @@ struct Script::ScriptPrivate {
return true;
}
- bool store_usergroups(Key* obj, int line, int *errors, int *,
- ScriptOptions) {
+ bool store_usergroups(Key* obj, const ScriptLocation &pos, int *errors,
+ int *, const ScriptOptions &) {
std::unique_ptr<UserGroups> grp(dynamic_cast<UserGroups *>(obj));
GET_USER_DETAIL(grp, "usergroups")
detail->groups.push_back(std::move(grp));
diff --git a/hscript/script_l.hh b/hscript/script_l.hh
new file mode 100644
index 0000000..1f048c6
--- /dev/null
+++ b/hscript/script_l.hh
@@ -0,0 +1,35 @@
+/*
+ * script_l.hh - Definition of the ScriptLocation structure
+ * libhscript, the HorizonScript library for
+ * Project Horizon
+ *
+ * Copyright (c) 2020 Adélie Linux and contributors. All rights reserved.
+ * This code is licensed under the AGPL 3.0 license, as noted in the
+ * LICENSE-code file in the root directory of this repository.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+#ifndef SCRIPT_L_HH
+#define SCRIPT_L_HH
+
+#include <string>
+
+namespace Horizon {
+
+/*! Defines a location within a script. */
+struct ScriptLocation {
+ /*! The filename of the script. */
+ std::string name;
+ /*! The line number of the current location. */
+ int line;
+ /*! Whether this script is nested or the original script. */
+ bool nested;
+
+ ScriptLocation(std::string _n, int _l, bool _nest = false) :
+ name{_n}, line{_l}, nested{_nest} {};
+};
+
+}
+
+#endif /* !SCRIPT_L_HH */
diff --git a/hscript/script_v.cc b/hscript/script_v.cc
index 3622365..8fd1327 100644
--- a/hscript/script_v.cc
+++ b/hscript/script_v.cc
@@ -59,8 +59,7 @@ int validate_one_account(const std::string &name, UserDetail *detail) {
/* REQ: Runner.Validate.userpw.None */
if(!detail->passphrase) {
- long line = detail->name->lineno();
- output_warning("installfile:" + to_string(line),
+ output_warning(detail->name->where(),
"username: " + name + " has no set passphrase",
"This account will not be able to log in.");
}
@@ -81,7 +80,7 @@ int validate_one_account(const std::string &name, UserDetail *detail) {
return seen_groups.find(elem) == seen_groups.end();
})
) {
- output_error("installfile:" + to_string(group->lineno()),
+ output_error(group->where(),
"usergroups: duplicate group name specified");
failures++;
}
@@ -110,7 +109,7 @@ bool add_default_repos(std::vector<std::unique_ptr<Repository>> &repos,
const Script *s, bool firmware = false) {
Repository *sys_key = dynamic_cast<Repository *>(
Repository::parseFromData(
- "https://distfiles.adelielinux.org/adelie/stable/system", 0,
+ "https://distfiles.adelielinux.org/adelie/stable/system", {"", 0},
nullptr, nullptr, s
)
);
@@ -122,7 +121,7 @@ bool add_default_repos(std::vector<std::unique_ptr<Repository>> &repos,
repos.push_back(std::move(sys_repo));
Repository *user_key = dynamic_cast<Repository *>(
Repository::parseFromData(
- "https://distfiles.adelielinux.org/adelie/stable/user", 0,
+ "https://distfiles.adelielinux.org/adelie/stable/user", {"", 0},
nullptr, nullptr, s
)
);
@@ -164,8 +163,8 @@ bool add_default_repo_keys(std::vector<std::unique_ptr<SigningKey>> &keys,
const Script *s, bool firmware = false) {
SigningKey *key = dynamic_cast<SigningKey *>(
SigningKey::parseFromData(
- "/etc/apk/keys/packages@adelielinux.org.pub", 0, nullptr, nullptr,
- s)
+ "/etc/apk/keys/packages@adelielinux.org.pub", {"", 0},
+ nullptr, nullptr, s)
);
if(!key) {
output_error("internal", "failed to create default repository signing key");
@@ -179,7 +178,7 @@ bool add_default_repo_keys(std::vector<std::unique_ptr<SigningKey>> &keys,
if(firmware) {
SigningKey *fkey = dynamic_cast<SigningKey *>(SigningKey::parseFromData(
"/etc/apk/keys/packages@pleroma.apkfission.net-5ac0b300.rsa.pub",
- 0, nullptr, nullptr, s)
+ {"", 0}, nullptr, nullptr, s)
);
if(!fkey) {
output_error("internal", "failed to create firmware signing key");
@@ -189,7 +188,7 @@ bool add_default_repo_keys(std::vector<std::unique_ptr<SigningKey>> &keys,
keys.push_back(std::move(fw_key));
fkey = dynamic_cast<SigningKey *>(SigningKey::parseFromData(
"/etc/apk/keys/packages@pleroma.apkfission.net-5ac04808.rsa.pub",
- 0, nullptr, nullptr, s));
+ {"", 0}, nullptr, nullptr, s));
if(fkey) {
std::unique_ptr<SigningKey> fw_key2(fkey);
keys.push_back(std::move(fw_key2));
@@ -230,9 +229,8 @@ bool Horizon::Script::validate() const {
seen_iface[address->iface()] += 1;
if(seen_iface[address->iface()] > 255) {
failures++;
- output_error("installfile:" + std::to_string(address->lineno()),
- "netaddress: interface '" + address->iface() +
- "' has too many addresses assigned");
+ output_error(address->where(), "netaddress: interface '" +
+ address->iface() + "' has too many addresses");
}
}
}
@@ -242,8 +240,7 @@ bool Horizon::Script::validate() const {
if(!ns->validate()) failures++;
}
if(internal->nses.size() > MAXNS) {
- output_warning("installfile:" +
- to_string(internal->nses[MAXNS]->lineno()),
+ output_warning(internal->nses[MAXNS]->where(),
"nameserver: more nameservers are defined than usable",
to_string(MAXNS) + " nameservers are allowed");
}
@@ -276,7 +273,7 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Execute.timezone */
if(!internal->tzone) {
Timezone *utc = dynamic_cast<Timezone *>
- (Timezone::parseFromData("UTC", 0, &failures, nullptr, this));
+ (Timezone::parseFromData("UTC", {"", 0}, &failures, nullptr, this));
if(!utc) {
output_error("internal", "failed to create default timezone");
return false;
@@ -305,7 +302,7 @@ bool Horizon::Script::validate() const {
}
if(internal->repos.size() > 10) {
failures++;
- output_error("installfile:" + to_string(internal->repos[11]->lineno()),
+ output_error(internal->repos[11]->where(),
"repository: too many repositories specified",
"You may only specify up to 10 repositories.");
}
@@ -327,8 +324,7 @@ bool Horizon::Script::validate() const {
}
if(internal->repo_keys.size() > 10) {
failures++;
- output_error("installfile:" +
- to_string(internal->repo_keys[11]->lineno()),
+ output_error(internal->repo_keys[11]->where(),
"signingkey: too many keys specified",
"You may only specify up to 10 repository keys.");
}
@@ -351,9 +347,8 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.diskid.Unique */
if(seen_diskids.find(diskid->device()) != seen_diskids.end()) {
failures++;
- output_error("installfile:" + to_string(diskid->lineno()),
- "diskid: device " + diskid->device() +
- " has already been identified");
+ output_error(diskid->where(), "diskid: device " +
+ diskid->device() + " has already been identified");
}
seen_diskids.insert(diskid->device());
}
@@ -365,9 +360,8 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.disklabel.Unique */
if(seen_labels.find(label->device()) != seen_labels.end()) {
failures++;
- output_error("installfile:" + to_string(label->lineno()),
- "disklabel: device " + label->device() +
- " already has a label queued");
+ output_error(label->where(), "disklabel: device " +
+ label->device() + " already has a label queued");
} else {
seen_labels.insert(label->device());
}
@@ -383,9 +377,9 @@ bool Horizon::Script::validate() const {
std::string name = dev + maybe_p + to_string(part->partno());
if(seen_parts.find(name) != seen_parts.end()) {
failures++;
- output_error("installfile:" + to_string(part->lineno()),
- "partition: partition #" + to_string(part->partno()) +
- " already exists on device " + part->device());
+ output_error(part->where(), "partition: partition #" +
+ to_string(part->partno()) + " already exists on " +
+ part->device());
} else {
seen_parts.insert(name);
}
@@ -398,9 +392,8 @@ bool Horizon::Script::validate() const {
/* We don't actually have a requirement, but... */
if(seen_pvs.find(pv->value()) != seen_pvs.end()) {
failures++;
- output_error("installfile:" + to_string(pv->lineno()),
- "lvm_pv: a physical volume already exists on device "
- + pv->value());
+ output_error(pv->where(), "lvm_pv: a physical volume already "
+ "exists on device " + pv->value());
} else {
seen_pvs.insert(pv->value());
}
@@ -411,8 +404,7 @@ bool Horizon::Script::validate() const {
if(!fs::exists(pv->value(), ec) &&
seen_parts.find(pv->value()) == seen_parts.end()) {
failures++;
- output_error("installfile:" + to_string(pv->lineno()),
- "lvm_pv: device " + pv->value() +
+ output_error(pv->where(), "lvm_pv: device " + pv->value() +
" does not exist");
}
#endif /* HAS_INSTALL_ENV */
@@ -425,8 +417,7 @@ bool Horizon::Script::validate() const {
if(seen_vg_names.find(vg->name()) != seen_vg_names.end()) {
failures++;
- output_error("installfile:" + to_string(vg->lineno()),
- "lvm_vg: duplicate volume group name specified",
+ output_error(vg->where(), "lvm_vg: duplicate volume group name",
vg->name() + " already given");
} else {
seen_vg_names.insert(vg->name());
@@ -434,9 +425,8 @@ bool Horizon::Script::validate() const {
if(seen_vg_pvs.find(vg->pv()) != seen_vg_pvs.end()) {
failures++;
- output_error("installfile:" + to_string(vg->lineno()),
- "lvm_vg: a volume group already exists on " +
- vg->pv());
+ output_error(vg->where(), "lvm_vg: a volume group already exists "
+ "on " + vg->pv());
} else {
seen_vg_pvs.insert(vg->pv());
}
@@ -449,16 +439,14 @@ bool Horizon::Script::validate() const {
#ifdef HAS_INSTALL_ENV
if(!vg->test_pv()) {
failures++;
- output_error("installfile:" + to_string(vg->lineno()),
- "lvm_vg: a physical volume does not exist on "
- + vg->pv());
+ output_error(vg->where(), "lvm_vg: a physical volume does "
+ "not exist on " + vg->pv());
}
#endif /* HAS_INSTALL_ENV */
} else {
/* We can't tell if we aren't running on the target. */
- output_warning("installfile:" + to_string(vg->lineno()),
- "lvm_vg: please ensure an LVM physical volume "
- "already exists at " + vg->pv());
+ output_warning(vg->where(), "lvm_vg: please ensure an LVM "
+ "physical volume already exists at " + vg->pv());
}
}
}
@@ -471,9 +459,9 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.lvm_lv.Name */
if(seen_lvs.find(lvpath) != seen_lvs.end()) {
failures++;
- output_error("installfile:" + to_string(lv->lineno()),
- "lvm_lv: a volume with the name " + lv->name() +
- " already exists on the volume group " + lv->vg());
+ output_error(lv->where(), "lvm_lv: a volume with the name " +
+ lv->name() + " already exists on the volume group " +
+ lv->vg());
} else {
seen_lvs.insert(lvpath);
}
@@ -485,22 +473,20 @@ bool Horizon::Script::validate() const {
#ifdef HAS_INSTALL_ENV
if(!fs::exists("/dev/" + lv->vg())) {
failures++;
- output_error("installfile:" + to_string(lv->lineno()),
- "lvm_lv: volume group " + lv->vg() +
- " does not exist");
+ output_error(lv->where(), "lvm_lv: volume group " +
+ lv->vg() + " does not exist");
}
#endif /* HAS_INSTALL_ENV */
}
}
}
-#define CHECK_EXIST_PART_LV(device, key, line) \
+#define CHECK_EXIST_PART_LV(device, key, where) \
if(!fs::exists(device, ec) &&\
seen_parts.find(device) == seen_parts.end() &&\
seen_lvs.find(device.substr(5)) == seen_lvs.end()) {\
failures++;\
- output_error("installfile:" + to_string(line),\
- std::string(key) + ": device " + device +\
+ output_error(where, std::string(key) + ": device " + device +\
" does not exist");\
}
@@ -511,8 +497,7 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.encrypt.Unique */
if(seen_luks.find(crypt->device()) != seen_luks.end()) {
failures++;
- output_error("installfile:" + to_string(crypt->lineno()),
- "encrypt: encryption is already scheduled for " +
+ output_error(crypt->where(), "encrypt: encryption already enabled",
crypt->device());
} else {
seen_luks.insert(crypt->device());
@@ -521,7 +506,7 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.encrypt.Block */
if(opts.test(InstallEnvironment)) {
#ifdef HAS_INSTALL_ENV
- CHECK_EXIST_PART_LV(crypt->device(), "encrypt", crypt->lineno())
+ CHECK_EXIST_PART_LV(crypt->device(), "encrypt", crypt->where())
#endif /* HAS_INSTALL_ENV */
}
}
@@ -533,16 +518,15 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.fs.Unique */
if(seen_fses.find(fs->device()) != seen_fses.end()) {
failures++;
- output_error("installfile:" + std::to_string(fs->lineno()),
- "fs: a filesystem is already scheduled to be "
- "created on " + fs->device());
+ output_error(fs->where(), "fs: a filesystem is already scheduled "
+ "to be created on " + fs->device());
}
seen_fses.insert(fs->device());
/* REQ: Runner.Validate.fs.Block */
if(opts.test(InstallEnvironment)) {
#ifdef HAS_INSTALL_ENV
- CHECK_EXIST_PART_LV(fs->device(), "fs", fs->lineno())
+ CHECK_EXIST_PART_LV(fs->device(), "fs", fs->where())
#endif /* HAS_INSTALL_ENV */
}
}
@@ -554,10 +538,9 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.mount.Unique */
if(seen_mounts.find(mount->mountpoint()) != seen_mounts.end()) {
failures++;
- output_error("installfile:" + to_string(mount->lineno()),
- "mount: mountpoint " + mount->mountpoint() +
- " has already been specified; " + mount->device() +
- " is a duplicate");
+ output_error(mount->where(), "mount: mountpoint " +
+ mount->mountpoint() + " has already been specified; " +
+ mount->device() + " is a duplicate");
} else {
seen_mounts.insert(mount->mountpoint());
}
@@ -565,7 +548,7 @@ bool Horizon::Script::validate() const {
/* REQ: Runner.Validate.mount.Block */
if(opts.test(InstallEnvironment)) {
#ifdef HAS_INSTALL_ENV
- CHECK_EXIST_PART_LV(mount->device(), "mount", mount->lineno())
+ CHECK_EXIST_PART_LV(mount->device(), "mount", mount->where())
#endif /* HAS_INSTALL_ENV */
}
}
diff --git a/hscript/user.cc b/hscript/user.cc
index 0dc4eba..ae2b99c 100644
--- a/hscript/user.cc
+++ b/hscript/user.cc
@@ -106,14 +106,14 @@ static bool is_valid_name (const char *name)
/*! Determine if a string is a valid crypt passphrase
* @param pw The string to test for validity.
* @param key The name of key being validated ('rootpw', 'userpw', ...)
- * @param lineno The line number where the key occurs.
+ * @param pos The location where the key occurs.
* @returns true if +pw+ is a valid crypt passphrase; false otherwise.
*/
static bool string_is_crypt(const std::string &pw, const std::string &key,
- int lineno) {
+ const Horizon::ScriptLocation &pos) {
if(pw.size() < 5 || pw[0] != '$' || (pw[1] != '2' && pw[1] != '6')
|| pw[2] != '$') {
- output_error("installfile:" + std::to_string(lineno),
+ output_error(pos,
key + ": value is not a crypt-style encrypted passphrase");
return false;
}
@@ -121,13 +121,14 @@ static bool string_is_crypt(const std::string &pw, const std::string &key,
}
-Key *RootPassphrase::parseFromData(const std::string &data, int lineno,
+Key *RootPassphrase::parseFromData(const std::string &data,
+ const ScriptLocation &pos,
int *errors, int *, const Script *script) {
- if(!string_is_crypt(data, "rootpw", lineno)) {
+ if(!string_is_crypt(data, "rootpw", pos)) {
if(errors) *errors += 1;
return nullptr;
}
- return new RootPassphrase(script, lineno, data);
+ return new RootPassphrase(script, pos, data);
}
bool RootPassphrase::validate() const {
@@ -138,8 +139,7 @@ bool RootPassphrase::execute() const {
const std::string root_line = "root:" + this->_value + ":" +
std::to_string(time(nullptr) / 86400) + ":0:::::";
- output_info("installfile:" + std::to_string(this->lineno()),
- "rootpw: setting root passphrase");
+ output_info(pos, "rootpw: setting root passphrase");
if(script->options().test(Simulate)) {
std::cout << "(printf '" << root_line << "\\" << "n'; "
@@ -159,8 +159,7 @@ bool RootPassphrase::execute() const {
/* This was tested on gwyn during development. */
std::ifstream old_shadow(script->targetDirectory() + "/etc/shadow");
if(!old_shadow) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "rootpw: cannot open existing shadow file");
+ output_error(pos, "rootpw: cannot open existing shadow file");
return false;
}
@@ -182,8 +181,7 @@ bool RootPassphrase::execute() const {
std::ofstream new_shadow(script->targetDirectory() + "/etc/shadow",
std::ios_base::trunc);
if(!new_shadow) {
- output_error("installfile:" + std::to_string(this->lineno()),
- "rootpw: cannot replace target shadow file");
+ output_error(pos, "rootpw: cannot replace target shadow file");
return false;
}
new_shadow << shadow_stream.str();
@@ -194,29 +192,26 @@ bool RootPassphrase::execute() const {
}
-Key *Username::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *Username::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
if(!is_valid_name(data.c_str())) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "username: invalid username specified");
+ output_error(pos, "username: invalid username specified");
return nullptr;
}
/* REQ: Runner.Validate.username.System */
if(system_names.find(data) != system_names.end()) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "username: " + data + " is a reserved system username");
+ output_error(pos, "username: reserved system username", data);
return nullptr;
}
- return new Username(script, lineno, data);
+ return new Username(script, pos, data);
}
bool Username::execute() const {
- output_info("installfile:" + std::to_string(line),
- "username: creating account " + _value);
+ output_info(pos, "username: creating account " + _value);
if(script->options().test(Simulate)) {
std::cout << "useradd -c \"Adélie User\" -m -R "
@@ -230,8 +225,7 @@ bool Username::execute() const {
"-R", script->targetDirectory(),
"-U", _value}) != 0)
{
- output_error("installfile:" + std::to_string(line),
- "username: failed to create user account");
+ output_error(pos, "username: failed to create user account", _value);
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -239,19 +233,19 @@ bool Username::execute() const {
}
-Key *UserAlias::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *UserAlias::parseFromData(const std::string &data,
+ const ScriptLocation &pos, int *errors, int *,
+ const Script *script) {
/* REQ: Runner.Validate.useralias.Validity */
const std::string::size_type sep = data.find_first_of(' ');
if(sep == std::string::npos || data.length() == sep + 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "useralias: alias is required",
+ output_error(pos, "useralias: alias is required",
"expected format is: useralias [username] [alias...]");
return nullptr;
}
- return new UserAlias(script, lineno, data.substr(0, sep),
+ return new UserAlias(script, pos, data.substr(0, sep),
data.substr(sep + 1));
}
@@ -260,8 +254,7 @@ bool UserAlias::validate() const {
}
bool UserAlias::execute() const {
- output_info("installfile:" + std::to_string(line),
- "useralias: setting GECOS name for " + _username);
+ output_info(pos, "useralias: setting GECOS name for " + _username);
if(script->options().test(Simulate)) {
std::cout << "usermod -c \"" << _alias << "\" "
@@ -273,8 +266,7 @@ bool UserAlias::execute() const {
#ifdef HAS_INSTALL_ENV
if(run_command("usermod", {"-c", _alias, "-R", script->targetDirectory(),
_username}) != 0) {
- output_error("installfile:" + std::to_string(line),
- "useralias: failed to change GECOS of user " + _username);
+ output_error(pos, "useralias: failed to change GECOS for " + _username);
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -282,25 +274,25 @@ bool UserAlias::execute() const {
}
-Key *UserPassphrase::parseFromData(const std::string &data, int lineno,
+Key *UserPassphrase::parseFromData(const std::string &data,
+ const ScriptLocation &pos,
int *errors, int *, const Script *script) {
/* REQ: Runner.Validate.userpw.Validity */
const std::string::size_type sep = data.find_first_of(' ');
if(sep == std::string::npos || data.length() == sep + 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "userpw: passphrase is required",
+ output_error(pos, "userpw: passphrase is required",
"expected format is: userpw [username] [crypt...]");
return nullptr;
}
std::string passphrase = data.substr(sep + 1);
- if(!string_is_crypt(passphrase, "userpw", lineno)) {
+ if(!string_is_crypt(passphrase, "userpw", pos)) {
if(errors) *errors += 1;
return nullptr;
}
- return new UserPassphrase(script, lineno, data.substr(0, sep),
+ return new UserPassphrase(script, pos, data.substr(0, sep),
data.substr(sep + 1));
}
@@ -310,8 +302,7 @@ bool UserPassphrase::validate() const {
}
bool UserPassphrase::execute() const {
- output_info("installfile:" + std::to_string(line),
- "userpw: setting passphrase for " + _username);
+ output_info(pos, "userpw: setting passphrase for " + _username);
if(script->options().test(Simulate)) {
std::cout << "usermod -p '" << _passphrase << "' "
@@ -324,8 +315,7 @@ bool UserPassphrase::execute() const {
if(run_command("usermod", {"-p", _passphrase,
"-R", script->targetDirectory(),
_username}) != 0) {
- output_error("installfile:" + std::to_string(line),
- "userpw: failed to set passphrase for " + _username);
+ output_error(pos, "userpw: failed to set passphrase for " + _username);
return false;
}
#endif /* HAS_INSTALL_ENV */
@@ -333,14 +323,13 @@ bool UserPassphrase::execute() const {
}
-Key *UserIcon::parseFromData(const std::string &data, int lineno, int *errors,
- int *, const Script *script) {
+Key *UserIcon::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
/* REQ: Runner.Validate.usericon.Validity */
const std::string::size_type sep = data.find_first_of(' ');
if(sep == std::string::npos || data.length() == sep + 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "usericon: icon is required",
+ output_error(pos, "usericon: icon is required",
"expected format is: usericon [username] [path|url]");
return nullptr;
}
@@ -348,12 +337,11 @@ Key *UserIcon::parseFromData(const std::string &data, int lineno, int *errors,
std::string icon_path = data.substr(sep + 1);
if(icon_path[0] != '/' && !is_valid_url(icon_path)) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "usericon: path must be absolute path or valid URL");
+ output_error(pos, "usericon: path must be absolute path or valid URL");
return nullptr;
}
- return new UserIcon(script, lineno, data.substr(0, sep), icon_path);
+ return new UserIcon(script, pos, data.substr(0, sep), icon_path);
}
bool UserIcon::validate() const {
@@ -367,8 +355,7 @@ bool UserIcon::execute() const {
const std::string face_path(script->targetDirectory() + "/home/" +
_username + "/.face");
- output_info("installfile:" + std::to_string(line),
- "usericon: setting avatar for " + _username);
+ output_info(pos, "usericon: setting avatar for " + _username);
if(script->options().test(Simulate)) {
if(_icon_path[0] == '/') {
@@ -391,43 +378,39 @@ bool UserIcon::execute() const {
if(_icon_path[0] == '/') {
fs::copy_file(_icon_path, as_path, ec);
if(ec) {
- output_error("installfile:" + std::to_string(line),
- "usericon: failed to copy icon", ec.message());
+ output_error(pos, "usericon: failed to copy icon", ec.message());
return false;
}
} else {
if(!download_file(_icon_path, as_path)) {
- output_error("installfile:" + std::to_string(line),
- "usericon: failed to download icon");
+ output_error(pos, "usericon: failed to download icon");
return false;
}
}
fs::copy_file(as_path, face_path + ".icon", ec);
if(ec) {
- output_error("installfile:" + std::to_string(line),
- "usericon: failed to copy icon to home", ec.message());
+ output_error(pos, "usericon: failed to copy icon home", ec.message());
return false;
}
fs::create_symlink(".face.icon", face_path, ec);
if(ec) {
- output_warning("installfile:" + std::to_string(line),
- "usericon: failed to create legacy symlink");
+ output_warning(pos, "usericon: failed to create legacy symlink");
}
#endif /* HAS_INSTALL_ENV */
return true; /* LCOV_EXCL_LINE */
}
-Key *UserGroups::parseFromData(const std::string &data, int lineno,
+Key *UserGroups::parseFromData(const std::string &data,
+ const ScriptLocation &pos,
int *errors, int *, const Script *script) {
/* REQ: Runner.Validate.usergroups.Validity */
const std::string::size_type sep = data.find_first_of(' ');
if(sep == std::string::npos || data.length() == sep + 1) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "usergroups: at least one group is required",
+ output_error(pos, "usergroups: at least one group is required",
"expected format is: usergroups [user] [group(,...)]");
return nullptr;
}
@@ -440,8 +423,7 @@ Key *UserGroups::parseFromData(const std::string &data, int lineno,
/* REQ: Runner.Validate.usergroups.Group */
if(system_groups.find(group) == system_groups.end()) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "usergroups: group name '" + group + "' is invalid",
+ output_error(pos, "usergroups: invalid group name '" + group + "'",
"group is not a recognised system group");
return nullptr;
}
@@ -450,13 +432,12 @@ Key *UserGroups::parseFromData(const std::string &data, int lineno,
/* REQ: Runner.Validate.usergroups.Group */
if(stream.fail() && !stream.eof()) {
if(errors) *errors += 1;
- output_error("installfile:" + std::to_string(lineno),
- "usergroups: group name exceeds maximum length",
+ output_error(pos, "usergroups: group name exceeds maximum length",
"groups may only be 16 characters or less");
return nullptr;
}
- return new UserGroups(script, lineno, data.substr(0, sep), group_set);
+ return new UserGroups(script, pos, data.substr(0, sep), group_set);
}
bool UserGroups::validate() const {
@@ -465,8 +446,7 @@ bool UserGroups::validate() const {
}
bool UserGroups::execute() const {
- output_info("installfile:" + std::to_string(line),
- "usergroups: setting group membership for " + _username);
+ output_info(pos, "usergroups: setting group membership for " + _username);
std::string groups;
for(auto &grp : _groups) {
@@ -486,8 +466,7 @@ bool UserGroups::execute() const {
if(run_command("usermod", {"-a", "-G", groups,
"-R", script->targetDirectory(),
_username}) != 0) {
- output_error("installfile:" + std::to_string(line),
- "usergroups: failed to add groups to " + _username);
+ output_error(pos, "usergroups: failed to add groups to " + _username);
return false;
}
#endif /* HAS_INSTALL_ENV */
diff --git a/hscript/user.hh b/hscript/user.hh
index 8a093fb..dfda46d 100644
--- a/hscript/user.hh
+++ b/hscript/user.hh
@@ -22,22 +22,22 @@ namespace Keys {
class RootPassphrase : public StringKey {
private:
- RootPassphrase(const Script *_s, int _line, const std::string &my_pw) :
- StringKey(_s, _line, my_pw) {}
+ RootPassphrase(const Script *_s, const ScriptLocation &_p,
+ const std::string &my_pw) : StringKey(_s, _p, my_pw) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool validate() const override;
bool execute() const override;
};
class Username : public StringKey {
private:
- Username(const Script *_s, int _line, const std::string &name) :
- StringKey(_s, _line, name) {}
+ Username(const Script *_s, const ScriptLocation &_p,
+ const std::string &name) : StringKey(_s, _p, name) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
bool execute() const override;
};
@@ -46,12 +46,11 @@ private:
const std::string _username;
const std::string _alias;
- UserAlias(const Script *_s, int _line, const std::string &_n,
- const std::string &_a) :
- Key(_s, _line), _username(_n), _alias(_a) {}
+ UserAlias(const Script *_s, const ScriptLocation &_p, const std::string &_n,
+ const std::string &_a) : Key(_s, _p), _username(_n), _alias(_a) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the username for this alias. */
const std::string &username() const { return this->_username; }
@@ -67,12 +66,12 @@ private:
const std::string _username;
const std::string _passphrase;
- UserPassphrase(const Script *_s, int _line, const std::string &_n,
- const std::string &_p) :
- Key(_s, _line), _username(_n), _passphrase(_p) {}
+ UserPassphrase(const Script *_s, const ScriptLocation &_pos,
+ const std::string &_n, const std::string &_p) :
+ Key(_s, _pos), _username(_n), _passphrase(_p) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the username for this passphrase. */
const std::string &username() const { return this->_username; }
@@ -88,12 +87,12 @@ private:
const std::string _username;
const std::string _icon_path;
- UserIcon(const Script *_s, int _line, const std::string &_n,
+ UserIcon(const Script *_s, const ScriptLocation &_p, const std::string &_n,
const std::string &_i) :
- Key(_s, _line), _username(_n), _icon_path(_i) {}
+ Key(_s, _p), _username(_n), _icon_path(_i) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the username for this icon. */
const std::string &username() const { return this->_username; }
@@ -109,12 +108,12 @@ private:
const std::string _username;
const std::set<std::string> _groups;
- UserGroups(const Script *_s, int _line, const std::string &_n,
- const std::set<std::string> &_g) :
- Key(_s, _line), _username(_n), _groups(_g) {}
+ UserGroups(const Script *_s, const ScriptLocation &_pos,
+ const std::string &_n, const std::set<std::string> &_g) :
+ Key(_s, _pos), _username(_n), _groups(_g) {}
public:
- static Key *parseFromData(const std::string &, int, int*, int*,
- const Script *);
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
/*! Retrieve the username for this group set. */
const std::string &username() const { return this->_username; }