diff --git a/src/modules/preservefiles/CMakeLists.txt b/src/modules/preservefiles/CMakeLists.txt new file mode 100644 index 000000000..43602024c --- /dev/null +++ b/src/modules/preservefiles/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) + +calamares_add_plugin( preservefiles + TYPE job + EXPORT_MACRO PLUGINDLLEXPORT_PRO + SOURCES + PreserveFiles.cpp + LINK_PRIVATE_LIBRARIES + calamares + SHARED_LIB +) diff --git a/src/modules/preservefiles/PreserveFiles.cpp b/src/modules/preservefiles/PreserveFiles.cpp new file mode 100644 index 000000000..9ef473f27 --- /dev/null +++ b/src/modules/preservefiles/PreserveFiles.cpp @@ -0,0 +1,181 @@ +/* === This file is part of Calamares - === + * + * Copyright 2018, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "PreserveFiles.h" + +#include "CalamaresVersion.h" +#include "JobQueue.h" +#include "GlobalStorage.h" + +#include "utils/CalamaresUtils.h" +#include "utils/CalamaresUtilsSystem.h" +#include "utils/CommandList.h" +#include "utils/Logger.h" +#include "utils/Units.h" + +#include + +using CalamaresUtils::operator""_MiB; + +QString targetPrefix() +{ + if ( CalamaresUtils::System::instance()->doChroot() ) + { + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( gs && gs->contains( "rootMountPoint" ) ) + { + QString r = gs->value( "rootMountPoint" ).toString(); + if ( !r.isEmpty() ) + return r; + else + cDebug() << "RootMountPoint is empty"; + } + else + { + cDebug() << "No rootMountPoint defined, preserving files to '/'"; + } + } + + return QLatin1Literal( "/" ); +} + +PreserveFiles::PreserveFiles( QObject* parent ) + : Calamares::CppJob( parent ) +{ +} + +PreserveFiles::~PreserveFiles() +{ +} + +QString +PreserveFiles::prettyName() const +{ + return tr( "Saving files for later ..." ); +} + +Calamares::JobResult PreserveFiles::exec() +{ + if ( m_items.isEmpty() ) + return Calamares::JobResult::error( tr( "No files configured to save for later." ) ); + + QString prefix = targetPrefix(); + if ( !prefix.endsWith( '/' ) ) + prefix.append( '/' ); + + int count = 0; + for ( const auto it : m_items ) + { + QString source = it.source; + if ( it.type == ItemType::Log ) + source = Logger::logFile(); + if ( it.type == ItemType::Config ) + cDebug() << "Config-preserving is not implemented yet."; + + if ( source.isEmpty() ) + cWarning() << "Skipping unnamed source file for" << it.dest; + else + { + QFile sourcef( source ); + if ( !sourcef.open( QFile::ReadOnly ) ) + { + cWarning() << "Could not read" << source; + continue; + } + + QFile destf( prefix + it.dest ); + if ( !destf.open( QFile::WriteOnly ) ) + { + sourcef.close(); + cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source; + continue; + } + + QByteArray b; + do + { + b = sourcef.read( 1_MiB ); + destf.write( b ); + } + while ( b.count() > 0 ); + + sourcef.close(); + destf.close(); + ++count; + } + } + + return count == m_items.count() ? + Calamares::JobResult::ok() : + Calamares::JobResult::error( tr( "Not all of the configured files could be preserved." ) ); +} + +void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap) +{ + auto files = configurationMap[ "files" ]; + + if ( ! ( files.isValid() && ( files.type() == QVariant::List ) ) ) + { + cDebug() << "No files: configuration key, or not a list."; + return; + } + + QVariantList l = files.toList(); + unsigned int c = 0; + for ( const auto li : l ) + { + if ( li.type() == QVariant::String ) + { + QString filename = li.toString(); + if ( !filename.isEmpty() ) + m_items.append( Item{ filename, filename, ItemType::Path } ); + else + cDebug() << "Empty filename for preservefiles, item" << c; + } + else if ( li.type() == QVariant::Map ) + { + const auto map = li.toMap(); + QString dest = map[ "dest" ].toString(); + QString from = map[ "from" ].toString(); + ItemType t = + ( from == "log" ) ? ItemType::Log : + ( from == "config" ) ? ItemType::Config : + ItemType::None; + + if ( dest.isEmpty() ) + { + cDebug() << "Empty dest for preservefiles, item" << c; + } + else if ( t == ItemType::None ) + { + cDebug() << "Invalid type for preservefiles, item" << c; + } + else + { + m_items.append( Item{ QString(), dest, t } ); + } + } + else + cDebug() << "Invalid type for preservefiles, item" << c; + + ++c; + } +} + +CALAMARES_PLUGIN_FACTORY_DEFINITION( PreserveFilesFactory, registerPlugin(); ) + diff --git a/src/modules/preservefiles/PreserveFiles.h b/src/modules/preservefiles/PreserveFiles.h new file mode 100644 index 000000000..0c9216336 --- /dev/null +++ b/src/modules/preservefiles/PreserveFiles.h @@ -0,0 +1,70 @@ +/* === This file is part of Calamares - === + * + * Copyright 2018, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef PRESERVEFILES_H +#define PRESERVEFILES_H + +#include +#include +#include + +#include "CppJob.h" + +#include "utils/PluginFactory.h" + +#include "PluginDllMacro.h" + + +class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob +{ + Q_OBJECT + + enum class ItemType + { + None, + Path, + Log, + Config + } ; + + struct Item + { + QString source; + QString dest; + ItemType type; + } ; + + using ItemList = QList< Item >; + +public: + explicit PreserveFiles( QObject* parent = nullptr ); + virtual ~PreserveFiles() override; + + QString prettyName() const override; + + Calamares::JobResult exec() override; + + void setConfigurationMap( const QVariantMap& configurationMap ) override; + +private: + ItemList m_items; +}; + +CALAMARES_PLUGIN_FACTORY_DECLARATION( PreserveFilesFactory ) + +#endif // PRESERVEFILES_H diff --git a/src/modules/preservefiles/module.desc b/src/modules/preservefiles/module.desc new file mode 100644 index 000000000..953d8c81b --- /dev/null +++ b/src/modules/preservefiles/module.desc @@ -0,0 +1,5 @@ +--- +type: "job" +name: "preservefiles" +interface: "qtplugin" +load: "libcalamares_job_preservefiles.so" diff --git a/src/modules/preservefiles/preservefiles.conf b/src/modules/preservefiles/preservefiles.conf new file mode 100644 index 000000000..4c33d93d9 --- /dev/null +++ b/src/modules/preservefiles/preservefiles.conf @@ -0,0 +1,31 @@ +# Configuration for the preserve-files job +# +# The *files* key contains a list of files to preserve. Each element of +# the list should have one of these forms: +# +# - an absolute path (probably within the host system). This will be preserved +# as the same path within the target system (chroot). If, globally, dontChroot +# is true, then these items are ignored (since the destination is the same +# as the source). +# - a map with a *dest* key. The *dest* value is a path interpreted in the +# target system (if dontChroot is true, in the host system). Relative paths +# are not recommended. There are two possible other keys in the map: +# - *from*, which must have one of the values, below; it is used to +# preserve files whose pathname is known to Calamares internally. +# - *src*, to refer to a path interpreted in the host system. Relative +# paths are not recommended, and are interpreted relative to where +# Calamares is being run. +# Only one of the two other keys may be set. +# +# Special values for the key *from* are: +# - *log*, for the complete log file (up to the moment the preservefiles +# module is run), +# - *config*, for the Calamares configuration file +# - *globals*, for a JSON dump of the contents of global storage +--- +files: + - /etc/oem-information + - from: log + dest: /root/install.log + - from: config + dest: /root/install.cfg