From 0e5d52b23ae0b86e938905a332ad5b7439011dcc Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Mon, 4 Nov 2019 15:51:15 -0600 Subject: hscript: Refactor script.cc and disk.cc for maintainability --- hscript/script_i.hh | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 hscript/script_i.hh (limited to 'hscript/script_i.hh') diff --git a/hscript/script_i.hh b/hscript/script_i.hh new file mode 100644 index 0000000..cb7da13 --- /dev/null +++ b/hscript/script_i.hh @@ -0,0 +1,289 @@ +/* + * script_i.hh - Implementation of internal doodads for 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 + */ + +#ifndef HSCRIPT_SCRIPT_INTERNAL_HH_ +#define HSCRIPT_SCRIPT_INTERNAL_HH_ + +#include +#include +#include +#include +#include + +#include "disk.hh" +#include "meta.hh" +#include "network.hh" +#include "user.hh" + +using namespace Horizon::Keys; + +namespace Horizon { + +/*! Describes a user account. */ +struct UserDetail { + std::unique_ptr name; + std::unique_ptr alias; + std::unique_ptr passphrase; + std::unique_ptr icon; + std::vector< std::unique_ptr > groups; +}; + +struct Script::ScriptPrivate { + /*! Determines whether or not to enable networking. */ + std::unique_ptr network; + /*! The target system's hostname. */ + std::unique_ptr hostname; + /*! The packages to install to the target system. */ + std::set packages; + /*! The root shadow line. */ + std::unique_ptr rootpw; + /*! The system language. */ + std::unique_ptr lang; + /*! The system keymap. */ + std::unique_ptr keymap; + /*! The system timezone. */ + std::unique_ptr tzone; + + /*! Network addressing configuration */ + std::vector< std::unique_ptr > addresses; + /*! Network nameserver resolver addresses */ + std::vector< std::unique_ptr > nses; + /*! Wireless networking configuration */ + std::vector< std::unique_ptr > ssids; + + /*! APK repositories */ + std::vector< std::unique_ptr > repos; + /*! APK repository keys */ + std::vector< std::unique_ptr > repo_keys; + + /*! User account information */ + std::map< std::string, std::unique_ptr > accounts; + + /*! Disk identification keys */ + std::vector< std::unique_ptr > diskids; + /*! Disklabel configuration keys */ + std::vector< std::unique_ptr > disklabels; + /*! Partition creation keys */ + std::vector< std::unique_ptr > partitions; + /*! LVM physical volume keys */ + std::vector< std::unique_ptr > lvm_pvs; + /*! LVM volume group keys */ + std::vector< std::unique_ptr > lvm_vgs; + /*! LVM logical volume keys */ + std::vector< std::unique_ptr > lvm_lvs; + /*! LUKS creation keys */ + std::vector< std::unique_ptr > luks; + /*! Filesystem creation keys */ + std::vector< std::unique_ptr > fses; + /*! Target system's mountpoints. */ + std::vector< std::unique_ptr > mounts; + +#ifdef NON_LIBRE_FIRMWARE + std::unique_ptr firmware; +#endif + + /*! 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 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); + +#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());\ + if(errors) *errors += 1;\ + output_error("installfile:" + std::to_string(line),\ + "duplicate value for key '" + std::string(KEY) + "'",\ + err_str); + + bool store_network(Key* obj, int line, int *errors, int *, ScriptOptions) { + if(network) { + DUPLICATE_ERROR(network, "network", + network->test() ? "true" : "false") + return false; + } + std::unique_ptr net(dynamic_cast(obj)); + network = std::move(net); + return true; + } + + bool store_hostname(Key* obj, int line, int *errors, int *, ScriptOptions) { + if(hostname) { + DUPLICATE_ERROR(hostname, "hostname", hostname->value()) + return false; + } + std::unique_ptr name(dynamic_cast(obj)); + hostname = std::move(name); + return true; + } + + bool store_pkginstall(Key* obj, int line, int *, int *warnings, + ScriptOptions opts) { + PkgInstall *install = dynamic_cast(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 + + "' has already been specified"); + continue; + } + packages.insert(pkg); + } + delete install; + return true; + } + + bool store_rootpw(Key* obj, int line, int *errors, int *, ScriptOptions) { + if(rootpw) { + DUPLICATE_ERROR(rootpw, "rootpw", "an encrypted passphrase") + return false; + } + std::unique_ptr r(dynamic_cast(obj)); + rootpw = std::move(r); + return true; + } + + bool store_firmware(Key *obj, int line, int *errors, int *, ScriptOptions) { + std::unique_ptr f(dynamic_cast(obj)); +#ifdef NON_LIBRE_FIRMWARE + if(firmware) { + DUPLICATE_ERROR(firmware, "firmware", + (firmware->test()) ? "true" : "false") + return false; + } + firmware = std::move(f); + return true; +#else + assert(!f->test()); + return true; +#endif + } + + bool store_lang(Key *obj, int line, int *errors, int *, ScriptOptions) { + if(lang) { + DUPLICATE_ERROR(lang, "language", lang->value()) + return false; + } + std::unique_ptr l(dynamic_cast(obj)); + lang = std::move(l); + return true; + } + + bool store_keymap(Key *obj, int line, int *errors, int *, ScriptOptions) { + if(keymap) { + DUPLICATE_ERROR(keymap, "keymap", keymap->value()) + return false; + } + std::unique_ptr k(dynamic_cast(obj)); + keymap = std::move(k); + return true; + } + + bool store_timezone(Key *obj, int line, int *errors, int *, ScriptOptions) { + if(tzone) { + DUPLICATE_ERROR(tzone, "timezone", tzone->value()) + return false; + } + std::unique_ptr t(dynamic_cast(obj)); + tzone = std::move(t); + return true; + } + + bool store_username(Key *obj, int line, int *errors, int *, ScriptOptions) { + if(accounts.size() >= 255) { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(line), + "username: too many users", + "you may only specify 255 users"); + return false; + } + std::unique_ptr name(dynamic_cast(obj)); + if(accounts.find(name->value()) != accounts.end()) { + DUPLICATE_ERROR((*accounts.find(name->value())).second->name, + "username", "assigned") + return false; + } + std::unique_ptr detail(new UserDetail); + detail->name = std::move(name); + accounts.insert(std::make_pair(detail->name->value(), + std::move(detail))); + return true; + } + +#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");\ + return false;\ + }\ + UserDetail *detail = (*accounts.find(OBJ->username())).second.get(); + + bool store_useralias(Key* obj, int line, int *errors, int *, ScriptOptions) { + std::unique_ptr alias(dynamic_cast(obj)); + GET_USER_DETAIL(alias, "useralias") + /* REQ: Runner.Validate.useralias.Unique */ + if(detail->alias) { + DUPLICATE_ERROR(detail->alias, "useralias", detail->alias->alias()) + return false; + } + detail->alias = std::move(alias); + return true; + } + + bool store_userpw(Key *obj, int line, int *errors, int *, ScriptOptions) { + std::unique_ptr pw(dynamic_cast(obj)); + GET_USER_DETAIL(pw, "userpw") + /* REQ: Runner.Validate.userpw.Unique */ + if(detail->passphrase) { + DUPLICATE_ERROR(detail->passphrase, "userpw", + "an encrypted passphrase") + return false; + } + detail->passphrase = std::move(pw); + return true; + } + + bool store_usericon(Key *obj, int line, int *errors, int *, ScriptOptions) { + std::unique_ptr icon(dynamic_cast(obj)); + GET_USER_DETAIL(icon, "usericon") + /* REQ: Runner.Validate.usericon.Unique */ + if(detail->icon) { + DUPLICATE_ERROR(detail->icon, "usericon", detail->icon->icon()) + return false; + } + detail->icon = std::move(icon); + return true; + } + + bool store_usergroups(Key* obj, int line, int *errors, int *, + ScriptOptions) { + std::unique_ptr grp(dynamic_cast(obj)); + GET_USER_DETAIL(grp, "usergroups") + detail->groups.push_back(std::move(grp)); + return true; + } +#undef GET_USER_DETAIL + +#undef DUPLICATE_ERROR +}; + +} + +#endif /* !HSCRIPT_SCRIPT_INTERNAL_HH_ */ -- cgit v1.2.3-60-g2f50