2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-04-25 05:21:26 +00:00

fix: Add scripts & patches for building in mock for EL10

Signed-off-by: Daniel Hilst Selli <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst Selli
2026-03-05 08:17:23 -03:00
parent 87d2b8fad2
commit fdf8393a2b
27 changed files with 4518 additions and 36 deletions

265
BUILD.md Normal file
View File

@@ -0,0 +1,265 @@
# Build Guide (`mockbuild-all.pl`)
This guide explains how to use `mockbuild-all.pl` to build, validate, and package xCAT dependencies and optional xCAT packages into a unified EL10 repository layout.
It also documents the operational flags for controlling build, install-check, collection, and packaging behavior.
# Purpose
`mockbuild-all.pl` is the top-level build orchestrator for generating a **unified xCAT repository**.
It builds required dependency RPMs and, by default, xCAT RPMs, then assembles:
- a binary RPM repo tree with repodata
- an SRPM repo tree with repodata
- one binary repo tarball and one SRPM repo tarball
# Historical Context
Historically, the deployment flow used separate repositories:
- `xcat-core` for xCAT packages
- `xcat-dep` for dependency packages
The current flow produces a single **unified `xcat` repository** containing all required packages together.
# Placeholder Conventions
This guide uses the following placeholders consistently:
- `<REPO_ROOT>`: xcat-dep repository root (example: `/root/xcat-dep`)
- `<XCAT_SOURCE>`: xCAT source root (example: `<REPO_ROOT>/xcat-source-code`)
- `<ARCH>`: output of `uname -m` (for example: `x86_64`, `ppc64le`)
- `<OS_ID>`: `ID` field from `/etc/os-release` (for example: `rhel`, `rocky`)
- `<REL>`: integer major release from `VERSION_ID` in `/etc/os-release` (for example: `10`)
- `<TARGET>`: `<OS_ID>+epel-<REL>-<ARCH>`
- `<RUN_ID>`: build run identifier (auto-generated if omitted)
# Build Pipeline Overview
`mockbuild-all.pl` orchestrates these build components in parallel:
- `<REPO_ROOT>/elilo/mockbuild.pl`
- `<REPO_ROOT>/grub2-xcat/mockbuild.pl`
- `<REPO_ROOT>/ipmitool/mockbuild.pl`
- `<REPO_ROOT>/syslinux/mockbuild.pl`
- `<REPO_ROOT>/goconserver/mockbuild.pl`
- `<REPO_ROOT>/mockbuild-perl-packages.pl`
- `<XCAT_SOURCE>/buildrpms.pl` (unless `--skip-xcat` is set)
Each build path uses `mock` for chroot isolation. Top-level steps are parallelized by `mockbuild-all.pl`, and perl dependency builds are also parallelized internally by `mockbuild-perl-packages.pl`.
`mockbuild-all.pl` does more than building RPMs. In a default run it performs these stages:
1. Optional chroot cleanup (`--scrub-all-chroots`)
2. Parallel build execution
3. Optional install/smoke checks inside child builders (disabled with `--skip-install`)
4. Binary RPM collection into `repo/<ARCH>/`
5. Source RPM collection into `repo-src/`
6. `createrepo --update` on both repo trees
7. Tarball creation for both repo trees
8. Summary generation (`summary.txt`)
# Skip and Control Flags
Use these flags to skip specific operations:
- `--skip-install`
- Skips install/smoke checks performed by child builder scripts after RPM build.
- `--skip-xcat`
- Skips `<XCAT_SOURCE>/buildrpms.pl` (xCAT package build step).
- `--skip-xcat-dep`
- Skips non-perl xcat-dep package builders (`elilo`, `grub2-xcat`, `ipmitool-xcat`, `syslinux-xcat`, `goconserver`).
- `--skip-perl`
- Skips `<REPO_ROOT>/mockbuild-perl-packages.pl`.
- `--skip-build`
- Skips all build steps; only runs collection/repo/tarball stages from existing artifact roots.
- `--skip-createrepo`
- Skips `createrepo --update`.
- `--skip-tarball`
- Skips tarball creation for both binary and SRPM repos.
- `--scrub-all-chroots`
- Runs `mock -r <TARGET> --scrub=all` before build and collection.
- `--collect-dir <PATH>`
- Adds extra artifact roots to the collection phase (repeatable).
- `--dry-run`
- Prints planned actions without executing them.
# Prerequisites
- Run as `root`.
- `mockbuild-all.pl` and package sources present under `<REPO_ROOT>`.
- xCAT sources present under `<XCAT_SOURCE>`.
Install baseline tooling:
```bash
dnf -y install perl perl-Parallel-ForkManager mock createrepo tar rpm-build rpmdevtools dnf-plugins-core wget git
```
If you will build xCAT packages (that is, you will **not** use `--skip-xcat`), install xCAT build dependencies:
```bash
cd <XCAT_SOURCE>
perl buildrpms.pl --install_deps
```
Validate mock config availability:
```bash
mock -r <TARGET> --print-root-path
```
# Target Resolution
`--target` is optional.
If `--target` is omitted, `mockbuild-all.pl` derives `<TARGET>` from:
- `/etc/os-release` (`ID`, `VERSION_ID`)
- `uname -m`
Equivalent derivation:
```text
<TARGET> = <OS_ID>+epel-<REL>-<ARCH>
```
`<TARGET>` is also passed to `mock` as the chroot/config identifier:
```text
mock -r <TARGET> ...
```
# Build Full Unified Repository (xCAT + Dependencies)
Use this mode to build dependency packages and xCAT packages together.
```bash
cd /root/xcat-dep
perl ./mockbuild-all.pl \
--repo-root /root/xcat-dep \
--xcat-source /root/xcat-dep/xcat-source-code \
--scrub-all-chroots
```
Notes:
- Install/smoke checks run by default inside child builders.
- Add `--skip-install` to skip those checks.
- `<RUN_ID>` is optional; when omitted it is timestamp-based.
# Build Unified Repository Without xCAT (`--skip-xcat`)
Use this mode to build dependency packages only and skip invoking `/root/xcat-dep/xcat-source-code/buildrpms.pl`.
```bash
cd /root/xcat-dep
perl ./mockbuild-all.pl \
--repo-root /root/xcat-dep \
--xcat-source /root/xcat-dep/xcat-source-code \
--scrub-all-chroots \
--skip-xcat \
--skip-install
```
Important behavior:
- `--skip-xcat` skips the xCAT build step, but collection still scans:
- `<XCAT_SOURCE>/dist/<TARGET>/rpms`
- If that path already has xCAT RPMs, they are included in the resulting unified repo.
# Common Build Modes
Full unified repo (xCAT + dependencies, with install/smoke checks):
```bash
cd <REPO_ROOT>
perl ./mockbuild-all.pl \
--repo-root <REPO_ROOT> \
--xcat-source <XCAT_SOURCE> \
--scrub-all-chroots
```
Full unified repo (xCAT + dependencies, skip install/smoke checks):
```bash
cd <REPO_ROOT>
perl ./mockbuild-all.pl \
--repo-root <REPO_ROOT> \
--xcat-source <XCAT_SOURCE> \
--scrub-all-chroots \
--skip-install
```
Dependency-only repo (skip xCAT package build):
```bash
cd <REPO_ROOT>
perl ./mockbuild-all.pl \
--repo-root <REPO_ROOT> \
--xcat-source <XCAT_SOURCE> \
--scrub-all-chroots \
--skip-xcat \
--skip-install
```
Collection-only pass from existing build artifacts:
```bash
cd <REPO_ROOT>
perl ./mockbuild-all.pl \
--repo-root <REPO_ROOT> \
--xcat-source <XCAT_SOURCE> \
--skip-build
```
# Output Artifacts and Paths
For each run:
- Binary repo path:
- `<REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/repo/<ARCH>/`
- SRPM repo path:
- `<REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/repo-src/`
- Run summary:
- `<REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/summary.txt`
- Binary repo tarball:
- `<REPO_ROOT>/build-output/mockbuild-all/mockbuild-all-<TARGET>-<RUN_ID>.tar.gz`
- SRPM repo tarball:
- `<REPO_ROOT>/build-output/mockbuild-all/mockbuild-all-<TARGET>-<RUN_ID>-srpm.tar.gz`
# Architecture Requirements
`mockbuild-all.pl` derives architecture from the build host:
- `<ARCH> = $(uname -m)`
Because of this, to build `ppc64le` artifacts you must run `mockbuild-all.pl` on a Power host where:
- `uname -m` returns `ppc64le`
- a matching mock config exists for `<TARGET>` (for example `rocky+epel-10-ppc64le`)
In short: build `ppc64le` packages on a Power machine.
# Validation Commands
```bash
cat <REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/summary.txt
ls -1 <REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/repo/<ARCH>/
ls -1 <REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/repo-src/
ls -1 <REPO_ROOT>/build-output/mockbuild-all/mockbuild-all-<TARGET>-<RUN_ID>.tar.gz
ls -1 <REPO_ROOT>/build-output/mockbuild-all/mockbuild-all-<TARGET>-<RUN_ID>-srpm.tar.gz
find <REPO_ROOT>/build-output/mockbuild-all/<RUN_ID>/build-logs -type f | sort
```
# Common Issues
- `Missing xCAT build script: .../buildrpms.pl`
- Ensure `<XCAT_SOURCE>` points to a valid xCAT source tree.
- `WARN: missing dep builder script, skipping: ...`
- Sync the repository; one or more package build scripts are missing.
- `mock target not found`
- Validate with `mock -r <TARGET> --print-root-path` and install the required mock config packages.
# References
- [mock project repository](https://github.com/rpm-software-management/mock)

View File

@@ -5,6 +5,7 @@ Version: 0.7
Release: 10
License: GPL
Vendor: Linux Networx Inc.
%undefine _hardened_build
Source: atftp_0.7.dfsg.orig.tar.gz
Source1: tftpd
Patch: atftp_0.7.dfsg-3.diff
@@ -12,6 +13,11 @@ Patch1: dfsg-3-to-multicast.diff
Patch2: dfsg-3-bigfiles.diff
Patch3: dfsg-3-to-winpaths.diff
Patch4: dfsg-3-mclistfix.diff
Patch5: dfsg-3-pthread-self-include.diff
BuildRequires: gcc
BuildRequires: make
BuildRequires: glibc-devel
Buildroot: /var/tmp/atftp-buildroot
Packager: Allen Reese <areese@lnxi.com>
Conflicts: tftp-server
@@ -38,11 +44,25 @@ files using the TFTP protocol.
%prep
%setup -n atftp-0.7.dfsg
%patch -p1
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
# Avoid argz_next redefinition with modern glibc extern inline semantics.
sed -i '/^#include <stdlib.h>$/a\
#ifdef __USE_EXTERN_INLINES\
#undef __USE_EXTERN_INLINES\
#endif' argz.c
# Disable glibc extern-inline argz bodies to prevent multiple definitions.
sed -i 's/^#ifdef __USE_EXTERN_INLINES/#if 0/' argz.h
# Force Strncpy to have a linkable external definition with modern GCC.
sed -i 's/^inline char \*Strncpy(/char *Strncpy(/' tftp_def.h
sed -i 's/^inline char \*Strncpy(/char *Strncpy(/' tftp_def.c
# Force tftpd_clientlist_ready to have a linkable external definition.
sed -i 's/^inline void tftpd_clientlist_ready(/void tftpd_clientlist_ready(/' tftpd.h
sed -i 's/^inline void tftpd_clientlist_ready(/void tftpd_clientlist_ready(/' tftpd_list.c
%build

View File

@@ -0,0 +1,11 @@
diff -Naur atftp-0.7.dfsg/argz.c atftp-0.7.dfsg-fixed/argz.c
--- atftp-0.7.dfsg/argz.c
+++ atftp-0.7.dfsg-fixed/argz.c
@@ -41,6 +41,9 @@
#include <stdlib.h>
+#ifdef __USE_EXTERN_INLINES
+#undef __USE_EXTERN_INLINES
+#endif
#include "argz.h"
char * argz_next (const char *argz, size_t argz_len, const char *entry)

View File

@@ -0,0 +1,11 @@
diff -Naur atftp-0.7.dfsg/logger.c atftp-0.7.dfsg-fixed/logger.c
--- atftp-0.7.dfsg/logger.c
+++ atftp-0.7.dfsg-fixed/logger.c
@@ -27,6 +27,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <pthread.h>
#include <netdb.h>
#include "logger.h"

View File

@@ -0,0 +1,32 @@
--- elilo/strops.h.orig 2003-08-19 13:47:46.000000000 -0300
+++ elilo/strops.h 2026-03-02 13:08:16.755263536 -0300
@@ -27,7 +27,6 @@
#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 CHAR8 *StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, UINTN count);
extern CHAR8 *strtok_simple(CHAR8 *in, CHAR8 c);
--- elilo/strops.c.orig 2010-11-09 21:11:07.000000000 -0200
+++ elilo/strops.c 2026-03-02 13:08:16.755263536 -0300
@@ -36,19 +36,6 @@
return (CHAR16 *)s;
}
-CHAR16 *
-StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size)
-{
- CHAR16 *res = dst;
-
- while (size && size-- && (*dst++ = *src++) != CHAR_NULL);
- /*
- * does the null padding
- */
- while (size && size-- > 0) *dst++ = CHAR_NULL;
-
- return res;
-}
CHAR8 *
StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size)

View File

@@ -17,6 +17,15 @@ BuildArch: noarch
Source0: elilo-3.14-source.tar.gz
Patch1: elilo-xcat.patch
Patch2: elilo-big-bzimage-limit.patch
Patch3: elilo-gnu-efi-strncpy-conflict.patch
Source4: elilo-xcat-3.14-6.noarch.rpm
BuildRequires: gcc
BuildRequires: make
BuildRequires: cpio
%if "%{_host_cpu}" != "ppc64le"
BuildRequires: gnu-efi
BuildRequires: gnu-efi-devel
%endif
%description
elilo with patches from the xCAT team. Most significantly, adds iPXE usage to the network support
@@ -26,18 +35,35 @@ elilo with patches from the xCAT team. Most significantly, adds iPXE usage to t
%setup -n elilo
%patch1 -p1
%patch2 -p1
%patch3 -p1
# EL10 gnu-efi installs linker scripts and crt0 objects under /usr/lib.
sed -i 's|^GNUEFILIB[[:space:]]*=.*|GNUEFILIB = /usr/lib|' Make.defaults
sed -i 's|^EFILIB[[:space:]]*=.*|EFILIB = /usr/lib|' Make.defaults
sed -i 's|^EFICRT0[[:space:]]*=.*|EFICRT0 = /usr/lib|' Make.defaults
%if "%{_host_cpu}" == "ppc64le"
# On ppc64le, reuse the prebuilt EFI payload from the tracked noarch package.
mkdir -p prebuilt
rpm2cpio %{SOURCE4} | (cd prebuilt && cpio -idm --quiet)
test -f prebuilt/tftpboot/xcat/elilo-x64.efi
%endif
%build
rm -rf %{buildroot}
%if "%{_host_cpu}" != "ppc64le"
make
%endif
%install
mkdir -p %{buildroot}/tftpboot/xcat
%if "%{_host_cpu}" == "ppc64le"
cp prebuilt/tftpboot/xcat/elilo-x64.efi %{buildroot}/tftpboot/xcat/elilo-x64.efi
%else
cp elilo.efi %{buildroot}/tftpboot/xcat/elilo-x64.efi
%endif
%post

346
elilo/mockbuild.pl Executable file
View File

