3
3
4
4
// SPDX-License-Identifier: Apache-2.0 OR MIT
5
5
6
+ use std:: str:: FromStr ;
7
+
6
8
use anyhow:: { Context , Result } ;
7
9
use camino:: Utf8Path ;
8
10
use glib:: Cast ;
@@ -11,6 +13,7 @@ use ostree::{gio, glib};
11
13
12
14
use crate :: keyfileext:: KeyFileExt ;
13
15
use crate :: ostree_manual;
16
+ use crate :: utils:: ResultExt ;
14
17
15
18
pub ( crate ) const CONF_PATH : & str = "ostree/prepare-root.conf" ;
16
19
@@ -44,14 +47,98 @@ pub(crate) fn overlayfs_root_enabled(root: &ostree::RepoFile) -> Result<bool> {
44
47
}
45
48
}
46
49
50
+ #[ derive( Debug , PartialEq , Eq ) ]
51
+ enum Tristate {
52
+ Enabled ,
53
+ Disabled ,
54
+ Maybe ,
55
+ }
56
+
57
+ impl FromStr for Tristate {
58
+ type Err = anyhow:: Error ;
59
+
60
+ fn from_str ( s : & str ) -> Result < Self > {
61
+ let r = match s {
62
+ // Keep this in sync with ot_keyfile_get_tristate_with_default from ostree
63
+ "yes" | "true" | "1" => Tristate :: Enabled ,
64
+ "no" | "false" | "0" => Tristate :: Disabled ,
65
+ "maybe" => Tristate :: Maybe ,
66
+ o => anyhow:: bail!( "Invalid tristate value: {o}" ) ,
67
+ } ;
68
+ Ok ( r)
69
+ }
70
+ }
71
+
72
+ impl Default for Tristate {
73
+ fn default ( ) -> Self {
74
+ Self :: Disabled
75
+ }
76
+ }
77
+
78
+ impl Tristate {
79
+ pub ( crate ) fn maybe_enabled ( & self ) -> bool {
80
+ match self {
81
+ Self :: Enabled | Self :: Maybe => true ,
82
+ Self :: Disabled => false ,
83
+ }
84
+ }
85
+ }
86
+
47
87
/// Query whether the config uses an overlayfs model (composefs or plain overlayfs).
48
88
pub fn overlayfs_enabled_in_config ( config : & glib:: KeyFile ) -> Result < bool > {
49
89
let root_transient = config
50
90
. optional_bool ( "root" , "transient" ) ?
51
91
. unwrap_or_default ( ) ;
52
- let required_composefs = config
92
+ let composefs = config
53
93
. optional_string ( "composefs" , "enabled" ) ?
54
- . map ( |s| s. as_str ( ) == "yes" )
94
+ . map ( |s| Tristate :: from_str ( s. as_str ( ) ) )
95
+ . transpose ( )
96
+ . log_err_default ( )
55
97
. unwrap_or_default ( ) ;
56
- Ok ( root_transient || required_composefs)
98
+ Ok ( root_transient || composefs. maybe_enabled ( ) )
99
+ }
100
+
101
+ #[ test]
102
+ fn test_tristate ( ) {
103
+ for v in [ "yes" , "true" , "1" ] {
104
+ assert_eq ! ( Tristate :: from_str( v) . unwrap( ) , Tristate :: Enabled ) ;
105
+ }
106
+ assert_eq ! ( Tristate :: from_str( "maybe" ) . unwrap( ) , Tristate :: Maybe ) ;
107
+ for v in [ "no" , "false" , "0" ] {
108
+ assert_eq ! ( Tristate :: from_str( v) . unwrap( ) , Tristate :: Disabled ) ;
109
+ }
110
+ for v in [ "" , "junk" , "fal" , "tr1" ] {
111
+ assert ! ( Tristate :: from_str( v) . is_err( ) ) ;
112
+ }
113
+ }
114
+
115
+ #[ test]
116
+ fn test_overlayfs_enabled ( ) {
117
+ let d0 = indoc:: indoc! { r#"
118
+ [foo]
119
+ bar = baz
120
+ [root]
121
+ "# } ;
122
+ let d1 = indoc:: indoc! { r#"
123
+ [root]
124
+ transient = false
125
+ "# } ;
126
+ let d2 = indoc:: indoc! { r#"
127
+ [composefs]
128
+ enabled = false
129
+ "# } ;
130
+ for v in [ "" , d0, d1, d2] {
131
+ let kf = glib:: KeyFile :: new ( ) ;
132
+ kf. load_from_data ( v, glib:: KeyFileFlags :: empty ( ) ) . unwrap ( ) ;
133
+ assert_eq ! ( overlayfs_enabled_in_config( & kf) . unwrap( ) , false ) ;
134
+ }
135
+
136
+ let e0 = format ! ( "{d0}\n [root]\n transient = true" ) ;
137
+ let e1 = format ! ( "{d1}\n [composefs]\n enabled = true\n [other]\n somekey = someval" ) ;
138
+ let e2 = format ! ( "{d1}\n [composefs]\n enabled = yes" ) ;
139
+ for v in [ e0, e1, e2] {
140
+ let kf = glib:: KeyFile :: new ( ) ;
141
+ kf. load_from_data ( & v, glib:: KeyFileFlags :: empty ( ) ) . unwrap ( ) ;
142
+ assert_eq ! ( overlayfs_enabled_in_config( & kf) . unwrap( ) , true ) ;
143
+ }
57
144
}
0 commit comments