[Libguestfs] [PATCH 10/13] fish: edit: add perl file editing

Pino Toscano ptoscano at redhat.com
Thu Aug 28 13:21:54 UTC 2014


Add the perl file editing, mostly based in the virt-edit implementation.

This introduces a mild code duplication with edit_file_editor; will deal
with it in a later commit.
---
 fish/file-edit.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fish/file-edit.h |  11 ++++++
 2 files changed, 121 insertions(+)

diff --git a/fish/file-edit.c b/fish/file-edit.c
index e2298eb..fa68626 100644
--- a/fish/file-edit.c
+++ b/fish/file-edit.c
@@ -159,6 +159,116 @@ edit_file_editor (guestfs_h *g, const char *filename, const char *editor,
   return 0;
 }
 
+int
+edit_file_perl (guestfs_h *g, const char *filename, const char *perl_expr,
+                const char *backup_extension)
+{
+  CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
+  CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
+  char buf[256];
+  CLEANUP_FREE char *newname = NULL;
+  CLEANUP_FREE char *cmd = NULL;
+  CLEANUP_FREE char *outfile = NULL;
+  int r, fd;
+
+  /* Download the file and write it to a temporary. */
+  if (asprintf (&tmpfilename, "%s/libguestfsXXXXXX", tmpdir) == -1) {
+    perror ("asprintf");
+    return -1;
+  }
+
+  fd = mkstemp (tmpfilename);
+  if (fd == -1) {
+    perror ("mkstemp");
+    return -1;
+  }
+
+  snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
+
+  if (guestfs_download (g, filename, buf) == -1) {
+    close (fd);
+    return -1;
+  }
+
+  if (close (fd) == -1) {
+    perror (tmpfilename);
+    return -1;
+  }
+
+  if (asprintf (&outfile, "%s.out", tmpfilename) == -1) {
+    perror ("asprintf");
+    return -1;
+  }
+
+  /* Pass the expression to Perl via the environment.  This sidesteps
+   * any quoting problems with the already complex Perl command line.
+   */
+  setenv ("virt_edit_expr", perl_expr, 1);
+
+  /* Call out to a canned Perl script. */
+  if (asprintf (&cmd,
+                "perl -e '"
+                "$lineno = 0; "
+                "$expr = $ENV{virt_edit_expr}; "
+                "while (<STDIN>) { "
+                "  $lineno++; "
+                "  eval $expr; "
+                "  die if $@; "
+                "  print STDOUT $_ or die \"print: $!\"; "
+                "} "
+                "close STDOUT or die \"close: $!\"; "
+                "' < %s > %s",
+                tmpfilename, outfile) == -1) {
+    perror ("asprintf");
+    return -1;
+  }
+
+  r = system (cmd);
+  if (r == -1 || WEXITSTATUS (r) != 0)
+    return -1;
+
+  if (rename (outfile, tmpfilename) == -1) {
+    perror ("rename");
+    return -1;
+  }
+
+  /* Upload to a new file in the same directory, so if it fails we
+   * don't end up with a partially written file.  Give the new file
+   * a completely random name so we have only a tiny chance of
+   * overwriting some existing file.
+   */
+  newname = generate_random_name (filename);
+  if (!newname)
+    return -1;
+
+  /* Write new content. */
+  if (guestfs_upload (g, tmpfilename, newname) == -1)
+    return -1;
+
+  /* Set the permissions, UID, GID and SELinux context of the new
+   * file to match the old file (RHBZ#788641).
+   */
+  if (guestfs_copy_attributes (g, filename, newname,
+      GUESTFS_COPY_ATTRIBUTES_ALL, 1, -1) == -1)
+    return -1;
+
+  /* Backup or overwrite the file. */
+  if (backup_extension) {
+    CLEANUP_FREE char *backupname = NULL;
+
+    backupname = generate_backup_name (filename, backup_extension);
+    if (backupname == NULL)
+      return -1;
+
+    if (guestfs_mv (g, filename, backupname) == -1)
+      return -1;
+  }
+  if (guestfs_mv (g, newname, filename) == -1)
+    return -1;
+
+  return 0;
+}
+
 static char
 random_char (void)
 {
diff --git a/fish/file-edit.h b/fish/file-edit.h
index 1d401c6..98fc453 100644
--- a/fish/file-edit.h
+++ b/fish/file-edit.h
@@ -32,4 +32,15 @@
 extern int edit_file_editor (guestfs_h *g, const char *filename,
                              const char *editor, const char *backup_extension);
 
+/**
+ * Edit 'filename' running the specified 'perl_expr' using Perl.
+ * If 'backup_extension' is not null, then a copy of 'filename' is saved
+ * with 'backup_extension' appended to its file name.
+ *
+ * Returns -1 for failure, 0 otherwise (on success).
+ */
+extern int edit_file_perl (guestfs_h *g, const char *filename,
+                           const char *perl_expr,
+                           const char *backup_extension);
+
 #endif
-- 
1.9.3




More information about the Libguestfs mailing list