>From cb56911983cda17b3a814fda1f0cae40112a5da6 Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Wed, 30 Jan 2013 13:59:17 +0100 Subject: [PATCH] Allow the --use-compress-program option to have arguments * doc/tar.texi: Document this change in manual. * NEWS: Document changes. * lib/prepargs.c: Add new function option_to_argv. Comment the prepend_default_options function. * lib/prepargs.h: Add declaration for option_to_argv. * src/system.c: Use "prepargs.h". Parse the use_compress_program_option by option_to_argv () and exec it by execvp (). --- NEWS | 5 +++++ doc/tar.texi | 6 ++++++ lib/prepargs.c | 26 ++++++++++++++++++++++++++ lib/prepargs.h | 1 + src/system.c | 41 +++++++++++++++++++++++++++++++++++------ 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 29b4486..a676b88 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,11 @@ Please send GNU tar bug reports to version 1.26.90 (Git) +* Improved functionality of --use-compress-program option + +Using this option, there is now possible to pass commands also +containing program arguments. + * Bug fixes ** Sparse files with large data diff --git a/doc/tar.texi b/doc/tar.texi index 4a49282..ee93b2a 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -8977,6 +8977,7 @@ suffix. The following suffixes are recognized: @item @samp{.xz} @tab @command{xz} @end multitable address@hidden @opindex use-compress-program @item address@hidden @itemx address@hidden @@ -8991,6 +8992,11 @@ input, compress it and output it on standard output. Secondly, if invoked with the @option{-d} option, it should do exactly the opposite, i.e., read the compressed data from the standard input and produce uncompressed data on the standard output. + +From @GNUTAR{} version 1.26.90, the @var{prog} may be command consisting of +multiple arguments. In example, @command{xz --format=lzma}. There is +possible to escape white space (or backslash) charaters using backslash +(@pxref{TAR_OPTIONS} is parsed similar way). @end table @cindex gpg, using with tar diff --git a/lib/prepargs.c b/lib/prepargs.c index 9b30d24..3413759 100644 --- a/lib/prepargs.c +++ b/lib/prepargs.c @@ -70,6 +70,29 @@ prepend_args (char const *options, char *buf, char **argv) } } +/* Parse the OPTIONS into argv-like array *PARGV. The *PARGV array will be + allocated & will be NULL terminated. Returns -1 when error occurred, + otherwise returns number of parsed options. */ +int options_to_argv (const char *options, char ***pargv) +{ + char *buf; + int prepended; + char **argv; + + if (!options) + return -1; + + buf = xmalloc (strlen (options) + 1); + prepended = prepend_args (options, buf, (char **) 0); + argv = xmalloc ((prepended + 1) *sizeof(char **)); + + prepend_args (options, buf, argv); + argv[prepended] = NULL; + + *pargv = argv; + return prepended; +} + /* Prepend the whitespace-separated options in OPTIONS to the argument vector of a main program with argument count *PARGC and argument vector *PARGV. */ @@ -85,8 +108,11 @@ prepend_default_options (char const *options, int *pargc, char ***pargv) char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); *pargc = prepended + argc; *pargv = pp; + /* "pop" to move argv after the program name */ *pp++ = *argv++; + /* append options wanted to be prepended now */ pp += prepend_args (options, buf, pp); + /* and "pop" remaining options (including NULL) */ while ((*pp++ = *argv++)) continue; } diff --git a/lib/prepargs.h b/lib/prepargs.h index ce93ea8..6bda109 100644 --- a/lib/prepargs.h +++ b/lib/prepargs.h @@ -1,3 +1,4 @@ /* Parse arguments from a string and prepend them to an argv. */ void prepend_default_options (char const *, int *, char ***); +int options_to_argv (const char *options, char ***argv); diff --git a/src/system.c b/src/system.c index 9dfffcf..7c607f2 100644 --- a/src/system.c +++ b/src/system.c @@ -18,6 +18,8 @@ #include #include "common.h" +#include "prepargs.h" + #include #include #include @@ -115,6 +117,9 @@ extern union block *record_start; /* FIXME */ static struct stat archive_stat; /* stat block for archive file */ +static void +sys_execvp (const char *command, const char *aargs) __attribute__ ((noreturn)); + bool sys_get_archive_stat (void) { @@ -307,6 +312,33 @@ wait_for_grandchild (pid_t pid) exit (exit_code); } +/* Parse the COMMAND string into argv-like array and execute. + This function never returns, the AARGS string may be used to pass + additional arguments (set to NULL otherwise). */ +void +sys_execvp (const char *command, const char *aargs) +{ + char **argv = NULL; + char *acmd; + struct obstack stk; + + obstack_init (&stk); + obstack_grow (&stk, command, strlen (command)); + if (aargs) + { + obstack_1grow (&stk, ' '); + obstack_grow (&stk, aargs, strlen (aargs)); + } + obstack_1grow (&stk, 0); + acmd = obstack_finish (&stk); + + if (1 > options_to_argv (acmd, &argv)) + FATAL_ERROR ((0, 0, _("Bad command: '%s'"), acmd)); + + execvp (argv[0], argv); + exec_fatal (acmd); +} + /* Set ARCHIVE for writing, then compressing an archive. */ pid_t sys_child_open_for_compress (void) @@ -363,8 +395,7 @@ sys_child_open_for_compress (void) xdup2 (archive, STDOUT_FILENO); } priv_set_restore_linkdir (); - execlp (use_compress_program_option, use_compress_program_option, NULL); - exec_fatal (use_compress_program_option); + sys_execvp (use_compress_program_option, 0); } /* We do need a grandchild tar. */ @@ -381,9 +412,7 @@ sys_child_open_for_compress (void) xdup2 (child_pipe[PWRITE], STDOUT_FILENO); xclose (child_pipe[PREAD]); priv_set_restore_linkdir (); - execlp (use_compress_program_option, use_compress_program_option, - (char *) 0); - exec_fatal (use_compress_program_option); + sys_execvp (use_compress_program_option, 0); } /* The child tar is still here! */ @@ -469,7 +498,7 @@ run_decompress_program (void) (0, 0, _("trying %s"), p)); } prog = p; - execlp (p, p, "-d", NULL); + sys_execvp (p, "-d"); } if (!prog) FATAL_ERROR ((0, 0, _("unable to run decompression program"))); -- 1.7.11.7