Browse Source

xtask: patch gen_init_cpio.c

Recent changes[0][1] have broken compatibility with macOS; add a patch
to conditionally compile these snippets.

Patch and compile the source unconditionally; caching only the network
portion is good enough and less error prone.

[0] https://github.com/torvalds/linux/commit/ae18b94099b04264b32e33b057114024bc72c993
[1] https://github.com/torvalds/linux/commit/97169cd6d95b338f2dbf5d3154b7d2233fce7d8a
Tamir Duberstein 4 weeks ago
parent
commit
bb45904b08
2 changed files with 77 additions and 28 deletions
  1. 32 0
      xtask/patches/gen_init_cpio.c.macos.diff
  2. 45 28
      xtask/src/run.rs

+ 32 - 0
xtask/patches/gen_init_cpio.c.macos.diff

@@ -0,0 +1,32 @@
+diff --git a/gen_init_cpio.c b/gen_init_cpio.c
+index 75e9561b..406c4d0a 100644
+--- a/gen_init_cpio.c
++++ b/gen_init_cpio.c
+@@ -453,6 +453,7 @@ static int cpio_mkfile(const char *name, const char *location,
+ 		    push_pad(namepadlen ? namepadlen : padlen(offset, 4)) < 0)
+ 			goto error;
+ 
++#ifdef __linux__
+ 		if (size) {
+ 			this_read = copy_file_range(file, NULL, outfd, NULL, size, 0);
+ 			if (this_read > 0) {
+@@ -463,6 +464,7 @@ static int cpio_mkfile(const char *name, const char *location,
+ 			}
+ 			/* short or failed copy falls back to read/write... */
+ 		}
++#endif
+ 
+ 		while (size) {
+ 			unsigned char filebuf[65536];
+@@ -671,7 +673,10 @@ int main (int argc, char *argv[])
+ 			break;
+ 		case 'o':
+ 			outfd = open(optarg,
+-				     O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC,
++#ifdef O_LARGEFILE
++				     O_LARGEFILE |
++#endif
++				     O_WRONLY | O_CREAT | O_TRUNC,
+ 				     0600);
+ 			if (outfd < 0) {
+ 				fprintf(stderr, "failed to open %s\n", optarg);

+ 45 - 28
xtask/src/run.rs

@@ -16,6 +16,8 @@ use clap::Parser;
 use walkdir::WalkDir;
 use xtask::{AYA_BUILD_INTEGRATION_BPF, Errors};
 
+const GEN_INIT_CPIO_PATCH: &str = include_str!("../patches/gen_init_cpio.c.macos.diff");
+
 #[derive(Parser)]
 enum Environment {
     /// Runs the integration tests locally.
@@ -231,68 +233,83 @@ pub(crate) fn run(opts: Options) -> Result<()> {
             // VM images and report to the user. The end.
 
             create_dir_all(&cache_dir).context("failed to create cache dir")?;
+
             let gen_init_cpio = cache_dir.join("gen_init_cpio");
-            let etag_path = cache_dir.join("gen_init_cpio.etag");
             {
-                let gen_init_cpio_exists = gen_init_cpio.try_exists().with_context(|| {
-                    format!("failed to check existence of {}", gen_init_cpio.display())
+                let dest_path = cache_dir.join("gen_init_cpio.c");
+                let etag_path = cache_dir.join("gen_init_cpio.etag");
+                let dest_path_exists = dest_path.try_exists().with_context(|| {
+                    format!("failed to check existence of {}", dest_path.display())
                 })?;
                 let etag_path_exists = etag_path.try_exists().with_context(|| {
                     format!("failed to check existence of {}", etag_path.display())
                 })?;
-                if !gen_init_cpio_exists && etag_path_exists {
+                if !dest_path_exists && etag_path_exists {
                     println!(
                         "cargo:warning=({}).exists()={} != ({})={} (mismatch)",
-                        gen_init_cpio.display(),
-                        gen_init_cpio_exists,
+                        dest_path.display(),
+                        dest_path_exists,
                         etag_path.display(),
                         etag_path_exists,
                     )
                 }
-            }
 
-            let gen_init_cpio_source = {
-                drop(github_api_token); // Currently unused, but kept around in case we need it in the future.
+                // Currently unused. Can be used for authenticated requests if needed in the future.
+                drop(github_api_token);
 
                 let mut curl = Command::new("curl");
                 curl.args([
                     "-sfSL",
                     "https://raw.githubusercontent.com/torvalds/linux/master/usr/gen_init_cpio.c",
-                ]);
+                    "--output",
+                ])
+                .arg(&dest_path);
                 for arg in ["--etag-compare", "--etag-save"] {
                     curl.arg(arg).arg(&etag_path);
                 }
 
-                let Output {
-                    status,
-                    stdout,
-                    stderr,
-                } = curl
+                let output = curl
                     .output()
                     .with_context(|| format!("failed to run {curl:?}"))?;
+                let Output { status, .. } = &output;
                 if status.code() != Some(0) {
-                    bail!("{curl:?} failed: stdout={stdout:?} stderr={stderr:?}")
+                    bail!("{curl:?} failed: {output:?}")
                 }
-                stdout
-            };
 
-            if !gen_init_cpio_source.is_empty() {
+                let mut patch = Command::new("patch");
+                patch
+                    .current_dir(&cache_dir)
+                    .args(["--quiet", "--forward", "--output", "-"])
+                    .stdin(Stdio::piped())
+                    .stdout(Stdio::piped());
+                let mut patch_child = patch
+                    .spawn()
+                    .with_context(|| format!("failed to spawn {patch:?}"))?;
+
+                let Child { stdin, stdout, .. } = &mut patch_child;
+                let mut stdin = stdin.take().unwrap();
+                stdin
+                    .write_all(GEN_INIT_CPIO_PATCH.as_bytes())
+                    .with_context(|| format!("failed to write to {patch:?} stdin"))?;
+                drop(stdin); // Must explicitly close to signal EOF.
+                let stdout = stdout.take().unwrap();
+
                 let mut clang = Command::new("clang");
                 clang
                     .args(["-g", "-O2", "-x", "c", "-", "-o"])
                     .arg(&gen_init_cpio)
-                    .stdin(Stdio::piped());
-                let mut clang_child = clang
+                    .stdin(stdout);
+                let clang_child = clang
                     .spawn()
                     .with_context(|| format!("failed to spawn {clang:?}"))?;
 
-                let Child { stdin, .. } = &mut clang_child;
-
-                let mut stdin = stdin.take().unwrap();
-                stdin
-                    .write_all(&gen_init_cpio_source)
-                    .with_context(|| format!("failed to write to {clang:?} stdin"))?;
-                drop(stdin); // Must explicitly close to signal EOF.
+                let output = patch_child
+                    .wait_with_output()
+                    .with_context(|| format!("failed to wait for {patch:?}"))?;
+                let Output { status, .. } = &output;
+                if status.code() != Some(0) {
+                    bail!("{patch:?} failed: {output:?}")
+                }
 
                 let output = clang_child
                     .wait_with_output()