Richard W.M. Jones
2012-Feb-08 18:24 UTC
[Libguestfs] Fix virt-edit so it preserves permissions (RHBZ#788641)
The first patch preserves file mode, UID, GID and SELinux context across edited files. The second patch adds a useful new command in guestfish ('llz') which shows SELinux context (like 'ls -laZ') that was useful when debugging this. Rich.
Richard W.M. Jones
2012-Feb-08 18:24 UTC
[Libguestfs] [PATCH 1/2] edit: Preserve file permissions, UID, GID, SELinux context on edited files. (RHBZ#788641)
From: "Richard W.M. Jones" <rjones at redhat.com> --- edit/virt-edit.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 82 insertions(+), 0 deletions(-) diff --git a/edit/virt-edit.c b/edit/virt-edit.c index baa0b3e..a23e66a 100644 --- a/edit/virt-edit.c +++ b/edit/virt-edit.c @@ -55,6 +55,8 @@ static const char *perl_expr = NULL; static void edit (const char *filename, const char *root); static char *edit_interactively (const char *tmpfile); static char *edit_non_interactively (const char *tmpfile); +static int copy_attributes (const char *src, const char *dest); +static int feature_available (guestfs_h *g, const char *feature); static int is_windows (guestfs_h *g, const char *root); static char *windows_path (guestfs_h *g, const char *root, const char *filename); static char *generate_random_name (const char *filename); @@ -357,6 +359,12 @@ edit (const char *filename, const char *root) if (guestfs_upload (g, upload_from, newname) == -1) goto error; + /* Set the permissions, UID, GID and SELinux context of the new + * file to match the old file (RHBZ#788641). + */ + if (copy_attributes (filename, newname) == -1) + goto error; + /* Backup or overwrite the file. */ if (backup_extension) { backupname = generate_backup_name (filename); @@ -511,6 +519,80 @@ edit_non_interactively (const char *tmpfile) } static int +copy_attributes (const char *src, const char *dest) +{ + struct guestfs_stat *stat; + int has_linuxxattrs; + char *selinux_context = NULL; + size_t selinux_context_size; + + has_linuxxattrs = feature_available (g, "linuxxattrs"); + + /* Get the mode. */ + stat = guestfs_stat (g, src); + if (stat == NULL) + return -1; + + /* Get the SELinux context. XXX Should we copy over other extended + * attributes too? + */ + if (has_linuxxattrs) { + guestfs_error_handler_cb old_error_cb; + void *old_error_data; + old_error_cb = guestfs_get_error_handler (g, &old_error_data); + guestfs_set_error_handler (g, NULL, NULL); + + selinux_context = guestfs_getxattr (g, src, "security.selinux", + &selinux_context_size); + /* selinux_context could be NULL. This isn't an error. */ + + guestfs_set_error_handler (g, old_error_cb, old_error_data); + } + + /* Set the permissions, UID, GID. */ + if (guestfs_chmod (g, stat->mode & 0777, dest) == -1) { + guestfs_free_stat (stat); + return -1; + } + if (guestfs_chown (g, stat->uid, stat->gid, dest) == -1) { + guestfs_free_stat (stat); + return -1; + } + guestfs_free_stat (stat); + + /* Set the SELinux context. */ + if (has_linuxxattrs && selinux_context) { + if (guestfs_setxattr (g, "security.selinux", selinux_context, + (int) selinux_context_size, dest) == -1) { + free (selinux_context); + return -1; + } + } + free (selinux_context); + + return 0; +} + +static int +feature_available (guestfs_h *g, const char *feature) +{ + /* If there's an error we should ignore it, so to do that we have to + * temporarily replace the error handler with a null one. + */ + guestfs_error_handler_cb old_error_cb; + void *old_error_data; + old_error_cb = guestfs_get_error_handler (g, &old_error_data); + guestfs_set_error_handler (g, NULL, NULL); + + const char *groups[] = { feature, NULL }; + int r = guestfs_available (g, (char * const *) groups); + + guestfs_set_error_handler (g, old_error_cb, old_error_data); + + return r == 0 ? 1 : 0; +} + +static int is_windows (guestfs_h *g, const char *root) { char *type; -- 1.7.9
Richard W.M. Jones
2012-Feb-08 18:24 UTC
[Libguestfs] [PATCH 2/2] New API: llz: This runs ls -laZ and is useful for showing SELinux contexts.
From: "Richard W.M. Jones" <rjones at redhat.com> --- daemon/ls.c | 26 ++++++++++++++++++++++++++ generator/generator_actions.ml | 9 +++++++++ src/MAX_PROC_NR | 2 +- 3 files changed, 36 insertions(+), 1 deletions(-) diff --git a/daemon/ls.c b/daemon/ls.c index d0c7b52..1df0b6a 100644 --- a/daemon/ls.c +++ b/daemon/ls.c @@ -102,3 +102,29 @@ do_ll (const char *path) free (err); return out; /* caller frees */ } + +char * +do_llz (const char *path) +{ + int r; + char *out, *err; + char *spath; + + spath = sysroot_path (path); + if (!spath) { + reply_with_perror ("malloc"); + return NULL; + } + + r = command (&out, &err, "ls", "-laZ", spath, NULL); + free (spath); + if (r == -1) { + reply_with_error ("%s", err); + free (out); + free (err); + return NULL; + } + + free (err); + return out; /* caller frees */ +} diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 3a7be79..f9ba5c3 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -6651,6 +6651,15 @@ This option may not be specified at the same time as the C<correct> option. =back"); + ("llz", (RString "listing", [Pathname "directory"], []), 305, [], + [], + "list the files in a directory (long format with SELinux contexts)", + "\ +List the files in C<directory> in the format of 'ls -laZ'. + +This command is mostly useful for interactive sessions. It +is I<not> intended that you try to parse the output string."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 873b744..67d04b9 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -304 +305 -- 1.7.9
Apparently Analagous Threads
- [PATCH 0/3] Fix guestfish edit command.
- RFC: copy-attributes command
- [PATCH] builder, edit, fish: use copy-attributes
- [PATCH 0/4] fish: Allow the glob command to expand device patterns (RHBZ#635971).
- [PATCH 0/2] Make appliance building thread-safe (RHBZ#790721).