From: Richard Jones Date: Mon, 19 Apr 2010 13:41:01 +0000 (+0100) Subject: fish: Allow -< upload -< cat /foo some data some more data --- diff --git a/fish/fish.c b/fish/fish.c index 61a8405..db3149e 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -1419,3 +1419,144 @@ resolve_win_path (const char *path) return ret; } + +/* Resolve the special FileIn paths ("-" or "-< or "END\n" in input. */ + size_t blen = strlen (buffer); + if (STREQLEN (buffer, endmarker, markerlen) && + (blen == markerlen || + (blen == markerlen+1 && buffer[markerlen] == '\n'))) + goto found_end; + + if (xwrite (fd, buffer, blen) == -1) { + if (!write_error) perror ("write"); + write_error = 1; + /* continue reading up to the end marker */ + } + } + + /* Reached EOF of stdin without finding the end marker, which + * is likely to be an error. + */ + fprintf (stderr, "%s: end of input reached without finding '%s'\n", + program_name, endmarker); + goto error2; + + found_end: + if (write_error) { + close (fd); + goto error2; + } + + if (close (fd) == -1) { + perror ("close"); + goto error2; + } + + return file_in_tmpfile; + + error2: + unlink (file_in_tmpfile); + + error1: + free (file_in_tmpfile); + file_in_tmpfile = NULL; + return NULL; +} + +void +free_file_in (char *s) +{ + if (file_in_tmpfile) { + if (unlink (file_in_tmpfile) == -1) + perror (file_in_tmpfile); + file_in_tmpfile = NULL; + } + + /* Free the device or file name which was strdup'd in file_in(). + * Note it's not immediately clear, but for -<< heredocs, + * s == file_in_tmpfile, so this frees up that buffer. + */ + free (s); +} + +/* Resolve the special FileOut paths ("-" or filename). + * The caller (cmds.c) will call free (str) after the command has run. + */ +char * +file_out (const char *arg) +{ + char *ret; + + if (STREQ (arg, "-")) + ret = strdup ("/dev/stdout"); + else + ret = strdup (arg); + + if (!ret) { + perror ("strdup"); + return NULL; + } + return ret; +} diff --git a/fish/fish.h b/fish/fish.h index 5856b8e..05135fb 100644 --- a/fish/fish.h +++ b/fish/fish.h @@ -65,6 +65,9 @@ extern int is_true (const char *str); extern char **parse_string_list (const char *str); extern int xwrite (int fd, const void *buf, size_t len); extern char *resolve_win_path (const char *path); +extern char *file_in (const char *arg); +extern void free_file_in (char *s); +extern char *file_out (const char *arg); extern void extended_help_message (void); /* in cmds.c (auto-generated) */ diff --git a/fish/guestfish.pod b/fish/guestfish.pod index e61d4e5..836c4f7 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -486,6 +486,39 @@ user ID of the process, and C<$PID> is the process ID of the server. Guestfish client and server versions must match exactly. +=head1 UPLOADING AND DOWNLOADING FILES + +For commands such as C, C, C, C and +others which upload from or download to a local file, you can use the +special filename C<-> to mean "from stdin" or "to stdout". For example: + + upload - /foo + +reads stdin and creates from that a file C in the disk image, +and: + + tar-out /etc - | tar tf - + +writes the tarball to stdout and then pipes that into the external +"tar" command (see L). + +When using C<-> to read from stdin, the input is read up to the end of +stdin. You can also use a special "heredoc"-like syntax to read up to +some arbitrary end marker: + + upload -<. The end +marker must appear on a line of its own, without any preceeding or +following characters (not even spaces). + +Note that the C<-EE> syntax only applies to parameters used to +upload local files (so-called "FileIn" parameters in the generator). + =head1 GUESTFISH COMMANDS The commands in this section are guestfish convenience commands, in diff --git a/src/generator.ml b/src/generator.ml index 65efd66..580cb14 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -7385,11 +7385,11 @@ and generate_fish_cmds () = function | Device n | String n - | OptString n - | FileIn n - | FileOut n -> pr " const char *%s;\n" n + | OptString n -> pr " const char *%s;\n" n | Pathname n - | Dev_or_Path n -> pr " char *%s;\n" n + | Dev_or_Path n + | FileIn n + | FileOut n -> pr " char *%s;\n" n | StringList n | DeviceList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n @@ -7446,11 +7446,11 @@ and generate_fish_cmds () = pr " %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n" name i i | FileIn name -> - pr " %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n" - name i i + pr " %s = file_in (argv[%d]);\n" name i; + pr " if (%s == NULL) return -1;\n" name | FileOut name -> - pr " %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n" - name i i + pr " %s = file_out (argv[%d]);\n" name i; + pr " if (%s == NULL) return -1;\n" name | StringList name | DeviceList name -> pr " %s = parse_string_list (argv[%d]);\n" name i; pr " if (%s == NULL) return -1;\n" name; @@ -7479,10 +7479,12 @@ and generate_fish_cmds () = List.iter ( function | Device name | String name - | OptString name | FileIn name | FileOut name | Bool name + | OptString name | Bool name | Int name | Int64 name -> () - | Pathname name | Dev_or_Path name -> + | Pathname name | Dev_or_Path name | FileOut name -> pr " free (%s);\n" name + | FileIn name -> + pr " free_file_in (%s);\n" name | StringList name | DeviceList name -> pr " free_strings (%s);\n" name ) (snd style);