-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sysroot merge ⛙ config #741
Closed
Closed
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -423,38 +423,56 @@ copy_modified_config_file (int orig_etc_fd, | |
return ret; | ||
} | ||
|
||
/** | ||
* merge_etc_changes: | ||
/* | ||
* merge_configuration_from: | ||
* @sysroot: Sysroot | ||
* @merge_deployment: Source of configuration differences | ||
* @merge_deployment_dfd: Directory fd, may be -1 | ||
* @new_deployment: Target for merge of configuration | ||
* @new_deployment_dfd: Directory fd for @new_deployment (may *not* be -1) | ||
* @cancellable: Cancellable | ||
* @error: Error | ||
* | ||
* Compute the difference between @orig_etc and @modified_etc, | ||
* and apply that to @new_etc. | ||
* Compute the difference between @merge_deployment's `/usr/etc` and `/etc`, and | ||
* apply that to @new_deployment's `/etc`. | ||
* | ||
* The algorithm for computing the difference is pretty simple; it's | ||
* approximately equivalent to "diff -unR orig_etc modified_etc", | ||
* except that rather than attempting a 3-way merge if a file is also | ||
* changed in @new_etc, the modified version always wins. | ||
*/ | ||
static gboolean | ||
merge_etc_changes (GFile *orig_etc, | ||
GFile *modified_etc, | ||
GFile *new_etc, | ||
OstreeSysrootDebugFlags flags, | ||
GCancellable *cancellable, | ||
GError **error) | ||
merge_configuration_from (OstreeSysroot *sysroot, | ||
OstreeDeployment *merge_deployment, | ||
int merge_deployment_dfd, | ||
OstreeDeployment *new_deployment, | ||
int new_deployment_dfd, | ||
GCancellable *cancellable, | ||
GError **error) | ||
{ | ||
gboolean ret = FALSE; | ||
g_autoptr(GPtrArray) modified = NULL; | ||
g_autoptr(GPtrArray) removed = NULL; | ||
g_autoptr(GPtrArray) added = NULL; | ||
guint i; | ||
glnx_fd_close int orig_etc_fd = -1; | ||
glnx_fd_close int modified_etc_fd = -1; | ||
glnx_fd_close int new_etc_fd = -1; | ||
glnx_fd_close int owned_merge_deployment_dfd = -1; | ||
const OstreeSysrootDebugFlags flags = sysroot->debug_flags; | ||
|
||
modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref); | ||
removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); | ||
added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); | ||
g_assert (merge_deployment != NULL && new_deployment != NULL); | ||
g_assert (new_deployment_dfd != -1); | ||
|
||
/* Allow the caller to pass -1 for the merge, for convenience */ | ||
if (merge_deployment_dfd == -1) | ||
{ | ||
g_autofree char *merge_deployment_path = ostree_sysroot_get_deployment_dirpath (sysroot, merge_deployment); | ||
if (!glnx_opendirat (sysroot->sysroot_fd, merge_deployment_path, FALSE, | ||
&owned_merge_deployment_dfd, error)) | ||
return FALSE; | ||
merge_deployment_dfd = owned_merge_deployment_dfd; | ||
} | ||
|
||
/* TODO: get rid of GFile usage here */ | ||
g_autoptr(GFile) orig_etc = ot_fdrel_to_gfile (merge_deployment_dfd, "usr/etc"); | ||
g_autoptr(GFile) modified_etc = ot_fdrel_to_gfile (merge_deployment_dfd, "etc"); | ||
/* Return values for below */ | ||
g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref); | ||
g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); | ||
g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); | ||
/* For now, ignore changes to xattrs; the problem is that | ||
* security.selinux will be different between the /usr/etc labels | ||
* and the ones in the real /etc, so they all show up as different. | ||
|
@@ -466,42 +484,37 @@ merge_etc_changes (GFile *orig_etc, | |
if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_IGNORE_XATTRS, | ||
orig_etc, modified_etc, modified, removed, added, | ||
cancellable, error)) | ||
{ | ||
g_prefix_error (error, "While computing configuration diff: "); | ||
goto out; | ||
} | ||
return g_prefix_error (error, "While computing configuration diff: "), FALSE; | ||
|
||
ot_log_structured_print_id_v (OSTREE_CONFIGMERGE_ID, | ||
"Copying /etc changes: %u modified, %u removed, %u added", | ||
"Copying /etc changes: %u modified, %u removed, %u added", | ||
modified->len, | ||
removed->len, | ||
added->len); | ||
|
||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (orig_etc), TRUE, | ||
&orig_etc_fd, error)) | ||
goto out; | ||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (modified_etc), TRUE, | ||
&modified_etc_fd, error)) | ||
goto out; | ||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (new_etc), TRUE, | ||
&new_etc_fd, error)) | ||
goto out; | ||
glnx_fd_close int orig_etc_fd = -1; | ||
if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error)) | ||
return FALSE; | ||
glnx_fd_close int modified_etc_fd = -1; | ||
if (!glnx_opendirat (merge_deployment_dfd, "etc", TRUE, &modified_etc_fd, error)) | ||
return FALSE; | ||
glnx_fd_close int new_etc_fd = -1; | ||
if (!glnx_opendirat (new_deployment_dfd, "etc", TRUE, &new_etc_fd, error)) | ||
return FALSE; | ||
|
||
for (i = 0; i < removed->len; i++) | ||
for (guint i = 0; i < removed->len; i++) | ||
{ | ||
GFile *file = removed->pdata[i]; | ||
g_autoptr(GFile) target_file = NULL; | ||
g_autofree char *path = NULL; | ||
|
||
path = g_file_get_relative_path (orig_etc, file); | ||
g_assert (path); | ||
target_file = g_file_resolve_relative_path (new_etc, path); | ||
|
||
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (target_file), cancellable, error)) | ||
goto out; | ||
if (!glnx_shutil_rm_rf_at (new_etc_fd, path, cancellable, error)) | ||
return FALSE; | ||
} | ||
|
||
for (i = 0; i < modified->len; i++) | ||
for (guint i = 0; i < modified->len; i++) | ||
{ | ||
OstreeDiffItem *diff = modified->pdata[i]; | ||
g_autofree char *path = g_file_get_relative_path (modified_etc, diff->target); | ||
|
@@ -510,9 +523,9 @@ merge_etc_changes (GFile *orig_etc, | |
|
||
if (!copy_modified_config_file (orig_etc_fd, modified_etc_fd, new_etc_fd, path, | ||
flags, cancellable, error)) | ||
goto out; | ||
return FALSE; | ||
} | ||
for (i = 0; i < added->len; i++) | ||
for (guint i = 0; i < added->len; i++) | ||
{ | ||
GFile *file = added->pdata[i]; | ||
g_autofree char *path = g_file_get_relative_path (modified_etc, file); | ||
|
@@ -521,12 +534,10 @@ merge_etc_changes (GFile *orig_etc, | |
|
||
if (!copy_modified_config_file (orig_etc_fd, modified_etc_fd, new_etc_fd, path, | ||
flags, cancellable, error)) | ||
goto out; | ||
return FALSE; | ||
} | ||
|
||
ret = TRUE; | ||
out: | ||
return ret; | ||
return TRUE; | ||
} | ||
|
||
/** | ||
|
@@ -775,25 +786,14 @@ merge_configuration (OstreeSysroot *sysroot, | |
GCancellable *cancellable, | ||
GError **error) | ||
{ | ||
gboolean ret = FALSE; | ||
g_autofree char *deployment_abspath = glnx_fdrel_abspath (deployment_dfd, "."); | ||
g_autoptr(GFile) deployment_path = g_file_new_for_path (deployment_abspath); | ||
g_autoptr(GFile) source_etc_path = NULL; | ||
g_autoptr(GFile) source_etc_pristine_path = NULL; | ||
g_autoptr(GFile) deployment_usretc_path = NULL; | ||
g_autoptr(GFile) deployment_etc_path = NULL; | ||
glnx_unref_object OstreeSePolicy *sepolicy = NULL; | ||
gboolean etc_exists; | ||
gboolean usretc_exists; | ||
|
||
if (previous_deployment) | ||
{ | ||
g_autoptr(GFile) previous_path = NULL; | ||
OstreeBootconfigParser *previous_bootconfig; | ||
|
||
previous_path = ostree_sysroot_get_deployment_directory (sysroot, previous_deployment); | ||
source_etc_path = g_file_resolve_relative_path (previous_path, "etc"); | ||
source_etc_pristine_path = g_file_resolve_relative_path (previous_path, "usr/etc"); | ||
|
||
previous_bootconfig = ostree_deployment_get_bootconfig (previous_deployment); | ||
if (previous_bootconfig) | ||
|
@@ -807,26 +807,20 @@ merge_configuration (OstreeSysroot *sysroot, | |
} | ||
} | ||
|
||
deployment_etc_path = g_file_get_child (deployment_path, "etc"); | ||
deployment_usretc_path = g_file_resolve_relative_path (deployment_path, "usr/etc"); | ||
|
||
etc_exists = g_file_query_exists (deployment_etc_path, NULL); | ||
usretc_exists = g_file_query_exists (deployment_usretc_path, NULL); | ||
gboolean etc_exists = FALSE; | ||
if (!ot_query_exists_at (deployment_dfd, "etc", &etc_exists, error)) | ||
return FALSE; | ||
gboolean usretc_exists = FALSE; | ||
if (!ot_query_exists_at (deployment_dfd, "usr/etc", &usretc_exists, error)) | ||
return FALSE; | ||
|
||
if (etc_exists && usretc_exists) | ||
{ | ||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, | ||
"Tree contains both /etc and /usr/etc"); | ||
goto out; | ||
} | ||
return glnx_throw (error, "Tree contains both /etc and /usr/etc"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, this returned |
||
else if (etc_exists) | ||
{ | ||
/* Compatibility hack */ | ||
if (renameat (deployment_dfd, "etc", deployment_dfd, "usr/etc") < 0) | ||
{ | ||
glnx_set_error_from_errno (error); | ||
goto out; | ||
} | ||
return glnx_throw_errno_prefix (error, "renameat"); | ||
usretc_exists = TRUE; | ||
etc_exists = FALSE; | ||
} | ||
|
@@ -843,9 +837,9 @@ merge_configuration (OstreeSysroot *sysroot, | |
/* Here, we initialize SELinux policy from the /usr/etc inside | ||
* the root - this is before we've finalized the configuration | ||
* merge into /etc. */ | ||
sepolicy = ostree_sepolicy_new (deployment_path, cancellable, error); | ||
sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); | ||
if (!sepolicy) | ||
goto out; | ||
return FALSE; | ||
if (ostree_sepolicy_get_name (sepolicy) != NULL) | ||
etc_co_opts.sepolicy = sepolicy; | ||
|
||
|
@@ -854,21 +848,21 @@ merge_configuration (OstreeSysroot *sysroot, | |
deployment_dfd, "etc", | ||
ostree_deployment_get_csum (deployment), | ||
cancellable, error)) | ||
goto out; | ||
return FALSE; | ||
|
||
} | ||
|
||
if (source_etc_path) | ||
if (previous_deployment) | ||
{ | ||
if (!merge_etc_changes (source_etc_pristine_path, source_etc_path, deployment_etc_path, | ||
sysroot->debug_flags, cancellable, error)) | ||
goto out; | ||
if (!merge_configuration_from (sysroot, previous_deployment, -1, | ||
deployment, deployment_dfd, | ||
cancellable, error)) | ||
return FALSE; | ||
} | ||
|
||
ret = TRUE; | ||
if (out_sepolicy) | ||
*out_sepolicy = g_steal_pointer (&sepolicy); | ||
out: | ||
return ret; | ||
return TRUE; | ||
} | ||
|
||
static gboolean | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
glnx_prefix_error()
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, fixup ⏬