3
3
//! Create a merged filesystem tree with the image and mounted configmaps.
4
4
5
5
use std:: collections:: HashSet ;
6
+ use std:: fmt:: Write as _;
6
7
use std:: fs:: create_dir_all;
7
- use std:: io:: { BufRead , Write } ;
8
+ use std:: io:: { BufRead , Read , Write } ;
8
9
use std:: path:: PathBuf ;
9
10
10
11
use anyhow:: Ok ;
@@ -25,10 +26,11 @@ use ostree_ext::tokio_util::spawn_blocking_cancellable_flatten;
25
26
use rustix:: fs:: { fsync, renameat_with, AtFlags , RenameFlags } ;
26
27
27
28
use crate :: bls_config:: { parse_bls_config, BLSConfig } ;
28
- use crate :: install:: { get_efi_uuid_source, get_user_config, BootType } ;
29
+ use crate :: install:: { get_efi_uuid_source, BootType } ;
30
+ use crate :: parsers:: grub_menuconfig:: { parse_grub_menuentry_file, MenuEntry } ;
29
31
use crate :: progress_jsonl:: { Event , ProgressWriter , SubTaskBytes , SubTaskStep } ;
30
32
use crate :: spec:: ImageReference ;
31
- use crate :: spec:: { BootEntry , BootOrder , HostSpec } ;
33
+ use crate :: spec:: { BootOrder , HostSpec } ;
32
34
use crate :: status:: { composefs_deployment_status, labels_of_config} ;
33
35
use crate :: store:: Storage ;
34
36
use crate :: utils:: async_task_with_spinner;
@@ -742,38 +744,59 @@ pub(crate) async fn stage(
742
744
Ok ( ( ) )
743
745
}
744
746
747
+ /// Filename for `loader/entries`
748
+ pub ( crate ) const USER_CFG : & str = "user.cfg" ;
749
+ pub ( crate ) const USER_CFG_STAGED : & str = "user.cfg.staged" ;
750
+ pub ( crate ) const USER_CFG_ROLLBACK : & str = USER_CFG_STAGED ;
751
+
745
752
#[ context( "Rolling back UKI" ) ]
746
- pub ( crate ) fn rollback_composefs_uki ( current : & BootEntry , rollback : & BootEntry ) -> Result < ( ) > {
747
- let user_cfg_name = "grub2/user.cfg.staged" ;
748
- let user_cfg_path = PathBuf :: from ( "/sysroot/boot" ) . join ( user_cfg_name) ;
753
+ pub ( crate ) fn rollback_composefs_uki ( ) -> Result < ( ) > {
754
+ let user_cfg_path = PathBuf :: from ( "/sysroot/boot/grub2" ) ;
749
755
750
- let efi_uuid_source = get_efi_uuid_source ( ) ;
756
+ let mut str = String :: new ( ) ;
757
+ let mut menuentries =
758
+ get_sorted_uki_boot_entries ( & mut str) . context ( "Getting UKI boot entries" ) ?;
751
759
752
- // TODO: Need to check if user.cfg.staged exists
753
- let mut usr_cfg = std:: fs:: OpenOptions :: new ( )
754
- . write ( true )
755
- . create ( true )
756
- . truncate ( true )
757
- . open ( user_cfg_path)
758
- . with_context ( || format ! ( "Opening {user_cfg_name}" ) ) ?;
760
+ // TODO(Johan-Liebert): Currently assuming there are only two deployments
761
+ assert ! ( menuentries. len( ) == 2 ) ;
759
762
760
- usr_cfg. write ( efi_uuid_source. as_bytes ( ) ) ?;
763
+ let ( first, second) = menuentries. split_at_mut ( 1 ) ;
764
+ std:: mem:: swap ( & mut first[ 0 ] , & mut second[ 0 ] ) ;
761
765
762
- let verity = if let Some ( composefs) = & rollback. composefs {
763
- composefs. verity . clone ( )
764
- } else {
765
- // Shouldn't really happen
766
- anyhow:: bail!( "Verity not found for rollback deployment" )
767
- } ;
768
- usr_cfg. write ( get_user_config ( todo ! ( ) , & verity) . as_bytes ( ) ) ?;
766
+ let mut buffer = get_efi_uuid_source ( ) ;
769
767
770
- let verity = if let Some ( composefs) = & current. composefs {
771
- composefs. verity . clone ( )
772
- } else {
773
- // Shouldn't really happen
774
- anyhow:: bail!( "Verity not found for booted deployment" )
775
- } ;
776
- usr_cfg. write ( get_user_config ( todo ! ( ) , & verity) . as_bytes ( ) ) ?;
768
+ for entry in menuentries {
769
+ write ! ( buffer, "{entry}" ) ?;
770
+ }
771
+
772
+ let entries_dir =
773
+ cap_std:: fs:: Dir :: open_ambient_dir ( & user_cfg_path, cap_std:: ambient_authority ( ) )
774
+ . with_context ( || format ! ( "Opening {user_cfg_path:?}" ) ) ?;
775
+
776
+ entries_dir
777
+ . atomic_write ( USER_CFG_ROLLBACK , buffer)
778
+ . with_context ( || format ! ( "Writing to {USER_CFG_ROLLBACK}" ) ) ?;
779
+
780
+ tracing:: debug!( "Atomically exchanging for {USER_CFG_ROLLBACK} and {USER_CFG}" ) ;
781
+ renameat_with (
782
+ & entries_dir,
783
+ USER_CFG_ROLLBACK ,
784
+ & entries_dir,
785
+ USER_CFG ,
786
+ RenameFlags :: EXCHANGE ,
787
+ )
788
+ . context ( "renameat" ) ?;
789
+
790
+ tracing:: debug!( "Removing {USER_CFG_ROLLBACK}" ) ;
791
+ rustix:: fs:: unlinkat ( & entries_dir, USER_CFG_ROLLBACK , AtFlags :: REMOVEDIR ) . context ( "unlinkat" ) ?;
792
+
793
+ tracing:: debug!( "Syncing to disk" ) ;
794
+ fsync (
795
+ entries_dir
796
+ . reopen_as_ownedfd ( )
797
+ . with_context ( || format ! ( "Reopening {user_cfg_path:?} as owned fd" ) ) ?,
798
+ )
799
+ . with_context ( || format ! ( "fsync {user_cfg_path:?}" ) ) ?;
777
800
778
801
Ok ( ( ) )
779
802
}
@@ -834,6 +857,7 @@ pub(crate) fn rollback_composefs_bls() -> Result<()> {
834
857
cfg. version = idx as u32 ;
835
858
}
836
859
860
+ // TODO(Johan-Liebert): Currently assuming there are only two deployments
837
861
assert ! ( all_configs. len( ) == 2 ) ;
838
862
839
863
// Write these
@@ -849,7 +873,7 @@ pub(crate) fn rollback_composefs_bls() -> Result<()> {
849
873
let file_name = format ! ( "bootc-composefs-{}.conf" , cfg. version) ;
850
874
851
875
rollback_entries_dir
852
- . atomic_write ( & file_name, cfg. to_string ( ) . as_bytes ( ) )
876
+ . atomic_write ( & file_name, cfg. to_string ( ) )
853
877
. with_context ( || format ! ( "Writing to {file_name}" ) ) ?;
854
878
}
855
879
@@ -920,7 +944,7 @@ pub(crate) async fn composefs_rollback() -> Result<()> {
920
944
921
945
match rollback_composefs_entry. boot_type {
922
946
BootType :: Bls => rollback_composefs_bls ( ) ,
923
- BootType :: Uki => rollback_composefs_uki ( & host . status . booted . unwrap ( ) , & rollback_status ) ,
947
+ BootType :: Uki => rollback_composefs_uki ( ) ,
924
948
} ?;
925
949
926
950
Ok ( ( ) )
0 commit comments