summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2010-09-18 10:09:04 +0100
committerRichard W.M. Jones <rjones@redhat.com>2010-09-21 19:51:22 +0100
commitd75a2bff1264828f02b68a9c8bc7eb2521bd6684 (patch)
treeef07f08e52996b6fbafb17f8ec68b198b357b7e9
parent5d4ae18e2b93073080fbbf8c98b11eec15dbc1e6 (diff)
downloadlibguestfs-d75a2bff1264828f02b68a9c8bc7eb2521bd6684.tar.gz
libguestfs-d75a2bff1264828f02b68a9c8bc7eb2521bd6684.tar.xz
libguestfs-d75a2bff1264828f02b68a9c8bc7eb2521bd6684.zip
fish: Implement 'hexedit' command.
-rw-r--r--fish/Makefile.am1
-rw-r--r--fish/fish.h3
-rw-r--r--fish/guestfish.pod9
-rw-r--r--fish/hexedit.c190
-rw-r--r--generator/generator_actions.ml36
-rw-r--r--po/POTFILES.in1
6 files changed, 239 insertions, 1 deletions
diff --git a/fish/Makefile.am b/fish/Makefile.am
index 4d17aa1b..91094df0 100644
--- a/fish/Makefile.am
+++ b/fish/Makefile.am
@@ -48,6 +48,7 @@ guestfish_SOURCES = \
fish.c \
fish.h \
glob.c \
+ hexedit.c \
inspect.c \
lcd.c \
man.c \
diff --git a/fish/fish.h b/fish/fish.h
index f6e1aeb9..b941c493 100644
--- a/fish/fish.h
+++ b/fish/fish.h
@@ -104,6 +104,9 @@ extern int run_echo (const char *cmd, int argc, char *argv[]);
/* in edit.c */
extern int run_edit (const char *cmd, int argc, char *argv[]);
+/* in hexedit.c */
+extern int run_hexedit (const char *cmd, int argc, char *argv[]);
+
/* in inspect.c */
extern void inspect_mount (void);
extern void print_inspect_prompt (void);
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index 4e0ff131..181a053a 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -815,6 +815,12 @@ Used with the I<--remote> option to specify the remote guestfish
process to control. See section
L</REMOTE CONTROL GUESTFISH OVER A SOCKET>.
+=item HEXEDITOR
+
+The L</hexedit> command uses C<$HEXEDITOR> as the external hex
+editor. If not specified, the external L<hexedit(1)> program
+is used.
+
=item HOME
If compiled with GNU readline support, various files in the
@@ -932,7 +938,8 @@ L<virt-make-fs(1)>,
L<virt-rescue(1)>,
L<virt-resize(1)>,
L<virt-tar(1)>,
-L<virt-win-reg(1)>.
+L<virt-win-reg(1)>,
+L<hexedit(1)>.
=head1 AUTHORS
diff --git a/fish/hexedit.c b/fish/hexedit.c
new file mode 100644
index 00000000..dfa18890
--- /dev/null
+++ b/fish/hexedit.c
@@ -0,0 +1,190 @@
+/* guestfish - the filesystem interactive shell
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "fish.h"
+
+#define MAX_DOWNLOAD_SIZE (16 * 1024 * 1024)
+#define MAX_DOWNLOAD_SIZE_TEXT "16MB"
+
+static off_t get_size (const char *filename);
+
+int
+run_hexedit (const char *cmd, int argc, char *argv[])
+{
+ if (argc < 1 || argc > 3) {
+ fprintf (stderr, _("hexedit (device|filename) [max | start max]\n"));
+ return -1;
+ }
+
+ const char *filename = argv[0];
+ off_t size = get_size (filename);
+ if (size == -1)
+ return -1;
+
+ if (size == 0) {
+ fprintf (stderr,
+ _("hexedit: %s is a zero length file or device\n"), filename);
+ return -1;
+ }
+
+ off_t start;
+ off_t max;
+
+ if (argc == 1) { /* hexedit device */
+ /* Check we're not going to download a huge file. */
+ if (size > MAX_DOWNLOAD_SIZE) {
+ fprintf (stderr,
+ _("hexedit: %s is larger than %s. You must supply a limit using\n"
+ " 'hexedit %s <max>' (eg. 'hexedit %s 1M') or a range using\n"
+ " 'hexedit %s <start> <max>'.\n"),
+ filename, MAX_DOWNLOAD_SIZE_TEXT,
+ filename, filename,
+ filename);
+ return -1;
+ }
+
+ start = 0;
+ max = size;
+ }
+ else {
+ if (argc == 3) { /* hexedit device start max */
+ if (parse_size (argv[1], &start) == -1)
+ return -1;
+ if (parse_size (argv[2], &max) == -1)
+ return -1;
+ } else { /* hexedit device max */
+ start = 0;
+ if (parse_size (argv[1], &max) == -1)
+ return -1;
+ }
+
+ if (start + max > size)
+ max = size - start;
+ }
+
+ if (max <= 0) {
+ fprintf (stderr, _("hexedit: invalid range\n"));
+ return -1;
+ }
+
+ /* Download the requested range from the remote file|device into a
+ * local temporary file.
+ */
+ const char *editor;
+ int r;
+ struct stat oldstat, newstat;
+ char buf[BUFSIZ];
+ char tmp[] = "/tmp/guestfishXXXXXX";
+ int fd = mkstemp (tmp);
+ if (fd == -1) {
+ perror ("mkstemp");
+ return -1;
+ }
+
+ /* Choose an editor. */
+ editor = getenv ("HEXEDITOR");
+ if (editor == NULL)
+ editor = "hexedit";
+
+ snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
+
+ if (guestfs_download_offset (g, filename, buf, start, max) == -1) {
+ unlink (tmp);
+ close (fd);
+ return -1;
+ }
+
+ if (close (fd) == -1) {
+ unlink (tmp);
+ return -1;
+ }
+
+ /* Get the old stat. */
+ if (stat (tmp, &oldstat) == -1) {
+ perror (tmp);
+ unlink (tmp);
+ return -1;
+ }
+
+ /* Edit it. */
+ snprintf (buf, sizeof buf, "%s %s", editor, tmp);
+
+ r = system (buf);
+ if (r != 0) {
+ perror (buf);
+ unlink (tmp);
+ return -1;
+ }
+
+ /* Get the new stat. */
+ if (stat (tmp, &newstat) == -1) {
+ perror (tmp);
+ unlink (tmp);
+ return -1;
+ }
+
+ /* Changed? */
+ if (oldstat.st_ctime == newstat.st_ctime &&
+ oldstat.st_size == newstat.st_size) {
+ unlink (tmp);
+ return 0;
+ }
+
+ /* Write new content. */
+ if (guestfs_upload_offset (g, tmp, filename, start) == -1) {
+ unlink (tmp);
+ return -1;
+ }
+
+ unlink (tmp);
+ return 0;
+}
+
+/* Get the size of the file or block device. */
+static off_t
+get_size (const char *filename)
+{
+ int64_t size;
+
+ if (STRPREFIX (filename, "/dev/")) {
+ size = guestfs_blockdev_getsize64 (g, filename);
+ if (size == -1)
+ return -1;
+ }
+ else {
+ size = guestfs_filesize (g, filename);
+ if (size == -1)
+ return -1;
+ }
+
+ /* This case should be safe because we always compile with
+ * 64 bit file offsets.
+ */
+ return (off_t) size;
+}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 5a95a6d4..ac8dab21 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -5270,6 +5270,42 @@ repeatedly on each matching path.
See L</WILDCARDS AND GLOBBING>.");
+ ("hexedit", (RErr,[]), -1, [], [],
+ "edit with a hex editor",
+ " hexedit <filename|device>
+ hexedit <filename|device> <max>
+ hexedit <filename|device> <start> <max>
+
+Use hexedit (a hex editor) to edit all or part of a binary file
+or block device.
+
+This command works by downloading potentially the whole file or
+device, editing it locally, then uploading it. If the file or
+device is large, you have to specify which part you wish to edit
+by using C<max> and/or C<start> C<max> parameters.
+C<start> and C<max> are specified in bytes, with the usual
+modifiers allowed such as C<1M> (1 megabyte).
+
+For example to edit the first few sectors of a disk you
+might do:
+
+ hexedit /dev/sda 1M
+
+which would allow you to edit anywhere within the first megabyte
+of the disk.
+
+To edit the superblock of an ext2 filesystem on C</dev/sda1>, do:
+
+ hexedit /dev/sda1 0x400 0x400
+
+(assuming the superblock is in the standard location).
+
+This command requires the external L<hexedit(1)> program. You
+can specify another program to use by setting the C<HEXEDITOR>
+environment variable.
+
+See also L</hexdump>.");
+
("lcd", (RErr,[]), -1, [], [],
"change working directory",
" lcd directory
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4518eabe..10b690c6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -78,6 +78,7 @@ fish/echo.c
fish/edit.c
fish/fish.c
fish/glob.c
+fish/hexedit.c
fish/inspect.c
fish/lcd.c
fish/man.c