Skip to content

Commit 0c45183

Browse files
committed
sysroot: Detect "live" system on /run/ostree-live
Support read-only queries, but deny any attempts to make changes with a clear error. Now...in the future, we probably do want to support making "transient" overlays. See: coreos/fedora-coreos-tracker#354 (comment) Closes: ostreedev#1921
1 parent 677f0bf commit 0c45183

File tree

3 files changed

+133
-31
lines changed

3 files changed

+133
-31
lines changed

src/libostree/ostree-sysroot-private.h

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct OstreeSysroot {
6060
OstreeSysrootLoadState loadstate;
6161
gboolean mount_namespace_in_use; /* TRUE if caller has told us they used CLONE_NEWNS */
6262
gboolean root_is_ostree_booted; /* TRUE if sysroot is / and we are booted via ostree */
63+
gboolean root_is_ostree_live; /* TRUE if sysroot is / and we are running fully in RAM */
6364
/* The device/inode for /, used to detect booted deployment */
6465
dev_t root_device;
6566
ino_t root_inode;

src/libostree/ostree-sysroot.c

+122-31
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ gboolean
284284
_ostree_sysroot_ensure_writable (OstreeSysroot *self,
285285
GError **error)
286286
{
287+
if (self->root_is_ostree_live)
288+
return glnx_throw (error, "sysroot does not support persistent changes");
289+
287290
/* Do nothing if no mount namespace is in use */
288291
if (!self->mount_namespace_in_use)
289292
return TRUE;
@@ -908,6 +911,9 @@ ostree_sysroot_initialize (OstreeSysroot *self,
908911
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error))
909912
return FALSE;
910913
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);
911917

912918
{ struct stat root_stbuf;
913919
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
@@ -925,6 +931,7 @@ ostree_sysroot_initialize (OstreeSysroot *self,
925931
self->root_inode == self_stbuf.st_ino);
926932

927933
self->root_is_ostree_booted = (ostree_booted && root_is_sysroot);
934+
self->root_is_ostree_live = self->root_is_ostree_booted && ostree_live;
928935
self->loadstate = OSTREE_SYSROOT_LOAD_STATE_INIT;
929936
}
930937

@@ -993,8 +1000,6 @@ sysroot_load_from_bootloader_configs (OstreeSysroot *self,
9931000
GCancellable *cancellable,
9941001
GError **error)
9951002
{
996-
struct stat stbuf;
997-
9981003
int bootversion = 0;
9991004
if (!read_current_bootversion (self, &bootversion, cancellable, error))
10001005
return FALSE;
@@ -1049,39 +1054,86 @@ sysroot_load_from_bootloader_configs (OstreeSysroot *self,
10491054
if (self->staged_deployment)
10501055
g_ptr_array_insert (deployments, 0, g_object_ref (self->staged_deployment));
10511056

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);
10581060

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)
10611079
{
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;
10781081

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;
10801093
}
10811094

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));
10841135
self->deployments = g_steal_pointer (&deployments);
1136+
self->booted_deployment = g_steal_pointer (&deployment);
10851137

10861138
return TRUE;
10871139
}
@@ -1130,8 +1182,47 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
11301182
self->bootversion = -1;
11311183
self->subbootversion = -1;
11321184

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+
}
11351226

11361227
self->loaded_ts = stbuf.st_mtim;
11371228

src/libostree/ostree-sysroot.h

+10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ G_BEGIN_DECLS
3232
#define OSTREE_IS_SYSROOT(obj) \
3333
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SYSROOT))
3434

35+
/**
36+
* OSTREE_SYSROOT_LIVE_PATH:
37+
*
38+
* The existence of this file declares that the system
39+
* is booted "live" (fully in RAM).
40+
*
41+
* Since: 2020.1
42+
**/
43+
#define OSTREE_SYSROOT_LIVE_PATH "/run/ostree-live"
44+
3545
_OSTREE_PUBLIC
3646
GType ostree_sysroot_get_type (void);
3747

0 commit comments

Comments
 (0)