/**************************************************************************** ** Modern Linbo GUI ** Copyright (C) 2020 Dorian Zedler ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU Affero General Public License as published ** by the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License ** along with this program. If not, see . ****************************************************************************/ #include "linbobackend.h" #define LINBO_CMD(arg) QStringList("linbo_cmd") << (arg) using namespace std; LinboBackend::LinboBackend(QObject *parent) : QObject(parent) { this->config = new LinboConfig(this); // read start.conf qDebug() << "Starting to parse start.conf"; ifstream input; input.open( "start.conf", ios_base::in ); QString tmp_qstring; while( !input.eof() ) { // *** Image description section *** // entry in start tab read_qstring(&input, tmp_qstring); if ( tmp_qstring.startsWith("#") || tmp_qstring.isEmpty() ) continue; tmp_qstring = tmp_qstring.section("#",0,0).stripWhiteSpace(); // Strip comment if(tmp_qstring.lower().compare("[os]") == 0) { LinboOs* tmpOs = read_os(&input); if(!tmpOs->getName().isEmpty()) { this->operatingSystems.append(tmpOs); // check if this is an additional/incremental image for an existing OS /* TODO unsigned int i; // Being checked later. for(i = 0; i < elements.size(); i++ ) { if(tmp_os.get_name().lower().compare(elements[i].get_name().lower()) == 0) { elements[i].image_history.push_back(tmp_image); break; } } if(i==elements.size()) { // Not included yet -> new image tmp_os.image_history.push_back(tmp_image); elements.push_back(tmp_os); }*/ } else { tmpOs->deleteLater(); } } else if(tmp_qstring.lower().compare("[linbo]") == 0) { read_globals(&input, config); } else if(tmp_qstring.lower().compare("[partition]") == 0) { LinboDiskPartition* tmpPartition = read_partition(&input); if(!tmpPartition->getPath().isEmpty()) { diskPartitions.append(tmpPartition); } else { tmpPartition->deleteLater(); } } } input.close(); qDebug() << "Finished parsing start.conf"; qDebug() << "Loading global configuration"; // load global config QStringList command; this->process = new QProcess(); /* connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout()) ); connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr()) ); */ // client ip this->config->setIpAddress(this->executeCommand(true, "ip")); // mac address this->config->setMacAddress(this->executeCommand(true, "mac")); // Version this->config->setVersion(this->executeCommand(true, "version").stripWhiteSpace()); // hostname this->config->setHostname(this->executeCommand(true, "hostname")); // CPU this->config->setCpu(this->executeCommand(true, "cpu")); // Memory this->config->setRamSize(this->executeCommand(true, "memory")); // Cache Size this->config->setCacheSize(this->executeCommand(true, "size")); // Harddisk Size QRegExp *removePartition = new QRegExp("[0-9]{1,2}"); QString hd = this->config->getCache(); // e.g. turn /dev/sda1 into /dev/sda hd.remove( *removePartition ); this->config->setHddSize(this->executeCommand(true, "size", hd)); } // -------------------- // - Public functions - // -------------------- void LinboBackend::executeAutostart() { } void LinboBackend::shutdown() { this->executeCommand(false, "busybox", QStringList("poweroff")); } void LinboBackend::reboot() { this->executeCommand(false, "busybox", QStringList("reboot")); } bool LinboBackend::startOs(LinboOs* os) { if(os == nullptr || this->state != Idle) return false; this->setState(Starting); this->executeCommand( false, "start", os->getBootPartition(), os->getRootPartition(), os->getKernel(), os->getInitrd(), os->getKernelOptions(), this->config->getCache() ); return true; } bool LinboBackend::syncOs(LinboOs* os) { if(os == nullptr || this->state != Idle) return false; this->setState(Syncing); this->executeCommand( false, "syncstart", this->config->getServer(), this->config->getCache(), os->getBaseImage()->getName(), os->getDifferentialImage()->getName(), os->getBootPartition(), os->getRootPartition(), os->getKernel(), os->getInitrd(), os->getKernelOptions() ); return true; } bool LinboBackend::reinstallOs(LinboOs* os) { if(os == nullptr || this->state != Idle) return false; this->setState(Reinstalling); this->executeCommand( false, "syncr", this->config->getServer(), this->config->getCache(), os->getBaseImage()->getName(), os->getDifferentialImage()->getName(), os->getBootPartition(), os->getRootPartition(), os->getKernel(), os->getInitrd(), os->getKernelOptions(), QString("force") ); return true; } LinboConfig* LinboBackend::getConfig() { return this->config; } QList LinboBackend::getOperatingSystems() { return this->operatingSystems; } // ----------- // - Helpers - // ----------- QString LinboBackend::executeCommand(bool waitForFinished) { QStringList tmpList = this->linboCommandCache; this->linboCommandCache.clear(); return this->executeCommand(waitForFinished, "linbo_cmd", tmpList); } QString LinboBackend::executeCommand(bool waitForFinished, QString command, QStringList commandArgs) { if(waitForFinished) // clear old output this->process->readAll(); qDebug() << "Executing: " << command << " " << commandArgs.join(" "); process->start(command, commandArgs); process->waitForStarted(); if(waitForFinished) { while( !process->waitForFinished(10000) ) {} return this->process->readAllStandardOutput(); } return ""; } LinboBackend::LinboState LinboBackend::getState() { return this->state; } void LinboBackend::setState(LinboState state) { if(this->state == state) return; this->state = state; emit this->stateChanged(); } void LinboBackend::read_qstring( ifstream* input, QString& tmp ) { char line[500]; input->getline(line,500,'\n'); tmp = QString::fromAscii( line, -1 ).stripWhiteSpace(); } void LinboBackend::read_bool( ifstream* input, bool& tmp) { char line[500]; input->getline(line,500,'\n'); tmp = atoi( line ); } // Return true unless beginning of new section '[' is found. bool LinboBackend::read_pair(ifstream* input, QString& key, QString& value) { char line[1024]; if(input->peek() == '[') return false; // Next section found. input->getline(line,1024,'\n'); QString s = QString::fromAscii( line, -1 ).stripWhiteSpace(); key = s.section("=",0,0).stripWhiteSpace().lower(); if(s.startsWith("#")||key.isEmpty()) { key = QString(""); value = QString(""); } else { value=s.section("=",1).section("#",0,0).stripWhiteSpace(); } return true; } bool LinboBackend::toBool(const QString& value) { if(value.startsWith("yes",false)) return true; if(value.startsWith("true",false)) return true; if(value.startsWith("enable",false)) return true; return false; } LinboOs* LinboBackend::read_os(ifstream* input) { LinboOs* os = new LinboOs(this); QString key, value; while(!input->eof() && read_pair(input, key, value)) { qDebug() << key << "=" << value; if(key.compare("name") == 0) os->setName(value); else if(key.compare("description") == 0) os->setDescription(value); else if(key.compare("version") == 0) os->setVersion(value); else if(key.compare("iconname") == 0) os->setIconName(value); else if(key.compare("image") == 0) os->setDifferentialImage(new LinboImage(value, os)); else if(key.compare("baseimage") == 0) os->setBaseImage(new LinboImage(value, os)); else if(key.compare("boot") == 0) os->setBootPartition(value); else if(key.compare("root") == 0) os->setRootPartition(value); else if(key.compare("kernel") == 0) os->setKernel(value); else if(key.compare("initrd") == 0) os->setInitrd(value); else if(key.compare("append") == 0) os->setKernelOptions(value); else if(key.compare("syncenabled") == 0) os->setSyncButton(toBool(value)); else if(key.compare("startenabled") == 0) os->setStartButton(toBool(value)); else if((key.compare("remotesyncenabled") == 0) || (key.compare("newenabled") == 0)) os->setNewButton(toBool(value)); else if(key.compare("defaultaction") == 0) os->setDefaultAction(os->startActionFromString(value)); else if(key.compare("autostart") == 0) os->setAutostart(toBool(value)); else if(key.compare("autostarttimeout") == 0) os->setAutostartTimeout(value.toInt()); else if(key.compare("hidden") == 0) os->setHidden(toBool(value)); } return os; } LinboDiskPartition* LinboBackend::read_partition(ifstream* input) { LinboDiskPartition* partition = new LinboDiskPartition(this); QString key, value; while(!input->eof() && read_pair(input, key, value)) { if(key.compare("dev") == 0) partition->setPath(value); else if(key.compare("size") == 0) partition->setSize(value.toInt()); else if(key.compare("id") == 0) partition->setId(value); else if(key.compare("fstype") == 0) partition->setFstype(value); else if(key.startsWith("bootable", false)) partition->setBootable(toBool(value)); } return partition; } void LinboBackend::read_globals( ifstream* input, LinboConfig* config ) { QString key, value; while(!input->eof() && read_pair(input, key, value)) { if(key.compare("server") == 0) config->setServer(value); else if(key.compare("cache") == 0) config->setCache(value); else if(key.compare("roottimeout") == 0) config->setRootTimeout((unsigned int)value.toInt()); else if(key.compare("group") == 0) config->setHostgroup(value); else if(key.compare("autopartition") == 0) config->setAutopartition(toBool(value)); else if(key.compare("autoinitcache") == 0) config->setAutoInitCache(toBool(value)); else if(key.compare("autoformat") == 0) config->setAutoFormat(toBool(value)); else if(key.compare("backgroundfontcolor") == 0) config->setBackgroundFontcolor(value); else if(key.compare("consolefontcolorstdout") == 0) config->setConsoleFontcolorStdout(value); else if(key.compare("consolefontcolorstderr") == 0) config->setConsoleFontcolorStderr(value); else if(key.compare("usemulticast") == 0) { if( (unsigned int)value.toInt() == 0 ) config->setDownloadType("rsync"); else config->setDownloadType("multicast"); } else if(key.compare("downloadtype") == 0) config->setDownloadType(value); } } QStringList LinboBackend::mkpartitioncommand(vector &p) { QStringList command = LINBO_CMD("partition"); for(unsigned int i=0; i &p) { QStringList command = LINBO_CMD("partition_noformat"); for(unsigned int i=0; i &os, const QString& type) { QStringList command = LINBO_CMD("initcache"); saveappend( command, config.getServer() ); saveappend( command, config.getCache() ); if( ! type.isEmpty() ) command.append(type); else command.append("rsync"); for(unsigned int i = 0; i < os.size(); i++) { saveappend( command, os[i].getBaseImage()->getName() ); /* TODO ?? for(unsigned int j = 0; j < os[i].image_history.size(); j++) { saveappend( command, os[i].image_history[j].get_image() ); }*/ } return command; } QStringList LinboBackend::mklinboupdatecommand(LinboConfig& config) { QStringList command = LINBO_CMD("update"); saveappend( command, config.getServer() ); saveappend( command, config.getCache() ); return command; }