Skip to content
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

compose: Support "preserve-passwd" option (enabled by default) #79

Merged
merged 1 commit into from
Dec 24, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/treefile.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ Treefile

Note this does not alter the RPM database, so `rpm -V` will complain.

* `preserve-passwd`: boolean, optional: Defaults to `true`. If enabled,
copy the `/etc/passwd` (and `/usr/lib/passwd`) files from the previous commit
if they exist. This helps ensure consistent uid/gid allocations across
builds. However, it does mean that removed users will exist in the `passwd`
database forever. It also does not help clients switch between unrelated
trees.

* `check-passwd`: Object, optional: Checks to run against the new passwd file
before accepting the tree. All the entries specified should exist (unless
ignored) and have the same values or the compose will fail. There are four
Expand Down
17 changes: 17 additions & 0 deletions src/rpmostree-compose-builtin-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,23 @@ rpmostree_compose_builtin_tree (int argc,
self->serialized_treefile = g_bytes_new_take (treefile_buf, len);
}

{
gboolean generate_from_previous = TRUE;

if (!_rpmostree_jsonutil_object_get_optional_boolean_member (treefile,
"preserve-passwd",
&generate_from_previous,
error))
goto out;

if (generate_from_previous)
{
if (!rpmostree_generate_passwd_from_previous (repo, yumroot, ref,
cancellable, error))
goto out;
}
}

if (!yuminstall (self, treefile, yumroot,
(char**)packages->pdata,
cancellable, error))
Expand Down
25 changes: 25 additions & 0 deletions src/rpmostree-json-parsing.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,31 @@ _rpmostree_jsonutil_object_require_int_member (JsonObject *object,
return TRUE;
}

gboolean
_rpmostree_jsonutil_object_get_optional_boolean_member (JsonObject *object,
const char *member_name,
gboolean *out_value,
GError **error)
{
gboolean ret = FALSE;
JsonNode *node = json_object_get_member (object, member_name);

if (node != NULL)
{
if (json_node_get_value_type (node) != G_TYPE_BOOLEAN)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Member '%s' is not a boolean", member_name);
goto out;
}
*out_value = json_node_get_boolean (node);
}

ret = TRUE;
out:
return ret;
}

const char *
_rpmostree_jsonutil_array_require_string_element (JsonArray *array,
guint i,
Expand Down
6 changes: 6 additions & 0 deletions src/rpmostree-json-parsing.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ _rpmostree_jsonutil_object_require_int_member (JsonObject *object,
gint64 *out_val,
GError **error);

gboolean
_rpmostree_jsonutil_object_get_optional_boolean_member (JsonObject *object,
const char *member_name,
gboolean *out_value,
GError **error);

const char *
_rpmostree_jsonutil_array_require_string_element (JsonArray *array,
guint i,
Expand Down
103 changes: 103 additions & 0 deletions src/rpmostree-passwd-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,3 +667,106 @@ rpmostree_check_groups (OstreeRepo *repo,
return rpmostree_check_passwd_groups (TRUE, repo, yumroot, treefile_dirpath,
treedata, cancellable, error);
}

static gboolean
concat_passwd_file (GFile *yumroot,
GFile *previous_commit,
const char *filename,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
gs_free char *etc_subpath = g_strconcat ("etc/", filename, NULL);
gs_free char *usrlib_subpath = g_strconcat ("usr/lib/", filename, NULL);
gs_unref_object GFile *yumroot_etc = g_file_resolve_relative_path (yumroot, "etc");
gs_unref_object GFile *yumroot_dest = g_file_resolve_relative_path (yumroot, etc_subpath);
gs_unref_object GFile *orig_etc_content = g_file_resolve_relative_path (previous_commit, etc_subpath);
gs_unref_object GFile *orig_usrlib_content = g_file_resolve_relative_path (previous_commit, usrlib_subpath);
gs_unref_object GFileOutputStream *out = NULL;
gboolean have_etc, have_usr;

if (!gs_file_ensure_directory (yumroot_etc, TRUE, cancellable, error))
goto out;

have_etc = g_file_query_exists (orig_etc_content, NULL);
have_usr = g_file_query_exists (orig_usrlib_content, NULL);

if (!(have_etc || have_usr))
{
ret = TRUE;
goto out;
}

out = g_file_replace (yumroot_dest, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
cancellable, error);
if (!out)
goto out;

if (have_etc)
{
gs_unref_object GInputStream *src =
(GInputStream*)g_file_read (orig_etc_content, cancellable, error);
if (g_output_stream_splice ((GOutputStream*)out, src,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error ) < 0)
goto out;
}

if (have_usr)
{
gs_unref_object GInputStream *src =
(GInputStream*)g_file_read (orig_usrlib_content, cancellable, error);
if (g_output_stream_splice ((GOutputStream*)out, src,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error ) < 0)
goto out;
}

if (!g_output_stream_flush ((GOutputStream*)out, cancellable, error))
goto out;

ret = TRUE;
out:
return ret;
}


gboolean
rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
GFile *yumroot,
const char *ref,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GError *temp_error = NULL;
gs_unref_object GFile *previous_root = NULL;
gs_unref_object GFile *yumroot_etc_group = g_file_resolve_relative_path (yumroot, "etc/group");
gs_unref_object GFile *out = NULL;

if (!ostree_repo_read_commit (repo, ref, &previous_root, NULL, NULL, &temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
ret = TRUE;
}
else
{
g_propagate_error (error, temp_error);
}
goto out;
}

if (!concat_passwd_file (yumroot, previous_root, "passwd",
cancellable, error))
goto out;

if (!concat_passwd_file (yumroot, previous_root, "group",
cancellable, error))
goto out;

ret = TRUE;
out:
return ret;
}
7 changes: 7 additions & 0 deletions src/rpmostree-passwd-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ rpmostree_check_groups (OstreeRepo *repo,
JsonObject *treedata,
GCancellable *cancellable,
GError **error);

gboolean
rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
GFile *yumroot,
const char *ref,
GCancellable *cancellable,
GError **error);