@@ -0,0 +1,346 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(dirname);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
my $pkg_dir = "$repo_root/elilo";
my $spec_file = "$pkg_dir/elilo-xcat.spec";
my $source_url = 'https://downloads.sourceforge.net/project/elilo/elilo/elilo-3.14/elilo-3.14-all.tar.gz';
my $source_file = '';
my $work_dir = '/tmp/elilo-xcat-mockbuild';
my $mock_cfg = '';
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;
GetOptions(
'source-url=s' => \$source_url,
'source-file=s' => \$source_file,
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'skip-install!' => \$skip_install,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
die "Missing spec file: $spec_file\n" if !-f $spec_file;
for my $bin (qw(wget mock rpmbuild rpm dnf file bash grep)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
my ($version, @spec_assets) = parse_spec($spec_file);
die "Could not parse Version from $spec_file\n" if !$version;
if (!$source_file) {
$source_file = "elilo-$version-source.tar.gz";
}
my $source_path = "$pkg_dir/$source_file";
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = "${os_id}+epel-10-${arch}";
}
my $mock_uniqueext_opt = $mock_uniqueext ne ''
? ' --uniqueext ' . sh_quote($mock_uniqueext)
: '';
print_step("Configuration");
print "repo_root: $repo_root\n";
print "pkg_dir: $pkg_dir\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "mock_cfg: $mock_cfg\n";
print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n";
print "source_url: $source_url\n";
print "source_file:$source_file\n";
print "skip_install: $skip_install\n";
make_path($result_dir);
make_path($log_dir);
print_step("Mock config check");
run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null");
print_step("Download upstream source");
run("wget --spider " . sh_quote($source_url));
run("wget -O " . sh_quote($source_path) . " " . sh_quote($source_url));
normalize_source_archive($source_path, $version, $work_dir);
print_step("Verify spec assets");
for my $asset (@spec_assets) {
my $path = "$pkg_dir/$asset";
die "Missing required spec asset: $path\n" if !-f $path;
}
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";
for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) {
make_path("$prep_top/$d");
}
copy($spec_file, "$prep_top/SPECS/elilo-xcat.spec")
or die "Failed to copy spec to prep topdir: $!\n";
for my $asset (@spec_assets) {
copy("$pkg_dir/$asset", "$prep_top/SOURCES/$asset")
or die "Failed to copy $asset into prep SOURCES: $!\n";
}
print_step("Apply patches in %prep");
my $prep_log = "$log_dir/prep.log";
run(
"rpmbuild --define " . sh_quote("_topdir $prep_top") .
" -bp --nodeps " . sh_quote("$prep_top/SPECS/elilo-xcat.spec") .
" > " . sh_quote($prep_log) . " 2>&1"
);
my $patch_count = capture(
"grep -c '^Patch #' " . sh_quote($prep_log) . " || true"
);
print "Patch application check passed. Applied patches: $patch_count\n";
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 .
" --buildsrpm --spec " . sh_quote($spec_file) .
" --sources " . sh_quote($pkg_dir) .
" --resultdir " . sh_quote($srpm_out)
);
my @srpms = sort glob("$srpm_out/elilo-xcat-*.src.rpm");
die "SRPM not generated in $srpm_out\n" if !@srpms;
my $srpm = $srpms[-1];
print "SRPM: $srpm\n";
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 .
" --rebuild " . sh_quote($srpm) .
" --resultdir " . sh_quote($rpm_out)
);
my @all_rpms = sort glob("$rpm_out/*.rpm");
die "No RPMs generated in $rpm_out\n" if !@all_rpms;
my $main_rpm = '';
for my $rpm (@all_rpms) {
next if $rpm =~ /\.src\.rpm$/;
my $name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($rpm));
my $rarch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($rpm));
if ($name eq 'elilo-xcat' && $rarch eq 'noarch') {
$main_rpm = $rpm;
last;
}
}
die "Could not find main elilo-xcat noarch RPM in $rpm_out\n" if !$main_rpm;
print_step("Verify generated RPM");
my $rpm_name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($main_rpm));
my $rpm_arch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($main_rpm));
die "Unexpected RPM name: $rpm_name\n" if $rpm_name ne 'elilo-xcat';
die "Unexpected RPM arch: $rpm_arch (expected noarch)\n" if $rpm_arch ne 'noarch';
run(
"rpm -qpl " . sh_quote($main_rpm) .
" | grep -Fx /tftpboot/xcat/elilo-x64.efi >/dev/null"
);
print "Verified RPM name/arch/payload: $main_rpm\n";
print_step("Copy artifacts and logs");
for my $rpm (@all_rpms) {
copy($rpm, $result_dir) or die "Failed to copy $rpm to $result_dir: $!\n";
}
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$rpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/$log")
or die "Failed to copy $src to $log_dir: $!\n";
}
if (!$skip_install) {
print_step("Install RPM and run smoke tests");
run("dnf -y install " . sh_quote($main_rpm));
my $efi_file = '/tftpboot/xcat/elilo-x64.efi';
die "Missing installed EFI binary: $efi_file\n" if !-f $efi_file;
my $file_log = "$log_dir/smoke-file.log";
my $qf_log = "$log_dir/smoke-rpm-qf.log";
my $rc_file = run_capture_rc("file $efi_file", $file_log);
my $rc_qf = run_capture_rc("rpm -qf $efi_file", $qf_log);
die "Smoke check failed: file returned $rc_file\n" if $rc_file != 0;
die "Smoke check failed: rpm -qf returned $rc_qf\n" if $rc_qf != 0;
my $file_out = slurp($file_log);
my $qf_out = slurp($qf_log);
die "EFI file signature check failed:\n$file_out\n"
if $file_out !~ /(EFI application|PE32\+ executable)/i;
die "Installed file is not owned by elilo-xcat:\n$qf_out\n"
if $qf_out !~ /^elilo-xcat-/m;
my $summary = "$log_dir/smoke-summary.txt";
open my $sfh, '>', $summary or die "Cannot write $summary: $!\n";
print {$sfh} "efi_file=$efi_file\n";
print {$sfh} "rc_file=$rc_file\n";
print {$sfh} "rc_qf=$rc_qf\n";
close $sfh;
}
print_step("Completed");
print "Main RPM: $main_rpm\n";
print "Artifacts: $result_dir\n";
print "Logs: $log_dir\n";
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
--source-url URL Upstream tarball URL (default: $source_url)
--source-file FILE Source filename stored in elilo/ (default: inferred from spec version)
--work-dir PATH Temporary work dir (default: $work_dir)
--mock-cfg NAME Mock config (default: <ID>+epel-10-<ARCH>)
--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)
--skip-install Skip dnf install + smoke tests
USAGE
}
sub parse_spec {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open spec $path: $!\n";
my $version = '';
my @assets;
while (my $line = <$fh>) {
if ($line =~ /^Version:\s*(\S+)/) {
$version = $1;
}
if ($line =~ /^(?:Source|Patch)\d*:\s*(\S+)/) {
my $asset = $1;
push @assets, $asset;
}
}
close $fh;
@assets = map {
my $v = $_;
$v =~ s/%\{version\}/$version/g;
$v =~ s/%\{ver\}/$version/g;
$v;
} @assets;
return ($version, @assets);
}
sub normalize_source_archive {
my ($archive, $version, $work_base) = @_;
my $has_elilo = capture(
"tar -tzf " . sh_quote($archive) .
" | grep -E '^(\\./)?elilo/' | head -n1 || true"
);
return if $has_elilo ne '';
my $nested = capture(
"tar -tzf " . sh_quote($archive) .
" | grep -E '^(\\./)?elilo-$version-source\\.tar\\.gz\$' | head -n1 || true"
);
die "Downloaded archive does not contain elilo source payload: $archive\n"
if $nested eq '';
my $normalize_dir = "$work_base/source-normalize";
remove_tree($normalize_dir) if -d $normalize_dir;
make_path($normalize_dir);
run(
"tar -xzf " . sh_quote($archive) .
" -C " . sh_quote($normalize_dir) .
" " . sh_quote($nested)
);
my $nested_rel = $nested;
$nested_rel =~ s{^\./}{};
my $nested_path = "$normalize_dir/$nested_rel";
die "Failed to extract nested source archive: $nested_path\n"
if !-f $nested_path;
copy($nested_path, $archive)
or die "Failed to normalize source archive $archive: $!\n";
my $recheck = capture(
"tar -tzf " . sh_quote($archive) .
" | grep -E '^(\\./)?elilo/' | head -n1 || true"
);
die "Normalized source archive still missing elilo top-level tree: $archive\n"
if $recheck eq '';
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub sh_quote {
my ($s) = @_;
$s =~ s/'/'"'"'/g;
return "'$s'";
}
sub run {
my ($cmd) = @_;
print "+ $cmd\n";
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
print "+ $cmd\n";
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\nOutput:\n$out\n";
}
chomp $out;
return $out;
}
sub run_capture_rc {
my ($cmd, $log_file) = @_;
my $full = "$cmd > " . sh_quote($log_file) . " 2>&1";
print "+ $full\n";
my $rc = system($full);
return $rc == -1 ? 255 : ($rc >> 8);
}
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}

398
goconserver/mockbuild.pl Executable file
View File

@@ -0,0 +1,398 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
my $pkg_dir = "$repo_root/goconserver";
my $work_dir = '/tmp/goconserver-mockbuild';
my $mock_cfg = '';
my $mock_uniqueext = '';
my $result_dir = '';
my $log_dir = '';
my $src_rpm = '';
my $src_rpm_url = '';
my $skip_install = 0;
GetOptions(
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'src-rpm=s' => \$src_rpm,
'src-rpm-url=s' => \$src_rpm_url,
'skip-install!' => \$skip_install,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
die "Missing package directory: $pkg_dir\n" if !-d $pkg_dir;
for my $bin (qw(mock rpmbuild rpm dnf ldd bash grep tar wget sha256sum cut)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
my $has_bsdtar = command_exists('bsdtar');
if (!$has_bsdtar) {
for my $bin (qw(rpm2cpio cpio)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
}
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = "${os_id}+epel-10-${arch}";
}
my $mock_uniqueext_opt = $mock_uniqueext ne ''
? ' --uniqueext ' . sh_quote($mock_uniqueext)
: '';
if (!$result_dir) {
$result_dir = "$repo_root/build-output/list5/goconserver/$arch";
}
if (!$log_dir) {
$log_dir = "$repo_root/build-logs/list5/goconserver/$arch";
}
make_path($result_dir);
make_path($log_dir);
make_path($work_dir);
if ($src_rpm_url) {
my $dst = "$work_dir/" . basename($src_rpm_url);
print_step("Download source RPM");
run("wget --spider " . sh_quote($src_rpm_url));
run("wget -O " . sh_quote($dst) . " " . sh_quote($src_rpm_url));
my $sha = capture("sha256sum " . sh_quote($dst) . " | cut -d ' ' -f1");
open my $mfh, '>', "$log_dir/source-rpm.txt"
or die "Cannot write $log_dir/source-rpm.txt: $!\n";
print {$mfh} "url=$src_rpm_url\n";
print {$mfh} "path=$dst\n";
print {$mfh} "sha256=$sha\n";
close $mfh;
$src_rpm = $dst;
}
if (!$src_rpm) {
my @candidates;
push @candidates, glob("$repo_root/build-output/list5/goconserver/$arch/goconserver-*.src.rpm");
push @candidates, glob("$repo_root/goconserver-build-$arch/results/srpm/goconserver-*.src.rpm");
push @candidates, glob("$repo_root/goconserver-build-$arch/results/rpm/goconserver-*.src.rpm");
@candidates = sort @candidates;
$src_rpm = $candidates[-1] if @candidates;
}
die "Could not locate goconserver source RPM. Use --src-rpm or --src-rpm-url.\n"
if !$src_rpm || !-f $src_rpm;
print_step("Configuration");
print "repo_root: $repo_root\n";
print "pkg_dir: $pkg_dir\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "arch: $arch\n";
print "mock_cfg: $mock_cfg\n";
print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n";
print "src_rpm: $src_rpm\n";
print "skip_install:$skip_install\n";
print "extractor: " . ($has_bsdtar ? 'bsdtar' : 'rpm2cpio|cpio') . "\n";
print_step("Mock config check");
run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null");
print_step("Extract source RPM contents");
my $stage_dir = "$work_dir/stage";
remove_tree($stage_dir) if -d $stage_dir;
make_path($stage_dir);
if ($has_bsdtar) {
run("bsdtar -xf " . sh_quote($src_rpm) . " -C " . sh_quote($stage_dir));
} else {
my $extract_cmd =
"cd " . sh_quote($stage_dir) .
" && rpm2cpio " . sh_quote($src_rpm) .
" | cpio -idm --quiet";
run(
"bash -lc " .
sh_quote($extract_cmd)
);
}
my @specs = sort glob("$stage_dir/*.spec");
die "Expected exactly one spec in $stage_dir, found " . scalar(@specs) . "\n"
if @specs != 1;
my $spec_file = $specs[0];
my ($version, @assets) = parse_spec($spec_file);
die "Could not parse Version from $spec_file\n" if !$version;
die "No Source/Patch assets parsed from $spec_file\n" if !@assets;
for my $asset (@assets) {
my $path = "$stage_dir/$asset";
die "Missing extracted spec asset: $path\n" if !-f $path;
}
my @repack = grep { /goconserver-repack-.*\.tar\.gz$/ } @assets;
die "Expected goconserver-repack source tar from spec assets.\n" if !@repack;
my $repack_tar = "$stage_dir/$repack[0]";
print_step("Verify repack payload");
for my $required (
'/usr/bin/goconserver',
'/usr/bin/congo',
'/usr/lib/systemd/system/goconserver.service',
'/etc/goconserver/server.conf'
) {
my $rel = substr($required, 1);
run(
"tar -tzf " . sh_quote($repack_tar) .
" | grep -F " . sh_quote("./$rel") .
" >/dev/null"
);
}
print_step("Run %prep check");
my $prep_top = "$work_dir/prep";
remove_tree($prep_top) if -d $prep_top;
for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) {
make_path("$prep_top/$d");
}
copy($spec_file, "$prep_top/SPECS/" . basename($spec_file))
or die "Failed to copy spec for prep check: $!\n";
for my $asset (@assets) {
copy("$stage_dir/$asset", "$prep_top/SOURCES/$asset")
or die "Failed to copy $asset for prep check: $!\n";
}
run(
"rpmbuild --define " . sh_quote("_topdir $prep_top") .
" -bp --nodeps " . sh_quote("$prep_top/SPECS/" . basename($spec_file)) .
" > " . sh_quote("$log_dir/prep.log") . " 2>&1"
);
print_step("Build SRPM with mock");
my $srpm_out = "$work_dir/srpm";
remove_tree($srpm_out) if -d $srpm_out;
make_path($srpm_out);
run(
"mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt .
" --buildsrpm --spec " . sh_quote($spec_file) .
" --sources " . sh_quote($stage_dir) .
" --resultdir " . sh_quote($srpm_out) .
" > " . sh_quote("$log_dir/mock-buildsrpm.log") . " 2>&1"
);
my @srpms = sort glob("$srpm_out/goconserver-*.src.rpm");
die "SRPM not generated in $srpm_out\n" if !@srpms;
my $built_srpm = $srpms[-1];
print "SRPM: $built_srpm\n";
print_step("Rebuild RPM with mock");
my $rpm_out = "$work_dir/rpm";
remove_tree($rpm_out) if -d $rpm_out;
make_path($rpm_out);
run(
"mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt .
" --rebuild " . sh_quote($built_srpm) .
" --resultdir " . sh_quote($rpm_out) .
" > " . sh_quote("$log_dir/mock-rebuild.log") . " 2>&1"
);
my @all_rpms = sort glob("$rpm_out/*.rpm");
die "No RPMs generated in $rpm_out\n" if !@all_rpms;
my $main_rpm = '';
for my $rpm (@all_rpms) {
next if $rpm =~ /\.src\.rpm$/;
my $name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($rpm));
my $rarch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($rpm));
if ($name eq 'goconserver' && $rarch eq $arch) {
$main_rpm = $rpm;
last;
}
}
die "Could not find main goconserver RPM in $rpm_out\n" if !$main_rpm;
print_step("Verify generated RPM");
my $rpm_name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($main_rpm));
my $rpm_arch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($main_rpm));
die "Unexpected main RPM name: $rpm_name\n" if $rpm_name ne 'goconserver';
die "Unexpected main RPM arch: $rpm_arch (expected $arch)\n" if $rpm_arch ne $arch;
for my $required (
'/usr/bin/goconserver',
'/usr/bin/congo',
'/usr/lib/systemd/system/goconserver.service'
) {
run("rpm -qpl " . sh_quote($main_rpm) . " | grep -Fx " . sh_quote($required) . " >/dev/null");
}
print_step("Copy artifacts and logs");
for my $rpm (@all_rpms) {
copy($rpm, $result_dir) or die "Failed to copy $rpm to $result_dir: $!\n";
}
copy($built_srpm, $result_dir) or die "Failed to copy $built_srpm to $result_dir: $!\n";
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$rpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/$log") or die "Failed to copy $src to $log_dir: $!\n";
}
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$srpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/srpm-$log") or die "Failed to copy $src to $log_dir: $!\n";
}
if (!$skip_install) {
print_step("Install RPM and run smoke tests");
run("dnf -y install " . sh_quote($main_rpm));
my $bin_main = '/usr/bin/goconserver';
my $bin_cli = '/usr/bin/congo';
die "Missing installed binary: $bin_main\n" if !-x $bin_main;
die "Missing installed binary: $bin_cli\n" if !-x $bin_cli;
my $rc_help_main = run_capture_rc("$bin_main -h", "$log_dir/smoke-goconserver-help.log");
my $rc_help_cli = run_capture_rc("$bin_cli -h", "$log_dir/smoke-congo-help.log");
my $rc_ldd_main = run_capture_rc("ldd $bin_main", "$log_dir/smoke-goconserver-ldd.log");
my $rc_ldd_cli = run_capture_rc("ldd $bin_cli", "$log_dir/smoke-congo-ldd.log");
die "goconserver -h returned unexpected rc=$rc_help_main\n"
if $rc_help_main != 0 && $rc_help_main != 1;
die "congo -h returned unexpected rc=$rc_help_cli\n"
if $rc_help_cli != 0 && $rc_help_cli != 1;
die "ldd goconserver returned rc=$rc_ldd_main\n" if $rc_ldd_main != 0;
die "ldd congo returned rc=$rc_ldd_cli\n" if $rc_ldd_cli != 0;
my $help_main = slurp("$log_dir/smoke-goconserver-help.log");
my $help_cli = slurp("$log_dir/smoke-congo-help.log");
my $ldd_main = slurp("$log_dir/smoke-goconserver-ldd.log");
my $ldd_cli = slurp("$log_dir/smoke-congo-ldd.log");
die "goconserver help output missing usage text\n"
if $help_main !~ /usage|goconserver/i;
die "congo help output missing usage text\n"
if $help_cli !~ /usage|congo/i;
die "goconserver ldd output missing libc\n"
if $ldd_main !~ /libc/;
die "congo ldd output missing libc\n"
if $ldd_cli !~ /libc/;
open my $sfh, '>', "$log_dir/smoke-summary.txt"
or die "Cannot write $log_dir/smoke-summary.txt: $!\n";
print {$sfh} "binary_main=$bin_main\n";
print {$sfh} "binary_cli=$bin_cli\n";
print {$sfh} "rc_help_main=$rc_help_main\n";
print {$sfh} "rc_help_cli=$rc_help_cli\n";
print {$sfh} "rc_ldd_main=$rc_ldd_main\n";
print {$sfh} "rc_ldd_cli=$rc_ldd_cli\n";
close $sfh;
}
print_step("Completed");
print "Main RPM: $main_rpm\n";
print "Artifacts: $result_dir\n";
print "Logs: $log_dir\n";
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
--src-rpm PATH Source RPM containing goconserver.spec + repack tar
--src-rpm-url URL Optional URL to download source RPM before build
--work-dir PATH Temporary work dir (default: $work_dir)
--mock-cfg NAME Mock config (default: <ID>+epel-10-<ARCH>)
--mock-uniqueext TXT Optional mock --uniqueext suffix to isolate concurrent builds
--result-dir PATH Output RPM/SRPM directory (default: build-output/list5/goconserver/<ARCH>)
--log-dir PATH Log directory (default: build-logs/list5/goconserver/<ARCH>)
--skip-install Skip dnf install + smoke tests
USAGE
}
sub parse_spec {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open spec $path: $!\n";
my $version = '';
my @assets;
while (my $line = <$fh>) {
if ($line =~ /^Version:\s*(\S+)/) {
$version = $1;
}
if ($line =~ /^(?:Source|Patch)\d*:\s*(\S+)/) {
my $asset = $1;
push @assets, $asset;
}
}
close $fh;
@assets = map {
my $v = $_;
$v =~ s/%\{version\}/$version/g;
$v =~ s/%\{ver\}/$version/g;
$v;
} @assets;
return ($version, @assets);
}
sub command_exists {
my ($bin) = @_;
my $rc = system("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
return $rc == 0 ? 1 : 0;
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub sh_quote {
my ($s) = @_;
$s =~ s/'/'"'"'/g;
return "'$s'";
}
sub run {
my ($cmd) = @_;
print "+ $cmd\n";
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
print "+ $cmd\n";
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\nOutput:\n$out\n";
}
chomp $out;
return $out;
}
sub run_capture_rc {
my ($cmd, $log_file) = @_;
my $full = "$cmd > " . sh_quote($log_file) . " 2>&1";
print "+ $full\n";
my $rc = system($full);
return $rc == -1 ? 255 : ($rc >> 8);
}
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}

362
grub2-xcat/mockbuild.pl Executable file
View File

