/* On USB root drives we create a dummy recovery and settings partition. * Just in case the user wants to start booting from HDD later */ bool InitDriveThread::formatUsbDrive() { zeroMbr(); partitionDrive(); setDiskId(); formatBootPartition(); formatSettingsPartition(); return true; }
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; }
void DriveFormatThread::run() { if (_reformatBoot) { emit statusUpdate(tr("Saving boot files to memory")); if (!_i->saveBootFiles() ) { emit error(tr("Error saving boot files to memory. Not enough memory to save all files currently on SD card?")); return; } _i->umountSystemPartition(); } emit statusUpdate(tr("Zeroing partition table")); if (!zeroMbr()) { emit error(tr("Error zero'ing MBR")); return; } emit statusUpdate(tr("Creating partitions")); if (!partitionDrive()) { emit error(tr("Error partitioning")); return; } if (_reformatBoot) { /* A10 devices need to have u-boot written to the spare space before the first partition */ if (QFile::exists("/tmp/boot/u-boot.bin") && QFile::exists("/tmp/boot/sunxi-spl.bin")) { emit statusUpdate(tr("Installing u-boot SPL")); if (!installUbootSPL()) { emit error(tr("Error writing u-boot to disk")); return; } } emit statusUpdate(tr("Formatting boot partition (fat)")); if (!formatBootPartition()) { emit error(tr("Error formatting boot partition (vfat)")); return; } emit statusUpdate(tr("Copying boot files to storage")); _i->mountSystemPartition(); _i->restoreBootFiles(); emit statusUpdate(tr("Finish writing boot files to disk (sync)")); sync(); } emit statusUpdate(tr("Formatting data partition (%1)").arg(_fs)); if (!formatDataPartition()) { emit error(tr("Error Formatting data partition (%1)").arg(_fs)); return; } emit statusUpdate(tr("Mounting and initializing data partition")); _i->initializeDataPartition(_datadev); emit statusUpdate(tr("Editing cmdline.txt")); /* Data dev setting */ QFile f("/boot/cmdline.txt"); f.open(QIODevice::ReadWrite); QByteArray line = f.readAll().trimmed(); if (_fs == "btrfs") line += " fstype=btrfs"; if (_iscsi) line += " datadev=iscsi"; else line += " datadev="+_datadev; f.seek(0); f.write(line.trimmed()); f.close(); /* Data dev setting in uEnv.txt (for A10 devices) */ f.setFileName("/boot/uEnv.txt"); f.open(QIODevice::ReadWrite); line = f.readAll().trimmed(); if (_fs == "btrfs") line += " fstype=btrfs"; if (_iscsi) line += " datadev=iscsi"; else line += " datadev="+_datadev; f.seek(0); f.write(line.trimmed()); f.close(); /* Overscan setting */ bool configchanged = false; f.setFileName("/boot/config.txt"); f.open(QIODevice::ReadOnly); QByteArray configdata = f.readAll(); f.close(); bool overscanCurrentlyDisabled = configdata.contains("disable_overscan=1"); if (_i->disableOverscan() && !overscanCurrentlyDisabled) { configdata += "\ndisable_overscan=1"; configchanged = true; } else if (!_i->disableOverscan() && overscanCurrentlyDisabled) { configdata.replace("disable_overscan=1", ""); configchanged = true; } if (configchanged) { f.open(QIODevice::WriteOnly); f.write(configdata.trimmed()); f.close(); } /* Finished */ emit statusUpdate(tr("Unmounting boot partition")); _i->umountSystemPartition(); emit statusUpdate(tr("Finish writing to disk (sync)")); sync(); emit completed(); }
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; }
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; }