@@ -11,6 +11,7 @@ use anyhow::{ensure, Context, Result};
11
11
use camino:: Utf8PathBuf ;
12
12
use cap_std_ext:: cap_std;
13
13
use cap_std_ext:: cap_std:: fs:: Dir ;
14
+ use cfg_if:: cfg_if;
14
15
use clap:: Parser ;
15
16
use clap:: ValueEnum ;
16
17
use fn_error_context:: context;
@@ -544,7 +545,7 @@ pub(crate) enum Opt {
544
545
Note on Rollbacks and the `/etc` Directory:
545
546
546
547
When you perform a rollback (e.g., with `bootc rollback`), any
547
- changes made to files in the `/etc` directory won’ t carry over
548
+ changes made to files in the `/etc` directory won' t carry over
548
549
to the rolled-back deployment. The `/etc` files will revert
549
550
to their state from that previous deployment instead.
550
551
@@ -723,6 +724,43 @@ pub(crate) fn require_root(is_container: bool) -> Result<()> {
723
724
Ok ( ( ) )
724
725
}
725
726
727
+ /// Check if a deployment can perform a soft reboot
728
+ #[ cfg( feature = "ostree-2025-3" ) ]
729
+ fn can_perform_soft_reboot ( deployment : Option < & crate :: spec:: BootEntry > ) -> bool {
730
+ deployment. map ( |d| d. soft_reboot_capable ) . unwrap_or ( false )
731
+ }
732
+
733
+ /// Prepare and execute a soft reboot for the given deployment
734
+ #[ context( "Preparing soft reboot" ) ]
735
+ #[ cfg( feature = "ostree-2025-3" ) ]
736
+ fn prepare_soft_reboot (
737
+ sysroot : & crate :: store:: Storage ,
738
+ deployment : & ostree:: Deployment ,
739
+ ) -> Result < ( ) > {
740
+ let cancellable = ostree:: gio:: Cancellable :: NONE ;
741
+ sysroot
742
+ . sysroot
743
+ . deployment_set_soft_reboot ( deployment, false , cancellable)
744
+ . context ( "Failed to prepare soft-reboot" ) ?;
745
+ Ok ( ( ) )
746
+ }
747
+
748
+ /// Perform a soft reboot for a staged deployment
749
+ #[ context( "Soft reboot staged deployment" ) ]
750
+ #[ cfg( feature = "ostree-2025-3" ) ]
751
+ fn soft_reboot_staged ( sysroot : & crate :: store:: Storage ) -> Result < ( ) > {
752
+ println ! ( "Staged deployment is soft-reboot capable, performing soft-reboot..." ) ;
753
+
754
+ let deployments_list = sysroot. deployments ( ) ;
755
+ let staged_deployment = deployments_list
756
+ . iter ( )
757
+ . find ( |d| d. is_staged ( ) )
758
+ . ok_or_else ( || anyhow:: anyhow!( "Failed to find staged deployment" ) ) ?;
759
+
760
+ prepare_soft_reboot ( sysroot, staged_deployment) ?;
761
+ Ok ( ( ) )
762
+ }
763
+
726
764
/// A few process changes that need to be made for writing.
727
765
/// IMPORTANT: This may end up re-executing the current process,
728
766
/// so anything that happens before this should be idempotent.
@@ -843,6 +881,10 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
843
881
println ! ( "Staged update present, not changed." ) ;
844
882
845
883
if opts. apply {
884
+ #[ cfg( feature = "ostree-2025-3" ) ]
885
+ if can_perform_soft_reboot ( host. status . staged . as_ref ( ) ) {
886
+ soft_reboot_staged ( sysroot) ?;
887
+ }
846
888
crate :: reboot:: reboot ( ) ?;
847
889
}
848
890
} else if booted_unchanged {
@@ -939,6 +981,16 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
939
981
sysroot. update_mtime ( ) ?;
940
982
941
983
if opts. apply {
984
+ #[ cfg( feature = "ostree-2025-3" ) ]
985
+ {
986
+ // Get updated status to check for soft-reboot capability
987
+ let ( _updated_deployments, updated_host) =
988
+ crate :: status:: get_status ( sysroot, Some ( & booted_deployment) ) ?;
989
+
990
+ if can_perform_soft_reboot ( updated_host. status . staged . as_ref ( ) ) {
991
+ soft_reboot_staged ( sysroot) ?;
992
+ }
993
+ }
942
994
crate :: reboot:: reboot ( ) ?;
943
995
}
944
996
@@ -949,10 +1001,35 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
949
1001
#[ context( "Rollback" ) ]
950
1002
async fn rollback ( opts : RollbackOpts ) -> Result < ( ) > {
951
1003
let sysroot = & get_storage ( ) . await ?;
952
- crate :: deploy:: rollback ( sysroot) . await ?;
953
1004
954
1005
if opts. apply {
1006
+ // Get status before rollback to check soft-reboot capability
1007
+ let ( _booted_deployment, _deployments, host) =
1008
+ crate :: status:: get_status_require_booted ( sysroot) ?;
1009
+
1010
+ // Perform the rollback
1011
+ crate :: deploy:: rollback ( sysroot) . await ?;
1012
+
1013
+ cfg_if ! {
1014
+ if #[ cfg( feature = "ostree-2025-3" ) ] {
1015
+ if can_perform_soft_reboot( host. status. rollback. as_ref( ) ) {
1016
+ println!( "Rollback deployment is soft-reboot capable, performing soft-reboot..." ) ;
1017
+
1018
+ let deployments_list = sysroot. deployments( ) ;
1019
+ let target_deployment = deployments_list
1020
+ . first( )
1021
+ . ok_or_else( || anyhow:: anyhow!( "No deployments found after rollback" ) ) ?;
1022
+
1023
+ prepare_soft_reboot( sysroot, target_deployment) ?;
1024
+ }
1025
+ } else {
1026
+ let _host = host;
1027
+ }
1028
+ }
1029
+
955
1030
crate :: reboot:: reboot ( ) ?;
1031
+ } else {
1032
+ crate :: deploy:: rollback ( sysroot) . await ?;
956
1033
}
957
1034
958
1035
Ok ( ( ) )
0 commit comments