aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
Diffstat (limited to 'archival')
-rw-r--r--archival/ar.c15
-rw-r--r--archival/bbunzip.c7
-rw-r--r--archival/bzip2.c8
-rw-r--r--archival/cpio.c7
-rw-r--r--archival/dpkg.c3
-rw-r--r--archival/dpkg_deb.c5
-rw-r--r--archival/gzip.c7
-rw-r--r--archival/libarchive/Kbuild.src2
-rw-r--r--archival/libarchive/data_extract_all.c37
-rw-r--r--archival/libarchive/decompress_unxz.c1
-rw-r--r--archival/libarchive/open_transformer.c40
-rw-r--r--archival/libarchive/unsafe_symlink_target.c48
-rw-r--r--archival/lzop.c2
-rw-r--r--archival/rpm.c412
-rw-r--r--archival/rpm2cpio.c96
-rw-r--r--archival/tar.c55
-rw-r--r--archival/unzip.c10
17 files changed, 435 insertions, 320 deletions
diff --git a/archival/ar.c b/archival/ar.c
index ea36bda88..d113bc6ca 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -254,11 +254,16 @@ int ar_main(int argc UNUSED_PARAM, char **argv)
254 254
255 archive_handle = init_handle(); 255 archive_handle = init_handle();
256 256
257 /* --: prepend '-' to the first argument if required */ 257 /* prepend '-' to the first argument if required */
258 /* -1: at least one param is reqd */ 258 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0')
259 /* one of p,t,x[,r] is required */ 259 argv[1] = xasprintf("-%s", argv[1]);
260 opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r"); 260 opt = getopt32(argv, "^"
261 opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r")); 261 "voc""ptx"IF_FEATURE_AR_CREATE("r")
262 "\0"
263 /* -1: at least one arg is reqd */
264 /* one of p,t,x[,r] is required */
265 "-1:p:t:x"IF_FEATURE_AR_CREATE(":r")
266 );
262 argv += optind; 267 argv += optind;
263 268
264 t = opt / FIRST_CMD; 269 t = opt / FIRST_CMD;
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index f91dd25eb..34a2e8e96 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -319,7 +319,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
319//config: select FEATURE_GZIP_DECOMPRESS 319//config: select FEATURE_GZIP_DECOMPRESS
320//config: help 320//config: help
321//config: gunzip is used to decompress archives created by gzip. 321//config: gunzip is used to decompress archives created by gzip.
322//config: You can use the `-t' option to test the integrity of 322//config: You can use the '-t' option to test the integrity of
323//config: an archive, without decompressing it. 323//config: an archive, without decompressing it.
324//config: 324//config:
325//config:config ZCAT 325//config:config ZCAT
@@ -391,9 +391,10 @@ int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
391int gunzip_main(int argc UNUSED_PARAM, char **argv) 391int gunzip_main(int argc UNUSED_PARAM, char **argv)
392{ 392{
393#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS 393#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS
394 applet_long_options = gunzip_longopts; 394 getopt32long(argv, "cfkvqdtn", gunzip_longopts);
395#endif 395#else
396 getopt32(argv, "cfkvqdtn"); 396 getopt32(argv, "cfkvqdtn");
397#endif
397 argv += optind; 398 argv += optind;
398 399
399 /* If called as zcat... 400 /* If called as zcat...
diff --git a/archival/bzip2.c b/archival/bzip2.c
index 0b9c508df..d578eb7ad 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -195,9 +195,11 @@ int bzip2_main(int argc UNUSED_PARAM, char **argv)
195 * --best alias for -9 195 * --best alias for -9
196 */ 196 */
197 197
198 opt_complementary = "s2"; /* -s means -2 (compatibility) */ 198 opt = getopt32(argv, "^"
199 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ 199 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
200 opt = getopt32(argv, "cfkv" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789qzs"); 200 "cfkv" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789qzs"
201 "\0" "s2" /* -s means -2 (compatibility) */
202 );
201#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */ 203#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */
202 if (opt & 0x30) // -d and/or -t 204 if (opt & 0x30) // -d and/or -t
203 return bunzip2_main(argc, argv); 205 return bunzip2_main(argc, argv);
diff --git a/archival/cpio.c b/archival/cpio.c
index 38bab8257..f2165be3a 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -360,9 +360,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
360 char *cpio_owner; 360 char *cpio_owner;
361 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) 361 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
362 unsigned opt; 362 unsigned opt;
363
364#if ENABLE_LONG_OPTS 363#if ENABLE_LONG_OPTS
365 applet_long_options = 364 const char *long_opts =
366 "extract\0" No_argument "i" 365 "extract\0" No_argument "i"
367 "list\0" No_argument "t" 366 "list\0" No_argument "t"
368#if ENABLE_FEATURE_CPIO_O 367#if ENABLE_FEATURE_CPIO_O
@@ -390,9 +389,9 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
390 /* -L makes sense only with -o or -p */ 389 /* -L makes sense only with -o or -p */
391 390
392#if !ENABLE_FEATURE_CPIO_O 391#if !ENABLE_FEATURE_CPIO_O
393 opt = getopt32(argv, OPTION_STR, &cpio_filename, &cpio_owner); 392 opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner);
394#else 393#else
395 opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), 394 opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts,
396 &cpio_filename, &cpio_owner, &cpio_fmt); 395 &cpio_filename, &cpio_owner, &cpio_fmt);
397#endif 396#endif
398 argv += optind; 397 argv += optind;
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 90ad8766c..852e0cac2 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1766,8 +1766,7 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv)
1766 1766
1767 INIT_G(); 1767 INIT_G();
1768 1768
1769 IF_LONG_OPTS(applet_long_options = dpkg_longopts); 1769 opt = getopt32long(argv, "CilPruF:", dpkg_longopts, &str_f);
1770 opt = getopt32(argv, "CilPruF:", &str_f);
1771 argv += optind; 1770 argv += optind;
1772 //if (opt & OPT_configure) ... // -C 1771 //if (opt & OPT_configure) ... // -C
1773 if (opt & OPT_force) { // -F (--force in official dpkg) 1772 if (opt & OPT_force) { // -F (--force in official dpkg)
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index 029bc4af1..f6bf9eb04 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -80,8 +80,9 @@ int dpkg_deb_main(int argc UNUSED_PARAM, char **argv)
80#endif 80#endif
81 81
82 /* Must have 1 or 2 args */ 82 /* Must have 1 or 2 args */
83 opt_complementary = "-1:?2:c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX"; 83 opt = getopt32(argv, "^" "cefXx"
84 opt = getopt32(argv, "cefXx"); 84 "\0" "-1:?2:c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX"
85 );
85 argv += optind; 86 argv += optind;
86 //argc -= optind; 87 //argc -= optind;
87 88
diff --git a/archival/gzip.c b/archival/gzip.c
index 4cf34ac28..9c53895e9 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -2216,11 +2216,12 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
2216 SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) 2216 SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2))
2217 + sizeof(struct globals)); 2217 + sizeof(struct globals));
2218 2218
2219#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
2220 applet_long_options = gzip_longopts;
2221#endif
2222 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ 2219 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
2220#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
2221 opt = getopt32long(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789", gzip_longopts);
2222#else
2223 opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789"); 2223 opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789");
2224#endif
2224#if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ 2225#if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */
2225 if (opt & 0x30) // -d and/or -t 2226 if (opt & 0x30) // -d and/or -t
2226 return gunzip_main(argc, argv); 2227 return gunzip_main(argc, argv);
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index 942e755b9..e1a8a7529 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -12,6 +12,8 @@ COMMON_FILES:= \
12 data_extract_all.o \ 12 data_extract_all.o \
13 data_extract_to_stdout.o \ 13 data_extract_to_stdout.o \
14\ 14\
15 unsafe_symlink_target.o \
16\
15 filter_accept_all.o \ 17 filter_accept_all.o \
16 filter_accept_list.o \ 18 filter_accept_list.o \
17 filter_accept_reject_list.o \ 19 filter_accept_reject_list.o \
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 1ce927c2f..e658444e0 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -129,9 +129,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
129 if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { 129 if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
130 /* shared message */ 130 /* shared message */
131 bb_perror_msg("can't create %slink '%s' to '%s'", 131 bb_perror_msg("can't create %slink '%s' to '%s'",
132 "hard", 132 "hard", dst_name, hard_link
133 dst_name,
134 hard_link
135 ); 133 );
136 } 134 }
137 /* Hardlinks have no separate mode/ownership, skip chown/chmod */ 135 /* Hardlinks have no separate mode/ownership, skip chown/chmod */
@@ -181,7 +179,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
181//TODO: what if file_header->link_target == NULL (say, corrupted tarball?) 179//TODO: what if file_header->link_target == NULL (say, corrupted tarball?)
182 180
183 /* To avoid a directory traversal attack via symlinks, 181 /* To avoid a directory traversal attack via symlinks,
184 * for certain link targets postpone creation of symlinks. 182 * do not restore symlinks with ".." components
183 * or symlinks starting with "/", unless a magic
184 * envvar is set.
185 * 185 *
186 * For example, consider a .tar created via: 186 * For example, consider a .tar created via:
187 * $ tar cvf bug.tar anything.txt 187 * $ tar cvf bug.tar anything.txt
@@ -199,24 +199,17 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
199 * 199 *
200 * Untarring bug.tar would otherwise place evil.py in '/tmp'. 200 * Untarring bug.tar would otherwise place evil.py in '/tmp'.
201 */ 201 */
202 if (file_header->link_target[0] == '/' 202 if (!unsafe_symlink_target(file_header->link_target)) {
203 || strstr(file_header->link_target, "..") 203 res = symlink(file_header->link_target, dst_name);
204 ) { 204 if (res != 0
205 llist_add_to(&archive_handle->symlink_placeholders, 205 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
206 xasprintf("%s%c%s", file_header->name, '\0', file_header->link_target) 206 ) {
207 ); 207 /* shared message */
208 break; 208 bb_perror_msg("can't create %slink '%s' to '%s'",
209 } 209 "sym",
210 res = symlink(file_header->link_target, dst_name); 210 dst_name, file_header->link_target
211 if (res != 0 211 );
212 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) 212 }
213 ) {
214 /* shared message */
215 bb_perror_msg("can't create %slink '%s' to '%s'",
216 "sym",
217 dst_name,
218 file_header->link_target
219 );
220 } 213 }
221 break; 214 break;
222 case S_IFSOCK: 215 case S_IFSOCK:
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 350e5358a..0be85500c 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -37,7 +37,6 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
37 || !defined(put_unaligned_be32) 37 || !defined(put_unaligned_be32)
38# error get_unaligned_le32 accessors are not defined 38# error get_unaligned_le32 accessors are not defined
39#endif 39#endif
40#define get_le32(p) (*(uint32_t*)(p))
41 40
42#include "unxz/xz_dec_bcj.c" 41#include "unxz/xz_dec_bcj.c"
43#include "unxz/xz_dec_lzma2.c" 42#include "unxz/xz_dec_lzma2.c"
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 641256787..7d912152c 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -251,18 +251,8 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp
251 return xstate; 251 return xstate;
252} 252}
253 253
254/* Used by e.g. rpm which gives us a fd without filename, 254static void fork_transformer_and_free(transformer_state_t *xstate)
255 * thus we can't guess the format from filename's extension.
256 */
257int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
258{ 255{
259 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
260
261 if (!xstate || !xstate->xformer) {
262 free(xstate);
263 return 1;
264 }
265
266# if BB_MMU 256# if BB_MMU
267 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); 257 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
268# else 258# else
@@ -270,13 +260,39 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
270 * an external unzipper that wants 260 * an external unzipper that wants
271 * file position at the start of the file. 261 * file position at the start of the file.
272 */ 262 */
273 xlseek(fd, - xstate->signature_skipped, SEEK_CUR); 263 xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR);
274 xstate->signature_skipped = 0; 264 xstate->signature_skipped = 0;
275 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); 265 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
276# endif 266# endif
277 free(xstate); 267 free(xstate);
268}
269
270/* Used by e.g. rpm which gives us a fd without filename,
271 * thus we can't guess the format from filename's extension.
272 */
273int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
274{
275 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
276
277 if (!xstate->xformer) {
278 free(xstate);
279 return 1;
280 }
281
282 fork_transformer_and_free(xstate);
278 return 0; 283 return 0;
279} 284}
285#if ENABLE_FEATURE_SEAMLESS_LZMA
286/* ...and custom version for LZMA */
287void FAST_FUNC setup_lzma_on_fd(int fd)
288{
289 transformer_state_t *xstate = xzalloc(sizeof(*xstate));
290 xstate->src_fd = fd;
291 xstate->xformer = unpack_lzma_stream;
292 USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
293 fork_transformer_and_free(xstate);
294}
295#endif
280 296
281static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) 297static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed)
282{ 298{
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c
new file mode 100644
index 000000000..441ba8b24
--- /dev/null
+++ b/archival/libarchive/unsafe_symlink_target.c
@@ -0,0 +1,48 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5#include "libbb.h"
6#include "bb_archive.h"
7
8int FAST_FUNC unsafe_symlink_target(const char *target)
9{
10 const char *dot;
11
12 if (target[0] == '/') {
13 const char *var;
14 unsafe:
15 var = getenv("EXTRACT_UNSAFE_SYMLINKS");
16 if (var) {
17 if (LONE_CHAR(var, '1'))
18 return 0; /* pretend it's safe */
19 return 1; /* "UNSAFE!" */
20 }
21 bb_error_msg("skipping unsafe symlink to '%s' in archive,"
22 " set %s=1 to extract",
23 target,
24 "EXTRACT_UNSAFE_SYMLINKS"
25 );
26 /* Prevent further messages */
27 setenv("EXTRACT_UNSAFE_SYMLINKS", "0", 0);
28 return 1; /* "UNSAFE!" */
29 }
30
31 dot = target;
32 for (;;) {
33 dot = strchr(dot, '.');
34 if (!dot)
35 return 0; /* safe target */
36
37 /* Is it a path component starting with ".."? */
38 if ((dot[1] == '.')
39 && (dot == target || dot[-1] == '/')
40 /* Is it exactly ".."? */
41 && (dot[2] == '/' || dot[2] == '\0')
42 ) {
43 goto unsafe;
44 }
45 /* NB: it can even be trailing ".", should only add 1 */
46 dot += 1;
47 }
48}
diff --git a/archival/lzop.c b/archival/lzop.c
index df18ff170..1bf954f4f 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -1138,7 +1138,7 @@ int lzop_main(int argc UNUSED_PARAM, char **argv)
1138 /* -U is "anti -k", invert bit for bbunpack(): */ 1138 /* -U is "anti -k", invert bit for bbunpack(): */
1139 option_mask32 ^= OPT_KEEP; 1139 option_mask32 ^= OPT_KEEP;
1140 /* -k disables -U (if any): */ 1140 /* -k disables -U (if any): */
1141 /* opt_complementary = "k-U"; - nope, only handles -Uk, not -kU */ 1141 /* opt_complementary "k-U"? - nope, only handles -Uk, not -kU */
1142 if (option_mask32 & OPT_k) 1142 if (option_mask32 & OPT_k)
1143 option_mask32 |= OPT_KEEP; 1143 option_mask32 |= OPT_KEEP;
1144 1144
diff --git a/archival/rpm.c b/archival/rpm.c
index 98039d499..790eeb59d 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -6,7 +6,6 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9
10//config:config RPM 9//config:config RPM
11//config: bool "rpm (33 kb)" 10//config: bool "rpm (33 kb)"
12//config: default y 11//config: default y
@@ -14,19 +13,8 @@
14//config: Mini RPM applet - queries and extracts RPM packages. 13//config: Mini RPM applet - queries and extracts RPM packages.
15 14
16//applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) 15//applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP))
17//kbuild:lib-$(CONFIG_RPM) += rpm.o
18 16
19//usage:#define rpm_trivial_usage 17//kbuild:lib-$(CONFIG_RPM) += rpm.o
20//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
21//usage:#define rpm_full_usage "\n\n"
22//usage: "Manipulate RPM packages\n"
23//usage: "\nCommands:"
24//usage: "\n -i Install package"
25//usage: "\n -qp Query package"
26//usage: "\n -qpi Show information"
27//usage: "\n -qpl List contents"
28//usage: "\n -qpd List documents"
29//usage: "\n -qpc List config files"
30 18
31#include "libbb.h" 19#include "libbb.h"
32#include "common_bufsiz.h" 20#include "common_bufsiz.h"
@@ -68,6 +56,8 @@
68#define TAG_DIRINDEXES 1116 56#define TAG_DIRINDEXES 1116
69#define TAG_BASENAMES 1117 57#define TAG_BASENAMES 1117
70#define TAG_DIRNAMES 1118 58#define TAG_DIRNAMES 1118
59#define TAG_PAYLOADCOMPRESSOR 1125
60
71 61
72#define RPMFILE_CONFIG (1 << 0) 62#define RPMFILE_CONFIG (1 << 0)
73#define RPMFILE_DOC (1 << 1) 63#define RPMFILE_DOC (1 << 1)
@@ -91,148 +81,145 @@ typedef struct {
91 81
92struct globals { 82struct globals {
93 void *map; 83 void *map;
94 rpm_index **mytags; 84 rpm_index *mytags;
95 int tagcount; 85 int tagcount;
86 unsigned mapsize, pagesize;
96} FIX_ALIASING; 87} FIX_ALIASING;
97#define G (*(struct globals*)bb_common_bufsiz1) 88#define G (*(struct globals*)bb_common_bufsiz1)
98#define INIT_G() do { setup_common_bufsiz(); } while (0) 89#define INIT_G() do { setup_common_bufsiz(); } while (0)
99 90
100static void extract_cpio(int fd, const char *source_rpm) 91static int rpm_gettags(const char *filename)
101{
102 archive_handle_t *archive_handle;
103
104 if (source_rpm != NULL) {
105 /* Binary rpm (it was built from some SRPM), install to root */
106 xchdir("/");
107 } /* else: SRPM, install to current dir */
108
109 /* Initialize */
110 archive_handle = init_handle();
111 archive_handle->seek = seek_by_read;
112 archive_handle->action_data = data_extract_all;
113#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
114 archive_handle->action_header = header_list;
115 archive_handle->action_data = data_skip;
116#endif
117 archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
118 /* compat: overwrite existing files.
119 * try "rpm -i foo.src.rpm" few times in a row -
120 * standard rpm will not complain.
121 */
122 | ARCHIVE_REPLACE_VIA_RENAME;
123 archive_handle->src_fd = fd;
124 /*archive_handle->offset = 0; - init_handle() did it */
125
126 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1);
127 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
128 continue;
129}
130
131static rpm_index **rpm_gettags(int fd, int *num_tags)
132{ 92{
133 /* We should never need more than 200 (shrink via realloc later) */ 93 rpm_index *tags;
134 rpm_index **tags = xzalloc(200 * sizeof(tags[0])); 94 int fd;
135 int pass, tagindex = 0; 95 unsigned pass, idx;
136 96 unsigned storepos;
137 xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ 97
98 if (!filename) { /* rpm2cpio w/o filename? */
99 filename = bb_msg_standard_output;
100 fd = 0;
101 } else {
102 fd = xopen(filename, O_RDONLY);
103 }
138 104
105 storepos = xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
106 G.tagcount = 0;
107 tags = NULL;
108 idx = 0;
139 /* 1st pass is the signature headers, 2nd is the main stuff */ 109 /* 1st pass is the signature headers, 2nd is the main stuff */
140 for (pass = 0; pass < 2; pass++) { 110 for (pass = 0; pass < 2; pass++) {
141 struct rpm_header header; 111 struct rpm_header header;
142 rpm_index *tmpindex; 112 unsigned cnt;
143 int storepos;
144 113
145 xread(fd, &header, sizeof(header)); 114 xread(fd, &header, sizeof(header));
146 if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) 115 if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
147 return NULL; /* Invalid magic, or not version 1 */ 116 bb_error_msg_and_die("invalid RPM header magic in '%s'", filename);
148 header.size = ntohl(header.size); 117 header.size = ntohl(header.size);
149 header.entries = ntohl(header.entries); 118 cnt = ntohl(header.entries);
150 storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16; 119 storepos += sizeof(header) + cnt * 16;
151 120
152 while (header.entries--) { 121 G.tagcount += cnt;
153 tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); 122 tags = xrealloc(tags, sizeof(tags[0]) * G.tagcount);
154 xread(fd, tmpindex, sizeof(*tmpindex)); 123 xread(fd, &tags[idx], sizeof(tags[0]) * cnt);
155 tmpindex->tag = ntohl(tmpindex->tag); 124 while (cnt--) {
156 tmpindex->type = ntohl(tmpindex->type); 125 rpm_index *tag = &tags[idx];
157 tmpindex->count = ntohl(tmpindex->count); 126 tag->tag = ntohl(tag->tag);
158 tmpindex->offset = storepos + ntohl(tmpindex->offset); 127 tag->type = ntohl(tag->type);
128 tag->count = ntohl(tag->count);
129 tag->offset = storepos + ntohl(tag->offset);
159 if (pass == 0) 130 if (pass == 0)
160 tmpindex->tag -= 743; 131 tag->tag -= 743;
132 idx++;
161 } 133 }
162 storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
163 /* Skip padding to 8 byte boundary after reading signature headers */ 134 /* Skip padding to 8 byte boundary after reading signature headers */
164 if (pass == 0) 135 if (pass == 0)
165 xlseek(fd, (-storepos) & 0x7, SEEK_CUR); 136 while (header.size & 7)
137 header.size++;
138 /* Seek past store */
139 storepos = xlseek(fd, header.size, SEEK_CUR);
166 } 140 }
167 /* realloc tags to save space */ 141 G.mytags = tags;
168 tags = xrealloc(tags, tagindex * sizeof(tags[0])); 142
169 *num_tags = tagindex; 143 /* Map the store */
170 /* All done, leave the file at the start of the gzipped cpio archive */ 144 storepos = (storepos + G.pagesize) & -(int)G.pagesize;
171 return tags; 145 /* remember size for munmap */
146 G.mapsize = storepos;
147 /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */
148 G.map = mmap(0, storepos, PROT_READ, MAP_PRIVATE, fd, 0);
149 if (G.map == MAP_FAILED)
150 bb_perror_msg_and_die("mmap '%s'", filename);
151
152 return fd;
172} 153}
173 154
174static int bsearch_rpmtag(const void *key, const void *item) 155static int bsearch_rpmtag(const void *key, const void *item)
175{ 156{
176 int *tag = (int *)key; 157 int *tag = (int *)key;
177 rpm_index **tmp = (rpm_index **) item; 158 rpm_index *tmp = (rpm_index *) item;
178 return (*tag - tmp[0]->tag); 159 return (*tag - tmp->tag);
179}
180
181static int rpm_getcount(int tag)
182{
183 rpm_index **found;
184 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
185 if (!found)
186 return 0;
187 return found[0]->count;
188} 160}
189 161
190static char *rpm_getstr(int tag, int itemindex) 162static char *rpm_getstr(int tag, int itemindex)
191{ 163{
192 rpm_index **found; 164 rpm_index *found;
193 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); 165 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag);
194 if (!found || itemindex >= found[0]->count) 166 if (!found || itemindex >= found->count)
195 return NULL; 167 return NULL;
196 if (found[0]->type == RPM_STRING_TYPE 168 if (found->type == RPM_STRING_TYPE
197 || found[0]->type == RPM_I18NSTRING_TYPE 169 || found->type == RPM_I18NSTRING_TYPE
198 || found[0]->type == RPM_STRING_ARRAY_TYPE 170 || found->type == RPM_STRING_ARRAY_TYPE
199 ) { 171 ) {
200 int n; 172 int n;
201 char *tmpstr = (char *) G.map + found[0]->offset; 173 char *tmpstr = (char *) G.map + found->offset;
202 for (n = 0; n < itemindex; n++) 174 for (n = 0; n < itemindex; n++)
203 tmpstr = tmpstr + strlen(tmpstr) + 1; 175 tmpstr = tmpstr + strlen(tmpstr) + 1;
204 return tmpstr; 176 return tmpstr;
205 } 177 }
206 return NULL; 178 return NULL;
207} 179}
180static char *rpm_getstr0(int tag)
181{
182 return rpm_getstr(tag, 0);
183}
184
185#if ENABLE_RPM
208 186
209static int rpm_getint(int tag, int itemindex) 187static int rpm_getint(int tag, int itemindex)
210{ 188{
211 rpm_index **found; 189 rpm_index *found;
212 char *tmpint; 190 char *tmpint;
213 191
214 /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... 192 /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
215 * it's ok to ignore it because tag won't be used as a pointer */ 193 * it's ok to ignore it because tag won't be used as a pointer */
216 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); 194 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag);
217 if (!found || itemindex >= found[0]->count) 195 if (!found || itemindex >= found->count)
218 return -1; 196 return -1;
219 197
220 tmpint = (char *) G.map + found[0]->offset; 198 tmpint = (char *) G.map + found->offset;
221 if (found[0]->type == RPM_INT32_TYPE) { 199 if (found->type == RPM_INT32_TYPE) {
222 tmpint += itemindex*4; 200 tmpint += itemindex*4;
223 return ntohl(*(int32_t*)tmpint); 201 return ntohl(*(int32_t*)tmpint);
224 } 202 }
225 if (found[0]->type == RPM_INT16_TYPE) { 203 if (found->type == RPM_INT16_TYPE) {
226 tmpint += itemindex*2; 204 tmpint += itemindex*2;
227 return ntohs(*(int16_t*)tmpint); 205 return ntohs(*(int16_t*)tmpint);
228 } 206 }
229 if (found[0]->type == RPM_INT8_TYPE) { 207 if (found->type == RPM_INT8_TYPE) {
230 tmpint += itemindex; 208 tmpint += itemindex;
231 return *(int8_t*)tmpint; 209 return *(int8_t*)tmpint;
232 } 210 }
233 return -1; 211 return -1;
234} 212}
235 213
214static int rpm_getcount(int tag)
215{
216 rpm_index *found;
217 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag);
218 if (!found)
219 return 0;
220 return found->count;
221}
222
236static void fileaction_dobackup(char *filename, int fileref) 223static void fileaction_dobackup(char *filename, int fileref)
237{ 224{
238 struct stat oldfile; 225 struct stat oldfile;
@@ -273,11 +260,103 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i
273 } 260 }
274} 261}
275 262
263#if 0 //DEBUG
264static void print_all_tags(void)
265{
266 unsigned i = 0;
267 while (i < G.tagcount) {
268 rpm_index *tag = &G.mytags[i];
269 if (tag->type == RPM_STRING_TYPE
270 || tag->type == RPM_I18NSTRING_TYPE
271 || tag->type == RPM_STRING_ARRAY_TYPE
272 ) {
273 unsigned n;
274 char *str = (char *) G.map + tag->offset;
275
276 printf("tag[%u] %08x type %08x offset %08x count %d '%s'\n",
277 i, tag->tag, tag->type, tag->offset, tag->count, str
278 );
279 for (n = 1; n < tag->count; n++) {
280 str += strlen(str) + 1;
281 printf("\t'%s'\n", str);
282 }
283 }
284 i++;
285 }
286}
287#else
288#define print_all_tags() ((void)0)
289#endif
290
291static void extract_cpio(int fd, const char *source_rpm)
292{
293 archive_handle_t *archive_handle;
294
295 if (source_rpm != NULL) {
296 /* Binary rpm (it was built from some SRPM), install to root */
297 xchdir("/");
298 } /* else: SRPM, install to current dir */
299
300 /* Initialize */
301 archive_handle = init_handle();
302 archive_handle->seek = seek_by_read;
303 archive_handle->action_data = data_extract_all;
304#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
305 archive_handle->action_header = header_list;
306 archive_handle->action_data = data_skip;
307#endif
308 archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
309 /* compat: overwrite existing files.
310 * try "rpm -i foo.src.rpm" few times in a row -
311 * standard rpm will not complain.
312 */
313 | ARCHIVE_REPLACE_VIA_RENAME;
314 archive_handle->src_fd = fd;
315 /*archive_handle->offset = 0; - init_handle() did it */
316
317 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1);
318 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
319 continue;
320}
321
322//usage:#define rpm_trivial_usage
323//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
324//usage:#define rpm_full_usage "\n\n"
325//usage: "Manipulate RPM packages\n"
326//usage: "\nCommands:"
327//usage: "\n -i Install package"
328//usage: "\n -qp Query package"
329//usage: "\n -qpi Show information"
330//usage: "\n -qpl List contents"
331//usage: "\n -qpd List documents"
332//usage: "\n -qpc List config files"
333
334/* RPM version 4.13.0.1:
335 * Unlike -q, -i seems to imply -p: -i, -ip and -pi work the same.
336 * OTOH, with -q order is important: "-piq FILE.rpm" works as -qp, not -qpi
337 * (IOW: shows only package name, not package info).
338 * "-iq ARG" works as -q: treats ARG as package name, not a file.
339 *
340 * "man rpm" on -l option and options implying it:
341 * -l, --list List files in package.
342 * -c, --configfiles List only configuration files (implies -l).
343 * -d, --docfiles List only documentation files (implies -l).
344 * -L, --licensefiles List only license files (implies -l).
345 * --dump Dump file information as follows (implies -l):
346 * path size mtime digest mode owner group isconfig isdoc rdev symlink
347 * -s, --state Display the states of files in the package (implies -l).
348 * The state of each file is one of normal, not installed, or replaced.
349 *
350 * Looks like we can switch to getopt32 here: in practice, people
351 * do place -q first if they intend to use it (misinterpreting "-piq" wouldn't matter).
352 */
276int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 353int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
277int rpm_main(int argc, char **argv) 354int rpm_main(int argc, char **argv)
278{ 355{
279 int opt, func = 0; 356 int opt, func = 0;
280 const unsigned pagesize = getpagesize(); 357
358 INIT_G();
359 G.pagesize = getpagesize();
281 360
282 while ((opt = getopt(argc, argv, "iqpldc")) != -1) { 361 while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
283 switch (opt) { 362 switch (opt) {
@@ -289,17 +368,17 @@ int rpm_main(int argc, char **argv)
289 if (func) bb_show_usage(); 368 if (func) bb_show_usage();
290 func = rpm_query; 369 func = rpm_query;
291 break; 370 break;
292 case 'p': /* Query a package */ 371 case 'p': /* Query a package (IOW: .rpm file, we are not querying RPMDB) */
293 func |= rpm_query_package; 372 func |= rpm_query_package;
294 break; 373 break;
295 case 'l': /* List files in a package */ 374 case 'l': /* List files in a package */
296 func |= rpm_query_list; 375 func |= rpm_query_list;
297 break; 376 break;
298 case 'd': /* List doc files in a package (implies list) */ 377 case 'd': /* List doc files in a package (implies -l) */
299 func |= rpm_query_list; 378 func |= rpm_query_list;
300 func |= rpm_query_list_doc; 379 func |= rpm_query_list_doc;
301 break; 380 break;
302 case 'c': /* List config files in a package (implies list) */ 381 case 'c': /* List config files in a package (implies -l) */
303 func |= rpm_query_list; 382 func |= rpm_query_list;
304 func |= rpm_query_list_config; 383 func |= rpm_query_list_config;
305 break; 384 break;
@@ -313,24 +392,18 @@ int rpm_main(int argc, char **argv)
313 bb_show_usage(); 392 bb_show_usage();
314 } 393 }
315 394
316 while (*argv) { 395 for (;;) {
317 int rpm_fd; 396 int rpm_fd;
318 unsigned mapsize;
319 const char *source_rpm; 397 const char *source_rpm;
320 398
321 rpm_fd = xopen(*argv++, O_RDONLY); 399 rpm_fd = rpm_gettags(*argv);
322 G.mytags = rpm_gettags(rpm_fd, &G.tagcount); 400 print_all_tags();
323 if (!G.mytags)
324 bb_error_msg_and_die("error reading rpm header");
325 mapsize = xlseek(rpm_fd, 0, SEEK_CUR);
326 mapsize = (mapsize + pagesize) & -(int)pagesize;
327 /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */
328 G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
329//FIXME: error check?
330 401
331 source_rpm = rpm_getstr(TAG_SOURCERPM, 0); 402 source_rpm = rpm_getstr0(TAG_SOURCERPM);
332 403
333 if (func & rpm_install) { 404 if (func & rpm_install) {
405 /* -i (and not -qi) */
406
334 /* Backup any config files */ 407 /* Backup any config files */
335 loop_through_files(TAG_BASENAMES, fileaction_dobackup); 408 loop_through_files(TAG_BASENAMES, fileaction_dobackup);
336 /* Extact the archive */ 409 /* Extact the archive */
@@ -338,10 +411,13 @@ int rpm_main(int argc, char **argv)
338 /* Set the correct file uid/gid's */ 411 /* Set the correct file uid/gid's */
339 loop_through_files(TAG_BASENAMES, fileaction_setowngrp); 412 loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
340 } 413 }
341 else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { 414 else
415 if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
416 /* -qp */
417
342 if (!(func & (rpm_query_info|rpm_query_list))) { 418 if (!(func & (rpm_query_info|rpm_query_list))) {
343 /* If just a straight query, just give package name */ 419 /* If just a straight query, just give package name */
344 printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); 420 printf("%s-%s-%s\n", rpm_getstr0(TAG_NAME), rpm_getstr0(TAG_VERSION), rpm_getstr0(TAG_RELEASE));
345 } 421 }
346 if (func & rpm_query_info) { 422 if (func & rpm_query_info) {
347 /* Do the nice printout */ 423 /* Do the nice printout */
@@ -350,30 +426,33 @@ int rpm_main(int argc, char **argv)
350 char bdatestring[50]; 426 char bdatestring[50];
351 const char *p; 427 const char *p;
352 428
353 printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); 429 printf("%-12s: %s\n", "Name" , rpm_getstr0(TAG_NAME));
354 /* TODO compat: add "Epoch" here */ 430 /* TODO compat: add "Epoch" here */
355 printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); 431 printf("%-12s: %s\n", "Version" , rpm_getstr0(TAG_VERSION));
356 printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); 432 printf("%-12s: %s\n", "Release" , rpm_getstr0(TAG_RELEASE));
357 /* add "Architecture" */ 433 /* add "Architecture" */
358 printf("%-12s: %s\n", "Install Date", "(not installed)"); 434 /* printf("%-12s: %s\n", "Install Date", "(not installed)"); - we don't know */
359 printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); 435 printf("%-12s: %s\n", "Group" , rpm_getstr0(TAG_GROUP));
360 printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); 436 printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0));
361 printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); 437 printf("%-12s: %s\n", "License" , rpm_getstr0(TAG_LICENSE));
362 /* add "Signature" */ 438 /* add "Signature" */
363 printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); 439 printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)");
364 bdate_time = rpm_getint(TAG_BUILDTIME, 0); 440 bdate_time = rpm_getint(TAG_BUILDTIME, 0);
365 bdate_ptm = localtime(&bdate_time); 441 bdate_ptm = localtime(&bdate_time);
366 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); 442 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
367 printf("%-12s: %s\n", "Build Date" , bdatestring); 443 printf("%-12s: %s\n", "Build Date" , bdatestring);
368 printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); 444 printf("%-12s: %s\n", "Build Host" , rpm_getstr0(TAG_BUILDHOST));
369 p = rpm_getstr(TAG_PREFIXS, 0); 445 p = rpm_getstr0(TAG_PREFIXS);
370 printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); 446 printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)");
371 /* add "Packager" */ 447 /* add "Packager" */
372 p = rpm_getstr(TAG_VENDOR, 0); 448 p = rpm_getstr0(TAG_VENDOR);
373 printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); 449 if (p) /* rpm 4.13.0.1 does not show "(none)" for Vendor: */
374 printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); 450 printf("%-12s: %s\n", "Vendor" , p);
375 printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); 451 p = rpm_getstr0(TAG_URL);
376 printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); 452 if (p) /* rpm 4.13.0.1 does not show "(none)"/"(null)" for URL: */
453 printf("%-12s: %s\n", "URL" , p);
454 printf("%-12s: %s\n", "Summary" , rpm_getstr0(TAG_SUMMARY));
455 printf("Description :\n%s\n", rpm_getstr0(TAG_DESCRIPTION));
377 } 456 }
378 if (func & rpm_query_list) { 457 if (func & rpm_query_list) {
379 int count, it, flags; 458 int count, it, flags;
@@ -396,10 +475,85 @@ int rpm_main(int argc, char **argv)
396 rpm_getstr(TAG_BASENAMES, it)); 475 rpm_getstr(TAG_BASENAMES, it));
397 } 476 }
398 } 477 }
478 } else {
479 /* Unsupported (help text shows what we support) */
480 bb_show_usage();
399 } 481 }
400 munmap(G.map, mapsize); 482 if (!*++argv)
483 break;
484 munmap(G.map, G.mapsize);
401 free(G.mytags); 485 free(G.mytags);
402 close(rpm_fd); 486 close(rpm_fd);
403 } 487 }
488
404 return 0; 489 return 0;
405} 490}
491
492#endif /* RPM */
493
494/*
495 * Mini rpm2cpio implementation for busybox
496 *
497 * Copyright (C) 2001 by Laurence Anderson
498 *
499 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
500 */
501//config:config RPM2CPIO
502//config: bool "rpm2cpio (20 kb)"
503//config: default y
504//config: help
505//config: Converts a RPM file into a CPIO archive.
506
507//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP))
508
509//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm.o
510
511//usage:#define rpm2cpio_trivial_usage
512//usage: "PACKAGE.rpm"
513//usage:#define rpm2cpio_full_usage "\n\n"
514//usage: "Output a cpio archive of the rpm file"
515
516#if ENABLE_RPM2CPIO
517
518/* No getopt required */
519int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
520int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
521{
522 const char *str;
523 int rpm_fd;
524
525 INIT_G();
526 G.pagesize = getpagesize();
527
528 rpm_fd = rpm_gettags(argv[1]);
529
530 //if (SEAMLESS_COMPRESSION) - we do this at the end instead.
531 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
532 // signal(SIGCHLD, check_errors_in_children);
533
534 if (ENABLE_FEATURE_SEAMLESS_LZMA
535 && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL
536 && strcmp(str, "lzma") == 0
537 ) {
538 // lzma compression can't be detected
539 // set up decompressor without detection
540 setup_lzma_on_fd(rpm_fd);
541 } else {
542 setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1);
543 }
544
545 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
546 bb_error_msg_and_die("error unpacking");
547
548 if (ENABLE_FEATURE_CLEAN_UP) {
549 close(rpm_fd);
550 }
551
552 if (SEAMLESS_COMPRESSION) {
553 check_errors_in_children(0);
554 return bb_got_signal;
555 }
556 return EXIT_SUCCESS;
557}
558
559#endif /* RPM2CPIO */
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
deleted file mode 100644
index 3e4a6a249..000000000
--- a/archival/rpm2cpio.c
+++ /dev/null
@@ -1,96 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rpm2cpio implementation for busybox
4 *
5 * Copyright (C) 2001 by Laurence Anderson
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10//config:config RPM2CPIO
11//config: bool "rpm2cpio (20 kb)"
12//config: default y
13//config: help
14//config: Converts a RPM file into a CPIO archive.
15
16//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP))
17//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
18
19//usage:#define rpm2cpio_trivial_usage
20//usage: "package.rpm"
21//usage:#define rpm2cpio_full_usage "\n\n"
22//usage: "Output a cpio archive of the rpm file"
23
24#include "libbb.h"
25#include "bb_archive.h"
26#include "rpm.h"
27
28enum { rpm_fd = STDIN_FILENO };
29
30static unsigned skip_header(void)
31{
32 struct rpm_header header;
33 unsigned len;
34
35 xread(rpm_fd, &header, sizeof(header));
36// if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) {
37// bb_error_msg_and_die("invalid RPM header magic");
38// }
39// if (header.version != 1) {
40// bb_error_msg_and_die("unsupported RPM header version");
41// }
42 if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) {
43 bb_error_msg_and_die("invalid RPM header magic or unsupported version");
44 // ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER));
45 }
46
47 /* Seek past index entries, and past store */
48 len = 16 * ntohl(header.entries) + ntohl(header.size);
49 seek_by_jump(rpm_fd, len);
50
51 return sizeof(header) + len;
52}
53
54/* No getopt required */
55int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
56int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
57{
58 struct rpm_lead lead;
59 unsigned pos;
60
61 if (argv[1]) {
62 xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd);
63 }
64 xread(rpm_fd, &lead, sizeof(lead));
65
66 /* Just check the magic, the rest is irrelevant */
67 if (lead.magic != htonl(RPM_LEAD_MAGIC)) {
68 bb_error_msg_and_die("invalid RPM magic");
69 }
70
71 /* Skip the signature header, align to 8 bytes */
72 pos = skip_header();
73 seek_by_jump(rpm_fd, (-(int)pos) & 7);
74
75 /* Skip the main header */
76 skip_header();
77
78 //if (SEAMLESS_COMPRESSION)
79 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
80 // signal(SIGCHLD, check_errors_in_children);
81
82 /* This works, but doesn't report uncompress errors (they happen in child) */
83 setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1);
84 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
85 bb_error_msg_and_die("error unpacking");
86
87 if (ENABLE_FEATURE_CLEAN_UP) {
88 close(rpm_fd);
89 }
90
91 if (SEAMLESS_COMPRESSION) {
92 check_errors_in_children(0);
93 return bb_got_signal;
94 }
95 return EXIT_SUCCESS;
96}
diff --git a/archival/tar.c b/archival/tar.c
index d90a5dc4f..503444796 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -278,23 +278,6 @@ static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
278 xwrite(fd, hp, sizeof(*hp)); 278 xwrite(fd, hp, sizeof(*hp));
279} 279}
280 280
281static void replace_symlink_placeholders(llist_t *list)
282{
283 while (list) {
284 char *target;
285
286 target = list->data + strlen(list->data) + 1;
287 if (symlink(target, list->data)) {
288 /* shared message */
289 bb_error_msg_and_die("can't create %slink '%s' to '%s'",
290 "sym",
291 list->data, target
292 );
293 }
294 list = list->link;
295 }
296}
297
298#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 281#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
299static void writeLongname(int fd, int type, const char *name, int dir) 282static void writeLongname(int fd, int type, const char *name, int dir)
300{ 283{
@@ -969,6 +952,11 @@ static const char tar_longopts[] ALIGN1 =
969 "exclude\0" Required_argument "\xff" 952 "exclude\0" Required_argument "\xff"
970# endif 953# endif
971 ; 954 ;
955# define GETOPT32 getopt32long
956# define LONGOPTS ,tar_longopts
957#else
958# define GETOPT32 getopt32
959# define LONGOPTS
972#endif 960#endif
973 961
974int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 962int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -995,21 +983,8 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
995 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; 983 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
996 984
997 /* Prepend '-' to the first argument if required */ 985 /* Prepend '-' to the first argument if required */
998 opt_complementary = "--:" // first arg is options 986 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0')
999 "tt:vv:" // count -t,-v 987 argv[1] = xasprintf("-%s", argv[1]);
1000#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1001 "\xff::" // --exclude=PATTERN is a list
1002#endif
1003 IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
1004 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
1005 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive
1006#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1007 ":\xf9+" // --strip-components=NUM
1008#endif
1009 ;
1010#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1011 applet_long_options = tar_longopts;
1012#endif
1013#if ENABLE_DESKTOP 988#if ENABLE_DESKTOP
1014 /* Lie to buildroot when it starts asking stupid questions. */ 989 /* Lie to buildroot when it starts asking stupid questions. */
1015 if (argv[1] && strcmp(argv[1], "--version") == 0) { 990 if (argv[1] && strcmp(argv[1], "--version") == 0) {
@@ -1046,7 +1021,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1046 } 1021 }
1047 } 1022 }
1048#endif 1023#endif
1049 opt = getopt32(argv, 1024 opt = GETOPT32(argv, "^"
1050 "txC:f:Oopvk" 1025 "txC:f:Oopvk"
1051 IF_FEATURE_TAR_CREATE( "ch" ) 1026 IF_FEATURE_TAR_CREATE( "ch" )
1052 IF_FEATURE_SEAMLESS_BZ2( "j" ) 1027 IF_FEATURE_SEAMLESS_BZ2( "j" )
@@ -1057,6 +1032,18 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1057 IF_FEATURE_SEAMLESS_Z( "Z" ) 1032 IF_FEATURE_SEAMLESS_Z( "Z" )
1058 IF_FEATURE_TAR_NOPRESERVE_TIME("m") 1033 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
1059 IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components 1034 IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components
1035 "\0"
1036 "tt:vv:" // count -t,-v
1037#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1038 "\xff::" // --exclude=PATTERN is a list
1039#endif
1040 IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
1041 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
1042 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive
1043#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1044 ":\xf9+" // --strip-components=NUM
1045#endif
1046 LONGOPTS
1060 , &base_dir // -C dir 1047 , &base_dir // -C dir
1061 , &tar_filename // -f filename 1048 , &tar_filename // -f filename
1062 IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T 1049 IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
@@ -1280,8 +1267,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1280 while (get_header_tar(tar_handle) == EXIT_SUCCESS) 1267 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1281 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ 1268 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */
1282 1269
1283 replace_symlink_placeholders(tar_handle->symlink_placeholders);
1284
1285 /* Check that every file that should have been extracted was */ 1270 /* Check that every file that should have been extracted was */
1286 while (tar_handle->accept) { 1271 while (tar_handle->accept) {
1287 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) 1272 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
diff --git a/archival/unzip.c b/archival/unzip.c
index f37ea3519..233487697 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -371,9 +371,15 @@ static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn)
371 target[xstate.mem_output_size] = '\0'; 371 target[xstate.mem_output_size] = '\0';
372#endif 372#endif
373 } 373 }
374 if (!unsafe_symlink_target(target)) {
374//TODO: libbb candidate 375//TODO: libbb candidate
375 if (symlink(target, dst_fn)) 376 if (symlink(target, dst_fn)) {
376 bb_perror_msg_and_die("can't create symlink '%s'", dst_fn); 377 /* shared message */
378 bb_perror_msg_and_die("can't create %slink '%s' to '%s'",
379 "sym", dst_fn, target
380 );
381 }
382 }
377 free(target); 383 free(target);
378} 384}
379#endif 385#endif