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
Reasonably Related 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).