@@ -0,0 +1,362 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
my $pkg_dir = "$repo_root/grub2-xcat";
my $spec_file = "$pkg_dir/grub2-xcat.spec";
my $recompile_dir = "$repo_root/grub2-xcat.recompile";
my $resource_mode = 'reuse-grub2-res';
my $upstream_url = 'https://mirror.stream.centos.org/10-stream/BaseOS/source/tree/Packages/grub2-2.12-37.el10.src.rpm';
my $upstream_file = '';
my $work_dir = '/tmp/grub2-xcat-mockbuild';
my $mock_cfg = '';
my $mock_uniqueext = '';
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;
GetOptions(
'resource-mode=s' => \$resource_mode,
'upstream-url=s' => \$upstream_url,
'upstream-file=s' => \$upstream_file,
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'skip-install!' => \$skip_install,
'skip-upstream-download!' => \$skip_upstream_download,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
die "Missing spec file: $spec_file\n" if !-f $spec_file;
die "Missing recompile dir: $recompile_dir\n" if !-d $recompile_dir;
die "Invalid --resource-mode '$resource_mode'\n"
if $resource_mode ne 'reuse-grub2-res' && $resource_mode ne 'regenerate-from-el10-srcrpm';
die "Mode regenerate-from-el10-srcrpm is not supported in this script yet; use reuse-grub2-res on x86_64 first.\n"
if $resource_mode eq 'regenerate-from-el10-srcrpm';
for my $bin (qw(wget mock rpmbuild rpm dnf file bash tar sha256sum grep cmp cut)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
my ($version, @spec_assets) = parse_spec($spec_file);
die "Could not parse Version from $spec_file\n" if !$version;
if (!$upstream_file) {
$upstream_file = basename($upstream_url);
}
die "Could not derive upstream file name from URL: $upstream_url\n" if !$upstream_file;
my $upstream_path = "$recompile_dir/$upstream_file";
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = "${os_id}+epel-10-${arch}";
}
my $mock_uniqueext_opt = $mock_uniqueext ne ''
? ' --uniqueext ' . sh_quote($mock_uniqueext)
: '';
print_step("Configuration");
print "repo_root: $repo_root\n";
print "pkg_dir: $pkg_dir\n";
print "spec_file: $spec_file\n";
print "recompile_dir: $recompile_dir\n";
print "resource_mode: $resource_mode\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "mock_cfg: $mock_cfg\n";
print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n";
print "upstream_url: $upstream_url\n";
print "upstream_file: $upstream_file\n";
print "skip_install: $skip_install\n";
print "skip_upstream_download: $skip_upstream_download\n";
make_path($result_dir);
make_path($log_dir);
print_step("Mock config check");
run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null");
if (!$skip_upstream_download) {
print_step("Download upstream source RPM");
run("wget --spider " . sh_quote($upstream_url));
run("wget -O " . sh_quote($upstream_path) . " " . sh_quote($upstream_url));
my $sha = capture("sha256sum " . sh_quote($upstream_path) . " | cut -d ' ' -f1");
my $meta_file = "$log_dir/upstream-source.txt";
open my $mfh, '>', $meta_file or die "Cannot write $meta_file: $!\n";
print {$mfh} "url=$upstream_url\n";
print {$mfh} "file=$upstream_path\n";
print {$mfh} "sha256=$sha\n";
close $mfh;
print "Downloaded upstream source rpm: $upstream_path\n";
print "SHA256: $sha\n";
}
print_step("Verify grub2 resource payload");
my $resource_tar = "$pkg_dir/grub2-res.tar.gz";
die "Missing required resource tarball: $resource_tar\n" if !-f $resource_tar;
run(
"tar -tzf " . sh_quote($resource_tar) .
" | grep -F 'powerpc-ieee1275/' >/dev/null"
);
run(
"tar -tzf " . sh_quote($resource_tar) .
" | grep -F 'powerpc-ieee1275/core.elf' >/dev/null"
);
print_step("Verify spec assets");
for my $asset (@spec_assets) {
my $path = "$pkg_dir/$asset";
die "Missing required spec asset: $path\n" if !-f $path;
}
print "Verified " . scalar(@spec_assets) . " Source/Patch assets from spec.\n";
print_step("Stage files for prep check");
remove_tree($work_dir) if -d $work_dir;
my $prep_top = "$work_dir/prep";
for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) {
make_path("$prep_top/$d");
}
copy($spec_file, "$prep_top/SPECS/grub2-xcat.spec")
or die "Failed to copy spec to prep topdir: $!\n";
for my $asset (@spec_assets) {
copy("$pkg_dir/$asset", "$prep_top/SOURCES/$asset")
or die "Failed to copy $asset into prep SOURCES: $!\n";
}
print_step("Apply %prep flow");
my $prep_log = "$log_dir/prep.log";
run(
"rpmbuild --define " . sh_quote("_topdir $prep_top") .
" -bp --nodeps " . sh_quote("$prep_top/SPECS/grub2-xcat.spec") .
" > " . sh_quote($prep_log) . " 2>&1"
);
my $patch_count = capture("grep -c '^Patch #' " . sh_quote($prep_log) . " || true");
print "Prep dry run passed. Applied patches: $patch_count\n";
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 .
" --buildsrpm --spec " . sh_quote($spec_file) .
" --sources " . sh_quote($pkg_dir) .
" --resultdir " . sh_quote($srpm_out)
);
my @srpms = sort glob("$srpm_out/grub2-xcat-*.src.rpm");
die "SRPM not generated in $srpm_out\n" if !@srpms;
my $srpm = $srpms[-1];
print "SRPM: $srpm\n";
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 .
" --rebuild " . sh_quote($srpm) .
" --resultdir " . sh_quote($rpm_out)
);
my @all_rpms = sort glob("$rpm_out/*.rpm");
die "No RPMs generated in $rpm_out\n" if !@all_rpms;
my $main_rpm = '';
for my $rpm (@all_rpms) {
next if $rpm =~ /\.src\.rpm$/;
my $name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($rpm));
my $rarch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($rpm));
if ($name eq 'grub2-xcat' && $rarch eq 'noarch') {
$main_rpm = $rpm;
last;
}
}
die "Could not find main grub2-xcat noarch RPM in $rpm_out\n" if !$main_rpm;
print_step("Verify generated RPM");
my $rpm_name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($main_rpm));
my $rpm_arch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($main_rpm));
die "Unexpected RPM name: $rpm_name\n" if $rpm_name ne 'grub2-xcat';
die "Unexpected RPM arch: $rpm_arch (expected noarch)\n" if $rpm_arch ne 'noarch';
run(
"rpm -qpl " . sh_quote($main_rpm) .
" | grep -F '/tftpboot/boot/grub2/powerpc-ieee1275/' >/dev/null"
);
run(
"rpm -qpl " . sh_quote($main_rpm) .
" | grep -Fx /tftpboot/boot/grub2/powerpc-ieee1275/core.elf >/dev/null"
);
print "Verified RPM name/arch/payload: $main_rpm\n";
print_step("Copy artifacts and logs");
for my $rpm (@all_rpms) {
copy($rpm, $result_dir) or die "Failed to copy $rpm to $result_dir: $!\n";
}
copy($srpm, $result_dir) or die "Failed to copy $srpm to $result_dir: $!\n";
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$rpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/$log")
or die "Failed to copy $src to $log_dir: $!\n";
}
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$srpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/srpm-$log")
or die "Failed to copy $src to $log_dir: $!\n";
}
if (!$skip_install) {
print_step("Install RPM and run smoke tests");
run("dnf -y install " . sh_quote($main_rpm));
my $core = '/tftpboot/boot/grub2/powerpc-ieee1275/core.elf';
my $grub2ppc = '/tftpboot/boot/grub2/grub2.ppc';
die "Missing installed core image: $core\n" if !-f $core;
die "Missing installed post script output: $grub2ppc\n" if !-f $grub2ppc;
my $file_core_log = "$log_dir/smoke-file-core.log";
my $file_ppc_log = "$log_dir/smoke-file-grub2ppc.log";
my $qf_log = "$log_dir/smoke-rpm-qf.log";
my $rc_file_core = run_capture_rc("file $core", $file_core_log);
my $rc_file_ppc = run_capture_rc("file $grub2ppc", $file_ppc_log);
my $rc_qf = run_capture_rc("rpm -qf $core", $qf_log);
my $rc_cmp = run_capture_rc("cmp -s $core $grub2ppc", "$log_dir/smoke-cmp.log");
die "Smoke check failed: file core returned $rc_file_core\n" if $rc_file_core != 0;
die "Smoke check failed: file grub2.ppc returned $rc_file_ppc\n" if $rc_file_ppc != 0;
die "Smoke check failed: rpm -qf returned $rc_qf\n" if $rc_qf != 0;
die "Smoke check failed: core.elf and grub2.ppc differ (cmp rc=$rc_cmp)\n" if $rc_cmp != 0;
my $core_out = slurp($file_core_log);
my $qf_out = slurp($qf_log);
die "Core image signature check failed:\n$core_out\n"
if $core_out !~ /ELF|data/i;
die "Installed core image is not owned by grub2-xcat:\n$qf_out\n"
if $qf_out !~ /^grub2-xcat-/m;
my $summary = "$log_dir/smoke-summary.txt";
open my $sfh, '>', $summary or die "Cannot write $summary: $!\n";
print {$sfh} "core=$core\n";
print {$sfh} "grub2ppc=$grub2ppc\n";
print {$sfh} "rc_file_core=$rc_file_core\n";
print {$sfh} "rc_file_ppc=$rc_file_ppc\n";
print {$sfh} "rc_qf=$rc_qf\n";
print {$sfh} "rc_cmp=$rc_cmp\n";
close $sfh;
}
print_step("Completed");
print "Main RPM: $main_rpm\n";
print "Artifacts: $result_dir\n";
print "Logs: $log_dir\n";
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
--resource-mode MODE Build mode: reuse-grub2-res|regenerate-from-el10-srcrpm (default: $resource_mode)
--upstream-url URL Upstream grub2 source RPM URL (default: $upstream_url)
--upstream-file FILE Source RPM filename stored in grub2-xcat.recompile/ (default: basename of URL)
--work-dir PATH Temporary work dir (default: $work_dir)
--mock-cfg NAME Mock config (default: <ID>+epel-10-<ARCH>)
--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)
--skip-upstream-download Skip wget of upstream source RPM
--skip-install Skip dnf install + smoke tests
USAGE
}
sub parse_spec {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open spec $path: $!\n";
my $version = '';
my @assets;
while (my $line = <$fh>) {
if ($line =~ /^Version:\s*(\S+)/) {
$version = $1;
}
if ($line =~ /^(?:Source|Patch)\d*:\s*(\S+)/) {
my $asset = $1;
push @assets, $asset;
}
}
close $fh;
@assets = map {
my $v = $_;
$v =~ s/%\{version\}/$version/g;
$v =~ s/%\{ver\}/$version/g;
$v;
} @assets;
return ($version, @assets);
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub sh_quote {
my ($s) = @_;
$s =~ s/'/'"'"'/g;
return "'$s'";
}
sub run {
my ($cmd) = @_;
print "+ $cmd\n";
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
print "+ $cmd\n";
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\nOutput:\n$out\n";
}
chomp $out;
return $out;
}
sub run_capture_rc {
my ($cmd, $log_file) = @_;
my $full = "$cmd > " . sh_quote($log_file) . " 2>&1";
print "+ $full\n";
my $rc = system($full);
return $rc == -1 ? 255 : ($rc >> 8);
}
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}

View File

@@ -0,0 +1,13 @@
diff --git a/include/ipmitool/ipmi_intf.h b/include/ipmitool/ipmi_intf.h
index 063fdd5..fcf5937 100644
--- a/include/ipmitool/ipmi_intf.h
+++ b/include/ipmitool/ipmi_intf.h
@@ -262,6 +262,8 @@ struct ipmi_intf {
struct ipmi_intf * ipmi_intf_load(char * name);
void ipmi_intf_print(struct ipmi_intf_support * intflist);
+uint16_t ipmi_intf_get_max_request_data_size(struct ipmi_intf * intf);
+uint16_t ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf);
void ipmi_intf_session_set_hostname(struct ipmi_intf * intf, char * hostname);
void ipmi_intf_session_set_username(struct ipmi_intf * intf, char * username);
void ipmi_intf_session_set_password(struct ipmi_intf * intf, char * password);

View File

@@ -23,6 +23,7 @@ Patch12: 0012-CVE-2020-5208.patch
Patch13: 0013-quanta-oem-support.patch
Patch14: 0014-lanplus-cipher-retry.patch
Patch15: 0015-lanplus-Cleanup.-Refix-6dec83ff-fix-be2c0c4b.patch
Patch16: 0016-el10-gcc14-missing-intf-getters.patch
Patch80: ipmitool-%{version}-saneretry.patch
Patch82: ipmitool-%{version}-rflash.patch
@@ -73,6 +74,7 @@ fi
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch80 -p1
%patch82 -p1
%patch83 -p1
@@ -475,4 +477,3 @@ fi
* Sun Mar 30 2003 <duncan@iceblink.org> 1.0-1
- Initial release.

357
ipmitool/mockbuild.pl Executable file
View File

@@ -0,0 +1,357 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
my $pkg_dir = "$repo_root/ipmitool";
my $spec_file = "$pkg_dir/ipmitool.spec";
my $source_url = 'https://github.com/ipmitool/ipmitool/archive/refs/tags/IPMITOOL_1_8_18.tar.gz';
my $source_file = '';
my $work_dir = '/tmp/ipmitool-xcat-mockbuild';
my $mock_cfg = '';
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;
GetOptions(
'source-url=s' => \$source_url,
'source-file=s' => \$source_file,
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'skip-install!' => \$skip_install,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
die "Missing spec file: $spec_file\n" if !-f $spec_file;
for my $bin (qw(wget mock rpmbuild rpm dnf ldd bash)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
my ($version, @spec_assets) = parse_spec($spec_file);
die "Could not parse Version from $spec_file\n" if !$version;
if (!$source_file) {
$source_file = "ipmitool-$version.tar.gz";
}
my $source_path = "$pkg_dir/$source_file";
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = "${os_id}+epel-10-${arch}";
}
my $mock_uniqueext_opt = $mock_uniqueext ne ''
? ' --uniqueext ' . sh_quote($mock_uniqueext)
: '';
print_step("Configuration");
print "repo_root: $repo_root\n";
print "pkg_dir: $pkg_dir\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "mock_cfg: $mock_cfg\n";
print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n";
print "source_url: $source_url\n";
print "source_file:$source_file\n";
print "skip_install: $skip_install\n";
make_path($result_dir);
make_path($log_dir);
print_step("Mock config check");
run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null");
print_step("Download upstream source");
run("wget --spider " . sh_quote($source_url));
run("wget -O " . sh_quote($source_path) . " " . sh_quote($source_url));
normalize_source_archive($source_path, $version, $work_dir);
print_step("Verify spec assets");
for my $asset (@spec_assets) {
my $path = "$pkg_dir/$asset";
die "Missing required spec asset: $path\n" if !-f $path;
}
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";
for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) {
make_path("$prep_top/$d");
}
copy($spec_file, "$prep_top/SPECS/ipmitool.spec")
or die "Failed to copy spec to prep topdir: $!\n";
for my $asset (@spec_assets) {
copy("$pkg_dir/$asset", "$prep_top/SOURCES/$asset")
or die "Failed to copy $asset into prep SOURCES: $!\n";
}
print_step("Apply patches in %prep");
my $prep_log = "$log_dir/prep.log";
run(
"rpmbuild --define " . sh_quote("_topdir $prep_top") .
" -bp --nodeps " . sh_quote("$prep_top/SPECS/ipmitool.spec") .
" > " . sh_quote($prep_log) . " 2>&1"
);
my $patch_count = capture(
"grep -c '^Patch #' " . sh_quote($prep_log) . " || true"
);
print "Patch application check passed. Applied patches: $patch_count\n";
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 .
" --buildsrpm --spec " . sh_quote($spec_file) .
" --sources " . sh_quote($pkg_dir) .
" --resultdir " . sh_quote($srpm_out)
);
my @srpms = sort glob("$srpm_out/ipmitool-xcat-*.src.rpm");
die "SRPM not generated in $srpm_out\n" if !@srpms;
my $srpm = $srpms[-1];
print "SRPM: $srpm\n";
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 .
" --rebuild " . sh_quote($srpm) .
" --resultdir " . sh_quote($rpm_out)
);
my @arch_rpms = sort glob("$rpm_out/*.${arch}.rpm");
die "No architecture RPMs generated in $rpm_out\n" if !@arch_rpms;
my $main_rpm = '';
for my $rpm (@arch_rpms) {
my $name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($rpm));
if ($name eq 'ipmitool-xcat') {
$main_rpm = $rpm;
last;
}
}
die "Could not find main ipmitool-xcat RPM in $rpm_out\n" if !$main_rpm;
print_step("Verify generated RPM");
my $rpm_name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($main_rpm));
my $rpm_arch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($main_rpm));
die "Unexpected RPM name: $rpm_name\n" if $rpm_name ne 'ipmitool-xcat';
die "Unexpected RPM arch: $rpm_arch (expected $arch)\n" if $rpm_arch ne $arch;
run(
"rpm -qpl " . sh_quote($main_rpm) .
" | grep -Fx /opt/xcat/bin/ipmitool-xcat >/dev/null"
);
print "Verified RPM name/arch/payload: $main_rpm\n";
print_step("Copy artifacts and logs");
for my $rpm (@arch_rpms) {
copy($rpm, $result_dir) or die "Failed to copy $rpm to $result_dir: $!\n";
}
copy($srpm, $result_dir) or die "Failed to copy $srpm to $result_dir: $!\n";
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$rpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/$log")
or die "Failed to copy $src to $log_dir: $!\n";
}
if (!$skip_install) {
print_step("Install RPM and run smoke tests");
run("dnf -y install " . sh_quote($main_rpm));
my $bin = '/opt/xcat/bin/ipmitool-xcat';
die "Missing installed binary: $bin\n" if !-x $bin;
my $help_short_log = "$log_dir/smoke-help-short.log";
my $help_long_log = "$log_dir/smoke-help-long.log";
my $version_log = "$log_dir/smoke-version.log";
my $open_log = "$log_dir/smoke-open-mc-info.log";
my $ldd_log = "$log_dir/smoke-ldd.log";
my $rc_help_short = run_capture_rc("$bin -h", $help_short_log);
my $rc_help_long = run_capture_rc("$bin --help", $help_long_log);
my $rc_version = run_capture_rc("$bin -V", $version_log);
my $rc_open = run_capture_rc("$bin -I open mc info", $open_log);
my $rc_ldd = run_capture_rc("ldd $bin", $ldd_log);
die "Smoke check failed: -h returned $rc_help_short\n" if $rc_help_short != 0;
die "Smoke check failed: -V returned $rc_version\n" if $rc_version != 0;
die "Smoke check failed: ldd returned $rc_ldd\n" if $rc_ldd != 0;
my $help_short_out = slurp($help_short_log);
my $help_long_out = slurp($help_long_log);
my $version_out = slurp($version_log);
my $open_out = slurp($open_log);
my $ldd_out = slurp($ldd_log);
die "Short help output does not contain usage text\n"
if $help_short_out !~ /usage:/i;
die "Long help output does not contain usage text\n"
if $help_long_out !~ /usage:/i;
die "Long help returned unexpected rc=$rc_help_long (expected 0 or 1)\n"
if $rc_help_long != 0 && $rc_help_long != 1;
die "Version output missing expected version string\n"
if $version_out !~ /ipmitool-xcat version \Q$version\E/i;
die "ldd output missing libcrypto dependency\n"
if $ldd_out !~ /libcrypto/;
die "Expected no-IPMI failure did not occur; rc=$rc_open\n"
if $rc_open == 0;
die "No-IPMI probe failed with unexpected output:\n$open_out\n"
if $open_out !~ m{Could not open device|/dev/ipmi};
my $summary = "$log_dir/smoke-summary.txt";
open my $sfh, '>', $summary or die "Cannot write $summary: $!\n";
print {$sfh} "binary=$bin\n";
print {$sfh} "rc_help_short=$rc_help_short\n";
print {$sfh} "rc_help_long=$rc_help_long\n";
print {$sfh} "rc_version=$rc_version\n";
print {$sfh} "rc_open=$rc_open\n";
print {$sfh} "rc_ldd=$rc_ldd\n";
close $sfh;
}
print_step("Completed");
print "Main RPM: $main_rpm\n";
print "Artifacts: $result_dir\n";
print "Logs: $log_dir\n";
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
--source-url URL Upstream tarball URL (default: $source_url)
--source-file FILE Source filename stored in ipmitool/ (default: inferred from spec version)
--work-dir PATH Temporary work dir (default: $work_dir)
--mock-cfg NAME Mock config (default: <ID>+epel-10-<ARCH>)
--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)
--skip-install Skip dnf install + smoke tests
USAGE
}
sub parse_spec {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open spec $path: $!\n";
my $version = '';
my @assets;
while (my $line = <$fh>) {
if ($line =~ /^Version:\s*(\S+)/) {
$version = $1;
}
if ($line =~ /^(?:Source|Patch)\d*:\s*(\S+)/) {
my $asset = $1;
push @assets, $asset;
}
}
close $fh;
@assets = map {
my $v = $_;
$v =~ s/%\{version\}/$version/g;
$v =~ s/%\{ver\}/$version/g;
$v;
} @assets;
return ($version, @assets);
}
sub normalize_source_archive {
my ($archive, $version, $work_base) = @_;
my $normalize_dir = "$work_base/source-normalize";
remove_tree($normalize_dir) if -d $normalize_dir;
make_path($normalize_dir);
run("tar -xzf " . sh_quote($archive) . " -C " . sh_quote($normalize_dir));
my @entries = grep { $_ !~ m{/\.\.?$} } glob("$normalize_dir/*");
die "Unexpected archive layout in $archive\n" if @entries != 1;
my $top_path = $entries[0];
die "Unexpected non-directory top-level entry in $archive: $top_path\n"
if !-d $top_path;
my $expected_top = "ipmitool-$version";
my $actual_top = basename($top_path);
if ($actual_top ne $expected_top) {
my $new_path = "$normalize_dir/$expected_top";
run("rm -rf " . sh_quote($new_path));
run("mv " . sh_quote($top_path) . " " . sh_quote($new_path));
}
# Repack using the expected top-level directory required by the spec.
run(
"tar -C " . sh_quote($normalize_dir) .
" -czf " . sh_quote($archive) .
" " . sh_quote($expected_top)
);
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub sh_quote {
my ($s) = @_;
$s =~ s/'/'"'"'/g;
return "'$s'";
}
sub run {
my ($cmd) = @_;
print "+ $cmd\n";
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
print "+ $cmd\n";
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\nOutput:\n$out\n";
}
chomp $out;
return $out;
}
sub run_capture_rc {
my ($cmd, $log_file) = @_;
my $full = "$cmd > " . sh_quote($log_file) . " 2>&1";
print "+ $full\n";
my $rc = system($full);
return $rc == -1 ? 255 : ($rc >> 8);
}
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}

