Dorian Zedler
ba722f1634
- implemented new executeCommand() function - further implemented backend functionality
399 lines
14 KiB
C++
399 lines
14 KiB
C++
/****************************************************************************
|
|
** Modern Linbo GUI
|
|
** Copyright (C) 2020 Dorian Zedler <dorian@itsblue.de>
|
|
**
|
|
** 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 <http://www.gnu.org/licenses/>.
|
|
****************************************************************************/
|
|
|
|
#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<LinboOs*> 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 <LinboDiskPartition> &p) {
|
|
QStringList command = LINBO_CMD("partition");
|
|
for(unsigned int i=0; i<p.size(); i++) {
|
|
saveappend( command, p[i].getPath() );
|
|
saveappend( command, (QString::number(p[i].getSize())) );
|
|
saveappend( command, p[i].getId() );
|
|
saveappend( command, (QString((p[i].getBootable())?"bootable":"\" \"")) );
|
|
saveappend( command, p[i].getFstype() );
|
|
}
|
|
return command;
|
|
}
|
|
|
|
QStringList LinboBackend::mkpartitioncommand_noformat(vector <LinboDiskPartition> &p) {
|
|
QStringList command = LINBO_CMD("partition_noformat");
|
|
for(unsigned int i=0; i<p.size(); i++) {
|
|
saveappend( command, p[i].getPath() );
|
|
saveappend( command, (QString::number(p[i].getSize())) );
|
|
saveappend( command, p[i].getId() );
|
|
saveappend( command, (QString((p[i].getBootable())?"bootable":"\" \"")) );
|
|
saveappend( command, p[i].getFstype() );
|
|
}
|
|
return command;
|
|
}
|
|
|
|
// type is 0 for rsync, 1 for multicast, 3 for bittorrent
|
|
QStringList LinboBackend::mkcacheinitcommand(LinboConfig& config, vector<LinboOs> &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;
|
|
}
|