From 6d2e10fd0bd6b67994b6ed3beccf5a8bc190590d Mon Sep 17 00:00:00 2001 From: James Stringer <38541878+jamesstringer90@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:14:44 -0400 Subject: [PATCH] Fix Ubuntu ISO build dependency version selection --- src/backend_win/asb_core.c | 19 +- tools/iso-patch/iso-patch.c | 10 +- tools/iso-patch/prefetch_build_deps.c | 306 ++++++++++++++++++++------ tools/iso-patch/prefetch_build_deps.h | 3 +- tools/iso-patch/ubuntu_vhdx.c | 6 +- 5 files changed, 263 insertions(+), 81 deletions(-) diff --git a/src/backend_win/asb_core.c b/src/backend_win/asb_core.c index e417aec..8640cae 100644 --- a/src/backend_win/asb_core.c +++ b/src/backend_win/asb_core.c @@ -1971,7 +1971,8 @@ static int generate_vhdx_manifest_ubuntu(const wchar_t *manifest_path, * Output buffers should be at least 64 wchars each. */ static int detect_iso_kernel(const wchar_t *iso_path, wchar_t *codename_out, size_t codename_cap, - wchar_t *kver_out, size_t kver_cap) + wchar_t *kver_out, size_t kver_cap, + HANDLE *iso_out, wchar_t *drive_out) { HANDLE iso_handle = INVALID_HANDLE_VALUE; DWORD cdrom_before, cdrom_after, newly; @@ -1980,6 +1981,8 @@ static int detect_iso_kernel(const wchar_t *iso_path, codename_out[0] = 0; kver_out[0] = 0; + *iso_out = INVALID_HANDLE_VALUE; + *drive_out = 0; /* Snapshot current CD-ROM drive letters before mount. */ cdrom_before = 0; @@ -2128,6 +2131,9 @@ static int detect_iso_kernel(const wchar_t *iso_path, } asb_log(L"detect_iso_kernel: codename=%s kver=%s", codename_out, kver_out); + *iso_out = iso_handle; + *drive_out = iso_drive; + iso_handle = INVALID_HANDLE_VALUE; rc = 0; cleanup: @@ -2383,17 +2389,22 @@ static DWORD WINAPI linux_create_thread(LPVOID param) Needs (codename, kernel) detected from the ISO. */ asb_log(L"Prefetch 2/3: apt build-deps closure..."); wchar_t codename[64] = L"", kver[64] = L""; + HANDLE iso_handle = INVALID_HANDLE_VALUE; + wchar_t iso_drive = 0; if (detect_iso_kernel(args->config.image_path, codename, ARRAYSIZE(codename), - kver, ARRAYSIZE(kver)) == 0) { + kver, ARRAYSIZE(kver), + &iso_handle, &iso_drive) == 0) { wchar_t apt_out[MAX_PATH]; swprintf_s(apt_out, MAX_PATH, L"%s\\local-apt-extras", extras); swprintf_s(args_buf, 2048, L"--prefetch-build-deps --codename \"%s\" --kernel \"%s\" " - L"--out-dir \"%s\"", - codename, kver, apt_out); + L"--out-dir \"%s\" --iso-root \"%c:\"", + codename, kver, apt_out, iso_drive); if (spawn_iso_patch_prefetch(args_buf) != 0) asb_log(L"WARN: prefetch-build-deps failed"); + DetachVirtualDisk(iso_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0); + CloseHandle(iso_handle); } else { asb_log(L"WARN: could not detect ISO kernel — skipping build-deps"); } diff --git a/tools/iso-patch/iso-patch.c b/tools/iso-patch/iso-patch.c index 86d5f4d..a129f6f 100644 --- a/tools/iso-patch/iso-patch.c +++ b/tools/iso-patch/iso-patch.c @@ -2922,7 +2922,7 @@ int wmain(int argc, wchar_t *argv[]) if (_wcsicmp(argv[1], L"--prefetch-build-deps") == 0) { const wchar_t *codename = NULL, *kver = NULL; - const wchar_t *out_dir = NULL, *mirror = NULL; + const wchar_t *out_dir = NULL, *mirror = NULL, *iso_root = NULL; for (int i = 2; i < argc; i++) { if (_wcsicmp(argv[i], L"--codename") == 0 && i + 1 < argc) { codename = argv[++i]; @@ -2932,13 +2932,15 @@ int wmain(int argc, wchar_t *argv[]) out_dir = argv[++i]; } else if (_wcsicmp(argv[i], L"--mirror") == 0 && i + 1 < argc) { mirror = argv[++i]; + } else if (_wcsicmp(argv[i], L"--iso-root") == 0 && i + 1 < argc) { + iso_root = argv[++i]; } } - if (!codename || !kver || !out_dir) { - log_err(L"--prefetch-build-deps requires --codename, --kernel, --out-dir"); + if (!codename || !kver || !out_dir || !iso_root) { + log_err(L"--prefetch-build-deps requires --codename, --kernel, --out-dir, --iso-root"); return 1; } - return do_prefetch_build_deps(codename, kver, out_dir, mirror); + return do_prefetch_build_deps(codename, kver, out_dir, mirror, iso_root); } if (_wcsicmp(argv[1], L"--ubuntu-to-vhdx") == 0) { diff --git a/tools/iso-patch/prefetch_build_deps.c b/tools/iso-patch/prefetch_build_deps.c index a859dfc..dbe9611 100644 --- a/tools/iso-patch/prefetch_build_deps.c +++ b/tools/iso-patch/prefetch_build_deps.c @@ -1,7 +1,8 @@ /* prefetch_build_deps.c - see header for design. * * Pipeline: - * 1. WinHTTP-download Packages.xz for /main/binary- + * 1. WinHTTP-download main/binary-/Packages.xz for the release, + * updates and security pockets. * 2. Decompress it in-process with the vendored xz-embedded decoder * (xz_decompress_file_to_file below; Packages.gz is raw-gzipped * text that tar.exe rejects, so we target the .xz instead). @@ -9,7 +10,7 @@ * Package name. Each stanza is stored verbatim so we can write * it back into the synthetic Packages we ship. * 4. BFS the Depends:/Pre-Depends: closure from seed packages. - * Disjunctions ("a | b"): take the first alternative that exists. + * Match source versions to the ISO; leave dependency resolution to APT. * 5. For each pkg in closure: WinHTTP-download the .deb, verify * its SHA256 against the Packages metadata. * 6. Write synthetic Packages with the closure stanzas, but @@ -27,6 +28,7 @@ #include "prefetch_build_deps.h" #include "iso_patch_log.h" #include "target_arch.h" +#include "engine/squashfs.h" #include "engine/xz/xz.h" #include @@ -378,6 +380,14 @@ cleanup: typedef struct pkg_record { const char *name; /* not null-terminated; use name_len */ size_t name_len; + const char *version; + size_t version_len; + const char *source; + size_t source_len; + const char *source_version; + size_t source_version_len; + const char *status; + size_t status_len; const char *filename; size_t filename_len; const char *sha256_hex; @@ -390,6 +400,7 @@ typedef struct pkg_record { size_t stanza_len; /* length of the stanza (no trailing blank) */ int in_closure; /* set during BFS */ struct pkg_record *bucket_next; + struct pkg_record *source_next; } pkg_record_t; #define PKG_HASH_BUCKETS 4096 /* >> 4500 packages */ @@ -400,6 +411,7 @@ typedef struct { pkg_record_t *records; size_t n_records; pkg_record_t *buckets[PKG_HASH_BUCKETS]; + pkg_record_t *sources[PKG_HASH_BUCKETS]; } pkg_table_t; static size_t hash_name(const char *s, size_t len) @@ -436,6 +448,78 @@ static pkg_record_t *lookup_pkg(pkg_table_t *t, const char *name, size_t len) return NULL; } +static pkg_record_t *lookup_source(pkg_table_t *t, const char *name, size_t len) +{ + for (pkg_record_t *r = t->sources[hash_name(name, len)]; r; r = r->source_next) { + if (name_eq(r->source, r->source_len, name, len)) return r; + } + return NULL; +} + +static int mark_packages(pkg_table_t *t, pkg_table_t *installed, pkg_table_t *iso, + const char *name, size_t len) +{ + if (lookup_pkg(installed, name, len)) return 0; + pkg_record_t *local = lookup_pkg(iso, name, len); + if (local) { + if (local->in_closure) return 0; + local->in_closure = 1; + return 1; + } + int added = 0, matched = 0; + for (pkg_record_t *r = t->buckets[hash_name(name, len)]; r; r = r->bucket_next) { + if (!name_eq(r->name, r->name_len, name, len)) continue; + pkg_record_t *pin = lookup_source(installed, r->source, r->source_len); + if (!pin) pin = lookup_source(iso, r->source, r->source_len); + if (pin && (pin->source_version_len != r->source_version_len || + memcmp(pin->source_version, r->source_version, + r->source_version_len) != 0)) continue; + matched = 1; + if (!r->in_closure) { + r->in_closure = 1; + added++; + } + } + if (!matched && lookup_pkg(t, name, len)) return -1; + return added; +} + +static void index_package(pkg_table_t *t, pkg_record_t *r) +{ + if (r->status && (r->status_len < 13 || + memcmp(r->status + r->status_len - 13, " ok installed", 13) != 0)) return; + r->source_version = r->version; + r->source_version_len = r->version_len; + if (!r->source) { + r->source = r->name; + r->source_len = r->name_len; + } else { + const char *end = r->source + r->source_len; + const char *p = r->source; + while (p < end && *p != ' ' && *p != '(') p++; + r->source_len = (size_t)(p - r->source); + while (p < end && *p != '(') p++; + if (p < end) { + r->source_version = ++p; + while (p < end && *p != ')') p++; + r->source_version_len = (size_t)(p - r->source_version); + } + } + size_t h = hash_name(r->name, r->name_len); + for (pkg_record_t *p = t->buckets[h]; p; p = p->bucket_next) { + if (r->filename && p->filename && r->sha256_hex && p->sha256_hex && + r->filename_len == p->filename_len && r->sha256_len == p->sha256_len && + memcmp(r->filename, p->filename, r->filename_len) == 0 && + memcmp(r->sha256_hex, p->sha256_hex, r->sha256_len) == 0) + return; + } + r->bucket_next = t->buckets[h]; + t->buckets[h] = r; + h = hash_name(r->source, r->source_len); + r->source_next = t->sources[h]; + t->sources[h] = r; +} + /* For a "Key: value" line, return (key, val) views or NULL if not a * "Key:" line. Continuation lines (leading whitespace) are not * handled here — the parser skips them. */ @@ -507,9 +591,7 @@ static int parse_packages(pkg_table_t *t) (cur->stanza_start[cur->stanza_len - 1] == '\n' || cur->stanza_start[cur->stanza_len - 1] == '\r')) cur->stanza_len--; - size_t h = hash_name(cur->name, cur->name_len); - cur->bucket_next = t->buckets[h]; - t->buckets[h] = cur; + index_package(t, cur); ri++; } cur = NULL; @@ -522,6 +604,12 @@ static int parse_packages(pkg_table_t *t) if (cur) { if (kl == 7 && memcmp(k, "Package", 7) == 0) { cur->name = v; cur->name_len = vl; + } else if (kl == 7 && memcmp(k, "Version", 7) == 0) { + cur->version = v; cur->version_len = vl; + } else if (kl == 6 && memcmp(k, "Source", 6) == 0) { + cur->source = v; cur->source_len = vl; + } else if (kl == 6 && memcmp(k, "Status", 6) == 0) { + cur->status = v; cur->status_len = vl; } else if (kl == 8 && memcmp(k, "Filename", 8) == 0) { cur->filename = v; cur->filename_len = vl; } else if (kl == 6 && memcmp(k, "SHA256", 6) == 0) { @@ -542,16 +630,15 @@ static int parse_packages(pkg_table_t *t) if (cur && cur->name && !cur->stanza_start) { cur->stanza_start = stanza_start; cur->stanza_len = (size_t)(end - stanza_start); - size_t h = hash_name(cur->name, cur->name_len); - cur->bucket_next = t->buckets[h]; - t->buckets[h] = cur; + index_package(t, cur); } return 0; } /* BFS one pass: for each pkg already in_closure, walk Depends + Pre-Depends. * Returns count of NEW pkgs added in this pass. */ -static int bfs_add_deps(pkg_table_t *t, pkg_record_t *r, int *added_count) +static int bfs_add_deps(pkg_table_t *t, pkg_table_t *installed, pkg_table_t *iso, + pkg_record_t *r, int *added_count) { const char *fields[2] = { r->depends, r->predepends }; size_t lens[2] = { r->depends_len, r->predepends_len }; @@ -561,28 +648,44 @@ static int bfs_add_deps(pkg_table_t *t, pkg_record_t *r, int *added_count) if (!p || n == 0) continue; const char *q = p; size_t i = 0; + int available = 0; while (i <= n) { - /* Walk to next ',' or end -> one Depends element. */ - if (i == n || p[i] == ',') { - size_t elen = (size_t)(p + i - q); - /* Take first alternative (split on '|'). */ - const char *alt_end = q; - while (alt_end < q + elen && *alt_end != '|') alt_end++; - size_t alen = (size_t)(alt_end - q); + if (i == n || p[i] == ',' || p[i] == '|') { + size_t alen = (size_t)(p + i - q); /* Trim trailing/leading WS. */ while (alen > 0 && (q[0] == ' ' || q[0] == '\t')) { q++; alen--; } while (alen > 0 && (q[alen - 1] == ' ' || q[alen - 1] == '\t' || q[alen - 1] == '\n')) alen--; /* Strip version constraint "(...)" */ const char *paren = q; - while (paren < q + alen && *paren != ' ' && *paren != '(') paren++; + while (paren < q + alen && *paren != ' ' && *paren != '\t' && + *paren != '(' && *paren != ':') paren++; size_t name_len = (size_t)(paren - q); + if (paren < q + alen && *paren == ':') { + const char *arch = paren + 1, *end = arch; + while (end < q + alen && *end != ' ' && *end != '\t' && *end != '(') end++; + size_t arch_len = (size_t)(end - arch); + if (!name_eq(arch, arch_len, "any", 3) && + !name_eq(arch, arch_len, "native", 6) && + !name_eq(arch, arch_len, IP_DEB_ARCH_A, strlen(IP_DEB_ARCH_A))) + name_len = 0; + } if (name_len > 0) { - pkg_record_t *dep = lookup_pkg(t, q, name_len); - if (dep && !dep->in_closure) { - dep->in_closure = 1; - (*added_count)++; + int added = mark_packages(t, installed, iso, q, name_len); + if (added >= 0) { + available = 1; + *added_count += added; } + } else { + available = 1; + } + if (i == n || p[i] == ',') { + if (!available) { + log_err(L"prefetch: no ISO-compatible dependency '%.*hs' for '%.*hs'", + (int)name_len, q, (int)r->name_len, r->name); + return -1; + } + available = 0; } q = p + i + 1; } @@ -683,10 +786,53 @@ static int write_closure_json(pkg_table_t *t, * Main entry point * ==================================================================== */ +static int append_package_file(pkg_table_t *t, const wchar_t *path) +{ + HANDLE h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) return -1; + LARGE_INTEGER sz; + if (!GetFileSizeEx(h, &sz) || sz.QuadPart < 0 || sz.QuadPart > 64 * 1024 * 1024) { + CloseHandle(h); + return -1; + } + char *buf = (char *)realloc(t->buf, t->buf_len + (size_t)sz.QuadPart + 3); + if (!buf) { CloseHandle(h); return -1; } + t->buf = buf; + DWORD br = 0; + BOOL ok = ReadFile(h, buf + t->buf_len, (DWORD)sz.QuadPart, &br, NULL); + CloseHandle(h); + if (!ok || br != sz.QuadPart) return -1; + t->buf_len += br; + t->buf[t->buf_len++] = '\n'; + t->buf[t->buf_len++] = '\n'; + t->buf[t->buf_len] = 0; + return 0; +} + +typedef struct { + sqfs_ctx_t *sq; + pkg_table_t *packages; +} installed_packages_t; + +static int read_installed_packages(const sqfs_entry_t *entry, void *user) +{ + if (strcmp(entry->path, "/var/lib/dpkg/status") != 0) return 0; + installed_packages_t *ctx = (installed_packages_t *)user; + void *data = NULL; + size_t size = 0; + if (sqfs_read_file(ctx->sq, entry, &data, &size) == 0) { + ctx->packages->buf = (char *)data; + ctx->packages->buf_len = size; + } + return 1; +} + int do_prefetch_build_deps(const wchar_t *codename, const wchar_t *kernel_ver, const wchar_t *out_dir, - const wchar_t *mirror_arg) + const wchar_t *mirror_arg, + const wchar_t *iso_root) { const wchar_t *mirror = mirror_arg ? mirror_arg : L"http://archive.ubuntu.com/ubuntu"; @@ -699,57 +845,69 @@ int do_prefetch_build_deps(const wchar_t *codename, u_mkdir_p(out_dir); const wchar_t *staging = out_dir; - /* ---- 1. Download Packages.xz ---- */ + int rc = -1; + pkg_table_t T = { 0 }, installed = { 0 }, iso = { 0 }; wchar_t pkgs_xz[MAX_PATH], pkgs[MAX_PATH]; swprintf_s(pkgs_xz, MAX_PATH, L"%s\\Packages.xz", staging); swprintf_s(pkgs, MAX_PATH, L"%s\\Packages", staging); + wchar_t path[MAX_PATH]; + swprintf_s(path, MAX_PATH, L"%s\\casper\\minimal.squashfs", iso_root); + sqfs_ctx_t *sq = sqfs_open(path); + if (!sq) goto cleanup; + installed_packages_t ctx = { sq, &installed }; + sqfs_walk(sq, read_installed_packages, &ctx); + sqfs_close(sq); + if (!installed.buf || parse_packages(&installed) != 0) goto cleanup; + + swprintf_s(path, MAX_PATH, L"%s\\dists\\%s\\main\\binary-" IP_DEB_ARCH L"\\Packages", + iso_root, codename); + if (append_package_file(&iso, path) != 0 || parse_packages(&iso) != 0) goto cleanup; + + const wchar_t *pockets[] = { L"", L"-updates", L"-security" }; wchar_t url[1024]; - swprintf_s(url, 1024, L"%s/dists/%s/main/binary-" IP_DEB_ARCH L"/Packages.xz", - mirror, codename); - log_msg(L"prefetch: GET %s", url); - if (http_download(url, pkgs_xz) != 0) { - log_err(L"prefetch: download Packages.xz failed"); - return -1; - } - - /* ---- 2. In-process xz decompression via vendored xz-embedded ---- */ - if (xz_decompress_file_to_file(pkgs_xz, pkgs) != 0) { - log_err(L"prefetch: xz decompress failed"); - return -1; - } - - /* ---- 3. Slurp Packages into memory + parse ---- */ - pkg_table_t T = { 0 }; - { - HANDLE h = CreateFileW(pkgs, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { log_err(L"prefetch: open Packages failed"); return -1; } - LARGE_INTEGER sz; GetFileSizeEx(h, &sz); - T.buf_len = (size_t)sz.QuadPart; - T.buf = (char *)malloc(T.buf_len + 1); - if (!T.buf) { CloseHandle(h); return -1; } - DWORD br = 0; - if (!ReadFile(h, T.buf, (DWORD)T.buf_len, &br, NULL) || br != T.buf_len) { - log_err(L"prefetch: read Packages failed"); CloseHandle(h); return -1; + for (size_t i = 0; i < ARRAYSIZE(pockets); i++) { + swprintf_s(url, 1024, L"%s/dists/%s%s/main/binary-" IP_DEB_ARCH L"/Packages.xz", + mirror, codename, pockets[i]); + log_msg(L"prefetch: GET %s", url); + if (http_download(url, pkgs_xz) != 0) { + log_err(L"prefetch: download Packages.xz failed"); + goto cleanup; } - T.buf[T.buf_len] = 0; - CloseHandle(h); + if (xz_decompress_file_to_file(pkgs_xz, pkgs) != 0) { + log_err(L"prefetch: xz decompress failed"); + goto cleanup; + } + if (append_package_file(&T, pkgs) != 0) { + log_err(L"prefetch: read Packages failed"); + goto cleanup; + } + DeleteFileW(pkgs); } - if (parse_packages(&T) != 0) { log_err(L"prefetch: parse failed"); return -1; } + if (parse_packages(&T) != 0) { log_err(L"prefetch: parse failed"); goto cleanup; } log_msg(L"prefetch: parsed %zu package records", T.n_records); /* ---- 4. Mark seeds in_closure ---- */ const char *seeds[] = { "libasound2-dev", "libxcb1-dev", "libxcb-xfixes0-dev", "libdrm-dev", "libsystemd-dev", "pkg-config", + "build-essential", "dkms", "zstd", "openssh-server" /* for ssh_enabled VMs; firstboot installs conditionally */ }; int closure_count = 0; for (size_t i = 0; i < sizeof(seeds) / sizeof(seeds[0]); i++) { - pkg_record_t *r = lookup_pkg(&T, seeds[i], strlen(seeds[i])); - if (!r) { log_msg(L"prefetch: WARN seed '%hs' not in archive", seeds[i]); continue; } - if (!r->in_closure) { r->in_closure = 1; closure_count++; } + int added = mark_packages(&T, &installed, &iso, seeds[i], strlen(seeds[i])); + if (added < 0) { + log_err(L"prefetch: no ISO-compatible package for '%hs'", seeds[i]); + goto cleanup; + } + if (added == 0 && !lookup_pkg(&installed, seeds[i], strlen(seeds[i])) && + !lookup_pkg(&iso, seeds[i], strlen(seeds[i])) && + !lookup_pkg(&T, seeds[i], strlen(seeds[i]))) { + log_msg(L"prefetch: WARN seed '%hs' not in archive", seeds[i]); + continue; + } + closure_count += added; } /* Also linux-headers-. */ { @@ -757,18 +915,24 @@ int do_prefetch_build_deps(const wchar_t *codename, char kver_utf8[64]; WideCharToMultiByte(CP_UTF8, 0, kernel_ver, -1, kver_utf8, sizeof(kver_utf8), NULL, NULL); snprintf(hdr, sizeof(hdr), "linux-headers-%s", kver_utf8); - pkg_record_t *r = lookup_pkg(&T, hdr, strlen(hdr)); - if (r && !r->in_closure) { r->in_closure = 1; closure_count++; } + int added = mark_packages(&T, &installed, &iso, hdr, strlen(hdr)); + if (added < 0) goto cleanup; + closure_count += added; } /* ---- 5. BFS until stable ---- */ int total_added = closure_count; for (int iter = 0; iter < 32; iter++) { int added = 0; + for (size_t i = 0; i < iso.n_records; i++) { + pkg_record_t *r = &iso.records[i]; + if (r->in_closure && bfs_add_deps(&T, &installed, &iso, r, &added) != 0) + goto cleanup; + } for (size_t i = 0; i < T.n_records; i++) { pkg_record_t *r = &T.records[i]; if (!r->in_closure) continue; - bfs_add_deps(&T, r, &added); + if (bfs_add_deps(&T, &installed, &iso, r, &added) != 0) goto cleanup; } if (added == 0) break; total_added += added; @@ -787,7 +951,7 @@ int do_prefetch_build_deps(const wchar_t *codename, if (r->filename_len >= sizeof(fn_utf8)) { log_err(L"prefetch: Filename too long (%zu) for %.*hs", r->filename_len, (int)r->name_len, r->name); - return -1; + goto cleanup; } memcpy(fn_utf8, r->filename, r->filename_len); fn_utf8[r->filename_len] = 0; if (r->sha256_hex && r->sha256_len < sizeof(sha_utf8)) { @@ -806,18 +970,18 @@ int do_prefetch_build_deps(const wchar_t *codename, log_msg(L"prefetch: GET %s", basename); if (http_download(url2, dst) != 0) { log_err(L"prefetch: download %ls failed", basename); - return -1; + goto cleanup; } if (sha_utf8[0]) { char actual[65]; if (sha256_file(dst, actual) != 0) { log_err(L"prefetch: SHA256 hash compute failed for %ls", basename); - return -1; + goto cleanup; } if (_stricmp(actual, sha_utf8) != 0) { log_err(L"prefetch: SHA256 mismatch for %ls (got %hs, want %hs)", basename, actual, sha_utf8); - return -1; + goto cleanup; } } downloaded++; @@ -832,7 +996,7 @@ int do_prefetch_build_deps(const wchar_t *codename, DeleteFileW(synth); if (write_synth_packages(&T, synth) != 0) { log_err(L"prefetch: write synthetic Packages failed"); - return -1; + goto cleanup; } } { @@ -841,12 +1005,16 @@ int do_prefetch_build_deps(const wchar_t *codename, write_closure_json(&T, cj, codename, kernel_ver); } - /* Clean up Packages.xz — we don't ship it (we wrote our own - synthetic Packages with closure entries only). */ + rc = 0; +cleanup: DeleteFileW(pkgs_xz); - + if (rc != 0) DeleteFileW(pkgs); free(T.buf); free(T.records); - log_msg(L"prefetch: OK -> %s", out_dir); - return 0; + free(installed.buf); + free(installed.records); + free(iso.buf); + free(iso.records); + if (rc == 0) log_msg(L"prefetch: OK -> %s", out_dir); + return rc; } diff --git a/tools/iso-patch/prefetch_build_deps.h b/tools/iso-patch/prefetch_build_deps.h index aa6aa56..a03867b 100644 --- a/tools/iso-patch/prefetch_build_deps.h +++ b/tools/iso-patch/prefetch_build_deps.h @@ -35,6 +35,7 @@ int do_prefetch_build_deps(const wchar_t *codename, const wchar_t *kernel_ver, const wchar_t *out_dir, - const wchar_t *mirror); + const wchar_t *mirror, + const wchar_t *iso_root); #endif /* PREFETCH_BUILD_DEPS_H */ diff --git a/tools/iso-patch/ubuntu_vhdx.c b/tools/iso-patch/ubuntu_vhdx.c index 4cd2866..c816a78 100644 --- a/tools/iso-patch/ubuntu_vhdx.c +++ b/tools/iso-patch/ubuntu_vhdx.c @@ -1305,7 +1305,7 @@ static void plant_firstboot_service(ext4_writer_t *ew) "\n" "# All apt operations in firstboot use this APT_OPTS to force\n" "# apt to read ONLY our local sources (no network).\n" - "APT_OPTS=\"-o Dir::Etc::sourcelist=/dev/null -o Dir::Etc::sourceparts=$APT_SOURCES_DIR\"\n" + "APT_OPTS=\"-o Dir::Etc::sourcelist=/dev/null -o Dir::Etc::sourceparts=$APT_SOURCES_DIR -o APT::Install-Recommends=false -o APT::Install-Suggests=false\"\n" "\n" "# Offline apt update.\n" "if apt-get update $APT_OPTS 2>&1 | tail -10; then\n" @@ -1375,7 +1375,7 @@ static void plant_firstboot_service(ext4_writer_t *ew) " # Build, capturing log; pipefail propagates make's rc.\n" " if make -j$(nproc) 2>&1 | tail -20; then\n" " echo \"OK: make\"\n" - " if make install PREFIX=/usr/local 2>&1 | tail -5; then\n" + " if make install PREFIX=/usr/local SYSTEM_UNITS= USER_UNITS= 2>&1 | tail -5; then\n" " echo \"OK: make install\"\n" " else\n" " echo \"FAIL: make install (rc=$?)\"\n" @@ -1482,7 +1482,7 @@ static void plant_firstboot_service(ext4_writer_t *ew) "echo \"==== STEP 13: wsl-mesa ====\"\n" "if [ -f \"$EXTRAS/wsl-mesa.tar.zst\" ]; then\n" " if ! command -v zstd >/dev/null 2>&1; then\n" - " DEBIAN_FRONTEND=noninteractive apt-get install -y zstd 2>&1 | tail -3\n" + " DEBIAN_FRONTEND=noninteractive apt-get install -y $APT_OPTS zstd 2>&1 | tail -3\n" " fi\n" " if command -v zstd >/dev/null 2>&1; then\n" " zstd -d \"$EXTRAS/wsl-mesa.tar.zst\" -c | tar -C / -x \\\n"