diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | applets/applets.c | 7 | ||||
| -rw-r--r-- | archival/bbunzip.c | 2 | ||||
| -rw-r--r-- | archival/libunarchive/Kbuild | 60 | ||||
| -rw-r--r-- | archival/libunarchive/get_header_tar_bz2.c | 2 | ||||
| -rw-r--r-- | archival/libunarchive/get_header_tar_gz.c | 9 | ||||
| -rw-r--r-- | archival/libunarchive/get_header_tar_lzma.c | 2 | ||||
| -rw-r--r-- | archival/libunarchive/open_transformer.c | 31 | ||||
| -rw-r--r-- | archival/rpm.c | 26 | ||||
| -rw-r--r-- | archival/tar.c | 2 | ||||
| -rw-r--r-- | include/libbb.h | 9 | ||||
| -rw-r--r-- | include/unarchive.h | 6 | ||||
| -rw-r--r-- | libbb/copy_file.c | 191 | ||||
| -rw-r--r-- | libbb/xreadlink.c | 22 | ||||
| -rw-r--r-- | networking/isrv.c | 18 | ||||
| -rw-r--r-- | runit/runsv.c | 36 | ||||
| -rwxr-xr-x | scripts/trylink | 58 |
17 files changed, 283 insertions, 200 deletions
| @@ -1,7 +1,7 @@ | |||
| 1 | VERSION = 1 | 1 | VERSION = 1 |
| 2 | PATCHLEVEL = 7 | 2 | PATCHLEVEL = 7 |
| 3 | SUBLEVEL = 1 | 3 | SUBLEVEL = 1 |
| 4 | EXTRAVERSION = .svn | 4 | EXTRAVERSION = |
| 5 | NAME = Unnamed | 5 | NAME = Unnamed |
| 6 | 6 | ||
| 7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
diff --git a/applets/applets.c b/applets/applets.c index 6de6db3cd..b40f01836 100644 --- a/applets/applets.c +++ b/applets/applets.c | |||
| @@ -546,7 +546,7 @@ static int busybox_main(char **argv) | |||
| 546 | help: | 546 | help: |
| 547 | output_width = 80; | 547 | output_width = 80; |
| 548 | if (ENABLE_FEATURE_AUTOWIDTH) { | 548 | if (ENABLE_FEATURE_AUTOWIDTH) { |
| 549 | /* Obtain the terminal width. */ | 549 | /* Obtain the terminal width */ |
| 550 | get_terminal_width_height(0, &output_width, NULL); | 550 | get_terminal_width_height(0, &output_width, NULL); |
| 551 | } | 551 | } |
| 552 | /* leading tab and room to wrap */ | 552 | /* leading tab and room to wrap */ |
| @@ -580,12 +580,11 @@ static int busybox_main(char **argv) | |||
| 580 | 580 | ||
| 581 | if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { | 581 | if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { |
| 582 | const char *busybox; | 582 | const char *busybox; |
| 583 | busybox = xmalloc_readlink_or_warn(bb_busybox_exec_path); | 583 | busybox = xmalloc_readlink(bb_busybox_exec_path); |
| 584 | if (!busybox) | 584 | if (!busybox) |
| 585 | busybox = bb_busybox_exec_path; | 585 | busybox = bb_busybox_exec_path; |
| 586 | /* -s makes symlinks */ | 586 | /* -s makes symlinks */ |
| 587 | install_links(busybox, | 587 | install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0); |
| 588 | argv[2] && strcmp(argv[2], "-s") == 0); | ||
| 589 | return 0; | 588 | return 0; |
| 590 | } | 589 | } |
| 591 | 590 | ||
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 56c742a49..a4e525f2e 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
| @@ -298,7 +298,7 @@ USE_DESKTOP(long long) int unpack_unlzma(void) | |||
| 298 | int unlzma_main(int argc, char **argv); | 298 | int unlzma_main(int argc, char **argv); |
| 299 | int unlzma_main(int argc, char **argv) | 299 | int unlzma_main(int argc, char **argv) |
| 300 | { | 300 | { |
| 301 | getopt32(argv, "c"); | 301 | getopt32(argv, "cf"); |
| 302 | argv += optind; | 302 | argv += optind; |
| 303 | /* lzmacat? */ | 303 | /* lzmacat? */ |
| 304 | if (applet_name[4] == 'c') | 304 | if (applet_name[4] == 'c') |
diff --git a/archival/libunarchive/Kbuild b/archival/libunarchive/Kbuild index 3c29d541a..d104524e4 100644 --- a/archival/libunarchive/Kbuild +++ b/archival/libunarchive/Kbuild | |||
| @@ -35,36 +35,34 @@ DPKG_FILES:= \ | |||
| 35 | get_header_tar.o \ | 35 | get_header_tar.o \ |
| 36 | filter_accept_list_reassign.o | 36 | filter_accept_list_reassign.o |
| 37 | 37 | ||
| 38 | # open_transformer uses fork(). Compile it only if absolutely necessary | ||
| 39 | lib-$(CONFIG_RPM) += open_transformer.o | 38 | lib-$(CONFIG_RPM) += open_transformer.o |
| 40 | lib-$(CONFIG_FEATURE_TAR_BZIP2) += open_transformer.o | 39 | lib-$(CONFIG_FEATURE_TAR_BZIP2) += open_transformer.o |
| 41 | lib-$(CONFIG_FEATURE_TAR_LZMA) += open_transformer.o | 40 | lib-$(CONFIG_FEATURE_TAR_LZMA) += open_transformer.o |
| 42 | lib-$(CONFIG_FEATURE_TAR_GZIP) += open_transformer.o | 41 | lib-$(CONFIG_FEATURE_TAR_GZIP) += open_transformer.o |
| 43 | lib-$(CONFIG_FEATURE_TAR_COMPRESS) += open_transformer.o | 42 | lib-$(CONFIG_FEATURE_TAR_COMPRESS) += open_transformer.o |
| 44 | lib-$(CONFIG_FEATURE_DEB_TAR_GZ) += open_transformer.o | 43 | lib-$(CONFIG_FEATURE_DEB_TAR_GZ) += open_transformer.o |
| 45 | lib-$(CONFIG_FEATURE_DEB_TAR_BZ2) += open_transformer.o | 44 | lib-$(CONFIG_FEATURE_DEB_TAR_BZ2) += open_transformer.o |
| 46 | lib-$(CONFIG_FEATURE_DEB_TAR_LZMA) += open_transformer.o | 45 | lib-$(CONFIG_FEATURE_DEB_TAR_LZMA) += open_transformer.o |
| 47 | |||
| 48 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o | ||
| 49 | lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o | ||
| 50 | lib-$(CONFIG_UNLZMA) += decompress_unlzma.o | ||
| 51 | lib-$(CONFIG_CPIO) += get_header_cpio.o | ||
| 52 | lib-$(CONFIG_DPKG) += $(DPKG_FILES) | ||
| 53 | lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) | ||
| 54 | lib-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o | ||
| 55 | lib-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o | ||
| 56 | lib-$(CONFIG_FEATURE_DEB_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o | ||
| 57 | lib-$(CONFIG_GUNZIP) += $(GUNZIP_FILES) | ||
| 58 | lib-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o | ||
| 59 | lib-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o | ||
| 60 | lib-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o | ||
| 61 | lib-$(CONFIG_FEATURE_RPM_BZ2) += decompress_bunzip2.o | ||
| 62 | lib-$(CONFIG_TAR) += get_header_tar.o | ||
| 63 | lib-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o | ||
| 64 | lib-$(CONFIG_FEATURE_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o | ||
| 65 | lib-$(CONFIG_FEATURE_TAR_GZIP) += $(GUNZIP_FILES) get_header_tar_gz.o | ||
| 66 | lib-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o | ||
| 67 | lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o | ||
| 68 | lib-$(CONFIG_UNZIP) += $(GUNZIP_FILES) | ||
| 69 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o | ||
| 70 | 46 | ||
| 47 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o | ||
| 48 | lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o | ||
| 49 | lib-$(CONFIG_UNLZMA) += decompress_unlzma.o | ||
| 50 | lib-$(CONFIG_CPIO) += get_header_cpio.o | ||
| 51 | lib-$(CONFIG_DPKG) += $(DPKG_FILES) | ||
| 52 | lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) | ||
| 53 | lib-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o | ||
| 54 | lib-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o | ||
| 55 | lib-$(CONFIG_FEATURE_DEB_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o | ||
| 56 | lib-$(CONFIG_GUNZIP) += $(GUNZIP_FILES) | ||
| 57 | lib-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o | ||
| 58 | lib-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o | ||
| 59 | lib-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o | ||
| 60 | lib-$(CONFIG_FEATURE_RPM_BZ2) += decompress_bunzip2.o | ||
| 61 | lib-$(CONFIG_TAR) += get_header_tar.o | ||
| 62 | lib-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o | ||
| 63 | lib-$(CONFIG_FEATURE_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o | ||
| 64 | lib-$(CONFIG_FEATURE_TAR_GZIP) += $(GUNZIP_FILES) get_header_tar_gz.o | ||
| 65 | lib-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o | ||
| 66 | lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o | ||
| 67 | lib-$(CONFIG_UNZIP) += $(GUNZIP_FILES) | ||
| 68 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o | ||
diff --git a/archival/libunarchive/get_header_tar_bz2.c b/archival/libunarchive/get_header_tar_bz2.c index e11f44cad..8f7f83fc2 100644 --- a/archival/libunarchive/get_header_tar_bz2.c +++ b/archival/libunarchive/get_header_tar_bz2.c | |||
| @@ -11,7 +11,7 @@ char get_header_tar_bz2(archive_handle_t *archive_handle) | |||
| 11 | /* Can't lseek over pipes */ | 11 | /* Can't lseek over pipes */ |
| 12 | archive_handle->seek = seek_by_read; | 12 | archive_handle->seek = seek_by_read; |
| 13 | 13 | ||
| 14 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_bz2_stream); | 14 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_bz2_stream, "bunzip2", "bunzip2", "-cf", "-", NULL); |
| 15 | archive_handle->offset = 0; | 15 | archive_handle->offset = 0; |
| 16 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) /**/; | 16 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) /**/; |
| 17 | 17 | ||
diff --git a/archival/libunarchive/get_header_tar_gz.c b/archival/libunarchive/get_header_tar_gz.c index 85070d978..a99061411 100644 --- a/archival/libunarchive/get_header_tar_gz.c +++ b/archival/libunarchive/get_header_tar_gz.c | |||
| @@ -8,19 +8,26 @@ | |||
| 8 | 8 | ||
| 9 | char get_header_tar_gz(archive_handle_t *archive_handle) | 9 | char get_header_tar_gz(archive_handle_t *archive_handle) |
| 10 | { | 10 | { |
| 11 | #if BB_MMU | ||
| 11 | unsigned char magic[2]; | 12 | unsigned char magic[2]; |
| 13 | #endif | ||
| 12 | 14 | ||
| 13 | /* Can't lseek over pipes */ | 15 | /* Can't lseek over pipes */ |
| 14 | archive_handle->seek = seek_by_read; | 16 | archive_handle->seek = seek_by_read; |
| 15 | 17 | ||
| 18 | /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). | ||
| 19 | * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will | ||
| 20 | * need the header. */ | ||
| 21 | #if BB_MMU | ||
| 16 | xread(archive_handle->src_fd, &magic, 2); | 22 | xread(archive_handle->src_fd, &magic, 2); |
| 17 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { | 23 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { |
| 18 | bb_error_msg_and_die("invalid gzip magic"); | 24 | bb_error_msg_and_die("invalid gzip magic"); |
| 19 | } | 25 | } |
| 20 | 26 | ||
| 21 | check_header_gzip_or_die(archive_handle->src_fd); | 27 | check_header_gzip_or_die(archive_handle->src_fd); |
| 28 | #endif | ||
| 22 | 29 | ||
| 23 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_gz_stream); | 30 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip", "gunzip", "-cf", "-", NULL); |
| 24 | archive_handle->offset = 0; | 31 | archive_handle->offset = 0; |
| 25 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) /**/; | 32 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) /**/; |
| 26 | 33 | ||
diff --git a/archival/libunarchive/get_header_tar_lzma.c b/archival/libunarchive/get_header_tar_lzma.c index 771f664f2..f0e45f2c5 100644 --- a/archival/libunarchive/get_header_tar_lzma.c +++ b/archival/libunarchive/get_header_tar_lzma.c | |||
| @@ -14,7 +14,7 @@ char get_header_tar_lzma(archive_handle_t * archive_handle) | |||
| 14 | /* Can't lseek over pipes */ | 14 | /* Can't lseek over pipes */ |
| 15 | archive_handle->seek = seek_by_read; | 15 | archive_handle->seek = seek_by_read; |
| 16 | 16 | ||
| 17 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_lzma_stream); | 17 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma", "unlzma", "-cf", "-", NULL); |
| 18 | archive_handle->offset = 0; | 18 | archive_handle->offset = 0; |
| 19 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) /**/; | 19 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) /**/; |
| 20 | 20 | ||
diff --git a/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c index 0ee080621..f8f587e8d 100644 --- a/archival/libunarchive/open_transformer.c +++ b/archival/libunarchive/open_transformer.c | |||
| @@ -7,27 +7,48 @@ | |||
| 7 | #include "unarchive.h" | 7 | #include "unarchive.h" |
| 8 | 8 | ||
| 9 | /* transformer(), more than meets the eye */ | 9 | /* transformer(), more than meets the eye */ |
| 10 | /* | ||
| 11 | * On MMU machine, the transform_prog and ... are stripped | ||
| 12 | * by a macro in include/unarchive.h. On NOMMU, transformer is stripped. | ||
| 13 | */ | ||
| 10 | int open_transformer(int src_fd, | 14 | int open_transformer(int src_fd, |
| 11 | USE_DESKTOP(long long) int (*transformer)(int src_fd, int dst_fd)) | 15 | USE_DESKTOP(long long) int (*transformer)(int src_fd, int dst_fd), |
| 16 | const char *transform_prog, ...) | ||
| 12 | { | 17 | { |
| 13 | int fd_pipe[2]; | 18 | int fd_pipe[2]; |
| 14 | int pid; | 19 | int pid; |
| 15 | 20 | ||
| 16 | xpipe(fd_pipe); | 21 | xpipe(fd_pipe); |
| 17 | 22 | ||
| 23 | #if BB_MMU | ||
| 18 | pid = fork(); | 24 | pid = fork(); |
| 19 | if (pid == -1) { | 25 | #else |
| 26 | pid = vfork(); | ||
| 27 | #endif | ||
| 28 | if (pid == -1) | ||
| 20 | bb_perror_msg_and_die("fork failed"); | 29 | bb_perror_msg_and_die("fork failed"); |
| 21 | } | ||
| 22 | 30 | ||
| 23 | if (pid == 0) { | 31 | if (pid == 0) { |
| 32 | #if !BB_MMU | ||
| 33 | va_list ap; | ||
| 34 | #endif | ||
| 24 | /* child process */ | 35 | /* child process */ |
| 25 | close(fd_pipe[0]); /* We don't wan't to read from the parent */ | 36 | close(fd_pipe[0]); /* We don't wan't to read from the parent */ |
| 26 | // FIXME: error check? | 37 | // FIXME: error check? |
| 38 | #if BB_MMU | ||
| 27 | transformer(src_fd, fd_pipe[1]); | 39 | transformer(src_fd, fd_pipe[1]); |
| 28 | close(fd_pipe[1]); /* Send EOF */ | 40 | if (ENABLE_FEATURE_CLEAN_UP) { |
| 29 | close(src_fd); | 41 | close(fd_pipe[1]); /* Send EOF */ |
| 42 | close(src_fd); | ||
| 43 | } | ||
| 30 | exit(0); | 44 | exit(0); |
| 45 | #else | ||
| 46 | xmove_fd(src_fd, 0); | ||
| 47 | xmove_fd(fd_pipe[1], 1); | ||
| 48 | va_start(ap, transform_prog); | ||
| 49 | BB_EXECVP(transform_prog, ap); | ||
| 50 | bb_perror_and_die("exec failed"); | ||
| 51 | #endif | ||
| 31 | /* notreached */ | 52 | /* notreached */ |
| 32 | } | 53 | } |
| 33 | 54 | ||
diff --git a/archival/rpm.c b/archival/rpm.c index 674ee2640..4d723b73f 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
| @@ -187,9 +187,15 @@ int rpm_main(int argc, char **argv) | |||
| 187 | 187 | ||
| 188 | static void extract_cpio_gz(int fd) | 188 | static void extract_cpio_gz(int fd) |
| 189 | { | 189 | { |
| 190 | USE_DESKTOP(long long) int (*xformer)(int src_fd, int dst_fd); | ||
| 191 | archive_handle_t *archive_handle; | 190 | archive_handle_t *archive_handle; |
| 192 | unsigned char magic[2]; | 191 | unsigned char magic[2]; |
| 192 | #if BB_MMU | ||
| 193 | USE_DESKTOP(long long) int (*xformer)(int src_fd, int dst_fd); | ||
| 194 | enum { xformer_prog = 0 }; | ||
| 195 | #else | ||
| 196 | enum { xformer = 0 }; | ||
| 197 | const char *xformer_prog; | ||
| 198 | #endif | ||
| 193 | 199 | ||
| 194 | /* Initialize */ | 200 | /* Initialize */ |
| 195 | archive_handle = init_handle(); | 201 | archive_handle = init_handle(); |
| @@ -202,11 +208,19 @@ static void extract_cpio_gz(int fd) | |||
| 202 | archive_handle->offset = 0; | 208 | archive_handle->offset = 0; |
| 203 | 209 | ||
| 204 | xread(archive_handle->src_fd, &magic, 2); | 210 | xread(archive_handle->src_fd, &magic, 2); |
| 211 | #if BB_MMU | ||
| 205 | xformer = unpack_gz_stream; | 212 | xformer = unpack_gz_stream; |
| 213 | #else | ||
| 214 | xformer_prog = "gunzip"; | ||
| 215 | #endif | ||
| 206 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { | 216 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { |
| 207 | if (ENABLE_FEATURE_RPM_BZ2 | 217 | if (ENABLE_FEATURE_RPM_BZ2 |
| 208 | && (magic[0] == 0x42) && (magic[1] == 0x5a)) { | 218 | && (magic[0] == 0x42) && (magic[1] == 0x5a)) { |
| 219 | #if BB_MMU | ||
| 209 | xformer = unpack_bz2_stream; | 220 | xformer = unpack_bz2_stream; |
| 221 | #else | ||
| 222 | xformer_prog = "bunzip2"; | ||
| 223 | #endif | ||
| 210 | /* We can do better, need modifying unpack_bz2_stream to not require | 224 | /* We can do better, need modifying unpack_bz2_stream to not require |
| 211 | * first 2 bytes. Not very hard to do... I mean, TODO :) */ | 225 | * first 2 bytes. Not very hard to do... I mean, TODO :) */ |
| 212 | xlseek(archive_handle->src_fd, -2, SEEK_CUR); | 226 | xlseek(archive_handle->src_fd, -2, SEEK_CUR); |
| @@ -214,11 +228,17 @@ static void extract_cpio_gz(int fd) | |||
| 214 | bb_error_msg_and_die("no gzip" | 228 | bb_error_msg_and_die("no gzip" |
| 215 | USE_FEATURE_RPM_BZ2("/bzip") | 229 | USE_FEATURE_RPM_BZ2("/bzip") |
| 216 | " magic"); | 230 | " magic"); |
| 217 | } else | 231 | } else { |
| 218 | check_header_gzip_or_die(archive_handle->src_fd); | 232 | check_header_gzip_or_die(archive_handle->src_fd); |
| 233 | #if !BB_MMU | ||
| 234 | /* NOMMU version of open_transformer execs an external unzipper that should | ||
| 235 | * have the file position at the start of the file */ | ||
| 236 | xlseek(archive_handle->src_fd, 0, SEEK_SET); | ||
| 237 | #endif | ||
| 238 | } | ||
| 219 | 239 | ||
| 220 | xchdir("/"); /* Install RPM's to root */ | 240 | xchdir("/"); /* Install RPM's to root */ |
| 221 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, xformer); | 241 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, xformer, xformer_prog, xformer_prog, "-cf", "-", NULL); |
| 222 | archive_handle->offset = 0; | 242 | archive_handle->offset = 0; |
| 223 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | 243 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) |
| 224 | continue; | 244 | continue; |
diff --git a/archival/tar.c b/archival/tar.c index 9bf9058d8..7235616cf 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
| @@ -648,7 +648,7 @@ static char get_header_tar_Z(archive_handle_t *archive_handle) | |||
| 648 | bb_error_msg_and_die("invalid magic"); | 648 | bb_error_msg_and_die("invalid magic"); |
| 649 | } | 649 | } |
| 650 | 650 | ||
| 651 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress); | 651 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress, "uncompress", "uncompress", "-cf", "-", NULL); |
| 652 | archive_handle->offset = 0; | 652 | archive_handle->offset = 0; |
| 653 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) | 653 | while (get_header_tar(archive_handle) == EXIT_SUCCESS) |
| 654 | /* nothing */; | 654 | /* nothing */; |
diff --git a/include/libbb.h b/include/libbb.h index e514fe2f2..140e21dea 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -248,9 +248,10 @@ void xmove_fd(int, int); | |||
| 248 | DIR *xopendir(const char *path); | 248 | DIR *xopendir(const char *path); |
| 249 | DIR *warn_opendir(const char *path); | 249 | DIR *warn_opendir(const char *path); |
| 250 | 250 | ||
| 251 | char *xrealloc_getcwd_or_warn(char *cwd); | 251 | /* UNUSED: char *xmalloc_realpath(const char *path); */ |
| 252 | char *xmalloc_readlink(const char *path); | ||
| 252 | char *xmalloc_readlink_or_warn(const char *path); | 253 | char *xmalloc_readlink_or_warn(const char *path); |
| 253 | char *xmalloc_realpath(const char *path); | 254 | char *xrealloc_getcwd_or_warn(char *cwd); |
| 254 | 255 | ||
| 255 | 256 | ||
| 256 | //TODO: signal(sid, f) is the same? then why? | 257 | //TODO: signal(sid, f) is the same? then why? |
| @@ -316,8 +317,8 @@ enum { | |||
| 316 | }; | 317 | }; |
| 317 | /* Create stream socket, and allocate suitable lsa. | 318 | /* Create stream socket, and allocate suitable lsa. |
| 318 | * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6)) | 319 | * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6)) |
| 319 | * af == AF_UNSPEC will result in trying to create IPv6, and | 320 | * af == AF_UNSPEC will result in trying to create IPv6 socket, |
| 320 | * if kernel doesn't support it, IPv4. | 321 | * and if kernel doesn't support it, IPv4. |
| 321 | */ | 322 | */ |
| 322 | int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int af,) int sock_type); | 323 | int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int af,) int sock_type); |
| 323 | int xsocket_stream(len_and_sockaddr **lsap); | 324 | int xsocket_stream(len_and_sockaddr **lsap); |
diff --git a/include/unarchive.h b/include/unarchive.h index bea055852..51ec89cc0 100644 --- a/include/unarchive.h +++ b/include/unarchive.h | |||
| @@ -115,7 +115,13 @@ extern USE_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, unsig | |||
| 115 | extern USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd); | 115 | extern USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd); |
| 116 | extern USE_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd); | 116 | extern USE_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd); |
| 117 | 117 | ||
| 118 | #if BB_MMU | ||
| 118 | extern int open_transformer(int src_fd, | 119 | extern int open_transformer(int src_fd, |
| 119 | USE_DESKTOP(long long) int (*transformer)(int src_fd, int dst_fd)); | 120 | USE_DESKTOP(long long) int (*transformer)(int src_fd, int dst_fd)); |
| 121 | #define open_transformer(src_fd, transformer, transform_prog, ...) open_transformer(src_fd, transformer) | ||
| 122 | #else | ||
| 123 | extern int open_transformer(int src_fd, const char *transform_prog, ...); | ||
| 124 | #define open_transformer(src_fd, transformer, transform_prog, ...) open_transformer(src_fd, transform_prog, __VA_ARGS__) | ||
| 125 | #endif | ||
| 120 | 126 | ||
| 121 | #endif | 127 | #endif |
diff --git a/libbb/copy_file.c b/libbb/copy_file.c index b68a257b5..3da8a3531 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c | |||
| @@ -19,28 +19,31 @@ | |||
| 19 | // (or fail, if it points to dir/nonexistent location/etc). | 19 | // (or fail, if it points to dir/nonexistent location/etc). |
| 20 | // This is strange, but POSIX-correct. | 20 | // This is strange, but POSIX-correct. |
| 21 | // coreutils cp has --remove-destination to override this... | 21 | // coreutils cp has --remove-destination to override this... |
| 22 | // | ||
| 23 | // NB: we have special code which still allows for "cp file /dev/node" | ||
| 24 | // to work POSIX-ly (the only realistic case where it makes sense) | ||
| 22 | 25 | ||
| 23 | #define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */ | 26 | #define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */ |
| 24 | 27 | ||
| 25 | 28 | // errno must be set to relevant value ("why we cannot create dest?") | |
| 29 | // for POSIX mode to give reasonable error message | ||
| 26 | static int ask_and_unlink(const char *dest, int flags) | 30 | static int ask_and_unlink(const char *dest, int flags) |
| 27 | { | 31 | { |
| 28 | // If !DO_POSIX_CP, act as if -f is always in effect - we don't want | ||
| 29 | // "'file' exists" msg, we want unlink to be done (silently unless -i | ||
| 30 | // is also in effect). | ||
| 31 | // This prevents safe way from asking more questions than POSIX does. | ||
| 32 | #if DO_POSIX_CP | 32 | #if DO_POSIX_CP |
| 33 | if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) { | 33 | if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) { |
| 34 | fprintf(stderr, "'%s' exists\n", dest); | 34 | // Either it exists, or the *path* doesnt exist |
| 35 | bb_perror_msg("cannot create '%s'", dest); | ||
| 35 | return -1; | 36 | return -1; |
| 36 | } | 37 | } |
| 37 | #endif | 38 | #endif |
| 39 | // If !DO_POSIX_CP, act as if -f is always in effect - we don't want | ||
| 40 | // "cannot create" msg, we want unlink to be done (silently unless -i). | ||
| 38 | 41 | ||
| 39 | // TODO: maybe we should do it only if ctty is present? | 42 | // TODO: maybe we should do it only if ctty is present? |
| 40 | if (flags & FILEUTILS_INTERACTIVE) { | 43 | if (flags & FILEUTILS_INTERACTIVE) { |
| 41 | // We would not do POSIX insanity. -i asks, | 44 | // We would not do POSIX insanity. -i asks, |
| 42 | // then _unlinks_ the offender. Presto. | 45 | // then _unlinks_ the offender. Presto. |
| 43 | // (No opening without O_EXCL, no unlinks only if -f) | 46 | // (No "opening without O_EXCL", no "unlink only if -f") |
| 44 | // Or else we will end up having 3 open()s! | 47 | // Or else we will end up having 3 open()s! |
| 45 | fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest); | 48 | fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest); |
| 46 | if (!bb_ask_confirmation()) | 49 | if (!bb_ask_confirmation()) |
| @@ -60,9 +63,11 @@ static int ask_and_unlink(const char *dest, int flags) | |||
| 60 | */ | 63 | */ |
| 61 | int copy_file(const char *source, const char *dest, int flags) | 64 | int copy_file(const char *source, const char *dest, int flags) |
| 62 | { | 65 | { |
| 66 | /* This is a recursive function, try to minimize stack usage */ | ||
| 67 | /* NB: each struct stat is ~100 bytes */ | ||
| 63 | struct stat source_stat; | 68 | struct stat source_stat; |
| 64 | struct stat dest_stat; | 69 | struct stat dest_stat; |
| 65 | int status = 0; | 70 | signed char retval = 0; |
| 66 | signed char dest_exists = 0; | 71 | signed char dest_exists = 0; |
| 67 | signed char ovr; | 72 | signed char ovr; |
| 68 | 73 | ||
| @@ -112,6 +117,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 112 | 117 | ||
| 113 | if (S_ISDIR(source_stat.st_mode)) { | 118 | if (S_ISDIR(source_stat.st_mode)) { |
| 114 | DIR *dp; | 119 | DIR *dp; |
| 120 | const char *tp; | ||
| 115 | struct dirent *d; | 121 | struct dirent *d; |
| 116 | mode_t saved_umask = 0; | 122 | mode_t saved_umask = 0; |
| 117 | 123 | ||
| @@ -120,12 +126,23 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 120 | return -1; | 126 | return -1; |
| 121 | } | 127 | } |
| 122 | 128 | ||
| 123 | /* Create DEST. */ | 129 | /* Did we ever create source ourself before? */ |
| 130 | tp = is_in_ino_dev_hashtable(&source_stat); | ||
| 131 | if (tp) { | ||
| 132 | /* We did! it's a recursion! man the lifeboats... */ | ||
| 133 | bb_error_msg("recursion detected, omitting directory '%s'", | ||
| 134 | source); | ||
| 135 | return -1; | ||
| 136 | } | ||
| 137 | |||
| 138 | /* Create DEST */ | ||
| 124 | if (dest_exists) { | 139 | if (dest_exists) { |
| 125 | if (!S_ISDIR(dest_stat.st_mode)) { | 140 | if (!S_ISDIR(dest_stat.st_mode)) { |
| 126 | bb_error_msg("target '%s' is not a directory", dest); | 141 | bb_error_msg("target '%s' is not a directory", dest); |
| 127 | return -1; | 142 | return -1; |
| 128 | } | 143 | } |
| 144 | /* race here: user can substitute a symlink between | ||
| 145 | * this check and actual creation of files inside dest */ | ||
| 129 | } else { | 146 | } else { |
| 130 | mode_t mode; | 147 | mode_t mode; |
| 131 | saved_umask = umask(0); | 148 | saved_umask = umask(0); |
| @@ -133,22 +150,29 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 133 | mode = source_stat.st_mode; | 150 | mode = source_stat.st_mode; |
| 134 | if (!(flags & FILEUTILS_PRESERVE_STATUS)) | 151 | if (!(flags & FILEUTILS_PRESERVE_STATUS)) |
| 135 | mode = source_stat.st_mode & ~saved_umask; | 152 | mode = source_stat.st_mode & ~saved_umask; |
| 153 | /* Allow owner to access new dir (at least for now) */ | ||
| 136 | mode |= S_IRWXU; | 154 | mode |= S_IRWXU; |
| 137 | |||
| 138 | if (mkdir(dest, mode) < 0) { | 155 | if (mkdir(dest, mode) < 0) { |
| 139 | umask(saved_umask); | 156 | umask(saved_umask); |
| 140 | bb_perror_msg("cannot create directory '%s'", dest); | 157 | bb_perror_msg("cannot create directory '%s'", dest); |
| 141 | return -1; | 158 | return -1; |
| 142 | } | 159 | } |
| 143 | |||
| 144 | umask(saved_umask); | 160 | umask(saved_umask); |
| 161 | /* need stat info for add_to_ino_dev_hashtable */ | ||
| 162 | if (lstat(dest, &dest_stat) < 0) { | ||
| 163 | bb_perror_msg("cannot stat '%s'", dest); | ||
| 164 | return -1; | ||
| 165 | } | ||
| 145 | } | 166 | } |
| 167 | /* remember (dev,inode) of each created dir. | ||
| 168 | * NULL: name is not remembered */ | ||
| 169 | add_to_ino_dev_hashtable(&dest_stat, NULL); | ||
| 146 | 170 | ||
| 147 | /* Recursively copy files in SOURCE. */ | 171 | /* Recursively copy files in SOURCE */ |
| 148 | dp = opendir(source); | 172 | dp = opendir(source); |
| 149 | if (dp == NULL) { | 173 | if (dp == NULL) { |
| 150 | status = -1; | 174 | retval = -1; |
| 151 | goto preserve_status; | 175 | goto preserve_mode_ugid_time; |
| 152 | } | 176 | } |
| 153 | 177 | ||
| 154 | while ((d = readdir(dp)) != NULL) { | 178 | while ((d = readdir(dp)) != NULL) { |
| @@ -159,7 +183,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 159 | continue; | 183 | continue; |
| 160 | new_dest = concat_path_file(dest, d->d_name); | 184 | new_dest = concat_path_file(dest, d->d_name); |
| 161 | if (copy_file(new_source, new_dest, flags) < 0) | 185 | if (copy_file(new_source, new_dest, flags) < 0) |
| 162 | status = -1; | 186 | retval = -1; |
| 163 | free(new_source); | 187 | free(new_source); |
| 164 | free(new_dest); | 188 | free(new_dest); |
| 165 | } | 189 | } |
| @@ -168,11 +192,13 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 168 | if (!dest_exists | 192 | if (!dest_exists |
| 169 | && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 | 193 | && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 |
| 170 | ) { | 194 | ) { |
| 171 | bb_perror_msg("cannot change permissions of '%s'", dest); | 195 | bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest); |
| 172 | status = -1; | 196 | /* retval = -1; - WRONG! copy *WAS* made */ |
| 173 | } | 197 | } |
| 198 | goto preserve_mode_ugid_time; | ||
| 199 | } | ||
| 174 | 200 | ||
| 175 | } else if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { | 201 | if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { |
| 176 | int (*lf)(const char *oldpath, const char *newpath); | 202 | int (*lf)(const char *oldpath, const char *newpath); |
| 177 | make_links: | 203 | make_links: |
| 178 | // Hmm... maybe | 204 | // Hmm... maybe |
| @@ -188,47 +214,52 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 188 | return -1; | 214 | return -1; |
| 189 | } | 215 | } |
| 190 | } | 216 | } |
| 217 | /* _Not_ jumping to preserve_mode_ugid_time: | ||
| 218 | * hard/softlinks don't have those */ | ||
| 191 | return 0; | 219 | return 0; |
| 220 | } | ||
| 192 | 221 | ||
| 193 | } else if (S_ISREG(source_stat.st_mode) | 222 | if (S_ISREG(source_stat.st_mode) |
| 194 | /* Huh? DEREF uses stat, which never returns links! */ | 223 | /* DEREF uses stat, which never returns S_ISLNK() == true. */ |
| 195 | /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ | 224 | /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ |
| 196 | ) { | 225 | ) { |
| 197 | int src_fd; | 226 | int src_fd; |
| 198 | int dst_fd; | 227 | int dst_fd; |
| 199 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { | ||
| 200 | char *link_target; | ||
| 201 | 228 | ||
| 202 | if (!FLAGS_DEREF) { | 229 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { |
| 203 | link_target = is_in_ino_dev_hashtable(&source_stat); | 230 | const char *link_target; |
| 204 | if (link_target) { | 231 | link_target = is_in_ino_dev_hashtable(&source_stat); |
| 232 | if (link_target) { | ||
| 233 | if (link(link_target, dest) < 0) { | ||
| 234 | ovr = ask_and_unlink(dest, flags); | ||
| 235 | if (ovr <= 0) | ||
| 236 | return ovr; | ||
| 205 | if (link(link_target, dest) < 0) { | 237 | if (link(link_target, dest) < 0) { |
| 206 | ovr = ask_and_unlink(dest, flags); | 238 | bb_perror_msg("cannot create link '%s'", dest); |
| 207 | if (ovr <= 0) | 239 | return -1; |
| 208 | return ovr; | ||
| 209 | if (link(link_target, dest) < 0) { | ||
| 210 | bb_perror_msg("cannot create link '%s'", dest); | ||
| 211 | return -1; | ||
| 212 | } | ||
| 213 | } | 240 | } |
| 214 | return 0; | ||
| 215 | } | 241 | } |
| 242 | return 0; | ||
| 216 | } | 243 | } |
| 217 | add_to_ino_dev_hashtable(&source_stat, dest); | 244 | add_to_ino_dev_hashtable(&source_stat, dest); |
| 218 | } | 245 | } |
| 219 | 246 | ||
| 220 | src_fd = open_or_warn(source, O_RDONLY); | 247 | src_fd = open_or_warn(source, O_RDONLY); |
| 221 | if (src_fd < 0) { | 248 | if (src_fd < 0) |
| 222 | return -1; | 249 | return -1; |
| 223 | } | ||
| 224 | 250 | ||
| 225 | #if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */ | 251 | /* POSIX way is a security problem versus symlink attacks, |
| 226 | dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE) | 252 | * we do it only for non-symlinks, and only for non-recursive, |
| 227 | ? O_WRONLY|O_CREAT|O_EXCL | 253 | * non-interactive cp. NB: it is still racy |
| 228 | : O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); | 254 | * for "cp file /home/bad_user/file" case |
| 229 | #else /* safe way: */ | 255 | * (user can rm file and create a link to /etc/passwd) */ |
| 230 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); | 256 | if (DO_POSIX_CP |
| 231 | #endif | 257 | || (dest_exists && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE)) |
| 258 | && !S_ISLNK(dest_stat.st_mode)) | ||
| 259 | ) { | ||
| 260 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); | ||
| 261 | } else /* safe way: */ | ||
| 262 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); | ||
| 232 | if (dst_fd == -1) { | 263 | if (dst_fd == -1) { |
| 233 | ovr = ask_and_unlink(dest, flags); | 264 | ovr = ask_and_unlink(dest, flags); |
| 234 | if (ovr <= 0) { | 265 | if (ovr <= 0) { |
| @@ -264,60 +295,55 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 264 | } | 295 | } |
| 265 | #endif | 296 | #endif |
| 266 | if (bb_copyfd_eof(src_fd, dst_fd) == -1) | 297 | if (bb_copyfd_eof(src_fd, dst_fd) == -1) |
| 267 | status = -1; | 298 | retval = -1; |
| 299 | /* Ok, writing side I can understand... */ | ||
| 268 | if (close(dst_fd) < 0) { | 300 | if (close(dst_fd) < 0) { |
| 269 | bb_perror_msg("cannot close '%s'", dest); | 301 | bb_perror_msg("cannot close '%s'", dest); |
| 270 | status = -1; | 302 | retval = -1; |
| 271 | } | ||
| 272 | if (close(src_fd) < 0) { | ||
| 273 | bb_perror_msg("cannot close '%s'", source); | ||
| 274 | status = -1; | ||
| 275 | } | 303 | } |
| 304 | /* ...but read size is already checked by bb_copyfd_eof */ | ||
| 305 | close(src_fd); | ||
| 306 | goto preserve_mode_ugid_time; | ||
| 307 | } | ||
| 276 | 308 | ||
| 277 | } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) | 309 | /* Source is a symlink or a special file */ |
| 278 | || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) | 310 | /* We are lazy here, a bit lax with races... */ |
| 279 | || S_ISLNK(source_stat.st_mode) | 311 | if (dest_exists) { |
| 280 | ) { | 312 | errno = EEXIST; |
| 281 | // We are lazy here, a bit lax with races... | 313 | ovr = ask_and_unlink(dest, flags); |
| 282 | if (dest_exists) { | 314 | if (ovr <= 0) |
| 283 | ovr = ask_and_unlink(dest, flags); | 315 | return ovr; |
| 284 | if (ovr <= 0) | 316 | } |
| 285 | return ovr; | 317 | if (S_ISLNK(source_stat.st_mode)) { |
| 286 | } | 318 | char *lpath = xmalloc_readlink_or_warn(source); |
| 287 | if (S_ISFIFO(source_stat.st_mode)) { | 319 | if (lpath) { |
| 288 | if (mkfifo(dest, source_stat.st_mode) < 0) { | 320 | int r = symlink(lpath, dest); |
| 289 | bb_perror_msg("cannot create fifo '%s'", dest); | 321 | free(lpath); |
| 290 | return -1; | 322 | if (r < 0) { |
| 291 | } | ||
| 292 | } else if (S_ISLNK(source_stat.st_mode)) { | ||
| 293 | char *lpath; | ||
| 294 | |||
| 295 | lpath = xmalloc_readlink_or_warn(source); | ||
| 296 | if (lpath && symlink(lpath, dest) < 0) { | ||
| 297 | bb_perror_msg("cannot create symlink '%s'", dest); | 323 | bb_perror_msg("cannot create symlink '%s'", dest); |
| 298 | free(lpath); | ||
| 299 | return -1; | 324 | return -1; |
| 300 | } | 325 | } |
| 301 | free(lpath); | ||
| 302 | |||
| 303 | if (flags & FILEUTILS_PRESERVE_STATUS) | 326 | if (flags & FILEUTILS_PRESERVE_STATUS) |
| 304 | if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) | 327 | if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) |
| 305 | bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest); | 328 | bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest); |
| 306 | 329 | } | |
| 307 | return 0; | 330 | /* _Not_ jumping to preserve_mode_ugid_time: |
| 308 | 331 | * symlinks don't have those */ | |
| 309 | } else { | 332 | return 0; |
| 310 | if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { | 333 | } |
| 311 | bb_perror_msg("cannot create '%s'", dest); | 334 | if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) |
| 312 | return -1; | 335 | || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) |
| 313 | } | 336 | ) { |
| 337 | if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { | ||
| 338 | bb_perror_msg("cannot create '%s'", dest); | ||
| 339 | return -1; | ||
| 314 | } | 340 | } |
| 315 | } else { | 341 | } else { |
| 316 | bb_error_msg("internal error: unrecognized file type"); | 342 | bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode); |
| 317 | return -1; | 343 | return -1; |
| 318 | } | 344 | } |
| 319 | 345 | ||
| 320 | preserve_status: | 346 | preserve_mode_ugid_time: |
| 321 | 347 | ||
| 322 | if (flags & FILEUTILS_PRESERVE_STATUS | 348 | if (flags & FILEUTILS_PRESERVE_STATUS |
| 323 | /* Cannot happen: */ | 349 | /* Cannot happen: */ |
| @@ -327,6 +353,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 327 | 353 | ||
| 328 | times.actime = source_stat.st_atime; | 354 | times.actime = source_stat.st_atime; |
| 329 | times.modtime = source_stat.st_mtime; | 355 | times.modtime = source_stat.st_mtime; |
| 356 | /* BTW, utimes sets usec-precision time - just FYI */ | ||
| 330 | if (utime(dest, ×) < 0) | 357 | if (utime(dest, ×) < 0) |
| 331 | bb_perror_msg("cannot preserve %s of '%s'", "times", dest); | 358 | bb_perror_msg("cannot preserve %s of '%s'", "times", dest); |
| 332 | if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { | 359 | if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { |
| @@ -337,5 +364,5 @@ int copy_file(const char *source, const char *dest, int flags) | |||
| 337 | bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest); | 364 | bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest); |
| 338 | } | 365 | } |
| 339 | 366 | ||
| 340 | return status; | 367 | return retval; |
| 341 | } | 368 | } |
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index 18a8b9467..4d87b944d 100644 --- a/libbb/xreadlink.c +++ b/libbb/xreadlink.c | |||
| @@ -10,8 +10,7 @@ | |||
| 10 | * NOTE: This function returns a malloced char* that you will have to free | 10 | * NOTE: This function returns a malloced char* that you will have to free |
| 11 | * yourself. You have been warned. | 11 | * yourself. You have been warned. |
| 12 | */ | 12 | */ |
| 13 | 13 | char *xmalloc_readlink(const char *path) | |
| 14 | char *xmalloc_readlink_or_warn(const char *path) | ||
| 15 | { | 14 | { |
| 16 | enum { GROWBY = 80 }; /* how large we will grow strings by */ | 15 | enum { GROWBY = 80 }; /* how large we will grow strings by */ |
| 17 | 16 | ||
| @@ -20,20 +19,30 @@ char *xmalloc_readlink_or_warn(const char *path) | |||
| 20 | 19 | ||
| 21 | do { | 20 | do { |
| 22 | buf = xrealloc(buf, bufsize += GROWBY); | 21 | buf = xrealloc(buf, bufsize += GROWBY); |
| 23 | readsize = readlink(path, buf, bufsize); /* 1st try */ | 22 | readsize = readlink(path, buf, bufsize); |
| 24 | if (readsize == -1) { | 23 | if (readsize == -1) { |
| 25 | bb_perror_msg("%s", path); | ||
| 26 | free(buf); | 24 | free(buf); |
| 27 | return NULL; | 25 | return NULL; |
| 28 | } | 26 | } |
| 29 | } | 27 | } while (bufsize < readsize + 1); |
| 30 | while (bufsize < readsize + 1); | ||
| 31 | 28 | ||
| 32 | buf[readsize] = '\0'; | 29 | buf[readsize] = '\0'; |
| 33 | 30 | ||
| 34 | return buf; | 31 | return buf; |
| 35 | } | 32 | } |
| 36 | 33 | ||
| 34 | char *xmalloc_readlink_or_warn(const char *path) | ||
| 35 | { | ||
| 36 | char *buf = xmalloc_readlink(path); | ||
| 37 | if (!buf) { | ||
| 38 | /* EINVAL => "file: Invalid argument" => puzzled user */ | ||
| 39 | bb_error_msg("%s: cannot read link (not a symlink?)", path); | ||
| 40 | } | ||
| 41 | return buf; | ||
| 42 | } | ||
| 43 | |||
| 44 | /* UNUSED */ | ||
| 45 | #if 0 | ||
| 37 | char *xmalloc_realpath(const char *path) | 46 | char *xmalloc_realpath(const char *path) |
| 38 | { | 47 | { |
| 39 | #if defined(__GLIBC__) && !defined(__UCLIBC__) | 48 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
| @@ -46,3 +55,4 @@ char *xmalloc_realpath(const char *path) | |||
| 46 | return xstrdup(realpath(path, buf)); | 55 | return xstrdup(realpath(path, buf)); |
| 47 | #endif | 56 | #endif |
| 48 | } | 57 | } |
| 58 | #endif | ||
diff --git a/networking/isrv.c b/networking/isrv.c index 1a41dd4fb..080c60fbd 100644 --- a/networking/isrv.c +++ b/networking/isrv.c | |||
| @@ -21,20 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | /* Helpers */ | 22 | /* Helpers */ |
| 23 | 23 | ||
| 24 | /* Even if _POSIX_MONOTONIC_CLOCK is defined, this | ||
| 25 | * may require librt */ | ||
| 26 | #if 0 /*def _POSIX_MONOTONIC_CLOCK*/ | ||
| 27 | static time_t monotonic_time(void) | ||
| 28 | { | ||
| 29 | struct timespec ts; | ||
| 30 | if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) | ||
| 31 | time(&ts.tv_sec); | ||
| 32 | return ts.tv_sec; | ||
| 33 | } | ||
| 34 | #else | ||
| 35 | #define monotonic_time() (time(NULL)) | ||
| 36 | #endif | ||
| 37 | |||
| 38 | /* Opaque structure */ | 24 | /* Opaque structure */ |
| 39 | 25 | ||
| 40 | struct isrv_state_t { | 26 | struct isrv_state_t { |
| @@ -258,7 +244,7 @@ static void handle_fd_set(isrv_state_t *state, fd_set *fds, int (*h)(int, void * | |||
| 258 | /* this peer is gone */ | 244 | /* this peer is gone */ |
| 259 | remove_peer(state, peer); | 245 | remove_peer(state, peer); |
| 260 | } else if (TIMEOUT) { | 246 | } else if (TIMEOUT) { |
| 261 | TIMEO_TBL[peer] = monotonic_time(); | 247 | TIMEO_TBL[peer] = monotonic_sec(); |
| 262 | } | 248 | } |
| 263 | } | 249 | } |
| 264 | } | 250 | } |
| @@ -335,7 +321,7 @@ void isrv_run( | |||
| 335 | break; | 321 | break; |
| 336 | 322 | ||
| 337 | if (timeout) { | 323 | if (timeout) { |
| 338 | time_t t = monotonic_time(); | 324 | time_t t = monotonic_sec(); |
| 339 | if (t != CURTIME) { | 325 | if (t != CURTIME) { |
| 340 | CURTIME = t; | 326 | CURTIME = t; |
| 341 | handle_timeout(state, do_timeout); | 327 | handle_timeout(state, do_timeout); |
diff --git a/runit/runsv.c b/runit/runsv.c index baef6e13f..b35c26630 100644 --- a/runit/runsv.c +++ b/runit/runsv.c | |||
| @@ -33,6 +33,34 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 33 | #include "libbb.h" | 33 | #include "libbb.h" |
| 34 | #include "runit_lib.h" | 34 | #include "runit_lib.h" |
| 35 | 35 | ||
| 36 | #if ENABLE_MONOTONIC_SYSCALL | ||
| 37 | #include <sys/syscall.h> | ||
| 38 | |||
| 39 | /* libc has incredibly messy way of doing this, | ||
| 40 | * typically requiring -lrt. We just skip all this mess */ | ||
| 41 | static void gettimeofday_ns(struct timespec *ts) | ||
| 42 | { | ||
| 43 | syscall(__NR_clock_gettime, CLOCK_REALTIME, ts); | ||
| 44 | } | ||
| 45 | #else | ||
| 46 | static void gettimeofday_ns(struct timespec *ts) | ||
| 47 | { | ||
| 48 | if (sizeof(struct timeval) == sizeof(struct timespec) | ||
| 49 | && sizeof(((struct timeval*)ts)->tv_usec) == sizeof(ts->tv_nsec) | ||
| 50 | ) { | ||
| 51 | /* Cheat */ | ||
| 52 | gettimeofday((void*)ts, NULL); | ||
| 53 | ts->tv_nsec *= 1000; | ||
| 54 | } else { | ||
| 55 | extern void BUG_need_to_implement_gettimeofday_ns(void); | ||
| 56 | BUG_need_to_implement_gettimeofday_ns(); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /* Compare possibly overflowing unsigned counters */ | ||
| 62 | #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0) | ||
| 63 | |||
| 36 | static int selfpipe[2]; | 64 | static int selfpipe[2]; |
| 37 | 65 | ||
| 38 | /* state */ | 66 | /* state */ |
| @@ -126,14 +154,6 @@ static int rename_or_warn(const char *old, const char *new) | |||
| 126 | return 0; | 154 | return 0; |
| 127 | } | 155 | } |
| 128 | 156 | ||
| 129 | #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0) | ||
| 130 | |||
| 131 | #include <sys/syscall.h> | ||
| 132 | static void gettimeofday_ns(struct timespec *ts) | ||
| 133 | { | ||
| 134 | syscall(__NR_clock_gettime, CLOCK_REALTIME, ts); | ||
| 135 | } | ||
| 136 | |||
| 137 | static void update_status(struct svdir *s) | 157 | static void update_status(struct svdir *s) |
| 138 | { | 158 | { |
| 139 | ssize_t sz; | 159 | ssize_t sz; |
diff --git a/scripts/trylink b/scripts/trylink index 4eaa334d5..0b8f6c062 100755 --- a/scripts/trylink +++ b/scripts/trylink | |||
| @@ -14,37 +14,30 @@ try() { | |||
| 14 | BBOX_LIB_LIST=`echo "$BBOX_LIB_LIST" | xargs -n1 | sort | uniq | xargs` | 14 | BBOX_LIB_LIST=`echo "$BBOX_LIB_LIST" | xargs -n1 | sort | uniq | xargs` |
| 15 | 15 | ||
| 16 | # First link with all libs. If it fails, bail out | 16 | # First link with all libs. If it fails, bail out |
| 17 | l_list=`echo "$BBOX_LIB_LIST" | sed -e 's/ / -l/g' -e 's/^/-l/'` | ||
| 18 | echo "Trying libraries: $BBOX_LIB_LIST" | 17 | echo "Trying libraries: $BBOX_LIB_LIST" |
| 19 | try "-Wl,--start-group $l_list -Wl,--end-group" "$@" \ | 18 | l_list=`echo "$BBOX_LIB_LIST" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` |
| 19 | test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" | ||
| 20 | try "$l_list" "$@" \ | ||
| 20 | || { | 21 | || { |
| 21 | echo "Failed: $* -Wl,--start-group $l_list -Wl,--end-group" | 22 | echo "Failed: $* -Wl,--start-group $l_list -Wl,--end-group" |
| 22 | cat busybox_ld.err | 23 | cat busybox_ld.err |
| 23 | exit 1 | 24 | exit 1 |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | #### Hack disabled: conflicts with ld --verbose flag in last link phase | ||
| 27 | |||
| 28 | ##### Hack: we are not supposed to know executable name, | ||
| 29 | ##### but this hack cuts down link time | ||
| 30 | ####mv busybox_unstripped busybox_unstripped.tmp | ||
| 31 | ####mv busybox.map busybox.map.tmp | ||
| 32 | |||
| 33 | # Now try to remove each lib and build without it. | 27 | # Now try to remove each lib and build without it. |
| 34 | # Stop when no lib can be removed. | 28 | # Stop when no lib can be removed. |
| 35 | ####ever_discarded=false | ||
| 36 | while test "$BBOX_LIB_LIST"; do | 29 | while test "$BBOX_LIB_LIST"; do |
| 37 | $debug && echo "Trying libraries: $BBOX_LIB_LIST" | 30 | $debug && echo "Trying libraries: $BBOX_LIB_LIST" |
| 38 | all_needed=true | 31 | all_needed=true |
| 39 | for one in $BBOX_LIB_LIST; do | 32 | for one in $BBOX_LIB_LIST; do |
| 40 | without_one=`echo " $BBOX_LIB_LIST " | sed "s/ $one / /g" | xargs` | 33 | without_one=`echo " $BBOX_LIB_LIST " | sed "s/ $one / /g" | xargs` |
| 41 | l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/'` | 34 | l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` |
| 42 | $debug && echo "Trying -l options: $l_list" | 35 | test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" |
| 43 | if try "-Wl,--start-group $l_list -Wl,--end-group" "$@"; then | 36 | $debug && echo "Trying -l options: '$l_list'" |
| 37 | if try "$l_list" "$@"; then | ||
| 44 | echo "Library $one is not needed" | 38 | echo "Library $one is not needed" |
| 45 | BBOX_LIB_LIST="$without_one" | 39 | BBOX_LIB_LIST="$without_one" |
| 46 | all_needed=false | 40 | all_needed=false |
| 47 | #### ever_discarded=true | ||
| 48 | else | 41 | else |
| 49 | echo "Library $one is needed" | 42 | echo "Library $one is needed" |
| 50 | fi | 43 | fi |
| @@ -57,24 +50,19 @@ while test "$BBOX_LIB_LIST"; do | |||
| 57 | #{ echo "$BBOX_LIB_LIST" | grep -q ' '; } || break | 50 | #{ echo "$BBOX_LIB_LIST" | grep -q ' '; } || break |
| 58 | done | 51 | done |
| 59 | 52 | ||
| 60 | ####mv busybox_unstripped.tmp busybox_unstripped | 53 | # Make the binary with final, minimal list of libs |
| 61 | ####mv busybox.map.tmp busybox.map | 54 | echo "Final link with: $BBOX_LIB_LIST" |
| 62 | ####$ever_discarded && { | 55 | l_list=`echo "$BBOX_LIB_LIST" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` |
| 63 | # Make the binary with final, minimal list of libs | 56 | test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group -Wl,--verbose" |
| 64 | echo "Final link with: $BBOX_LIB_LIST" | 57 | # --verbose gives us gobs of info to stdout (e.g. linker script used) |
| 65 | l_list=`echo "$BBOX_LIB_LIST" | sed -e 's/ / -l/g' -e 's/^/-l/'` | 58 | if ! test -f busybox_ldscript; then |
| 66 | # --verbose gives us gobs of info to stdout (e.g. linker script used) | 59 | try "$l_list -Wl,--verbose" "$@" >busybox_ld.out |
| 67 | if ! test -f busybox_ldscript; then | 60 | else |
| 68 | try "-Wl,--start-group $l_list -Wl,--end-group -Wl,--verbose" "$@" >busybox_ld.out ####|| exit 1 | 61 | echo "Custom linker script 'busybox_ldscript' found, using it" |
| 69 | else | 62 | # Add SORT_BY_ALIGNMENT to linker script (found in busybox_ld.out): |
| 70 | echo "Custom linker script 'busybox_ldscript' found, using it" | 63 | # .rodata : { *(.rodata SORT_BY_ALIGNMENT(.rodata.*) .gnu.linkonce.r.*) } |
| 71 | # Add SORT_BY_ALIGNMENT to linker script (found in busybox_ld.out): | 64 | # *(.data SORT_BY_ALIGNMENT(.data.*) .gnu.linkonce.d.*) |
| 72 | # .rodata : { *(.rodata SORT_BY_ALIGNMENT(.rodata.*) .gnu.linkonce.r.*) } | 65 | # *(.bss SORT_BY_ALIGNMENT(.bss.*) .gnu.linkonce.b.*) |
| 73 | # *(.data SORT_BY_ALIGNMENT(.data.*) .gnu.linkonce.d.*) | 66 | # This will eliminate most of the data padding (~3kb). |
| 74 | # *(.bss SORT_BY_ALIGNMENT(.bss.*) .gnu.linkonce.b.*) | 67 | try "$l_list -Wl,--verbose -Wl,-T -Wl,busybox_ldscript" "$@" >busybox_ld.out |
| 75 | # This will eliminate most of the data padding (~3kb). | 68 | fi |
| 76 | try "-Wl,--start-group $l_list -Wl,--end-group -Wl,--verbose -Wl,-T -Wl,busybox_ldscript" "$@" >busybox_ld.out | ||
| 77 | fi | ||
| 78 | ####} | ||
| 79 | ####rm busybox_ld.err | ||
| 80 | ####exit 0 # Ensure "success" exit code | ||
