diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0622450 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Gitepoch +Gitinfo +Release diff --git a/build-apt-repo.sh b/build-apt-repo.sh new file mode 100755 index 0000000..3328497 --- /dev/null +++ b/build-apt-repo.sh @@ -0,0 +1,244 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +if [ -z "${SOURCE_DATE_EPOCH:-}" ] && [ -f "$SCRIPT_DIR/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$SCRIPT_DIR/Gitepoch") +fi + +REPO_ROOT="$SCRIPT_DIR" +APT_DIR="" +GPG_KEY_ID="xcat@megware.com" +SKIP_SIGN=0 +DRY_RUN=0 + +declare -A CODENAME_MAP=( + [ubuntu22.04]=jammy + [ubuntu24.04]=noble + [ubuntu26.04]=resolute +) +ARCHITECTURES=(amd64 ppc64el) + +usage() { + cat <<'EOF' +Usage: build-apt-repo.sh [options] + +Generate APT repository metadata from pre-built .deb packages. + +Options: + --repo-root PATH xcat-dep repository root (default: script directory) + --apt-dir PATH APT output directory (default: /repos/apt) + --gpg-key-id ID GPG key ID for signing (default: xcat@megware.com) + --skip-sign Skip GPG signing (for testing) + --dry-run Print planned actions without executing + -h, --help Show this help +EOF +} + +die() { echo "ERROR: $*" >&2; exit 1; } + +step() { echo -e "\n== $* =="; } + +run() { + echo "+ $*" + if [[ $DRY_RUN -eq 0 ]]; then + "$@" + fi +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --repo-root) REPO_ROOT="$2"; shift 2 ;; + --apt-dir) APT_DIR="$2"; shift 2 ;; + --gpg-key-id) GPG_KEY_ID="$2"; shift 2 ;; + --skip-sign) SKIP_SIGN=1; shift ;; + --dry-run) DRY_RUN=1; shift ;; + -h|--help) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +REPO_ROOT="$(cd "$REPO_ROOT" && pwd)" +APT_DIR="${APT_DIR:-$REPO_ROOT/repos/apt}" + +step "Validating prerequisites" + +command -v apt-ftparchive >/dev/null 2>&1 \ + || die "apt-ftparchive not found. Install: sudo apt-get install apt-utils" +command -v gpg >/dev/null 2>&1 \ + || die "gpg not found. Install: sudo apt-get install gnupg" + +if [[ $SKIP_SIGN -eq 0 ]]; then + if ! gpg --list-secret-keys "$GPG_KEY_ID" >/dev/null 2>&1; then + die "Secret key '$GPG_KEY_ID' not in GPG keyring. Import it or use --skip-sign." + fi + echo "GPG signing key: $GPG_KEY_ID" +else + echo "GPG signing: skipped" +fi + +for ver in "${!CODENAME_MAP[@]}"; do + src="$APT_DIR/$ver" + [[ -d "$src" ]] || die "Source directory missing: $src" + count=$(find "$src" -maxdepth 1 -name '*.deb' | wc -l) + [[ $count -gt 0 ]] || die "No .deb files in $src" + echo "Found $count debs in $src" +done + +step "Cleaning previous repo metadata" + +if [[ $DRY_RUN -eq 0 ]]; then + rm -rf "$APT_DIR/dists" "$APT_DIR/pool" +fi +echo "Removed dists/ and pool/" + +step "Creating directory structure" + +for ver in "${!CODENAME_MAP[@]}"; do + codename="${CODENAME_MAP[$ver]}" + run mkdir -p "$APT_DIR/pool/main/$codename" + for arch in "${ARCHITECTURES[@]}"; do + run mkdir -p "$APT_DIR/dists/$codename/main/binary-$arch" + done +done + +step "Populating pool" + +for ver in "${!CODENAME_MAP[@]}"; do + codename="${CODENAME_MAP[$ver]}" + src="$APT_DIR/$ver" + dst="$APT_DIR/pool/main/$codename" + echo "$ver -> pool/main/$codename/" + if [[ $DRY_RUN -eq 0 ]]; then + for deb in "$src"/*.deb; do + ln "$deb" "$dst/" 2>/dev/null || cp "$deb" "$dst/" + done + fi +done + +step "Generating Packages indexes" + +for ver in "${!CODENAME_MAP[@]}"; do + codename="${CODENAME_MAP[$ver]}" + echo "Indexing $codename..." + + if [[ $DRY_RUN -eq 1 ]]; then + echo "(dry-run: would generate Packages for $codename)" + continue + fi + + all_packages=$(cd "$APT_DIR" && apt-ftparchive packages "pool/main/$codename/") + + for arch in "${ARCHITECTURES[@]}"; do + pkg_file="$APT_DIR/dists/$codename/main/binary-$arch/Packages" + + echo -n "" > "$pkg_file" + + echo "$all_packages" | awk -v arch="$arch" ' + BEGIN { RS=""; FS="\n"; OFS="\n"; ORS="\n\n" } + { + pkg_arch = "" + for (i = 1; i <= NF; i++) { + if ($i ~ /^Architecture:/) { + split($i, a, ": ") + pkg_arch = a[2] + } + } + if (pkg_arch == arch || pkg_arch == "all") { + print + } + } + ' >> "$pkg_file" + + gzip -9 -k -f -n "$pkg_file" + + pkg_count=$(grep -c '^Package:' "$pkg_file" 2>/dev/null || echo 0) + echo " binary-$arch: $pkg_count packages" + done +done + +step "Generating Release files" + +for ver in "${!CODENAME_MAP[@]}"; do + codename="${CODENAME_MAP[$ver]}" + echo "Release for $codename..." + + if [[ $DRY_RUN -eq 1 ]]; then + echo "(dry-run: would generate Release for $codename)" + continue + fi + + apt-ftparchive \ + -o "APT::FTPArchive::Release::Origin=xCAT" \ + -o "APT::FTPArchive::Release::Label=xcat-dep" \ + -o "APT::FTPArchive::Release::Suite=$codename" \ + -o "APT::FTPArchive::Release::Codename=$codename" \ + -o "APT::FTPArchive::Release::Architectures=amd64 ppc64el" \ + -o "APT::FTPArchive::Release::Components=main" \ + -o "APT::FTPArchive::Release::Description=xCAT dependency packages for $ver" \ + release "$APT_DIR/dists/$codename/" \ + > "$APT_DIR/dists/$codename/Release" + + if [ -n "${SOURCE_DATE_EPOCH:-}" ]; then + deterministic_date=$(date -R -d "@$SOURCE_DATE_EPOCH" --utc) + sed -i "s/^Date: .*/Date: $deterministic_date/" "$APT_DIR/dists/$codename/Release" + fi +done + +if [[ $SKIP_SIGN -eq 0 ]]; then + step "Signing Release files" + + for ver in "${!CODENAME_MAP[@]}"; do + codename="${CODENAME_MAP[$ver]}" + release="$APT_DIR/dists/$codename/Release" + + echo "Signing $codename..." + if [[ $DRY_RUN -eq 0 ]]; then + gpg --default-key "$GPG_KEY_ID" \ + --batch --yes --armor \ + --detach-sign \ + -o "$release.gpg" "$release" + + gpg --default-key "$GPG_KEY_ID" \ + --batch --yes --armor \ + --clearsign \ + -o "$APT_DIR/dists/$codename/InRelease" "$release" + fi + done +fi + +step "Exporting public key" + +key_src="$REPO_ROOT/repomd.xml.key" +key_dst="$APT_DIR/xcat-dep.asc" +if [[ -f "$key_src" ]]; then + run cp "$key_src" "$key_dst" + echo "Public key -> xcat-dep.asc" +else + echo "WARNING: $key_src not found, skipping key export" +fi + +step "Summary" + +echo "" +echo "APT repository generated at: $APT_DIR" +echo "" +echo "Structure:" +if [[ $DRY_RUN -eq 0 ]]; then + find "$APT_DIR/dists" -type f | sort | sed "s|$APT_DIR/||" + echo "" + pool_count=$(find "$APT_DIR/pool" -name '*.deb' | wc -l) + echo "Pool: $pool_count .deb files" +fi +echo "" +echo "Example sources.list entries:" +echo " deb [arch=amd64 signed-by=/etc/apt/keyrings/xcat-dep.asc] http://SERVER/xcat/repos/apt jammy main" +echo " deb [arch=amd64 signed-by=/etc/apt/keyrings/xcat-dep.asc] http://SERVER/xcat/repos/apt noble main" +echo " deb [arch=amd64 signed-by=/etc/apt/keyrings/xcat-dep.asc] http://SERVER/xcat/repos/apt resolute main" +echo "" +echo "Client setup:" +echo " curl -fsSL http://SERVER/xcat/repos/apt/xcat-dep.asc | sudo tee /etc/apt/keyrings/xcat-dep.asc >/dev/null" +echo " echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/xcat-dep.asc] http://SERVER/xcat/repos/apt main' \\" +echo " | sudo tee /etc/apt/sources.list.d/xcat-dep.list" +echo " sudo apt-get update" diff --git a/conserver/debian/patches/fix-true-keyword-gcc15.patch b/conserver/debian/patches/fix-true-keyword-gcc15.patch new file mode 100644 index 0000000..24dc500 --- /dev/null +++ b/conserver/debian/patches/fix-true-keyword-gcc15.patch @@ -0,0 +1,72 @@ +Description: Rename 'true' variable to 'reuse' to fix GCC 15 / C23 build error + In C23 (and GCC 15 defaults), 'true' is a keyword and cannot be used as a + variable name. Rename the setsockopt flag variable from 'true' to 'reuse' + in both group.c and master.c. +Author: Daniel Hilst +--- +diff -ruN a/conserver/group.c b/conserver/group.c +--- a/conserver/group.c ++++ b/conserver/group.c +@@ -5036,7 +5036,7 @@ + struct sockaddr_in lstn_port; + # endif + # if HAVE_SETSOCKOPT +- int true = 1; ++ int reuse = 1; + # endif + unsigned short portInc = 0; + #else +@@ -5063,8 +5063,8 @@ + } + # if HAVE_SETSOCKOPT + if (setsockopt +- (sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, +- sizeof(true)) < 0) { ++ (sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, ++ sizeof(reuse)) < 0) { + Error("Spawn(): setsockopt(%u,SO_REUSEADDR): %s", sfd, + strerror(errno)); + return; +@@ -5195,7 +5195,7 @@ + } + # if HAVE_SETSOCKOPT + if (setsockopt +- (sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, sizeof(true)) < 0) { ++ (sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { + Error("Spawn(): setsockopt(%u,SO_REUSEADDR): %s", sfd, + strerror(errno)); + Bye(EX_OSERR); +diff -ruN a/conserver/master.c b/conserver/master.c +--- a/conserver/master.c ++++ b/conserver/master.c +@@ -687,7 +687,7 @@ + struct sockaddr_in master_port; + # endif + # if HAVE_SETSOCKOPT +- int true = 1; ++ int reuse = 1; + # endif + #else + struct sockaddr_un master_port; +@@ -747,8 +747,8 @@ + + # if HAVE_SETSOCKOPT + if (setsockopt +- (msfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, +- sizeof(true)) < 0) ++ (msfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, ++ sizeof(reuse)) < 0) + goto fail; + # endif + if (!SetFlags(msfd, O_NONBLOCK, 0)) +@@ -818,8 +818,8 @@ + } + # if HAVE_SETSOCKOPT + if (setsockopt +- (msfd, SOL_SOCKET, SO_REUSEADDR, (char *)&true, +- sizeof(true)) < 0) { ++ (msfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, ++ sizeof(reuse)) < 0) { + Error("Master(): setsockopt(%u,SO_REUSEADDR): %s", msfd, + strerror(errno)); + return; diff --git a/conserver/debian/patches/openssl3-dh-opaque.patch b/conserver/debian/patches/openssl3-dh-opaque.patch new file mode 100644 index 0000000..22d8277 --- /dev/null +++ b/conserver/debian/patches/openssl3-dh-opaque.patch @@ -0,0 +1,106 @@ +--- a/conserver/main.c 2026-05-11 12:58:13 ++++ b/conserver/main.c 2026-05-11 13:01:10 +@@ -112,12 +112,25 @@ + + if ((dh = DH_new()) == NULL) + return (NULL); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0 */ ++ { ++ BIGNUM *p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); ++ BIGNUM *g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); ++ if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) { ++ BN_free(p); ++ BN_free(g); ++ DH_free(dh); ++ return (NULL); ++ } ++ } ++#else + dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); + dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) { + DH_free(dh); + return (NULL); + } ++#endif + return (dh); + } + +@@ -146,12 +159,25 @@ + + if ((dh = DH_new()) == NULL) + return (NULL); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0 */ ++ { ++ BIGNUM *p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); ++ BIGNUM *g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); ++ if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) { ++ BN_free(p); ++ BN_free(g); ++ DH_free(dh); ++ return (NULL); ++ } ++ } ++#else + dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); + dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) { + DH_free(dh); + return (NULL); + } ++#endif + return (dh); + } + +@@ -193,12 +219,25 @@ + + if ((dh = DH_new()) == NULL) + return (NULL); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0 */ ++ { ++ BIGNUM *p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); ++ BIGNUM *g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); ++ if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) { ++ BN_free(p); ++ BN_free(g); ++ DH_free(dh); ++ return (NULL); ++ } ++ } ++#else + dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); + dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) { + DH_free(dh); + return (NULL); + } ++#endif + return (dh); + } + +@@ -266,12 +305,25 @@ + + if ((dh = DH_new()) == NULL) + return (NULL); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0 */ ++ { ++ BIGNUM *p = BN_bin2bn(dh4096_p, sizeof(dh4096_p), NULL); ++ BIGNUM *g = BN_bin2bn(dh4096_g, sizeof(dh4096_g), NULL); ++ if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) { ++ BN_free(p); ++ BN_free(g); ++ DH_free(dh); ++ return (NULL); ++ } ++ } ++#else + dh->p = BN_bin2bn(dh4096_p, sizeof(dh4096_p), NULL); + dh->g = BN_bin2bn(dh4096_g, sizeof(dh4096_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) { + DH_free(dh); + return (NULL); + } ++#endif + return (dh); + } + diff --git a/conserver/debian/patches/series b/conserver/debian/patches/series index 110cd53..c23fa73 100644 --- a/conserver/debian/patches/series +++ b/conserver/debian/patches/series @@ -1 +1,3 @@ -initscript_8.2.1.patch \ No newline at end of file +initscript_8.2.1.patch +openssl3-dh-opaque.patch +fix-true-keyword-gcc15.patch \ No newline at end of file diff --git a/conserver/make_deb.sh b/conserver/make_deb.sh index 38dd536..ba044ba 100644 --- a/conserver/make_deb.sh +++ b/conserver/make_deb.sh @@ -1,4 +1,12 @@ #!/bin/bash +set -e + +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi tar xvfz conserver-8.2.1.tar.gz cd conserver-8.2.1 diff --git a/elilo/debian/changelog b/elilo/debian/changelog index bcc4b66..ac4915b 100644 --- a/elilo/debian/changelog +++ b/elilo/debian/changelog @@ -2,19 +2,19 @@ elilo-xcat (3.14-6) UNRELEASED; urgency=low * bump up the version number to include elilo-x86.efi - -- xCAT Fri, 7 May 2021 23:16:56 -0800 + -- xCAT Fri, 7 May 2021 23:16:56 -0800 elilo-xcat (3.14-5) UNRELEASED; urgency=low * bump up the kernel_size from 8M to 15M - -- xCAT Fri, 10 Jul 2020 23:16:56 -0800 + -- xCAT Fri, 10 Jul 2020 23:16:56 -0800 elilo-xcat (3.14-4) UNRELEASED; urgency=low * modify the package to be arch indep - -- xCAT Thu, 13 Nov 2014 23:16:56 -0800 + -- xCAT Thu, 13 Nov 2014 23:16:56 -0800 elilo-xcat (1.2.1-1) unstable; urgency=low diff --git a/elilo/debian/compat b/elilo/debian/compat index 7ed6ff8..f599e28 100644 --- a/elilo/debian/compat +++ b/elilo/debian/compat @@ -1 +1 @@ -5 +10 diff --git a/elilo/debian/patches/elilo-fix-bool-keyword.patch b/elilo/debian/patches/elilo-fix-bool-keyword.patch new file mode 100644 index 0000000..23f7697 --- /dev/null +++ b/elilo/debian/patches/elilo-fix-bool-keyword.patch @@ -0,0 +1,36 @@ +--- elilo.orig/elilo.c 2026-05-19 14:49:25.504833083 +0000 ++++ elilo/elilo.c 2026-05-19 14:49:30.174044609 +0000 +@@ -405,15 +405,15 @@ + { + EFI_STATUS status; + UINTN l = sizeof(BOOLEAN); +- UINT8 bool = FALSE; ++ UINT8 edd_bool = FALSE; + INTN ret = -1; + +- status = uefi_call_wrapper(RT->GetVariable, 5, L"EDD30", &edd30_guid, NULL, &l, &bool); +- if (status == EFI_BUFFER_TOO_SMALL || (bool != TRUE && bool != FALSE)) { ++ status = uefi_call_wrapper(RT->GetVariable, 5, L"EDD30", &edd30_guid, NULL, &l, &edd_bool); ++ if (status == EFI_BUFFER_TOO_SMALL || (edd_bool != TRUE && edd_bool != FALSE)) { + ERR_PRT((L"Warning: EDD30 EFI variable is not boolean value: forcing it to TRUE")); + return -1; + } +- if (status == EFI_SUCCESS && bool == TRUE) { ++ if (status == EFI_SUCCESS && edd_bool == TRUE) { + VERB_PRT(3, Print(L"EDD30 is TRUE\n")); + elilo_opt.edd30_on = TRUE; + ret = 0; +@@ -435,10 +435,10 @@ + { + EFI_STATUS status; + UINTN l = sizeof(BOOLEAN); +- UINT8 bool; ++ UINT8 edd_bool; + +- bool = TRUE; +- status = uefi_call_wrapper(RT->SetVariable, 5, L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool); ++ edd_bool = TRUE; ++ status = uefi_call_wrapper(RT->SetVariable, 5, L"EDD30", &edd30_guid, EDD30_ATTR, l, &edd_bool); + if (EFI_ERROR(status)) { + ERR_PRT((L"can't set EDD30 variable: ignoring it")); + return -1; diff --git a/elilo/debian/patches/elilo-fix-objcopy-format.patch b/elilo/debian/patches/elilo-fix-objcopy-format.patch new file mode 100644 index 0000000..ea43f81 --- /dev/null +++ b/elilo/debian/patches/elilo-fix-objcopy-format.patch @@ -0,0 +1,25 @@ +diff -ruN elilo.orig/Make.rules elilo/Make.rules +--- elilo.orig/Make.rules 2007-07-20 19:47:25.000000000 +0000 ++++ elilo/Make.rules 2026-05-19 14:52:32.458614655 +0000 +@@ -25,7 +25,7 @@ + + %.efi: %.so + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ +- -j .rela -j .reloc --target=$(FORMAT) $*.so $@ ++ -j .rela -j .reloc -I elf64-$(OBJCOPY_ARCH) -O $(FORMAT) --subsystem=efi-app $*.so $@ + + %.so: %.o + $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES) +diff -ruN elilo.orig/Makefile elilo/Makefile +--- elilo.orig/Makefile 2010-11-09 23:16:50.000000000 +0000 ++++ elilo/Makefile 2026-05-19 14:52:19.617943296 +0000 +@@ -34,7 +34,8 @@ + + LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) + LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) +-FORMAT = efi-app-$(ARCH) ++OBJCOPY_ARCH = $(shell echo $(ARCH) | sed s,_,-,g) ++FORMAT = pei-$(OBJCOPY_ARCH) + + FILESYSTEM = + diff --git a/elilo/debian/patches/elilo-fix-strncpy-conflict.patch b/elilo/debian/patches/elilo-fix-strncpy-conflict.patch new file mode 100644 index 0000000..55400e2 --- /dev/null +++ b/elilo/debian/patches/elilo-fix-strncpy-conflict.patch @@ -0,0 +1,183 @@ +diff -ruN elilo.orig/fileops.c elilo/fileops.c +--- elilo.orig/fileops.c 2010-11-09 23:16:50.000000000 +0000 ++++ elilo/fileops.c 2026-05-19 14:48:27.942072518 +0000 +@@ -390,7 +390,7 @@ + + Print(L"Using builtin defaults for kernel and config file\n"); + +- StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1); ++ EliloStrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1); + } + else { + boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath); +@@ -402,8 +402,8 @@ + return EFI_INVALID_PARAMETER; + } + #endif +- StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1); +- StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1); ++ EliloStrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1); ++ EliloStrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1); + + #ifdef ELILO_DEBUG + VERB_PRT(3,Print(L"Default config filename list:\n")); +diff -ruN elilo.orig/fs/ext2fs.c elilo/fs/ext2fs.c +--- elilo.orig/fs/ext2fs.c 2009-04-02 20:17:13.000000000 +0000 ++++ elilo/fs/ext2fs.c 2026-05-19 14:48:27.942649987 +0000 +@@ -769,7 +769,7 @@ + { + if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; + +- StrnCpy(name, FS_NAME, maxlen-1); ++ EliloStrnCpy(name, FS_NAME, maxlen-1); + + name[maxlen-1] = CHAR_NULL; + +diff -ruN elilo.orig/fs/localfs.c elilo/fs/localfs.c +--- elilo.orig/fs/localfs.c 2010-11-09 23:14:21.000000000 +0000 ++++ elilo/fs/localfs.c 2026-05-19 14:48:27.943106300 +0000 +@@ -77,7 +77,7 @@ + { + if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; + +- StrnCpy(name, FS_NAME, maxlen-1); ++ EliloStrnCpy(name, FS_NAME, maxlen-1); + + name[maxlen-1] = CHAR_NULL; + +diff -ruN elilo.orig/fs/netfs.c elilo/fs/netfs.c +--- elilo.orig/fs/netfs.c 2026-05-19 14:48:14.413690716 +0000 ++++ elilo/fs/netfs.c 2026-05-19 14:48:27.942879702 +0000 +@@ -209,7 +209,7 @@ + { + if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER; + +- StrnCpy(name, FS_NAME, maxlen-1); ++ EliloStrnCpy(name, FS_NAME, maxlen-1); + + name[maxlen-1] = CHAR_NULL; + +diff -ruN elilo.orig/glue_localfs.c elilo/glue_localfs.c +--- elilo.orig/glue_localfs.c 2004-02-19 22:39:04.000000000 +0000 ++++ elilo/glue_localfs.c 2026-05-19 14:48:27.942374366 +0000 +@@ -101,10 +101,10 @@ + static EFI_STATUS + localfs_setdefaults(VOID *this, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) + { +- StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1); ++ EliloStrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1); + kname[maxlen-1] = CHAR_NULL; + +- StrnCpy(config[0].fname, LOCALFS_DEFAULT_CONFIG, maxlen-1); ++ EliloStrnCpy(config[0].fname, LOCALFS_DEFAULT_CONFIG, maxlen-1); + config[0].fname[maxlen-1] = CHAR_NULL; + + set_default_path(devpath); +diff -ruN elilo.orig/glue_netfs.c elilo/glue_netfs.c +--- elilo.orig/glue_netfs.c 2026-05-19 14:48:14.414011673 +0000 ++++ elilo/glue_netfs.c 2026-05-19 14:48:27.942495255 +0000 +@@ -132,7 +132,7 @@ + { + INTN len; + +- StrnCpy(netfs_default_path, info->bootfile, FILENAME_MAXLEN); ++ EliloStrnCpy(netfs_default_path, info->bootfile, FILENAME_MAXLEN); + + len = StrLen(netfs_default_path) - 1; + +@@ -191,13 +191,13 @@ + + status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname); + if (EFI_ERROR(status)) { +- StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); ++ EliloStrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); + config[0].fname[maxlen-1] = CHAR_NULL; + } + + status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname); + if (EFI_ERROR(status)) { +- StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); ++ EliloStrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); + kname[maxlen-1] = CHAR_NULL; + } + } else { +@@ -224,37 +224,37 @@ + * the filenames are constructed based on the IP(v4) address + */ + convert_ip2hex(ipaddr, m, str); +- StrnCpy(config[0].fname, str, maxlen-1); +- StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); ++ EliloStrnCpy(config[0].fname, str, maxlen-1); ++ EliloStrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); + +- StrnCpy(config[1].fname, str, maxlen-1); +- StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ EliloStrnCpy(config[1].fname, str, maxlen-1); ++ EliloStrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); + +- StrnCpy(config[2].fname, str, maxlen-1); +- StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6); ++ EliloStrnCpy(config[2].fname, str, maxlen-1); ++ EliloStrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6); + +- StrnCpy(config[3].fname, str, maxlen-1); +- StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ EliloStrnCpy(config[3].fname, str, maxlen-1); ++ EliloStrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); + +- StrnCpy(config[4].fname, str, maxlen-1); +- StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6); ++ EliloStrnCpy(config[4].fname, str, maxlen-1); ++ EliloStrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6); + +- StrnCpy(config[5].fname, str, maxlen-1); +- StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ EliloStrnCpy(config[5].fname, str, maxlen-1); ++ EliloStrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); + +- StrnCpy(config[6].fname, str, maxlen-1); +- StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); ++ EliloStrnCpy(config[6].fname, str, maxlen-1); ++ EliloStrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); + + /* use the MAC address as a possible file name as well */ + convert_mac2hex(info.hw_addr,6,str); +- StrnCpy(config[7].fname, str, maxlen-1); +- StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); ++ EliloStrnCpy(config[7].fname, str, maxlen-1); ++ EliloStrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); + + #else +- StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); ++ EliloStrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); + config[0].fname[maxlen-1] = CHAR_NULL; + #endif +- StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); ++ EliloStrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); + kname[maxlen-1] = CHAR_NULL; + + /* +diff -ruN elilo.orig/strops.c elilo/strops.c +--- elilo.orig/strops.c 2010-11-09 23:11:07.000000000 +0000 ++++ elilo/strops.c 2026-05-19 14:48:27.942069100 +0000 +@@ -37,7 +37,7 @@ + } + + CHAR16 * +-StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size) ++EliloStrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size) + { + CHAR16 *res = dst; + +diff -ruN elilo.orig/strops.h elilo/strops.h +--- elilo.orig/strops.h 2003-08-19 16:47:46.000000000 +0000 ++++ elilo/strops.h 2026-05-19 14:48:27.941905430 +0000 +@@ -27,7 +27,7 @@ + #define __STROPS_H__ + + extern CHAR16 *StrChr(IN const CHAR16 *s, const CHAR16 c); +-extern CHAR16 *StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); ++extern CHAR16 *EliloStrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); + extern CHAR8 *StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, UINTN count); + + extern CHAR8 *strtok_simple(CHAR8 *in, CHAR8 c); diff --git a/elilo/debian/patches/series b/elilo/debian/patches/series index aefb549..84f6376 100644 --- a/elilo/debian/patches/series +++ b/elilo/debian/patches/series @@ -1,3 +1,6 @@ elilo-xcat.patch elilo-xcat-ubuntu.patch elilo-big-bzimage-limit.patch +elilo-fix-strncpy-conflict.patch +elilo-fix-bool-keyword.patch +elilo-fix-objcopy-format.patch diff --git a/elilo/make_deb.sh b/elilo/make_deb.sh index e6f52d4..2227f77 100755 --- a/elilo/make_deb.sh +++ b/elilo/make_deb.sh @@ -1,4 +1,12 @@ #!/bin/bash +set -e + +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi tar xvfz elilo-3.14-source.tar.gz cd elilo diff --git a/elilo/mockbuild.pl b/elilo/mockbuild.pl index 267d1f1..aee1619 100755 --- a/elilo/mockbuild.pl +++ b/elilo/mockbuild.pl @@ -21,6 +21,7 @@ my $mock_uniqueext = ''; my $result_dir = "$repo_root/build-output/list3/elilo-xcat"; my $log_dir = "$repo_root/build-logs/list3/elilo-xcat"; my $skip_install = 0; +my $build_timestamp; GetOptions( 'source-url=s' => \$source_url, @@ -31,6 +32,7 @@ GetOptions( 'result-dir=s' => \$result_dir, 'log-dir=s' => \$log_dir, 'skip-install!' => \$skip_install, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -57,6 +59,19 @@ my $mock_uniqueext_opt = $mock_uniqueext ne '' ? ' --uniqueext ' . sh_quote($mock_uniqueext) : ''; +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + $SOURCE_DATE_EPOCH = slurp("$repo_root/Gitepoch"); + chomp $SOURCE_DATE_EPOCH; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + print_step("Configuration"); print "repo_root: $repo_root\n"; print "pkg_dir: $pkg_dir\n"; @@ -93,6 +108,7 @@ my $prep_top = "$work_dir/prep"; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$prep_top/$d"); } +my $det_mock_cfg = create_deterministic_mock_cfg($mock_cfg, $SOURCE_DATE_EPOCH, $work_dir); copy($spec_file, "$prep_top/SPECS/elilo-xcat.spec") or die "Failed to copy spec to prep topdir: $!\n"; for my $asset (@spec_assets) { @@ -116,9 +132,12 @@ print_step("Build SRPM with mock"); my $srpm_out = "$work_dir/srpm"; make_path($srpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --buildsrpm --spec " . sh_quote($spec_file) . " --sources " . sh_quote($pkg_dir) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " --resultdir " . sh_quote($srpm_out) ); @@ -131,8 +150,11 @@ print_step("Rebuild RPM with mock"); my $rpm_out = "$work_dir/rpm"; make_path($rpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --rebuild " . sh_quote($srpm) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " --resultdir " . sh_quote($rpm_out) ); @@ -221,9 +243,20 @@ Usage: $0 [options] --result-dir PATH Output RPM/SRPM directory (default: $result_dir) --log-dir PATH Log directory (default: $log_dir) --skip-install Skip dnf install + smoke tests + --build-timestamp EPOCH Unix timestamp for SOURCE_DATE_EPOCH (deterministic builds) USAGE } +sub create_deterministic_mock_cfg { + my ($base_cfg, $epoch, $dir) = @_; + my $cfg_path = "$dir/mock-deterministic.cfg"; + open my $fh, '>', $cfg_path or die "Cannot write $cfg_path: $!\n"; + print $fh "include('/etc/mock/${base_cfg}.cfg')\n"; + print $fh "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n"; + close $fh; + return $cfg_path; +} + sub parse_spec { my ($path) = @_; open my $fh, '<', $path or die "Cannot open spec $path: $!\n"; diff --git a/goconserver/debian/rules b/goconserver/debian/rules index 37f2d19..a8a3d32 100755 --- a/goconserver/debian/rules +++ b/goconserver/debian/rules @@ -4,13 +4,14 @@ export CGO_ENABLED=0 dh $@ override_dh_auto_configure: override_dh_auto_build: - go build -ldflags "-X main.Version=0.3.3" -o goconserver goconserver.go - go build -ldflags "-X main.Version=0.3.3" -o congo cmd/congo.go + go build -trimpath -buildvcs=false -ldflags "-X main.Version=0.3.3" -o goconserver goconserver.go + go build -trimpath -buildvcs=false -ldflags "-X main.Version=0.3.3" -o congo cmd/congo.go override_dh_auto_install: install -D -m 755 goconserver $(CURDIR)/debian/goconserver/usr/bin/goconserver install -D -m 755 congo $(CURDIR)/debian/goconserver/usr/bin/congo install -D -m 644 etc/goconserver/server.conf $(CURDIR)/debian/goconserver/etc/goconserver/server.conf mkdir -p $(CURDIR)/debian/goconserver/var/log/goconserver + mkdir -p $(CURDIR)/debian/goconserver/var/lib/goconserver override_dh_auto_test: override_dh_auto_clean: rm -f goconserver congo diff --git a/goconserver/make_deb.sh b/goconserver/make_deb.sh index 78501b6..6132df0 100755 --- a/goconserver/make_deb.sh +++ b/goconserver/make_deb.sh @@ -6,6 +6,20 @@ VERSION=0.3.3 REPO=https://github.com/xcat2/goconserver.git REF=master +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi + +if [ -n "${SOURCE_DATE_EPOCH:-}" ]; then + SNAP_TS=$(date -d "@$SOURCE_DATE_EPOCH" --utc '+%Y%m%d%H%M') +else + SNAP_TS=$(date '+%Y%m%d%H%M') +fi +FULL_VERSION="${VERSION}-snap${SNAP_TS}" + WORKDIR=$(mktemp -d) trap "rm -rf $WORKDIR" EXIT @@ -27,6 +41,18 @@ go mod tidy cp -rL "$SCRIPT_DIR/debian" . +sed -i "s/Version=${VERSION}/Version=${FULL_VERSION}/g" debian/rules + +if [ -n "${SOURCE_DATE_EPOCH:-}" ]; then + export DEBEMAIL="${DEBEMAIL:-xcat-build@xcat.org}" + export DEBFULLNAME="${DEBFULLNAME:-xCAT Build}" + deterministic_date=$(date -R -d "@$SOURCE_DATE_EPOCH" --utc) + sed -i "1s/(.*)/(${FULL_VERSION})/" debian/changelog + sed -i "s/^ -- .*/ -- $DEBFULLNAME <$DEBEMAIL> $deterministic_date/" debian/changelog +else + dch -v "$FULL_VERSION" -b -D unstable "Snap build for xCAT" +fi + dpkg-buildpackage -uc -us echo "Built debs:" diff --git a/goconserver/mockbuild.pl b/goconserver/mockbuild.pl index e1889a7..ff2b0df 100755 --- a/goconserver/mockbuild.pl +++ b/goconserver/mockbuild.pl @@ -21,6 +21,7 @@ my $skip_install = 0; my $version = '0.3.3'; my $go_repo = 'https://github.com/xcat2/goconserver.git'; my $go_ref = 'master'; +my $build_timestamp; GetOptions( 'work-dir=s' => \$work_dir, @@ -32,6 +33,7 @@ GetOptions( 'version=s' => \$version, 'go-repo=s' => \$go_repo, 'go-ref=s' => \$go_ref, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -49,6 +51,24 @@ if (!$mock_cfg) { my ($rel) = $mock_cfg =~ /-(\d+)-/; $rel //= '10'; +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + my $epoch_content = ''; + if (open my $efh, '<', "$repo_root/Gitepoch") { + $epoch_content = <$efh>; + close $efh; + chomp $epoch_content; + } + $SOURCE_DATE_EPOCH = $epoch_content; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + print_step("Configuration"); print "repo_root: $repo_root\n"; print "pkg_dir: $pkg_dir\n"; @@ -69,7 +89,8 @@ print_step("Stage build environment"); remove_tree($work_dir) if -d $work_dir; make_path($work_dir); -my $rpmbuild_top = "$work_dir/rpmbuild"; +my $rpmbuild_top = "/var/tmp/xcat-rpmbuild-goconserver"; +remove_tree($rpmbuild_top) if -d $rpmbuild_top; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$rpmbuild_top/$d"); } @@ -91,8 +112,12 @@ $ENV{GOCACHE} = "$work_dir/gocache"; $ENV{GOMODCACHE} = "$work_dir/gomodcache"; $ENV{CGO_ENABLED} = '0'; +# The archived github.com/kr/pty sets SysProcAttr.Ctty to the parent-side fd, +# which modern Go's os/exec rejects with "Setctty set but Ctty not valid in +# child". Replace it with the API-identical maintained fork creack/pty. run("cd " . sh_quote($src_dir) . " && " . "go mod init github.com/xcat2/goconserver && " . + "go mod edit -replace github.com/kr/pty=github.com/creack/pty\@v1.1.21 && " . "go mod tidy" . " >" . sh_quote("$log_dir/go-mod.log") . " 2>&1"); @@ -103,12 +128,12 @@ make_path($go_build_dir); my $ldflags = "-X main.Version=$version"; run("cd " . sh_quote($src_dir) . " && " . - "go build -ldflags " . sh_quote($ldflags) . + "go build -trimpath -buildvcs=false -ldflags " . sh_quote($ldflags) . " -o " . sh_quote("$go_build_dir/goconserver") . " goconserver.go" . " >" . sh_quote("$log_dir/go-build-server.log") . " 2>&1"); run("cd " . sh_quote($src_dir) . " && " . - "go build -ldflags " . sh_quote($ldflags) . + "go build -trimpath -buildvcs=false -ldflags " . sh_quote($ldflags) . " -o " . sh_quote("$go_build_dir/congo") . " cmd/congo.go" . " >" . sh_quote("$log_dir/go-build-client.log") . " 2>&1"); @@ -137,6 +162,7 @@ After=network.target Type=simple ExecStart=/usr/bin/goconserver Restart=on-failure +StateDirectory=goconserver [Install] WantedBy=multi-user.target @@ -153,14 +179,15 @@ log_level = info CONF my $tarball = "$rpmbuild_top/SOURCES/goconserver-$version.tar.gz"; -run("tar -C " . sh_quote($work_dir) . " -czf " . sh_quote($tarball) . +run("tar --sort=name --owner=0 --group=0 --mtime=\@$SOURCE_DATE_EPOCH" . + " -C " . sh_quote($work_dir) . " -czf " . sh_quote($tarball) . " goconserver-$version"); print_step("Create spec and build RPM"); my $spec_content = <<"SPEC"; Name: goconserver Version: $version -Release: 1.el$rel +Release: 2.el$rel Summary: Console server written in Go for xCAT License: EPL-1.0 URL: https://github.com/xcat2/goconserver @@ -180,6 +207,7 @@ mkdir -p %{buildroot}/usr/bin mkdir -p %{buildroot}/usr/lib/systemd/system mkdir -p %{buildroot}/etc/goconserver mkdir -p %{buildroot}/var/log/goconserver +mkdir -p %{buildroot}/var/lib/goconserver install -m 755 usr/bin/goconserver %{buildroot}/usr/bin/goconserver install -m 755 usr/bin/congo %{buildroot}/usr/bin/congo @@ -192,8 +220,12 @@ install -m 644 etc/goconserver/server.conf %{buildroot}/etc/goconserver/server.c /usr/lib/systemd/system/goconserver.service %config(noreplace) /etc/goconserver/server.conf %dir /var/log/goconserver +%dir /var/lib/goconserver %changelog +* Mon Jun 08 2026 xCAT EL10 build - 0.3.3-2.el10 +- Replace archived github.com/kr/pty with github.com/creack/pty to fix + "Setctty set but Ctty not valid in child" console fork failure on modern Go. SPEC my $spec_file = "$rpmbuild_top/SPECS/goconserver.spec"; @@ -201,6 +233,9 @@ write_file($spec_file, $spec_content); run( "rpmbuild --define " . sh_quote("_topdir $rpmbuild_top") . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " -ba " . sh_quote($spec_file) . " >" . sh_quote("$log_dir/rpmbuild.log") . " 2>&1" ); @@ -253,6 +288,7 @@ Options: --version VER Version string (default: 0.3.3) --go-repo URL Git repo URL (default: github.com/xcat2/goconserver) --go-ref REF Git ref to build (default: master) + --build-timestamp EPOCH SOURCE_DATE_EPOCH for deterministic builds USAGE } diff --git a/grub2-xcat/debian/changelog b/grub2-xcat/debian/changelog index 65bc2b7..f0ebc27 100644 --- a/grub2-xcat/debian/changelog +++ b/grub2-xcat/debian/changelog @@ -1,3 +1,9 @@ +grub2-xcat (2.12-1) unstable; urgency=low + + * Bump version to satisfy xcat-server dependency (>= 2.02) + + -- XCAT Wed, 21 May 2025 12:00:00 +0000 + grub2-xcat (1.0-2) unstable; urgency=low * update core.elf to support ppc64le diff --git a/grub2-xcat/debian/rules b/grub2-xcat/debian/rules index 733de96..0a52f96 100755 --- a/grub2-xcat/debian/rules +++ b/grub2-xcat/debian/rules @@ -9,7 +9,7 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -export DH_COMPAT=5 +export DH_COMPAT=8 build: diff --git a/grub2-xcat/make_deb.sh b/grub2-xcat/make_deb.sh new file mode 100755 index 0000000..405fa0c --- /dev/null +++ b/grub2-xcat/make_deb.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi + +dpkg-buildpackage -uc -us diff --git a/grub2-xcat/mockbuild.pl b/grub2-xcat/mockbuild.pl index 9575ddc..adc50da 100755 --- a/grub2-xcat/mockbuild.pl +++ b/grub2-xcat/mockbuild.pl @@ -24,6 +24,7 @@ my $result_dir = "$repo_root/build-output/list3/grub2-xcat"; my $log_dir = "$repo_root/build-logs/list3/grub2-xcat"; my $skip_install = 0; my $skip_upstream_download = 0; +my $build_timestamp; GetOptions( 'resource-mode=s' => \$resource_mode, @@ -36,6 +37,7 @@ GetOptions( 'log-dir=s' => \$log_dir, 'skip-install!' => \$skip_install, 'skip-upstream-download!' => \$skip_upstream_download, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -69,6 +71,19 @@ my $mock_uniqueext_opt = $mock_uniqueext ne '' ? ' --uniqueext ' . sh_quote($mock_uniqueext) : ''; +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + $SOURCE_DATE_EPOCH = slurp("$repo_root/Gitepoch"); + chomp $SOURCE_DATE_EPOCH; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + print_step("Configuration"); print "repo_root: $repo_root\n"; print "pkg_dir: $pkg_dir\n"; @@ -131,6 +146,8 @@ my $prep_top = "$work_dir/prep"; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$prep_top/$d"); } +my $det_mock_cfg = create_deterministic_mock_cfg($mock_cfg, $SOURCE_DATE_EPOCH, $work_dir); + copy($spec_file, "$prep_top/SPECS/grub2-xcat.spec") or die "Failed to copy spec to prep topdir: $!\n"; for my $asset (@spec_assets) { @@ -152,10 +169,13 @@ print_step("Build SRPM with mock"); my $srpm_out = "$work_dir/srpm"; make_path($srpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --buildsrpm --spec " . sh_quote($spec_file) . " --sources " . sh_quote($pkg_dir) . - " --resultdir " . sh_quote($srpm_out) + " --resultdir " . sh_quote($srpm_out) . + " --define 'use_source_date_epoch_as_buildtime 1'" . + " --define 'clamp_mtime_to_source_date_epoch 1'" . + " --define '_buildhost xcat-build'" ); my @srpms = sort glob("$srpm_out/grub2-xcat-*.src.rpm"); @@ -167,9 +187,12 @@ print_step("Rebuild RPM with mock"); my $rpm_out = "$work_dir/rpm"; make_path($rpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --rebuild " . sh_quote($srpm) . - " --resultdir " . sh_quote($rpm_out) + " --resultdir " . sh_quote($rpm_out) . + " --define 'use_source_date_epoch_as_buildtime 1'" . + " --define 'clamp_mtime_to_source_date_epoch 1'" . + " --define '_buildhost xcat-build'" ); my @all_rpms = sort glob("$rpm_out/*.rpm"); @@ -281,9 +304,20 @@ Usage: $0 [options] --log-dir PATH Log directory (default: $log_dir) --skip-upstream-download Skip wget of upstream source RPM --skip-install Skip dnf install + smoke tests + --build-timestamp EPOCH Unix timestamp for deterministic builds (SOURCE_DATE_EPOCH) USAGE } +sub create_deterministic_mock_cfg { + my ($base_cfg, $epoch, $dir) = @_; + my $cfg_path = "$dir/mock-deterministic.cfg"; + open my $fh, '>', $cfg_path or die "Cannot write $cfg_path: $!\n"; + print $fh "include('/etc/mock/${base_cfg}.cfg')\n"; + print $fh "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n"; + close $fh; + return $cfg_path; +} + sub parse_spec { my ($path) = @_; open my $fh, '<', $path or die "Cannot open spec $path: $!\n"; diff --git a/ipmitool/debian/control b/ipmitool/debian/control index 29569ad..98f2bf0 100644 --- a/ipmitool/debian/control +++ b/ipmitool/debian/control @@ -2,12 +2,12 @@ Source: ipmitool-xcat Section: utils Priority: optional Maintainer: xCAT -Build-Depends: debhelper (>> 4.0.0), libreadline-dev, libssl-dev, quilt, autotools-dev +Build-Depends: debhelper (>= 13), libreadline-dev, libssl-dev, quilt Standards-Version: 3.6.2.1 Package: ipmitool-xcat Architecture: i386 amd64 ia64 ppc64el -Depends: libc6 (>= 2.15), libssl3 | libssl1.1 (>= 1.1.0) | libssl1.0.0 (>=1.0.0), lsb-base +Depends: libc6 (>= 2.15), libssl3t64 | libssl3 | libssl1.1 Suggests: openipmi Description: utility for IPMI control with kernel driver or LAN interface A utility for managing and configuring devices that support the diff --git a/ipmitool/debian/rules b/ipmitool/debian/rules index 816ed13..dee807e 100755 --- a/ipmitool/debian/rules +++ b/ipmitool/debian/rules @@ -25,7 +25,6 @@ configure-stamp: ifneq ($(TARGET_ARCH),ppc64el) ./configure --prefix=/usr \ - --with-kerneldir \ --mandir=/usr/share/man else diff --git a/ipmitool/make_deb.sh b/ipmitool/make_deb.sh index cc74b9c..8b6b374 100755 --- a/ipmitool/make_deb.sh +++ b/ipmitool/make_deb.sh @@ -1,4 +1,13 @@ #!/bin/bash +set -e + +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi + VERSION=1.8.18 tar xvfz ipmitool-$VERSION.tar.gz diff --git a/ipmitool/mockbuild.pl b/ipmitool/mockbuild.pl index 3f377b9..3afcb26 100755 --- a/ipmitool/mockbuild.pl +++ b/ipmitool/mockbuild.pl @@ -21,6 +21,7 @@ my $mock_uniqueext = ''; my $result_dir = "$repo_root/build-output/list3/ipmitool-xcat"; my $log_dir = "$repo_root/build-logs/list3/ipmitool-xcat"; my $skip_install = 0; +my $build_timestamp; GetOptions( 'source-url=s' => \$source_url, @@ -31,6 +32,7 @@ GetOptions( 'result-dir=s' => \$result_dir, 'log-dir=s' => \$log_dir, 'skip-install!' => \$skip_install, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -57,6 +59,19 @@ my $mock_uniqueext_opt = $mock_uniqueext ne '' ? ' --uniqueext ' . sh_quote($mock_uniqueext) : ''; +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + $SOURCE_DATE_EPOCH = slurp("$repo_root/Gitepoch"); + chomp $SOURCE_DATE_EPOCH; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + print_step("Configuration"); print "repo_root: $repo_root\n"; print "pkg_dir: $pkg_dir\n"; @@ -68,6 +83,7 @@ print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') print "source_url: $source_url\n"; print "source_file:$source_file\n"; print "skip_install: $skip_install\n"; +print "SOURCE_DATE_EPOCH: $SOURCE_DATE_EPOCH\n"; make_path($result_dir); make_path($log_dir); @@ -90,6 +106,7 @@ print "Verified " . scalar(@spec_assets) . " Source/Patch assets from spec.\n"; print_step("Stage files for patch-application check"); remove_tree($work_dir) if -d $work_dir; my $prep_top = "$work_dir/prep"; +my $det_mock_cfg = create_deterministic_mock_cfg($mock_cfg, $SOURCE_DATE_EPOCH, $work_dir); for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$prep_top/$d"); } @@ -116,9 +133,12 @@ print_step("Build SRPM with mock"); my $srpm_out = "$work_dir/srpm"; make_path($srpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --buildsrpm --spec " . sh_quote($spec_file) . " --sources " . sh_quote($pkg_dir) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " --resultdir " . sh_quote($srpm_out) ); @@ -131,8 +151,11 @@ print_step("Rebuild RPM with mock"); my $rpm_out = "$work_dir/rpm"; make_path($rpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --rebuild " . sh_quote($srpm) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " --resultdir " . sh_quote($rpm_out) ); @@ -243,9 +266,21 @@ Usage: $0 [options] --result-dir PATH Output RPM/SRPM directory (default: $result_dir) --log-dir PATH Log directory (default: $log_dir) --skip-install Skip dnf install + smoke tests + --build-timestamp N Unix epoch for SOURCE_DATE_EPOCH (deterministic builds) USAGE } +sub create_deterministic_mock_cfg { + my ($base_cfg, $epoch, $dir) = @_; + make_path($dir) unless -d $dir; + my $cfg_path = "$dir/mock-deterministic.cfg"; + open my $fh, '>', $cfg_path or die "Cannot write $cfg_path: $!\n"; + print $fh "include('/etc/mock/${base_cfg}.cfg')\n"; + print $fh "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n"; + close $fh; + return $cfg_path; +} + sub parse_spec { my ($path) = @_; open my $fh, '<', $path or die "Cannot open spec $path: $!\n"; @@ -298,7 +333,8 @@ sub normalize_source_archive { # Repack using the expected top-level directory required by the spec. run( - "tar -C " . sh_quote($normalize_dir) . + "tar --sort=name --owner=0 --group=0 --mtime=\@$SOURCE_DATE_EPOCH" . + " -C " . sh_quote($normalize_dir) . " -czf " . sh_quote($archive) . " " . sh_quote($expected_top) ); diff --git a/mockbuild-all.pl b/mockbuild-all.pl index e168220..186dc33 100755 --- a/mockbuild-all.pl +++ b/mockbuild-all.pl @@ -19,7 +19,8 @@ my $output_root = "$repo_root/build-output/mockbuild-all"; my $target = ''; my $nproc = 1; my $parallel_builds; -my $run_id = strftime('%Y%m%d-%H%M%S', localtime); +my $run_id = ''; +my $build_timestamp; my $skip_install = 0; my $skip_build = 0; my $skip_xcat_dep = 0; @@ -39,6 +40,7 @@ GetOptions( 'nproc=i' => \$nproc, 'parallel-builds=i' => \$parallel_builds, 'run-id=s' => \$run_id, + 'build-timestamp=i' => \$build_timestamp, 'skip-install!' => \$skip_install, 'skip-build!' => \$skip_build, 'skip-xcat-dep!' => \$skip_xcat_dep, @@ -56,6 +58,23 @@ die "--parallel-builds must be >= 1\n" if defined($parallel_builds) && $parallel_builds < 1; $repo_root = abs_path($repo_root); + +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + $SOURCE_DATE_EPOCH = slurp_chomp("$repo_root/Gitepoch"); +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + +if ($run_id eq '') { + $run_id = strftime('%Y%m%d-%H%M%S', gmtime($SOURCE_DATE_EPOCH)); +} + $xcat_src = resolve_xcat_source($xcat_src, $repo_root); my $arch = capture('uname -m'); @@ -170,6 +189,7 @@ if (!$skip_build) { '--mock-uniqueext', sh_quote($step_uniqueext), '--result-dir', sh_quote($step_result), '--log-dir', sh_quote($step_log), + '--build-timestamp', $SOURCE_DATE_EPOCH, ($skip_install ? '--skip-install' : ()), ); push @build_steps, { @@ -192,6 +212,7 @@ if (!$skip_build) { '--mock-uniqueext', sh_quote($perl_uniqueext), '--result-dir', sh_quote($perl_result), '--log-dir', sh_quote($perl_log), + '--build-timestamp', $SOURCE_DATE_EPOCH, ($skip_install ? '--skip-install' : ()), ); push @build_steps, { @@ -284,19 +305,21 @@ if (!$dry_run && $copied_srpms == 0) { if (!$skip_createrepo) { run_step( step => 'Run createrepo', - cmd => 'createrepo --update ' . sh_quote($repo_dir), + cmd => 'createrepo --update --revision ' . sh_quote($SOURCE_DATE_EPOCH) . ' ' . sh_quote($repo_dir), log => "$log_root/createrepo.log", ); run_step( step => 'Run createrepo for SRPM repo', - cmd => 'createrepo --update ' . sh_quote($srpm_repo_dir), + cmd => 'createrepo --update --revision ' . sh_quote($SOURCE_DATE_EPOCH) . ' ' . sh_quote($srpm_repo_dir), log => "$log_root/createrepo-srpm.log", ); } if (!$skip_tarball) { my $cmd = join(' ', - 'tar', '-C', sh_quote($run_root), + 'tar', '--sort=name', '--owner=0', '--group=0', + "--mtime=\@$SOURCE_DATE_EPOCH", + '-C', sh_quote($run_root), '-czf', sh_quote($tarball), 'repo' ); @@ -306,7 +329,9 @@ if (!$skip_tarball) { log => "$log_root/tarball.log", ); my $srpm_cmd = join(' ', - 'tar', '-C', sh_quote($run_root), + 'tar', '--sort=name', '--owner=0', '--group=0', + "--mtime=\@$SOURCE_DATE_EPOCH", + '-C', sh_quote($run_root), '-czf', sh_quote($srpm_tarball), 'repo-src' ); @@ -365,7 +390,8 @@ Options: --target NAME Optional unified target in +epel-- format --nproc N Parallel jobs for buildrpms.pl (default: 1) --parallel-builds N Max concurrent top-level build steps (default: auto=queued steps) - --run-id ID Run identifier suffix (default: timestamp) + --run-id ID Run identifier suffix (default: derived from build timestamp) + --build-timestamp EPOCH Unix epoch for deterministic builds (default: Gitepoch or git log) --skip-install Skip install/smoke tests in child builder scripts --skip-build Skip all build steps and only collect/create repo/tarballs --skip-xcat-dep Skip xcat-dep mockbuild.pl package steps @@ -705,6 +731,15 @@ sub uniq { return grep { defined($_) && !$seen{$_}++ } @_; } +sub slurp_chomp { + my ($path) = @_; + open my $fh, '<', $path or die "Cannot read $path: $!\n"; + my $line = <$fh>; + close $fh; + chomp $line if defined $line; + return $line // ''; +} + sub sh_quote { my ($s) = @_; $s = '' if !defined $s; diff --git a/mockbuild-perl-packages.pl b/mockbuild-perl-packages.pl index 359dd2e..9408b40 100755 --- a/mockbuild-perl-packages.pl +++ b/mockbuild-perl-packages.pl @@ -19,6 +19,7 @@ my $packages_csv = ''; my $jobs = 0; my $skip_install = 0; my $allow_erasing = 0; +my $build_timestamp; GetOptions( 'work-dir=s' => \$work_dir, @@ -30,6 +31,7 @@ GetOptions( 'jobs=i' => \$jobs, 'skip-install!' => \$skip_install, 'allow-erasing!' => \$allow_erasing, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -46,6 +48,20 @@ if (!$mock_cfg) { my $mock_uniqueext_opt = $mock_uniqueext ne '' ? ' --uniqueext ' . sh_quote($mock_uniqueext) : ''; + +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + $SOURCE_DATE_EPOCH = slurp("$repo_root/Gitepoch"); + chomp $SOURCE_DATE_EPOCH; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + if (!$result_dir) { $result_dir = "$repo_root/build-output/list6/perl/$arch"; } @@ -277,6 +293,8 @@ sub build_package { make_path($pkg_result); make_path($pkg_log); + my $det_mock_cfg = create_deterministic_mock_cfg($mock_cfg, $SOURCE_DATE_EPOCH, $pkg_run_dir); + my $run_log = "$pkg_log/run.log"; open my $runfh, '>', $run_log or die "Cannot write $run_log: $!\n"; open STDOUT, '>&', $runfh or die "Cannot redirect stdout to $run_log: $!\n"; @@ -341,9 +359,12 @@ sub build_package { my $srpm_result = "$pkg_run_dir/srpm"; make_path($srpm_result); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --buildsrpm --spec " . sh_quote($spec) . " --sources " . sh_quote($source_dir) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " --resultdir " . sh_quote($srpm_result) . " > " . sh_quote("$pkg_log/mock-buildsrpm.log") . " 2>&1" ); @@ -353,8 +374,11 @@ sub build_package { } run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --rebuild " . sh_quote($srpm_path) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") . " --resultdir " . sh_quote($rebuild_result) . " > " . sh_quote("$pkg_log/mock-rebuild.log") . " 2>&1" ); @@ -453,6 +477,7 @@ Usage: $0 [options] --result-dir PATH Output directory (default: build-output/list6/perl/) --log-dir PATH Log directory (default: build-logs/list6/perl/) --packages LIST Comma-separated subset of packages to build + --build-timestamp EPOCH Unix epoch for SOURCE_DATE_EPOCH (deterministic builds) --skip-install Skip dnf install + perl module import checks --allow-erasing Allow dnf to erase conflicting packages during install smoke tests USAGE @@ -594,6 +619,16 @@ sub resolve_mock_cfg { return $candidate; } +sub create_deterministic_mock_cfg { + my ($base_cfg, $epoch, $dir) = @_; + my $cfg_path = "$dir/mock-deterministic.cfg"; + open my $fh, '>', $cfg_path or die "Cannot write $cfg_path: $!\n"; + print $fh "include('/etc/mock/${base_cfg}.cfg')\n"; + print $fh "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n"; + close $fh; + return $cfg_path; +} + sub resolve_source_urls { my ($spec_path) = @_; open my $fh, '<', $spec_path or return (); diff --git a/perl-Sys-Virt/Sys-Virt-0.2.0.tar.gz b/perl-Sys-Virt/Sys-Virt-0.2.0.tar.gz deleted file mode 100644 index ce7ca77..0000000 Binary files a/perl-Sys-Virt/Sys-Virt-0.2.0.tar.gz and /dev/null differ diff --git a/perl-Sys-Virt/Sys-Virt-fixes.patch b/perl-Sys-Virt/Sys-Virt-fixes.patch deleted file mode 100644 index a958f90..0000000 --- a/perl-Sys-Virt/Sys-Virt-fixes.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- Virt.xs 2009-03-27 15:45:33.000000000 -0400 -+++ /root/Virt.xs 2009-04-10 09:08:00.000000000 -0400 -@@ -1337,12 +1337,12 @@ - virDomainPtr dom; - virConnectPtr destcon; - unsigned long flags; -- const char *dname; -- const char *uri; -+ const char *dname = SvPOK($arg) ? (char *)SvPV_nolen($arg) : NULL; -+ const char *uri = SvPOK($arg) ? (char *)SvPV_nolen($arg) : NULL; - unsigned long bandwidth; - CODE: - if ((RETVAL = virDomainMigrate(dom, destcon, flags, dname, uri, bandwidth)) == NULL) { -- _croak_error(virConnGetLastError(virDomainGetConnect(dom))); -+ _croak_error(virGetLastError()); - } - OUTPUT: - RETVAL diff --git a/perl-Sys-Virt/Sys-Virt-v11.10.0.tar.gz b/perl-Sys-Virt/Sys-Virt-v11.10.0.tar.gz new file mode 100644 index 0000000..c4d6e48 Binary files /dev/null and b/perl-Sys-Virt/Sys-Virt-v11.10.0.tar.gz differ diff --git a/perl-Sys-Virt/Sys-Virt.spec b/perl-Sys-Virt/Sys-Virt.spec index 36a16f0..3dc84c9 100644 --- a/perl-Sys-Virt/Sys-Virt.spec +++ b/perl-Sys-Virt/Sys-Virt.spec @@ -1,11 +1,3 @@ -# -# - Sys::Virt - -# This spec file was automatically generated by cpan2rpm [ver: 2.027] -# The following arguments were used: -# --version 0.2.0 --author 'Daniel P. Berrange ' Sys-Virt-0.2.0.tar.gz -# For more information on cpan2rpm please visit: http://perl.arix.com/ -# - %define pkgname Sys-Virt %define filelist %{pkgname}-%{version}-filelist %define NVR %{pkgname}-%{version}-%{release} @@ -13,8 +5,8 @@ name: perl-Sys-Virt summary: Sys-Virt - Represent and manage a libvirt hypervisor connection -version: 0.2.0 -release: 3%{?dist} +version: 11.10.0 +release: 1%{?dist} vendor: Daniel P. Berrange packager: Arix International license: Artistic @@ -22,16 +14,22 @@ group: Applications/CPAN url: http://www.cpan.org buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n) prefix: %(echo %{_prefix}) -source: Sys-Virt-0.2.0.tar.gz -patch0: Sys-Virt-fixes.patch +source: Sys-Virt-v%{version}.tar.gz BuildRequires: gcc BuildRequires: make BuildRequires: perl-interpreter BuildRequires: perl-devel BuildRequires: perl(ExtUtils::MakeMaker) +BuildRequires: perl(ExtUtils::CBuilder) +BuildRequires: perl(Module::Build) +BuildRequires: perl(XML::XPath) +BuildRequires: perl(XML::XPath::XMLParser) +BuildRequires: perl(Time::HiRes) +BuildRequires: perl(Sys::Hostname) BuildRequires: perl-generators BuildRequires: libvirt-devel +BuildRequires: pkgconfig(libvirt) %description The Sys::Virt module provides a Perl XS binding to the libvirt @@ -39,25 +37,14 @@ virtual machine management APIs. This allows machines running within arbitrary virtualization containers to be managed with a consistent API. -# -# This package was generated automatically with the cpan2rpm -# utility. To get this software or for more information -# please visit: http://perl.arix.com/ -# - %prep -%setup -q -n %{pkgname}-%{version} -%patch 0 -p0 -chmod -R u+w %{_builddir}/%{pkgname}-%{version} +%setup -q -n %{pkgname}-v%{version} +chmod -R u+w %{_builddir}/%{pkgname}-v%{version} %build -export PERL_USE_UNSAFE_INC=1 -grep -rsl '^#!.*perl' . | -grep -v '.bak$' |xargs --no-run-if-empty \ -%__perl -MExtUtils::MakeMaker -e 'MY->fixin(@ARGV)' CFLAGS="$RPM_OPT_FLAGS" %{__perl} Makefile.PL `%{__perl} -MExtUtils::MakeMaker -e ' print qq|PREFIX=%{buildroot}%{_prefix}| if \$ExtUtils::MakeMaker::VERSION =~ /5\.9[1-6]|6\.0[0-5]/ '` -%{__make} +%{__make} %if %maketest %{__make} test %endif @@ -93,7 +80,7 @@ find %{buildroot}%{_prefix} \ %{__perl} -MFile::Find -le ' find({ wanted => \&wanted, no_chdir => 1}, "%{buildroot}"); - print "%doc CHANGES INSTALL README LICENSE examples"; + print "%doc Changes INSTALL README LICENSE examples"; for my $x (sort @dirs, @files) { push @ret, $x unless indirs($x); } @@ -133,5 +120,9 @@ find %{buildroot}%{_prefix} \ %defattr(-,root,root) %changelog +* Sat Jun 06 2026 Daniel Hilst <392820+dhilst@users.noreply.github.com> - 11.10.0-1 +- Update to v11.10.0 from CPAN +- Drop Sys-Virt-fixes.patch (not applicable to modern codebase) + * Sun Jul 27 2008 root@mgt.cluster - Initial build. diff --git a/perl-Sys-Virt/build-el10.sh b/perl-Sys-Virt/build-el10.sh new file mode 100755 index 0000000..4a7c0dc --- /dev/null +++ b/perl-Sys-Virt/build-el10.sh @@ -0,0 +1,91 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +SPEC="$SCRIPT_DIR/Sys-Virt.spec" +MOCK_CFG="${MOCK_CFG:-almalinux-10-x86_64}" +WORK_DIR="${WORK_DIR:-/tmp/perl-Sys-Virt-mockbuild}" +RESULT_DIR="${RESULT_DIR:-$REPO_ROOT/build-output/perl-Sys-Virt}" +LOG_DIR="${LOG_DIR:-$REPO_ROOT/build-logs/perl-Sys-Virt}" + +# --- Deterministic build timestamp --- +if [[ -z "${SOURCE_DATE_EPOCH:-}" ]]; then + if [[ -f "$REPO_ROOT/Gitepoch" ]]; then + SOURCE_DATE_EPOCH="$(cat "$REPO_ROOT/Gitepoch")" + else + SOURCE_DATE_EPOCH="$(git -C "$REPO_ROOT" log -1 --format=%ct HEAD 2>/dev/null || date +%s)" + fi +fi +export SOURCE_DATE_EPOCH + +echo "== Configuration ==" +echo "spec: $SPEC" +echo "mock_cfg: $MOCK_CFG" +echo "work_dir: $WORK_DIR" +echo "result_dir: $RESULT_DIR" +echo "log_dir: $LOG_DIR" +echo "SOURCE_DATE_EPOCH: $SOURCE_DATE_EPOCH" + +rm -rf "$WORK_DIR" +mkdir -p "$WORK_DIR" "$RESULT_DIR" "$LOG_DIR" + +# --- Deterministic mock config overlay --- +DET_MOCK_CFG="$WORK_DIR/mock-deterministic.cfg" +cat > "$DET_MOCK_CFG" <&1 | tee "$LOG_DIR/mock-buildsrpm.log" + +SRPM="$(ls -t "$SRPM_OUT"/*.src.rpm 2>/dev/null | head -1)" +if [[ -z "$SRPM" ]]; then + echo "ERROR: No SRPM produced" + exit 1 +fi +echo "SRPM: $SRPM" + +# --- Rebuild RPM via mock --- +echo "" +echo "== Rebuild RPM ==" +RPM_OUT="$WORK_DIR/rpm" +mkdir -p "$RPM_OUT" +mock -r "$DET_MOCK_CFG" \ + --uniqueext "$MOCK_UNIQUEEXT" \ + --rebuild "$SRPM" \ + --define "use_source_date_epoch_as_buildtime 1" \ + --define "clamp_mtime_to_source_date_epoch 1" \ + --define "_buildhost xcat-build" \ + --resultdir "$RPM_OUT" \ + 2>&1 | tee "$LOG_DIR/mock-rebuild.log" + +# --- Collect artifacts --- +echo "" +echo "== Collect artifacts ==" +cp -v "$RPM_OUT"/*.rpm "$RESULT_DIR/" +for log in build.log root.log state.log hw_info.log installed_pkgs.log; do + [[ -f "$RPM_OUT/$log" ]] && cp "$RPM_OUT/$log" "$LOG_DIR/" +done + +echo "" +echo "== Completed ==" +ls -lh "$RESULT_DIR"/*.rpm +echo "Artifacts: $RESULT_DIR" +echo "Logs: $LOG_DIR" diff --git a/syslinux/debian/control b/syslinux/debian/control index bf74523..e69c7db 100644 --- a/syslinux/debian/control +++ b/syslinux/debian/control @@ -2,7 +2,7 @@ Source: syslinux Section: admin Priority: extra Maintainer: xCAT -Build-Depends: debhelper (>= 7.0.50~) +Build-Depends: debhelper (>= 7.0.50~), nasm, gcc-multilib, perl Standards-Version: 3.8.4 #Homepage: #Vcs-Git: git://git.debian.org/collab-maint/syslinux.git diff --git a/syslinux/make_deb.sh b/syslinux/make_deb.sh index 4372364..9296426 100644 --- a/syslinux/make_deb.sh +++ b/syslinux/make_deb.sh @@ -1,8 +1,34 @@ #!/bin/bash +set -e + +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi tar xvfj syslinux-3.86.tar.bz2 cd syslinux-3.86 cp -rL ../debian . + +# GCC >= 10 defaults to -fno-common; syslinux 3.86 relies on common symbols +# GCC 15 promotes implicit-function-declaration and incompatible-pointer-types to errors +sed -i '/^GCCWARN := -W -Wall/s/$/ -fcommon -Wno-error=implicit-function-declaration -Wno-error=incompatible-pointer-types -Wno-error=int-conversion/' MCONFIG +sed -i "s|^GCCWARN := .*|& -fdebug-prefix-map=$(pwd)=.|" MCONFIG + +# glibc >= 2.28 moved major()/minor() to sys/sysmacros.h +# extlinux/main.c:843 calls major()/minor() unconditionally in 3.86 +sed -i '/#include /a #include ' extlinux/main.c + +# com32/cmenu/Makefile uses python2 menugen.py for test .menu files — not needed for build +rm -f com32/cmenu/*.menu + +# vpd.c:67 passes &vpd->base_address (char(*)[6]) not char*; format %X wrong for char* arg +sed -i 's/snprintf(&vpd->base_address, 5, "%X", q)/snprintf(vpd->base_address, sizeof(vpd->base_address), "%s", q)/' com32/gpllib/vpd/vpd.c + +export NO_WERROR=1 dpkg-buildpackage -uc -us + cd - rm -rf syslinux-3.86 diff --git a/syslinux/mockbuild.pl b/syslinux/mockbuild.pl index b77918d..cc320c1 100755 --- a/syslinux/mockbuild.pl +++ b/syslinux/mockbuild.pl @@ -22,6 +22,7 @@ my $result_dir = "$repo_root/build-output/list3/syslinux-xcat"; my $log_dir = "$repo_root/build-logs/list3/syslinux-xcat"; my $skip_install = 0; my $skip_upstream_download = 0; +my $build_timestamp; GetOptions( 'source-url=s' => \$source_url, @@ -33,6 +34,7 @@ GetOptions( 'log-dir=s' => \$log_dir, 'skip-install!' => \$skip_install, 'skip-upstream-download!' => \$skip_upstream_download, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -64,6 +66,19 @@ my $mock_uniqueext_opt = $mock_uniqueext ne '' ? ' --uniqueext ' . sh_quote($mock_uniqueext) : ''; +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + $SOURCE_DATE_EPOCH = slurp("$repo_root/Gitepoch"); + chomp $SOURCE_DATE_EPOCH; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + print_step("Configuration"); print "repo_root: $repo_root\n"; print "pkg_dir: $pkg_dir\n"; @@ -115,6 +130,7 @@ my $prep_top = "$work_dir/prep"; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$prep_top/$d"); } +my $det_mock_cfg = create_deterministic_mock_cfg($mock_cfg, $SOURCE_DATE_EPOCH, $work_dir); copy($spec_file, "$prep_top/SPECS/syslinux-xcat.spec") or die "Failed to copy spec to prep topdir: $!\n"; for my $asset (@all_assets) { @@ -136,10 +152,13 @@ print_step("Build SRPM with mock"); my $srpm_out = "$work_dir/srpm"; make_path($srpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --buildsrpm --spec " . sh_quote($spec_file) . " --sources " . sh_quote($pkg_dir) . - " --resultdir " . sh_quote($srpm_out) + " --resultdir " . sh_quote($srpm_out) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") ); my @srpms = sort glob("$srpm_out/*.src.rpm"); @@ -151,9 +170,12 @@ print_step("Rebuild RPM with mock"); my $rpm_out = "$work_dir/rpm"; make_path($rpm_out); run( - "mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . + "mock -r " . sh_quote($det_mock_cfg) . $mock_uniqueext_opt . " --rebuild " . sh_quote($srpm) . - " --resultdir " . sh_quote($rpm_out) + " --resultdir " . sh_quote($rpm_out) . + " --define " . sh_quote("use_source_date_epoch_as_buildtime 1") . + " --define " . sh_quote("clamp_mtime_to_source_date_epoch 1") . + " --define " . sh_quote("_buildhost xcat-build") ); my @all_rpms = sort glob("$rpm_out/*.rpm"); @@ -265,11 +287,23 @@ Usage: $0 [options] --mock-uniqueext TXT Optional mock --uniqueext suffix to isolate concurrent builds --result-dir PATH Output RPM/SRPM directory (default: $result_dir) --log-dir PATH Log directory (default: $log_dir) + --build-timestamp EPOCH SOURCE_DATE_EPOCH for deterministic builds --skip-upstream-download Skip wget download step --skip-install Skip dnf install + smoke tests USAGE } +sub create_deterministic_mock_cfg { + my ($base_cfg, $epoch, $dir) = @_; + my $cfg_path = "$dir/mock-deterministic.cfg"; + open my $fh, '>', $cfg_path or die "Cannot write $cfg_path: $!\n"; + print $fh "include('/etc/mock/${base_cfg}.cfg')\n"; + print $fh "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n"; + print $fh "config_opts['environment']['ZERO_AR_DATE'] = '1'\n"; + close $fh; + return $cfg_path; +} + sub parse_spec { my ($path) = @_; open my $fh, '<', $path or die "Cannot open spec $path: $!\n"; diff --git a/xnba/make_deb.sh b/xnba/make_deb.sh index 87c12b4..05dce0b 100755 --- a/xnba/make_deb.sh +++ b/xnba/make_deb.sh @@ -1,3 +1,11 @@ #!/bin/bash +set -e -dpkg-buildpackage -uc -us -R./build/rules.fromBIN +if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + if [ -f "$REPO_ROOT/Gitepoch" ]; then + export SOURCE_DATE_EPOCH=$(cat "$REPO_ROOT/Gitepoch") + fi +fi + +dpkg-buildpackage -uc -us -R./build/rules.fromBIN diff --git a/xnba/mockbuild.pl b/xnba/mockbuild.pl index bda758d..1c799dd 100755 --- a/xnba/mockbuild.pl +++ b/xnba/mockbuild.pl @@ -20,6 +20,7 @@ my $mock_uniqueext = ''; my $result_dir = "$repo_root/build-output/list3/xnba-undi"; my $log_dir = "$repo_root/build-logs/list3/xnba-undi"; my $skip_install = 0; +my $build_timestamp; GetOptions( 'work-dir=s' => \$work_dir, @@ -28,6 +29,7 @@ GetOptions( 'result-dir=s' => \$result_dir, 'log-dir=s' => \$log_dir, 'skip-install!' => \$skip_install, + 'build-timestamp=i' => \$build_timestamp, ) or die usage(); die "Run as root (current uid=$>)\n" if $> != 0; @@ -46,6 +48,24 @@ if (!$mock_cfg) { $mock_cfg = resolve_mock_cfg($os_id, '10', $arch); } +my $SOURCE_DATE_EPOCH; +$SOURCE_DATE_EPOCH = $build_timestamp if defined $build_timestamp; +if (!$SOURCE_DATE_EPOCH && -f "$repo_root/Gitepoch") { + my $epoch_content = ''; + if (open my $efh, '<', "$repo_root/Gitepoch") { + $epoch_content = <$efh>; + close $efh; + chomp $epoch_content; + } + $SOURCE_DATE_EPOCH = $epoch_content; +} +unless ($SOURCE_DATE_EPOCH && $SOURCE_DATE_EPOCH =~ /^\d+$/) { + $SOURCE_DATE_EPOCH = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null`; + chomp $SOURCE_DATE_EPOCH; +} +$SOURCE_DATE_EPOCH = time() unless $SOURCE_DATE_EPOCH =~ /^\d+$/; +$ENV{SOURCE_DATE_EPOCH} = $SOURCE_DATE_EPOCH; + print_step("Configuration"); print "repo_root: $repo_root\n"; print "pkg_dir: $pkg_dir\n"; @@ -60,7 +80,8 @@ make_path($log_dir); print_step("Stage build environment"); remove_tree($work_dir) if -d $work_dir; -my $rpmbuild_top = "$work_dir/rpmbuild"; +my $rpmbuild_top = "/var/tmp/xcat-rpmbuild-xnba"; +remove_tree($rpmbuild_top) if -d $rpmbuild_top; for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) { make_path("$rpmbuild_top/$d"); } @@ -75,7 +96,8 @@ copy("$binary_dir/xnba.efi", "$src_dir/binary/xnba.efi") or die "Failed to copy xnba.efi: $!\n"; my $tarball = "$rpmbuild_top/SOURCES/xnba-$version.tar.gz"; -run("tar -C " . sh_quote($work_dir) . " -czf " . sh_quote($tarball) . " xnba-$version"); +run("tar --sort=name --owner=0 --group=0 --mtime=\@$SOURCE_DATE_EPOCH" . + " -C " . sh_quote($work_dir) . " -czf " . sh_quote($tarball) . " xnba-$version"); # Create simplified spec that uses pre-built binaries my $simple_spec = <<'SPEC'; @@ -120,6 +142,9 @@ print_step("Build RPM"); my $rpmbuild_cmd = join(' ', 'rpmbuild', '--define', sh_quote("_topdir $rpmbuild_top"), + '--define', sh_quote("use_source_date_epoch_as_buildtime 1"), + '--define', sh_quote("clamp_mtime_to_source_date_epoch 1"), + '--define', sh_quote("_buildhost xcat-build"), '-ba', sh_quote("$rpmbuild_top/SPECS/xnba-undi.spec"), ); @@ -149,6 +174,7 @@ Options: --result-dir PATH Output directory for RPMs --log-dir PATH Output directory for logs --skip-install Skip install verification + --build-timestamp EPOCH Unix timestamp for reproducible builds USAGE }