Esempio n. 1
0
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();
}
Esempio n. 2
0
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();
}
Esempio n. 3
0
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();
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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( "/" );
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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();
}
Esempio n. 9
0
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();
}
Esempio n. 10
0
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 );
    }
}
Esempio n. 11
0
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();
}