840
mockbuild-all.pl Executable file
View File

@@ -0,0 +1,840 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path cwd);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Find qw(find);
use File::Path qw(make_path);
use Getopt::Long qw(GetOptions);
use Parallel::ForkManager;
use POSIX qw(strftime);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path($script_dir);
my $xcat_src = "$repo_root/xcat-source-code";
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 $skip_install = 0;
my $skip_build = 0;
my $skip_xcat_dep = 0;
my $skip_perl = 0;
my $skip_xcat = 0;
my $skip_createrepo = 0;
my $skip_tarball = 0;
my $skip_dhcp = 0;
my $scrub_all_chroots = 0;
my $dry_run = 0;
my $dhcp_repo_url = 'https://github.com/VersatusHPC/rpms-dhcp.git';
my $dhcp_repo_ref = 'master';
my $dhcp_source_dir = '';
my @extra_collect_dirs;
GetOptions(
'repo-root=s' => \$repo_root,
'xcat-source=s' => \$xcat_src,
'output-root=s' => \$output_root,
'target=s' => \$target,
'nproc=i' => \$nproc,
'parallel-builds=i' => \$parallel_builds,
'run-id=s' => \$run_id,
'skip-install!' => \$skip_install,
'skip-build!' => \$skip_build,
'skip-xcat-dep!' => \$skip_xcat_dep,
'skip-perl!' => \$skip_perl,
'skip-xcat!' => \$skip_xcat,
'skip-createrepo!' => \$skip_createrepo,
'skip-tarball!' => \$skip_tarball,
'skip-dhcp!' => \$skip_dhcp,
'scrub-all-chroots!' => \$scrub_all_chroots,
'dhcp-repo-url=s' => \$dhcp_repo_url,
'dhcp-repo-ref=s' => \$dhcp_repo_ref,
'dhcp-source-dir=s' => \$dhcp_source_dir,
'collect-dir=s@' => \@extra_collect_dirs,
'dry-run!' => \$dry_run,
) or die usage();
die "Run as root (uid=$>)\n" if $> != 0;
die "--parallel-builds must be >= 1\n"
if defined($parallel_builds) && $parallel_builds < 1;
$repo_root = abs_path($repo_root);
$xcat_src = resolve_xcat_source($xcat_src, $repo_root);
my $arch = capture('uname -m');
my %os = read_os_release('/etc/os-release');
my $os_id = $os{ID} // '';
my $version_id = $os{VERSION_ID} // '';
my ($rel) = $version_id =~ /^(\d+)/;
die "Could not resolve ID from /etc/os-release\n" if $os_id eq '';
die "Could not resolve major release from VERSION_ID='$version_id' in /etc/os-release\n"
if !defined($rel) || $rel eq '';
if (!$target) {
$target = "${os_id}+epel-${rel}-${arch}";
}
my $target_rel = parse_target_rel($target);
my $dhcp_auto_enabled = defined($target_rel) && $target_rel eq '10' ? 1 : 0;
my $dhcp_enabled = (!$skip_dhcp && $dhcp_auto_enabled) ? 1 : 0;
my $dhcp_effective_source = '';
my $dhcp_commit = '';
my @dhcp_srpm_collect_roots;
if (!$dhcp_auto_enabled && !$skip_dhcp) {
print "INFO: DHCP build step disabled for non-EL10 target '$target'.\n";
}
for my $bin (qw(perl uname createrepo tar find rpm)) {
require_command($bin);
}
require_command('mock') if $scrub_all_chroots;
if ($dhcp_enabled && !$skip_build) {
require_command('git');
require_command('mock');
require_command('rpmdev-spectool');
}
my $run_root = "$output_root/$run_id";
my $build_root = "$run_root/build-results";
my $log_root = "$run_root/build-logs";
my $repo_dir = "$run_root/repo/$arch";
my $summary_file = "$run_root/summary.txt";
my $tarball = "$output_root/mockbuild-all-$target-$run_id.tar.gz";
my $srpm_repo_dir = "$run_root/repo-src";
my $srpm_tarball = "$output_root/mockbuild-all-$target-$run_id-srpm.tar.gz";
my @dep_builders = (
{ name => 'elilo-xcat', script => "$repo_root/elilo/mockbuild.pl" },
{ name => 'grub2-xcat', script => "$repo_root/grub2-xcat/mockbuild.pl" },
{ name => 'ipmitool-xcat', script => "$repo_root/ipmitool/mockbuild.pl" },
{ name => 'syslinux-xcat', script => "$repo_root/syslinux/mockbuild.pl" },
{ name => 'goconserver', script => "$repo_root/goconserver/mockbuild.pl" },
);
my $perl_builder = "$repo_root/mockbuild-perl-packages.pl";
die "Missing xCAT build script: $xcat_src/buildrpms.pl\n"
if !$skip_xcat && !-f "$xcat_src/buildrpms.pl";
my @active_dep_builders;
for my $b (@dep_builders) {
if (-f $b->{script}) {
push @active_dep_builders, $b;
next;
}
print "WARN: missing dep builder script, skipping: $b->{script}\n";
}
die "Missing perl builder script: $perl_builder\n"
if !$skip_perl && !$perl_builder;
if (!$dry_run) {
make_path($build_root, $log_root, $repo_dir, $srpm_repo_dir);
}
print_step("Configuration");
print "repo_root: $repo_root\n";
print "xcat_source: $xcat_src\n";
print "output_root: $output_root\n";
print "run_root: $run_root\n";
print "arch: $arch\n";
print "os_id: $os_id\n";
print "version_id: $version_id\n";
print "rel: $rel\n";
print "target: $target\n";
print "target_rel: " . (defined($target_rel) ? $target_rel : 'unknown') . "\n";
print "nproc: $nproc\n";
print "parallel_builds: " . (defined($parallel_builds) ? $parallel_builds : 'auto') . "\n";
print "skip_build: $skip_build\n";
print "skip_xcat_dep: $skip_xcat_dep\n";
print "skip_perl: $skip_perl\n";
print "skip_xcat: $skip_xcat\n";
print "skip_dhcp: $skip_dhcp\n";
print "dhcp_enabled: $dhcp_enabled\n";
print "dhcp_repo_url: $dhcp_repo_url\n";
print "dhcp_repo_ref: $dhcp_repo_ref\n";
print "dhcp_source_dir: " . ($dhcp_source_dir ne '' ? $dhcp_source_dir : '(auto)') . "\n";
print "skip_install: $skip_install\n";
print "skip_createrepo: $skip_createrepo\n";
print "skip_tarball: $skip_tarball\n";
print "scrub_all_chroots:$scrub_all_chroots\n";
print "dry_run: $dry_run\n";
print "perl_builder: $perl_builder\n";
print "tarball: $tarball\n";
print "srpm_repo_dir: $srpm_repo_dir\n";
print "srpm_tarball: $srpm_tarball\n";
my @collect_roots;
if ($dhcp_enabled && !$skip_build) {
($dhcp_effective_source, $dhcp_commit) = prepare_dhcp_source(
run_root => $run_root,
log_root => "$log_root/dhcpd",
repo_url => $dhcp_repo_url,
repo_ref => $dhcp_repo_ref,
source_dir => $dhcp_source_dir,
);
} elsif ($dhcp_enabled && $skip_build && $dhcp_source_dir ne '') {
$dhcp_effective_source = eval { abs_path($dhcp_source_dir) } || $dhcp_source_dir;
$dhcp_commit = '(skip-build)';
}
if ($dhcp_enabled) {
print "dhcp_source: " . ($dhcp_effective_source ne '' ? $dhcp_effective_source : '(pending)') . "\n";
print "dhcp_commit: " . ($dhcp_commit ne '' ? $dhcp_commit : '(pending)') . "\n";
}
if ($scrub_all_chroots) {
run_step(
step => "Scrub all chroots for target $target",
cmd => "mock -r " . sh_quote($target) . " --scrub=all",
log => "$log_root/scrub-all-chroots.log",
);
}
if (!$skip_build) {
my @build_steps;
my $build_step_seq = 0;
if (!$skip_xcat_dep) {
for my $builder (@active_dep_builders) {
my $name = $builder->{name};
my $script = $builder->{script};
my $step_result = "$build_root/$name";
my $step_log = "$log_root/$name";
my $step_uniqueext = build_mock_uniqueext($run_id, ++$build_step_seq, $name);
my $cmd = join(' ',
'perl', sh_quote($script),
'--mock-cfg', sh_quote($target),
'--mock-uniqueext', sh_quote($step_uniqueext),
'--result-dir', sh_quote($step_result),
'--log-dir', sh_quote($step_log),
($skip_install ? '--skip-install' : ()),
);
push @build_steps, {
id => "xcat-dep:$name",
step => "Build xcat-dep: $name",
cmd => $cmd,
log => "$log_root/$name/run.log",
};
push @collect_roots, $step_result;
}
}
if ($dhcp_enabled) {
my $dhcp_uniqueext = build_mock_uniqueext($run_id, ++$build_step_seq, 'dhcpd');
my $dhcp_build_cmd = join(' && ',
'mkdir -p build/SRPMS build/RPMS',
'rpmdev-spectool --get-files --sources ./dhcp.spec',
'mock -r ' . sh_quote($target) .
' --uniqueext ' . sh_quote($dhcp_uniqueext) .
' --buildsrpm --spec ./dhcp.spec --sources . --resultdir ./build/SRPMS',
'mock -r ' . sh_quote($target) .
' --uniqueext ' . sh_quote($dhcp_uniqueext) .
' --rebuild ./build/SRPMS/*.src.rpm --resultdir ./build/RPMS',
);
push @build_steps, {
id => 'xcat-dep:dhcpd',
step => 'Build xcat-dep: dhcpd',
cmd => $dhcp_build_cmd,
cwd => $dhcp_effective_source,
log => "$log_root/dhcpd/build.log",
};
push @collect_roots, "$dhcp_effective_source/build/RPMS";
push @dhcp_srpm_collect_roots, "$dhcp_effective_source/build/SRPMS";
}
if (!$skip_perl) {
my $perl_result = "$build_root/perl/$arch";
my $perl_log = "$log_root/perl/$arch";
my $perl_uniqueext = build_mock_uniqueext($run_id, ++$build_step_seq, 'perl-list6');
my $cmd = join(' ',
'perl', sh_quote($perl_builder),
'--mock-cfg', sh_quote($target),
'--mock-uniqueext', sh_quote($perl_uniqueext),
'--result-dir', sh_quote($perl_result),
'--log-dir', sh_quote($perl_log),
($skip_install ? '--skip-install' : ()),
);
push @build_steps, {
id => 'perl',
step => 'Build perl xcat-dep packages',
cmd => $cmd,
log => "$log_root/perl-build.log",
};
push @collect_roots, $perl_result;
}
if (!$skip_xcat) {
my $cmd = join(' ',
'perl', sh_quote("$xcat_src/buildrpms.pl"),
'--target', sh_quote($target),
'--nproc', int($nproc),
'--force',
'--verbose',
'--xcat_dep_path', sh_quote($repo_root),
);
push @build_steps, {
id => 'xcat',
step => 'Build xCAT packages',
cmd => $cmd,
cwd => $xcat_src,
log => "$log_root/xcat-build.log",
};
}
if (@build_steps) {
my $effective_parallel_builds = defined($parallel_builds)
? $parallel_builds
: scalar(@build_steps);
run_build_steps_parallel(
steps => \@build_steps,
max_processes => $effective_parallel_builds,
);
}
}
my $xcat_rpms_dir = "$xcat_src/dist/$target/rpms";
my $xcat_srpms_dir = "$xcat_src/dist/$target/srpms";
push @collect_roots, $xcat_rpms_dir;
if ($skip_build) {
push @collect_roots,
"$repo_root/build-output/list3/elilo-xcat",
"$repo_root/build-output/list3/grub2-xcat",
"$repo_root/build-output/list3/ipmitool-xcat",
"$repo_root/build-output/list3/syslinux-xcat",
"$repo_root/build-output/list5/goconserver/$arch",
"$repo_root/goconserver-build-$arch/results/rpm",
"$repo_root/build-output/list6/perl/$arch",
"$repo_root/perl-list6/$arch";
}
if ($dhcp_effective_source ne '') {
push @collect_roots, "$dhcp_effective_source/build/RPMS";
push @dhcp_srpm_collect_roots, "$dhcp_effective_source/build/SRPMS";
}
push @collect_roots, @extra_collect_dirs;
@collect_roots = uniq(@collect_roots);
my @srpm_collect_roots = uniq(@collect_roots, $xcat_srpms_dir, @dhcp_srpm_collect_roots);
print_step('Collect RPM artifacts');
print "collection roots:\n";
print " $_\n" for @collect_roots;
my ($copied, $skipped_src, $missing_roots) = collect_rpms(
roots => \@collect_roots,
dest_dir => $repo_dir,
dry_run => $dry_run,
);
if (!$dry_run && $copied == 0) {
die "No binary RPMs were collected. Check build logs and collection roots.\n";
}
print_step('Collect source RPM artifacts');
print "source collection roots:\n";
print " $_\n" for @srpm_collect_roots;
my ($copied_srpms, $skipped_non_src, $missing_srpm_roots) = collect_srpms(
roots => \@srpm_collect_roots,
dest_dir => $srpm_repo_dir,
dry_run => $dry_run,
);
if (!$dry_run && $copied_srpms == 0) {
print "WARN: No source RPMs were collected. SRPM repo and tarball may be empty.\n";
}
if (!$skip_createrepo) {
run_step(
step => 'Run createrepo',
cmd => 'createrepo --update ' . 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),
log => "$log_root/createrepo-srpm.log",
);
}
if (!$skip_tarball) {
my $cmd = join(' ',
'tar', '-C', sh_quote($run_root),
'-czf', sh_quote($tarball),
'repo'
);
run_step(
step => 'Create tarball',
cmd => $cmd,
log => "$log_root/tarball.log",
);
my $srpm_cmd = join(' ',
'tar', '-C', sh_quote($run_root),
'-czf', sh_quote($srpm_tarball),
'repo-src'
);
run_step(
step => 'Create SRPM tarball',
cmd => $srpm_cmd,
log => "$log_root/tarball-srpm.log",
);
}
if (!$dry_run) {
open my $sfh, '>', $summary_file or die "Cannot write $summary_file: $!\n";
print {$sfh} "run_root=$run_root\n";
print {$sfh} "repo_dir=$repo_dir\n";
print {$sfh} "target=$target\n";
print {$sfh} "target_rel=" . (defined($target_rel) ? $target_rel : '') . "\n";
print {$sfh} "arch=$arch\n";
print {$sfh} "os_id=$os_id\n";
print {$sfh} "version_id=$version_id\n";
print {$sfh} "rel=$rel\n";
print {$sfh} "dhcp_enabled=$dhcp_enabled\n";
print {$sfh} "dhcp_repo_url=$dhcp_repo_url\n";
print {$sfh} "dhcp_repo_ref=$dhcp_repo_ref\n";
print {$sfh} "dhcp_source=" . ($dhcp_effective_source ne '' ? $dhcp_effective_source : '') . "\n";
print {$sfh} "dhcp_commit=" . ($dhcp_commit ne '' ? $dhcp_commit : '') . "\n";
print {$sfh} "copied_rpms=$copied\n";
print {$sfh} "skipped_src_rpms=$skipped_src\n";
print {$sfh} "missing_collection_roots=$missing_roots\n";
print {$sfh} "srpm_repo_dir=$srpm_repo_dir\n";
print {$sfh} "copied_srpms=$copied_srpms\n";
print {$sfh} "skipped_non_src_rpms=$skipped_non_src\n";
print {$sfh} "missing_srpm_collection_roots=$missing_srpm_roots\n";
print {$sfh} "tarball=$tarball\n" if !$skip_tarball;
print {$sfh} "srpm_tarball=$srpm_tarball\n" if !$skip_tarball;
close $sfh;
}
print_step('Completed');
print "Collected binary RPMs: $copied\n";
print "Skipped source RPMs: $skipped_src\n";
print "Missing roots: $missing_roots\n";
print "Repo dir: $repo_dir\n";
print "Collected source RPMs: $copied_srpms\n";
print "Skipped non-src RPMs: $skipped_non_src\n";
print "Missing source roots: $missing_srpm_roots\n";
print "SRPM repo dir: $srpm_repo_dir\n";
print "DHCP source: $dhcp_effective_source\n" if $dhcp_effective_source ne '';
print "DHCP ref: $dhcp_repo_ref\n" if $dhcp_enabled;
print "DHCP commit: $dhcp_commit\n" if $dhcp_commit ne '';
print "Summary: $summary_file\n" if !$dry_run;
print "Tarball: $tarball\n" if !$skip_tarball;
print "SRPM Tarball: $srpm_tarball\n" if !$skip_tarball;
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
Build xcat-dep and xCAT RPMs, consolidate binary/source artifacts, run createrepo, and create tarballs.
Options:
--repo-root PATH xcat-dep repository root (default: script directory)
--xcat-source PATH xCAT source root with buildrpms.pl (default: <repo-root>/xcat-source-code)
--output-root PATH Root output directory (default: <repo-root>/build-output/mockbuild-all)
--target NAME Optional unified target in <ID>+epel-<REL>-<ARCH> 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)
--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
--skip-perl Skip perl package build step
--skip-xcat Skip xCAT buildrpms.pl step
--skip-dhcp Skip rpms-dhcp build step
--skip-createrepo Skip createrepo
--skip-tarball Skip binary/SRPM tarball creation
--scrub-all-chroots Run mock -r <target> --scrub=all before build/collect
--dhcp-repo-url URL rpms-dhcp git URL (default: https://github.com/VersatusHPC/rpms-dhcp.git)
--dhcp-repo-ref REF rpms-dhcp git ref/tag/branch to checkout (default: master)
--dhcp-source-dir PATH Local rpms-dhcp source directory override (skip clone/fetch)
--collect-dir PATH Additional directory to scan recursively for RPMs (repeatable)
--dry-run Print planned commands without executing
Notes:
- Run this script as root on the build host.
- ARCH is derived from: uname -m
- Top-level parallel queue includes xcat-dep mockbuild.pl steps, perl builder,
and xcat-source-code/buildrpms.pl.
- Child mockbuild scripts are invoked with per-step mock --uniqueext values
to avoid lock collisions on the same mock config.
- If --target is omitted, it is deduced from /etc/os-release:
ID + epel + int(VERSION_ID) + ARCH
- DHCP step auto-enables only for EL10 targets, unless explicitly skipped.
USAGE
}
sub parse_target_rel {
my ($target_name) = @_;
return undef if !defined($target_name) || $target_name eq '';
return $1 if $target_name =~ /\+epel-(\d+)-/;
return undef;
}
sub prepare_dhcp_source {
my (%args) = @_;
my $run_root = $args{run_root} // die "prepare_dhcp_source missing run_root\n";
my $log_root = $args{log_root} // die "prepare_dhcp_source missing log_root\n";
my $repo_url = $args{repo_url} // die "prepare_dhcp_source missing repo_url\n";
my $repo_ref = $args{repo_ref} // 'master';
my $source_dir = $args{source_dir} // '';
my $clone_log = "$log_root/clone.log";
my $source_path;
if ($source_dir ne '') {
$source_path = eval { abs_path($source_dir) } || $source_dir;
die "DHCP source directory does not exist: $source_path\n"
if !$dry_run && !-d $source_path;
run_step(
step => 'Prepare DHCP source',
cmd => 'echo Using local DHCP source directory: ' . sh_quote($source_path),
log => $clone_log,
);
} else {
$source_path = "$run_root/sources/rpms-dhcp";
my $prepare_cmd = join(' && ',
'mkdir -p ' . sh_quote("$run_root/sources"),
'if [ -d ' . sh_quote("$source_path/.git") . ' ]; then ' .
'cd ' . sh_quote($source_path) . ' && ' .
'git remote set-url origin ' . sh_quote($repo_url) . ' && ' .
'git fetch --tags origin' .
'; else ' .
'git clone ' . sh_quote($repo_url) . ' ' . sh_quote($source_path) .
'; fi',
'cd ' . sh_quote($source_path),
'git fetch --tags origin',
'git checkout --force ' . sh_quote($repo_ref),
);
run_step(
step => 'Prepare DHCP source',
cmd => $prepare_cmd,
log => $clone_log,
);
}
if (!$dry_run && !-f "$source_path/dhcp.spec") {
die "Missing dhcp.spec in DHCP source: $source_path/dhcp.spec\n";
}
my $commit = '';
if ($dry_run) {
$commit = '(dry-run)';
} elsif (-d "$source_path/.git") {
$commit = capture("cd " . sh_quote($source_path) . " && git rev-parse HEAD");
} else {
$commit = '(local-source-no-git)';
}
return ($source_path, $commit);
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub require_command {
my ($cmd) = @_;
run_simple("command -v " . sh_quote($cmd) . " >/dev/null 2>&1");
}
sub run_simple {
my ($cmd) = @_;
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n$out\n";
}
chomp $out;
return $out;
}
sub run_step {
my (%args) = @_;
my $step = $args{step} // 'Run command';
my $cmd = $args{cmd} // die "run_step missing cmd\n";
my $cwd = $args{cwd};
my $log = $args{log};
print_step($step);
print "+ $cmd\n";
if ($cwd) {
print " (cwd: $cwd)\n";
}
if ($log) {
print " (log: $log)\n";
}
return if $dry_run;
my $full_cmd = $cmd;
if ($cwd) {
$full_cmd = "cd " . sh_quote($cwd) . " && $cmd";
}
if ($log) {
my $log_dir = dirname($log);
make_path($log_dir) if !-d $log_dir;
$full_cmd .= " > " . sh_quote($log) . " 2>&1";
}
my $rc = system($full_cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Step failed (rc=$exit): $step\nCommand: $cmd\n";
}
}
sub run_build_steps_parallel {
my (%args) = @_;
my $steps = $args{steps} // [];
my $max_processes = $args{max_processes} // 1;
return if !@{$steps};
if ($dry_run || $max_processes <= 1 || @{$steps} == 1) {
for my $step (@{$steps}) {
run_step(%{$step});
}
return;
}
my $workers = $max_processes;
$workers = scalar(@{$steps}) if $workers > scalar(@{$steps});
print_step('Run build steps in parallel');
print "max_processes: $workers\n";
print "queued steps:\n";
print " - $_->{step}\n" for @{$steps};
my %failed;
my $pm = Parallel::ForkManager->new($workers);
$pm->run_on_finish(
sub {
my ($pid, $exit_code, $ident, $signal, $core_dump) = @_;
return if $exit_code == 0 && $signal == 0 && !$core_dump;
my $key = defined($ident) ? $ident : "pid:$pid";
$failed{$key} = {
exit => $exit_code,
signal => $signal,
core_dump => $core_dump ? 1 : 0,
};
}
);
for my $step (@{$steps}) {
my %step_copy = %{$step};
my $ident = delete $step_copy{id};
$ident = $step_copy{step} if !defined($ident) || $ident eq '';
my $pid = $pm->start($ident);
next if $pid;
my $ok = eval {
run_step(%step_copy);
1;
};
if (!$ok) {
my $err = $@;
$err = "unknown error\n" if !defined($err) || $err eq '';
print STDERR "ERROR [$ident] $err";
$pm->finish(1);
}
$pm->finish(0);
}
$pm->wait_all_children;
if (%failed) {
my @lines;
for my $id (sort keys %failed) {
my $f = $failed{$id};
push @lines,
"$id (exit=$f->{exit}, signal=$f->{signal}, core_dump=$f->{core_dump})";
}
die "Parallel build steps failed:\n " . join("\n ", @lines) . "\n";
}
}
sub collect_rpms {
my (%args) = @_;
my $roots = $args{roots} // [];
my $dest = $args{dest_dir} // die "collect_rpms missing dest_dir\n";
my $is_dry = $args{dry_run} ? 1 : 0;
my %seen;
my $copied = 0;
my $skipped_src = 0;
my $missing_roots = 0;
for my $root (@{$roots}) {
if (!$root || !-d $root) {
$missing_roots++;
print "WARN: missing collection root: $root\n";
next;
}
my @rpms;
find(
sub {
return if !-f $_;
return if $_ !~ /\.rpm$/;
push @rpms, $File::Find::name;
},
$root,
);
@rpms = sort uniq(@rpms);
for my $rpm (@rpms) {
next if !-f $rpm;
if ($rpm =~ /\.src\.rpm$/) {
$skipped_src++;
next;
}
my $base = basename($rpm);
next if $seen{$base}++;
if ($is_dry) {
print "DRY-RUN copy: $rpm -> $dest/$base\n";
$copied++;
next;
}
copy($rpm, "$dest/$base")
or die "Failed to copy $rpm to $dest/$base: $!\n";
$copied++;
}
}
return ($copied, $skipped_src, $missing_roots);
}
sub collect_srpms {
my (%args) = @_;
my $roots = $args{roots} // [];
my $dest = $args{dest_dir} // die "collect_srpms missing dest_dir\n";
my $is_dry = $args{dry_run} ? 1 : 0;
my %seen;
my $copied = 0;
my $skipped_non_src = 0;
my $missing_roots = 0;
for my $root (@{$roots}) {
if (!$root || !-d $root) {
$missing_roots++;
print "WARN: missing source collection root: $root\n";
next;
}
my @rpms;
find(
sub {
return if !-f $_;
return if $_ !~ /\.rpm$/;
push @rpms, $File::Find::name;
},
$root,
);
@rpms = sort uniq(@rpms);
for my $rpm (@rpms) {
next if !-f $rpm;
if ($rpm !~ /\.src\.rpm$/) {
$skipped_non_src++;
next;
}
my $base = basename($rpm);
next if $seen{$base}++;
if ($is_dry) {
print "DRY-RUN copy source: $rpm -> $dest/$base\n";
$copied++;
next;
}
copy($rpm, "$dest/$base")
or die "Failed to copy $rpm to $dest/$base: $!\n";
$copied++;
}
}
return ($copied, $skipped_non_src, $missing_roots);
}
sub build_mock_uniqueext {
my ($run, $seq, $label) = @_;
my $run_part = defined($run) ? $run : 'run';
$run_part =~ s/[^A-Za-z0-9_.-]+/-/g;
$run_part =~ s/^-+|-+$//g;
$run_part = 'run' if $run_part eq '';
$run_part = substr($run_part, -24) if length($run_part) > 24;
my $label_part = defined($label) ? $label : 'step';
$label_part =~ s/[^A-Za-z0-9_.-]+/-/g;
$label_part =~ s/^-+|-+$//g;
$label_part = 'step' if $label_part eq '';
$label_part = substr($label_part, 0, 20) if length($label_part) > 20;
my $idx = defined($seq) ? int($seq) : 0;
$idx = 0 if $idx < 0;
return sprintf("mba-%02d-%s-%s", $idx, $run_part, $label_part);
}
sub resolve_xcat_source {
my ($requested, $root) = @_;
my @candidates = (
$requested,
"$root/xcat-source-code",
"$root/../xCAT3",
'/home/build/xCAT3',
);
for my $c (@candidates) {
next if !defined($c) || $c eq '';
my $abs = eval { abs_path($c) };
next if !$abs;
return $abs if -f "$abs/buildrpms.pl";
}
return eval { abs_path($requested) } || $requested;
}
sub read_os_release {
my ($path) = @_;
my %vals;
open my $fh, '<', $path or die "Cannot open $path: $!\n";
while (my $line = <$fh>) {
chomp $line;
next if $line =~ /^\s*#/;
next if $line !~ /=/;
my ($k, $v) = split /=/, $line, 2;
$v =~ s/^"(.*)"$/$1/;
$v =~ s/^'(.*)'$/$1/;
$vals{$k} = $v;
}
close $fh;
return %vals;
}
sub uniq {
my %seen;
return grep { defined($_) && !$seen{$_}++ } @_;
}
sub sh_quote {
my ($s) = @_;
$s = '' if !defined $s;
$s =~ s/'/'"'"'/g;
return "'$s'";
}

