Skip to content

Commit 1ec31a6

Browse files
committed
fix bokren pkgmgr-policy, match cru functionality
1 parent 386cee7 commit 1ec31a6

1 file changed

Lines changed: 76 additions & 78 deletions

File tree

src/lib/UpdateManager.cpp

Lines changed: 76 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -218,26 +218,24 @@ bool UpdateManager::applyUpdate() {
218218
}
219219
lockFile.close();
220220

221-
// HOST SIDE: Check disk space on the host before entering the chroot,
222-
// so QStorageInfo can read the available space on mounted partitions.
221+
// Check disk space on the host before entering the chroot.
223222
Q_EMIT updateProgress(5, "Checking disk space");
224223
if (!checkDiskSpace()) {
225224
Logger::instance().error("Insufficient disk space for update");
226225
QFile::remove(lockPath);
227226
return false;
228227
}
229228

230-
// CHROOT SIDE: Everything from here runs inside overlayroot-chroot,
231-
// writing to the persistent lower layer — matching the original nuts-cru
232-
// architecture where the entire update executes inside the chroot.
229+
// Everything from here runs inside overlayroot-chroot.
233230

234-
// Step 1: Mount devtmpfs inside the chroot (required for device nodes
235-
// that dpkg maintainer scripts and initramfs-tools depend on).
231+
// Step 1: Prepare chroot environment.
236232
Q_EMIT updateProgress(8, "Preparing chroot environment");
237233
{
238234
QString output, error;
239235
m_sysInterface->executeInOverlay({"/usr/bin/mount", "-t", "devtmpfs", "dev", "/dev"}, output, error);
240236
// Non-fatal: may already be mounted; proceed regardless.
237+
m_sysInterface->executeInOverlay({"/usr/bin/mkdir", "-p", "/tmp"}, output, error);
238+
m_sysInterface->executeInOverlay({"/usr/bin/chmod", "1777", "/tmp"}, output, error);
241239
}
242240

243241
Q_EMIT updateProgress(10, "Mounting partitions");
@@ -289,6 +287,29 @@ bool UpdateManager::applyUpdate() {
289287
return false;
290288
}
291289

290+
// Create nx-pkgmgr-policy symlinks.
291+
{
292+
QString output, error;
293+
QStringList aptTools = {"apt", "apt-cache", "apt-cdrom", "apt-config", "apt-get", "apt-mark"};
294+
for (const QString& tool : aptTools)
295+
m_sysInterface->executeInOverlay({"/usr/bin/ln", "-sf", "/usr/bin/nx-pkgmgr-policy", "/usr/bin/" + tool}, output, error);
296+
297+
QStringList dpkgTools = {
298+
"dpkg", "dpkg-deb", "dpkg-divert", "dpkg-maintscript-helper", "dpkg-query",
299+
"dpkg-realpath", "dpkg-split", "dpkg-statoverride", "dpkg-trigger",
300+
"dpkg-architecture", "dpkg-buildapi", "dpkg-buildflags", "dpkg-buildpackage",
301+
"dpkg-buildtree", "dpkg-checkbuilddeps", "dpkg-distaddfile",
302+
"dpkg-genbuildinfo", "dpkg-genchanges", "dpkg-gencontrol", "dpkg-gensymbols",
303+
"dpkg-mergechangelogs", "dpkg-name", "dpkg-parsechangelog",
304+
"dpkg-scanpackages", "dpkg-scansources", "dpkg-shlibdeps", "dpkg-source", "dpkg-vendor"
305+
};
306+
for (const QString& tool : dpkgTools)
307+
m_sysInterface->executeInOverlay({"/usr/bin/ln", "-sf", "/usr/bin/nx-pkgmgr-policy", "/usr/bin/" + tool}, output, error);
308+
309+
// Flush all pending writes to disk before exiting the chroot.
310+
m_sysInterface->executeInOverlay({"/usr/bin/sync"}, output, error);
311+
}
312+
292313
cleanup();
293314
QFile::remove(lockPath);
294315

