Calamares::JobResult DummyCppJob::exec() { // Ported from dummypython QProcess::execute( "/bin/sh", QStringList() << "-c" << "touch ~/calamares-dummycpp" ); QString accumulator = QDateTime::currentDateTimeUtc().toString( Qt::ISODate ) + '\n'; accumulator += QStringLiteral( "Calamares version: " ) + CALAMARES_VERSION_SHORT + '\n'; accumulator += QStringLiteral( "This job's name: " ) + prettyName() + '\n'; accumulator += QStringLiteral( "Configuration map: %1\n" ).arg( variantMapToString( m_configurationMap ) ); accumulator += QStringLiteral( " *** globalstorage test ***\n" ); Calamares::GlobalStorage *globalStorage = Calamares::JobQueue::instance()->globalStorage(); accumulator += QStringLiteral( "lala: " ) + (globalStorage->contains( "lala" ) ? QStringLiteral( "true" ) : QStringLiteral( "false" )) + '\n'; accumulator += QStringLiteral( "foo: " ) + (globalStorage->contains( "foo" ) ? QStringLiteral( "true" ) : QStringLiteral( "false" )) + '\n'; accumulator += QStringLiteral( "count: " ) + QString::number( globalStorage->count() ) + '\n'; globalStorage->insert( "item2", "value2" ); globalStorage->insert( "item3", 3 ); accumulator += QStringLiteral( "keys: %1\n" ).arg( globalStorage->keys().join( ',' ) ); accumulator += QStringLiteral( "remove: %1\n" ).arg( QString::number( globalStorage->remove( "item2" ) ) ); accumulator += QStringLiteral( "values: %1 %2 %3\n" ).arg( globalStorage->value( "foo" ).toString(), globalStorage->value( "item2" ).toString(), globalStorage->value( "item3" ).toString() ); emit progress( 0.1 ); cDebug() << "[DUMMYCPP]: " << accumulator; globalStorage->debugDump(); emit progress( 0.5 ); QThread::sleep( 3 ); return Calamares::JobResult::ok(); }
Calamares::JobResult SetTimezoneJob::exec() { // do not call timedatectl in a chroot, it is not safe (timedatectl talks // to a running timedated over D-Bus), and we have code that works if ( !Calamares::Settings::instance()->doChroot() ) { int ec = CalamaresUtils::System::instance()-> targetEnvCall( { "timedatectl", "set-timezone", m_region + '/' + m_zone } ); if ( !ec ) return Calamares::JobResult::ok(); } QString localtimeSlink( "/etc/localtime" ); QString zoneinfoPath( "/usr/share/zoneinfo" ); zoneinfoPath.append( QDir::separator() + m_region ); zoneinfoPath.append( QDir::separator() + m_zone ); Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QFileInfo zoneFile( gs->value( "rootMountPoint" ).toString() + zoneinfoPath ); if ( !zoneFile.exists() || !zoneFile.isReadable() ) return Calamares::JobResult::error( tr( "Cannot access selected timezone path." ), tr( "Bad path: %1" ).arg( zoneFile.absolutePath() ) ); // Make sure /etc/localtime doesn't exist, otherwise symlinking will fail CalamaresUtils::System::instance()-> targetEnvCall( { "rm", "-f", localtimeSlink } ); int ec = CalamaresUtils::System::instance()-> targetEnvCall( { "ln", "-s", zoneinfoPath, localtimeSlink } ); if ( ec ) return Calamares::JobResult::error( tr( "Cannot set timezone." ), tr( "Link creation failed, target: %1; link name: %2" ) .arg( zoneinfoPath ) .arg( "/etc/localtime" ) ); QFile timezoneFile( gs->value( "rootMountPoint" ).toString() + "/etc/timezone" ); if ( !timezoneFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) ) return Calamares::JobResult::error( tr( "Cannot set timezone,"), tr( "Cannot open /etc/timezone for writing")); QTextStream out(&timezoneFile); out << m_region << '/' << m_zone << "\n"; timezoneFile.close(); return Calamares::JobResult::ok(); }
QString atReplacements( QString s ) { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QString root( "/" ); QString user; if ( gs && gs->contains( "rootMountPoint" ) ) root = gs->value( "rootMountPoint" ).toString(); if ( gs && gs->contains( "username" ) ) user = gs->value( "username" ).toString(); return s.replace( "@@ROOT@@", root ).replace( "@@USER@@", user ); }
Calamares::JobResult SetKeyboardLayoutJob::exec() { // Read the location of the destination's / in the host file system from // the global settings Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QDir destDir( gs->value( "rootMountPoint" ).toString() ); // Get the path to the destination's /etc/vconsole.conf QString vconsoleConfPath = destDir.absoluteFilePath( "etc/vconsole.conf" ); // Get the path to the destination's /etc/X11/xorg.conf.d/00-keyboard.conf QString xorgConfDPath; QString keyboardConfPath; if ( QDir::isAbsolutePath( m_xOrgConfFileName ) ) { keyboardConfPath = m_xOrgConfFileName; while ( keyboardConfPath.startsWith( '/' ) ) keyboardConfPath.remove( 0, 1 ); keyboardConfPath = destDir.absoluteFilePath( keyboardConfPath ); xorgConfDPath = QFileInfo( keyboardConfPath ).path(); } else { xorgConfDPath = destDir.absoluteFilePath( "etc/X11/xorg.conf.d" ); keyboardConfPath = QDir( xorgConfDPath ) .absoluteFilePath( m_xOrgConfFileName ); } destDir.mkpath( xorgConfDPath ); // Get the path to the destination's path to the converted key mappings QString convertedKeymapPath = m_convertedKeymapPath; if ( !convertedKeymapPath.isEmpty() ) { while ( convertedKeymapPath.startsWith( '/' ) ) convertedKeymapPath.remove( 0, 1 ); convertedKeymapPath = destDir.absoluteFilePath( convertedKeymapPath ); } if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) ) return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for the virtual console." ), tr( "Failed to write to %1" ).arg( vconsoleConfPath ) ); if ( !writeX11Data( keyboardConfPath ) ) return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for X11." ), tr( "Failed to write to %1" ).arg( keyboardConfPath ) ); return Calamares::JobResult::ok(); }
static FileSystem::Type getDefaultFileSystemType() { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); FileSystem::Type defaultFS = FileSystem::Ext4; if ( gs->contains( "defaultFileSystemType" ) ) { PartUtils::findFS( gs->value( "defaultFileSystemType" ).toString(), &defaultFS); if ( defaultFS == FileSystem::Unknown ) defaultFS = FileSystem::Ext4; } return defaultFS; }
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( "/" ); }
static QStringList _gettext_languages() { QStringList languages; // There are two ways that Python jobs can be initialised: // - through JobQueue, in which case that has an instance which holds // a GlobalStorage object, or // - through the Python test-script, which initialises its // own GlobalStoragePythonWrapper, which then holds a // GlobalStorage object for all of Python. Calamares::JobQueue* jq = Calamares::JobQueue::instance(); Calamares::GlobalStorage* gs = jq ? jq->globalStorage() : CalamaresPython::GlobalStoragePythonWrapper::globalStorageInstance(); QVariant localeConf_ = gs->value( "localeConf" ); if ( localeConf_.canConvert< QVariantMap >() ) { QVariant lang_ = localeConf_.value< QVariantMap >()[ "LANG" ]; if ( lang_.canConvert< QString >() ) { QString lang = lang_.value< QString >(); languages.append( lang ); if ( lang.indexOf( '.' ) > 0 ) { lang.truncate( lang.indexOf( '.' ) ); languages.append( lang ); } if ( lang.indexOf( '_' ) > 0 ) { lang.truncate( lang.indexOf( '_' ) ); languages.append( lang ); } } } return languages; }
Calamares::JobResult CreateUserJob::exec() { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QDir destDir( gs->value( "rootMountPoint" ).toString() ); if ( gs->contains( "sudoersGroup" ) && !gs->value( "sudoersGroup" ).toString().isEmpty() ) { QFileInfo sudoersFi( destDir.absoluteFilePath( "etc/sudoers.d/10-installer" ) ); if ( !sudoersFi.absoluteDir().exists() ) return Calamares::JobResult::error( tr( "Sudoers dir is not writable." ) ); QFile sudoersFile( sudoersFi.absoluteFilePath() ); if (!sudoersFile.open( QIODevice::WriteOnly | QIODevice::Text ) ) return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) ); QString sudoersGroup = gs->value( "sudoersGroup" ).toString(); QTextStream sudoersOut( &sudoersFile ); sudoersOut << QString( "%%1 ALL=(ALL) ALL\n" ).arg( sudoersGroup ); if ( QProcess::execute( "chmod", { "440", sudoersFi.absoluteFilePath() } ) ) return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) ); } QFileInfo groupsFi( destDir.absoluteFilePath( "etc/group" ) ); QFile groupsFile( groupsFi.absoluteFilePath() ); if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) return Calamares::JobResult::error( tr( "Cannot open groups file for reading." ) ); QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() ); QStringList groupsLines = groupsData.split( '\n' ); for ( QStringList::iterator it = groupsLines.begin(); it != groupsLines.end(); ++it ) { int indexOfFirstToDrop = it->indexOf( ':' ); it->truncate( indexOfFirstToDrop ); } foreach ( const QString& group, m_defaultGroups ) if ( !groupsLines.contains( group ) ) CalamaresUtils::System::instance()-> targetEnvCall( { "groupadd", group } ); QString defaultGroups = m_defaultGroups.join( ',' ); if ( m_autologin ) { QString autologinGroup; if ( gs->contains( "autologinGroup" ) && !gs->value( "autologinGroup" ).toString().isEmpty() ) autologinGroup = gs->value( "autologinGroup" ).toString(); else autologinGroup = QStringLiteral( "autologin" ); CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", autologinGroup } ); defaultGroups.append( QString( ",%1" ).arg( autologinGroup ) ); } int ec = CalamaresUtils::System::instance()-> targetEnvCall( { "useradd", "-m", "-s", "/bin/bash", "-U", "-G", defaultGroups, m_userName } ); if ( ec ) return Calamares::JobResult::error( tr( "Cannot create user %1." ) .arg( m_userName ), tr( "useradd terminated with error code %1." ) .arg( ec ) ); ec = CalamaresUtils::System::instance()->targetEnvCall( { "chfn", "-f", m_fullName, m_userName } ); if ( ec ) return Calamares::JobResult::error( tr( "Cannot set full name for user %1." ) .arg( m_userName ), tr( "chfn terminated with error code %1." ) .arg( ec ) ); ec = CalamaresUtils::System::instance()-> targetEnvCall( { "chown", "-R", QString( "%1:%2" ).arg( m_userName ) .arg( m_userName ), QString( "/home/%1" ).arg( m_userName ) } ); if ( ec ) return Calamares::JobResult::error( tr( "Cannot set home directory ownership for user %1." ) .arg( m_userName ), tr( "chown terminated with error code %1." ) .arg( ec ) ); return Calamares::JobResult::ok(); }
Calamares::JobResult CommandList::run() { QLatin1Literal rootMagic( "@@ROOT@@" ); QLatin1Literal userMagic( "@@USER@@" ); System::RunLocation location = m_doChroot ? System::RunLocation::RunInTarget : System::RunLocation::RunInHost; /* Figure out the replacement for @@ROOT@@ */ QString root = QStringLiteral( "/" ); Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); bool needsRootSubstitution = findInCommands( *this, rootMagic ); if ( needsRootSubstitution && ( location == System::RunLocation::RunInHost ) ) { if ( !gs || !gs->contains( "rootMountPoint" ) ) { cError() << "No rootMountPoint defined."; return Calamares::JobResult::error( QCoreApplication::translate( "CommandList", "Could not run command." ), QCoreApplication::translate( "CommandList", "The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined." ) ); } root = gs->value( "rootMountPoint" ).toString(); } bool needsUserSubstitution = findInCommands( *this, userMagic ); if ( needsUserSubstitution && ( !gs || !gs->contains( "username" ) ) ) { cError() << "No username defined."; return Calamares::JobResult::error( QCoreApplication::translate( "CommandList", "Could not run command." ), QCoreApplication::translate( "CommandList", "The command needs to know the user's name, but no username is defined." ) ); } QString user = gs->value( "username" ).toString(); // may be blank if unset for ( CommandList::const_iterator i = cbegin(); i != cend(); ++i ) { QString processed_cmd = i->command(); processed_cmd.replace( rootMagic, root ).replace( userMagic, user ); bool suppress_result = false; if ( processed_cmd.startsWith( '-' ) ) { suppress_result = true; processed_cmd.remove( 0, 1 ); // Drop the - } QStringList shell_cmd { "/bin/sh", "-c" }; shell_cmd << processed_cmd; int timeout = i->timeout() >= 0 ? i->timeout() : m_timeout; ProcessResult r = System::runCommand( location, shell_cmd, QString(), QString(), timeout ); if ( r.getExitCode() != 0 ) { if ( suppress_result ) cDebug() << "Error code" << r.getExitCode() << "ignored by CommandList configuration."; else return r.explainProcess( processed_cmd, timeout ); } } return Calamares::JobResult::ok(); }
void KeyboardPage::onActivate() { /* Guessing a keyboard layout based on the locale means * mapping between language identifiers in <lang>_<country> * format to keyboard mappings, which are <country>_<layout> * format; in addition, some countries have multiple languages, * so fr_BE and nl_BE want different layouts (both Belgian) * and sometimes the language-country name doesn't match the * keyboard-country name at all (e.g. Ellas vs. Greek). * * This is a table of language-to-keyboard mappings. The * language identifier is the key, while the value is * a string that is used instead of the real language * identifier in guessing -- so it should be something * like <layout>_<country>. */ static constexpr char arabic[] = "ara"; static const auto specialCaseMap = QMap<std::string, std::string>( { /* Most Arab countries map to Arabic keyboard (Default) */ { "ar_AE", arabic }, { "ar_BH", arabic }, { "ar_DZ", arabic }, { "ar_EG", arabic }, { "ar_IN", arabic }, { "ar_IQ", arabic }, { "ar_JO", arabic }, { "ar_KW", arabic }, { "ar_LB", arabic }, { "ar_LY", arabic }, /* Not Morocco: use layout ma */ { "ar_OM", arabic }, { "ar_QA", arabic }, { "ar_SA", arabic }, { "ar_SD", arabic }, { "ar_SS", arabic }, /* Not Syria: use layout sy */ { "ar_TN", arabic }, { "ar_YE", arabic }, { "ca_ES", "cat_ES" }, /* Catalan */ { "as_ES", "ast_ES" }, /* Asturian */ { "en_CA", "eng_CA" }, /* Canadian English */ { "el_CY", "gr" }, /* Greek in Cyprus */ { "el_GR", "gr" }, /* Greek in Greeze */ { "ig_NG", "igbo_NG" }, /* Igbo in Nigeria */ { "ha_NG", "hausa_NG" } /* Hausa */ } ); ui->listLayout->setFocus(); // Try to preselect a layout, depending on language and locale Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QString lang = gs->value( "localeConf" ).toMap().value( "LANG" ).toString(); cDebug() << "Got locale language" << lang; if ( !lang.isEmpty() ) { // Chop off .codeset and @modifier int index = lang.indexOf( '.' ); if ( index >= 0 ) lang.truncate( index ); index = lang.indexOf( '@' ); if ( index >= 0 ) lang.truncate( index ); lang.replace( '-', '_' ); // Normalize separators } if ( !lang.isEmpty() ) { std::string lang_s = lang.toStdString(); if ( specialCaseMap.contains( lang_s ) ) { QString newLang = QString::fromStdString( specialCaseMap.value( lang_s ) ); cDebug() << " .. special case language" << lang << "becomes" << newLang; lang = newLang; } } if ( !lang.isEmpty() ) { const auto langParts = lang.split( '_', QString::SkipEmptyParts ); // Note that this his string is not fit for display purposes! // It doesn't come from QLocale::nativeCountryName. QString country = QLocale::countryToString( QLocale( lang ).country() ); cDebug() << " .. extracted country" << country << "::" << langParts; guessLayout( langParts ); } }
void doAutopartition( PartitionCoreModule* core, Device* dev, const QString& luksPassphrase ) { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); bool isEfi = false; if ( QDir( "/sys/firmware/efi/efivars" ).exists() ) isEfi = true; QString defaultFsType = gs->value( "defaultFileSystemType" ).toString(); if ( FileSystem::typeForName( defaultFsType ) == FileSystem::Unknown ) defaultFsType = "ext4"; // Partition sizes are expressed in MiB, should be multiples of // the logical sector size (usually 512B). int uefisys_part_size = 0; int empty_space_size = 0; if ( isEfi ) { uefisys_part_size = 300; empty_space_size = 2; } else { // we start with a 1MiB offset before the first partition empty_space_size = 1; } qint64 firstFreeSector = toMiB(empty_space_size) / dev->logicalSize() + 1; if ( isEfi ) { qint64 lastSector = firstFreeSector + ( toMiB(uefisys_part_size) / dev->logicalSize() ); core->createPartitionTable( dev, PartitionTable::gpt ); Partition* efiPartition = KPMHelpers::createNewPartition( dev->partitionTable(), *dev, PartitionRole( PartitionRole::Primary ), FileSystem::Fat32, firstFreeSector, lastSector, PartitionTable::FlagEsp ); PartitionInfo::setFormat( efiPartition, true ); PartitionInfo::setMountPoint( efiPartition, gs->value( "efiSystemPartition" ) .toString() ); core->createPartition( dev, efiPartition, PartitionTable::FlagEsp | PartitionTable::FlagBoot ); firstFreeSector = lastSector + 1; } else { core->createPartitionTable( dev, PartitionTable::msdos ); } const bool mayCreateSwap = !gs->value( "neverCreateSwap" ).toBool(); bool shouldCreateSwap = false; qint64 suggestedSwapSizeB = 0; if ( mayCreateSwap ) { qint64 availableSpaceB = ( dev->totalLogical() - firstFreeSector ) * dev->logicalSize(); suggestedSwapSizeB = swapSuggestion( availableSpaceB ); qint64 requiredSpaceB = toGiB( gs->value( "requiredStorageGB" ).toDouble() + 0.1 + 2.0 ) + suggestedSwapSizeB; // If there is enough room for ESP + root + swap, create swap, otherwise don't. shouldCreateSwap = availableSpaceB > requiredSpaceB; } qint64 lastSectorForRoot = dev->totalLogical() - 1; //last sector of the device if ( shouldCreateSwap ) { lastSectorForRoot -= suggestedSwapSizeB / dev->logicalSize() + 1; } Partition* rootPartition = nullptr; if ( luksPassphrase.isEmpty() ) { rootPartition = KPMHelpers::createNewPartition( dev->partitionTable(), *dev, PartitionRole( PartitionRole::Primary ), FileSystem::typeForName( defaultFsType ), firstFreeSector, lastSectorForRoot ); } else { rootPartition = KPMHelpers::createNewEncryptedPartition( dev->partitionTable(), *dev, PartitionRole( PartitionRole::Primary ), FileSystem::typeForName( defaultFsType ), firstFreeSector, lastSectorForRoot, luksPassphrase ); } PartitionInfo::setFormat( rootPartition, true ); PartitionInfo::setMountPoint( rootPartition, "/" ); core->createPartition( dev, rootPartition ); if ( shouldCreateSwap ) { Partition* swapPartition = nullptr; if ( luksPassphrase.isEmpty() ) { swapPartition = KPMHelpers::createNewPartition( dev->partitionTable(), *dev, PartitionRole( PartitionRole::Primary ), FileSystem::LinuxSwap, lastSectorForRoot + 1, dev->totalLogical() - 1 ); } else { swapPartition = KPMHelpers::createNewEncryptedPartition( dev->partitionTable(), *dev, PartitionRole( PartitionRole::Primary ), FileSystem::LinuxSwap, lastSectorForRoot + 1, dev->totalLogical() - 1, luksPassphrase ); } PartitionInfo::setFormat( swapPartition, true ); core->createPartition( dev, swapPartition ); } core->dumpQueue(); }