557
mockbuild-perl-packages.pl Executable file
View File

@@ -0,0 +1,557 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
use Parallel::ForkManager;
my $repo_root = abs_path(dirname(__FILE__));
my $work_dir = '/tmp/perl-list6-mockbuild';
my $mock_cfg = '';
my $mock_uniqueext = '';
my $result_dir = '';
my $log_dir = '';
my $packages_csv = '';
my $jobs = 0;
my $skip_install = 0;
my $allow_erasing = 0;
GetOptions(
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'packages=s' => \$packages_csv,
'jobs=i' => \$jobs,
'skip-install!' => \$skip_install,
'allow-erasing!' => \$allow_erasing,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
for my $bin (qw(mock rpmbuild rpm dnf perl bash grep)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = "${os_id}+epel-10-${arch}";
}
my $mock_uniqueext_opt = $mock_uniqueext ne ''
? ' --uniqueext ' . sh_quote($mock_uniqueext)
: '';
if (!$result_dir) {
$result_dir = "$repo_root/build-output/list6/perl/$arch";
}
if (!$log_dir) {
$log_dir = "$repo_root/build-logs/list6/perl/$arch";
}
my %meta = (
'perl-Crypt-SSLeay' => {
mode => 'spec',
pkg_dir => "$repo_root/perl-Crypt-SSLeay",
spec => "$repo_root/perl-Crypt-SSLeay/perl-Crypt-SSLeay.spec",
rpm_name => 'perl-Crypt-SSLeay',
rpm_arch => 'native',
module => 'Crypt::SSLeay',
},
'perl-HTML-Form' => {
mode => 'srpm',
pkg_dir => "$repo_root/perl-HTML-Form",
srpm_globs => [
"$repo_root/perl-HTML-Form/perl-HTML-Form-6.07-4.fc34.src.rpm",
"$repo_root/perl-HTML-Form/perl-HTML-Form-*.src.rpm",
],
rpm_name => 'perl-HTML-Form',
rpm_arch => 'noarch',
module => 'HTML::Form',
},
'perl-HTTP-Async' => {
mode => 'spec',
pkg_dir => "$repo_root/perl-HTTP-Async",
spec => "$repo_root/perl-HTTP-Async/perl-HTTP-Async.spec",
rpm_name => 'perl-HTTP-Async',
rpm_arch => 'noarch',
module => 'HTTP::Async',
},
'perl-IO-Stty' => {
mode => 'srpm',
pkg_dir => "$repo_root/perl-IO-Stty",
srpm_globs => [
"$repo_root/perl-IO-Stty/perl-IO-Stty-0.04-5.fc34.src.rpm",
"$repo_root/perl-IO-Stty/perl-IO-Stty-*.src.rpm",
],
rpm_name => 'perl-IO-Stty',
rpm_arch => 'noarch',
module => 'IO::Stty',
},
'perl-Net-HTTPS-NB' => {
mode => 'spec',
pkg_dir => "$repo_root/perl-Net-HTTPS-NB",
spec => "$repo_root/perl-Net-HTTPS-NB/perl-Net-HTTPS-NB.spec",
rpm_name => 'perl-Net-HTTPS-NB',
rpm_arch => 'noarch',
module => 'Net::HTTPS::NB',
},
'perl-Net-Telnet' => {
mode => 'srpm',
pkg_dir => "$repo_root/perl-Net-Telnet",
srpm_globs => [
"$repo_root/perl-Net-Telnet/perl-Net-Telnet-3.04-16.fc34.src.rpm",
"$repo_root/perl-Net-Telnet/perl-Net-Telnet-*.src.rpm",
],
rpm_name => 'perl-Net-Telnet',
rpm_arch => 'noarch',
module => 'Net::Telnet',
},
'perl-Sys-Virt' => {
mode => 'spec',
pkg_dir => "$repo_root/perl-Sys-Virt",
spec => "$repo_root/perl-Sys-Virt/Sys-Virt.spec",
rpm_name => 'perl-Sys-Virt',
rpm_arch => 'native',
module => 'Sys::Virt',
},
);
my @default_order = qw(
perl-Crypt-SSLeay
perl-HTML-Form
perl-HTTP-Async
perl-IO-Stty
perl-Net-HTTPS-NB
perl-Net-Telnet
perl-Sys-Virt
);
my @packages = @default_order;
if ($packages_csv ne '') {
@packages = grep { $_ ne '' } map { s/^\s+|\s+$//gr } split /,/, $packages_csv;
}
for my $pkg (@packages) {
die "Unknown package in --packages: $pkg\n" if !exists $meta{$pkg};
}
if ($jobs <= 0) {
$jobs = scalar(@packages);
}
$jobs = 1 if $jobs < 1;
if (@packages && $jobs > scalar(@packages)) {
$jobs = scalar(@packages);
}
if (!$skip_install && $jobs > 1) {
print "INFO: --skip-install is disabled; forcing --jobs 1 to avoid host dnf lock contention\n";
$jobs = 1;
}
make_path($result_dir);
make_path($log_dir);
make_path($work_dir);
print_step("Configuration");
print "repo_root: $repo_root\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "arch: $arch\n";
print "mock_cfg: $mock_cfg\n";
print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n";
print "packages: " . join(', ', @packages) . "\n";
print "jobs: $jobs\n";
print "skip_install:$skip_install\n";
print "allow_erasing:$allow_erasing\n";
print_step("Mock config check");
run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null");
my @failed;
my @passed;
my @summary_lines;
print_step("Build packages");
print "parallel jobs: $jobs\n";
my $pm = Parallel::ForkManager->new($jobs);
$pm->run_on_finish(
sub {
my ($pid, $exit_code, $ident) = @_;
my $label = defined $ident ? $ident : "pid=$pid";
my $state = $exit_code == 0 ? 'PASS' : "FAIL(rc=$exit_code)";
print "[$label] $state\n";
}
);
for my $idx (0 .. $#packages) {
my $pkg = $packages[$idx];
my $cfg = $meta{$pkg};
my $pkg_uniqueext = package_uniqueext($mock_uniqueext, $idx + 1, $pkg);
my $pid = $pm->start($pkg);
next if $pid;
my $ok = build_package(
pkg => $pkg,
cfg => $cfg,
work_dir => $work_dir,
result_dir => $result_dir,
log_dir => $log_dir,
mock_cfg => $mock_cfg,
mock_uniqueext => $pkg_uniqueext,
arch => $arch,
skip_install => $skip_install,
allow_erasing => $allow_erasing,
);
$pm->finish($ok ? 0 : 1);
}
$pm->wait_all_children;
for my $pkg (@packages) {
my $status_file = "$log_dir/$pkg/status.txt";
if (!-f $status_file) {
push @failed, $pkg;
push @summary_lines, "$pkg FAIL missing status file ($status_file)";
next;
}
my $line = slurp($status_file);
$line =~ s/\r?\n.*$//s;
my ($status, $summary) = split /\t/, $line, 2;
if (!defined $status || !defined $summary || ($status ne 'PASS' && $status ne 'FAIL')) {
$status = 'FAIL';
$summary = "$pkg FAIL malformed status line in $status_file";
}
if ($status eq 'PASS') {
push @passed, $pkg;
} else {
push @failed, $pkg;
}
push @summary_lines, $summary;
}
open my $sfh, '>', "$log_dir/build-summary.txt"
or die "Cannot write $log_dir/build-summary.txt: $!\n";
print {$sfh} "mock_cfg=$mock_cfg\n";
print {$sfh} "mock_uniqueext=$mock_uniqueext\n" if $mock_uniqueext ne '';
print {$sfh} "arch=$arch\n";
print {$sfh} "result_dir=$result_dir\n";
print {$sfh} "log_dir=$log_dir\n";
print {$sfh} "packages=" . join(',', @packages) . "\n";
print {$sfh} "passed=" . join(',', @passed) . "\n";
print {$sfh} "failed=" . join(',', @failed) . "\n";
print {$sfh} "$_\n" for @summary_lines;
close $sfh;
print_step("Completed");
print "Passed: " . join(', ', @passed) . "\n" if @passed;
print "Failed: " . join(', ', @failed) . "\n" if @failed;
print "Artifacts: $result_dir\n";
print "Logs: $log_dir\n";
exit(@failed ? 1 : 0);
sub build_package {
my (%args) = @_;
my $pkg = $args{pkg};
my $cfg = $args{cfg};
my $work_dir = $args{work_dir};
my $result_dir = $args{result_dir};
my $log_dir = $args{log_dir};
my $mock_cfg = $args{mock_cfg};
my $mock_uniqueext = $args{mock_uniqueext};
my $arch = $args{arch};
my $skip_install = $args{skip_install};
my $allow_erasing = $args{allow_erasing};
my $pkg_run_dir = "$work_dir/$pkg";
my $pkg_result = "$result_dir/$pkg";
my $pkg_log = "$log_dir/$pkg";
my $status_file = "$pkg_log/status.txt";
remove_tree($pkg_run_dir) if -d $pkg_run_dir;
make_path($pkg_run_dir);
make_path($pkg_result);
make_path($pkg_log);
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";
open STDERR, '>&', $runfh or die "Cannot redirect stderr to $run_log: $!\n";
select(STDOUT);
$| = 1;
my $mock_uniqueext_opt = ' --uniqueext ' . sh_quote($mock_uniqueext);
print_step("Build $pkg");
print "mock_uniqueext: $mock_uniqueext\n";
my $summary = '';
my $ok = 0;
my $srpm_path = '';
my $rebuild_result = "$pkg_run_dir/rpm";
make_path($rebuild_result);
eval {
if ($cfg->{mode} eq 'srpm') {
$srpm_path = select_srpm($cfg->{srpm_globs});
die "Could not locate source RPM for $pkg\n" if !$srpm_path;
} else {
my $spec = $cfg->{spec};
die "Missing spec for $pkg: $spec\n" if !-f $spec;
my $source_dir = $cfg->{pkg_dir};
die "Missing source directory for $pkg: $source_dir\n" if !-d $source_dir;
my ($version, @assets) = parse_spec($spec);
die "Could not parse Version from $spec\n" if !$version;
for my $asset (@assets) {
my $asset_path = "$source_dir/$asset";
die "Missing Source/Patch asset for $pkg: $asset_path\n" if !-f $asset_path;
}
my $prep_top = "$pkg_run_dir/prep";
for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) {
make_path("$prep_top/$d");
}
my $prep_spec = "$prep_top/SPECS/" . basename($spec);
copy($spec, $prep_spec) or die "Failed to copy prep spec for $pkg: $!\n";
for my $asset (@assets) {
copy("$source_dir/$asset", "$prep_top/SOURCES/$asset")
or die "Failed to stage prep asset $asset for $pkg: $!\n";
}
run(
"rpmbuild --define " . sh_quote("_topdir $prep_top") .
" -bp --nodeps " . sh_quote($prep_spec) .
" > " . sh_quote("$pkg_log/prep.log") . " 2>&1"
);
my $srpm_result = "$pkg_run_dir/srpm";
make_path($srpm_result);
run(
"mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt .
" --buildsrpm --spec " . sh_quote($spec) .
" --sources " . sh_quote($source_dir) .
" --resultdir " . sh_quote($srpm_result) .
" > " . sh_quote("$pkg_log/mock-buildsrpm.log") . " 2>&1"
);
my @srpms = sort glob("$srpm_result/*.src.rpm");
die "No SRPM produced for $pkg in $srpm_result\n" if !@srpms;
$srpm_path = $srpms[-1];
}
run(
"mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt .
" --rebuild " . sh_quote($srpm_path) .
" --resultdir " . sh_quote($rebuild_result) .
" > " . sh_quote("$pkg_log/mock-rebuild.log") . " 2>&1"
);
my @rpms = sort glob("$rebuild_result/*.rpm");
die "No RPMs generated for $pkg in $rebuild_result\n" if !@rpms;
my $main_rpm = '';
for my $rpm (@rpms) {
next if $rpm =~ /\.src\.rpm$/;
my $name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($rpm));
my $rarch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($rpm));
next if $name ne $cfg->{rpm_name};
if ($cfg->{rpm_arch} eq 'noarch' && $rarch eq 'noarch') {
$main_rpm = $rpm;
last;
}
if ($cfg->{rpm_arch} eq 'native' && $rarch eq $arch) {
$main_rpm = $rpm;
last;
}
}
die "Could not find main RPM for $pkg in $rebuild_result\n" if !$main_rpm;
run("rpm -qpl " . sh_quote($main_rpm) . " > " . sh_quote("$pkg_log/payload.list"));
my $payload = slurp("$pkg_log/payload.list");
die "Empty payload list for $pkg main RPM\n" if $payload !~ m{^/}m;
for my $rpm (@rpms) {
copy($rpm, $pkg_result) or die "Failed to copy $rpm to $pkg_result: $!\n";
}
copy($srpm_path, $pkg_result) or die "Failed to copy $srpm_path to $pkg_result: $!\n";
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$rebuild_result/$log";
next if !-f $src;
copy($src, "$pkg_log/$log") or die "Failed to copy $src to $pkg_log: $!\n";
}
if (-d "$pkg_run_dir/srpm") {
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$pkg_run_dir/srpm/$log";
next if !-f $src;
copy($src, "$pkg_log/srpm-$log") or die "Failed to copy $src to $pkg_log: $!\n";
}
}
if (!$skip_install) {
my $install_cmd = "dnf -y install ";
$install_cmd .= "--allowerasing " if $allow_erasing;
run($install_cmd . sh_quote($main_rpm));
my $module = $cfg->{module};
my $rc_mod = run_capture_rc("perl -M$module -e 1", "$pkg_log/smoke-perl-module.log");
die "Perl module import failed for $pkg ($module), rc=$rc_mod\n" if $rc_mod != 0;
}
$summary = "$pkg PASS main_rpm=" . basename($main_rpm);
$ok = 1;
};
if ($@) {
my $err = $@;
chomp $err;
$err =~ s/\s+/ /g;
$summary = "$pkg FAIL $err";
open my $efh, '>', "$pkg_log/error.txt" or die "Cannot write $pkg_log/error.txt: $!\n";
print {$efh} "$err\n";
close $efh;
print "ERROR: $err\n";
}
open my $sfh, '>', $status_file or die "Cannot write $status_file: $!\n";
print {$sfh} (($ok ? 'PASS' : 'FAIL') . "\t$summary\n");
close $sfh;
return $ok;
}
sub package_uniqueext {
my ($base, $index, $pkg) = @_;
my $tag = lc $pkg;
$tag =~ s/[^a-z0-9]+/-/g;
$tag =~ s/^-+|-+$//g;
$tag = "pkg$index" if $tag eq '';
my $prefix = $base ne '' ? $base : "perl-list6-$$";
my $value = "${prefix}-${index}-${tag}";
$value =~ s/[^A-Za-z0-9_.-]+/-/g;
return $value;
}
sub usage {
return <<"USAGE";
Usage: $0 [options]
--work-dir PATH Temporary work dir (default: $work_dir)
--mock-cfg NAME Mock config (default: <ID>+epel-10-<ARCH>)
--mock-uniqueext TXT Optional mock --uniqueext suffix to isolate concurrent builds
--jobs N Number of parallel package workers (default: selected package count)
--result-dir PATH Output directory (default: build-output/list6/perl/<ARCH>)
--log-dir PATH Log directory (default: build-logs/list6/perl/<ARCH>)
--packages LIST Comma-separated subset of packages to build
--skip-install Skip dnf install + perl module import checks
--allow-erasing Allow dnf to erase conflicting packages during install smoke tests
USAGE
}
sub select_srpm {
my ($globs_ref) = @_;
for my $g (@{$globs_ref}) {
my @matches = sort glob($g);
next if !@matches;
return $matches[-1];
}
return '';
}
sub parse_spec {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open spec $path: $!\n";
my $version = '';
my %macros;
my @assets;
while (my $line = <$fh>) {
if ($line =~ /^\s*%(?:global|define)\s+([A-Za-z0-9_]+)\s+(.+?)\s*$/) {
my ($k, $v) = ($1, $2);
$v =~ s/\s+#.*$//;
$macros{$k} = $v;
}
if ($line =~ /^Version:\s*(\S+)/i) {
$version = $1;
}
if ($line =~ /^(?:Source|Patch)\d*:\s*(\S+)/i) {
my $asset = $1;
push @assets, $asset;
}
}
close $fh;
$macros{version} = $version if $version ne '';
$macros{ver} = $version if $version ne '';
@assets = map {
my $v = $_;
for my $i (1 .. 6) {
my $changed = 0;
for my $k (keys %macros) {
my $before = $v;
$v =~ s/%\{$k\}/$macros{$k}/g;
$changed = 1 if $v ne $before;
}
last if !$changed;
}
if ($v =~ m{^[a-zA-Z][a-zA-Z0-9+.-]*://}) {
$v = basename($v);
}
$v =~ s/\?.*$//;
$v;
} @assets;
return ($version, @assets);
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub sh_quote {
my ($s) = @_;
$s =~ s/'/'"'"'/g;
return "'$s'";
}
sub run {
my ($cmd) = @_;
print "+ $cmd\n";
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
print "+ $cmd\n";
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\nOutput:\n$out\n";
}
chomp $out;
return $out;
}
sub run_capture_rc {
my ($cmd, $log_file) = @_;
my $full = "$cmd > " . sh_quote($log_file) . " 2>&1";
print "+ $full\n";
my $rc = system($full);
return $rc == -1 ? 255 : ($rc >> 8);
}
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}

