|
5 | 5 | */ |
6 | 6 |
|
7 | 7 | use std::cell::RefCell; |
| 8 | +use std::collections::BTreeMap; |
8 | 9 | use std::os::unix::io::AsRawFd; |
9 | 10 | use std::path::{Path, PathBuf}; |
10 | 11 | use std::process::Command; |
@@ -328,6 +329,7 @@ impl Component for Efi { |
328 | 329 | meta: updatemeta.clone(), |
329 | 330 | filetree: Some(updatef), |
330 | 331 | adopted_from: Some(meta.version), |
| 332 | + firmware: BTreeMap::new(), |
331 | 333 | })) |
332 | 334 | } |
333 | 335 |
|
@@ -372,15 +374,70 @@ impl Component for Efi { |
372 | 374 | .arg(destpath) |
373 | 375 | .current_dir(format!("/proc/self/fd/{}", src_root.as_raw_fd())) |
374 | 376 | .run()?; |
| 377 | + |
| 378 | + let mut found_firmware = BTreeMap::new(); |
| 379 | + // Scan and install supplemental firmware |
| 380 | + let firmware_base_dir_path = Path::new("usr/lib/efi/firmware"); |
| 381 | + if src_root.exists(firmware_base_dir_path)? { |
| 382 | + let firmware_base_dir = src_root.sub_dir(firmware_base_dir_path)?; |
| 383 | + for pkg_entry in firmware_base_dir.list_dir(".")?.flatten() { |
| 384 | + if firmware_base_dir.get_file_type(&pkg_entry)? != openat::SimpleType::Dir { |
| 385 | + continue; |
| 386 | + } |
| 387 | + let pkg_name = pkg_entry.file_name().to_string_lossy().to_string(); |
| 388 | + let pkg_dir = firmware_base_dir.sub_dir(pkg_entry.file_name())?; |
| 389 | + |
| 390 | + let mut versions: Vec<_> = pkg_dir.list_dir(".")?.filter_map(Result::ok).collect(); |
| 391 | + versions.sort_by_key(|e| e.file_name().to_owned()); |
| 392 | + |
| 393 | + if let Some(ver_entry) = versions.pop() { |
| 394 | + let ver_dir = pkg_dir.sub_dir(ver_entry.file_name())?; |
| 395 | + let meta_path = Path::new("EFI.json"); |
| 396 | + |
| 397 | + if ver_dir.exists(meta_path)? { |
| 398 | + log::debug!( |
| 399 | + "Found supplemental firmware: {}/{}", |
| 400 | + pkg_name, |
| 401 | + ver_entry.file_name().to_string_lossy() |
| 402 | + ); |
| 403 | + let firmware_meta: ContentMetadata = |
| 404 | + serde_json::from_reader(ver_dir.open_file(meta_path)?)?; |
| 405 | + let payload_src_dir = ver_dir.sub_dir("EFI")?; |
| 406 | + let firmware_filetree = |
| 407 | + crate::filetree::FileTree::new_from_dir(&payload_src_dir)?; |
| 408 | + // copy all by applying a diff with a empty filetree |
| 409 | + let empty_filetree = filetree::FileTree { |
| 410 | + children: Default::default(), |
| 411 | + }; |
| 412 | + let diff = empty_filetree.diff(&firmware_filetree)?; |
| 413 | + filetree::apply_diff(&payload_src_dir, destd, &diff, None) |
| 414 | + .context("applying supplemental firmware")?; |
| 415 | + |
| 416 | + found_firmware.insert( |
| 417 | + pkg_name.clone(), |
| 418 | + Box::new(InstalledContent { |
| 419 | + meta: firmware_meta, |
| 420 | + filetree: Some(firmware_filetree), |
| 421 | + adopted_from: None, |
| 422 | + firmware: BTreeMap::new(), |
| 423 | + }), |
| 424 | + ); |
| 425 | + } |
| 426 | + } |
| 427 | + } |
| 428 | + } |
| 429 | + |
375 | 430 | if update_firmware { |
376 | | - if let Some(vendordir) = self.get_efi_vendor(&src_root)? { |
| 431 | + if let Some(vendordir) = self.get_efi_vendor(src_root)? { |
377 | 432 | self.update_firmware(device, destd, &vendordir)? |
378 | 433 | } |
379 | 434 | } |
| 435 | + |
380 | 436 | Ok(InstalledContent { |
381 | 437 | meta, |
382 | 438 | filetree: Some(ft), |
383 | 439 | adopted_from: None, |
| 440 | + firmware: found_firmware, |
384 | 441 | }) |
385 | 442 | } |
386 | 443 |
|
@@ -424,6 +481,7 @@ impl Component for Efi { |
424 | 481 | meta: updatemeta, |
425 | 482 | filetree: Some(updatef), |
426 | 483 | adopted_from, |
| 484 | + firmware: BTreeMap::new(), |
427 | 485 | }) |
428 | 486 | } |
429 | 487 |
|
@@ -465,72 +523,71 @@ impl Component for Efi { |
465 | 523 | fn extend_payload(&self, sysroot_path: &str, src_input: &str) -> Result<Option<bool>> { |
466 | 524 | let dest_efidir_base = Path::new(sysroot_path).join("usr/lib/efi").join("firmware"); |
467 | 525 |
|
468 | | - // Fetch version and release from the source input using query_files |
469 | 526 | let src_input_path = Path::new(src_input); |
470 | | - let meta_from_src = packagesystem::query_files(sysroot_path, [src_input_path]) |
| 527 | + let path_to_query = if src_input_path.is_dir() { |
| 528 | + WalkDir::new(src_input_path) |
| 529 | + .into_iter() |
| 530 | + .filter_map(|e| e.ok()) |
| 531 | + .find(|e| e.file_type().is_file()) |
| 532 | + .map(|e| e.path().to_path_buf()) |
| 533 | + .ok_or_else(|| anyhow!("No file found in directory {}", src_input))? |
| 534 | + } else { |
| 535 | + src_input_path.to_path_buf() |
| 536 | + }; |
| 537 | + |
| 538 | + let meta_from_src = packagesystem::query_files(sysroot_path, [path_to_query]) |
471 | 539 | .context(format!("Querying RPM metadata for {:?}", src_input_path))?; |
472 | 540 |
|
473 | | - let version_string_part = meta_from_src.version.split( ',').next() |
474 | | - .ok_or_else(|| anyhow!( |
475 | | - "RPM query returned an empty or malformed version string (no package name found in '{}').", |
476 | | - meta_from_src.version |
477 | | - ))?; |
| 541 | + let version_string_part = |
| 542 | + meta_from_src.version.split(',').next().ok_or_else(|| { |
| 543 | + anyhow!("RPM query returned an empty or malformed version string") |
| 544 | + })?; |
478 | 545 |
|
479 | 546 | let parts: Vec<&str> = version_string_part.split('-').collect(); |
480 | | - |
481 | 547 | let (pkg_name, version_release_str) = if parts.len() >= 3 { |
482 | | - // Successfully extracted package name, version, and release |
483 | | - let actual_pkg_name = parts[0]; |
484 | | - let version_part = parts[parts.len() - 2]; // version, e.g., "1.0" |
485 | | - let release_part = parts[parts.len() - 1] |
486 | | - .split('.') |
487 | | - .next() |
488 | | - .unwrap_or(parts[parts.len() - 1]); // release, e.g., "1" from "1.el8.noarch" |
489 | 548 | ( |
490 | | - actual_pkg_name.to_string(), |
491 | | - format!("{}-{}", version_part, release_part), |
| 549 | + parts[0].to_string(), |
| 550 | + format!( |
| 551 | + "{}-{}", |
| 552 | + parts[parts.len() - 2], |
| 553 | + parts[parts.len() - 1] |
| 554 | + .split('.') |
| 555 | + .next() |
| 556 | + .unwrap_or(parts[parts.len() - 1]) |
| 557 | + ), |
492 | 558 | ) |
493 | 559 | } else { |
494 | 560 | anyhow::bail!("Unexpected RPM version string format"); |
495 | 561 | }; |
496 | 562 |
|
497 | 563 | // Use the flattened destination path |
498 | | - let matadata_path = dest_efidir_base.join(&pkg_name).join(&version_release_str); |
499 | | - std::fs::create_dir_all(&matadata_path)?; |
500 | | - |
501 | | - let final_dest_path = matadata_path.join("EFI"); |
| 564 | + let final_dest_path = dest_efidir_base.join(&pkg_name).join(&version_release_str); |
502 | 565 | std::fs::create_dir_all(&final_dest_path)?; |
503 | 566 |
|
504 | 567 | // Copy the payload files |
505 | 568 | let src_metadata = std::fs::metadata(src_input_path)?; |
506 | 569 | if src_metadata.is_dir() { |
507 | | - log::debug!( |
508 | | - "Copying contents of directory {:?} to {:?}", |
509 | | - src_input, |
510 | | - &final_dest_efi_path |
511 | | - ); |
512 | 570 | Command::new("cp") |
513 | 571 | .args([ |
514 | 572 | "-rp", |
515 | 573 | &format!("{}/.", src_input), |
516 | | - final_dest_efi_path.to_str().unwrap(), |
| 574 | + final_dest_path.to_str().unwrap(), |
517 | 575 | ]) |
518 | 576 | .run() |
519 | 577 | .with_context(|| { |
520 | 578 | format!( |
521 | 579 | "Failed to copy contents of {:?} to {:?}", |
522 | | - src_input, &final_dest_efi_path |
| 580 | + src_input, &final_dest_path |
523 | 581 | ) |
524 | 582 | })?; |
525 | | - } else if src_metadata.is_file() { |
526 | | - log::debug!("Copying file {:?} to {:?}", src_input, &final_dest_efi_path); |
| 583 | + } else { |
527 | 584 | Command::new("cp") |
528 | 585 | .args(["-p", src_input, final_dest_path.to_str().unwrap()]) |
529 | 586 | .run()?; |
530 | 587 | } |
531 | 588 |
|
532 | 589 | // Create the metadata file for the firmware |
533 | | - let firmware_meta_path = matadata_path.join("EFI.json"); |
| 590 | + let firmware_meta_path = final_dest_path.join("EFI.json"); |
534 | 591 | let meta_file = std::fs::File::create(firmware_meta_path)?; |
535 | 592 | serde_json::to_writer(meta_file, &meta_from_src)?; |
536 | 593 | log::debug!("Wrote firmware metadata for {}", pkg_name); |
|
0 commit comments