[rfc] leverage -x/-X tar call to pass more tar options
I'm in the process of moving apt-listchanges to C, slowly, and the
attached patch would make it really easier for me to work with dpkg-deb.
The point is that doing chained pipes is pretty annoying from C
(especially if you want to use parallelism in the process), plus it kind
of make sense for many kind of operations where you don't need
--fsys-tarfile anymore: e.g. extracting a single file can be done with:
dpkg-deb -x file.deb some-dir ./path/to/file/to/extract
What I do is that additionnal arguments passed after the "directory"
argument of -x and -X are passed straight to tar.
--
·O· Pierre Habouzit
··O madcoder@debian.org
OOO http://www.madism.org
>From ba0dd1312e16e5a9ad266549b0caa8d6fa9186fd Mon Sep 17 00:00:00 2001
From: Pierre Habouzit <madcoder@debian.org>
Date: Sat, 3 Jul 2010 09:04:26 +0200
Subject: [PATCH] dpkg-deb: --[v]extract can take tar options.
Allow --extract/vextract to take additionnal arguments as arguments to the
underlying tar call. This leverages the underlying tar invocation.
Avoiding the need for a pipe of `dpkg-deb --fsys-tarfile` into tar(1).
This eases the call of dpkg-deb from e.g. C.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
dpkg-deb/dpkg-deb.h | 3 ++-
dpkg-deb/extract.c | 36 +++++++++++++++++++++++++++---------
dpkg-deb/info.c | 4 ++--
dpkg-deb/main.c | 6 ++++--
man/dpkg-deb.1 | 8 +++++---
5 files changed, 40 insertions(+), 17 deletions(-)
diff --git a/dpkg-deb/dpkg-deb.h b/dpkg-deb/dpkg-deb.h
index 4f302c1..5789132 100644
--- a/dpkg-deb/dpkg-deb.h
+++ b/dpkg-deb/dpkg-deb.h
@@ -31,7 +31,8 @@ extern const struct cmdinfo *cipaction;
extern dofunction *action;
void extracthalf(const char *debar, const char *directory,
- const char *taroption, int admininfo);
+ const char *taroption, int admininfo,
+ const char *const *taropts);
extern const char* showformat;
extern struct compressor *compressor;
diff --git a/dpkg-deb/extract.c b/dpkg-deb/extract.c
index e5e1f9c..914224b 100644
--- a/dpkg-deb/extract.c
+++ b/dpkg-deb/extract.c
@@ -111,7 +111,8 @@ safe_fflush(FILE *f)
}
void extracthalf(const char *debar, const char *directory,
- const char *taroption, int admininfo) {
+ const char *taroption, int admininfo,
+ const char *const *taropts) {
char versionbuf[40];
float versionnum;
char ctrllenbuf[40];
@@ -315,7 +316,10 @@ void extracthalf(const char *debar, const char *directory,
if (taroption) {
c3 = subproc_fork();
if (!c3) {
+ const char **targv, **arg;
char buffer[30+2];
+ int i;
+
if (strlen(taroption) > 30)
internerr("taroption is too long '%s'", taroption);
strcpy(buffer, taroption);
@@ -325,7 +329,17 @@ void extracthalf(const char *debar, const char *directory,
unsetenv("TAR_OPTIONS");
- execlp(TAR, "tar", buffer, "-", NULL);
+ for (i = 0; taropts && taropts[i]; i++);
+ arg = targv = m_malloc((5 + i + 1) * sizeof(targv[0]));
+ *arg++ = "tar";
+ *arg++ = buffer;
+ *arg++ = "-";
+ if (i) {
+ mempcpy(arg, taropts, i * sizeof(taropts[0]));
+ arg += i;
+ }
+ *arg++ = NULL;
+ execvp(TAR, (char *const *)targv);
ohshite(_("failed to exec tar"));
}
close(p2[0]);
@@ -348,17 +362,15 @@ static void controlextractvextract(int admin,
const char *taroptions,
const char *const *argv) {
const char *debar, *directory;
-
+
if (!(debar= *argv++))
badusage(_("--%s needs a .deb filename argument"),cipaction->olong);
if (!(directory= *argv++)) {
if (admin) directory= EXTRACTCONTROLDIR;
else ohshit(_("--%s needs a target directory.\n"
"Perhaps you should be using dpkg --install ?"),cipaction->olong);
- } else if (*argv) {
- badusage(_("--%s takes at most two arguments (.deb and directory)"),cipaction->olong);
}
- extracthalf(debar, directory, taroptions, admin);
+ extracthalf(debar, directory, taroptions, admin, argv);
}
void do_fsystarfile(const char *const *argv) {
@@ -368,10 +380,16 @@ void do_fsystarfile(const char *const *argv) {
badusage(_("--%s needs a .deb filename argument"),cipaction->olong);
if (*argv)
badusage(_("--%s takes only one argument (.deb filename)"),cipaction->olong);
- extracthalf(debar, NULL, NULL, 0);
+ extracthalf(debar, NULL, NULL, 0, argv);
+}
+
+void do_control(const char *const *argv) {
+ if (argv[0] && argv[1] && argv[2]) {
+ badusage(_("--%s takes at most two arguments (.deb and directory)"),
+ cipaction->olong);
+ }
+ controlextractvextract(1, "x", argv);
}
-
-void do_control(const char *const *argv) { controlextractvextract(1, "x", argv); }
void do_extract(const char *const *argv) { controlextractvextract(0, "xp", argv); }
void do_vextract(const char *const *argv) { controlextractvextract(0, "xpv", argv); }
diff --git a/dpkg-deb/info.c b/dpkg-deb/info.c
index a2b2790..9a6b492 100644
--- a/dpkg-deb/info.c
+++ b/dpkg-deb/info.c
@@ -80,7 +80,7 @@ static void info_prepare(const char *const **argvp,
*directoryp= dbuf;
push_cleanup(cu_info_prepare, -1, NULL, 0, 1, (void *)dbuf);
- extracthalf(*debarp, dbuf, "mx", admininfo);
+ extracthalf(*debarp, dbuf, "mx", admininfo, NULL);
}
static int ilist_select(const struct dirent *de) {
@@ -291,7 +291,7 @@ void do_contents(const char *const *argv) {
const char *debar;
if (!(debar= *argv++) || *argv) badusage(_("--contents takes exactly one argument"));
- extracthalf(debar, NULL, "tv", 0);
+ extracthalf(debar, NULL, "tv", 0, NULL);
}
/* vi: sw=2
*/
diff --git a/dpkg-deb/main.c b/dpkg-deb/main.c
index 319e715..8238720 100644
--- a/dpkg-deb/main.c
+++ b/dpkg-deb/main.c
@@ -78,8 +78,10 @@ usage(const struct cmdinfo *cip, const char *value)
" -W|--show <deb> Show information on package(s)\n"
" -f|--field <deb> [<cfield> ...] Show field(s) to stdout.\n"
" -e|--control <deb> [<directory>] Extract control info.\n"
-" -x|--extract <deb> <directory> Extract files.\n"
-" -X|--vextract <deb> <directory> Extract & list files.\n"
+" -x|--extract <deb> <directory> [tar-options...]\n"
+" Extract files.\n"
+" -X|--vextract <deb> <directory> [tar-options...]\n"
+" Extract & list files.\n"
" --fsys-tarfile <deb> Output filesystem tarfile.\n"
"\n"));
diff --git a/man/dpkg-deb.1 b/man/dpkg-deb.1
index ec451ef..c5db6e7 100644
--- a/man/dpkg-deb.1
+++ b/man/dpkg-deb.1
@@ -123,9 +123,11 @@ package archive. It is currently produced in the format generated by
.BR tar 's
verbose listing.
.TP
-.BR \-x ", " \-\-extract " \fIarchive directory\fP"
+.BR \-x ", " \-\-extract " \fIarchive directory\fP [\fItar-options\fP...]"
Extracts the filesystem tree from a package archive into the specified
-directory.
+directory. Additionnal arguments are passed straight to
+.BR tar (1)
+ .
Note that extracting a package to the root directory will
.I not
@@ -137,7 +139,7 @@ to install packages.
(but not its parents) will be created if necessary, and its permissions
modified to match the contents of the package.
.TP
-.BR \-X ", " \-\-vextract " \fIarchive directory\fP"
+.BR \-X ", " \-\-vextract " \fIarchive directory\fP [\fItar-options\fP...]"
Is like
.BR \-\-extract " (" \-x ")"
but prints a listing of the files extracted as it goes.
--
1.7.2.rc1.192.g262ff
Reply to: