150 lines
5.0 KiB
C++
150 lines
5.0 KiB
C++
#include <filesystem>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <map>
|
|
|
|
#include "db/database_manager.h"
|
|
#include "machine_manager.h"
|
|
#include "machine.h"
|
|
#include "vfs.h"
|
|
#include "util.h"
|
|
|
|
vfs_node* copy_vfs_node(vfs_node* original, vfs_node* new_parent) {
|
|
if(!original) {
|
|
return nullptr;
|
|
}
|
|
|
|
/* Create the new node and copy its properties. */
|
|
vfs_node* new_copy = new_node(original->name, original->type, new_parent,
|
|
original->owner_id, original->group_id,
|
|
original->permissions);
|
|
|
|
new_copy->content = original->content;
|
|
|
|
/* Recursively copy all children. */
|
|
for(auto const& [key, child_node] : original->children) {
|
|
new_copy->children[key] = copy_vfs_node(child_node, new_copy);
|
|
}
|
|
|
|
return new_copy;
|
|
}
|
|
|
|
MachineManager::MachineManager(DatabaseManager* db_manager) :
|
|
_db_manager(db_manager) {
|
|
/* Create template VFS that holds shared, read-only directories. */
|
|
_vfs_template_root = new_node("/", DIR_NODE, nullptr);
|
|
vfs_node* bin = new_node("bin", DIR_NODE, _vfs_template_root, 0, 0, 0755); /* System owned. */
|
|
_vfs_template_root->children["bin"] = bin;
|
|
|
|
/* Load all scripts from assets/scripts/bin into the VFS. */
|
|
const std::string path = "assets/scripts/bin";
|
|
for(const auto & entry : std::filesystem::directory_iterator(path)) {
|
|
if(entry.is_regular_file() && entry.path().extension() == ".lua") {
|
|
std::ifstream t(entry.path());
|
|
std::stringstream buffer;
|
|
buffer << t.rdbuf();
|
|
std::string filename_with_ext = entry.path().filename().string();
|
|
std::string filename = filename_with_ext.substr(0, filename_with_ext.find_last_of('.'));
|
|
vfs_node* script_node = new_node(filename, EXEC_NODE, bin, 0, 0, 0755); /* System owned. */
|
|
script_node->content = util::xor_string(buffer.str());
|
|
bin->children[filename] = script_node;
|
|
fprintf(stderr, "Loaded executable: /bin/%s\n", filename.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
MachineManager::~MachineManager(void) {
|
|
delete_vfs_tree(_vfs_template_root);
|
|
}
|
|
|
|
Machine* MachineManager::create_machine(uint32_t id, const std::string& hostname,
|
|
const std::string& system_type) {
|
|
auto* new_machine = new Machine(id, hostname);
|
|
|
|
vfs_node* root = new_node("/", DIR_NODE, nullptr, 0, 0, 0755); /* Root owned by system (0). */
|
|
|
|
/* Create directories for this specific VFS. */
|
|
vfs_node* home = new_node("home", DIR_NODE, root, id, id, 0755); /* Owned by player. */
|
|
vfs_node* user = new_node("user", DIR_NODE, home);
|
|
home->children["user"] = user;
|
|
vfs_node* readme = new_node("readme.txt", FILE_NODE, user, id, id, 0644); /* Owned by player. */
|
|
readme->content = "Welcome to your new virtual machine.";
|
|
user->children["readme.txt"] = readme;
|
|
|
|
/* Link to the shared directories from the template. */
|
|
root->children["bin"] = copy_vfs_node(_vfs_template_root->children["bin"], root);
|
|
/* Ensure copied bin directory has the correct owner/group/permissions. */
|
|
root->children["bin"]->owner_id = 0; /* System owned. */
|
|
root->children["bin"]->group_id = 0;
|
|
root->children["bin"]->permissions = 0755;
|
|
|
|
/* Assign the VFS to the new machine. */
|
|
new_machine->vfs_root = root;
|
|
|
|
if(system_type == "npc") {
|
|
vfs_node* npc_file = new_node("npc_system.txt", FILE_NODE, root, 0, 0, 0644);
|
|
npc_file->content = "This guy sucks nuts!";
|
|
root->children["npc_system.txt"] = npc_file;
|
|
|
|
}
|
|
|
|
return new_machine;
|
|
}
|
|
|
|
/* Recursively build the VFS tree from database nodes. */
|
|
void build_tree(vfs_node* parent, const std::map<long long, vfs_node*>& nodes) {
|
|
for(auto const& [id, node] : nodes) {
|
|
/* Inefficient but safe. Would be better to group nodes by parent_id. */
|
|
if(node->parent_id == parent->id) {
|
|
parent->children[node->name] = node;
|
|
node->parent = parent;
|
|
if(node->type == DIR_NODE) {
|
|
build_tree(node, nodes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Machine* MachineManager::load_machine(long long machine_id) {
|
|
printf("DEBUG: load_machine called for machine_id: %lld\n", machine_id);
|
|
|
|
std::string hostname = _db_manager->machines().get_hostname(machine_id);
|
|
long long owner_id = _db_manager->machines().get_owner_id(machine_id);
|
|
|
|
Machine* machine = new Machine(machine_id, hostname, owner_id);
|
|
|
|
/* Load all VFS nodes for this machine from the database. */
|
|
std::map<long long, vfs_node*> node_map;
|
|
vfs_node* root = nullptr;
|
|
|
|
auto nodes = _db_manager->vfs().get_nodes_for_machine(machine_id);
|
|
for(vfs_node* node : nodes) {
|
|
node_map[node->id] = node;
|
|
if(node->name == "/") {
|
|
root = node;
|
|
}
|
|
}
|
|
|
|
machine->services = _db_manager->services().get_for_machine(machine_id);
|
|
|
|
if(root) {
|
|
build_tree(root, node_map);
|
|
machine->vfs_root = root;
|
|
}
|
|
return machine;
|
|
}
|
|
|
|
long long MachineManager::get_machine_id_by_ip(const std::string& ip) {
|
|
if(_ip_to_id_map.count(ip)) {
|
|
return _ip_to_id_map[ip];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void MachineManager::init(void) {
|
|
auto all_machines = _db_manager->machines().get_all();
|
|
for(const auto& machine_data : all_machines) {
|
|
_ip_to_id_map[machine_data.ip_address] = machine_data.id;
|
|
}
|
|
}
|