Exemplo n.º 1
0
bool InitDriveThread::method_reformatDrive()
{
    emit statusUpdate(tr("Saving boot files to memory"));
    if (!saveBootFiles() )
    {
        emit error(tr("Error saving boot files to memory. SD card may be damaged."));
        return false;
    }
    if (!umountSystemPartition())
    {
        emit error(tr("Error unmounting system partition."));
        return false;
    }

    emit statusUpdate(tr("Zeroing partition table"));
    if (!zeroMbr())
    {
        emit error(tr("Error zero'ing MBR/GPT. SD card may be broken or advertising wrong capacity."));
        return false;
    }

    emit statusUpdate(tr("Creating partitions"));

    if (!partitionDrive())
    {
        emit error(tr("Error partitioning"));
        return false;
    }

    emit statusUpdate(tr("Formatting boot partition (fat)"));
    if (!formatBootPartition())
    {
       emit error(tr("Error formatting boot partition (fat)"));
       return false;
    }

    emit statusUpdate(tr("Copying boot files to storage"));
    mountSystemPartition();
    restoreBootFiles();
    umountSystemPartition();

    return true;
}
Exemplo n.º 2
0
bool InitDriveThread::method_resizePartitions()
{
    uint newStartOfRescuePartition = getFileContents(sysclassblock(_drive, 1)+"/start").trimmed().toUInt();
    uint newSizeOfRescuePartition  = sizeofBootFilesInKB()*1.024/1000 + 100;

    if (!umountSystemPartition())
    {
        emit error(tr("Error unmounting system partition."));
        return false;
    }

    if (!QFile::exists(partdev(_drive, 1)))
    {
        // SD card does not have a MBR.

        // Warn user that their SD card does not have an MBR and ask
        // if they would like us to create one for them
        QMessageBox::StandardButton answer;
        emit query(tr("Would you like NOOBS to create one for you?\nWARNING: This will erase all data on your SD card"),
                   tr("Error: No MBR present on SD Card"),
                   &answer);

        if(answer == QMessageBox::Yes)
        {
            emit statusUpdate(tr("Zeroing partition table"));
            if (!zeroMbr())
            {
                emit error(tr("Error zero'ing MBR/GPT. SD card may be broken or advertising wrong capacity."));
                return false;
            }

            // Create MBR containing single FAT partition
            emit statusUpdate(tr("Writing new MBR"));
            QProcess proc;
            proc.setProcessChannelMode(proc.MergedChannels);
            proc.start("/usr/sbin/parted "+_drive+" --script -- mktable msdos mkpartfs primary fat32 8192s -1");
            proc.waitForFinished(-1);
            if (proc.exitCode() != 0)
            {
                // Warn user if we failed to create an MBR on their card
                emit error(tr("Error creating MBR")+"\n"+proc.readAll());
                return false;
            }
            qDebug() << "Created missing MBR on SD card. parted output:" << proc.readAll();

            // Advise user that their SD card has now been formatted
            // suitably for installing NOOBS and that they will have to
            // re-copy the files before rebooting
            emit error(tr("SD card has now been formatted ready for NOOBS installation. Please re-copy the NOOBS files onto the card and reboot"));
            return false;
        }
        else
        {
            emit error(tr("SD card has not been formatted correctly. Please reformat using the SD Association Formatting Tool and try again."));
            return false;
        }

    }

    emit statusUpdate(tr("Removing partitions 2,3,4"));

    QFile f(_drive);
    f.open(f.ReadWrite);
    // Seek to partition entry 2
    f.seek(462);
    // Zero out partition 2,3,4 to prevent parted complaining about invalid constraints
    f.write(QByteArray(16*3, '\0'));
    f.flush();
    // Tell Linux to re-read the partition table
    ioctl(f.handle(), BLKRRPART);
    f.close();
    QThread::msleep(500);

    emit statusUpdate(tr("Resizing FAT partition"));

    /* Relocating the start of the FAT partition is a write intensive operation
     * only move it when it is not aligned on a MiB boundary already */
    if (newStartOfRescuePartition < 2048 || newStartOfRescuePartition % 2048 != 0)
    {
        newStartOfRescuePartition = PARTITION_ALIGNMENT; /* 4 MiB */
    }

    QString cmd = "/usr/sbin/parted --script "+_drive+" resize 1 "+QString::number(newStartOfRescuePartition)+"s "+QString::number(newSizeOfRescuePartition)+"M";
    qDebug() << "Executing" << cmd;
    QProcess p;
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    /* Suppress parted's big fat warning about its file system manipulation code not being robust.
       It distracts from any real error messages that may follow it. */
    env.insert("PARTED_SUPPRESS_FILE_SYSTEM_MANIPULATION_WARNING", "1");
    p.setProcessEnvironment(env);
    p.setProcessChannelMode(p.MergedChannels);
    p.start(cmd);
    p.closeWriteChannel();
    p.waitForFinished(-1);

    if (p.exitCode() != 0)
    {
        emit error(tr("Error resizing existing FAT partition")+"\n"+p.readAll());
        return false;
    }
    qDebug() << "parted done, output:" << p.readAll();
    QThread::msleep(500);

    emit statusUpdate(tr("Creating extended partition"));

    QByteArray partitionTable;
    uint startOfOurPartition = getFileContents(sysclassblock(_drive, 1)+"/start").trimmed().toUInt();
    uint sizeOfOurPartition  = getFileContents(sysclassblock(_drive, 1)+"/size").trimmed().toUInt();
    uint startOfExtended = startOfOurPartition+sizeOfOurPartition;

    // Align start of settings partition on 4 MiB boundary
    uint startOfSettings = startOfExtended + PARTITION_GAP;
    if (startOfSettings % PARTITION_ALIGNMENT != 0)
         startOfSettings += PARTITION_ALIGNMENT-(startOfSettings % PARTITION_ALIGNMENT);

    // Primary partitions
    partitionTable  = QByteArray::number(startOfOurPartition)+","+QByteArray::number(sizeOfOurPartition)+",0E\n"; /* FAT partition */
    partitionTable += QByteArray::number(startOfExtended)+",,E\n"; /* Extended partition with all remaining space */
    partitionTable += "0,0\n";
    partitionTable += "0,0\n";
    // Logical partitions
    partitionTable += QByteArray::number(startOfSettings)+","+QByteArray::number(SETTINGS_PARTITION_SIZE)+",L\n"; /* Settings partition */
    qDebug() << "Writing partition table" << partitionTable;

    /* Let sfdisk write a proper partition table */
    cmd = QString("/sbin/sfdisk -uS --force "+_drive);
    QProcess proc;
    proc.setProcessChannelMode(proc.MergedChannels);
    proc.start(cmd);
    proc.write(partitionTable);
    proc.closeWriteChannel();
    proc.waitForFinished(-1);
    if (proc.exitCode() != 0)
    {
        emit error(tr("Error creating extended partition")+"\n"+proc.readAll());
        return false;
    }
    qDebug() << "sfdisk done, output:" << proc.readAll();
    QThread::msleep(500);

    QProcess::execute("/sbin/mlabel -i "+partdev(_drive, 1)+" ::RECOVERY");

    return true;
}
Exemplo n.º 3
0
void InitDriveThread::run()
{
    QDir dir;

    emit statusUpdate("Waiting for SD card to be ready");
    while (!QFile::exists(_drive))
    {
        QThread::usleep(100);
    }

    emit statusUpdate(tr("Mounting FAT partition"));
    mountSystemPartition();

    if (sizeofBootFilesInKB() > (MAXIMUM_BOOTFILES_SIZE*1024))
    {
        // Try to resize existing partitions
        if (!method_resizePartitions())
        {
            return;
        }
    }
    else
    {
        // Reformat the drive
        if (!method_reformatDrive())
        {
            return;
        }
    }

    /* Make sure we have a disk volume ID,
       or refering partition by PARTUUID later will not work */
    setDiskId();

    emit statusUpdate(tr("Formatting settings partition"));
    if (!formatSettingsPartition())
    {
        emit error(tr("Error formatting settings partition"));
        return;
    }

    emit statusUpdate(tr("Mounting FAT partition"));
    if (!mountSystemPartition())
    {
        emit error(tr("Error mounting system partition."));
        return;
    }

    dir.mkdir("/mnt/os");
    emit statusUpdate(tr("Editing cmdline.txt"));

    QString cmdlinefilename = "/mnt/recovery.cmdline";
    if (!QFile::exists(cmdlinefilename))
        cmdlinefilename = "/mnt/cmdline.txt";

    /* Remove "runinstaller" from cmdline.txt */
    QFile f(cmdlinefilename);
    if (!f.open(f.ReadOnly))
    {
        emit error(tr("Error opening %1").arg(cmdlinefilename));
        return;
    }
    QByteArray line = f.readAll().trimmed();
    line = line.replace("runinstaller", "").trimmed();
    f.close();
    f.open(f.WriteOnly);
    f.write(line);
    f.close();

#ifdef RISCOS_BLOB_FILENAME
    if (QFile::exists(RISCOS_BLOB_FILENAME))
    {
        emit statusUpdate(tr("Writing RiscOS blob"));
        if (!writeRiscOSblob())
        {
            emit error(tr("Error writing RiscOS blob"));
            return;
        }
    }
#endif

    /* Finish writing */
    emit statusUpdate(tr("Unmounting boot partition"));
    umountSystemPartition();

    emit statusUpdate(tr("Finish writing to disk (sync)"));
    sync();

    /* Perform a quick test to verify our changes were written
     * Drop page cache to make sure we are reading from card, and not from cache */
    QFile dc("/proc/sys/vm/drop_caches");
    dc.open(f.WriteOnly);
    dc.write("3\n");
    dc.close();

    emit statusUpdate(tr("Mounting boot partition again"));
    mountSystemPartition();

    /* Verify that cmdline.txt was written correctly */
    f.open(f.ReadOnly);
    QByteArray cmdlineread = f.readAll();
    f.close();
    umountSystemPartition();

    if (cmdlineread != line)
    {
        emit error(tr("SD card broken (writes do not persist)"));
        return;
    }

    emit completed();
}
Exemplo n.º 4
0
bool InitDriveThread::method_resizePartitions()
{
    int newStartOfRescuePartition = getFileContents("/sys/class/block/mmcblk0p1/start").trimmed().toInt();
    int newSizeOfRescuePartition  = sizeofBootFilesInKB()/1000 + 100;

    if (!umountSystemPartition())
    {
        emit error(tr("Error unmounting system partition."));
        return false;
    }

    if (!QFile::exists("/dev/mmcblk0p1"))
    {
        // SD card does not have a MBR.

        // Warn user that their SD card does not have an MBR and ask
        // if they would like us to create one for them
        QMessageBox::StandardButton answer;
        emit query(tr("Would you like NOOBS to create one for you?\nWARNING: This will erase all data on your SD card"),
                   tr("Error: No MBR present on SD Card"),
                   &answer);

        if(answer == QMessageBox::Yes)
        {
            emit statusUpdate(tr("Zeroing partition table"));
            if (!zeroMbr())
            {
                emit error(tr("Error zero'ing MBR/GPT. SD card may be broken or advertising wrong capacity."));
                return false;
            }

            // Create MBR containing single FAT partition
            emit statusUpdate(tr("Writing new MBR"));
            QProcess proc;
            proc.setProcessChannelMode(proc.MergedChannels);
            proc.start("/usr/sbin/parted /dev/mmcblk0 --script -- mktable msdos mkpartfs primary fat32 8192s -1");
            proc.waitForFinished(-1);
            if (proc.exitCode() != 0)
            {
                // Warn user if we failed to create an MBR on their card
                emit error(tr("Error creating MBR")+"\n"+proc.readAll());
                return false;
            }
            qDebug() << "Created missing MBR on SD card. parted output:" << proc.readAll();

            // Advise user that their SD card has now been formatted
            // suitably for installing NOOBS and that they will have to
            // re-copy the files before rebooting
            emit error(tr("SD card has now been formatted ready for NOOBS installation. Please re-copy the NOOBS files onto the card and reboot"));
            return false;
        }
        else
        {
            emit error(tr("SD card has not been formatted correctly. Please reformat using the SD Association Formatting Tool and try again."));
            return false;
        }

    }

    emit statusUpdate(tr("Removing partitions 2,3,4"));

    QFile f("/dev/mmcblk0");
    f.open(f.ReadWrite);
    // Seek to partition entry 2
    f.seek(462);
    // Zero out partition 2,3,4 to prevent parted complaining about invalid constraints
    f.write(QByteArray(16*3, '\0'));
    f.flush();
    // Tell Linux to re-read the partition table
    ioctl(f.handle(), BLKRRPART);
    f.close();
    QThread::msleep(500);

    emit statusUpdate(tr("Resizing FAT partition"));

    /* Relocating the start of the FAT partition is a write intensive operation
     * only move it when it is not aligned on a MiB boundary already */
    if (newStartOfRescuePartition < 2048 || newStartOfRescuePartition % 2048 != 0)
    {
        newStartOfRescuePartition = 8192; /* 4 MiB */
    }

    QString cmd = "/usr/sbin/parted --script /dev/mmcblk0 resize 1 "+QString::number(newStartOfRescuePartition)+"s "+QString::number(newSizeOfRescuePartition)+"M";
    qDebug() << "Executing" << cmd;
    QProcess p;
    p.setProcessChannelMode(p.MergedChannels);
    p.start(cmd);
    p.closeWriteChannel();
    p.waitForFinished(-1);

    if (p.exitCode() != 0)
    {
        emit error(tr("Error resizing existing FAT partition")+"\n"+p.readAll());
        return false;
    }
    qDebug() << "parted done, output:" << p.readAll();
    QThread::msleep(500);

    emit statusUpdate(tr("Creating extended partition"));

    mbr_table extended_mbr;
    QByteArray partitionTable;
    int startOfOurPartition = getFileContents("/sys/class/block/mmcblk0p1/start").trimmed().toInt();
    int sizeOfOurPartition = getFileContents("/sys/class/block/mmcblk0p1/size").trimmed().toInt();
    int startOfExtended = startOfOurPartition + sizeOfOurPartition;
    // Align on 4 MiB boundary
    startOfExtended += 8192-(startOfExtended % 8192);

// BUGBUG - reserve space for WinIOT
    startOfExtended += 5000 * 2048;    
//

    int sizeOfDisk = sizeofSDCardInBlocks();
    int sizeOfExtended = sizeOfDisk - startOfExtended;

    partitionTable  = QByteArray::number(startOfOurPartition)+","+QByteArray::number(sizeOfOurPartition)+",0E\n"; /* FAT partition */
    partitionTable += "0,0\n";
    partitionTable += "0,0\n";
    partitionTable += QByteArray::number(startOfExtended)+","+QByteArray::number(sizeOfExtended)+",X\n"; /* Extended partition with all remaining space */
    qDebug() << "Writing partition table" << partitionTable;

    /* Write out extended partition table with settings logical partition */
    memset(&extended_mbr, 0, sizeof extended_mbr);
    extended_mbr.part[0].starting_sector = EBR_PARTITION_OFFSET;
    extended_mbr.part[0].nr_of_sectors = SETTINGS_PARTITION_SIZE;
    extended_mbr.part[0].id = 0x83;

    extended_mbr.signature[0] = 0x55;
    extended_mbr.signature[1] = 0xAA;
    f.open(f.ReadWrite);
    f.seek(((qint64)startOfExtended)*512L);
    f.write((char *) &extended_mbr, sizeof(extended_mbr));
    f.flush();
    f.close();

    /* Let sfdisk write a proper partition table */
    cmd = QString("/sbin/sfdisk -uS /dev/mmcblk0");
    QProcess proc;
    proc.setProcessChannelMode(proc.MergedChannels);
    proc.start(cmd);
    proc.write(partitionTable);
    proc.closeWriteChannel();
    proc.waitForFinished(-1);
    if (proc.exitCode() != 0)
    {
        emit error(tr("Error creating extended partition")+"\n"+proc.readAll());
        return false;
    }
    qDebug() << "sfdisk done, output:" << proc.readAll();
    QThread::msleep(500);

    /* For reasons unknown Linux sometimes
     * only finds /dev/mmcblk0p2 and /dev/mmcblk0p1 goes missing */
    if (!QFile::exists("/dev/mmcblk0p1"))
    {
        /* Probe again */
        QProcess::execute("/usr/sbin/partprobe");
        QThread::msleep(1500);
    }

    QProcess::execute("/sbin/mlabel p:RECOVERY");

    emit statusUpdate(tr("Mounting FAT partition"));
    if (!mountSystemPartition())
    {
        emit error(tr("Error mounting system partition."));
        return false;
    }

    return true;
}