/*
* script.hh - Implementation of the Script class
* libhscript, the HorizonScript library for
* Project Horizon
*
* Copyright (c) 2019 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
*/
#include <fstream>
#include <iostream>
#include "script.hh"
#include "disk.hh"
#include "meta.hh"
#include "network.hh"
#include "user.hh"
#include "util/output.hh"
#define LINE_MAX 512
namespace Horizon {
struct Script::ScriptPrivate {
/*! Determines whether or not to enable networking. */
std::unique_ptr<Horizon::Keys::Network> network;
/*! The target system's hostname. */
std::unique_ptr<Horizon::Keys::Hostname> hostname;
/*! The packages to install to the target system. */
std::vector<std::string> packages;
/*! The root shadow line. */
std::unique_ptr<Horizon::Keys::RootPassphrase> rootpw;
/*! Target system's mountpoints. */
std::vector< std::unique_ptr<Horizon::Keys::Mount> > mounts;
};
Script::Script() {
internal = new ScriptPrivate;
}
const Script *Script::load(std::string path, ScriptOptions opts) {
std::ifstream file(path);
if(!file) {
output_error(path, "Cannot open installfile", "",
(opts.test(Pretty)));
return nullptr;
}
return Script::load(file, opts);
}
const Script *Script::load(std::istream &sstream, ScriptOptions opts) {
Script *the_script = new Script;
int lineno = 0;
char nextline[LINE_MAX];
const std::string delim(" \t");
bool any_error = false;
while(sstream.getline(nextline, sizeof(nextline))) {
lineno++;
if(nextline[0] == '#') {
/* This is a comment line; ignore it. */
continue;
}
const std::string line(nextline);
std::string::size_type start, key_end, value_begin;
start = line.find_first_not_of(delim);
if(start == std::string::npos) {
/* This is a blank line; ignore it. */
continue;
}
key_end = line.find_first_of(delim, start);
value_begin = line.find_first_not_of(delim, key_end);
if(key_end == std::string::npos || value_begin == std::string::npos) {
/* Key without value */
any_error = true;
output_error("installfile:" + std::to_string(lineno),
"key '" + line.substr(start, key_end) +
"' has no value",
"", (opts.test(Pretty)));
if(!opts.test(ScriptOptionFlags::KeepGoing)) {
break;
}
}
}
if(any_error) {
delete the_script;
return nullptr;
}
if(sstream.fail() && !sstream.eof()) {
output_error("installfile:" + std::to_string(lineno + 1),
"line exceeds maximum length",
"Maximum length for line is " + std::to_string(LINE_MAX),
(opts.test(Pretty)));
delete the_script;
return nullptr;
}
if(sstream.bad() && !sstream.eof()) {
output_error("installfile:" + std::to_string(lineno),
"I/O error reading installfile", "",
(opts.test(Pretty)));
}
return the_script;
}
bool Script::validate() const {
return false;
}
}