@@ -302,10 +323,7 @@ bool UpdateManager::applyUpdate() {
302323
// ----------------------
303324

304325
bool UpdateManager::prepareSystemPartitions() {
305-
// All mount operations run inside the chroot (lower layer), matching
306-
// the original nuts-cru behaviour. findfs, mount, and mkdir are invoked
307-
// via executeInOverlay so the mounts are visible inside the chroot context
308-
// where all subsequent work happens.
326+
// All mount operations run inside the chroot (lower layer).
309327
QString output, error;
310328

311329
// Resolve and mount NX_HOME → /home
@@ -336,9 +354,7 @@ bool UpdateManager::prepareSystemPartitions() {
336354
}
337355

338356
bool UpdateManager::downloadOTAPayload() {
339-
// Runs inside the chroot (lower layer), matching the original nuts-cru behaviour.
340-
// axel -n 10 opens 10 parallel connections, bypassing SourceForge CDN per-connection
341-
// throttling. Each mirror is tried in sequence; the first to pass checksum wins.
357+
// Runs inside the chroot (lower layer).
342358
QString otaPath = Config::instance().downloadDir() + "/nuts-ota.squashfs";
343359
QString output, error;
344360

@@ -409,9 +425,9 @@ bool UpdateManager::mountOTAPayload() {
409425
}
410426

411427
bool UpdateManager::prepareUpdateTools() {
412-
QString workDir = Config::instance().workDir();
413-
QString appImagePath = workDir + "/dpkg-tooling.AppImage";
414-
QString extractDir = workDir + "/pkgman-extracted";
428+
// Use /tmp inside the chroot.
429+
QString appImagePath = "/tmp/dpkg-1.22.21-x86_64.AppImage";
430+
QString extractDir = "/tmp/pkgman-extracted";
415431
QString appRunPath = extractDir + "/squashfs-root/AppRun";
416432

417433
QString appImageUrl = "https://raw.githubusercontent.com/Nitrux/storage/master/Other/AppImages/dpkg-1.22.21-x86_64.AppImage";
@@ -457,8 +473,9 @@ bool UpdateManager::prepareUpdateTools() {
457473

458474
m_pkgManagerPath = appRunPath;
459475

460-
// Symlink tools into the lower layer.
461-
QStringList tools = {"dpkg", "dpkg-deb", "dpkg-divert", "dpkg-query",
476+
m_sysInterface->executeInOverlay({"/usr/bin/ln", "-svf", appRunPath, "/usr/bin/dpkg"}, output, error);
477+
478+
QStringList tools = {"dpkg-deb", "dpkg-divert", "dpkg-query",
462479
"dpkg-realpath", "dpkg-split", "dpkg-statoverride",
463480
"dpkg-trigger", "dpkg-maintscript-helper", "update-alternatives"};
464481

@@ -481,19 +498,21 @@ bool UpdateManager::prepareUpdateTools() {
481498

482499
bool UpdateManager::syncPackageData() {
483500
QString url = QString("https://raw.githubusercontent.com/Nitrux/storage/master/Other/var-lib-dpkg-%1.tar.xz").arg(m_minTarget);
484-
QString tarPath = Config::instance().workDir() + "/var-lib-dpkg.tar.xz";
501+
QString tarPath = QString("/tmp/var-lib-dpkg-%1.tar.xz").arg(m_minTarget);
485502
QString expectedChecksum = m_queryData.value("VAR_LIB_SUM");
486503
QString output, error;
487504

488-
// Download inside chroot using axel
505+
// Remove any stale file first
506+
m_sysInterface->executeInOverlay({"/usr/bin/rm", "-f", tarPath}, output, error);
507+
489508
Logger::instance().info("Downloading package database archive...");
490509
if (!m_sysInterface->executeInOverlay(
491510
{"/usr/bin/axel", "-n", "10", "-o", tarPath, url}, output, error)) {
492511
Logger::instance().error("Failed to download package database: " + error);
493512
return false;
494513
}
495514

496-
// Verify checksum inside chroot before extraction
515+
// Verify checksum inside chroot before extraction.
497516
// Extracting an unverified archive to / is extremely dangerous (zip slip / overwrite attacks).
498517
Logger::instance().info("Verifying package database archive...");
499518
QString checksumCmd = QString("echo '%1 %2' | /usr/bin/sha256sum -c -")
@@ -504,12 +523,20 @@ bool UpdateManager::syncPackageData() {
504523
return false;
505524
}
506525

507-
// Extract into the lower layer via overlayroot-chroot.
508-
if (!m_sysInterface->executeInOverlay({"/usr/bin/tar", "-xf", tarPath, "-C", "/"}, output, error)) {
526+
// Extract into the lower layer — original uses: cd / && tar -xf $TARFILE
527+
if (!m_sysInterface->executeInOverlay(
528+
{"/bin/sh", "-c", "mkdir -p /var/lib/dpkg && cd / && /usr/bin/tar -xf " + tarPath},
529+
output, error)) {
509530
Logger::instance().error("Failed to extract package database: " + error);
510531
return false;
511532
}
512533

534+
// Confirm extraction succeeded.
535+
if (!m_sysInterface->executeInOverlay({"/usr/bin/test", "-f", "/var/lib/dpkg/status"}, output, error)) {
536+
Logger::instance().error("Package database extraction failed: /var/lib/dpkg/status not found");
537+
return false;
538+
}
539+
513540
return true;
514541
}
515542

@@ -518,59 +545,38 @@ bool UpdateManager::performPackageUpdates() {
518545
QString updatesDir = otaDir + "/updates";
519546
QString nvidiaDir = otaDir + "/nvidia";
520547

521-
// Collect deb file list from inside the chroot — squashfsDir is mounted there
522-
QString output, error;
523-
m_sysInterface->executeInOverlay(
524-
{"/usr/bin/find", updatesDir, "-name", "*.deb", "-type", "f"}, output, error);
525-
QStringList debFiles = output.split('\n', Qt::SkipEmptyParts);
526-
548+
// Detect NVIDIA on the host via /proc (shared with chroot).
527549
bool isNvidia = QDir("/proc/driver/nvidia").exists();
528550
if (!isNvidia) {
551+
QString output, error;
529552
m_sysInterface->executeCommand("/usr/bin/lspci", {}, output, error);
530553
if (output.contains("NVIDIA", Qt::CaseInsensitive)) isNvidia = true;
531554
}
555+
if (isNvidia)
556+
Logger::instance().info("NVIDIA hardware detected. Including NVIDIA drivers.");
532557

533-
if (isNvidia) {
534-
QString nvidiaOutput, nvidiaError;
535-
m_sysInterface->executeInOverlay(
536-
{"/usr/bin/find", nvidiaDir, "-name", "*.deb", "-type", "f"}, nvidiaOutput, nvidiaError);
537-
QStringList nvidiaDebs = nvidiaOutput.split('\n', Qt::SkipEmptyParts);
538-
if (!nvidiaDebs.isEmpty()) {
539-
Logger::instance().info("NVIDIA hardware detected. Including NVIDIA drivers.");
540-
debFiles << nvidiaDebs;
541-
}
542-
}
543-
544-
if (debFiles.isEmpty()) {
545-
Logger::instance().warning("No packages found to update.");
546-
return true;
547-
}
548-
549-
// Phase 1: Unpack
550-
// All dpkg operations run inside overlayroot-chroot so they write to the
551-
// lower (persistent) layer, not the upper (ephemeral) overlay layer.
552-
const int BATCH_SIZE = 50;
553-
Logger::instance().info(QString("Unpacking %1 packages in batches...").arg(debFiles.size()));
554-
555-
for (int i = 0; i < debFiles.size(); i += BATCH_SIZE) {
556-
QStringList batch = debFiles.mid(i, BATCH_SIZE);
557-
Logger::instance().info(QString("Unpacking batch %1 of %2...").arg((i/BATCH_SIZE)+1).arg((debFiles.size()+BATCH_SIZE-1)/BATCH_SIZE));
558+
// Phase 1: Unpack.
559+
Logger::instance().info("Phase 1: Unpacking OTA content...");
560+
{
561+
QString searchPaths = updatesDir;
562+
if (isNvidia)
563+
searchPaths += " " + nvidiaDir;
558564

559-
QStringList args;
560-
args << "/usr/bin/env"
561-
<< "DEBIAN_FRONTEND=noninteractive"
562-
<< "TMPDIR=" + Config::instance().workDir()
563-
<< m_pkgManagerPath << "--force-all" << "--unpack";
564-
args << batch;
565+
QString unpackCmd = QString(
566+
"export DEBIAN_FRONTEND=noninteractive && "
567+
"export TMPDIR=/tmp && "
568+
"find %1 -name '*.deb' -print0 | "
569+
"xargs -0 -n 120 %2 --force-all --unpack"
570+
).arg(searchPaths, m_pkgManagerPath);
565571

566572
QString output, error;
567-
if (!m_sysInterface->executeInOverlay(args, output, error)) {
568-
Logger::instance().error("Failed to unpack batch: " + error);
573+
if (!m_sysInterface->executeInOverlay({"/bin/sh", "-c", unpackCmd}, output, error)) {
574+
Logger::instance().error("Failed to unpack OTA content: " + error);
569575
return false;
570576
}
571577
}
572578

573-
// Phase 2: Configure loop
579+
// Phase 2: Configure loop audit reports clean.
574580
Logger::instance().info("Configuring packages...");
575581
int maxPasses = 15;
576582
int pass = 1;
@@ -581,10 +587,9 @@ bool UpdateManager::performPackageUpdates() {
581587

582588
QString output, error;
583589
QStringList confArgs;
584-
confArgs << "/usr/bin/env"
585-
<< "DEBIAN_FRONTEND=noninteractive"
586-
<< "TMPDIR=" + Config::instance().workDir()
587-
<< m_pkgManagerPath << "--force-all" << "--configure" << "-a";
590+
confArgs << "/bin/sh" << "-c"
591+
<< QString("export DEBIAN_FRONTEND=noninteractive && export TMPDIR=/tmp && "
592+
"%1 --force-all --configure -a").arg(m_pkgManagerPath);
588593
m_sysInterface->executeInOverlay(confArgs, output, error);
589594

590595
QStringList auditArgs;
@@ -594,6 +599,7 @@ bool UpdateManager::performPackageUpdates() {
594599

595600
if (currentAudit.isEmpty()) {
596601
Logger::instance().success("Package configuration converged.");
602+
m_sysInterface->executeInOverlay({"/usr/bin/rm", "-rf", "/tmp/pkgman-extracted"}, output, error);
597603
return true;
598604
}
599605

@@ -614,7 +620,7 @@ bool UpdateManager::performPackageUpdates() {
614620

615621
bool UpdateManager::runCleanupCrew() {
616622
QString ccuChecksum = m_queryData.value("NUTS_CCU_CHECKSUM");
617-
QString ccuPath = Config::instance().workDir() + "/nuts-cpp-ccu";
623+
QString ccuPath = "/tmp/nuts-cpp-ccu";
618624
QString output, error;
619625

620626
// Build the component URL from internal config
@@ -651,19 +657,11 @@ bool UpdateManager::runCleanupCrew() {
651657
void UpdateManager::cleanup() {
652658
QString output, error;
653659

654-
// Unmount inside chroot — mounts were created inside the chroot
660+
// Unmount inside chroot — mounts were created inside the chroot.
655661
m_sysInterface->executeInOverlay({"/usr/bin/umount", Config::instance().squashfsDir()}, output, error);
656662
m_sysInterface->executeInOverlay({"/usr/bin/umount", "/home"}, output, error);
657663
m_sysInterface->executeInOverlay({"/usr/bin/umount", "/var/lib"}, output, error);
658664
m_sysInterface->executeInOverlay({"/usr/bin/umount", "/dev"}, output, error);
659-
660-
// Remove dpkg symlinks inside chroot
661-
QStringList tools = {"dpkg", "dpkg-deb", "dpkg-query", "update-alternatives",
662-
"dpkg-divert", "dpkg-realpath", "dpkg-split",
663-
"dpkg-statoverride", "dpkg-trigger", "dpkg-maintscript-helper"};
664-
for (const QString& tool : tools) {
665-
m_sysInterface->executeInOverlay({"/usr/bin/rm", "-f", "/usr/bin/" + tool}, output, error);
666-
}
667665
}
668666

669667

0 commit comments

Comments
 (0)