View File

@@ -0,0 +1,33 @@
From 1c725e333e9d20b87346fb394a1d01fa5be4fbaf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Wed, 12 Oct 2016 10:46:22 +0200
Subject: [PATCH] Do not use SSLv2_client_method() with OpenSSL >= 1.1.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
SSLv2 support was removed from OpenSSL 1.1.0.
CPAN RT#118343
Signed-off-by: Petr Písař <ppisar@redhat.com>
---
SSLeay.xs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SSLeay.xs b/SSLeay.xs
index 1560604..ba0dd24 100644
--- a/SSLeay.xs
+++ b/SSLeay.xs
@@ -152,7 +152,7 @@ SSL_CTX_new(packname, ssl_version)
ctx = SSL_CTX_new(SSLv3_client_method());
}
else {
-#ifndef OPENSSL_NO_SSL2
+#if !defined OPENSSL_NO_SSL2 && OPENSSL_VERSION_NUMBER < 0x10100000L
/* v2 is the default */
ctx = SSL_CTX_new(SSLv2_client_method());
#else
--
2.7.4

View File

@@ -0,0 +1,11 @@
diff -up Crypt-SSLeay-0.72/Makefile.PL.orig Crypt-SSLeay-0.72/Makefile.PL
--- Crypt-SSLeay-0.72/Makefile.PL.orig 2017-05-16 13:44:37.511126314 +0200
+++ Crypt-SSLeay-0.72/Makefile.PL 2017-05-16 13:45:31.141903223 +0200
@@ -8,6 +8,7 @@ use Getopt::Long qw( GetOptionsFromArray
use Path::Class;
use Try::Tiny;
+BEGIN { push @INC, '.'; }
use inc::IO::Interactive::Tiny;
caller

View File

@@ -0,0 +1,21 @@
--- a/SSLeay.xs
+++ b/SSLeay.xs
@@ -149,14 +149,14 @@
if(ssl_version == 23) {
ctx = SSL_CTX_new(SSLv23_client_method());
}
else if(ssl_version == 3) {
- ctx = SSL_CTX_new(SSLv3_client_method());
+ ctx = SSL_CTX_new(TLS_client_method());
}
else {
#ifndef OPENSSL_NO_SSL2
/* v2 is the default */
ctx = SSL_CTX_new(SSLv2_client_method());
#else
/* v3 is the default */
- ctx = SSL_CTX_new(SSLv3_client_method());
+ ctx = SSL_CTX_new(TLS_client_method());
#endif
}
EOF

View File

@@ -0,0 +1,390 @@
# Disable network tests by default
%bcond_with perl_Crypt_SSLeay_enables_network_test
Name: perl-Crypt-SSLeay
Summary: OpenSSL glue that provides LWP with HTTPS support
Version: 0.72
Release: 24%{?dist}
License: Artistic 2.0
Source0: https://cpan.metacpan.org/authors/id/N/NA/NANIS/Crypt-SSLeay-%{version}.tar.gz
# Adapt to OpenSSL 1.1.0, bug #1383756, CPAN RT#118343
Patch0: Crypt-SSLeay-0.72-Do-not-use-SSLv2_client_method-with-OpenSSL-1.1.0.patch
Patch1: Crypt-SSLeay-0.72-Fix-building-on-Perl-without-dot-in-INC.patch
URL: https://metacpan.org/release/Crypt-SSLeay
BuildRequires: coreutils
BuildRequires: findutils
BuildRequires: gcc
BuildRequires: make
BuildRequires: openssl-devel
BuildRequires: zlib-devel
BuildRequires: perl-interpreter
BuildRequires: perl-devel
BuildRequires: perl-generators
BuildRequires: perl(ExtUtils::CBuilder) >= 0.280205
BuildRequires: perl(ExtUtils::MakeMaker)
# ExtUtils::MakeMaker::Coverage is useless
BuildRequires: perl(Getopt::Long)
BuildRequires: perl(Path::Class)
BuildRequires: perl(strict)
BuildRequires: perl(warnings)
BuildRequires: pkgconf-pkg-config
# Run-time:
BuildRequires: /etc/pki/tls/certs/ca-bundle.crt
BuildRequires: perl(Carp)
# DynaLoader not needed if XSLoader is available
BuildRequires: perl(Exporter)
BuildRequires: perl(IO::Socket)
BuildRequires: perl(MIME::Base64)
BuildRequires: perl(Socket)
BuildRequires: perl(vars)
BuildRequires: perl(XSLoader)
# Tests:
BuildRequires: perl(Test::More) >= 0.88
BuildRequires: perl(Try::Tiny) >= 0.19
# Optional tests:
BuildRequires: perl(Test::Pod)
BuildRequires: perl(Test::Pod::Coverage)
%if %{with perl_Crypt_SSLeay_enables_network_test}
# Network tests:
BuildRequires: perl(constant)
BuildRequires: perl(HTTP::Request)
BuildRequires: perl(LWP::Protocol::https) >= 6.02
BuildRequires: perl(LWP::UserAgent)
%endif
Requires: perl(:MODULE_COMPAT_%(eval "`perl -V:version`"; echo $version))
Requires: /etc/pki/tls/certs/ca-bundle.crt
Requires: perl(XSLoader)
%global __provides_exclude %{?__provides_exclude:__provides_exclude|}^perl\\(DB\\)
%{?perl_default_filter}
%description
These Perl modules provide support for the HTTPS protocol under the World-Wide
Web library for Perl (LWP), so that a LWP::UserAgent can make HTTPS GET, HEAD,
and POST requests.
This package contains Net::SSL module which is automatically loaded by
LWP::Protocol::https on HTTPS requests, and provides the necessary SSL glue
for that module to work.
%prep
%setup -q -n Crypt-SSLeay-%{version}
%patch0 -p1
%patch1 -p1
# OpenSSL 3 removed SSLv3 symbols; force TLS method for the old SSLv3 code path.
sed -i 's/SSLv3_client_method()/TLS_client_method()/g' SSLeay.xs
# Placate rpmlint
chmod -c -x lib/Net/SSL.pm
%build
if pkg-config openssl ; then
export INC="$CFLAGS `pkg-config --cflags-only-I openssl`"
export LDFLAGS="$LDFLAGS `pkg-config --libs-only-L openssl`"
fi
perl Makefile.PL --%{!?with_perl_Crypt_SSLeay_enables_network_test:no-}live-tests \
INC="$INC" LDFLAGS="$LDFLAGS" INSTALLDIRS=vendor NO_PACKLIST=1 \
OPTIMIZE="%{optflags}" </dev/null
make %{?_smp_mflags}
%install
make pure_install DESTDIR=%{buildroot}
find %{buildroot} -type f -name '*.bs' -a -size 0 -delete
%{_fixperms} %{buildroot}
chmod -R u+w %{buildroot}/*
chmod -R 644 eg/*
chmod -R 644 certs/*
rm certs/ca-bundle.crt
ln -s /etc/pki/tls/certs/ca-bundle.crt certs/ca-bundle.crt
%check
make test
%files
%doc Changes eg/* certs/*
%{perl_vendorarch}/auto/Crypt/
%{perl_vendorarch}/Crypt/
%{perl_vendorarch}/Net/
%{_mandir}/man3/Crypt::SSLeay.3pm*
%{_mandir}/man3/Crypt::SSLeay::Version.3pm*
%{_mandir}/man3/Net::SSL.3pm*
%changelog
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.72-20
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Thu Jun 28 2018 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-19
- Perl 5.28 rebuild
* Thu Feb 08 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.72-18
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.72-17
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.72-16
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Wed Jun 07 2017 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-15
- Perl 5.26 re-rebuild of bootstrapped packages
* Mon Jun 05 2017 Petr Pisar <ppisar@redhat.com> - 0.72-14
- Modernize spec file
* Mon Jun 05 2017 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-13
- Perl 5.26 rebuild
* Tue May 16 2017 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-12
- Fix building on Perl without '.' in @INC
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.72-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Wed Oct 12 2016 Petr Pisar <ppisar@redhat.com> - 0.72-10
- Adapt to OpenSSL 1.1.0 (bug #1383756)
* Sun May 15 2016 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-9
- Perl 5.24 rebuild
* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.72-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.72-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Sat Jun 06 2015 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-6
- Perl 5.22 rebuild
* Fri Aug 29 2014 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-5
- Perl 5.20 rebuild
* Sun Aug 17 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.72-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.72-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
* Mon Apr 28 2014 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-2
- Correct License tag, which should be Artistic 2.0
* Mon Apr 28 2014 Jitka Plesnikova <jplesnik@redhat.com> - 0.72-1
- 0.72 bump
* Wed Apr 16 2014 Petr Pisar <ppisar@redhat.com> - 0.64-6
- Make build script non-interactive
- Update package description
- Specify all dependencies
* Sat Aug 03 2013 Petr Pisar <ppisar@redhat.com> - 0.64-5
- Perl 5.18 rebuild
* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.64-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
* Wed Aug 8 2012 Paul Howarth <paul@city-fan.org> - 0.64-3
- Remove circular BR: perl(Net::SSL) provided by this package
- Placate rpmlint regarding file permissions
- Don't need to remove empty directories from the buildroot
* Tue Aug 07 2012 Petr Šabata <contyk@redhat.com> - 0.64-1
- 0.64 bump
* Mon Jul 30 2012 Petr Šabata <contyk@redhat.com> - 0.60-1
- 0.60 bugfix bump
- Drop command macros and modernize the spec a bit
* Fri Jul 20 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.58-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
* Fri Jul 20 2012 Marcela Mašláňová <mmaslano@redhat.com> - 0.58-10
- Conditionalize ExtUtils::MakeMaker::Coverage
* Mon Jun 25 2012 Petr Pisar <ppisar@redhat.com> - 0.58-9
- Perl 5.16 rebuild
* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.58-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
* Wed Sep 07 2011 Petr Sabata <contyk@redhat.com> - 0.58-7
- Link to the ca-certificates ca-bundle.crt instead of shipping our own,
outdated copy (#734385)
* Fri Jul 22 2011 Petr Pisar <ppisar@redhat.com> - 0.58-6
- RPM 4.9 dependency filtering added
* Wed Jul 20 2011 Petr Sabata <contyk@redhat.com> - 0.58-5
- Perl mass rebuild
* Tue Apr 19 2011 Paul Howarth <paul@city-fan.org> - 0.58-4
- Remove buildroot specification and cleaning, not needed for modern rpmbuild
- Use %%{?perl_default_filter}
- Filter the perl(DB) provide in a way that works with rpm >= 4.9
- Use DESTDIR rather than PERL_INSTALL_ROOT
- Fix line endings on documentation
- Fix upstream source URL
- Fix argument order for find with -depth
* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.58-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Thu Dec 16 2010 Marcela Maslanova <mmaslano@redhat.com> - 0.58-2
- Rebuild to fix problems with vendorarch/lib (#661697)
* Wed Sep 1 2010 Petr Sabata <psabata@redhat.com> - 0.58-1
- New upstream release, v0.58
- removing perl-Crypt-SSLeay-0.57-live-tests.patch, fixed in upstream
- removing perl-Crypt-SSLeay-Makefile_ssl1.patch, fixed in upstream
* Fri Apr 30 2010 Marcela Maslanova <mmaslano@redhat.com> - 0.57-17
- Mass rebuild with perl-5.12.0
* Mon Dec 7 2009 Stepan Kasal <skasal@redhat.com> - 0.57-16
- rebuild against perl 5.10.1
* Wed Nov 25 2009 Marcela Mašláňová <mmaslano@redhat.com> - 0.57-14
- change Makefile for openssl 1.0, which couldn't be found properly before
* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 0.57-13
- rebuilt with new openssl
* Sat Jul 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.57-12
- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
* Thu Feb 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.57-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
* Sat Jan 17 2009 Tomas Mraz <tmraz@redhat.com> - 0.57-10
- rebuild with new openssl
* Mon Oct 6 2008 Marcela Maslanova <mmaslano@redhat.com> - 0.57-9
- add examples into doc
* Wed Sep 24 2008 Marcela Maslanova <mmaslano@redhat.com> - 0.57-8
- fix patches for fuzz
* Wed Mar 5 2008 Tom "spot" Callaway <tcallawa@redhat.com> - 0.57-7
- rebuild for new perl
* Tue Feb 19 2008 Fedora Release Engineering <rel-eng@fedoraproject.org> - 0.57-6
- Autorebuild for GCC 4.3
* Wed Dec 05 2007 Release Engineering <rel-eng at fedoraproject dot org> - 0.57-5
- Rebuild for deps
* Wed Dec 5 2007 Robin Norwood <rnorwood@redhat.com> - 0.57-4
- Rebuild for new openssl
* Sat Oct 27 2007 Robin Norwood <rnorwood@redhat.com> - 0.57-3
- Remove unnecessary BR: pkgconfig
* Fri Oct 26 2007 Robin Norwood <rnorwood@redhat.com> - 0.57-2
- Fix buildroot per package review
- Resolves: bz#226248
* Thu Oct 25 2007 Robin Norwood <rnorwood@redhat.com> - 0.57-1
- Update to latest upstream version.
- Remove old patch (patch applied to upstream)
- Several fixes for package review:
- Fixed BuildRequires (added Test::Pod and LWP::UserAgent)
- Apply patch to avoid prompting for input when building Makefile
- Fix defattr line
- Resolves: bz#226248
* Mon Aug 27 2007 Robin Norwood <rnorwood@redhat.com> - 0.56-2
- perl(ExtUtils::MakeMaker::Coverage) is now available
* Mon Aug 13 2007 Robin Norwood <rnorwood@redhat.com> - 0.56-1
- 0.56 is the latest CPAN version, not 0.55
* Mon Aug 13 2007 Robin Norwood <rnorwood@redhat.com> - 0.55-2
- Update to latest version from CPAN: 0.55
- Remove two old patches, update lib64 patch for Makefile.PL changes.
* Tue Feb 13 2007 Robin Norwood <rnorwood@redhat.com> - 0.53-1
- New version: 0.53
* Mon Nov 27 2006 Robin Norwood <rnorwood@redhat.com> - 0.51-12
- Resolves: bug#217138
- fix a segfault on x86_64
* Tue Oct 17 2006 Robin Norwood <rnorwood@redhat.com> - 0.51-10
- Filter out Provides perl(DB)
- bug #205562
* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 0.51-9.2.2.1
- rebuild
* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 0.51-9.2.2
- bump again for double-long bug on ppc(64)
* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 0.51-9.2.1
- rebuilt for new gcc4.1 snapshot and glibc changes
* Fri Feb 03 2006 Jason Vas Dias <jvdias@redhat.com> - 0.51-9.2
- rebuild for new perl-5.8.8 / gcc / glibc
* Fri Dec 16 2005 Jesse Keating <jkeating@redhat.com>
- rebuilt for new gcc
* Fri Dec 16 2005 Jesse Keating <jkeating@redhat.com>
- rebuilt for new gcj
* Thu Nov 10 2005 Tomas Mraz <tmraz@redhat.com> 0.51-9
- rebuilt against new openssl
- added missing SSL_library_init()
* Sat Sep 24 2005 Ville Skyttä <ville.skytta at iki.fi> 0.51-8
- Own more installed dirs (#73908).
- Enable rpmbuild's internal dependency generator, drop unneeded dependencies.
- Require perl(:MODULE_COMPAT_*).
- Run tests in the %%check section.
- Fix License, Source0, URL, and Group tags.
* Wed Mar 30 2005 Warren Togami <wtogami@redhat.com> 0.51-7
- remove brp-compress
* Tue Mar 8 2005 Joe Orton <jorton@redhat.com> 0.51-6
- rebuild
* Tue Aug 31 2004 Chip Turner <cturner@redhat.com> 0.51-5
- build for FC3
* Tue Aug 31 2004 Chip Turner <cturner@redhat.com> 0.51-4
- build for RHEL3 U4
* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
- rebuilt
* Tue Mar 02 2004 Elliot Lee <sopwith@redhat.com>
- rebuilt
* Fri Feb 13 2004 Chip Turner <cturner@redhat.com> 0.51-1
- update to upstream 0.51
* Thu Jun 05 2003 Elliot Lee <sopwith@redhat.com>
- rebuilt
* Tue Jan 7 2003 Nalin Dahyabhai <nalin@redhat.com>
- pass openssl includes to make as INC and ldflags in as LDFLAGS
* Thu Nov 21 2002 Chip Turner <cturner@redhat.com>
- patch to support /usr/lib64 before /usr/lib
* Wed Nov 20 2002 Chip Turner <cturner@redhat.com>
- rebuild
* Tue Aug 6 2002 Chip Turner <cturner@redhat.com>
- automated release bump and build
* Thu Jun 27 2002 Chip Turner <cturner@redhat.com>
- description update
* Tue Jun 25 2002 Chip Turner <cturner@redhat.com>
- move to 0.39
* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
- automated rebuild
* Fri Dec 7 2001 root <root@redhat.com>
- Spec file was autogenerated.

View File

@@ -5,16 +5,20 @@
Name: perl-%{upstream_name}
Version: %{upstream_version}
Release: 2
Release: 3%{?dist}
Summary: Politely process multiple HTTP requests
License: GPL+ or Artistic
Group: Development/Perl
Url: http://search.cpan.org/dist/%{upstream_name}
Source0: http://www.cpan.org/modules/by-module/HTTP/%{upstream_name}-%{upstream_version}.tar.gz
Patch: HTTP-Async-0.30.patch
Patch0: HTTP-Async-0.30.patch
BuildArch: noarch
BuildRequires: perl(ExtUtils::MakeMaker)
BuildRequires: make
BuildRequires: perl-generators
%description
Although using the conventional 'LWP::UserAgent' is fast and easy it does
have some drawbacks - the code execution blocks until the request has been
@@ -35,7 +39,7 @@ using 'select' lists.
%prep
%setup -q -n %{upstream_name}-%{upstream_version}
%patch -p1
%patch 0 -p1
%build
CFLAGS="$RPM_OPT_FLAGS $CFLAGS" %__perl Makefile.PL

View File

@@ -14,7 +14,7 @@
name: perl-IO-Tty
summary: IO-Tty - Pseudo ttys and constants
version: 1.07
release: 1
release: 2%{?dist}
vendor: Roland Giersig <RGiersig@cpan.org>
packager: Arix International <cpan2rpm@arix.com>
license: Artistic
@@ -24,6 +24,13 @@ buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n)
prefix: %(echo %{_prefix})
source: IO-Tty-1.07.tar.gz
BuildRequires: gcc
BuildRequires: make
BuildRequires: perl-interpreter
BuildRequires: perl-devel
BuildRequires: perl(ExtUtils::MakeMaker)
BuildRequires: perl-generators
%description
"IO::Tty" is used internally by "IO::Pty" to create a pseudo-tty.
You wouldn't want to use it directly except to import constants, use
@@ -80,7 +87,7 @@ CFLAGS="$RPM_OPT_FLAGS"
%install
[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
%{makeinstall} `%{__perl} -MExtUtils::MakeMaker -e ' print \$ExtUtils::MakeMaker::VERSION <= 6.05 ? qq|PREFIX=%{buildroot}%{_prefix}| : qq|DESTDIR=%{buildroot}| '`
%{__make} pure_install DESTDIR=%{buildroot}
cmd=/usr/share/spec-helper/compress_files
[ -x $cmd ] || cmd=/usr/lib/rpm/brp-compress

View File

@@ -5,20 +5,22 @@
Name: perl-%{upstream_name}
Version: %{upstream_version}
Release: 2
Release: 3%{?dist}
Summary: Non-blocking HTTPS client
License: GPL+ or Artistic
Group: Development/Perl
Url: http://search.cpan.org/dist/%{upstream_name}
Source0: http://www.cpan.org/modules/by-module/Net/%{upstream_name}-%{upstream_version}.tar.gz
Patch: Net-HTTPS-NB-0.14.patch
Patch0: Net-HTTPS-NB-0.14.patch
BuildRequires: perl(Exporter)
BuildRequires: perl(ExtUtils::MakeMaker)
BuildRequires: perl(IO::Socket::SSL) >= 0.980.0
BuildRequires: perl(Net::HTTP)
BuildRequires: perl(Net::HTTPS)
BuildRequires: make
BuildRequires: perl-generators
BuildArch: noarch
%description
@@ -35,7 +37,7 @@ addition allows non-blocking connect.
%prep
%setup -q -n %{upstream_name}-%{upstream_version}
%patch -p1
%patch 0 -p1
%build
%__perl Makefile.PL

View File

@@ -14,17 +14,24 @@
name: perl-Sys-Virt
summary: Sys-Virt - Represent and manage a libvirt hypervisor connection
version: 0.2.0
release: 2
release: 3%{?dist}
vendor: Daniel P. Berrange <berrange@redhat.com>
packager: Arix International <cpan2rpm@arix.com>
license: Artistic
group: Applications/CPAN
url: http://www.cpan.org
buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n)
buildarch: x86_64
prefix: %(echo %{_prefix})
source: Sys-Virt-0.2.0.tar.gz
patch: Sys-Virt-fixes.patch
patch0: Sys-Virt-fixes.patch
BuildRequires: gcc
BuildRequires: make
BuildRequires: perl-interpreter
BuildRequires: perl-devel
BuildRequires: perl(ExtUtils::MakeMaker)
BuildRequires: perl-generators
BuildRequires: libvirt-devel
%description
The Sys::Virt module provides a Perl XS binding to the libvirt
@@ -40,10 +47,11 @@ a consistent API.
%prep
%setup -q -n %{pkgname}-%{version}
%patch
%patch 0 -p0
chmod -R u+w %{_builddir}/%{pkgname}-%{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)'
@@ -57,7 +65,7 @@ CFLAGS="$RPM_OPT_FLAGS"
%install
[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
%{makeinstall} `%{__perl} -MExtUtils::MakeMaker -e ' print \$ExtUtils::MakeMaker::VERSION <= 6.05 ? qq|PREFIX=%{buildroot}%{_prefix}| : qq|DESTDIR=%{buildroot}| '`
%{__make} pure_install DESTDIR=%{buildroot}
cmd=/usr/share/spec-helper/compress_files
[ -x $cmd ] || cmd=/usr/lib/rpm/brp-compress

399
syslinux/mockbuild.pl Executable file
View File

@@ -0,0 +1,399 @@
#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(dirname basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use Getopt::Long qw(GetOptions);
my $script_dir = abs_path(dirname(__FILE__));
my $repo_root = abs_path("$script_dir/..");
my $pkg_dir = "$repo_root/syslinux";
my $spec_file = "$pkg_dir/syslinux-xcat.spec";
my $source_url = 'https://www.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.xz';
my $source_file = '';
my $work_dir = '/tmp/syslinux-xcat-mockbuild';
my $mock_cfg = '';
my $mock_uniqueext = '';
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;
GetOptions(
'source-url=s' => \$source_url,
'source-file=s' => \$source_file,
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'skip-install!' => \$skip_install,
'skip-upstream-download!' => \$skip_upstream_download,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
die "Missing spec file: $spec_file\n" if !-f $spec_file;
for my $bin (qw(wget mock rpmbuild rpm dnf file bash grep cut)) {
run("command -v " . sh_quote($bin) . " >/dev/null 2>&1");
}
my ($pkg_name, $version, $source_assets_ref, $patch_assets_ref, $all_assets_ref) = parse_spec($spec_file);
my @source_assets = @{$source_assets_ref};
my @patch_assets = @{$patch_assets_ref};
my @all_assets = @{$all_assets_ref};
die "Could not parse Name/Version from $spec_file\n" if !$pkg_name || !$version;
die "No Source assets found in $spec_file\n" if !@source_assets;
if (!$source_file) {
$source_file = $source_assets[0];
}
my $source_path = "$pkg_dir/$source_file";
my $arch = capture('uname -m');
if (!$mock_cfg) {
my $os_id = capture(q{bash -lc 'source /etc/os-release; echo $ID'});
$mock_cfg = "${os_id}+epel-10-${arch}";
}
my $mock_uniqueext_opt = $mock_uniqueext ne ''
? ' --uniqueext ' . sh_quote($mock_uniqueext)
: '';
print_step("Configuration");
print "repo_root: $repo_root\n";
print "pkg_dir: $pkg_dir\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "spec_file: $spec_file\n";
print "pkg_name: $pkg_name\n";
print "version: $version\n";
print "mock_cfg: $mock_cfg\n";
print "mock_uniqueext: " . ($mock_uniqueext ne '' ? $mock_uniqueext : '(none)') . "\n";
print "source_url: $source_url\n";
print "source_file:$source_file\n";
print "skip_install: $skip_install\n";
print "skip_upstream_download: $skip_upstream_download\n";
make_path($result_dir);
make_path($log_dir);
print_step("Mock config check");
run("mock -r " . sh_quote($mock_cfg) . $mock_uniqueext_opt . " --print-root-path >/dev/null");
if (!$skip_upstream_download) {
print_step("Download upstream source");
run("wget --spider " . sh_quote($source_url));
run("wget -O " . sh_quote($source_path) . " " . sh_quote($source_url));
my $sha = capture("sha256sum " . sh_quote($source_path) . " | cut -d ' ' -f1");
my $meta_file = "$log_dir/upstream-source.txt";
open my $mfh, '>', $meta_file or die "Cannot write $meta_file: $!\n";
print {$mfh} "url=$source_url\n";
print {$mfh} "file=$source_path\n";
print {$mfh} "sha256=$sha\n";
close $mfh;
print "Downloaded source: $source_path\n";
print "SHA256: $sha\n";
}
print_step("Verify spec assets");
for my $asset (@all_assets) {
my $path = "$pkg_dir/$asset";
die "Missing required spec asset: $path\n" if !-f $path;
}
print "Verified Sources=" . scalar(@source_assets) . ", Patches=" . scalar(@patch_assets) . "\n";
print_step("Stage files for patch-application check");
remove_tree($work_dir) if -d $work_dir;
my $prep_top = "$work_dir/prep";
for my $d (qw(BUILD BUILDROOT RPMS SOURCES SPECS SRPMS)) {
make_path("$prep_top/$d");
}
copy($spec_file, "$prep_top/SPECS/syslinux-xcat.spec")
or die "Failed to copy spec to prep topdir: $!\n";
for my $asset (@all_assets) {
copy("$pkg_dir/$asset", "$prep_top/SOURCES/$asset")
or die "Failed to copy $asset into prep SOURCES: $!\n";
}
print_step("Apply patches in %prep");
my $prep_log = "$log_dir/prep.log";
run(
"rpmbuild --define " . sh_quote("_topdir $prep_top") .
" -bp --nodeps " . sh_quote("$prep_top/SPECS/syslinux-xcat.spec") .
" > " . sh_quote($prep_log) . " 2>&1"
);
my $patch_count = capture("grep -c '^Patch #' " . sh_quote($prep_log) . " || true");
print "Patch application check passed. Applied patches: $patch_count\n";
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 .
" --buildsrpm --spec " . sh_quote($spec_file) .
" --sources " . sh_quote($pkg_dir) .
" --resultdir " . sh_quote($srpm_out)
);
my @srpms = sort glob("$srpm_out/*.src.rpm");
die "SRPM not generated in $srpm_out\n" if !@srpms;
my $srpm = $srpms[-1];
print "SRPM: $srpm\n";
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 .
" --rebuild " . sh_quote($srpm) .
" --resultdir " . sh_quote($rpm_out)
);
my @all_rpms = sort glob("$rpm_out/*.rpm");
die "No RPMs generated in $rpm_out\n" if !@all_rpms;
my $xcat_rpm = '';
my $main_rpm = '';
for my $rpm (@all_rpms) {
next if $rpm =~ /\.src\.rpm$/;
my $name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($rpm));
my $rarch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($rpm));
if ($name eq 'syslinux-xcat' && $rarch eq 'noarch') {
$xcat_rpm = $rpm;
}
if ($name eq 'syslinux' && $rarch eq $arch) {
$main_rpm = $rpm;
}
}
die "Could not find main syslinux-xcat noarch RPM in $rpm_out\n" if !$xcat_rpm;
print_step("Verify generated RPM");
my $rpm_name = capture("rpm -qp --qf '%{NAME}' " . sh_quote($xcat_rpm));
my $rpm_arch = capture("rpm -qp --qf '%{ARCH}' " . sh_quote($xcat_rpm));
die "Unexpected RPM name: $rpm_name\n" if $rpm_name ne 'syslinux-xcat';
die "Unexpected RPM arch: $rpm_arch (expected noarch)\n" if $rpm_arch ne 'noarch';
run(
"rpm -qpl " . sh_quote($xcat_rpm) .
" | grep -F '/opt/xcat/share/xcat/netboot/syslinux/' >/dev/null"
);
run(
"rpm -qpl " . sh_quote($xcat_rpm) .
" | grep -Fx /opt/xcat/share/xcat/netboot/syslinux/pxelinux.0 >/dev/null"
);
print "Verified RPM name/arch/payload: $xcat_rpm\n";
print_step("Copy artifacts and logs");
for my $rpm (@all_rpms) {
copy($rpm, $result_dir) or die "Failed to copy $rpm to $result_dir: $!\n";
}
copy($srpm, $result_dir) or die "Failed to copy $srpm to $result_dir: $!\n";
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$rpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/$log")
or die "Failed to copy $src to $log_dir: $!\n";
}
for my $log (qw(build.log root.log state.log hw_info.log installed_pkgs.log)) {
my $src = "$srpm_out/$log";
next if !-f $src;
copy($src, "$log_dir/srpm-$log")
or die "Failed to copy $src to $log_dir: $!\n";
}
if (!$skip_install) {
print_step("Install RPM(s) and run smoke tests");
run("dnf -y install " . sh_quote($xcat_rpm));
if ($main_rpm) {
run("dnf -y install " . sh_quote($main_rpm));
}
my $pxe_file = '/opt/xcat/share/xcat/netboot/syslinux/pxelinux.0';
die "Missing installed PXE file: $pxe_file\n" if !-f $pxe_file;
my $file_log = "$log_dir/smoke-file.log";
my $qf_log = "$log_dir/smoke-rpm-qf.log";
my $rc_file = run_capture_rc("file $pxe_file", $file_log);
my $rc_qf = run_capture_rc("rpm -qf $pxe_file", $qf_log);
die "Smoke check failed: file returned $rc_file\n" if $rc_file != 0;
die "Smoke check failed: rpm -qf returned $rc_qf\n" if $rc_qf != 0;
my $qf_out = slurp($qf_log);
die "Installed file is not owned by syslinux-xcat:\n$qf_out\n"
if $qf_out !~ /^syslinux-xcat-/m;
my $syslinux_help_log = "$log_dir/smoke-syslinux-help.log";
if (-x '/usr/bin/syslinux') {
my $rc_help = run_capture_rc("/usr/bin/syslinux --help", $syslinux_help_log);
my $help_out = slurp($syslinux_help_log);
die "syslinux --help returned unexpected rc=$rc_help\n"
if $rc_help != 0 && $rc_help != 1;
die "syslinux --help output missing expected usage text\n"
if $help_out !~ /usage|syslinux/i;
}
my $summary = "$log_dir/smoke-summary.txt";
open my $sfh, '>', $summary or die "Cannot write $summary: $!\n";
print {$sfh} "pxe_file=$pxe_file\n";
print {$sfh} "rc_file=$rc_file\n";
print {$sfh} "rc_qf=$rc_qf\n";
print {$sfh} "main_rpm_installed=" . ($main_rpm ? 1 : 0) . "\n";
close $sfh;
}
print_step("Completed");
print "syslinux-xcat RPM: $xcat_rpm\n";
print "Artifacts: $result_dir\n";
print "Logs: $log_dir\n";
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
--source-url URL Upstream tarball URL (default: $source_url)
--source-file FILE Source filename stored in syslinux/ (default: inferred from spec)
--work-dir PATH Temporary work dir (default: $work_dir)
--mock-cfg NAME Mock config (default: <ID>+epel-10-<ARCH>)
--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)
--skip-upstream-download Skip wget download step
--skip-install Skip dnf install + smoke tests
USAGE
}
sub parse_spec {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open spec $path: $!\n";
my %macros;
my $name = '';
my $version = '';
my @sources;
my @patches;
while (my $line = <$fh>) {
if ($line =~ /^\s*%(?:define|global)\s+([A-Za-z0-9_]+)\s+(.+?)\s*$/) {
my ($k, $v) = (lc($1), $2);
$v =~ s/\s+#.*$//;
$macros{$k} = $v;
next;
}
if ($line =~ /^Name:\s*(\S+)/) {
$name = $1;
$macros{name} = $name;
next;
}
if ($line =~ /^Version:\s*(\S+)/) {
$version = $1;
$macros{version} = $version;
next;
}
if ($line =~ /^Source\d*:\s*(\S+)/) {
push @sources, $1;
next;
}
if ($line =~ /^Patch\d*:\s*(\S+)/) {
push @patches, $1;
next;
}
}
close $fh;
$name = expand_macros($name, \%macros);
$macros{name} = $name if $name;
$version = expand_macros($version, \%macros);
$macros{version} = $version if $version;
@sources = map { normalize_asset(expand_macros($_, \%macros)) } @sources;
@patches = map { normalize_asset(expand_macros($_, \%macros)) } @patches;
my @assets = (@sources, @patches);
return ($name, $version, \@sources, \@patches, \@assets);
}
sub expand_macros {
my ($text, $macros) = @_;
return '' if !defined $text;
for (1..30) {
my $prev = $text;
$text =~ s/%\{([^}]+)\}/
exists $macros->{lc($1)} ? $macros->{lc($1)} : "%{$1}"
/ge;
last if $text eq $prev;
}
return $text;
}
sub normalize_asset {
my ($asset) = @_;
$asset //= '';
$asset =~ s/^["']//;
$asset =~ s/["']$//;
$asset =~ s/\?.*$//;
if ($asset =~ m{^[A-Za-z][A-Za-z0-9+.-]*://}) {
$asset =~ s{.*/}{};
}
$asset =~ s{^\./}{};
return $asset;
}
sub print_step {
my ($msg) = @_;
print "\n== $msg ==\n";
}
sub sh_quote {
my ($s) = @_;
$s =~ s/'/'"'"'/g;
return "'$s'";
}
sub run {
my ($cmd) = @_;
print "+ $cmd\n";
my $rc = system($cmd);
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\n";
}
}
sub capture {
my ($cmd) = @_;
print "+ $cmd\n";
my $out = `$cmd`;
my $rc = $?;
if ($rc != 0) {
my $exit = $rc == -1 ? 255 : ($rc >> 8);
die "Command failed (rc=$exit): $cmd\nOutput:\n$out\n";
}
chomp $out;
return $out;
}
sub run_capture_rc {
my ($cmd, $log_file) = @_;
my $full = "$cmd > " . sh_quote($log_file) . " 2>&1";
print "+ $full\n";
my $rc = system($full);
return $rc == -1 ? 255 : ($rc >> 8);
}
sub slurp {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot read $path: $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}

