@@ -284,6 +284,9 @@ gboolean
284
284
_ostree_sysroot_ensure_writable (OstreeSysroot * self ,
285
285
GError * * error )
286
286
{
287
+ if (self -> root_is_ostree_live )
288
+ return glnx_throw (error , "sysroot does not support persistent changes" );
289
+
287
290
/* Do nothing if no mount namespace is in use */
288
291
if (!self -> mount_namespace_in_use )
289
292
return TRUE;
@@ -908,6 +911,9 @@ ostree_sysroot_initialize (OstreeSysroot *self,
908
911
if (!glnx_fstatat_allow_noent (AT_FDCWD , "/run/ostree-booted" , NULL , 0 , error ))
909
912
return FALSE;
910
913
const gboolean ostree_booted = (errno == 0 );
914
+ if (!glnx_fstatat_allow_noent (AT_FDCWD , OSTREE_SYSROOT_LIVE_PATH , NULL , 0 , error ))
915
+ return FALSE;
916
+ const gboolean ostree_live = (errno == 0 );
911
917
912
918
{ struct stat root_stbuf ;
913
919
if (!glnx_fstatat (AT_FDCWD , "/" , & root_stbuf , 0 , error ))
@@ -925,6 +931,7 @@ ostree_sysroot_initialize (OstreeSysroot *self,
925
931
self -> root_inode == self_stbuf .st_ino );
926
932
927
933
self -> root_is_ostree_booted = (ostree_booted && root_is_sysroot );
934
+ self -> root_is_ostree_live = self -> root_is_ostree_booted && ostree_live ;
928
935
self -> loadstate = OSTREE_SYSROOT_LOAD_STATE_INIT ;
929
936
}
930
937
@@ -993,8 +1000,6 @@ sysroot_load_from_bootloader_configs (OstreeSysroot *self,
993
1000
GCancellable * cancellable ,
994
1001
GError * * error )
995
1002
{
996
- struct stat stbuf ;
997
-
998
1003
int bootversion = 0 ;
999
1004
if (!read_current_bootversion (self , & bootversion , cancellable , error ))
1000
1005
return FALSE;
@@ -1049,39 +1054,86 @@ sysroot_load_from_bootloader_configs (OstreeSysroot *self,
1049
1054
if (self -> staged_deployment )
1050
1055
g_ptr_array_insert (deployments , 0 , g_object_ref (self -> staged_deployment ));
1051
1056
1052
- /* And then set their index variables */
1053
- for (guint i = 0 ; i < deployments -> len ; i ++ )
1054
- {
1055
- OstreeDeployment * deployment = deployments -> pdata [i ];
1056
- ostree_deployment_set_index (deployment , i );
1057
- }
1057
+ self -> bootversion = bootversion ;
1058
+ self -> subbootversion = subbootversion ;
1059
+ self -> deployments = g_steal_pointer (& deployments );
1058
1060
1059
- /* Determine whether we're "physical" or not, the first time we load deployments */
1060
- if (self -> loadstate < OSTREE_SYSROOT_LOAD_STATE_LOADED )
1061
+ return TRUE;
1062
+ }
1063
+
1064
+ static gboolean
1065
+ find_first_ent_at (int dirfd ,
1066
+ const char * path ,
1067
+ int dtype ,
1068
+ char * * ret_name ,
1069
+ GCancellable * cancellable ,
1070
+ GError * * error )
1071
+ {
1072
+ g_auto (GLnxDirFdIterator ) dfd_iter = { 0 , };
1073
+
1074
+ if (!glnx_dirfd_iterator_init_at (dirfd , path , TRUE,
1075
+ & dfd_iter , error ))
1076
+ return FALSE;
1077
+
1078
+ while (TRUE)
1061
1079
{
1062
- /* If we have a booted deployment, the sysroot is / and we're definitely
1063
- * not physical.
1064
- */
1065
- if (self -> booted_deployment )
1066
- self -> is_physical = FALSE; /* (the default, but explicit for clarity) */
1067
- /* Otherwise - check for /sysroot which should only exist in a deployment,
1068
- * not in ${sysroot} (a metavariable for the real physical root).
1069
- */
1070
- else
1071
- {
1072
- if (!glnx_fstatat_allow_noent (self -> sysroot_fd , "sysroot" , & stbuf , 0 , error ))
1073
- return FALSE;
1074
- if (errno == ENOENT )
1075
- self -> is_physical = TRUE;
1076
- }
1077
- /* Otherwise, the default is FALSE */
1080
+ struct dirent * dent ;
1078
1081
1079
- self -> loadstate = OSTREE_SYSROOT_LOAD_STATE_LOADED ;
1082
+ if (!glnx_dirfd_iterator_next_dent_ensure_dtype (& dfd_iter , & dent ,
1083
+ cancellable , error ))
1084
+ return FALSE;
1085
+ if (dent == NULL )
1086
+ break ;
1087
+
1088
+ if (dent -> d_type != dtype )
1089
+ continue ;
1090
+
1091
+ * ret_name = g_strdup (dent -> d_name );
1092
+ break ;
1080
1093
}
1081
1094
1082
- self -> bootversion = bootversion ;
1083
- self -> subbootversion = subbootversion ;
1095
+ return TRUE;
1096
+ }
1097
+
1098
+ static gboolean
1099
+ sysroot_load_live (OstreeSysroot * self ,
1100
+ GCancellable * cancellable ,
1101
+ GError * * error )
1102
+ {
1103
+ g_autoptr (GString ) bootlink = g_string_new ("/ostree/boot.1" );
1104
+
1105
+ g_autofree char * osname = NULL ;
1106
+ if (!find_first_ent_at (AT_FDCWD , bootlink -> str , DT_DIR , & osname , cancellable , error ))
1107
+ return FALSE;
1108
+ if (!osname )
1109
+ return glnx_throw (error , "failed to find /ostree/boot subdirectory" );
1110
+ g_string_append_c (bootlink , '/' );
1111
+ g_string_append (bootlink , osname );
1112
+
1113
+ g_autofree char * checksum = NULL ;
1114
+ if (!find_first_ent_at (AT_FDCWD , bootlink -> str , DT_DIR , & checksum , cancellable , error ))
1115
+ return FALSE;
1116
+ if (!checksum )
1117
+ return glnx_throw (error , "failed to find /ostree/boot statedir" );
1118
+ g_string_append_c (bootlink , '/' );
1119
+ g_string_append (bootlink , checksum );
1120
+
1121
+ g_autofree char * treeserial = NULL ;
1122
+ if (!find_first_ent_at (AT_FDCWD , bootlink -> str , DT_LNK , & treeserial , cancellable , error ))
1123
+ return FALSE;
1124
+ if (!treeserial )
1125
+ return glnx_throw (error , "failed to find /ostree/boot treeserial" );
1126
+ g_string_append_c (bootlink , '/' );
1127
+ g_string_append (bootlink , treeserial );
1128
+
1129
+ g_autoptr (OstreeDeployment ) deployment = NULL ;
1130
+ if (!parse_deployment (self , bootlink -> str , & deployment ,
1131
+ cancellable , error ))
1132
+ return FALSE;
1133
+ g_autoptr (GPtrArray ) deployments = g_ptr_array_new_with_free_func ((GDestroyNotify )g_object_unref );
1134
+ g_ptr_array_add (deployments , g_object_ref (deployment ));
1084
1135
self -> deployments = g_steal_pointer (& deployments );
1136
+ self -> booted_deployment = g_steal_pointer (& deployment );
1085
1137
1086
1138
return TRUE;
1087
1139
}
@@ -1130,8 +1182,47 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
1130
1182
self -> bootversion = -1 ;
1131
1183
self -> subbootversion = -1 ;
1132
1184
1133
- if (!sysroot_load_from_bootloader_configs (self , cancellable , error ))
1134
- return FALSE;
1185
+ if (self -> root_is_ostree_live )
1186
+ {
1187
+ if (!sysroot_load_live (self , cancellable , error ))
1188
+ return FALSE;
1189
+ }
1190
+ else
1191
+ {
1192
+ if (!sysroot_load_from_bootloader_configs (self , cancellable , error ))
1193
+ return FALSE;
1194
+ }
1195
+
1196
+ /* Assign the index variables */
1197
+ g_assert (self -> deployments );
1198
+ for (guint i = 0 ; i < self -> deployments -> len ; i ++ )
1199
+ {
1200
+ OstreeDeployment * deployment = self -> deployments -> pdata [i ];
1201
+ ostree_deployment_set_index (deployment , i );
1202
+ }
1203
+
1204
+ /* Determine whether we're "physical" or not, the first time we load deployments */
1205
+ if (self -> loadstate < OSTREE_SYSROOT_LOAD_STATE_LOADED )
1206
+ {
1207
+ /* If we have a booted deployment, the sysroot is / and we're definitely
1208
+ * not physical.
1209
+ */
1210
+ if (self -> booted_deployment )
1211
+ self -> is_physical = FALSE; /* (the default, but explicit for clarity) */
1212
+ /* Otherwise - check for /sysroot which should only exist in a deployment,
1213
+ * not in ${sysroot} (a metavariable for the real physical root).
1214
+ */
1215
+ else
1216
+ {
1217
+ if (!glnx_fstatat_allow_noent (self -> sysroot_fd , "sysroot" , & stbuf , 0 , error ))
1218
+ return FALSE;
1219
+ if (errno == ENOENT )
1220
+ self -> is_physical = TRUE;
1221
+ }
1222
+ /* Otherwise, the default is FALSE */
1223
+
1224
+ self -> loadstate = OSTREE_SYSROOT_LOAD_STATE_LOADED ;
1225
+ }
1135
1226
1136
1227
self -> loaded_ts = stbuf .st_mtim ;
1137
1228
0 commit comments