@@ -11,6 +11,7 @@ use anyhow::{ensure, Context, Result};
1111use camino:: Utf8PathBuf ;
1212use cap_std_ext:: cap_std;
1313use cap_std_ext:: cap_std:: fs:: Dir ;
14+ use cfg_if:: cfg_if;
1415use clap:: Parser ;
1516use clap:: ValueEnum ;
1617use fn_error_context:: context;
@@ -544,7 +545,7 @@ pub(crate) enum Opt {
544545 Note on Rollbacks and the `/etc` Directory:
545546
546547 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
548549 to the rolled-back deployment. The `/etc` files will revert
549550 to their state from that previous deployment instead.
550551
@@ -723,6 +724,43 @@ pub(crate) fn require_root(is_container: bool) -> Result<()> {
723724 Ok ( ( ) )
724725}
725726
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+
726764/// A few process changes that need to be made for writing.
727765/// IMPORTANT: This may end up re-executing the current process,
728766/// so anything that happens before this should be idempotent.
@@ -843,6 +881,10 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
843881 println ! ( "Staged update present, not changed." ) ;
844882
845883 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+ }
846888 crate :: reboot:: reboot ( ) ?;
847889 }
848890 } else if booted_unchanged {
@@ -939,6 +981,16 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
939981 sysroot. update_mtime ( ) ?;
940982
941983 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+ }
942994 crate :: reboot:: reboot ( ) ?;
943995 }
944996
@@ -949,10 +1001,35 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
9491001#[ context( "Rollback" ) ]
9501002async fn rollback ( opts : RollbackOpts ) -> Result < ( ) > {
9511003 let sysroot = & get_storage ( ) . await ?;
952- crate :: deploy:: rollback ( sysroot) . await ?;
9531004
9541005 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+
9551030 crate :: reboot:: reboot ( ) ?;
1031+ } else {
1032+ crate :: deploy:: rollback ( sysroot) . await ?;
9561033 }
9571034
9581035 Ok ( ( ) )
0 commit comments