View File

@@ -0,0 +1,53 @@
--- a/com32/mboot/mboot.c 2014-10-06 09:29:01.000000000 -0700
+++ b/com32/mboot/mboot.c 2026-03-02 00:00:00.000000000 +0000
@@ -93,9 +93,18 @@ static int get_modules(char **argv, struct module_data **mdp)
char **argp, **argx;
struct module_data *mp;
int rv;
+ int firstmod = 1;
int module_count = 1;
int arglen;
const char module_separator[] = "---";
+ com32sys_t reg;
+ const char *bootifstr = "";
+
+ reg.eax.w[0] = 0x000f; /* Get IPAPPEND strings */
+ __intcall(0x22, &reg, &reg);
+ if (!(reg.eflags.l & EFLAGS_CF))
+ bootifstr = MK_PTR(reg.es,
+ *(uint16_t *)MK_PTR(reg.es, reg.ebx.w[0] + 2));
for (argp = argv; *argp; argp++) {
if (!strcmp(*argp, module_separator))
@@ -130,15 +139,29 @@ static int get_modules(char **argv, struct module_data **mdp)
arglen += strlen(*argx) + 1;
if (arglen == 0) {
- mp->cmdline = strdup("");
+ if (firstmod) {
+ firstmod = 0;
+ mp->cmdline = strdup(bootifstr);
+ } else {
+ mp->cmdline = strdup("");
+ }
} else {
char *p;
+ if (firstmod)
+ arglen += strlen(bootifstr) + 1;
+
mp->cmdline = p = malloc(arglen);
for (; *argp && strcmp(*argp, module_separator); argp++) {
p = stpcpy(p, *argp);
*p++ = ' ';
}
- *--p = '\0';
+ if (firstmod) {
+ firstmod = 0;
+ p = stpcpy(p, bootifstr);
+ *p = '\0';
+ } else {
+ *--p = '\0';
+ }
}
mp++;
if (*argp)

View File

@@ -1,30 +1,34 @@
# -*- rpm -*-
%define RPMVERSION 3.86
%define VERSION 3.86
%define RPMVERSION 6.03
%define VERSION 6.03
Summary: Kernel loader which uses a FAT, ext2/3 or iso9660 filesystem or a PXE network
Name: syslinux
Version: %{RPMVERSION}
Release: 2
Release: 1
License: GPL
Group: System/Boot
Source0: ftp://ftp.kernel.org/pub/linux/utils/boot/syslinux/%{name}-%{VERSION}.tar.bz2
Patch0: syslinux-3.86-multibootif.patch
ExclusiveArch: i386 i486 i586 i686 athlon pentium4 x86_64
Source0: https://www.kernel.org/pub/linux/utils/boot/syslinux/%{name}-%{VERSION}.tar.xz
Patch0: syslinux-6.03-multibootif.patch
ExclusiveArch: i386 i486 i586 i686 athlon pentium4 x86_64 ppc64le
Packager: H. Peter Anvin <hpa@zytor.com>
Buildroot: %{_tmppath}/%{name}-%{VERSION}-root
BuildPrereq: nasm >= 0.98.39, perl
Autoreq: 0
BuildRequires: mtools, libc.so.6()(64bit)
BuildRequires: nasm >= 2.03, perl
BuildRequires: mtools, libc.so.6()(64bit), python3
BuildRequires: git
BuildRequires: libuuid-devel
%define my_cc gcc
# NOTE: extlinux belongs in /sbin, not in /usr/sbin, since it is typically
# a system bootloader, and may be necessary for system recovery.
%define _sbindir /sbin
%ifnarch ppc64le
%package devel
Summary: Development environment for SYSLINUX add-on modules
Group: Development/Libraries
Requires: syslinux
%endif
%description
SYSLINUX is a suite of bootloaders, currently supporting DOS FAT
@@ -32,10 +36,12 @@ filesystems, Linux ext2/ext3 filesystems (EXTLINUX), PXE network boots
(PXELINUX), or ISO 9660 CD-ROMs (ISOLINUX). It also includes a tool,
MEMDISK, which loads legacy operating systems from these media.
%ifnarch ppc64le
%description devel
The SYSLINUX boot loader contains an API, called COM32, for writing
sophisticated add-on modules. This package contains the libraries
necessary to compile such modules.
%endif
%package extlinux
Summary: The EXTLINUX bootloader, for booting the local system.
@@ -58,24 +64,43 @@ booting in the /opt/xcat/share/xcat/netboot/syslinux directory.
%prep
%setup -q -n syslinux-%{VERSION}
%patch0 -p1
# Source tarballs do not include .git metadata; skip submodule refresh in that case.
sed -i 's/^[[:space:]]*git submodule update --init$/[ -d .git ] \&\& git submodule update --init || :/' efi/clean-gnu-efi.sh
# GCC/glibc compatibility for major()/minor() declarations.
sed -i '/#include <sys\/types.h>/a #include <sys/sysmacros.h>' extlinux/main.c
# GCC14 strict prototype fix in COM32 syslinux debug helper.
sed -i '/#include <stdbool.h>/a #include <stdio.h>' com32/lib/syslinux/debug.c
# GCC >= 10 defaults to -fno-common; legacy syslinux code expects common symbols.
for f in mk/lib.mk mk/com32.mk mk/elf.mk mk/embedded.mk; do \
sed -i '/fno-strict-aliasing/a GCCOPT += $(call gcc_ok,-fcommon,)' "$f"; \
done
%build
make CC='%{my_cc}' clean
make CC='%{my_cc}' -C com32
make CC='%{my_cc}' installer
make CC='%{my_cc}' -C sample tidy
make CC='%{my_cc}' PYTHON=python3 clean
make CC='%{my_cc}' PYTHON=python3 installer
%install
rm -rf %{buildroot}
make CC='%{my_cc}' install-all \
%ifarch ppc64le
make CC='%{my_cc}' PYTHON=python3 install \
INSTALLROOT=%{buildroot} BINDIR=%{_bindir} SBINDIR=%{_sbindir} \
LIBDIR=%{_libdir} DATADIR=%{_datadir} \
MANDIR=%{_mandir} INCDIR=%{_includedir} \
TFTPBOOT=/opt/xcat/share/xcat/netboot/syslinux EXTLINUXDIR=/boot/extlinux
rm %{buildroot}/usr/share/syslinux/dosutil/copybs.com
rm %{buildroot}/usr/share/syslinux/dosutil/eltorito.sys
rm %{buildroot}/usr/share/syslinux/dosutil/mdiskchk.com
make CC='%{my_cc}' -C sample tidy
INSTALLSUBDIRS=
%else
make CC='%{my_cc}' PYTHON=python3 install \
INSTALLROOT=%{buildroot} BINDIR=%{_bindir} SBINDIR=%{_sbindir} \
LIBDIR=%{_libdir} DATADIR=%{_datadir} \
MANDIR=%{_mandir} INCDIR=%{_includedir}
%endif
make CC='%{my_cc}' PYTHON=python3 netinstall \
INSTALLROOT=%{buildroot} TFTPBOOT=/opt/xcat/share/xcat/netboot/syslinux
if make -n extbootinstall >/dev/null 2>&1; then \
make CC='%{my_cc}' PYTHON=python3 extbootinstall \
INSTALLROOT=%{buildroot} EXTLINUXDIR=/boot/extlinux; \
else \
mkdir -p %{buildroot}/boot/extlinux; \
fi
mkdir -p %{buildroot}/etc
( cd %{buildroot}/etc && ln -s ../boot/extlinux/extlinux.conf . )
@@ -94,9 +119,17 @@ rm -rf %{buildroot}
%{_datadir}/syslinux/*.bin
%{_datadir}/syslinux/*.0
%{_datadir}/syslinux/memdisk
%ifnarch ppc64le
%{_datadir}/syslinux/dosutil/*
%endif
%{_datadir}/syslinux/diag/*
%{_datadir}/syslinux/efi32
%{_datadir}/syslinux/efi64
%ifnarch ppc64le
%files devel
%{_datadir}/syslinux/com32
%endif
%files extlinux
%{_sbindir}/extlinux
@@ -255,7 +288,7 @@ fi
* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
- automatic rebuild
* Thu Jul 06 2000 Trond Eivind Glomsrød <teg@redhat.com>
* Thu Jul 06 2000 Trond Eivind Glomsrod <teg@redhat.com>
- use %%{_tmppath}
- change application group (Applications/Internet doesn't seem
right to me)

View File

@@ -0,0 +1,274 @@
diff -urN xnba-1.21.1/src/arch/x86/core/patch_cf.S xnba-1.21.1.mod/src/arch/x86/core/patch_cf.S
--- xnba-1.21.1/src/arch/x86/core/patch_cf.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/core/patch_cf.S 2026-03-02 16:08:49.051016121 -0300
@@ -23,8 +23,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
- .arch i386
.code16
+ .arch i386
/****************************************************************************
* Set/clear CF on the stack as appropriate, assumes stack is as it should
diff -urN xnba-1.21.1/src/arch/x86/core/stack.S xnba-1.21.1.mod/src/arch/x86/core/stack.S
--- xnba-1.21.1/src/arch/x86/core/stack.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/core/stack.S 2026-03-02 16:08:49.051016121 -0300
@@ -1,6 +1,5 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
- .arch i386
#ifdef __x86_64__
#define STACK_SIZE 8192
diff -urN xnba-1.21.1/src/arch/x86/core/stack16.S xnba-1.21.1.mod/src/arch/x86/core/stack16.S
--- xnba-1.21.1/src/arch/x86/core/stack16.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/core/stack16.S 2026-03-02 16:08:49.051016121 -0300
@@ -1,6 +1,5 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
- .arch i386
/****************************************************************************
* Internal stack
diff -urN xnba-1.21.1/src/arch/x86/drivers/net/undiisr.S xnba-1.21.1.mod/src/arch/x86/drivers/net/undiisr.S
--- xnba-1.21.1/src/arch/x86/drivers/net/undiisr.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/drivers/net/undiisr.S 2026-03-02 16:08:49.051016121 -0300
@@ -11,8 +11,8 @@
#define PIC2_ICR 0xa0
.text
- .arch i386
.code16
+ .arch i386
.section ".text16", "ax", @progbits
.globl undiisr
diff -urN xnba-1.21.1/src/arch/x86/interface/pcbios/e820mangler.S xnba-1.21.1.mod/src/arch/x86/interface/pcbios/e820mangler.S
--- xnba-1.21.1/src/arch/x86/interface/pcbios/e820mangler.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/interface/pcbios/e820mangler.S 2026-03-02 16:08:49.051016121 -0300
@@ -24,8 +24,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
- .arch i386
.code16
+ .arch i386
#define SMAP 0x534d4150
diff -urN xnba-1.21.1/src/arch/x86/interface/pxe/pxe_entry.S xnba-1.21.1.mod/src/arch/x86/interface/pxe/pxe_entry.S
--- xnba-1.21.1/src/arch/x86/interface/pxe/pxe_entry.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/interface/pxe/pxe_entry.S 2026-03-02 16:08:49.051016121 -0300
@@ -26,7 +26,6 @@
#include <librm.h>
- .arch i386
/****************************************************************************
* !PXE structure
diff -urN xnba-1.21.1/src/arch/x86/prefix/bootpart.S xnba-1.21.1.mod/src/arch/x86/prefix/bootpart.S
--- xnba-1.21.1/src/arch/x86/prefix/bootpart.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/bootpart.S 2026-03-02 16:08:49.054349513 -0300
@@ -6,7 +6,6 @@
#define STACK_SIZE 0x2000
.text
- .arch i386
.section ".prefix", "awx", @progbits
.code16
diff -urN xnba-1.21.1/src/arch/x86/prefix/dskprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/dskprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/dskprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/dskprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -25,7 +25,6 @@
.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
.org 0
- .arch i386
.text
.section ".prefix", "ax", @progbits
.code16
diff -urN xnba-1.21.1/src/arch/x86/prefix/exeprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/exeprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/exeprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/exeprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -37,7 +37,6 @@
#define PSP_CMDLINE_START 0x81
.text
- .arch i386
.org 0
.code16
.section ".prefix", "awx", @progbits
diff -urN xnba-1.21.1/src/arch/x86/prefix/hdprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/hdprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/hdprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/hdprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -3,7 +3,6 @@
#include <librm.h>
.text
- .arch i386
.section ".prefix", "awx", @progbits
.code16
.org 0
diff -urN xnba-1.21.1/src/arch/x86/prefix/libprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/libprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/libprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/libprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -26,7 +26,6 @@
#include <librm.h>
- .arch i386
/* Image compression enabled */
#define COMPRESS 1
diff -urN xnba-1.21.1/src/arch/x86/prefix/lkrnprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/lkrnprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/lkrnprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/lkrnprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -5,8 +5,8 @@
#define BZI_LOAD_HIGH_ADDR 0x100000
.text
- .arch i386
.code16
+ .arch i386
.section ".prefix", "ax", @progbits
.globl _lkrn_start
_lkrn_start:
diff -urN xnba-1.21.1/src/arch/x86/prefix/mbr.S xnba-1.21.1.mod/src/arch/x86/prefix/mbr.S
--- xnba-1.21.1/src/arch/x86/prefix/mbr.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/mbr.S 2026-03-02 16:08:49.054349513 -0300
@@ -1,7 +1,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
- .arch i386
.section ".prefix", "awx", @progbits
.code16
.org 0
diff -urN xnba-1.21.1/src/arch/x86/prefix/mromprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/mromprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/mromprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/mromprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -42,8 +42,8 @@
#include "pciromprefix.S"
.text
- .arch i386
.code16
+ .arch i386
/* Obtain access to payload by exposing the expansion ROM BAR at the
* address currently used by a suitably large memory BAR on the same
diff -urN xnba-1.21.1/src/arch/x86/prefix/nbiprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/nbiprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/nbiprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/nbiprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -3,8 +3,8 @@
#include <librm.h>
.text
- .arch i386
.code16
+ .arch i386
.section ".prefix", "ax", @progbits
.org 0
diff -urN xnba-1.21.1/src/arch/x86/prefix/nullprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/nullprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/nullprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/nullprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -2,7 +2,6 @@
.org 0
.text
- .arch i386
.section ".prefix", "ax", @progbits
.code16
diff -urN xnba-1.21.1/src/arch/x86/prefix/pxeprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/pxeprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/pxeprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/pxeprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -12,7 +12,6 @@
#define PXE_HACK_EB54 0x0001
.text
- .arch i386
.org 0
.code16
diff -urN xnba-1.21.1/src/arch/x86/prefix/rawprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/rawprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/rawprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/rawprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -9,7 +9,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
- .arch i386
.org 0
.code16
diff -urN xnba-1.21.1/src/arch/x86/prefix/romprefix.S xnba-1.21.1.mod/src/arch/x86/prefix/romprefix.S
--- xnba-1.21.1/src/arch/x86/prefix/romprefix.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/romprefix.S 2026-03-02 16:08:49.054349513 -0300
@@ -56,7 +56,6 @@
.text
.code16
- .arch i386
.section ".prefix", "ax", @progbits
.globl _rom_start
_rom_start:
diff -urN xnba-1.21.1/src/arch/x86/prefix/undiloader.S xnba-1.21.1.mod/src/arch/x86/prefix/undiloader.S
--- xnba-1.21.1/src/arch/x86/prefix/undiloader.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/undiloader.S 2026-03-02 16:08:49.054349513 -0300
@@ -4,7 +4,6 @@
.text
.code16
- .arch i386
.section ".prefix", "ax", @progbits
/* UNDI loader
diff -urN xnba-1.21.1/src/arch/x86/prefix/unlzma.S xnba-1.21.1.mod/src/arch/x86/prefix/unlzma.S
--- xnba-1.21.1/src/arch/x86/prefix/unlzma.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/unlzma.S 2026-03-02 16:08:49.054349513 -0300
@@ -44,7 +44,6 @@
*/
.text
- .arch i486
.section ".prefix.lib", "ax", @progbits
#ifdef CODE16
diff -urN xnba-1.21.1/src/arch/x86/prefix/usbdisk.S xnba-1.21.1.mod/src/arch/x86/prefix/usbdisk.S
--- xnba-1.21.1/src/arch/x86/prefix/usbdisk.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/prefix/usbdisk.S 2026-03-02 16:08:49.054349513 -0300
@@ -3,7 +3,6 @@
#include <config/console.h>
.text
- .arch i386
.section ".prefix", "awx", @progbits
.code16
.org 0
diff -urN xnba-1.21.1/src/arch/x86/transitions/liba20.S xnba-1.21.1.mod/src/arch/x86/transitions/liba20.S
--- xnba-1.21.1/src/arch/x86/transitions/liba20.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/transitions/liba20.S 2026-03-02 16:08:49.054349513 -0300
@@ -24,7 +24,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
- .arch i386
/****************************************************************************
* test_a20_short, test_a20_long
diff -urN xnba-1.21.1/src/arch/x86/transitions/libkir.S xnba-1.21.1.mod/src/arch/x86/transitions/libkir.S
--- xnba-1.21.1/src/arch/x86/transitions/libkir.S 2021-09-23 14:29:02.000000000 -0300
+++ xnba-1.21.1.mod/src/arch/x86/transitions/libkir.S 2026-03-02 16:08:49.054349513 -0300
@@ -32,7 +32,6 @@
#define BOCHSBP xchgw %bx, %bx
.text
- .arch i386
.section ".text16", "awx", @progbits
.code16

View File

@@ -20,6 +20,13 @@ Patch2: ipxe-machyp.patch
Patch3: ipxe-xnbaclass.patch
Patch4: ipxe-dhcp.patch
Patch5: ipxe-verbump.patch
Patch6: ipxe-binutils-2.41-compat.patch
BuildRequires: make
BuildRequires: gcc
BuildRequires: binutils
BuildRequires: perl
BuildRequires: xz-devel
%description
The xCAT Network Boot Agent is a slightly modified version of iPXE. It provides enhanced boot features for any UNDI compliant x86 host. This includes iSCSI, http/ftp downloads, and iPXE script based booting.
@@ -32,14 +39,15 @@ The xCAT Network Boot Agent is a slightly modified version of iPXE. It provides
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%build
rm -rf %{buildroot}
cd src
make bin/undionly.kkpxe
make bin-x86_64-efi/snponly.efi
make NO_WERROR=1 bin/undionly.kkpxe
make NO_WERROR=1 bin-x86_64-efi/snponly.efi
%install