diff options
Diffstat (limited to 'archival')
-rw-r--r-- | archival/ar.c | 15 | ||||
-rw-r--r-- | archival/bbunzip.c | 7 | ||||
-rw-r--r-- | archival/bzip2.c | 8 | ||||
-rw-r--r-- | archival/cpio.c | 7 | ||||
-rw-r--r-- | archival/dpkg.c | 3 | ||||
-rw-r--r-- | archival/dpkg_deb.c | 5 | ||||
-rw-r--r-- | archival/gzip.c | 7 | ||||
-rw-r--r-- | archival/libarchive/Kbuild.src | 2 | ||||
-rw-r--r-- | archival/libarchive/data_extract_all.c | 37 | ||||
-rw-r--r-- | archival/libarchive/decompress_unxz.c | 1 | ||||
-rw-r--r-- | archival/libarchive/open_transformer.c | 40 | ||||
-rw-r--r-- | archival/libarchive/unsafe_symlink_target.c | 48 | ||||
-rw-r--r-- | archival/lzop.c | 2 | ||||
-rw-r--r-- | archival/rpm.c | 412 | ||||
-rw-r--r-- | archival/rpm2cpio.c | 96 | ||||
-rw-r--r-- | archival/tar.c | 55 | ||||
-rw-r--r-- | archival/unzip.c | 10 |
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; | |||
391 | int gunzip_main(int argc UNUSED_PARAM, char **argv) | 391 | int 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, | 254 | static void fork_transformer_and_free(transformer_state_t *xstate) |
255 | * thus we can't guess the format from filename's extension. | ||
256 | */ | ||
257 | int 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 | */ | ||
273 | int 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 */ | ||
287 | void 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 | ||
281 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) | 297 | static 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 | |||
8 | int 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 | ||
92 | struct globals { | 82 | struct 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 | ||
100 | static void extract_cpio(int fd, const char *source_rpm) | 91 | static 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 | |||
131 | static 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 | ||
174 | static int bsearch_rpmtag(const void *key, const void *item) | 155 | static 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 | |||
181 | static 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 | ||
190 | static char *rpm_getstr(int tag, int itemindex) | 162 | static 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 | } |
180 | static char *rpm_getstr0(int tag) | ||
181 | { | ||
182 | return rpm_getstr(tag, 0); | ||
183 | } | ||
184 | |||
185 | #if ENABLE_RPM | ||
208 | 186 | ||
209 | static int rpm_getint(int tag, int itemindex) | 187 | static 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 | ||
214 | static 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 | |||
236 | static void fileaction_dobackup(char *filename, int fileref) | 223 | static 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 | ||
264 | static 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 | |||
291 | static 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 | */ | ||
276 | int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 353 | int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
277 | int rpm_main(int argc, char **argv) | 354 | int 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 */ | ||
519 | int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
520 | int 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 | |||
28 | enum { rpm_fd = STDIN_FILENO }; | ||
29 | |||
30 | static 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 */ | ||
55 | int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
56 | int 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 | ||
281 | static 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 |
299 | static void writeLongname(int fd, int type, const char *name, int dir) | 282 | static 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 | ||
974 | int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 962 | int 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 |