/**************************************************************************** ** 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(); // client ip command = LINBO_CMD("ip"); // myprocess->setArguments( command ); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setIpAddress(process->readAllStandardOutput()); // mac address command.clear(); command = LINBO_CMD("mac"); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setMacAddress(process->readAllStandardOutput()); // Version command = LINBO_CMD("version"); // myprocess->setArguments( command ); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setVersion(process->readAllStandardOutput().stripWhiteSpace()); // hostname command = LINBO_CMD("hostname"); // myprocess->setArguments( command ); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setHostname(process->readAllStandardOutput()); // CPU command = LINBO_CMD("cpu"); // myprocess->setArguments( command ); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setCpu(process->readAllStandardOutput()); // Memory command = LINBO_CMD("memory"); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setRamSize(process->readAllStandardOutput()); // Cache Size command = LINBO_CMD("size"); saveappend( command, this->config->getCache() ); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setCacheSize(process->readAllStandardOutput()); // Harddisk Size QRegExp *removePartition = new QRegExp("[0-9]{1,2}"); QString hd = this->config->getCache(); hd.remove( *removePartition ); command = LINBO_CMD("size"); saveappend( command, hd ); process->start( command.join(" ") ); while( !process->waitForFinished(10000) ) {} this->config->setHddSize(process->readAllStandardOutput()); } // -------------------- // - Public functions - // -------------------- void LinboBackend::executeAutostart() { } void LinboBackend::shutdown() { QStringList command; command.clear(); command = QStringList("busybox"); command.append("poweroff"); // TODO logConsole->writeStdOut( QString("shutdown entered") ); process->start( command.join(" ") ); } void LinboBackend::reboot() { QStringList command; command.clear(); command = QStringList("busybox"); command.append("reboot"); // TODO logConsole->writeStdOut( QString("reboot entered") ); process->start( command.join(" ") ); } bool LinboBackend::startOs(LinboOs* os) { if(os == nullptr) return false; QStringList command = LINBO_CMD("start"); saveappend( command, os->getBootPartition() ); saveappend( command, os->getRootPartition() ); saveappend( command, os->getKernel() ); saveappend( command, os->getInitrd() ); saveappend( command, os->getKernelOptions() ); saveappend( command, this->config->getCache() ); this->executeCommand(command, false); return true; } LinboConfig* LinboBackend::getConfig() { return this->config; } QList LinboBackend::getOperatingSystems() { return this->operatingSystems; } // ----------- // - Helpers - // ----------- void LinboBackend::executeCommand(QStringList commandArgs, bool waitForFinished) { QString command = commandArgs.takeFirst(); qDebug() << "Executing: " << command << " " << commandArgs.join(" "); process->start(command, commandArgs); process->waitForStarted(); if(waitForFinished) while( !process->waitForFinished(10000) ) {} } 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)) { 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(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); } } // this appends a quoted space in case item is empty and resolves // problems with linbo_cmd's weird "shift"-usage void LinboBackend::saveappend( QStringList& command, const QString& item ) { if ( item.isEmpty() ) command.append(""); else command.append( item ); } // Sync+start image QStringList LinboBackend::mksyncstartcommand(LinboConfig& config, LinboOs& os) { QStringList command = LINBO_CMD("syncstart"); saveappend( command, config.getServer() ); saveappend( command, config.getCache() ); saveappend( command, os.getBaseImage()->getName() ); saveappend( command, os.getDifferentialImage()->getName() ); saveappend( command, os.getBootPartition() ); // boot is same as root saveappend( command, os.getRootPartition() ); saveappend( command, os.getKernel() ); saveappend( command, os.getInitrd() ); saveappend( command, os.getKernelOptions() ); return command; } // Sync image from cache QStringList LinboBackend::mksynccommand(LinboConfig& config, LinboOs& os) { QStringList command = LINBO_CMD("sync"); saveappend( command, config.getCache() ); saveappend( command, os.getBaseImage()->getName() ); saveappend( command, os.getDifferentialImage()->getName() ); saveappend( command, os.getBootPartition() ); saveappend( command, os.getRootPartition() ); saveappend( command, os.getKernel() ); saveappend( command, os.getInitrd() ); saveappend( command, os.getKernelOptions() ); return command; } // Sync image from server QStringList LinboBackend::mksyncrcommand(LinboConfig& config, LinboOs& os) { QStringList command = LINBO_CMD("syncr"); saveappend( command, config.getServer() ); saveappend( command, config.getCache() ); saveappend( command, os.getBaseImage()->getName() ); saveappend( command, os.getDifferentialImage()->getName() ); saveappend( command, os.getBootPartition() ); saveappend( command, os.getRootPartition() ); saveappend( command, os.getKernel() ); saveappend( command, os.getInitrd() ); saveappend( command, os.getKernelOptions() ); saveappend( command, QString("force") ); return command; } 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; }