aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.flags4
-rw-r--r--applets/individual.c2
-rw-r--r--archival/dpkg.c13
-rw-r--r--archival/libarchive/Kbuild.src2
-rw-r--r--archival/libarchive/filter_accept_reject_list.c8
-rw-r--r--archival/libarchive/get_header_tar.c8
-rw-r--r--archival/tar.c36
-rw-r--r--archival/unzip.c149
-rw-r--r--configs/TEST_nommu_defconfig1
-rw-r--r--configs/TEST_noprintf_defconfig1
-rw-r--r--configs/TEST_rh9_defconfig1
-rw-r--r--configs/android2_defconfig1
-rw-r--r--configs/android_defconfig1
-rw-r--r--configs/android_ndk_defconfig29
-rw-r--r--configs/cygwin_defconfig1
-rw-r--r--configs/freebsd_defconfig1
-rw-r--r--coreutils/od_bloaty.c2
-rw-r--r--coreutils/stat.c6
-rw-r--r--debianutils/run_parts.c15
-rw-r--r--editors/awk.c38
-rw-r--r--editors/sed.c97
-rw-r--r--editors/vi.c201
-rw-r--r--examples/mdev.conf10
-rw-r--r--examples/mdev_fat.conf9
-rw-r--r--findutils/find.c45
-rw-r--r--include/applets.src.h40
-rw-r--r--include/bb_archive.h1
-rw-r--r--include/bb_e2fs_defs.h63
-rw-r--r--include/busybox.h4
-rw-r--r--include/libbb.h46
-rw-r--r--include/platform.h9
-rw-r--r--libbb/appletlib.c8
-rw-r--r--libbb/correct_password.c9
-rw-r--r--libbb/lineedit.c6
-rw-r--r--libbb/make_directory.c7
-rw-r--r--libbb/missing_syscalls.c42
-rw-r--r--libbb/procps.c2
-rw-r--r--libbb/read_key.c15
-rw-r--r--libbb/setup_environment.c8
-rw-r--r--libbb/xfuncs_printf.c4
-rw-r--r--loginutils/add-remove-shell.c4
-rw-r--r--loginutils/getty.c9
-rw-r--r--loginutils/login.c3
-rw-r--r--loginutils/passwd.c1
-rw-r--r--loginutils/su.c3
-rw-r--r--miscutils/fbsplash.c27
-rw-r--r--miscutils/man.c14
-rw-r--r--miscutils/nandwrite.c2
-rw-r--r--miscutils/time.c1
-rw-r--r--modutils/modinfo.c25
-rw-r--r--networking/Config.src4
-rw-r--r--networking/brctl.c4
-rw-r--r--networking/ftpd.c3
-rw-r--r--networking/httpd.c2
-rw-r--r--networking/httpd_indexcgi.c1
-rw-r--r--networking/ifplugd.c6
-rw-r--r--networking/ifupdown.c2
-rw-r--r--networking/inetd.c2
-rw-r--r--networking/libiproute/ll_proto.c108
-rw-r--r--networking/ntpd.c51
-rw-r--r--networking/ntpd_simple.c1
-rw-r--r--networking/tftp.c64
-rw-r--r--networking/udhcp/common.h6
-rw-r--r--networking/udhcp/d6_dhcpc.c14
-rw-r--r--networking/udhcp/dhcpc.c23
-rw-r--r--networking/udhcp/dhcpc.h1
-rw-r--r--networking/udhcp/dhcpd.c8
-rw-r--r--networking/udhcp/socket.c10
-rw-r--r--networking/wget.c171
-rw-r--r--printutils/lpr.c30
-rw-r--r--procps/powertop.c2
-rw-r--r--procps/ps.c40
-rw-r--r--procps/sysctl.c32
-rw-r--r--runit/chpst.c1
-rw-r--r--scripts/kconfig/mconf.c2
-rw-r--r--shell/ash.c44
-rw-r--r--shell/ash_test/ash-redir/redirA.right2
-rwxr-xr-xshell/ash_test/ash-redir/redirA.tests11
-rw-r--r--shell/shell_common.c5
-rw-r--r--shell/shell_common.h2
-rwxr-xr-xtestsuite/awk.tests19
-rw-r--r--testsuite/du/du-k-works1
-rwxr-xr-xtestsuite/mkfs.minix.tests10
-rwxr-xr-xtestsuite/mount.tests27
-rwxr-xr-xtestsuite/sed.tests18
-rw-r--r--util-linux/Config.src7
-rw-r--r--util-linux/acpid.c1
-rw-r--r--util-linux/fbset.c26
-rw-r--r--util-linux/mdev.c249
-rw-r--r--util-linux/mkfs_ext2.c11
-rw-r--r--util-linux/mount.c49
-rw-r--r--util-linux/rdate.c23
-rw-r--r--util-linux/volume_id/Kbuild.src1
-rw-r--r--util-linux/volume_id/btrfs.c1
-rw-r--r--util-linux/volume_id/ext.c36
-rw-r--r--util-linux/volume_id/nilfs.c96
-rw-r--r--util-linux/volume_id/util.c34
-rw-r--r--util-linux/volume_id/volume_id.c3
-rw-r--r--util-linux/volume_id/volume_id_internal.h2
99 files changed, 1499 insertions, 801 deletions
diff --git a/Makefile.flags b/Makefile.flags
index 4cbef0597..fbb348a39 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -25,6 +25,7 @@ CFLAGS += $(call cc-option,-Wstrict-prototypes,)
25CFLAGS += $(call cc-option,-Wunused -Wunused-parameter,) 25CFLAGS += $(call cc-option,-Wunused -Wunused-parameter,)
26CFLAGS += $(call cc-option,-Wunused-function -Wunused-value,) 26CFLAGS += $(call cc-option,-Wunused-function -Wunused-value,)
27CFLAGS += $(call cc-option,-Wmissing-prototypes -Wmissing-declarations,) 27CFLAGS += $(call cc-option,-Wmissing-prototypes -Wmissing-declarations,)
28CFLAGS += $(call cc-option,-Wno-format-security,)
28# warn about C99 declaration after statement 29# warn about C99 declaration after statement
29CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) 30CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
30# If you want to add more -Wsomething above, make sure that it is 31# If you want to add more -Wsomething above, make sure that it is
@@ -52,6 +53,9 @@ CFLAGS += $(call cc-option,-fno-builtin-strlen -finline-limit=0 -fomit-frame-poi
52CFLAGS += $(call cc-option,-fno-guess-branch-probability,) 53CFLAGS += $(call cc-option,-fno-guess-branch-probability,)
53CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,) 54CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,)
54CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,) 55CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,)
56# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary):
57CFLAGS += $(call cc-option,-fno-unwind-tables,)
58CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,)
55 59
56# FIXME: These warnings are at least partially to be concerned about and should 60# FIXME: These warnings are at least partially to be concerned about and should
57# be fixed.. 61# be fixed..
diff --git a/applets/individual.c b/applets/individual.c
index 1e74e4ce5..4c468df06 100644
--- a/applets/individual.c
+++ b/applets/individual.c
@@ -14,7 +14,7 @@ const char *applet_name;
14int main(int argc, char **argv) 14int main(int argc, char **argv)
15{ 15{
16 applet_name = argv[0]; 16 applet_name = argv[0];
17 return APPLET_main(argc,argv); 17 return APPLET_main(argc, argv);
18} 18}
19 19
20void bb_show_usage(void) 20void bb_show_usage(void)
diff --git a/archival/dpkg.c b/archival/dpkg.c
index bf9e9992c..dae8a9747 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1665,20 +1665,25 @@ static void unpack_package(deb_file_t *deb_file)
1665 archive_handle = init_archive_deb_ar(deb_file->filename); 1665 archive_handle = init_archive_deb_ar(deb_file->filename);
1666 init_archive_deb_data(archive_handle); 1666 init_archive_deb_data(archive_handle);
1667 archive_handle->dpkg__sub_archive->accept = conffile_list; 1667 archive_handle->dpkg__sub_archive->accept = conffile_list;
1668 /* Why ARCHIVE_REMEMBER_NAMES?
1669 * We want names collected in ->passed list even if conffile_list
1670 * is NULL (otherwise get_header_tar may optimize name saving out):
1671 */
1672 archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_REMEMBER_NAMES | ARCHIVE_UNLINK_OLD;
1668 archive_handle->dpkg__sub_archive->filter = filter_rename_config; 1673 archive_handle->dpkg__sub_archive->filter = filter_rename_config;
1669 archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; 1674 archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
1670 archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */ 1675 archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */
1671 archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
1672 unpack_ar_archive(archive_handle); 1676 unpack_ar_archive(archive_handle);
1673 1677
1674 /* Create the list file */ 1678 /* Create the list file */
1675 list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list"); 1679 list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list");
1676 out_stream = xfopen_for_write(list_filename); 1680 out_stream = xfopen_for_write(list_filename);
1681 archive_handle->dpkg__sub_archive->passed = llist_rev(archive_handle->dpkg__sub_archive->passed);
1677 while (archive_handle->dpkg__sub_archive->passed) { 1682 while (archive_handle->dpkg__sub_archive->passed) {
1683 char *filename = llist_pop(&archive_handle->dpkg__sub_archive->passed);
1678 /* the leading . has been stripped by data_extract_all_prefix already */ 1684 /* the leading . has been stripped by data_extract_all_prefix already */
1679 fputs(archive_handle->dpkg__sub_archive->passed->data, out_stream); 1685 fprintf(out_stream, "%s\n", filename);
1680 fputc('\n', out_stream); 1686 free(filename);
1681 archive_handle->dpkg__sub_archive->passed = archive_handle->dpkg__sub_archive->passed->link;
1682 } 1687 }
1683 fclose(out_stream); 1688 fclose(out_stream);
1684 1689
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index e2134be4c..58457fc22 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -45,7 +45,7 @@ lib-$(CONFIG_UNXZ) += decompress_unxz.o
45lib-$(CONFIG_CPIO) += get_header_cpio.o 45lib-$(CONFIG_CPIO) += get_header_cpio.o
46lib-$(CONFIG_DPKG) += $(DPKG_FILES) 46lib-$(CONFIG_DPKG) += $(DPKG_FILES)
47lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) 47lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
48lib-$(CONFIG_GUNZIP) += decompress_gunzip.o 48lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o
49lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o 49lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o
50lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o 50lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o
51lib-$(CONFIG_TAR) += get_header_tar.o 51lib-$(CONFIG_TAR) += get_header_tar.o
diff --git a/archival/libarchive/filter_accept_reject_list.c b/archival/libarchive/filter_accept_reject_list.c
index 39c811337..248374941 100644
--- a/archival/libarchive/filter_accept_reject_list.c
+++ b/archival/libarchive/filter_accept_reject_list.c
@@ -24,11 +24,13 @@ char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle)
24 if (reject_entry) { 24 if (reject_entry) {
25 return EXIT_FAILURE; 25 return EXIT_FAILURE;
26 } 26 }
27 accept_entry = find_list_entry2(archive_handle->accept, key);
28 27
29 /* Fail if an accept list was specified and the key wasnt in there */ 28 /* Fail if an accept list was specified and the key wasnt in there */
30 if ((accept_entry == NULL) && archive_handle->accept) { 29 if (archive_handle->accept) {
31 return EXIT_FAILURE; 30 accept_entry = find_list_entry2(archive_handle->accept, key);
31 if (!accept_entry) {
32 return EXIT_FAILURE;
33 }
32 } 34 }
33 35
34 /* Accepted */ 36 /* Accepted */
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index 80a709144..bc09756ba 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -84,7 +84,7 @@ static unsigned long long getOctal(char *str, int len)
84 first >>= 1; /* now 7th bit = 6th bit */ 84 first >>= 1; /* now 7th bit = 6th bit */
85 v = first; /* sign-extend 8 bits to 64 */ 85 v = first; /* sign-extend 8 bits to 64 */
86 while (--len != 0) 86 while (--len != 0)
87 v = (v << 8) + (unsigned char) *str++; 87 v = (v << 8) + (uint8_t) *++str;
88 } 88 }
89 return v; 89 return v;
90} 90}
@@ -452,9 +452,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
452 if (cp) 452 if (cp)
453 *cp = '\0'; 453 *cp = '\0';
454 archive_handle->action_data(archive_handle); 454 archive_handle->action_data(archive_handle);
455 if (archive_handle->accept || archive_handle->reject) 455 if (archive_handle->accept || archive_handle->reject
456 || (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES)
457 ) {
456 llist_add_to(&archive_handle->passed, file_header->name); 458 llist_add_to(&archive_handle->passed, file_header->name);
457 else /* Caller isn't interested in list of unpacked files */ 459 } else /* Caller isn't interested in list of unpacked files */
458 free(file_header->name); 460 free(file_header->name);
459 } else { 461 } else {
460 data_skip(archive_handle); 462 data_skip(archive_handle);
diff --git a/archival/tar.c b/archival/tar.c
index 9fa5a0f44..e27950b6c 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -60,8 +60,8 @@
60 60
61#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2 61#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
62/* Do not pass gzip flag to writeTarFile() */ 62/* Do not pass gzip flag to writeTarFile() */
63#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \ 63#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
64 writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude) 64 writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
65#endif 65#endif
66 66
67 67
@@ -600,7 +600,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip)
600 600
601/* gcc 4.2.1 inlines it, making code bigger */ 601/* gcc 4.2.1 inlines it, making code bigger */
602static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, 602static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
603 int dereferenceFlag, const llist_t *include, 603 int recurseFlags, const llist_t *include,
604 const llist_t *exclude, int gzip) 604 const llist_t *exclude, int gzip)
605{ 605{
606 int errorFlag = FALSE; 606 int errorFlag = FALSE;
@@ -623,8 +623,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
623 623
624 /* Read the directory/files and iterate over them one at a time */ 624 /* Read the directory/files and iterate over them one at a time */
625 while (include) { 625 while (include) {
626 if (!recursive_action(include->data, ACTION_RECURSE | 626 if (!recursive_action(include->data, recurseFlags,
627 (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
628 writeFileToTarball, writeFileToTarball, &tbInfo, 0) 627 writeFileToTarball, writeFileToTarball, &tbInfo, 0)
629 ) { 628 ) {
630 errorFlag = TRUE; 629 errorFlag = TRUE;
@@ -664,7 +663,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
664} 663}
665#else 664#else
666int writeTarFile(int tar_fd, int verboseFlag, 665int writeTarFile(int tar_fd, int verboseFlag,
667 int dereferenceFlag, const llist_t *include, 666 int recurseFlags, const llist_t *include,
668 const llist_t *exclude, int gzip); 667 const llist_t *exclude, int gzip);
669#endif /* FEATURE_TAR_CREATE */ 668#endif /* FEATURE_TAR_CREATE */
670 669
@@ -696,6 +695,7 @@ static llist_t *append_file_list_to_list(llist_t *list)
696//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" 695//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt"
697//usage: IF_FEATURE_SEAMLESS_Z("Z") 696//usage: IF_FEATURE_SEAMLESS_Z("Z")
698//usage: IF_FEATURE_SEAMLESS_GZ("z") 697//usage: IF_FEATURE_SEAMLESS_GZ("z")
698//usage: IF_FEATURE_SEAMLESS_XZ("J")
699//usage: IF_FEATURE_SEAMLESS_BZ2("j") 699//usage: IF_FEATURE_SEAMLESS_BZ2("j")
700//usage: IF_FEATURE_SEAMLESS_LZMA("a") 700//usage: IF_FEATURE_SEAMLESS_LZMA("a")
701//usage: IF_FEATURE_TAR_CREATE("h") 701//usage: IF_FEATURE_TAR_CREATE("h")
@@ -722,6 +722,9 @@ static llist_t *append_file_list_to_list(llist_t *list)
722//usage: IF_FEATURE_SEAMLESS_GZ( 722//usage: IF_FEATURE_SEAMLESS_GZ(
723//usage: "\n z (De)compress using gzip" 723//usage: "\n z (De)compress using gzip"
724//usage: ) 724//usage: )
725//usage: IF_FEATURE_SEAMLESS_XZ(
726//usage: "\n J (De)compress using xz"
727//usage: )
725//usage: IF_FEATURE_SEAMLESS_BZ2( 728//usage: IF_FEATURE_SEAMLESS_BZ2(
726//usage: "\n j (De)compress using bzip2" 729//usage: "\n j (De)compress using bzip2"
727//usage: ) 730//usage: )
@@ -751,6 +754,7 @@ static llist_t *append_file_list_to_list(llist_t *list)
751// o no-same-owner 754// o no-same-owner
752// p same-permissions 755// p same-permissions
753// k keep-old 756// k keep-old
757// no-recursion
754// numeric-owner 758// numeric-owner
755// no-same-permissions 759// no-same-permissions
756// overwrite 760// overwrite
@@ -767,9 +771,11 @@ enum {
767 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,) 771 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
768 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,) 772 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
769 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,) 773 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
770 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit 774 IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,) // 16th bit
775 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,)
771 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) 776 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
772#if ENABLE_FEATURE_TAR_LONG_OPTIONS 777#if ENABLE_FEATURE_TAR_LONG_OPTIONS
778 OPTBIT_NORECURSION,
773 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) 779 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
774 OPTBIT_NUMERIC_OWNER, 780 OPTBIT_NUMERIC_OWNER,
775 OPTBIT_NOPRESERVE_PERM, 781 OPTBIT_NOPRESERVE_PERM,
@@ -791,14 +797,16 @@ enum {
791 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0, // T 797 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
792 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X 798 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
793 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z 799 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z
800 OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0, // J
794 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z 801 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z
795 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m 802 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
803 OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0, // no-recursion
796 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command 804 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command
797 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner 805 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner
798 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions 806 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
799 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite 807 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite
800 808
801 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_COMPRESS), 809 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
802}; 810};
803#if ENABLE_FEATURE_TAR_LONG_OPTIONS 811#if ENABLE_FEATURE_TAR_LONG_OPTIONS
804static const char tar_longopts[] ALIGN1 = 812static const char tar_longopts[] ALIGN1 =
@@ -831,12 +839,16 @@ static const char tar_longopts[] ALIGN1 =
831# if ENABLE_FEATURE_SEAMLESS_GZ 839# if ENABLE_FEATURE_SEAMLESS_GZ
832 "gzip\0" No_argument "z" 840 "gzip\0" No_argument "z"
833# endif 841# endif
842# if ENABLE_FEATURE_SEAMLESS_XZ
843 "xz\0" No_argument "J"
844# endif
834# if ENABLE_FEATURE_SEAMLESS_Z 845# if ENABLE_FEATURE_SEAMLESS_Z
835 "compress\0" No_argument "Z" 846 "compress\0" No_argument "Z"
836# endif 847# endif
837# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME 848# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
838 "touch\0" No_argument "m" 849 "touch\0" No_argument "m"
839# endif 850# endif
851 "no-recursion\0" No_argument "\xfa"
840# if ENABLE_FEATURE_TAR_TO_COMMAND 852# if ENABLE_FEATURE_TAR_TO_COMMAND
841 "to-command\0" Required_argument "\xfb" 853 "to-command\0" Required_argument "\xfb"
842# endif 854# endif
@@ -923,6 +935,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
923 IF_FEATURE_SEAMLESS_LZMA("a" ) 935 IF_FEATURE_SEAMLESS_LZMA("a" )
924 IF_FEATURE_TAR_FROM( "T:X:") 936 IF_FEATURE_TAR_FROM( "T:X:")
925 IF_FEATURE_SEAMLESS_GZ( "z" ) 937 IF_FEATURE_SEAMLESS_GZ( "z" )
938 IF_FEATURE_SEAMLESS_XZ( "J" )
926 IF_FEATURE_SEAMLESS_Z( "Z" ) 939 IF_FEATURE_SEAMLESS_Z( "Z" )
927 IF_FEATURE_TAR_NOPRESERVE_TIME("m") 940 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
928 , &base_dir // -C dir 941 , &base_dir // -C dir
@@ -1052,7 +1065,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1052 zipMode = 2; 1065 zipMode = 2;
1053#endif 1066#endif
1054 /* NB: writeTarFile() closes tar_handle->src_fd */ 1067 /* NB: writeTarFile() closes tar_handle->src_fd */
1055 return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, 1068 return writeTarFile(tar_handle->src_fd, verboseFlag,
1069 (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
1070 | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
1056 tar_handle->accept, 1071 tar_handle->accept,
1057 tar_handle->reject, zipMode); 1072 tar_handle->reject, zipMode);
1058 } 1073 }
@@ -1073,6 +1088,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1073 if (opt & OPT_LZMA) 1088 if (opt & OPT_LZMA)
1074 USE_FOR_MMU(xformer = unpack_lzma_stream;) 1089 USE_FOR_MMU(xformer = unpack_lzma_stream;)
1075 USE_FOR_NOMMU(xformer_prog = "unlzma";) 1090 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1091 if (opt & OPT_XZ)
1092 USE_FOR_MMU(xformer = unpack_xz_stream;)
1093 USE_FOR_NOMMU(xformer_prog = "unxz";)
1076 1094
1077 open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); 1095 open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1078 /* Can't lseek over pipes */ 1096 /* Can't lseek over pipes */
diff --git a/archival/unzip.c b/archival/unzip.c
index 3c76cdafc..046027cc6 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -20,16 +20,16 @@
20 */ 20 */
21 21
22//usage:#define unzip_trivial_usage 22//usage:#define unzip_trivial_usage
23//usage: "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-d DIR]" 23//usage: "[-lnopq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]"
24//usage:#define unzip_full_usage "\n\n" 24//usage:#define unzip_full_usage "\n\n"
25//usage: "Extract files from ZIP archives\n" 25//usage: "Extract FILEs from ZIP archive\n"
26//usage: "\n -l List archive contents (with -q for short form)" 26//usage: "\n -l List contents (with -q for short form)"
27//usage: "\n -n Never overwrite files (default)" 27//usage: "\n -n Never overwrite files (default: ask)"
28//usage: "\n -o Overwrite" 28//usage: "\n -o Overwrite"
29//usage: "\n -p Send output to stdout" 29//usage: "\n -p Print to stdout"
30//usage: "\n -q Quiet" 30//usage: "\n -q Quiet"
31//usage: "\n -x XLST Exclude these files" 31//usage: "\n -x FILE Exclude FILEs"
32//usage: "\n -d DIR Extract files into DIR" 32//usage: "\n -d DIR Extract into DIR"
33 33
34#include "libbb.h" 34#include "libbb.h"
35#include "bb_archive.h" 35#include "bb_archive.h"
@@ -277,6 +277,7 @@ int unzip_main(int argc, char **argv)
277 IF_NOT_DESKTOP(const) smallint verbose = 0; 277 IF_NOT_DESKTOP(const) smallint verbose = 0;
278 smallint listing = 0; 278 smallint listing = 0;
279 smallint overwrite = O_PROMPT; 279 smallint overwrite = O_PROMPT;
280 smallint x_opt_seen;
280#if ENABLE_DESKTOP 281#if ENABLE_DESKTOP
281 uint32_t cdf_offset; 282 uint32_t cdf_offset;
282#endif 283#endif
@@ -290,7 +291,6 @@ int unzip_main(int argc, char **argv)
290 llist_t *zreject = NULL; 291 llist_t *zreject = NULL;
291 char *base_dir = NULL; 292 char *base_dir = NULL;
292 int i, opt; 293 int i, opt;
293 int opt_range = 0;
294 char key_buf[80]; 294 char key_buf[80];
295 struct stat stat_buf; 295 struct stat stat_buf;
296 296
@@ -335,81 +335,81 @@ int unzip_main(int argc, char **argv)
335 * 204372 1 file 335 * 204372 1 file
336 */ 336 */
337 337
338 x_opt_seen = 0;
338 /* '-' makes getopt return 1 for non-options */ 339 /* '-' makes getopt return 1 for non-options */
339 while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) { 340 while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
340 switch (opt_range) { 341 switch (opt) {
341 case 0: /* Options */ 342 case 'd': /* Extract to base directory */
342 switch (opt) { 343 base_dir = optarg;
343 case 'l': /* List */ 344 break;
344 listing = 1;
345 break;
346 345
347 case 'n': /* Never overwrite existing files */ 346 case 'l': /* List */
348 overwrite = O_NEVER; 347 listing = 1;
349 break; 348 break;
350 349
351 case 'o': /* Always overwrite existing files */ 350 case 'n': /* Never overwrite existing files */
352 overwrite = O_ALWAYS; 351 overwrite = O_NEVER;
353 break; 352 break;
354 353
355 case 'p': /* Extract files to stdout and fall through to set verbosity */ 354 case 'o': /* Always overwrite existing files */
356 dst_fd = STDOUT_FILENO; 355 overwrite = O_ALWAYS;
356 break;
357 357
358 case 'q': /* Be quiet */ 358 case 'p': /* Extract files to stdout and fall through to set verbosity */
359 quiet++; 359 dst_fd = STDOUT_FILENO;
360 break;
361 360
362 case 'v': /* Verbose list */ 361 case 'q': /* Be quiet */
363 IF_DESKTOP(verbose++;) 362 quiet++;
364 listing = 1; 363 break;
365 break;
366 364
367 case 1: /* The zip file */ 365 case 'v': /* Verbose list */
368 /* +5: space for ".zip" and NUL */ 366 IF_DESKTOP(verbose++;)
369 src_fn = xmalloc(strlen(optarg) + 5); 367 listing = 1;
370 strcpy(src_fn, optarg); 368 break;
371 opt_range++;
372 break;
373 369
374 default: 370 case 'x':
375 bb_show_usage(); 371 x_opt_seen = 1;
376 }
377 break; 372 break;
378 373
379 case 1: /* Include files */ 374 case 1:
380 if (opt == 1) { 375 if (!src_fn) {
376 /* The zip file */
377 /* +5: space for ".zip" and NUL */
378 src_fn = xmalloc(strlen(optarg) + 5);
379 strcpy(src_fn, optarg);
380 } else if (!x_opt_seen) {
381 /* Include files */
381 llist_add_to(&zaccept, optarg); 382 llist_add_to(&zaccept, optarg);
382 break; 383 } else {
383 } 384 /* Exclude files */
384 if (opt == 'd') {
385 base_dir = optarg;
386 opt_range += 2;
387 break;
388 }
389 if (opt == 'x') {
390 opt_range++;
391 break;
392 }
393 bb_show_usage();
394
395 case 2 : /* Exclude files */
396 if (opt == 1) {
397 llist_add_to(&zreject, optarg); 385 llist_add_to(&zreject, optarg);
398 break;
399 } 386 }
400 if (opt == 'd') { /* Extract to base directory */ 387 break;
401 base_dir = optarg;
402 opt_range++;
403 break;
404 }
405 /* fall through */
406 388
407 default: 389 default:
408 bb_show_usage(); 390 bb_show_usage();
409 } 391 }
410 } 392 }
411 393
412 if (src_fn == NULL) { 394#ifndef __GLIBC__
395 /*
396 * This code is needed for non-GNU getopt
397 * which doesn't understand "-" in option string.
398 * The -x option won't work properly in this case:
399 * "unzip a.zip q -x w e" will be interpreted as
400 * "unzip a.zip q w e -x" = "unzip a.zip q w e"
401 */
402 argv += optind;
403 if (argv[0]) {
404 /* +5: space for ".zip" and NUL */
405 src_fn = xmalloc(strlen(argv[0]) + 5);
406 strcpy(src_fn, argv[0]);
407 while (*++argv)
408 llist_add_to(&zaccept, *argv);
409 }
410#endif
411
412 if (!src_fn) {
413 bb_show_usage(); 413 bb_show_usage();
414 } 414 }
415 415
@@ -420,17 +420,20 @@ int unzip_main(int argc, char **argv)
420 if (overwrite == O_PROMPT) 420 if (overwrite == O_PROMPT)
421 overwrite = O_NEVER; 421 overwrite = O_NEVER;
422 } else { 422 } else {
423 static const char extn[][5] = {"", ".zip", ".ZIP"}; 423 static const char extn[][5] = { ".zip", ".ZIP" };
424 int orig_src_fn_len = strlen(src_fn); 424 char *ext = src_fn + strlen(src_fn);
425 int src_fd = -1; 425 int src_fd;
426 426
427 for (i = 0; (i < 3) && (src_fd == -1); i++) { 427 i = 0;
428 strcpy(src_fn + orig_src_fn_len, extn[i]); 428 for (;;) {
429 src_fd = open(src_fn, O_RDONLY); 429 src_fd = open(src_fn, O_RDONLY);
430 } 430 if (src_fd >= 0)
431 if (src_fd == -1) { 431 break;
432 src_fn[orig_src_fn_len] = '\0'; 432 if (++i > 2) {
433 bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn); 433 *ext = '\0';
434 bb_error_msg_and_die("can't open %s[.zip]", src_fn);
435 }
436 strcpy(ext, extn[i - 1]);
434 } 437 }
435 xmove_fd(src_fd, zip_fd); 438 xmove_fd(src_fd, zip_fd);
436 } 439 }
@@ -596,7 +599,7 @@ int unzip_main(int argc, char **argv)
596 printf(" creating: %s\n", dst_fn); 599 printf(" creating: %s\n", dst_fn);
597 } 600 }
598 unzip_create_leading_dirs(dst_fn); 601 unzip_create_leading_dirs(dst_fn);
599 if (bb_make_directory(dst_fn, dir_mode, 0)) { 602 if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
600 xfunc_die(); 603 xfunc_die();
601 } 604 }
602 } else { 605 } else {
diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig
index 15e12b1d2..b45afd956 100644
--- a/configs/TEST_nommu_defconfig
+++ b/configs/TEST_nommu_defconfig
@@ -341,7 +341,6 @@ CONFIG_FEATURE_VI_READONLY=y
341CONFIG_FEATURE_VI_SETOPTS=y 341CONFIG_FEATURE_VI_SETOPTS=y
342CONFIG_FEATURE_VI_SET=y 342CONFIG_FEATURE_VI_SET=y
343CONFIG_FEATURE_VI_WIN_RESIZE=y 343CONFIG_FEATURE_VI_WIN_RESIZE=y
344CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
345CONFIG_FEATURE_ALLOW_EXEC=y 344CONFIG_FEATURE_ALLOW_EXEC=y
346 345
347# 346#
diff --git a/configs/TEST_noprintf_defconfig b/configs/TEST_noprintf_defconfig
index f4338df71..809b60cd8 100644
--- a/configs/TEST_noprintf_defconfig
+++ b/configs/TEST_noprintf_defconfig
@@ -346,7 +346,6 @@ CONFIG_FEATURE_VI_MAX_LEN=0
346# CONFIG_FEATURE_VI_SET is not set 346# CONFIG_FEATURE_VI_SET is not set
347# CONFIG_FEATURE_VI_WIN_RESIZE is not set 347# CONFIG_FEATURE_VI_WIN_RESIZE is not set
348# CONFIG_FEATURE_VI_ASK_TERMINAL is not set 348# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
349# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set
350# CONFIG_FEATURE_ALLOW_EXEC is not set 349# CONFIG_FEATURE_ALLOW_EXEC is not set
351 350
352# 351#
diff --git a/configs/TEST_rh9_defconfig b/configs/TEST_rh9_defconfig
index 193d8f615..565b826d0 100644
--- a/configs/TEST_rh9_defconfig
+++ b/configs/TEST_rh9_defconfig
@@ -358,7 +358,6 @@ CONFIG_FEATURE_VI_READONLY=y
358CONFIG_FEATURE_VI_SETOPTS=y 358CONFIG_FEATURE_VI_SETOPTS=y
359CONFIG_FEATURE_VI_SET=y 359CONFIG_FEATURE_VI_SET=y
360CONFIG_FEATURE_VI_WIN_RESIZE=y 360CONFIG_FEATURE_VI_WIN_RESIZE=y
361CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
362CONFIG_FEATURE_ALLOW_EXEC=y 361CONFIG_FEATURE_ALLOW_EXEC=y
363 362
364# 363#
diff --git a/configs/android2_defconfig b/configs/android2_defconfig
index b5166e0fc..4dfbdb526 100644
--- a/configs/android2_defconfig
+++ b/configs/android2_defconfig
@@ -363,7 +363,6 @@ CONFIG_FEATURE_VI_MAX_LEN=0
363# CONFIG_FEATURE_VI_SET is not set 363# CONFIG_FEATURE_VI_SET is not set
364# CONFIG_FEATURE_VI_WIN_RESIZE is not set 364# CONFIG_FEATURE_VI_WIN_RESIZE is not set
365# CONFIG_FEATURE_VI_ASK_TERMINAL is not set 365# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
366# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set
367# CONFIG_AWK is not set 366# CONFIG_AWK is not set
368# CONFIG_FEATURE_AWK_LIBM is not set 367# CONFIG_FEATURE_AWK_LIBM is not set
369CONFIG_CMP=y 368CONFIG_CMP=y
diff --git a/configs/android_defconfig b/configs/android_defconfig
index a9a8d5e1f..e35830e7f 100644
--- a/configs/android_defconfig
+++ b/configs/android_defconfig
@@ -386,7 +386,6 @@ CONFIG_FEATURE_VI_SETOPTS=y
386CONFIG_FEATURE_VI_SET=y 386CONFIG_FEATURE_VI_SET=y
387CONFIG_FEATURE_VI_WIN_RESIZE=y 387CONFIG_FEATURE_VI_WIN_RESIZE=y
388CONFIG_FEATURE_VI_ASK_TERMINAL=y 388CONFIG_FEATURE_VI_ASK_TERMINAL=y
389CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
390CONFIG_AWK=y 389CONFIG_AWK=y
391CONFIG_FEATURE_AWK_LIBM=y 390CONFIG_FEATURE_AWK_LIBM=y
392CONFIG_CMP=y 391CONFIG_CMP=y
diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig
index bf8827a58..01cc2dd15 100644
--- a/configs/android_ndk_defconfig
+++ b/configs/android_ndk_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.20.0.git 3# Busybox version: 1.21.0.git
4# Fri Mar 2 16:53:26 2012 4# Mon May 28 21:51:18 2012
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7 7
@@ -20,11 +20,11 @@ CONFIG_PLATFORM_LINUX=y
20CONFIG_FEATURE_BUFFERS_USE_MALLOC=y 20CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
21# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set 21# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
22# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set 22# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
23# CONFIG_SHOW_USAGE is not set 23CONFIG_SHOW_USAGE=y
24# CONFIG_FEATURE_VERBOSE_USAGE is not set 24CONFIG_FEATURE_VERBOSE_USAGE=y
25# CONFIG_FEATURE_COMPRESS_USAGE is not set 25CONFIG_FEATURE_COMPRESS_USAGE=y
26# CONFIG_FEATURE_INSTALLER is not set 26CONFIG_FEATURE_INSTALLER=y
27# CONFIG_INSTALL_NO_USR is not set 27CONFIG_INSTALL_NO_USR=y
28# CONFIG_LOCALE_SUPPORT is not set 28# CONFIG_LOCALE_SUPPORT is not set
29# CONFIG_UNICODE_SUPPORT is not set 29# CONFIG_UNICODE_SUPPORT is not set
30# CONFIG_UNICODE_USING_LOCALE is not set 30# CONFIG_UNICODE_USING_LOCALE is not set
@@ -36,7 +36,7 @@ CONFIG_LAST_SUPPORTED_WCHAR=0
36# CONFIG_UNICODE_BIDI_SUPPORT is not set 36# CONFIG_UNICODE_BIDI_SUPPORT is not set
37# CONFIG_UNICODE_NEUTRAL_TABLE is not set 37# CONFIG_UNICODE_NEUTRAL_TABLE is not set
38# CONFIG_UNICODE_PRESERVE_BROKEN is not set 38# CONFIG_UNICODE_PRESERVE_BROKEN is not set
39# CONFIG_LONG_OPTS is not set 39CONFIG_LONG_OPTS=y
40# CONFIG_FEATURE_DEVPTS is not set 40# CONFIG_FEATURE_DEVPTS is not set
41# CONFIG_FEATURE_CLEAN_UP is not set 41# CONFIG_FEATURE_CLEAN_UP is not set
42# CONFIG_FEATURE_UTMP is not set 42# CONFIG_FEATURE_UTMP is not set
@@ -67,7 +67,6 @@ CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7
67CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o" 67CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o"
68CONFIG_EXTRA_LDLIBS="dl m c gcc" 68CONFIG_EXTRA_LDLIBS="dl m c gcc"
69 69
70
71# 70#
72# Debugging Options 71# Debugging Options
73# 72#
@@ -112,7 +111,7 @@ CONFIG_FEATURE_EDITING_HISTORY=0
112# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set 111# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
113# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set 112# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
114# CONFIG_FEATURE_NON_POSIX_CP is not set 113# CONFIG_FEATURE_NON_POSIX_CP is not set
115# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set 114CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y
116CONFIG_FEATURE_COPYBUF_KB=4 115CONFIG_FEATURE_COPYBUF_KB=4
117# CONFIG_FEATURE_SKIP_ROOTFS is not set 116# CONFIG_FEATURE_SKIP_ROOTFS is not set
118# CONFIG_MONOTONIC_SYSCALL is not set 117# CONFIG_MONOTONIC_SYSCALL is not set
@@ -239,7 +238,7 @@ CONFIG_FEATURE_LS_RECURSIVE=y
239CONFIG_FEATURE_LS_SORTFILES=y 238CONFIG_FEATURE_LS_SORTFILES=y
240CONFIG_FEATURE_LS_TIMESTAMPS=y 239CONFIG_FEATURE_LS_TIMESTAMPS=y
241CONFIG_FEATURE_LS_USERNAME=y 240CONFIG_FEATURE_LS_USERNAME=y
242# CONFIG_FEATURE_LS_COLOR is not set 241CONFIG_FEATURE_LS_COLOR=y
243# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set 242# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
244CONFIG_MD5SUM=y 243CONFIG_MD5SUM=y
245CONFIG_MKDIR=y 244CONFIG_MKDIR=y
@@ -372,7 +371,6 @@ CONFIG_FEATURE_VI_SETOPTS=y
372CONFIG_FEATURE_VI_SET=y 371CONFIG_FEATURE_VI_SET=y
373CONFIG_FEATURE_VI_WIN_RESIZE=y 372CONFIG_FEATURE_VI_WIN_RESIZE=y
374CONFIG_FEATURE_VI_ASK_TERMINAL=y 373CONFIG_FEATURE_VI_ASK_TERMINAL=y
375CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
376CONFIG_AWK=y 374CONFIG_AWK=y
377CONFIG_FEATURE_AWK_LIBM=y 375CONFIG_FEATURE_AWK_LIBM=y
378CONFIG_CMP=y 376CONFIG_CMP=y
@@ -516,7 +514,7 @@ CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y
516# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set 514# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
517# CONFIG_FEATURE_MODUTILS_ALIAS is not set 515# CONFIG_FEATURE_MODUTILS_ALIAS is not set
518# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set 516# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
519CONFIG_DEFAULT_MODULES_DIR="/lib/modules" 517CONFIG_DEFAULT_MODULES_DIR="/system/lib/modules"
520CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" 518CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
521 519
522# 520#
@@ -647,8 +645,8 @@ CONFIG_SETSERIAL=y
647# CONFIG_UBIRSVOL is not set 645# CONFIG_UBIRSVOL is not set
648# CONFIG_UBIUPDATEVOL is not set 646# CONFIG_UBIUPDATEVOL is not set
649# CONFIG_ADJTIMEX is not set 647# CONFIG_ADJTIMEX is not set
650# CONFIG_BBCONFIG is not set 648CONFIG_BBCONFIG=y
651# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set 649CONFIG_FEATURE_COMPRESS_BBCONFIG=y
652CONFIG_BEEP=y 650CONFIG_BEEP=y
653CONFIG_FEATURE_BEEP_FREQ=4000 651CONFIG_FEATURE_BEEP_FREQ=4000
654CONFIG_FEATURE_BEEP_LENGTH_MS=30 652CONFIG_FEATURE_BEEP_LENGTH_MS=30
@@ -883,6 +881,7 @@ CONFIG_SENDMAIL=y
883# Process Utilities 881# Process Utilities
884# 882#
885CONFIG_IOSTAT=y 883CONFIG_IOSTAT=y
884CONFIG_LSOF=y
886CONFIG_MPSTAT=y 885CONFIG_MPSTAT=y
887CONFIG_NMETER=y 886CONFIG_NMETER=y
888CONFIG_PMAP=y 887CONFIG_PMAP=y
diff --git a/configs/cygwin_defconfig b/configs/cygwin_defconfig
index bdd0d66d0..aa346e34c 100644
--- a/configs/cygwin_defconfig
+++ b/configs/cygwin_defconfig
@@ -363,7 +363,6 @@ CONFIG_FEATURE_VI_SETOPTS=y
363CONFIG_FEATURE_VI_SET=y 363CONFIG_FEATURE_VI_SET=y
364CONFIG_FEATURE_VI_WIN_RESIZE=y 364CONFIG_FEATURE_VI_WIN_RESIZE=y
365CONFIG_FEATURE_VI_ASK_TERMINAL=y 365CONFIG_FEATURE_VI_ASK_TERMINAL=y
366CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
367CONFIG_AWK=y 366CONFIG_AWK=y
368CONFIG_FEATURE_AWK_LIBM=y 367CONFIG_FEATURE_AWK_LIBM=y
369CONFIG_CMP=y 368CONFIG_CMP=y
diff --git a/configs/freebsd_defconfig b/configs/freebsd_defconfig
index dcb5d953c..ec3ed03c4 100644
--- a/configs/freebsd_defconfig
+++ b/configs/freebsd_defconfig
@@ -367,7 +367,6 @@ CONFIG_FEATURE_VI_SETOPTS=y
367CONFIG_FEATURE_VI_SET=y 367CONFIG_FEATURE_VI_SET=y
368CONFIG_FEATURE_VI_WIN_RESIZE=y 368CONFIG_FEATURE_VI_WIN_RESIZE=y
369CONFIG_FEATURE_VI_ASK_TERMINAL=y 369CONFIG_FEATURE_VI_ASK_TERMINAL=y
370CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
371CONFIG_FEATURE_ALLOW_EXEC=y 370CONFIG_FEATURE_ALLOW_EXEC=y
372 371
373# 372#
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index 8497722ba..7a6f22b03 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -25,7 +25,7 @@
25 25
26//usage:#if ENABLE_DESKTOP 26//usage:#if ENABLE_DESKTOP
27//usage:#define od_trivial_usage 27//usage:#define od_trivial_usage
28//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE...]" 28//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..."
29// We don't support: 29// We don't support:
30// ... [FILE] [[+]OFFSET[.][b]] 30// ... [FILE] [[+]OFFSET[.][b]]
31// Support is buggy for: 31// Support is buggy for:
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 2797719dd..3fb212f0f 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -99,9 +99,15 @@ static const char *file_type(const struct stat *st)
99 if (S_ISFIFO(st->st_mode)) return "fifo"; 99 if (S_ISFIFO(st->st_mode)) return "fifo";
100 if (S_ISLNK(st->st_mode)) return "symbolic link"; 100 if (S_ISLNK(st->st_mode)) return "symbolic link";
101 if (S_ISSOCK(st->st_mode)) return "socket"; 101 if (S_ISSOCK(st->st_mode)) return "socket";
102#ifdef S_TYPEISMQ
102 if (S_TYPEISMQ(st)) return "message queue"; 103 if (S_TYPEISMQ(st)) return "message queue";
104#endif
105#ifdef S_TYPEISSEM
103 if (S_TYPEISSEM(st)) return "semaphore"; 106 if (S_TYPEISSEM(st)) return "semaphore";
107#endif
108#ifdef S_TYPEISSHM
104 if (S_TYPEISSHM(st)) return "shared memory object"; 109 if (S_TYPEISSHM(st)) return "shared memory object";
110#endif
105#ifdef S_TYPEISTMO 111#ifdef S_TYPEISTMO
106 if (S_TYPEISTMO(st)) return "typed memory object"; 112 if (S_TYPEISTMO(st)) return "typed memory object";
107#endif 113#endif
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 8f08f6dc6..005b30420 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -4,14 +4,13 @@
4 * 4 *
5 * Copyright (C) 2007 Bernhard Reutner-Fischer 5 * Copyright (C) 2007 Bernhard Reutner-Fischer
6 * 6 *
7 * Based on a older version that was in busybox which was 1k big.. 7 * Based on a older version that was in busybox which was 1k big.
8 * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it> 8 * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>
9 * 9 *
10 * Based on the Debian run-parts program, version 1.15 10 * Based on the Debian run-parts program, version 1.15
11 * Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>, 11 * Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>,
12 * Copyright (C) 1996-1999 Guy Maor <maor@debian.org> 12 * Copyright (C) 1996-1999 Guy Maor <maor@debian.org>
13 * 13 *
14 *
15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 14 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
16 */ 15 */
17 16
@@ -19,7 +18,7 @@
19 * attempt to write a program! :-) . */ 18 * attempt to write a program! :-) . */
20 19
21/* This piece of code is heavily based on the original version of run-parts, 20/* This piece of code is heavily based on the original version of run-parts,
22 * taken from debian-utils. I've only removed the long options and a the 21 * taken from debian-utils. I've only removed the long options and the
23 * report mode. As the original run-parts support only long options, I've 22 * report mode. As the original run-parts support only long options, I've
24 * broken compatibility because the BusyBox policy doesn't allow them. 23 * broken compatibility because the BusyBox policy doesn't allow them.
25 * The supported options are: 24 * The supported options are:
@@ -31,15 +30,15 @@
31 */ 30 */
32 31
33//usage:#define run_parts_trivial_usage 32//usage:#define run_parts_trivial_usage
34//usage: "[-t] "IF_FEATURE_RUN_PARTS_FANCY("[-l] ")"[-a ARG] [-u MASK] DIRECTORY" 33//usage: "[-t"IF_FEATURE_RUN_PARTS_FANCY("l")"] [-a ARG]... [-u MASK] DIRECTORY"
35//usage:#define run_parts_full_usage "\n\n" 34//usage:#define run_parts_full_usage "\n\n"
36//usage: "Run a bunch of scripts in DIRECTORY\n" 35//usage: "Run a bunch of scripts in DIRECTORY\n"
37//usage: "\n -t Print what would be run, but don't actually run anything" 36//usage: "\n -t Dry run"
38//usage: "\n -a ARG Pass ARG as argument for every program"
39//usage: "\n -u MASK Set the umask to MASK before running every program"
40//usage: IF_FEATURE_RUN_PARTS_FANCY( 37//usage: IF_FEATURE_RUN_PARTS_FANCY(
41//usage: "\n -l Print names of all matching files even if they are not executable" 38//usage: "\n -l Print names of matching files even if they are not executable"
42//usage: ) 39//usage: )
40//usage: "\n -a ARG Pass ARG as argument to programs"
41//usage: "\n -u MASK Set umask to MASK before running programs"
43//usage: 42//usage:
44//usage:#define run_parts_example_usage 43//usage:#define run_parts_example_usage
45//usage: "$ run-parts -a start /etc/init.d\n" 44//usage: "$ run-parts -a start /etc/init.d\n"
diff --git a/editors/awk.c b/editors/awk.c
index 71abca215..42f6ef866 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -696,6 +696,10 @@ static char nextchar(char **s)
696 pps = *s; 696 pps = *s;
697 if (c == '\\') 697 if (c == '\\')
698 c = bb_process_escape_sequence((const char**)s); 698 c = bb_process_escape_sequence((const char**)s);
699 /* Example awk statement:
700 * s = "abc\"def"
701 * we must treat \" as "
702 */
699 if (c == '\\' && *s == pps) { /* unrecognized \z? */ 703 if (c == '\\' && *s == pps) { /* unrecognized \z? */
700 c = *(*s); /* yes, fetch z */ 704 c = *(*s); /* yes, fetch z */
701 if (c) 705 if (c)
@@ -704,6 +708,15 @@ static char nextchar(char **s)
704 return c; 708 return c;
705} 709}
706 710
711/* TODO: merge with strcpy_and_process_escape_sequences()?
712 */
713static void unescape_string_in_place(char *s1)
714{
715 char *s = s1;
716 while ((*s1 = nextchar(&s)) != '\0')
717 s1++;
718}
719
707static ALWAYS_INLINE int isalnum_(int c) 720static ALWAYS_INLINE int isalnum_(int c)
708{ 721{
709 return (isalnum(c) || c == '_'); 722 return (isalnum(c) || c == '_');
@@ -1799,6 +1812,18 @@ static void handle_special(var *v)
1799 is_f0_split = FALSE; 1812 is_f0_split = FALSE;
1800 1813
1801 } else if (v == intvar[FS]) { 1814 } else if (v == intvar[FS]) {
1815 /*
1816 * The POSIX-2008 standard says that changing FS should have no effect on the
1817 * current input line, but only on the next one. The language is:
1818 *
1819 * > Before the first reference to a field in the record is evaluated, the record
1820 * > shall be split into fields, according to the rules in Regular Expressions,
1821 * > using the value of FS that was current at the time the record was read.
1822 *
1823 * So, split up current line before assignment to FS:
1824 */
1825 split_f0();
1826
1802 mk_splitter(getvar_s(v), &fsplitter); 1827 mk_splitter(getvar_s(v), &fsplitter);
1803 1828
1804 } else if (v == intvar[RS]) { 1829 } else if (v == intvar[RS]) {
@@ -2992,7 +3017,7 @@ static int awk_exit(int r)
2992 * otherwise return 0 */ 3017 * otherwise return 0 */
2993static int is_assignment(const char *expr) 3018static int is_assignment(const char *expr)
2994{ 3019{
2995 char *exprc, *val, *s, *s1; 3020 char *exprc, *val;
2996 3021
2997 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { 3022 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
2998 return FALSE; 3023 return FALSE;
@@ -3002,10 +3027,7 @@ static int is_assignment(const char *expr)
3002 val = exprc + (val - expr); 3027 val = exprc + (val - expr);
3003 *val++ = '\0'; 3028 *val++ = '\0';
3004 3029
3005 s = s1 = val; 3030 unescape_string_in_place(val);
3006 while ((*s1 = nextchar(&s)) != '\0')
3007 s1++;
3008
3009 setvar_u(newvar(exprc), val); 3031 setvar_u(newvar(exprc), val);
3010 free(exprc); 3032 free(exprc);
3011 return TRUE; 3033 return TRUE;
@@ -3118,8 +3140,10 @@ int awk_main(int argc, char **argv)
3118 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); 3140 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL);
3119 argv += optind; 3141 argv += optind;
3120 argc -= optind; 3142 argc -= optind;
3121 if (opt & 0x1) 3143 if (opt & 0x1) { /* -F */
3122 setvar_s(intvar[FS], opt_F); // -F 3144 unescape_string_in_place(opt_F);
3145 setvar_s(intvar[FS], opt_F);
3146 }
3123 while (list_v) { /* -v */ 3147 while (list_v) { /* -v */
3124 if (!is_assignment(llist_pop(&list_v))) 3148 if (!is_assignment(llist_pop(&list_v)))
3125 bb_show_usage(); 3149 bb_show_usage();
diff --git a/editors/sed.c b/editors/sed.c
index a2df93165..070af611a 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -53,7 +53,9 @@
53 * Todo: 53 * Todo:
54 * - Create a wrapper around regex to make libc's regex conform with sed 54 * - Create a wrapper around regex to make libc's regex conform with sed
55 * 55 *
56 * Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html 56 * Reference
57 * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
58 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
57 */ 59 */
58 60
59//usage:#define sed_trivial_usage 61//usage:#define sed_trivial_usage
@@ -63,7 +65,7 @@
63//usage: " -e CMD Add CMD to sed commands to be executed" 65//usage: " -e CMD Add CMD to sed commands to be executed"
64//usage: "\n -f FILE Add FILE contents to sed commands to be executed" 66//usage: "\n -f FILE Add FILE contents to sed commands to be executed"
65//usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" 67//usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)"
66//usage: "\n Optionally backs files up, appending SFX" 68//usage: "\n Optionally back files up, appending SFX"
67//usage: "\n -n Suppress automatic printing of pattern space" 69//usage: "\n -n Suppress automatic printing of pattern space"
68//usage: "\n -r Use extended regex syntax" 70//usage: "\n -r Use extended regex syntax"
69//usage: "\n" 71//usage: "\n"
@@ -492,8 +494,10 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
492 } 494 }
493 /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ 495 /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
494 else if (idx <= IDX_c) { /* a,i,c */ 496 else if (idx <= IDX_c) { /* a,i,c */
495 if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') 497 if (idx < IDX_c) { /* a,i */
496 bb_error_msg_and_die("only a beginning address can be specified for edit commands"); 498 if (sed_cmd->end_line || sed_cmd->end_match)
499 bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd);
500 }
497 for (;;) { 501 for (;;) {
498 if (*cmdstr == '\n' || *cmdstr == '\\') { 502 if (*cmdstr == '\n' || *cmdstr == '\\') {
499 cmdstr++; 503 cmdstr++;
@@ -510,8 +514,10 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
510 } 514 }
511 /* handle file cmds: (r)ead */ 515 /* handle file cmds: (r)ead */
512 else if (idx <= IDX_w) { /* r,w */ 516 else if (idx <= IDX_w) { /* r,w */
513 if (sed_cmd->end_line || sed_cmd->end_match) 517 if (idx < IDX_w) { /* r */
514 bb_error_msg_and_die("command only uses one address"); 518 if (sed_cmd->end_line || sed_cmd->end_match)
519 bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd);
520 }
515 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); 521 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string);
516 if (sed_cmd->cmd == 'w') { 522 if (sed_cmd->cmd == 'w') {
517 sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); 523 sed_cmd->sw_file = xfopen_for_write(sed_cmd->string);
@@ -673,7 +679,7 @@ static void do_subst_w_backrefs(char *line, char *replace)
673 679
674 /* go through the replacement string */ 680 /* go through the replacement string */
675 for (i = 0; replace[i]; i++) { 681 for (i = 0; replace[i]; i++) {
676 /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ 682 /* if we find a backreference (\1, \2, etc.) print the backref'ed text */
677 if (replace[i] == '\\') { 683 if (replace[i] == '\\') {
678 unsigned backref = replace[++i] - '0'; 684 unsigned backref = replace[++i] - '0';
679 if (backref <= 9) { 685 if (backref <= 9) {
@@ -707,8 +713,10 @@ static void do_subst_w_backrefs(char *line, char *replace)
707static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) 713static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
708{ 714{
709 char *line = *line_p; 715 char *line = *line_p;
710 int altered = 0;
711 unsigned match_count = 0; 716 unsigned match_count = 0;
717 bool altered = 0;
718 bool prev_match_empty = 1;
719 bool tried_at_eol = 0;
712 regex_t *current_regex; 720 regex_t *current_regex;
713 721
714 current_regex = sed_cmd->sub_match; 722 current_regex = sed_cmd->sub_match;
@@ -735,50 +743,75 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
735 743
736 /* Now loop through, substituting for matches */ 744 /* Now loop through, substituting for matches */
737 do { 745 do {
746 int start = G.regmatch[0].rm_so;
747 int end = G.regmatch[0].rm_eo;
738 int i; 748 int i;
739 749
740 /* Work around bug in glibc regexec, demonstrated by:
741 * echo " a.b" | busybox sed 's [^ .]* x g'
742 * The match_count check is so not to break
743 * echo "hi" | busybox sed 's/^/!/g'
744 */
745 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
746 pipe_putc(*line++);
747 goto next;
748 }
749
750 match_count++; 750 match_count++;
751 751
752 /* If we aren't interested in this match, output old line to 752 /* If we aren't interested in this match, output old line to
753 end of match and continue */ 753 * end of match and continue */
754 if (sed_cmd->which_match 754 if (sed_cmd->which_match
755 && (sed_cmd->which_match != match_count) 755 && (sed_cmd->which_match != match_count)
756 ) { 756 ) {
757 for (i = 0; i < G.regmatch[0].rm_eo; i++) 757 for (i = 0; i < end; i++)
758 pipe_putc(*line++);
759 /* Null match? Print one more char */
760 if (start == end && *line)
758 pipe_putc(*line++); 761 pipe_putc(*line++);
759 goto next; 762 goto next;
760 } 763 }
761 764
762 /* print everything before the match */ 765 /* Print everything before the match */
763 for (i = 0; i < G.regmatch[0].rm_so; i++) 766 for (i = 0; i < start; i++)
764 pipe_putc(line[i]); 767 pipe_putc(line[i]);
765 768
766 /* then print the substitution string */ 769 /* Then print the substitution string,
767 do_subst_w_backrefs(line, sed_cmd->string); 770 * unless we just matched empty string after non-empty one.
771 * Example: string "cccd", pattern "c*", repl "R":
772 * result is "RdR", not "RRdR": first match "ccc",
773 * second is "" before "d", third is "" after "d".
774 * Second match is NOT replaced!
775 */
776 if (prev_match_empty || start != 0 || start != end) {
777 //dbg("%d %d %d", prev_match_empty, start, end);
778 dbg("inserting replacement at %d in '%s'", start, line);
779 do_subst_w_backrefs(line, sed_cmd->string);
780 /* Flag that something has changed */
781 altered = 1;
782 } else {
783 dbg("NOT inserting replacement at %d in '%s'", start, line);
784 }
785
786 /* If matched string is empty (f.e. "c*" pattern),
787 * copy verbatim one char after it before attempting more matches
788 */
789 prev_match_empty = (start == end);
790 if (prev_match_empty) {
791 if (!line[end]) {
792 tried_at_eol = 1;
793 } else {
794 pipe_putc(line[end]);
795 end++;
796 }
797 }
768 798
769 /* advance past the match */ 799 /* Advance past the match */
770 line += G.regmatch[0].rm_eo; 800 dbg("line += %d", end);
771 /* flag that something has changed */ 801 line += end;
772 altered++;
773 802
774 /* if we're not doing this globally, get out now */ 803 /* if we're not doing this globally, get out now */
775 if (sed_cmd->which_match != 0) 804 if (sed_cmd->which_match != 0)
776 break; 805 break;
777 next: 806 next:
778 if (*line == '\0') 807 /* Exit if we are at EOL and already tried matching at it */
779 break; 808 if (*line == '\0') {
809 if (tried_at_eol)
810 break;
811 tried_at_eol = 1;
812 }
780 813
781//maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? 814//maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
782 } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); 815 } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);
783 816
784 /* Copy rest of string into output pipeline */ 817 /* Copy rest of string into output pipeline */
@@ -1127,7 +1160,7 @@ static void process_files(void)
1127 case 's': 1160 case 's':
1128 if (!do_subst_command(sed_cmd, &pattern_space)) 1161 if (!do_subst_command(sed_cmd, &pattern_space))
1129 break; 1162 break;
1130 dbg("do_subst_command succeeeded:'%s'", pattern_space); 1163 dbg("do_subst_command succeeded:'%s'", pattern_space);
1131 substituted |= 1; 1164 substituted |= 1;
1132 1165
1133 /* handle p option */ 1166 /* handle p option */
diff --git a/editors/vi.c b/editors/vi.c
index 6fae221ac..821583ec1 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -136,14 +136,6 @@
136//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. 136//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin.
137//config: 137//config:
138//config: This is not clean but helps a lot on serial lines and such. 138//config: This is not clean but helps a lot on serial lines and such.
139//config:
140//config:config FEATURE_VI_OPTIMIZE_CURSOR
141//config: bool "Optimize cursor movement"
142//config: default y
143//config: depends on VI
144//config: help
145//config: This will make the cursor movement faster, but requires more memory
146//config: and it makes the applet a tiny bit larger.
147 139
148//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) 140//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP))
149 141
@@ -154,12 +146,12 @@
154//usage:#define vi_full_usage "\n\n" 146//usage:#define vi_full_usage "\n\n"
155//usage: "Edit FILE\n" 147//usage: "Edit FILE\n"
156//usage: IF_FEATURE_VI_COLON( 148//usage: IF_FEATURE_VI_COLON(
157//usage: "\n -c Initial command to run ($EXINIT also available)" 149//usage: "\n -c CMD Initial command to run ($EXINIT also available)"
158//usage: ) 150//usage: )
159//usage: IF_FEATURE_VI_READONLY( 151//usage: IF_FEATURE_VI_READONLY(
160//usage: "\n -R Read-only" 152//usage: "\n -R Read-only"
161//usage: ) 153//usage: )
162//usage: "\n -H Short help regarding available features" 154//usage: "\n -H List available features"
163 155
164#include "libbb.h" 156#include "libbb.h"
165/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ 157/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */
@@ -202,20 +194,29 @@ enum {
202 MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, 194 MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN,
203}; 195};
204 196
205/* vt102 typical ESC sequence */ 197/* VT102 ESC sequences.
206/* terminal standout start/normal ESC sequence */ 198 * See "Xterm Control Sequences"
207#define SOs "\033[7m" 199 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
208#define SOn "\033[0m" 200 */
209/* terminal bell sequence */ 201/* Inverse/Normal text */
210#define bell "\007" 202#define ESC_BOLD_TEXT "\033[7m"
211/* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 203#define ESC_NORM_TEXT "\033[0m"
212#define Ceol "\033[K" 204/* Bell */
213#define Ceos "\033[J" 205#define ESC_BELL "\007"
214/* Cursor motion arbitrary destination ESC sequence */ 206/* Clear-to-end-of-line */
215#define CMrc "\033[%u;%uH" 207#define ESC_CLEAR2EOL "\033[K"
216/* Cursor motion up and down ESC sequence */ 208/* Clear-to-end-of-screen.
217#define CMup "\033[A" 209 * (We use default param here.
218#define CMdown "\n" 210 * Full sequence is "ESC [ <num> J",
211 * <num> is 0/1/2 = "erase below/above/all".)
212 */
213#define ESC_CLEAR2EOS "\033[J"
214/* Cursor to given coordinate (1,1: top left) */
215#define ESC_SET_CURSOR_POS "\033[%u;%uH"
216//UNUSED
217///* Cursor up and down */
218//#define ESC_CURSOR_UP "\033[A"
219//#define ESC_CURSOR_DOWN "\n"
219 220
220#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 221#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
221// cmds modifying text[] 222// cmds modifying text[]
@@ -303,9 +304,6 @@ struct globals {
303 int lmc_len; // length of last_modifying_cmd 304 int lmc_len; // length of last_modifying_cmd
304 char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 305 char *ioq, *ioq_start; // pointer to string for get_one_char to "read"
305#endif 306#endif
306#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
307 int last_row; // where the cursor was last moved to
308#endif
309#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 307#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
310 int my_pid; 308 int my_pid;
311#endif 309#endif
@@ -389,7 +387,6 @@ struct globals {
389#define lmc_len (G.lmc_len ) 387#define lmc_len (G.lmc_len )
390#define ioq (G.ioq ) 388#define ioq (G.ioq )
391#define ioq_start (G.ioq_start ) 389#define ioq_start (G.ioq_start )
392#define last_row (G.last_row )
393#define my_pid (G.my_pid ) 390#define my_pid (G.my_pid )
394#define last_search_pattern (G.last_search_pattern) 391#define last_search_pattern (G.last_search_pattern)
395 392
@@ -470,10 +467,7 @@ static int file_size(const char *); // what is the byte size of "fn"
470// file_insert might reallocate text[]! 467// file_insert might reallocate text[]!
471static int file_insert(const char *, char *, int); 468static int file_insert(const char *, char *, int);
472static int file_write(char *, char *, char *); 469static int file_write(char *, char *, char *);
473#if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 470static void place_cursor(int, int);
474#define place_cursor(a, b, optimize) place_cursor(a, b)
475#endif
476static void place_cursor(int, int, int);
477static void screen_erase(void); 471static void screen_erase(void);
478static void clear_to_eol(void); 472static void clear_to_eol(void);
479static void clear_to_eos(void); 473static void clear_to_eos(void);
@@ -558,7 +552,8 @@ int vi_main(int argc, char **argv)
558 } 552 }
559#endif 553#endif
560 554
561 vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; 555 // autoindent is not default in vim 7.3
556 vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE;
562 // 1- process $HOME/.exrc file (not inplemented yet) 557 // 1- process $HOME/.exrc file (not inplemented yet)
563 // 2- process EXINIT variable from environment 558 // 2- process EXINIT variable from environment
564 // 3- process command line args 559 // 3- process command line args
@@ -584,7 +579,7 @@ int vi_main(int argc, char **argv)
584#if ENABLE_FEATURE_VI_COLON 579#if ENABLE_FEATURE_VI_COLON
585 case 'c': // cmd line vi command 580 case 'c': // cmd line vi command
586 if (*optarg) 581 if (*optarg)
587 initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN); 582 initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN);
588 break; 583 break;
589#endif 584#endif
590 case 'H': 585 case 'H':
@@ -599,15 +594,19 @@ int vi_main(int argc, char **argv)
599 // The argv array can be used by the ":next" and ":rewind" commands 594 // The argv array can be used by the ":next" and ":rewind" commands
600 argv += optind; 595 argv += optind;
601 argc -= optind; 596 argc -= optind;
602 save_argc = argc;
603 optind = 0;
604 597
605 //----- This is the main file handling loop -------------- 598 //----- This is the main file handling loop --------------
599 save_argc = argc;
600 optind = 0;
601 // "Save cursor, use alternate screen buffer, clear screen"
602 write1("\033[?1049h");
606 while (1) { 603 while (1) {
607 edit_file(argv[optind]); /* param might be NULL */ 604 edit_file(argv[optind]); /* param might be NULL */
608 if (++optind >= argc) 605 if (++optind >= argc)
609 break; 606 break;
610 } 607 }
608 // "Use normal screen buffer, restore cursor"
609 write1("\033[?1049l");
611 //----------------------------------------------------------- 610 //-----------------------------------------------------------
612 611
613 return 0; 612 return 0;
@@ -1191,7 +1190,7 @@ static void colon(char *buf)
1191 char *argp; 1190 char *argp;
1192#endif 1191#endif
1193 i = 0; // offset into args 1192 i = 0; // offset into args
1194 // only blank is regarded as args delmiter. What about tab '\t' ? 1193 // only blank is regarded as args delimiter. What about tab '\t'?
1195 if (!args[0] || strcasecmp(args, "all") == 0) { 1194 if (!args[0] || strcasecmp(args, "all") == 0) {
1196 // print out values of all options 1195 // print out values of all options
1197#if ENABLE_FEATURE_VI_SETOPTS 1196#if ENABLE_FEATURE_VI_SETOPTS
@@ -2176,7 +2175,7 @@ static void show_help(void)
2176 "\n\tPattern searches with / and ?" 2175 "\n\tPattern searches with / and ?"
2177#endif 2176#endif
2178#if ENABLE_FEATURE_VI_DOT_CMD 2177#if ENABLE_FEATURE_VI_DOT_CMD
2179 "\n\tLast command repeat with \'.\'" 2178 "\n\tLast command repeat with ."
2180#endif 2179#endif
2181#if ENABLE_FEATURE_VI_YANKMARK 2180#if ENABLE_FEATURE_VI_YANKMARK
2182 "\n\tLine marking with 'x" 2181 "\n\tLine marking with 'x"
@@ -2187,7 +2186,7 @@ static void show_help(void)
2187 //redundant: usage text says this too: "\n\tReadonly with -R command line arg" 2186 //redundant: usage text says this too: "\n\tReadonly with -R command line arg"
2188#endif 2187#endif
2189#if ENABLE_FEATURE_VI_SET 2188#if ENABLE_FEATURE_VI_SET
2190 "\n\tSome colon mode commands with \':\'" 2189 "\n\tSome colon mode commands with :"
2191#endif 2190#endif
2192#if ENABLE_FEATURE_VI_SETOPTS 2191#if ENABLE_FEATURE_VI_SETOPTS
2193 "\n\tSettable options with \":set\"" 2192 "\n\tSettable options with \":set\""
@@ -2601,107 +2600,56 @@ static int file_write(char *fn, char *first, char *last)
2601// 23,0 ... 23,79 <- status line 2600// 23,0 ... 23,79 <- status line
2602 2601
2603//----- Move the cursor to row x col (count from 0, not 1) ------- 2602//----- Move the cursor to row x col (count from 0, not 1) -------
2604static void place_cursor(int row, int col, int optimize) 2603static void place_cursor(int row, int col)
2605{ 2604{
2606 char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; 2605 char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
2607#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
2608 enum {
2609 SZ_UP = sizeof(CMup),
2610 SZ_DN = sizeof(CMdown),
2611 SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN,
2612 };
2613 char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size
2614#endif
2615 char *cm;
2616 2606
2617 if (row < 0) row = 0; 2607 if (row < 0) row = 0;
2618 if (row >= rows) row = rows - 1; 2608 if (row >= rows) row = rows - 1;
2619 if (col < 0) col = 0; 2609 if (col < 0) col = 0;
2620 if (col >= columns) col = columns - 1; 2610 if (col >= columns) col = columns - 1;
2621 2611
2622 //----- 1. Try the standard terminal ESC sequence 2612 sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
2623 sprintf(cm1, CMrc, row + 1, col + 1); 2613 write1(cm1);
2624 cm = cm1;
2625
2626#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
2627 if (optimize && col < 16) {
2628 char *screenp;
2629 int Rrow = last_row;
2630 int diff = Rrow - row;
2631
2632 if (diff < -5 || diff > 5)
2633 goto skip;
2634
2635 //----- find the minimum # of chars to move cursor -------------
2636 //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
2637 cm2[0] = '\0';
2638
2639 // move to the correct row
2640 while (row < Rrow) {
2641 // the cursor has to move up
2642 strcat(cm2, CMup);
2643 Rrow--;
2644 }
2645 while (row > Rrow) {
2646 // the cursor has to move down
2647 strcat(cm2, CMdown);
2648 Rrow++;
2649 }
2650
2651 // now move to the correct column
2652 strcat(cm2, "\r"); // start at col 0
2653 // just send out orignal source char to get to correct place
2654 screenp = &screen[row * columns]; // start of screen line
2655 strncat(cm2, screenp, col);
2656
2657 // pick the shortest cursor motion to send out
2658 if (strlen(cm2) < strlen(cm)) {
2659 cm = cm2;
2660 }
2661 skip: ;
2662 }
2663 last_row = row;
2664#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
2665 write1(cm);
2666} 2614}
2667 2615
2668//----- Erase from cursor to end of line ----------------------- 2616//----- Erase from cursor to end of line -----------------------
2669static void clear_to_eol(void) 2617static void clear_to_eol(void)
2670{ 2618{
2671 write1(Ceol); // Erase from cursor to end of line 2619 write1(ESC_CLEAR2EOL);
2672} 2620}
2673 2621
2674static void go_bottom_and_clear_to_eol(void) 2622static void go_bottom_and_clear_to_eol(void)
2675{ 2623{
2676 place_cursor(rows - 1, 0, FALSE); // go to bottom of screen 2624 place_cursor(rows - 1, 0);
2677 clear_to_eol(); // erase to end of line 2625 clear_to_eol();
2678} 2626}
2679 2627
2680//----- Erase from cursor to end of screen ----------------------- 2628//----- Erase from cursor to end of screen -----------------------
2681static void clear_to_eos(void) 2629static void clear_to_eos(void)
2682{ 2630{
2683 write1(Ceos); // Erase from cursor to end of screen 2631 write1(ESC_CLEAR2EOS);
2684} 2632}
2685 2633
2686//----- Start standout mode ------------------------------------ 2634//----- Start standout mode ------------------------------------
2687static void standout_start(void) // send "start reverse video" sequence 2635static void standout_start(void)
2688{ 2636{
2689 write1(SOs); // Start reverse video mode 2637 write1(ESC_BOLD_TEXT);
2690} 2638}
2691 2639
2692//----- End standout mode -------------------------------------- 2640//----- End standout mode --------------------------------------
2693static void standout_end(void) // send "end reverse video" sequence 2641static void standout_end(void)
2694{ 2642{
2695 write1(SOn); // End reverse video mode 2643 write1(ESC_NORM_TEXT);
2696} 2644}
2697 2645
2698//----- Flash the screen -------------------------------------- 2646//----- Flash the screen --------------------------------------
2699static void flash(int h) 2647static void flash(int h)
2700{ 2648{
2701 standout_start(); // send "start reverse video" sequence 2649 standout_start();
2702 redraw(TRUE); 2650 redraw(TRUE);
2703 mysleep(h); 2651 mysleep(h);
2704 standout_end(); // send "end reverse video" sequence 2652 standout_end();
2705 redraw(TRUE); 2653 redraw(TRUE);
2706} 2654}
2707 2655
@@ -2712,7 +2660,7 @@ static void Indicate_Error(void)
2712 return; // generate a random command 2660 return; // generate a random command
2713#endif 2661#endif
2714 if (!err_method) { 2662 if (!err_method) {
2715 write1(bell); // send out a bell character 2663 write1(ESC_BELL);
2716 } else { 2664 } else {
2717 flash(10); 2665 flash(10);
2718 } 2666 }
@@ -2758,7 +2706,7 @@ static void show_status_line(void)
2758 } 2706 }
2759 have_status_msg = 0; 2707 have_status_msg = 0;
2760 } 2708 }
2761 place_cursor(crow, ccol, FALSE); // put cursor back in correct place 2709 place_cursor(crow, ccol); // put cursor back in correct place
2762 } 2710 }
2763 fflush_all(); 2711 fflush_all();
2764} 2712}
@@ -2770,12 +2718,12 @@ static void status_line_bold(const char *format, ...)
2770 va_list args; 2718 va_list args;
2771 2719
2772 va_start(args, format); 2720 va_start(args, format);
2773 strcpy(status_buffer, SOs); // Terminal standout mode on 2721 strcpy(status_buffer, ESC_BOLD_TEXT);
2774 vsprintf(status_buffer + sizeof(SOs)-1, format, args); 2722 vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args);
2775 strcat(status_buffer, SOn); // Terminal standout mode off 2723 strcat(status_buffer, ESC_NORM_TEXT);
2776 va_end(args); 2724 va_end(args);
2777 2725
2778 have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2; 2726 have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2;
2779} 2727}
2780 2728
2781// format status buffer 2729// format status buffer
@@ -2807,8 +2755,8 @@ static void print_literal(char *buf, const char *s)
2807 c = *s; 2755 c = *s;
2808 c_is_no_print = (c & 0x80) && !Isprint(c); 2756 c_is_no_print = (c & 0x80) && !Isprint(c);
2809 if (c_is_no_print) { 2757 if (c_is_no_print) {
2810 strcpy(d, SOn); 2758 strcpy(d, ESC_NORM_TEXT);
2811 d += sizeof(SOn)-1; 2759 d += sizeof(ESC_NORM_TEXT)-1;
2812 c = '.'; 2760 c = '.';
2813 } 2761 }
2814 if (c < ' ' || c == 0x7f) { 2762 if (c < ' ' || c == 0x7f) {
@@ -2820,8 +2768,8 @@ static void print_literal(char *buf, const char *s)
2820 *d++ = c; 2768 *d++ = c;
2821 *d = '\0'; 2769 *d = '\0';
2822 if (c_is_no_print) { 2770 if (c_is_no_print) {
2823 strcpy(d, SOs); 2771 strcpy(d, ESC_BOLD_TEXT);
2824 d += sizeof(SOs)-1; 2772 d += sizeof(ESC_BOLD_TEXT)-1;
2825 } 2773 }
2826 if (*s == '\n') { 2774 if (*s == '\n') {
2827 *d++ = '$'; 2775 *d++ = '$';
@@ -2903,8 +2851,8 @@ static int format_edit_status(void)
2903//----- Force refresh of all Lines ----------------------------- 2851//----- Force refresh of all Lines -----------------------------
2904static void redraw(int full_screen) 2852static void redraw(int full_screen)
2905{ 2853{
2906 place_cursor(0, 0, FALSE); // put cursor in correct place 2854 place_cursor(0, 0);
2907 clear_to_eos(); // tell terminal to erase display 2855 clear_to_eos();
2908 screen_erase(); // erase the internal screen buffer 2856 screen_erase(); // erase the internal screen buffer
2909 last_status_cksum = 0; // force status update 2857 last_status_cksum = 0; // force status update
2910 refresh(full_screen); // this will redraw the entire display 2858 refresh(full_screen); // this will redraw the entire display
@@ -3044,22 +2992,13 @@ static void refresh(int full_screen)
3044 if (changed) { 2992 if (changed) {
3045 // copy changed part of buffer to virtual screen 2993 // copy changed part of buffer to virtual screen
3046 memcpy(sp+cs, out_buf+cs, ce-cs+1); 2994 memcpy(sp+cs, out_buf+cs, ce-cs+1);
3047 2995 place_cursor(li, cs);
3048 // move cursor to column of first change
3049 //if (offset != old_offset) {
3050 // // place_cursor is still too stupid
3051 // // to handle offsets correctly
3052 // place_cursor(li, cs, FALSE);
3053 //} else {
3054 place_cursor(li, cs, TRUE);
3055 //}
3056
3057 // write line out to terminal 2996 // write line out to terminal
3058 fwrite(&sp[cs], ce - cs + 1, 1, stdout); 2997 fwrite(&sp[cs], ce - cs + 1, 1, stdout);
3059 } 2998 }
3060 } 2999 }
3061 3000
3062 place_cursor(crow, ccol, TRUE); 3001 place_cursor(crow, ccol);
3063 3002
3064 old_offset = offset; 3003 old_offset = offset;
3065#undef old_offset 3004#undef old_offset
@@ -3229,9 +3168,9 @@ static void do_cmd(int c)
3229 break; 3168 break;
3230 case 12: // ctrl-L force redraw whole screen 3169 case 12: // ctrl-L force redraw whole screen
3231 case 18: // ctrl-R force redraw 3170 case 18: // ctrl-R force redraw
3232 place_cursor(0, 0, FALSE); // put cursor in correct place 3171 place_cursor(0, 0);
3233 clear_to_eos(); // tel terminal to erase display 3172 clear_to_eos();
3234 mysleep(10); 3173 //mysleep(10); // why???
3235 screen_erase(); // erase the internal screen buffer 3174 screen_erase(); // erase the internal screen buffer
3236 last_status_cksum = 0; // force status update 3175 last_status_cksum = 0; // force status update
3237 refresh(TRUE); // this will redraw the entire display 3176 refresh(TRUE); // this will redraw the entire display
@@ -4150,7 +4089,7 @@ static void crash_test()
4150 4089
4151 if (msg[0]) { 4090 if (msg[0]) {
4152 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", 4091 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
4153 totalcmds, last_input_char, msg, SOs, SOn); 4092 totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT);
4154 fflush_all(); 4093 fflush_all();
4155 while (safe_read(STDIN_FILENO, d, 1) > 0) { 4094 while (safe_read(STDIN_FILENO, d, 1) > 0) {
4156 if (d[0] == '\n' || d[0] == '\r') 4095 if (d[0] == '\n' || d[0] == '\r')
diff --git a/examples/mdev.conf b/examples/mdev.conf
index cdbb4fcfe..51795694d 100644
--- a/examples/mdev.conf
+++ b/examples/mdev.conf
@@ -7,8 +7,14 @@
7# instead of the default 0:0 660. 7# instead of the default 0:0 660.
8# 8#
9# Syntax: 9# Syntax:
10# %s %d:%d %s 10# [-]devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
11# devicename_regex user:group mode 11# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
12# [-]@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
13#
14# [-]: do not stop on this match, continue reading mdev.conf
15# =: move, >: move and create a symlink
16# !: do not create device node
17# @|$|*: run@cmd if $ACTION=add, $cmd if $ACTION=remove, *cmd in all cases
12 18
13null 0:0 666 19null 0:0 666
14zero 0:0 666 20zero 0:0 666
diff --git a/examples/mdev_fat.conf b/examples/mdev_fat.conf
index df329b4b5..ceba3a797 100644
--- a/examples/mdev_fat.conf
+++ b/examples/mdev_fat.conf
@@ -7,10 +7,14 @@
7# instead of the default 0:0 660. 7# instead of the default 0:0 660.
8# 8#
9# Syntax: 9# Syntax:
10# [-]devicename_regex user:group mode [>|=path] [@|$|*cmd args...] 10# [-]devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
11# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
12# [-]@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...]
11# 13#
14# [-]: do not stop on this match, continue reading mdev.conf
12# =: move, >: move and create a symlink 15# =: move, >: move and create a symlink
13# @|$|*: run $cmd on delete, @cmd on create, *cmd on both 16# !: do not create device node
17# @|$|*: run cmd if $ACTION=remove, @cmd if $ACTION=add, *cmd in all cases
14 18
15# support module loading on hotplug 19# support module loading on hotplug
16$MODALIAS=.* root:root 660 @modprobe "$MODALIAS" 20$MODALIAS=.* root:root 660 @modprobe "$MODALIAS"
@@ -49,7 +53,6 @@ sr[0-9]* root:cdrom 660 @ln -sf $MDEV cdrom
49fd[0-9]* root:floppy 660 53fd[0-9]* root:floppy 660
50 54
51# net devices 55# net devices
52-net/.* root:root 600 @nameif
53tun[0-9]* root:root 600 =net/ 56tun[0-9]* root:root 600 =net/
54tap[0-9]* root:root 600 =net/ 57tap[0-9]* root:root 600 =net/
55 58
diff --git a/findutils/find.c b/findutils/find.c
index fc0fc5c9f..b521e5b08 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -728,10 +728,27 @@ static int FAST_FUNC fileAction(const char *fileName,
728 int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) 728 int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM))
729{ 729{
730 int r; 730 int r;
731 int same_fs = 1;
732
733#if ENABLE_FEATURE_FIND_XDEV
734 if (S_ISDIR(statbuf->st_mode) && G.xdev_count) {
735 int i;
736 for (i = 0; i < G.xdev_count; i++) {
737 if (G.xdev_dev[i] == statbuf->st_dev)
738 goto found;
739 }
740 //bb_error_msg("'%s': not same fs", fileName);
741 same_fs = 0;
742 found: ;
743 }
744#endif
731 745
732#if ENABLE_FEATURE_FIND_MAXDEPTH 746#if ENABLE_FEATURE_FIND_MAXDEPTH
733 if (depth < G.minmaxdepth[0]) 747 if (depth < G.minmaxdepth[0]) {
734 return TRUE; /* skip this, continue recursing */ 748 if (same_fs)
749 return TRUE; /* skip this, continue recursing */
750 return SKIP; /* stop recursing */
751 }
735 if (depth > G.minmaxdepth[1]) 752 if (depth > G.minmaxdepth[1])
736 return SKIP; /* stop recursing */ 753 return SKIP; /* stop recursing */
737#endif 754#endif
@@ -747,21 +764,11 @@ static int FAST_FUNC fileAction(const char *fileName,
747 return SKIP; 764 return SKIP;
748 } 765 }
749#endif 766#endif
750#if ENABLE_FEATURE_FIND_XDEV
751 /* -xdev stops on mountpoints, but AFTER mountpoit itself 767 /* -xdev stops on mountpoints, but AFTER mountpoit itself
752 * is processed as usual */ 768 * is processed as usual */
753 if (S_ISDIR(statbuf->st_mode)) { 769 if (!same_fs) {
754 if (G.xdev_count) { 770 return SKIP;
755 int i;
756 for (i = 0; i < G.xdev_count; i++) {
757 if (G.xdev_dev[i] == statbuf->st_dev)
758 goto found;
759 }
760 return SKIP;
761 found: ;
762 }
763 } 771 }
764#endif
765 772
766 /* Cannot return 0: our caller, recursive_action(), 773 /* Cannot return 0: our caller, recursive_action(),
767 * will perror() and skip dirs (if called on dir) */ 774 * will perror() and skip dirs (if called on dir) */
@@ -831,6 +838,11 @@ static action*** parse_params(char **argv)
831 PARM_name , 838 PARM_name ,
832 PARM_iname , 839 PARM_iname ,
833 IF_FEATURE_FIND_PATH( PARM_path ,) 840 IF_FEATURE_FIND_PATH( PARM_path ,)
841#if ENABLE_DESKTOP
842 /* -wholename is a synonym for -path */
843 /* We support it because Linux kernel's "make tags" uses it */
844 IF_FEATURE_FIND_PATH( PARM_wholename ,)
845#endif
834 IF_FEATURE_FIND_PATH( PARM_ipath ,) 846 IF_FEATURE_FIND_PATH( PARM_ipath ,)
835 IF_FEATURE_FIND_REGEX( PARM_regex ,) 847 IF_FEATURE_FIND_REGEX( PARM_regex ,)
836 IF_FEATURE_FIND_TYPE( PARM_type ,) 848 IF_FEATURE_FIND_TYPE( PARM_type ,)
@@ -869,6 +881,9 @@ static action*** parse_params(char **argv)
869 "-name\0" 881 "-name\0"
870 "-iname\0" 882 "-iname\0"
871 IF_FEATURE_FIND_PATH( "-path\0" ) 883 IF_FEATURE_FIND_PATH( "-path\0" )
884#if ENABLE_DESKTOP
885 IF_FEATURE_FIND_PATH( "-wholename\0")
886#endif
872 IF_FEATURE_FIND_PATH( "-ipath\0" ) 887 IF_FEATURE_FIND_PATH( "-ipath\0" )
873 IF_FEATURE_FIND_REGEX( "-regex\0" ) 888 IF_FEATURE_FIND_REGEX( "-regex\0" )
874 IF_FEATURE_FIND_TYPE( "-type\0" ) 889 IF_FEATURE_FIND_TYPE( "-type\0" )
@@ -1076,7 +1091,7 @@ static action*** parse_params(char **argv)
1076 ap->iname = (parm == PARM_iname); 1091 ap->iname = (parm == PARM_iname);
1077 } 1092 }
1078#if ENABLE_FEATURE_FIND_PATH 1093#if ENABLE_FEATURE_FIND_PATH
1079 else if (parm == PARM_path || parm == PARM_ipath) { 1094 else if (parm == PARM_path IF_DESKTOP(|| parm == PARM_wholename) || parm == PARM_ipath) {
1080 action_path *ap; 1095 action_path *ap;
1081 dbg("%d", __LINE__); 1096 dbg("%d", __LINE__);
1082 ap = ALLOC_ACTION(path); 1097 ap = ALLOC_ACTION(path);
diff --git a/include/applets.src.h b/include/applets.src.h
index 252a060fb..597b1c9a6 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -70,12 +70,12 @@ INSERT
70IF_TEST(APPLET_NOFORK([, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) 70IF_TEST(APPLET_NOFORK([, test, BB_DIR_USR_BIN, BB_SUID_DROP, test))
71IF_TEST(APPLET_NOFORK([[, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) 71IF_TEST(APPLET_NOFORK([[, test, BB_DIR_USR_BIN, BB_SUID_DROP, test))
72IF_ACPID(APPLET(acpid, BB_DIR_SBIN, BB_SUID_DROP)) 72IF_ACPID(APPLET(acpid, BB_DIR_SBIN, BB_SUID_DROP))
73IF_ADDGROUP(APPLET(addgroup, BB_DIR_BIN, BB_SUID_DROP)) 73IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP))
74IF_ADDUSER(APPLET(adduser, BB_DIR_BIN, BB_SUID_DROP)) 74IF_ADDUSER(APPLET(adduser, BB_DIR_USR_SBIN, BB_SUID_DROP))
75IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP)) 75IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP))
76IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP)) 76IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP))
77IF_ARP(APPLET(arp, BB_DIR_SBIN, BB_SUID_DROP)) 77IF_ARP(APPLET(arp, BB_DIR_SBIN, BB_SUID_DROP))
78IF_ARPING(APPLET(arping, BB_DIR_USR_BIN, BB_SUID_DROP)) 78IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
79IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk)) 79IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk))
80IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename)) 80IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename))
81IF_BBCONFIG(APPLET(bbconfig, BB_DIR_BIN, BB_SUID_DROP)) 81IF_BBCONFIG(APPLET(bbconfig, BB_DIR_BIN, BB_SUID_DROP))
@@ -86,7 +86,7 @@ IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
86IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP)) 86IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP))
87IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) 87IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat))
88IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP)) 88IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP))
89IF_CHAT(APPLET(chat, BB_DIR_USR_BIN, BB_SUID_DROP)) 89IF_CHAT(APPLET(chat, BB_DIR_USR_SBIN, BB_SUID_DROP))
90IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP)) 90IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP))
91IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP)) 91IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP))
92IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, BB_DIR_BIN, BB_SUID_DROP, chgrp)) 92IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, BB_DIR_BIN, BB_SUID_DROP, chgrp))
@@ -111,8 +111,8 @@ IF_CUT(APPLET_NOEXEC(cut, cut, BB_DIR_USR_BIN, BB_SUID_DROP, cut))
111IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP)) 111IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
112IF_DD(APPLET_NOEXEC(dd, dd, BB_DIR_BIN, BB_SUID_DROP, dd)) 112IF_DD(APPLET_NOEXEC(dd, dd, BB_DIR_BIN, BB_SUID_DROP, dd))
113IF_DEALLOCVT(APPLET(deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP)) 113IF_DEALLOCVT(APPLET(deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP))
114IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_BIN, BB_SUID_DROP, delgroup)) 114IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup))
115IF_DELUSER(APPLET(deluser, BB_DIR_BIN, BB_SUID_DROP)) 115IF_DELUSER(APPLET(deluser, BB_DIR_USR_SBIN, BB_SUID_DROP))
116IF_DEVFSD(APPLET(devfsd, BB_DIR_SBIN, BB_SUID_DROP)) 116IF_DEVFSD(APPLET(devfsd, BB_DIR_SBIN, BB_SUID_DROP))
117IF_DEVMEM(APPLET(devmem, BB_DIR_SBIN, BB_SUID_DROP)) 117IF_DEVMEM(APPLET(devmem, BB_DIR_SBIN, BB_SUID_DROP))
118IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP)) 118IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP))
@@ -136,7 +136,7 @@ IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP))
136IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) 136IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env))
137IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) 137IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir))
138IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) 138IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid))
139IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, BB_DIR_USR_BIN, BB_SUID_DROP, ether_wake)) 139IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, BB_DIR_USR_SBIN, BB_SUID_DROP, ether_wake))
140IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) 140IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP))
141IF_EXPR(APPLET(expr, BB_DIR_USR_BIN, BB_SUID_DROP)) 141IF_EXPR(APPLET(expr, BB_DIR_USR_BIN, BB_SUID_DROP))
142IF_FAKEIDENTD(APPLET(fakeidentd, BB_DIR_USR_SBIN, BB_SUID_DROP)) 142IF_FAKEIDENTD(APPLET(fakeidentd, BB_DIR_USR_SBIN, BB_SUID_DROP))
@@ -144,7 +144,7 @@ IF_FALSE(APPLET_NOFORK(false, false, BB_DIR_BIN, BB_SUID_DROP, false))
144IF_FBSET(APPLET(fbset, BB_DIR_USR_SBIN, BB_SUID_DROP)) 144IF_FBSET(APPLET(fbset, BB_DIR_USR_SBIN, BB_SUID_DROP))
145IF_FBSPLASH(APPLET(fbsplash, BB_DIR_SBIN, BB_SUID_DROP)) 145IF_FBSPLASH(APPLET(fbsplash, BB_DIR_SBIN, BB_SUID_DROP))
146IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush)) 146IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush))
147IF_FDFORMAT(APPLET(fdformat, BB_DIR_USR_BIN, BB_SUID_DROP)) 147IF_FDFORMAT(APPLET(fdformat, BB_DIR_USR_SBIN, BB_SUID_DROP))
148IF_FDISK(APPLET(fdisk, BB_DIR_SBIN, BB_SUID_DROP)) 148IF_FDISK(APPLET(fdisk, BB_DIR_SBIN, BB_SUID_DROP))
149IF_FGCONSOLE(APPLET(fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP)) 149IF_FGCONSOLE(APPLET(fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP))
150/* Benefits from suid root: better access to /dev/BLOCKDEVs: */ 150/* Benefits from suid root: better access to /dev/BLOCKDEVs: */
@@ -182,7 +182,7 @@ IF_HWCLOCK(APPLET(hwclock, BB_DIR_SBIN, BB_SUID_DROP))
182IF_IFCONFIG(APPLET(ifconfig, BB_DIR_SBIN, BB_SUID_DROP)) 182IF_IFCONFIG(APPLET(ifconfig, BB_DIR_SBIN, BB_SUID_DROP))
183IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifdown)) 183IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifdown))
184IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP)) 184IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP))
185IF_IFPLUGD(APPLET(ifplugd, BB_DIR_USR_BIN, BB_SUID_DROP)) 185IF_IFPLUGD(APPLET(ifplugd, BB_DIR_USR_SBIN, BB_SUID_DROP))
186IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifup)) 186IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifup))
187IF_INETD(APPLET(inetd, BB_DIR_USR_SBIN, BB_SUID_DROP)) 187IF_INETD(APPLET(inetd, BB_DIR_USR_SBIN, BB_SUID_DROP))
188IF_INOTIFYD(APPLET(inotifyd, BB_DIR_SBIN, BB_SUID_DROP)) 188IF_INOTIFYD(APPLET(inotifyd, BB_DIR_SBIN, BB_SUID_DROP))
@@ -193,20 +193,20 @@ IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP))
193 || ENABLE_FEATURE_IP_LINK \ 193 || ENABLE_FEATURE_IP_LINK \
194 || ENABLE_FEATURE_IP_TUNNEL \ 194 || ENABLE_FEATURE_IP_TUNNEL \
195 || ENABLE_FEATURE_IP_RULE 195 || ENABLE_FEATURE_IP_RULE
196IF_IP(APPLET(ip, BB_DIR_BIN, BB_SUID_DROP)) 196IF_IP(APPLET(ip, BB_DIR_SBIN, BB_SUID_DROP))
197#endif 197#endif
198IF_IPADDR(APPLET(ipaddr, BB_DIR_BIN, BB_SUID_DROP)) 198IF_IPADDR(APPLET(ipaddr, BB_DIR_SBIN, BB_SUID_DROP))
199IF_IPCALC(APPLET(ipcalc, BB_DIR_BIN, BB_SUID_DROP)) 199IF_IPCALC(APPLET(ipcalc, BB_DIR_BIN, BB_SUID_DROP))
200IF_IPCRM(APPLET(ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP)) 200IF_IPCRM(APPLET(ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP))
201IF_IPCS(APPLET(ipcs, BB_DIR_USR_BIN, BB_SUID_DROP)) 201IF_IPCS(APPLET(ipcs, BB_DIR_USR_BIN, BB_SUID_DROP))
202IF_IPLINK(APPLET(iplink, BB_DIR_BIN, BB_SUID_DROP)) 202IF_IPLINK(APPLET(iplink, BB_DIR_SBIN, BB_SUID_DROP))
203IF_IPROUTE(APPLET(iproute, BB_DIR_BIN, BB_SUID_DROP)) 203IF_IPROUTE(APPLET(iproute, BB_DIR_SBIN, BB_SUID_DROP))
204IF_IPRULE(APPLET(iprule, BB_DIR_BIN, BB_SUID_DROP)) 204IF_IPRULE(APPLET(iprule, BB_DIR_SBIN, BB_SUID_DROP))
205IF_IPTUNNEL(APPLET(iptunnel, BB_DIR_BIN, BB_SUID_DROP)) 205IF_IPTUNNEL(APPLET(iptunnel, BB_DIR_SBIN, BB_SUID_DROP))
206IF_KBD_MODE(APPLET(kbd_mode, BB_DIR_USR_BIN, BB_SUID_DROP)) 206IF_KBD_MODE(APPLET(kbd_mode, BB_DIR_BIN, BB_SUID_DROP))
207IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) 207IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP))
208IF_KILLALL(APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) 208IF_KILLALL(APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall))
209IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall5)) 209IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5))
210IF_KLOGD(APPLET(klogd, BB_DIR_SBIN, BB_SUID_DROP)) 210IF_KLOGD(APPLET(klogd, BB_DIR_SBIN, BB_SUID_DROP))
211IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP)) 211IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP))
212//IF_LENGTH(APPLET_NOFORK(length, length, BB_DIR_USR_BIN, BB_SUID_DROP, length)) 212//IF_LENGTH(APPLET_NOFORK(length, length, BB_DIR_USR_BIN, BB_SUID_DROP, length))
@@ -288,7 +288,7 @@ IF_PWD(APPLET_NOFORK(pwd, pwd, BB_DIR_BIN, BB_SUID_DROP, pwd))
288IF_RAIDAUTORUN(APPLET(raidautorun, BB_DIR_SBIN, BB_SUID_DROP)) 288IF_RAIDAUTORUN(APPLET(raidautorun, BB_DIR_SBIN, BB_SUID_DROP))
289IF_RDATE(APPLET(rdate, BB_DIR_USR_SBIN, BB_SUID_DROP)) 289IF_RDATE(APPLET(rdate, BB_DIR_USR_SBIN, BB_SUID_DROP))
290IF_RDEV(APPLET(rdev, BB_DIR_USR_SBIN, BB_SUID_DROP)) 290IF_RDEV(APPLET(rdev, BB_DIR_USR_SBIN, BB_SUID_DROP))
291IF_READAHEAD(APPLET(readahead, BB_DIR_USR_BIN, BB_SUID_DROP)) 291IF_READAHEAD(APPLET(readahead, BB_DIR_USR_SBIN, BB_SUID_DROP))
292IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) 292IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP))
293IF_READPROFILE(APPLET(readprofile, BB_DIR_USR_SBIN, BB_SUID_DROP)) 293IF_READPROFILE(APPLET(readprofile, BB_DIR_USR_SBIN, BB_SUID_DROP))
294IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP)) 294IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP))
@@ -303,7 +303,7 @@ IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir))
303IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP)) 303IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP))
304IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) 304IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP))
305IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) 305IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP))
306IF_RTCWAKE(APPLET(rtcwake, BB_DIR_USR_BIN, BB_SUID_DROP)) 306IF_RTCWAKE(APPLET(rtcwake, BB_DIR_USR_SBIN, BB_SUID_DROP))
307IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts)) 307IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts))
308IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP)) 308IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP))
309IF_RUNLEVEL(APPLET(runlevel, BB_DIR_SBIN, BB_SUID_DROP)) 309IF_RUNLEVEL(APPLET(runlevel, BB_DIR_SBIN, BB_SUID_DROP))
@@ -365,7 +365,7 @@ IF_TELNETD(APPLET(telnetd, BB_DIR_USR_SBIN, BB_SUID_DROP))
365IF_TEST(APPLET_NOFORK(test, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) 365IF_TEST(APPLET_NOFORK(test, test, BB_DIR_USR_BIN, BB_SUID_DROP, test))
366#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT 366#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
367IF_TFTP(APPLET(tftp, BB_DIR_USR_BIN, BB_SUID_DROP)) 367IF_TFTP(APPLET(tftp, BB_DIR_USR_BIN, BB_SUID_DROP))
368IF_TFTPD(APPLET(tftpd, BB_DIR_USR_BIN, BB_SUID_DROP)) 368IF_TFTPD(APPLET(tftpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
369#endif 369#endif
370IF_TIME(APPLET(time, BB_DIR_USR_BIN, BB_SUID_DROP)) 370IF_TIME(APPLET(time, BB_DIR_USR_BIN, BB_SUID_DROP))
371IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP)) 371IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP))
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 2043d8570..7bb5615da 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -121,6 +121,7 @@ typedef struct archive_handle_t {
121#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) 121#define ARCHIVE_DONT_RESTORE_PERM (1 << 6)
122#define ARCHIVE_NUMERIC_OWNER (1 << 7) 122#define ARCHIVE_NUMERIC_OWNER (1 << 7)
123#define ARCHIVE_O_TRUNC (1 << 8) 123#define ARCHIVE_O_TRUNC (1 << 8)
124#define ARCHIVE_REMEMBER_NAMES (1 << 9)
124 125
125 126
126/* POSIX tar Header Block, from POSIX 1003.1-1990 */ 127/* POSIX tar Header Block, from POSIX 1003.1-1990 */
diff --git a/include/bb_e2fs_defs.h b/include/bb_e2fs_defs.h
index 7974497ca..b400f8c11 100644
--- a/include/bb_e2fs_defs.h
+++ b/include/bb_e2fs_defs.h
@@ -406,25 +406,43 @@ struct ext2_super_block {
406 * Performance hints. Directory preallocation should only 406 * Performance hints. Directory preallocation should only
407 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. 407 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
408 */ 408 */
409 uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ 409 uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
410 uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ 410 uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
411 uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */ 411 uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */
412 /* 412 /*
413 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. 413 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
414 */ 414 */
415 uint8_t s_journal_uuid[16]; /* uuid of journal superblock */ 415/*D0*/ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
416 uint32_t s_journal_inum; /* inode number of journal file */ 416/*E0*/ uint32_t s_journal_inum; /* inode number of journal file */
417 uint32_t s_journal_dev; /* device number of journal file */ 417 uint32_t s_journal_dev; /* device number of journal file */
418 uint32_t s_last_orphan; /* start of list of inodes to delete */ 418 uint32_t s_last_orphan; /* start of list of inodes to delete */
419 uint32_t s_hash_seed[4]; /* HTREE hash seed */ 419 uint32_t s_hash_seed[4]; /* HTREE hash seed */
420 uint8_t s_def_hash_version; /* Default hash version to use */ 420 uint8_t s_def_hash_version; /* Default hash version to use */
421 uint8_t s_jnl_backup_type; /* Default type of journal backup */ 421 uint8_t s_jnl_backup_type; /* Default type of journal backup */
422 uint16_t s_reserved_word_pad; 422 uint16_t s_reserved_word_pad;
423 uint32_t s_default_mount_opts; 423/*100*/ uint32_t s_default_mount_opts;
424 uint32_t s_first_meta_bg; /* First metablock group */ 424 uint32_t s_first_meta_bg; /* First metablock group */
425 /* ext3 additions */
425 uint32_t s_mkfs_time; /* When the filesystem was created */ 426 uint32_t s_mkfs_time; /* When the filesystem was created */
426 uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */ 427 uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
427 uint32_t s_reserved[172]; /* Padding to the end of the block */ 428 /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
429/*150*/ uint32_t s_blocks_count_hi; /* Blocks count */
430 uint32_t s_r_blocks_count_hi; /* Reserved blocks count */
431 uint32_t s_free_blocks_count_hi; /* Free blocks count */
432 uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
433 uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
434 uint32_t s_flags; /* Miscellaneous flags */
435 uint16_t s_raid_stride; /* RAID stride */
436 uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */
437 uint64_t s_mmp_block; /* Block for multi-mount protection */
438 uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
439 uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
440 uint8_t s_reserved_char_pad2;
441 uint16_t s_reserved_pad;
442 uint32_t s_reserved[162]; /* Padding to the end of the block */
443};
444struct BUG_ext2_super_block {
445 char bug[sizeof(struct ext2_super_block) == 1024 ? 1 : -1];
428}; 446};
429 447
430/* 448/*
@@ -463,6 +481,7 @@ struct ext2_super_block {
463#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ 481#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
464 ( EXT2_SB(sb)->s_feature_incompat & (mask) ) 482 ( EXT2_SB(sb)->s_feature_incompat & (mask) )
465 483
484/* for s_feature_compat */
466#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 485#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
467#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 486#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
468#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 487#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
@@ -470,23 +489,45 @@ struct ext2_super_block {
470#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 489#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010
471#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 490#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
472 491
492/* for s_feature_ro_compat */
473#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 493#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
474#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 494#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
475/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */ 495#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 /* not used */
496#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
497#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
498#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
499#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
476 500
501/* for s_feature_incompat */
477#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 502#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
478#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 503#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
479#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ 504#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
480#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ 505#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
481#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 506#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
482#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040 507#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040
508#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
509#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
510#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
483 511
484 512
485#define EXT2_FEATURE_COMPAT_SUPP 0 513#define EXT2_FEATURE_COMPAT_SUPP 0
486#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
487#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ 514#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
488 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ 515 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
489 EXT2_FEATURE_RO_COMPAT_BTREE_DIR) 516 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
517#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
518 EXT2_FEATURE_INCOMPAT_META_BG)
519#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED (~EXT2_FEATURE_INCOMPAT_SUPP)
520#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED (~EXT2_FEATURE_RO_COMPAT_SUPP)
521
522#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
523 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
524 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
525#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
526 EXT3_FEATURE_INCOMPAT_RECOVER| \
527 EXT2_FEATURE_INCOMPAT_META_BG)
528#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED (~EXT3_FEATURE_INCOMPAT_SUPP)
529#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED (~EXT3_FEATURE_RO_COMPAT_SUPP)
530
490 531
491/* 532/*
492 * Default values for user and/or group using reserved blocks 533 * Default values for user and/or group using reserved blocks
diff --git a/include/busybox.h b/include/busybox.h
index 315ef8f26..b1e31e5ee 100644
--- a/include/busybox.h
+++ b/include/busybox.h
@@ -13,10 +13,10 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
13 13
14/* Defined in appletlib.c (by including generated applet_tables.h) */ 14/* Defined in appletlib.c (by including generated applet_tables.h) */
15/* Keep in sync with applets/applet_tables.c! */ 15/* Keep in sync with applets/applet_tables.c! */
16extern const char applet_names[]; 16extern const char applet_names[] ALIGN1;
17extern int (*const applet_main[])(int argc, char **argv); 17extern int (*const applet_main[])(int argc, char **argv);
18extern const uint16_t applet_nameofs[]; 18extern const uint16_t applet_nameofs[];
19extern const uint8_t applet_install_loc[]; 19extern const uint8_t applet_install_loc[] ALIGN1;
20 20
21#if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS 21#if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS
22# define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) 22# define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff))
diff --git a/include/libbb.h b/include/libbb.h
index a78772b6a..5012209f8 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -346,6 +346,7 @@ enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */
346 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 9, /* -c */ 346 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 9, /* -c */
347 FILEUTILS_SET_SECURITY_CONTEXT = 1 << 10, 347 FILEUTILS_SET_SECURITY_CONTEXT = 1 << 10,
348#endif 348#endif
349 FILEUTILS_IGNORE_CHMOD_ERR = 1 << 11,
349}; 350};
350#define FILEUTILS_CP_OPTSTR "pdRfilsLH" IF_SELINUX("c") 351#define FILEUTILS_CP_OPTSTR "pdRfilsLH" IF_SELINUX("c")
351extern int remove_file(const char *path, int flags) FAST_FUNC; 352extern int remove_file(const char *path, int flags) FAST_FUNC;
@@ -1301,6 +1302,7 @@ int sd_listen_fds(void);
1301#define SETUP_ENV_CHANGEENV (1 << 0) 1302#define SETUP_ENV_CHANGEENV (1 << 0)
1302#define SETUP_ENV_CLEARENV (1 << 1) 1303#define SETUP_ENV_CLEARENV (1 << 1)
1303#define SETUP_ENV_TO_TMP (1 << 2) 1304#define SETUP_ENV_TO_TMP (1 << 2)
1305#define SETUP_ENV_NO_CHDIR (1 << 4)
1304extern void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; 1306extern void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC;
1305extern int correct_password(const struct passwd *pw) FAST_FUNC; 1307extern int correct_password(const struct passwd *pw) FAST_FUNC;
1306/* Returns a malloced string */ 1308/* Returns a malloced string */
@@ -1629,8 +1631,8 @@ unsigned get_cpu_count(void) FAST_FUNC;
1629char *percent_decode_in_place(char *str, int strict) FAST_FUNC; 1631char *percent_decode_in_place(char *str, int strict) FAST_FUNC;
1630 1632
1631 1633
1632extern const char bb_uuenc_tbl_base64[]; 1634extern const char bb_uuenc_tbl_base64[] ALIGN1;
1633extern const char bb_uuenc_tbl_std[]; 1635extern const char bb_uuenc_tbl_std[] ALIGN1;
1634void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; 1636void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC;
1635enum { 1637enum {
1636 BASE64_FLAG_UU_STOP = 0x100, 1638 BASE64_FLAG_UU_STOP = 0x100,
@@ -1711,29 +1713,24 @@ extern const char *applet_name;
1711 * Therefore now we use #defines. 1713 * Therefore now we use #defines.
1712 */ 1714 */
1713/* "BusyBox vN.N.N (timestamp or extra_version)" */ 1715/* "BusyBox vN.N.N (timestamp or extra_version)" */
1714extern const char bb_banner[]; 1716extern const char bb_banner[] ALIGN1;
1715extern const char bb_msg_memory_exhausted[]; 1717extern const char bb_msg_memory_exhausted[] ALIGN1;
1716extern const char bb_msg_invalid_date[]; 1718extern const char bb_msg_invalid_date[] ALIGN1;
1717#define bb_msg_read_error "read error" 1719#define bb_msg_read_error "read error"
1718#define bb_msg_write_error "write error" 1720#define bb_msg_write_error "write error"
1719extern const char bb_msg_unknown[]; 1721extern const char bb_msg_unknown[] ALIGN1;
1720extern const char bb_msg_can_not_create_raw_socket[]; 1722extern const char bb_msg_can_not_create_raw_socket[] ALIGN1;
1721extern const char bb_msg_perm_denied_are_you_root[]; 1723extern const char bb_msg_perm_denied_are_you_root[] ALIGN1;
1722extern const char bb_msg_you_must_be_root[]; 1724extern const char bb_msg_you_must_be_root[] ALIGN1;
1723extern const char bb_msg_requires_arg[]; 1725extern const char bb_msg_requires_arg[] ALIGN1;
1724extern const char bb_msg_invalid_arg[]; 1726extern const char bb_msg_invalid_arg[] ALIGN1;
1725extern const char bb_msg_standard_input[]; 1727extern const char bb_msg_standard_input[] ALIGN1;
1726extern const char bb_msg_standard_output[]; 1728extern const char bb_msg_standard_output[] ALIGN1;
1727 1729
1728/* NB: (bb_hexdigits_upcase[i] | 0x20) -> lowercase hex digit */ 1730/* NB: (bb_hexdigits_upcase[i] | 0x20) -> lowercase hex digit */
1729extern const char bb_hexdigits_upcase[]; 1731extern const char bb_hexdigits_upcase[] ALIGN1;
1730 1732
1731extern const char bb_path_wtmp_file[]; 1733extern const char bb_path_wtmp_file[] ALIGN1;
1732#if ENABLE_PLATFORM_MINGW32
1733#define bb_busybox_exec_path get_busybox_exec_path()
1734#else
1735extern const char bb_busybox_exec_path[];
1736#endif
1737 1734
1738/* Busybox mount uses either /proc/mounts or /etc/mtab to 1735/* Busybox mount uses either /proc/mounts or /etc/mtab to
1739 * get the list of currently mounted filesystems */ 1736 * get the list of currently mounted filesystems */
@@ -1747,9 +1744,14 @@ extern const char bb_busybox_exec_path[];
1747#define bb_path_motd_file "/etc/motd" 1744#define bb_path_motd_file "/etc/motd"
1748 1745
1749#define bb_dev_null "/dev/null" 1746#define bb_dev_null "/dev/null"
1747#if ENABLE_PLATFORM_MINGW32
1748#define bb_busybox_exec_path get_busybox_exec_path()
1749#else
1750extern const char bb_busybox_exec_path[] ALIGN1;
1751#endif
1750/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 1752/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
1751 * but I want to save a few bytes here */ 1753 * but I want to save a few bytes here */
1752extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ 1754extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */
1753#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) 1755#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
1754#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin")) 1756#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin"))
1755 1757
@@ -1779,7 +1781,7 @@ extern struct globals *const ptr_to_globals;
1779 * If you change LIBBB_DEFAULT_LOGIN_SHELL, 1781 * If you change LIBBB_DEFAULT_LOGIN_SHELL,
1780 * don't forget to change increment constant. */ 1782 * don't forget to change increment constant. */
1781#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" 1783#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"
1782extern const char bb_default_login_shell[]; 1784extern const char bb_default_login_shell[] ALIGN1;
1783/* "/bin/sh" */ 1785/* "/bin/sh" */
1784#define DEFAULT_SHELL (bb_default_login_shell+1) 1786#define DEFAULT_SHELL (bb_default_login_shell+1)
1785/* "sh" */ 1787/* "sh" */
diff --git a/include/platform.h b/include/platform.h
index 925cce60c..78d42fed9 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -301,7 +301,8 @@ typedef unsigned smalluint;
301#define fdprintf dprintf 301#define fdprintf dprintf
302 302
303/* Useful for defeating gcc's alignment of "char message[]"-like data */ 303/* Useful for defeating gcc's alignment of "char message[]"-like data */
304#if 1 /* if needed: !defined(arch1) && !defined(arch2) */ 304#if !defined(__s390__)
305 /* on s390[x], non-word-aligned data accesses require larger code */
305# define ALIGN1 __attribute__((aligned(1))) 306# define ALIGN1 __attribute__((aligned(1)))
306# define ALIGN2 __attribute__((aligned(2))) 307# define ALIGN2 __attribute__((aligned(2)))
307# define ALIGN4 __attribute__((aligned(4))) 308# define ALIGN4 __attribute__((aligned(4)))
@@ -351,6 +352,12 @@ typedef unsigned smalluint;
351# define MAXSYMLINKS SYMLOOP_MAX 352# define MAXSYMLINKS SYMLOOP_MAX
352#endif 353#endif
353 354
355#if defined(ANDROID) || defined(__ANDROID__)
356# define BB_ADDITIONAL_PATH ":/system/sbin:/system/bin:/system/xbin"
357# define SYS_ioprio_set __NR_ioprio_set
358# define SYS_ioprio_get __NR_ioprio_get
359#endif
360
354 361
355/* ---- Who misses what? ------------------------------------ */ 362/* ---- Who misses what? ------------------------------------ */
356 363
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 76c4d8ff3..0c0d14499 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -629,11 +629,11 @@ static int busybox_main(char **argv)
629 full_write2_str(bb_banner); /* reuse const string */ 629 full_write2_str(bb_banner); /* reuse const string */
630 full_write2_str(" multi-call binary.\n"); /* reuse */ 630 full_write2_str(" multi-call binary.\n"); /* reuse */
631 full_write2_str( 631 full_write2_str(
632 "Copyright (C) 1998-2011 Erik Andersen, Rob Landley, Denys Vlasenko\n" 632 "BusyBox is copyrighted by many authors between 1998-2012.\n"
633 "and others. Licensed under GPLv2.\n" 633 "Licensed under GPLv2. See source distribution for detailed\n"
634 "See source distribution for full notice.\n" 634 "copyright notices.\n"
635 "\n" 635 "\n"
636 "Usage: busybox [function] [arguments]...\n" 636 "Usage: busybox [function [arguments]...]\n"
637 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 637 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
638 IF_FEATURE_INSTALLER( 638 IF_FEATURE_INSTALLER(
639 " or: busybox --install [-s] [DIR]\n" 639 " or: busybox --install [-s] [DIR]\n"
diff --git a/libbb/correct_password.c b/libbb/correct_password.c
index 6301589e6..7cabd33d0 100644
--- a/libbb/correct_password.c
+++ b/libbb/correct_password.c
@@ -41,12 +41,6 @@ int FAST_FUNC correct_password(const struct passwd *pw)
41 char *unencrypted, *encrypted; 41 char *unencrypted, *encrypted;
42 const char *correct; 42 const char *correct;
43 int r; 43 int r;
44#if ENABLE_FEATURE_SHADOWPASSWDS
45 /* Using _r function to avoid pulling in static buffers */
46 struct spwd spw;
47 char buffer[256];
48#endif
49
50 /* fake salt. crypt() can choke otherwise. */ 44 /* fake salt. crypt() can choke otherwise. */
51 correct = "aa"; 45 correct = "aa";
52 if (!pw) { 46 if (!pw) {
@@ -55,7 +49,10 @@ int FAST_FUNC correct_password(const struct passwd *pw)
55 } 49 }
56 correct = pw->pw_passwd; 50 correct = pw->pw_passwd;
57#if ENABLE_FEATURE_SHADOWPASSWDS 51#if ENABLE_FEATURE_SHADOWPASSWDS
52 /* Using _r function to avoid pulling in static buffers */
58 if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) { 53 if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
54 struct spwd spw;
55 char buffer[256];
59 /* getspnam_r may return 0 yet set result to NULL. 56 /* getspnam_r may return 0 yet set result to NULL.
60 * At least glibc 2.4 does this. Be extra paranoid here. */ 57 * At least glibc 2.4 does this. Be extra paranoid here. */
61 struct spwd *result = NULL; 58 struct spwd *result = NULL;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 6990b91b6..65dffe56d 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2552,9 +2552,9 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2552 /* Delete word forward */ 2552 /* Delete word forward */
2553 int nc, sc = cursor; 2553 int nc, sc = cursor;
2554 ctrl_right(); 2554 ctrl_right();
2555 nc = cursor; 2555 nc = cursor - sc;
2556 input_backward(cursor - sc); 2556 input_backward(nc);
2557 while (--nc >= cursor) 2557 while (--nc >= 0)
2558 input_delete(1); 2558 input_delete(1);
2559 break; 2559 break;
2560 } 2560 }
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
index 8057f2cec..6f59fda29 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -114,6 +114,10 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
114 * an error. */ 114 * an error. */
115 if ((mode != -1) && (chmod(path, mode) < 0)) { 115 if ((mode != -1) && (chmod(path, mode) < 0)) {
116 fail_msg = "set permissions of"; 116 fail_msg = "set permissions of";
117 if (flags & FILEUTILS_IGNORE_CHMOD_ERR) {
118 flags = 0;
119 goto print_err;
120 }
117 break; 121 break;
118 } 122 }
119 goto ret0; 123 goto ret0;
@@ -123,8 +127,9 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
123 *s2 = c; 127 *s2 = c;
124 } /* while (1) */ 128 } /* while (1) */
125 129
126 bb_perror_msg("can't %s directory '%s'", fail_msg, path);
127 flags = -1; 130 flags = -1;
131 print_err:
132 bb_perror_msg("can't %s directory '%s'", fail_msg, path);
128 goto ret; 133 goto ret;
129 ret0: 134 ret0:
130 flags = 0; 135 flags = 0;
diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c
new file mode 100644
index 000000000..c50308ba8
--- /dev/null
+++ b/libbb/missing_syscalls.c
@@ -0,0 +1,42 @@
1/*
2 * Copyright 2012, Denys Vlasenko
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6
7//kbuild:lib-$(CONFIG_PLATFORM_POSIX) += missing_syscalls.o
8
9/*#include <linux/timex.h> - for struct timex, but may collide with <time.h> */
10#include <sys/syscall.h>
11#include "libbb.h"
12
13#if defined(ANDROID) || defined(__ANDROID__)
14pid_t getsid(pid_t pid)
15{
16 return syscall(__NR_getsid, pid);
17}
18
19int stime(const time_t *t)
20{
21 struct timeval tv;
22 tv.tv_sec = *t;
23 tv.tv_usec = 0;
24 return settimeofday(&tv, NULL);
25}
26
27int sethostname(const char *name, size_t len)
28{
29 return syscall(__NR_sethostname, name, len);
30}
31
32struct timex;
33int adjtimex(struct timex *buf)
34{
35 return syscall(__NR_adjtimex, buf);
36}
37
38int pivot_root(const char *new_root, const char *put_old)
39{
40 return syscall(__NR_pivot_root, new_root, put_old);
41}
42#endif
diff --git a/libbb/procps.c b/libbb/procps.c
index dbae46e33..1080e0165 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -426,7 +426,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
426 if (n < 11) 426 if (n < 11)
427 continue; /* bogus data, get next /proc/XXX */ 427 continue; /* bogus data, get next /proc/XXX */
428# if ENABLE_FEATURE_TOP_SMP_PROCESS 428# if ENABLE_FEATURE_TOP_SMP_PROCESS
429 if (n < 11+15) 429 if (n == 11)
430 sp->last_seen_on_cpu = 0; 430 sp->last_seen_on_cpu = 0;
431# endif 431# endif
432 432
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 8d72d2a63..ace23defb 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -15,7 +15,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
15 const char *seq; 15 const char *seq;
16 int n; 16 int n;
17 17
18 /* Known escape sequences for cursor and function keys */ 18 /* Known escape sequences for cursor and function keys.
19 * See "Xterm Control Sequences"
20 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
21 */
19 static const char esccmds[] ALIGN1 = { 22 static const char esccmds[] ALIGN1 = {
20 'O','A' |0x80,KEYCODE_UP , 23 'O','A' |0x80,KEYCODE_UP ,
21 'O','B' |0x80,KEYCODE_DOWN , 24 'O','B' |0x80,KEYCODE_DOWN ,
@@ -44,6 +47,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
44 /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */ 47 /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */
45 /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */ 48 /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */
46 /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */ 49 /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */
50 /* ESC [ 1 ; 7 x, where x = A/B/C/D: Ctrl-Alt-<arrow> */
51 /* ESC [ 1 ; 8 x, where x = A/B/C/D: Ctrl-Alt-Shift-<arrow> */
47 '[','H' |0x80,KEYCODE_HOME , /* xterm */ 52 '[','H' |0x80,KEYCODE_HOME , /* xterm */
48 '[','F' |0x80,KEYCODE_END , /* xterm */ 53 '[','F' |0x80,KEYCODE_END , /* xterm */
49 /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */ 54 /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */
@@ -64,10 +69,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
64 '[','7','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ 69 '[','7','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
65 '[','8','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */ 70 '[','8','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */
66#if 0 71#if 0
67 '[','1','1','~'|0x80,KEYCODE_FUN1 , 72 '[','1','1','~'|0x80,KEYCODE_FUN1 , /* old xterm, deprecated by ESC O P */
68 '[','1','2','~'|0x80,KEYCODE_FUN2 , 73 '[','1','2','~'|0x80,KEYCODE_FUN2 , /* old xterm... */
69 '[','1','3','~'|0x80,KEYCODE_FUN3 , 74 '[','1','3','~'|0x80,KEYCODE_FUN3 , /* old xterm... */
70 '[','1','4','~'|0x80,KEYCODE_FUN4 , 75 '[','1','4','~'|0x80,KEYCODE_FUN4 , /* old xterm... */
71 '[','1','5','~'|0x80,KEYCODE_FUN5 , 76 '[','1','5','~'|0x80,KEYCODE_FUN5 ,
72 /* [ESC] ESC [ 1 5 [;2] ~ - [Alt-][Shift-]F5 */ 77 /* [ESC] ESC [ 1 5 [;2] ~ - [Alt-][Shift-]F5 */
73 '[','1','7','~'|0x80,KEYCODE_FUN6 , 78 '[','1','7','~'|0x80,KEYCODE_FUN6 ,
diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c
index 73229ca6c..4258656fe 100644
--- a/libbb/setup_environment.c
+++ b/libbb/setup_environment.c
@@ -37,9 +37,11 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct pass
37 37
38 /* Change the current working directory to be the home directory 38 /* Change the current working directory to be the home directory
39 * of the user */ 39 * of the user */
40 if (chdir(pw->pw_dir)) { 40 if (!(flags & SETUP_ENV_NO_CHDIR)) {
41 xchdir((flags & SETUP_ENV_TO_TMP) ? "/tmp" : "/"); 41 if (chdir(pw->pw_dir) != 0) {
42 bb_error_msg("can't chdir to home directory '%s'", pw->pw_dir); 42 bb_error_msg("can't change directory to '%s'", pw->pw_dir);
43 xchdir((flags & SETUP_ENV_TO_TMP) ? "/tmp" : "/");
44 }
43 } 45 }
44 46
45 if (flags & SETUP_ENV_CLEARENV) { 47 if (flags & SETUP_ENV_CLEARENV) {
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index d8a42ba0b..05aa07ce8 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -355,13 +355,13 @@ void FAST_FUNC xsetuid(uid_t uid)
355void FAST_FUNC xchdir(const char *path) 355void FAST_FUNC xchdir(const char *path)
356{ 356{
357 if (chdir(path)) 357 if (chdir(path))
358 bb_perror_msg_and_die("chdir(%s)", path); 358 bb_perror_msg_and_die("can't change directory to '%s'", path);
359} 359}
360 360
361void FAST_FUNC xchroot(const char *path) 361void FAST_FUNC xchroot(const char *path)
362{ 362{
363 if (chroot(path)) 363 if (chroot(path))
364 bb_perror_msg_and_die("can't change root directory to %s", path); 364 bb_perror_msg_and_die("can't change root directory to '%s'", path);
365 xchdir("/"); 365 xchdir("/");
366} 366}
367 367
diff --git a/loginutils/add-remove-shell.c b/loginutils/add-remove-shell.c
index 9a1454430..e492b6e5a 100644
--- a/loginutils/add-remove-shell.c
+++ b/loginutils/add-remove-shell.c
@@ -8,8 +8,8 @@
8 * for details. 8 * for details.
9 */ 9 */
10 10
11//applet:IF_ADD_SHELL( APPLET_ODDNAME(add-shell , add_remove_shell, BB_DIR_USR_BIN, BB_SUID_DROP, add_shell )) 11//applet:IF_ADD_SHELL( APPLET_ODDNAME(add-shell , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell ))
12//applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, BB_DIR_USR_BIN, BB_SUID_DROP, remove_shell)) 12//applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell))
13 13
14//kbuild:lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o 14//kbuild:lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o
15//kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o 15//kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o
diff --git a/loginutils/getty.c b/loginutils/getty.c
index bbb5a96b4..e5d13bed6 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -548,8 +548,15 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
548 * a session leader - which is quite possible for getty! 548 * a session leader - which is quite possible for getty!
549 */ 549 */
550 pid = getpid(); 550 pid = getpid();
551 if (getsid(0) != pid) 551 if (getsid(0) != pid) {
552 //for debugging:
553 //bb_perror_msg_and_die("setsid failed:"
554 // " pid %d ppid %d"
555 // " sid %d pgid %d",
556 // pid, getppid(),
557 // getsid(0), getpgid(0));
552 bb_perror_msg_and_die("setsid"); 558 bb_perror_msg_and_die("setsid");
559 }
553 /* Looks like we are already a session leader. 560 /* Looks like we are already a session leader.
554 * In this case (setsid failed) we may still have ctty, 561 * In this case (setsid failed) we may still have ctty,
555 * and it may be different from tty we need to control! 562 * and it may be different from tty we need to control!
diff --git a/loginutils/login.c b/loginutils/login.c
index bf43f3aba..6ec8dc42e 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -37,7 +37,8 @@ static const struct pam_conv conv = {
37enum { 37enum {
38 TIMEOUT = 60, 38 TIMEOUT = 60,
39 EMPTY_USERNAME_COUNT = 10, 39 EMPTY_USERNAME_COUNT = 10,
40 USERNAME_SIZE = 32, 40 /* Some users found 32 chars limit to be too low: */
41 USERNAME_SIZE = 64,
41 TTYNAME_SIZE = 32, 42 TTYNAME_SIZE = 32,
42}; 43};
43 44
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
index b83db0083..a7006f054 100644
--- a/loginutils/passwd.c
+++ b/loginutils/passwd.c
@@ -15,6 +15,7 @@
15 15
16#include "libbb.h" 16#include "libbb.h"
17#include <syslog.h> 17#include <syslog.h>
18#include <sys/resource.h> /* setrlimit */
18 19
19static void nuke_str(char *str) 20static void nuke_str(char *str)
20{ 21{
diff --git a/loginutils/su.c b/loginutils/su.c
index 57ea738f4..2ec05e125 100644
--- a/loginutils/su.c
+++ b/loginutils/su.c
@@ -131,7 +131,8 @@ int su_main(int argc UNUSED_PARAM, char **argv)
131 change_identity(pw); 131 change_identity(pw);
132 setup_environment(opt_shell, 132 setup_environment(opt_shell,
133 ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV) 133 ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV)
134 + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV), 134 + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV)
135 + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR),
135 pw); 136 pw);
136 IF_SELINUX(set_current_security_context(NULL);) 137 IF_SELINUX(set_current_security_context(NULL);)
137 138
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 988439b25..37ca66559 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -50,6 +50,10 @@ struct globals {
50 struct fb_var_screeninfo scr_var; 50 struct fb_var_screeninfo scr_var;
51 struct fb_fix_screeninfo scr_fix; 51 struct fb_fix_screeninfo scr_fix;
52 unsigned bytes_per_pixel; 52 unsigned bytes_per_pixel;
53 // cached (8 - scr_var.COLOR.length):
54 unsigned red_shift;
55 unsigned green_shift;
56 unsigned blue_shift;
53}; 57};
54#define G (*ptr_to_globals) 58#define G (*ptr_to_globals)
55#define INIT_G() do { \ 59#define INIT_G() do { \
@@ -139,6 +143,9 @@ static void fb_open(const char *strfb_device)
139 break; 143 break;
140 } 144 }
141 145
146 G.red_shift = 8 - G.scr_var.red.length;
147 G.green_shift = 8 - G.scr_var.green.length;
148 G.blue_shift = 8 - G.scr_var.blue.length;
142 G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3; 149 G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3;
143 150
144 // map the device in memory 151 // map the device in memory
@@ -155,10 +162,13 @@ static void fb_open(const char *strfb_device)
155 162
156 163
157/** 164/**
158 * Return pixel value of the passed RGB color 165 * Return pixel value of the passed RGB color.
166 * This is performance critical fn.
159 */ 167 */
160static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b) 168static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
161{ 169{
170 /* We assume that the r,g,b values are <= 255 */
171
162 if (G.bytes_per_pixel == 1) { 172 if (G.bytes_per_pixel == 1) {
163 r = r & 0xe0; // 3-bit red 173 r = r & 0xe0; // 3-bit red
164 g = (g >> 3) & 0x1c; // 3-bit green 174 g = (g >> 3) & 0x1c; // 3-bit green
@@ -166,10 +176,17 @@ static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
166 return r + g + b; 176 return r + g + b;
167 } 177 }
168 if (G.bytes_per_pixel == 2) { 178 if (G.bytes_per_pixel == 2) {
169 r = (r & 0xf8) << 8; // 5-bit red 179 // ARM PL110 on Integrator/CP has RGBA5551 bit arrangement.
170 g = (g & 0xfc) << 3; // 6-bit green 180 // We want to support bit locations like that.
171 b = b >> 3; // 5-bit blue 181 //
172 return r + g + b; 182 // First shift out unused bits
183 r = r >> G.red_shift;
184 g = g >> G.green_shift;
185 b = b >> G.blue_shift;
186 // Then shift the remaining bits to their offset
187 return (r << G.scr_var.red.offset) +
188 (g << G.scr_var.green.offset) +
189 (b << G.scr_var.blue.offset);
173 } 190 }
174 // RGB 888 191 // RGB 888
175 return b + (g << 8) + (r << 16); 192 return b + (g << 8) + (r << 16);
diff --git a/miscutils/man.c b/miscutils/man.c
index 236fdcebd..b8b15b83b 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -129,27 +129,21 @@ static int show_manpage(const char *pager, char *man_filename, int man, int leve
129#endif 129#endif
130#if ENABLE_FEATURE_SEAMLESS_XZ 130#if ENABLE_FEATURE_SEAMLESS_XZ
131 strcpy(ext, "xz"); 131 strcpy(ext, "xz");
132 if (run_pipe(pager, man_filename, man, level)) 132 if (run_pipe(pager, filename_with_zext, man, level))
133 return 1; 133 return 1;
134#endif 134#endif
135#if ENABLE_FEATURE_SEAMLESS_BZ2 135#if ENABLE_FEATURE_SEAMLESS_BZ2
136 strcpy(ext, "bz2"); 136 strcpy(ext, "bz2");
137 if (run_pipe(pager, man_filename, man, level)) 137 if (run_pipe(pager, filename_with_zext, man, level))
138 return 1; 138 return 1;
139#endif 139#endif
140#if ENABLE_FEATURE_SEAMLESS_GZ 140#if ENABLE_FEATURE_SEAMLESS_GZ
141 strcpy(ext, "gz"); 141 strcpy(ext, "gz");
142 if (run_pipe(pager, man_filename, man, level)) 142 if (run_pipe(pager, filename_with_zext, man, level))
143 return 1; 143 return 1;
144#endif 144#endif
145 145
146#if SEAMLESS_COMPRESSION 146 return run_pipe(pager, man_filename, man, level);
147 ext[-1] = '\0';
148#endif
149 if (run_pipe(pager, man_filename, man, level))
150 return 1;
151
152 return 0;
153} 147}
154 148
155int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 149int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index 2ba6e3fe5..c636a5aa2 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -129,7 +129,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
129 xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO); 129 xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO);
130 } 130 }
131 131
132 fd = xopen(argv[0], O_RDWR); 132 fd = xopen(argv[0], IS_NANDWRITE ? O_RDWR : O_RDONLY);
133 xioctl(fd, MEMGETINFO, &meminfo); 133 xioctl(fd, MEMGETINFO, &meminfo);
134 134
135 mtdoffset = xstrtou(opt_s, 0); 135 mtdoffset = xstrtou(opt_s, 0);
diff --git a/miscutils/time.c b/miscutils/time.c
index 945f15f0d..ffed38632 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -16,6 +16,7 @@
16//usage: "\n -v Verbose" 16//usage: "\n -v Verbose"
17 17
18#include "libbb.h" 18#include "libbb.h"
19#include <sys/resource.h> /* getrusage */
19 20
20/* Information on the resources used by a child process. */ 21/* Information on the resources used by a child process. */
21typedef struct { 22typedef struct {
diff --git a/modutils/modinfo.c b/modutils/modinfo.c
index c0910ffed..7c978d1da 100644
--- a/modutils/modinfo.c
+++ b/modutils/modinfo.c
@@ -24,9 +24,9 @@
24 24
25 25
26enum { 26enum {
27 OPT_TAGS = (1 << 8) - 1, 27 OPT_TAGS = (1 << 12) - 1, /* shortcut count */
28 OPT_F = (1 << 8), /* field name */ 28 OPT_F = (1 << 12), /* field name */
29 OPT_0 = (1 << 9), /* \0 as separator */ 29 OPT_0 = (1 << 13), /* \0 as separator */
30}; 30};
31 31
32struct modinfo_env { 32struct modinfo_env {
@@ -49,13 +49,17 @@ static void modinfo(const char *path, const char *version,
49{ 49{
50 static const char *const shortcuts[] = { 50 static const char *const shortcuts[] = {
51 "filename", 51 "filename",
52 "description",
53 "author",
54 "license", 52 "license",
53 "author",
54 "description",
55 "version",
56 "alias",
57 "srcversion",
58 "depends",
59 "uts_release",
55 "vermagic", 60 "vermagic",
56 "parm", 61 "parm",
57 "firmware", 62 "firmware",
58 "depends",
59 }; 63 };
60 size_t len; 64 size_t len;
61 int j, length; 65 int j, length;
@@ -97,8 +101,11 @@ static void modinfo(const char *path, const char *version,
97 if (ptr == NULL) /* no occurance left, done */ 101 if (ptr == NULL) /* no occurance left, done */
98 break; 102 break;
99 if (strncmp(ptr, pattern, length) == 0 && ptr[length] == '=') { 103 if (strncmp(ptr, pattern, length) == 0 && ptr[length] == '=') {
100 ptr += length + 1; 104 /* field prefixes are 0x80 or 0x00 */
101 ptr += display(ptr, pattern, (1<<j) != tags); 105 if ((ptr[-1] & 0x7F) == '\0') {
106 ptr += length + 1;
107 ptr += display(ptr, pattern, (1<<j) != tags);
108 }
102 } 109 }
103 ++ptr; 110 ++ptr;
104 } 111 }
@@ -131,7 +138,7 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv)
131 138
132 env.field = NULL; 139 env.field = NULL;
133 opt_complementary = "-1"; /* minimum one param */ 140 opt_complementary = "-1"; /* minimum one param */
134 opts = getopt32(argv, "fdalvpF:0", &env.field); 141 opts = getopt32(argv, "nladvAsDumpF:0", &env.field);
135 env.tags = opts & OPT_TAGS ? opts & OPT_TAGS : OPT_TAGS; 142 env.tags = opts & OPT_TAGS ? opts & OPT_TAGS : OPT_TAGS;
136 argv += optind; 143 argv += optind;
137 144
diff --git a/networking/Config.src b/networking/Config.src
index fb7dca7d4..e2376d548 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -945,8 +945,8 @@ config WGET
945 bool "wget" 945 bool "wget"
946 default y 946 default y
947 help 947 help
948 wget is a utility for non-interactive download of files from HTTP, 948 wget is a utility for non-interactive download of files from HTTP
949 HTTPS, and FTP servers. 949 and FTP servers.
950 950
951config FEATURE_WGET_STATUSBAR 951config FEATURE_WGET_STATUSBAR
952 bool "Enable a nifty process meter (+2k)" 952 bool "Enable a nifty process meter (+2k)"
diff --git a/networking/brctl.c b/networking/brctl.c
index 19f474fce..7289e641f 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -67,7 +67,7 @@
67# include <linux/if_bridge.h> 67# include <linux/if_bridge.h>
68 68
69/* FIXME: These 4 funcs are not really clean and could be improved */ 69/* FIXME: These 4 funcs are not really clean and could be improved */
70static ALWAYS_INLINE void strtotimeval(struct timeval *tv, 70static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv,
71 const char *time_str) 71 const char *time_str)
72{ 72{
73 double secs; 73 double secs;
@@ -104,7 +104,7 @@ static void jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
104static unsigned long str_to_jiffies(const char *time_str) 104static unsigned long str_to_jiffies(const char *time_str)
105{ 105{
106 struct timeval tv; 106 struct timeval tv;
107 strtotimeval(&tv, time_str); 107 bb_strtotimeval(&tv, time_str);
108 return tv_to_jiffies(&tv); 108 return tv_to_jiffies(&tv);
109} 109}
110 110
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 1c97df564..33db964fa 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -821,7 +821,7 @@ handle_size_or_mdtm(int need_size)
821 gmtime_r(&statbuf.st_mtime, &broken_out); 821 gmtime_r(&statbuf.st_mtime, &broken_out);
822 sprintf(buf, STR(FTP_STATFILE_OK)" %04u%02u%02u%02u%02u%02u\r\n", 822 sprintf(buf, STR(FTP_STATFILE_OK)" %04u%02u%02u%02u%02u%02u\r\n",
823 broken_out.tm_year + 1900, 823 broken_out.tm_year + 1900,
824 broken_out.tm_mon, 824 broken_out.tm_mon + 1,
825 broken_out.tm_mday, 825 broken_out.tm_mday,
826 broken_out.tm_hour, 826 broken_out.tm_hour,
827 broken_out.tm_min, 827 broken_out.tm_min,
@@ -927,6 +927,7 @@ handle_upload_common(int is_append, int is_unique)
927 || fstat(local_file_fd, &statbuf) != 0 927 || fstat(local_file_fd, &statbuf) != 0
928 || !S_ISREG(statbuf.st_mode) 928 || !S_ISREG(statbuf.st_mode)
929 ) { 929 ) {
930 free(tempname);
930 WRITE_ERR(FTP_UPLOADFAIL); 931 WRITE_ERR(FTP_UPLOADFAIL);
931 if (local_file_fd >= 0) 932 if (local_file_fd >= 0)
932 goto close_local_and_bail; 933 goto close_local_and_bail;
diff --git a/networking/httpd.c b/networking/httpd.c
index 12218a0a3..a942794f5 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1414,7 +1414,7 @@ static void send_cgi_and_exit(
1414 if (script != url) { /* paranoia */ 1414 if (script != url) { /* paranoia */
1415 *script = '\0'; 1415 *script = '\0';
1416 if (chdir(url + 1) != 0) { 1416 if (chdir(url + 1) != 0) {
1417 bb_perror_msg("chdir(%s)", url + 1); 1417 bb_perror_msg("can't change directory to '%s'", url + 1);
1418 goto error_execing_cgi; 1418 goto error_execing_cgi;
1419 } 1419 }
1420 // not needed: *script = '/'; 1420 // not needed: *script = '/';
diff --git a/networking/httpd_indexcgi.c b/networking/httpd_indexcgi.c
index d732cd4f8..562cd7fbe 100644
--- a/networking/httpd_indexcgi.c
+++ b/networking/httpd_indexcgi.c
@@ -35,6 +35,7 @@ httpd_indexcgi.c -o index.cgi
35 * 2576 4 2048 4628 1214 index.cgi.o 35 * 2576 4 2048 4628 1214 index.cgi.o
36 */ 36 */
37 37
38#define _GNU_SOURCE 1 /* for strchrnul */
38#include <sys/types.h> 39#include <sys/types.h>
39#include <sys/stat.h> 40#include <sys/stat.h>
40#include <errno.h> 41#include <errno.h>
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index d8358cdfd..88bf448fa 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -22,9 +22,9 @@
22//usage: "\n -r PROG Script to run" 22//usage: "\n -r PROG Script to run"
23//usage: "\n -x ARG Extra argument for script" 23//usage: "\n -x ARG Extra argument for script"
24//usage: "\n -I Don't exit on nonzero exit code from script" 24//usage: "\n -I Don't exit on nonzero exit code from script"
25//usage: "\n -p Don't run script on daemon startup" 25//usage: "\n -p Don't run \"up\" script on startup"
26//usage: "\n -q Don't run script on daemon quit" 26//usage: "\n -q Don't run \"down\" script on exit"
27//usage: "\n -l Run script on startup even if no cable is detected" 27//usage: "\n -l Always run script on startup"
28//usage: "\n -t SECS Poll time in seconds" 28//usage: "\n -t SECS Poll time in seconds"
29//usage: "\n -u SECS Delay before running script after link up" 29//usage: "\n -u SECS Delay before running script after link up"
30//usage: "\n -d SECS Delay after link down" 30//usage: "\n -d SECS Delay after link down"
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 9b3498696..ad0a9971b 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -1058,7 +1058,7 @@ static int iface_up(struct interface_defn_t *iface)
1058 1058
1059static int iface_down(struct interface_defn_t *iface) 1059static int iface_down(struct interface_defn_t *iface)
1060{ 1060{
1061 if (!iface->method->down(iface,check)) return -1; 1061 if (!iface->method->down(iface, check)) return -1;
1062 set_environ(iface, "stop", "pre-down"); 1062 set_environ(iface, "stop", "pre-down");
1063 if (!execute_all(iface, "down")) return 0; 1063 if (!execute_all(iface, "down")) return 0;
1064 if (!iface->method->down(iface, doit)) return 0; 1064 if (!iface->method->down(iface, doit)) return 0;
diff --git a/networking/inetd.c b/networking/inetd.c
index 26b66992d..00baf6971 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -165,6 +165,8 @@
165//usage: "\n (default: 0 - disabled)" 165//usage: "\n (default: 0 - disabled)"
166 166
167#include <syslog.h> 167#include <syslog.h>
168#include <sys/resource.h> /* setrlimit */
169#include <sys/socket.h> /* un.h may need this */
168#include <sys/un.h> 170#include <sys/un.h>
169 171
170#include "libbb.h" 172#include "libbb.h"
diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c
index 7aac8364d..da2b53cbf 100644
--- a/networking/libiproute/ll_proto.c
+++ b/networking/libiproute/ll_proto.c
@@ -14,19 +14,10 @@
14 14
15#include <netinet/if_ether.h> 15#include <netinet/if_ether.h>
16 16
17#if !ENABLE_WERROR 17/* Please conditionalize exotic protocols on CONFIG_something */
18#warning de-bloat
19#endif
20/* Before re-enabling this, please (1) conditionalize exotic protocols
21 * on CONFIG_something, and (2) decouple strings and numbers
22 * (use llproto_ids[] = n,n,n..; and llproto_names[] = "loop\0" "pup\0" ...;)
23 */
24 18
25#define __PF(f,n) { ETH_P_##f, #n }, 19static const uint16_t llproto_ids[] = {
26static struct { 20#define __PF(f,n) ETH_P_##f,
27 int id;
28 const char *name;
29} llproto_names[] = {
30__PF(LOOP,loop) 21__PF(LOOP,loop)
31__PF(PUP,pup) 22__PF(PUP,pup)
32#ifdef ETH_P_PUPAT 23#ifdef ETH_P_PUPAT
@@ -86,33 +77,104 @@ __PF(IRDA,irda)
86__PF(ECONET,econet) 77__PF(ECONET,econet)
87#endif 78#endif
88 79
89{ 0x8100, "802.1Q" }, 800x8100,
90{ ETH_P_IP, "ipv4" }, 81ETH_P_IP
91}; 82};
92#undef __PF 83#undef __PF
93 84
85/* Keep declarations above and below in sync! */
86
87static const char llproto_names[] =
88#define __PF(f,n) #n "\0"
89__PF(LOOP,loop)
90__PF(PUP,pup)
91#ifdef ETH_P_PUPAT
92__PF(PUPAT,pupat)
93#endif
94__PF(IP,ip)
95__PF(X25,x25)
96__PF(ARP,arp)
97__PF(BPQ,bpq)
98#ifdef ETH_P_IEEEPUP
99__PF(IEEEPUP,ieeepup)
100#endif
101#ifdef ETH_P_IEEEPUPAT
102__PF(IEEEPUPAT,ieeepupat)
103#endif
104__PF(DEC,dec)
105__PF(DNA_DL,dna_dl)
106__PF(DNA_RC,dna_rc)
107__PF(DNA_RT,dna_rt)
108__PF(LAT,lat)
109__PF(DIAG,diag)
110__PF(CUST,cust)
111__PF(SCA,sca)
112__PF(RARP,rarp)
113__PF(ATALK,atalk)
114__PF(AARP,aarp)
115__PF(IPX,ipx)
116__PF(IPV6,ipv6)
117#ifdef ETH_P_PPP_DISC
118__PF(PPP_DISC,ppp_disc)
119#endif
120#ifdef ETH_P_PPP_SES
121__PF(PPP_SES,ppp_ses)
122#endif
123#ifdef ETH_P_ATMMPOA
124__PF(ATMMPOA,atmmpoa)
125#endif
126#ifdef ETH_P_ATMFATE
127__PF(ATMFATE,atmfate)
128#endif
129
130__PF(802_3,802_3)
131__PF(AX25,ax25)
132__PF(ALL,all)
133__PF(802_2,802_2)
134__PF(SNAP,snap)
135__PF(DDCMP,ddcmp)
136__PF(WAN_PPP,wan_ppp)
137__PF(PPP_MP,ppp_mp)
138__PF(LOCALTALK,localtalk)
139__PF(PPPTALK,ppptalk)
140__PF(TR_802_2,tr_802_2)
141__PF(MOBITEX,mobitex)
142__PF(CONTROL,control)
143__PF(IRDA,irda)
144#ifdef ETH_P_ECONET
145__PF(ECONET,econet)
146#endif
147
148"802.1Q" "\0"
149"ipv4" "\0"
150;
151#undef __PF
152
94 153
95const char* FAST_FUNC ll_proto_n2a(unsigned short id, char *buf, int len) 154const char* FAST_FUNC ll_proto_n2a(unsigned short id, char *buf, int len)
96{ 155{
97 unsigned i; 156 unsigned i;
98 id = ntohs(id); 157 id = ntohs(id);
99 for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { 158 for (i = 0; i < ARRAY_SIZE(llproto_ids); i++) {
100 if (llproto_names[i].id == id) 159 if (llproto_ids[i] == id)
101 return llproto_names[i].name; 160 return nth_string(llproto_names, i);
102 } 161 }
103 snprintf(buf, len, "[%d]", id); 162 snprintf(buf, len, "[%u]", id);
104 return buf; 163 return buf;
105} 164}
106 165
107int FAST_FUNC ll_proto_a2n(unsigned short *id, char *buf) 166int FAST_FUNC ll_proto_a2n(unsigned short *id, char *buf)
108{ 167{
109 unsigned i; 168 unsigned i;
110 for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { 169 const char *name = llproto_names;
111 if (strcasecmp(llproto_names[i].name, buf) == 0) { 170 for (i = 0; i < ARRAY_SIZE(llproto_ids); i++) {
112 i = llproto_names[i].id; 171 if (strcasecmp(name, buf) == 0) {
113 goto good; 172 i = llproto_ids[i];
114 } 173 goto good;
174 }
175 name += strlen(name) + 1;
115 } 176 }
177 errno = 0;
116 i = bb_strtou(buf, NULL, 0); 178 i = bb_strtou(buf, NULL, 0);
117 if (errno || i > 0xffff) 179 if (errno || i > 0xffff)
118 return -1; 180 return -1;
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 603801ec6..5b92db6f6 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -46,6 +46,7 @@
46#include "libbb.h" 46#include "libbb.h"
47#include <math.h> 47#include <math.h>
48#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */ 48#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */
49#include <sys/resource.h> /* setpriority */
49#include <sys/timex.h> 50#include <sys/timex.h>
50#ifndef IPTOS_LOWDELAY 51#ifndef IPTOS_LOWDELAY
51# define IPTOS_LOWDELAY 0x10 52# define IPTOS_LOWDELAY 0x10
@@ -220,14 +221,14 @@ typedef struct {
220typedef struct { 221typedef struct {
221 len_and_sockaddr *p_lsa; 222 len_and_sockaddr *p_lsa;
222 char *p_dotted; 223 char *p_dotted;
223 /* when to send new query (if p_fd == -1)
224 * or when receive times out (if p_fd >= 0): */
225 int p_fd; 224 int p_fd;
226 int datapoint_idx; 225 int datapoint_idx;
227 uint32_t lastpkt_refid; 226 uint32_t lastpkt_refid;
228 uint8_t lastpkt_status; 227 uint8_t lastpkt_status;
229 uint8_t lastpkt_stratum; 228 uint8_t lastpkt_stratum;
230 uint8_t reachable_bits; 229 uint8_t reachable_bits;
230 /* when to send new query (if p_fd == -1)
231 * or when receive times out (if p_fd >= 0): */
231 double next_action_time; 232 double next_action_time;
232 double p_xmttime; 233 double p_xmttime;
233 double lastpkt_recv_time; 234 double lastpkt_recv_time;
@@ -895,6 +896,11 @@ step_time(double offset)
895 896
896 /* Correct various fields which contain time-relative values: */ 897 /* Correct various fields which contain time-relative values: */
897 898
899 /* Globals: */
900 G.cur_time += offset;
901 G.last_update_recv_time += offset;
902 G.last_script_run += offset;
903
898 /* p->lastpkt_recv_time, p->next_action_time and such: */ 904 /* p->lastpkt_recv_time, p->next_action_time and such: */
899 for (item = G.ntp_peers; item != NULL; item = item->link) { 905 for (item = G.ntp_peers; item != NULL; item = item->link) {
900 peer_t *pp = (peer_t *) item->data; 906 peer_t *pp = (peer_t *) item->data;
@@ -902,11 +908,16 @@ step_time(double offset)
902 //bb_error_msg("offset:%+f pp->next_action_time:%f -> %f", 908 //bb_error_msg("offset:%+f pp->next_action_time:%f -> %f",
903 // offset, pp->next_action_time, pp->next_action_time + offset); 909 // offset, pp->next_action_time, pp->next_action_time + offset);
904 pp->next_action_time += offset; 910 pp->next_action_time += offset;
911 if (pp->p_fd >= 0) {
912 /* We wait for reply from this peer too.
913 * But due to step we are doing, reply's data is no longer
914 * useful (in fact, it'll be bogus). Stop waiting for it.
915 */
916 close(pp->p_fd);
917 pp->p_fd = -1;
918 set_next(pp, RETRY_INTERVAL);
919 }
905 } 920 }
906 /* Globals: */
907 G.cur_time += offset;
908 G.last_update_recv_time += offset;
909 G.last_script_run += offset;
910} 921}
911 922
912 923
@@ -1623,22 +1634,30 @@ recv_and_process_peer_pkt(peer_t *p)
1623 ) { 1634 ) {
1624//TODO: always do this? 1635//TODO: always do this?
1625 interval = retry_interval(); 1636 interval = retry_interval();
1626 goto set_next_and_close_sock; 1637 goto set_next_and_ret;
1627 } 1638 }
1628 xfunc_die(); 1639 xfunc_die();
1629 } 1640 }
1630 1641
1631 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { 1642 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
1632 bb_error_msg("malformed packet received from %s", p->p_dotted); 1643 bb_error_msg("malformed packet received from %s", p->p_dotted);
1633 goto bail; 1644 return;
1634 } 1645 }
1635 1646
1636 if (msg.m_orgtime.int_partl != p->p_xmt_msg.m_xmttime.int_partl 1647 if (msg.m_orgtime.int_partl != p->p_xmt_msg.m_xmttime.int_partl
1637 || msg.m_orgtime.fractionl != p->p_xmt_msg.m_xmttime.fractionl 1648 || msg.m_orgtime.fractionl != p->p_xmt_msg.m_xmttime.fractionl
1638 ) { 1649 ) {
1639 goto bail; 1650 /* Somebody else's packet */
1651 return;
1640 } 1652 }
1641 1653
1654 /* We do not expect any more packets from this peer for now.
1655 * Closing the socket informs kernel about it.
1656 * We open a new socket when we send a new query.
1657 */
1658 close(p->p_fd);
1659 p->p_fd = -1;
1660
1642 if ((msg.m_status & LI_ALARM) == LI_ALARM 1661 if ((msg.m_status & LI_ALARM) == LI_ALARM
1643 || msg.m_stratum == 0 1662 || msg.m_stratum == 0
1644 || msg.m_stratum > NTP_MAXSTRATUM 1663 || msg.m_stratum > NTP_MAXSTRATUM
@@ -1647,8 +1666,8 @@ recv_and_process_peer_pkt(peer_t *p)
1647// "DENY", "RSTR" - peer does not like us at all 1666// "DENY", "RSTR" - peer does not like us at all
1648// "RATE" - peer is overloaded, reduce polling freq 1667// "RATE" - peer is overloaded, reduce polling freq
1649 interval = poll_interval(0); 1668 interval = poll_interval(0);
1650 bb_error_msg("reply from %s: not synced, next query in %us", p->p_dotted, interval); 1669 bb_error_msg("reply from %s: peer is unsynced, next query in %us", p->p_dotted, interval);
1651 goto set_next_and_close_sock; 1670 goto set_next_and_ret;
1652 } 1671 }
1653 1672
1654// /* Verify valid root distance */ 1673// /* Verify valid root distance */
@@ -1794,16 +1813,8 @@ recv_and_process_peer_pkt(peer_t *p)
1794 /* Decide when to send new query for this peer */ 1813 /* Decide when to send new query for this peer */
1795 interval = poll_interval(0); 1814 interval = poll_interval(0);
1796 1815
1797 set_next_and_close_sock: 1816 set_next_and_ret:
1798 set_next(p, interval); 1817 set_next(p, interval);
1799 /* We do not expect any more packets from this peer for now.
1800 * Closing the socket informs kernel about it.
1801 * We open a new socket when we send a new query.
1802 */
1803 close(p->p_fd);
1804 p->p_fd = -1;
1805 bail:
1806 return;
1807} 1818}
1808 1819
1809#if ENABLE_FEATURE_NTPD_SERVER 1820#if ENABLE_FEATURE_NTPD_SERVER
diff --git a/networking/ntpd_simple.c b/networking/ntpd_simple.c
index 4ad44e4f3..1b7c66b84 100644
--- a/networking/ntpd_simple.c
+++ b/networking/ntpd_simple.c
@@ -7,6 +7,7 @@
7 */ 7 */
8#include "libbb.h" 8#include "libbb.h"
9#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */ 9#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */
10#include <sys/resource.h> /* setpriority */
10#ifndef IPTOS_LOWDELAY 11#ifndef IPTOS_LOWDELAY
11# define IPTOS_LOWDELAY 0x10 12# define IPTOS_LOWDELAY 0x10
12#endif 13#endif
diff --git a/networking/tftp.c b/networking/tftp.c
index ce48a1edd..630fdaf9a 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -116,7 +116,7 @@ enum {
116struct globals { 116struct globals {
117 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ 117 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
118 uint8_t error_pkt[4 + 32]; 118 uint8_t error_pkt[4 + 32];
119 char *user_opt; 119 struct passwd *pw;
120 /* used in tftpd_main(), a bit big for stack: */ 120 /* used in tftpd_main(), a bit big for stack: */
121 char block_buf[TFTP_BLKSIZE_DEFAULT]; 121 char block_buf[TFTP_BLKSIZE_DEFAULT];
122#if ENABLE_FEATURE_TFTP_PROGRESS_BAR 122#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
@@ -130,13 +130,10 @@ struct globals {
130struct BUG_G_too_big { 130struct BUG_G_too_big {
131 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 131 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
132}; 132};
133#define block_buf (G.block_buf )
134#define user_opt (G.user_opt )
135#define error_pkt (G.error_pkt )
136#define INIT_G() do { } while (0) 133#define INIT_G() do { } while (0)
137 134
138#define error_pkt_reason (error_pkt[3]) 135#define G_error_pkt_reason (G.error_pkt[3])
139#define error_pkt_str (error_pkt + 4) 136#define G_error_pkt_str ((char*)(G.error_pkt + 4))
140 137
141#if ENABLE_FEATURE_TFTP_PROGRESS_BAR 138#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
142static void tftp_progress_update(void) 139static void tftp_progress_update(void)
@@ -272,12 +269,11 @@ static int tftp_protocol(
272 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len); 269 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
273 270
274 /* Is there an error already? Send pkt and bail out */ 271 /* Is there an error already? Send pkt and bail out */
275 if (error_pkt_reason || error_pkt_str[0]) 272 if (G_error_pkt_reason || G_error_pkt_str[0])
276 goto send_err_pkt; 273 goto send_err_pkt;
277 274
278 if (user_opt) { 275 if (G.pw) {
279 struct passwd *pw = xgetpwnam(user_opt); 276 change_identity(G.pw); /* initgroups, setgid, setuid */
280 change_identity(pw); /* initgroups, setgid, setuid */
281 } 277 }
282 } 278 }
283 279
@@ -329,8 +325,8 @@ static int tftp_protocol(
329 /* Open file (must be after changing user) */ 325 /* Open file (must be after changing user) */
330 local_fd = open(local_file, open_mode, 0666); 326 local_fd = open(local_file, open_mode, 0666);
331 if (local_fd < 0) { 327 if (local_fd < 0) {
332 error_pkt_reason = ERR_NOFILE; 328 G_error_pkt_reason = ERR_NOFILE;
333 strcpy((char*)error_pkt_str, "can't open file"); 329 strcpy(G_error_pkt_str, "can't open file");
334 goto send_err_pkt; 330 goto send_err_pkt;
335 } 331 }
336/* gcc 4.3.1 would NOT optimize it out as it should! */ 332/* gcc 4.3.1 would NOT optimize it out as it should! */
@@ -575,7 +571,7 @@ static int tftp_protocol(
575 if (res) { 571 if (res) {
576 blksize = tftp_blksize_check(res, blksize); 572 blksize = tftp_blksize_check(res, blksize);
577 if (blksize < 0) { 573 if (blksize < 0) {
578 error_pkt_reason = ERR_BAD_OPT; 574 G_error_pkt_reason = ERR_BAD_OPT;
579 goto send_err_pkt; 575 goto send_err_pkt;
580 } 576 }
581 io_bufsize = blksize + 4; 577 io_bufsize = blksize + 4;
@@ -614,8 +610,8 @@ static int tftp_protocol(
614 if (recv_blk == block_nr) { 610 if (recv_blk == block_nr) {
615 int sz = full_write(local_fd, &rbuf[4], len - 4); 611 int sz = full_write(local_fd, &rbuf[4], len - 4);
616 if (sz != len - 4) { 612 if (sz != len - 4) {
617 strcpy((char*)error_pkt_str, bb_msg_write_error); 613 strcpy(G_error_pkt_str, bb_msg_write_error);
618 error_pkt_reason = ERR_WRITE; 614 G_error_pkt_reason = ERR_WRITE;
619 goto send_err_pkt; 615 goto send_err_pkt;
620 } 616 }
621 if (sz != blksize) { 617 if (sz != blksize) {
@@ -664,12 +660,12 @@ static int tftp_protocol(
664 return finished == 0; /* returns 1 on failure */ 660 return finished == 0; /* returns 1 on failure */
665 661
666 send_read_err_pkt: 662 send_read_err_pkt:
667 strcpy((char*)error_pkt_str, bb_msg_read_error); 663 strcpy(G_error_pkt_str, bb_msg_read_error);
668 send_err_pkt: 664 send_err_pkt:
669 if (error_pkt_str[0]) 665 if (G_error_pkt_str[0])
670 bb_error_msg("%s", (char*)error_pkt_str); 666 bb_error_msg("%s", G_error_pkt_str);
671 error_pkt[1] = TFTP_ERROR; 667 G.error_pkt[1] = TFTP_ERROR;
672 xsendto(socket_fd, error_pkt, 4 + 1 + strlen((char*)error_pkt_str), 668 xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str),
673 &peer_lsa->u.sa, peer_lsa->len); 669 &peer_lsa->u.sa, peer_lsa->len);
674 return EXIT_FAILURE; 670 return EXIT_FAILURE;
675#undef remote_file 671#undef remote_file
@@ -761,7 +757,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
761{ 757{
762 len_and_sockaddr *our_lsa; 758 len_and_sockaddr *our_lsa;
763 len_and_sockaddr *peer_lsa; 759 len_and_sockaddr *peer_lsa;
764 char *local_file, *mode; 760 char *local_file, *mode, *user_opt;
765 const char *error_msg; 761 const char *error_msg;
766 int opt, result, opcode; 762 int opt, result, opcode;
767 IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;) 763 IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
@@ -789,18 +785,22 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
789 openlog(applet_name, LOG_PID, LOG_DAEMON); 785 openlog(applet_name, LOG_PID, LOG_DAEMON);
790 logmode = LOGMODE_SYSLOG; 786 logmode = LOGMODE_SYSLOG;
791 } 787 }
788 if (opt & TFTPD_OPT_u) {
789 /* Must be before xchroot */
790 G.pw = xgetpwnam(user_opt);
791 }
792 if (argv[0]) { 792 if (argv[0]) {
793 xchroot(argv[0]); 793 xchroot(argv[0]);
794 } 794 }
795 795
796 result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), 796 result = recv_from_to(STDIN_FILENO, G.block_buf, sizeof(G.block_buf),
797 0 /* flags */, 797 0 /* flags */,
798 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len); 798 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
799 799
800 error_msg = "malformed packet"; 800 error_msg = "malformed packet";
801 opcode = ntohs(*(uint16_t*)block_buf); 801 opcode = ntohs(*(uint16_t*)G.block_buf);
802 if (result < 4 || result >= sizeof(block_buf) 802 if (result < 4 || result >= sizeof(G.block_buf)
803 || block_buf[result-1] != '\0' 803 || G.block_buf[result-1] != '\0'
804 || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */ 804 || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
805 IF_GETPUT(&&) 805 IF_GETPUT(&&)
806 IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */ 806 IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
@@ -808,27 +808,27 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
808 ) { 808 ) {
809 goto err; 809 goto err;
810 } 810 }
811 local_file = block_buf + 2; 811 local_file = G.block_buf + 2;
812 if (local_file[0] == '.' || strstr(local_file, "/.")) { 812 if (local_file[0] == '.' || strstr(local_file, "/.")) {
813 error_msg = "dot in file name"; 813 error_msg = "dot in file name";
814 goto err; 814 goto err;
815 } 815 }
816 mode = local_file + strlen(local_file) + 1; 816 mode = local_file + strlen(local_file) + 1;
817 /* RFC 1350 says mode string is case independent */ 817 /* RFC 1350 says mode string is case independent */
818 if (mode >= block_buf + result || strcasecmp(mode, "octet") != 0) { 818 if (mode >= G.block_buf + result || strcasecmp(mode, "octet") != 0) {
819 goto err; 819 goto err;
820 } 820 }
821# if ENABLE_FEATURE_TFTP_BLOCKSIZE 821# if ENABLE_FEATURE_TFTP_BLOCKSIZE
822 { 822 {
823 char *res; 823 char *res;
824 char *opt_str = mode + sizeof("octet"); 824 char *opt_str = mode + sizeof("octet");
825 int opt_len = block_buf + result - opt_str; 825 int opt_len = G.block_buf + result - opt_str;
826 if (opt_len > 0) { 826 if (opt_len > 0) {
827 res = tftp_get_option("blksize", opt_str, opt_len); 827 res = tftp_get_option("blksize", opt_str, opt_len);
828 if (res) { 828 if (res) {
829 blksize = tftp_blksize_check(res, 65564); 829 blksize = tftp_blksize_check(res, 65564);
830 if (blksize < 0) { 830 if (blksize < 0) {
831 error_pkt_reason = ERR_BAD_OPT; 831 G_error_pkt_reason = ERR_BAD_OPT;
832 /* will just send error pkt */ 832 /* will just send error pkt */
833 goto do_proto; 833 goto do_proto;
834 } 834 }
@@ -846,7 +846,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
846 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { 846 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
847 if (opt & TFTPD_OPT_r) { 847 if (opt & TFTPD_OPT_r) {
848 /* This would mean "disk full" - not true */ 848 /* This would mean "disk full" - not true */
849 /*error_pkt_reason = ERR_WRITE;*/ 849 /*G_error_pkt_reason = ERR_WRITE;*/
850 error_msg = bb_msg_write_error; 850 error_msg = bb_msg_write_error;
851 goto err; 851 goto err;
852 } 852 }
@@ -855,7 +855,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
855 IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */ 855 IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
856 } 856 }
857 857
858 /* NB: if error_pkt_str or error_pkt_reason is set up, 858 /* NB: if G_error_pkt_str or G_error_pkt_reason is set up,
859 * tftp_protocol() just sends one error pkt and returns */ 859 * tftp_protocol() just sends one error pkt and returns */
860 860
861 do_proto: 861 do_proto:
@@ -870,7 +870,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
870 870
871 return result; 871 return result;
872 err: 872 err:
873 strcpy((char*)error_pkt_str, error_msg); 873 strcpy(G_error_pkt_str, error_msg);
874 goto do_proto; 874 goto do_proto;
875} 875}
876 876
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index cfd58679a..0e8e45fd2 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -14,7 +14,7 @@
14 14
15PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 15PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
16 16
17extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ 17extern const uint8_t MAC_BCAST_ADDR[6] ALIGN2; /* six all-ones */
18 18
19 19
20/*** DHCP packet ***/ 20/*** DHCP packet ***/
@@ -187,8 +187,8 @@ struct option_set {
187}; 187};
188 188
189extern const struct dhcp_optflag dhcp_optflags[]; 189extern const struct dhcp_optflag dhcp_optflags[];
190extern const char dhcp_option_strings[]; 190extern const char dhcp_option_strings[] ALIGN1;
191extern const uint8_t dhcp_option_lengths[]; 191extern const uint8_t dhcp_option_lengths[] ALIGN1;
192 192
193unsigned FAST_FUNC udhcp_option_idx(const char *name); 193unsigned FAST_FUNC udhcp_option_idx(const char *name);
194 194
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 7c9f52ae7..dda4a9112 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -965,8 +965,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
965 SERVER_PORT = CLIENT_PORT - 1; 965 SERVER_PORT = CLIENT_PORT - 1;
966 } 966 }
967#endif 967#endif
968 if (opt & OPT_o)
969 client_config.no_default_options = 1;
970 while (list_O) { 968 while (list_O) {
971 char *optstr = llist_pop(&list_O); 969 char *optstr = llist_pop(&list_O);
972 unsigned n = bb_strtou(optstr, NULL, 0); 970 unsigned n = bb_strtou(optstr, NULL, 0);
@@ -976,6 +974,16 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
976 } 974 }
977 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 975 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
978 } 976 }
977 if (!(opt & OPT_o)) {
978 /*
979 unsigned i, n;
980 for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) {
981 if (dhcp_optflags[i].flags & OPTION_REQ) {
982 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
983 }
984 }
985 */
986 }
979 while (list_x) { 987 while (list_x) {
980 char *optstr = llist_pop(&list_x); 988 char *optstr = llist_pop(&list_x);
981 char *colon = strchr(optstr, ':'); 989 char *colon = strchr(optstr, ':');
@@ -1066,8 +1074,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1066 retval = 0; 1074 retval = 0;
1067 /* If we already timed out, fall through with retval = 0, else... */ 1075 /* If we already timed out, fall through with retval = 0, else... */
1068 if ((int)tv.tv_sec > 0) { 1076 if ((int)tv.tv_sec > 0) {
1077 log1("Waiting on select %u seconds", (int)tv.tv_sec);
1069 timestamp_before_wait = (unsigned)monotonic_sec(); 1078 timestamp_before_wait = (unsigned)monotonic_sec();
1070 log1("Waiting on select...");
1071 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 1079 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
1072 if (retval < 0) { 1080 if (retval < 0) {
1073 /* EINTR? A signal was caught, don't panic */ 1081 /* EINTR? A signal was caught, don't panic */
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index ddb328dd5..bc1db7087 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -589,7 +589,6 @@ static void init_packet(struct dhcp_packet *packet, char type)
589 589
590static void add_client_options(struct dhcp_packet *packet) 590static void add_client_options(struct dhcp_packet *packet)
591{ 591{
592 uint8_t c;
593 int i, end, len; 592 int i, end, len;
594 593
595 udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE)); 594 udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE));
@@ -599,13 +598,9 @@ static void add_client_options(struct dhcp_packet *packet)
599 * No bounds checking because it goes towards the head of the packet. */ 598 * No bounds checking because it goes towards the head of the packet. */
600 end = udhcp_end_option(packet->options); 599 end = udhcp_end_option(packet->options);
601 len = 0; 600 len = 0;
602 for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { 601 for (i = 1; i < DHCP_END; i++) {
603 if (( (dhcp_optflags[i].flags & OPTION_REQ) 602 if (client_config.opt_mask[i >> 3] & (1 << (i & 7))) {
604 && !client_config.no_default_options 603 packet->options[end + OPT_DATA + len] = i;
605 )
606 || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
607 ) {
608 packet->options[end + OPT_DATA + len] = c;
609 len++; 604 len++;
610 } 605 }
611 } 606 }
@@ -1257,8 +1252,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1257 SERVER_PORT = CLIENT_PORT - 1; 1252 SERVER_PORT = CLIENT_PORT - 1;
1258 } 1253 }
1259#endif 1254#endif
1260 if (opt & OPT_o)
1261 client_config.no_default_options = 1;
1262 while (list_O) { 1255 while (list_O) {
1263 char *optstr = llist_pop(&list_O); 1256 char *optstr = llist_pop(&list_O);
1264 unsigned n = bb_strtou(optstr, NULL, 0); 1257 unsigned n = bb_strtou(optstr, NULL, 0);
@@ -1268,6 +1261,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1268 } 1261 }
1269 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 1262 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1270 } 1263 }
1264 if (!(opt & OPT_o)) {
1265 unsigned i, n;
1266 for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) {
1267 if (dhcp_optflags[i].flags & OPTION_REQ) {
1268 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1269 }
1270 }
1271 }
1271 while (list_x) { 1272 while (list_x) {
1272 char *optstr = llist_pop(&list_x); 1273 char *optstr = llist_pop(&list_x);
1273 char *colon = strchr(optstr, ':'); 1274 char *colon = strchr(optstr, ':');
@@ -1362,8 +1363,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1362 retval = 0; 1363 retval = 0;
1363 /* If we already timed out, fall through with retval = 0, else... */ 1364 /* If we already timed out, fall through with retval = 0, else... */
1364 if ((int)tv.tv_sec > 0) { 1365 if ((int)tv.tv_sec > 0) {
1366 log1("Waiting on select %u seconds", (int)tv.tv_sec);
1365 timestamp_before_wait = (unsigned)monotonic_sec(); 1367 timestamp_before_wait = (unsigned)monotonic_sec();
1366 log1("Waiting on select...");
1367 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 1368 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
1368 if (retval < 0) { 1369 if (retval < 0) {
1369 /* EINTR? A signal was caught, don't panic */ 1370 /* EINTR? A signal was caught, don't panic */
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h
index 2b3599120..2859a0772 100644
--- a/networking/udhcp/dhcpc.h
+++ b/networking/udhcp/dhcpc.h
@@ -9,7 +9,6 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
9 9
10struct client_config_t { 10struct client_config_t {
11 uint8_t client_mac[6]; /* Our mac address */ 11 uint8_t client_mac[6]; /* Our mac address */
12 char no_default_options; /* Do not include default options in request */
13 IF_FEATURE_UDHCP_PORT(uint16_t port;) 12 IF_FEATURE_UDHCP_PORT(uint16_t port;)
14 int ifindex; /* Index number of the interface to use */ 13 int ifindex; /* Index number of the interface to use */
15 uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ 14 uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index dd55e70f4..9ad95954d 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -377,6 +377,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
377 /* Setup the signal pipe */ 377 /* Setup the signal pipe */
378 udhcp_sp_setup(); 378 udhcp_sp_setup();
379 379
380 continue_with_autotime:
380 timeout_end = monotonic_sec() + server_config.auto_time; 381 timeout_end = monotonic_sec() + server_config.auto_time;
381 while (1) { /* loop until universe collapses */ 382 while (1) { /* loop until universe collapses */
382 fd_set rfds; 383 fd_set rfds;
@@ -406,8 +407,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
406 } 407 }
407 if (retval == 0) { 408 if (retval == 0) {
408 write_leases(); 409 write_leases();
409 timeout_end = monotonic_sec() + server_config.auto_time; 410 goto continue_with_autotime;
410 continue;
411 } 411 }
412 if (retval < 0 && errno != EINTR) { 412 if (retval < 0 && errno != EINTR) {
413 log1("Error on select"); 413 log1("Error on select");
@@ -419,10 +419,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
419 bb_info_msg("Received SIGUSR1"); 419 bb_info_msg("Received SIGUSR1");
420 write_leases(); 420 write_leases();
421 /* why not just reset the timeout, eh */ 421 /* why not just reset the timeout, eh */
422 timeout_end = monotonic_sec() + server_config.auto_time; 422 goto continue_with_autotime;
423 continue;
424 case SIGTERM: 423 case SIGTERM:
425 bb_info_msg("Received SIGTERM"); 424 bb_info_msg("Received SIGTERM");
425 write_leases();
426 goto ret0; 426 goto ret0;
427 case 0: /* no signal: read a packet */ 427 case 0: /* no signal: read a packet */
428 break; 428 break;
diff --git a/networking/udhcp/socket.c b/networking/udhcp/socket.c
index a5220ba74..a42106960 100644
--- a/networking/udhcp/socket.c
+++ b/networking/udhcp/socket.c
@@ -80,6 +80,7 @@ int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
80{ 80{
81 int fd; 81 int fd;
82 struct sockaddr_in addr; 82 struct sockaddr_in addr;
83 char *colon;
83 84
84 log1("Opening listen socket on *:%d %s", port, inf); 85 log1("Opening listen socket on *:%d %s", port, inf);
85 fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 86 fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -88,10 +89,17 @@ int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
88 if (setsockopt_broadcast(fd) == -1) 89 if (setsockopt_broadcast(fd) == -1)
89 bb_perror_msg_and_die("SO_BROADCAST"); 90 bb_perror_msg_and_die("SO_BROADCAST");
90 91
91 /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */ 92 /* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */
93 colon = strrchr(inf, ':');
94 if (colon)
95 *colon = '\0';
96
92 if (setsockopt_bindtodevice(fd, inf)) 97 if (setsockopt_bindtodevice(fd, inf))
93 xfunc_die(); /* warning is already printed */ 98 xfunc_die(); /* warning is already printed */
94 99
100 if (colon)
101 *colon = ':';
102
95 memset(&addr, 0, sizeof(addr)); 103 memset(&addr, 0, sizeof(addr));
96 addr.sin_family = AF_INET; 104 addr.sin_family = AF_INET;
97 addr.sin_port = htons(port); 105 addr.sin_port = htons(port);
diff --git a/networking/wget.c b/networking/wget.c
index 1991a1072..4eafebe40 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -13,8 +13,9 @@
13//usage: IF_FEATURE_WGET_LONG_OPTIONS( 13//usage: IF_FEATURE_WGET_LONG_OPTIONS(
14//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" 14//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n"
15//usage: " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" 15//usage: " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n"
16//usage: " [--no-check-certificate] [-U|--user-agent AGENT]" 16/* Since we ignore these opts, we don't show them in --help */
17//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." 17/* //usage: " [--no-check-certificate] [--no-cache]" */
18//usage: " [-U|--user-agent AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..."
18//usage: ) 19//usage: )
19//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS( 20//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS(
20//usage: "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]" 21//usage: "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]"
@@ -35,8 +36,11 @@
35 36
36#include "libbb.h" 37#include "libbb.h"
37 38
38//#define log_io(...) bb_error_msg(__VA_ARGS__) 39#if 0
39#define log_io(...) ((void)0) 40# define log_io(...) bb_error_msg(__VA_ARGS__)
41#else
42# define log_io(...) ((void)0)
43#endif
40 44
41 45
42struct host_info { 46struct host_info {
@@ -316,8 +320,6 @@ static char *gethdr(FILE *fp)
316 char *s, *hdrval; 320 char *s, *hdrval;
317 int c; 321 int c;
318 322
319 /* *istrunc = 0; */
320
321 /* retrieve header line */ 323 /* retrieve header line */
322 c = fgets_and_trim(fp); 324 c = fgets_and_trim(fp);
323 325
@@ -348,6 +350,15 @@ static char *gethdr(FILE *fp)
348 return hdrval; 350 return hdrval;
349} 351}
350 352
353static void reset_beg_range_to_zero(void)
354{
355 bb_error_msg("restart failed");
356 G.beg_range = 0;
357 xlseek(G.output_fd, 0, SEEK_SET);
358 /* Done at the end instead: */
359 /* ftruncate(G.output_fd, 0); */
360}
361
351static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) 362static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
352{ 363{
353 FILE *sfp; 364 FILE *sfp;
@@ -415,10 +426,12 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
415 426
416 *dfpp = open_socket(lsa); 427 *dfpp = open_socket(lsa);
417 428
418 if (G.beg_range) { 429 if (G.beg_range != 0) {
419 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range); 430 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
420 if (ftpcmd(G.wget_buf, NULL, sfp) == 350) 431 if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
421 G.content_len -= G.beg_range; 432 G.content_len -= G.beg_range;
433 else
434 reset_beg_range_to_zero();
422 } 435 }
423 436
424 if (ftpcmd("RETR ", target->path, sfp) > 150) 437 if (ftpcmd("RETR ", target->path, sfp) > 150)
@@ -431,7 +444,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
431{ 444{
432#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 445#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
433# if ENABLE_FEATURE_WGET_TIMEOUT 446# if ENABLE_FEATURE_WGET_TIMEOUT
434 unsigned second_cnt; 447 unsigned second_cnt = G.timeout_seconds;
435# endif 448# endif
436 struct pollfd polldata; 449 struct pollfd polldata;
437 450
@@ -452,7 +465,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
452 * which messes up progress bar and/or timeout logic. 465 * which messes up progress bar and/or timeout logic.
453 * Because of nonblocking I/O, we need to dance 466 * Because of nonblocking I/O, we need to dance
454 * very carefully around EAGAIN. See explanation at 467 * very carefully around EAGAIN. See explanation at
455 * clearerr() call. 468 * clearerr() calls.
456 */ 469 */
457 ndelay_on(polldata.fd); 470 ndelay_on(polldata.fd);
458#endif 471#endif
@@ -460,32 +473,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
460 int n; 473 int n;
461 unsigned rdsz; 474 unsigned rdsz;
462 475
463 rdsz = sizeof(G.wget_buf);
464 if (G.got_clen) {
465 if (G.content_len < (off_t)sizeof(G.wget_buf)) {
466 if ((int)G.content_len <= 0)
467 break;
468 rdsz = (unsigned)G.content_len;
469 }
470 }
471
472#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 476#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
473# if ENABLE_FEATURE_WGET_TIMEOUT
474 second_cnt = G.timeout_seconds;
475# endif
476 while (1) {
477 if (safe_poll(&polldata, 1, 1000) != 0)
478 break; /* error, EOF, or data is available */
479# if ENABLE_FEATURE_WGET_TIMEOUT
480 if (second_cnt != 0 && --second_cnt == 0) {
481 progress_meter(PROGRESS_END);
482 bb_error_msg_and_die("download timed out");
483 }
484# endif
485 /* Needed for "stalled" indicator */
486 progress_meter(PROGRESS_BUMP);
487 }
488
489 /* fread internally uses read loop, which in our case 477 /* fread internally uses read loop, which in our case
490 * is usually exited when we get EAGAIN. 478 * is usually exited when we get EAGAIN.
491 * In this case, libc sets error marker on the stream. 479 * In this case, libc sets error marker on the stream.
@@ -495,36 +483,71 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
495 * into if (n <= 0) ... 483 * into if (n <= 0) ...
496 */ 484 */
497 clearerr(dfp); 485 clearerr(dfp);
498 errno = 0;
499#endif 486#endif
487 errno = 0;
488 rdsz = sizeof(G.wget_buf);
489 if (G.got_clen) {
490 if (G.content_len < (off_t)sizeof(G.wget_buf)) {
491 if ((int)G.content_len <= 0)
492 break;
493 rdsz = (unsigned)G.content_len;
494 }
495 }
500 n = fread(G.wget_buf, 1, rdsz, dfp); 496 n = fread(G.wget_buf, 1, rdsz, dfp);
501 /* man fread: 497
498 if (n > 0) {
499 xwrite(G.output_fd, G.wget_buf, n);
500#if ENABLE_FEATURE_WGET_STATUSBAR
501 G.transferred += n;
502#endif
503 if (G.got_clen) {
504 G.content_len -= n;
505 if (G.content_len == 0)
506 break;
507 }
508#if ENABLE_FEATURE_WGET_TIMEOUT
509 second_cnt = G.timeout_seconds;
510#endif
511 continue;
512 }
513
514 /* n <= 0.
515 * man fread:
502 * If error occurs, or EOF is reached, the return value 516 * If error occurs, or EOF is reached, the return value
503 * is a short item count (or zero). 517 * is a short item count (or zero).
504 * fread does not distinguish between EOF and error. 518 * fread does not distinguish between EOF and error.
505 */ 519 */
506 if (n <= 0) { 520 if (errno != EAGAIN) {
507#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 521 if (ferror(dfp)) {
508 if (errno == EAGAIN) /* poll lied, there is no data? */ 522 progress_meter(PROGRESS_END);
509 continue; /* yes */
510#endif
511 if (ferror(dfp))
512 bb_perror_msg_and_die(bb_msg_read_error); 523 bb_perror_msg_and_die(bb_msg_read_error);
524 }
513 break; /* EOF, not error */ 525 break; /* EOF, not error */
514 } 526 }
515 527
516 xwrite(G.output_fd, G.wget_buf, n); 528#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
517 529 /* It was EAGAIN. There is no data. Wait up to one second
518#if ENABLE_FEATURE_WGET_STATUSBAR 530 * then abort if timed out, or update the bar and try reading again.
519 G.transferred += n; 531 */
532 if (safe_poll(&polldata, 1, 1000) == 0) {
533# if ENABLE_FEATURE_WGET_TIMEOUT
534 if (second_cnt != 0 && --second_cnt == 0) {
535 progress_meter(PROGRESS_END);
536 bb_error_msg_and_die("download timed out");
537 }
538# endif
539 /* We used to loop back to poll here,
540 * but there is no great harm in letting fread
541 * to try reading anyway.
542 */
543 }
544 /* Need to do it _every_ second for "stalled" indicator
545 * to be shown properly.
546 */
520 progress_meter(PROGRESS_BUMP); 547 progress_meter(PROGRESS_BUMP);
521#endif 548#endif
522 if (G.got_clen) { 549 } /* while (reading data) */
523 G.content_len -= n; 550
524 if (G.content_len == 0)
525 break;
526 }
527 }
528#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 551#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
529 clearerr(dfp); 552 clearerr(dfp);
530 ndelay_off(polldata.fd); /* else fgets can get very unhappy */ 553 ndelay_off(polldata.fd); /* else fgets can get very unhappy */
@@ -540,6 +563,24 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
540 if (G.content_len == 0) 563 if (G.content_len == 0)
541 break; /* all done! */ 564 break; /* all done! */
542 G.got_clen = 1; 565 G.got_clen = 1;
566 /*
567 * Note that fgets may result in some data being buffered in dfp.
568 * We loop back to fread, which will retrieve this data.
569 * Also note that code has to be arranged so that fread
570 * is done _before_ one-second poll wait - poll doesn't know
571 * about stdio buffering and can result in spurious one second waits!
572 */
573 }
574
575 /* If -c failed, we restart from the beginning,
576 * but we do not truncate file then, we do it only now, at the end.
577 * This lets user to ^C if his 99% complete 10 GB file download
578 * failed to restart *without* losing the almost complete file.
579 */
580 {
581 off_t pos = lseek(G.output_fd, 0, SEEK_CUR);
582 if (pos != (off_t)-1)
583 ftruncate(G.output_fd, pos);
543 } 584 }
544 585
545 /* Draw full bar and free its resources */ 586 /* Draw full bar and free its resources */
@@ -597,13 +638,11 @@ static void download_one_url(const char *url)
597 if (G.fname_out[0] == '/' || !G.fname_out[0]) 638 if (G.fname_out[0] == '/' || !G.fname_out[0])
598 G.fname_out = (char*)"index.html"; 639 G.fname_out = (char*)"index.html";
599 /* -P DIR is considered only if there was no -O FILE */ 640 /* -P DIR is considered only if there was no -O FILE */
641 if (G.dir_prefix)
642 G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out);
600 else { 643 else {
601 if (G.dir_prefix) 644 /* redirects may free target.path later, need to make a copy */
602 G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); 645 G.fname_out = fname_out_alloc = xstrdup(G.fname_out);
603 else {
604 /* redirects may free target.path later, need to make a copy */
605 G.fname_out = fname_out_alloc = xstrdup(G.fname_out);
606 }
607 } 646 }
608 } 647 }
609#if ENABLE_FEATURE_WGET_STATUSBAR 648#if ENABLE_FEATURE_WGET_STATUSBAR
@@ -675,7 +714,7 @@ static void download_one_url(const char *url)
675 } 714 }
676#endif 715#endif
677 716
678 if (G.beg_range) 717 if (G.beg_range != 0)
679 fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); 718 fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range);
680 719
681#if ENABLE_FEATURE_WGET_LONG_OPTIONS 720#if ENABLE_FEATURE_WGET_LONG_OPTIONS
@@ -742,15 +781,23 @@ However, in real world it was observed that some web servers
742(e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. 781(e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero.
743*/ 782*/
744 case 204: 783 case 204:
784 if (G.beg_range != 0) {
785 /* "Range:..." was not honored by the server.
786 * Restart download from the beginning.
787 */
788 reset_beg_range_to_zero();
789 }
745 break; 790 break;
746 case 300: /* redirection */ 791 case 300: /* redirection */
747 case 301: 792 case 301:
748 case 302: 793 case 302:
749 case 303: 794 case 303:
750 break; 795 break;
751 case 206: 796 case 206: /* Partial Content */
752 if (G.beg_range) 797 if (G.beg_range != 0)
798 /* "Range:..." worked. Good. */
753 break; 799 break;
800 /* Partial Content even though we did not ask for it??? */
754 /* fall through */ 801 /* fall through */
755 default: 802 default:
756 bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); 803 bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf));
@@ -878,6 +925,8 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
878 "post-data\0" Required_argument "\xfd" 925 "post-data\0" Required_argument "\xfd"
879 /* Ignored (we don't do ssl) */ 926 /* Ignored (we don't do ssl) */
880 "no-check-certificate\0" No_argument "\xfc" 927 "no-check-certificate\0" No_argument "\xfc"
928 /* Ignored (we don't support caching) */
929 "no-cache\0" No_argument "\xfb"
881 ; 930 ;
882#endif 931#endif
883 932
diff --git a/printutils/lpr.c b/printutils/lpr.c
index 748879542..70cda7717 100644
--- a/printutils/lpr.c
+++ b/printutils/lpr.c
@@ -89,6 +89,10 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[])
89 unsigned opts; 89 unsigned opts;
90 int fd; 90 int fd;
91 91
92 queue = getenv("PRINTER");
93 if (!queue)
94 queue = "lp";
95
92 // parse options 96 // parse options
93 // TODO: set opt_complementary: s,d,f are mutually exclusive 97 // TODO: set opt_complementary: s,d,f are mutually exclusive
94 opts = getopt32(argv, 98 opts = getopt32(argv,
@@ -98,16 +102,7 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[])
98 ); 102 );
99 argv += optind; 103 argv += optind;
100 104
101 // if queue is not specified -> use $PRINTER 105 {
102 if (!(opts & OPT_P))
103 queue = getenv("PRINTER");
104 // if queue is still not specified ->
105 if (!queue) {
106 // ... queue defaults to "lp"
107 // server defaults to "localhost"
108 queue = "lp";
109 // if queue is specified ->
110 } else {
111 // queue name is to the left of '@' 106 // queue name is to the left of '@'
112 char *s = strchr(queue, '@'); 107 char *s = strchr(queue, '@');
113 if (s) { 108 if (s) {
@@ -186,6 +181,17 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[])
186 dfd = xopen(*argv, O_RDONLY); 181 dfd = xopen(*argv, O_RDONLY);
187 } 182 }
188 183
184 st.st_size = 0; /* paranoia: fstat may theoretically fail */
185 fstat(dfd, &st);
186
187 /* Apparently, some servers are buggy and won't accept 0-sized jobs.
188 * Standard lpr works around it by refusing to send such jobs:
189 */
190 if (st.st_size == 0) {
191 bb_error_msg("nothing to print");
192 continue;
193 }
194
189 /* "The name ... should start with ASCII "cfA", 195 /* "The name ... should start with ASCII "cfA",
190 * followed by a three digit job number, followed 196 * followed by a three digit job number, followed
191 * by the host name which has constructed the file." 197 * by the host name which has constructed the file."
@@ -210,7 +216,7 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[])
210 , (opts & LPR_m) ? user : "" 216 , (opts & LPR_m) ? user : ""
211 , remote_filename 217 , remote_filename
212 ); 218 );
213 // delete possible "\nX\n" patterns 219 // delete possible "\nX\n" (that is, one-char) patterns
214 c = controlfile; 220 c = controlfile;
215 while ((c = strchr(c, '\n')) != NULL) { 221 while ((c = strchr(c, '\n')) != NULL) {
216 if (c[1] && c[2] == '\n') { 222 if (c[1] && c[2] == '\n') {
@@ -239,8 +245,6 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[])
239 // send data file, with name "dfaXXX" 245 // send data file, with name "dfaXXX"
240 if (opts & LPR_V) 246 if (opts & LPR_V)
241 bb_error_msg("sending data file"); 247 bb_error_msg("sending data file");
242 st.st_size = 0; /* paranoia: fstat may theoretically fail */
243 fstat(dfd, &st);
244 fdprintf(fd, "\x3" "%"OFF_FMT"u d%s\n", st.st_size, remote_filename); 248 fdprintf(fd, "\x3" "%"OFF_FMT"u d%s\n", st.st_size, remote_filename);
245 get_response_or_say_and_die(fd, "sending data file"); 249 get_response_or_say_and_die(fd, "sending data file");
246 if (bb_copyfd_size(dfd, fd, st.st_size) != st.st_size) { 250 if (bb_copyfd_size(dfd, fd, st.st_size) != st.st_size) {
diff --git a/procps/powertop.c b/procps/powertop.c
index 008cdfca4..b4c45edbc 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -9,7 +9,7 @@
9 * Licensed under GPLv2, see file LICENSE in this source tree. 9 * Licensed under GPLv2, see file LICENSE in this source tree.
10 */ 10 */
11 11
12//applet:IF_POWERTOP(APPLET(powertop, BB_DIR_BIN, BB_SUID_DROP)) 12//applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP))
13 13
14//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o 14//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o
15 15
diff --git a/procps/ps.c b/procps/ps.c
index aa004aa22..dc6fda61d 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -69,6 +69,31 @@
69/* Absolute maximum on output line length */ 69/* Absolute maximum on output line length */
70enum { MAX_WIDTH = 2*1024 }; 70enum { MAX_WIDTH = 2*1024 };
71 71
72#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG
73static long get_uptime(void)
74{
75#ifdef __linux__
76 struct sysinfo info;
77 if (sysinfo(&info) < 0)
78 return 0;
79 return info.uptime;
80#elif 1
81 char buf[64];
82 long uptime;
83 if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0)
84 bb_perror_msg_and_die("can't read %s", "/proc/uptime");
85 buf[sizeof(buf)-1] = '\0';
86 sscanf(buf, "%l", &uptime);
87 return uptime;
88#else
89 struct timespec ts;
90 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
91 return 0;
92 return ts.tv_sec;
93#endif
94}
95#endif
96
72#if ENABLE_DESKTOP 97#if ENABLE_DESKTOP
73 98
74#include <sys/times.h> /* for times() */ 99#include <sys/times.h> /* for times() */
@@ -197,8 +222,6 @@ static inline unsigned get_HZ_by_waiting(void)
197 222
198static unsigned get_kernel_HZ(void) 223static unsigned get_kernel_HZ(void)
199{ 224{
200 //char buf[64];
201 struct sysinfo info;
202 225
203 if (kernel_HZ) 226 if (kernel_HZ)
204 return kernel_HZ; 227 return kernel_HZ;
@@ -208,12 +231,7 @@ static unsigned get_kernel_HZ(void)
208 if (kernel_HZ == (unsigned)-1) 231 if (kernel_HZ == (unsigned)-1)
209 kernel_HZ = get_HZ_by_waiting(); 232 kernel_HZ = get_HZ_by_waiting();
210 233
211 //if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0) 234 seconds_since_boot = get_uptime();
212 // bb_perror_msg_and_die("can't read %s", "/proc/uptime");
213 //buf[sizeof(buf)-1] = '\0';
214 ///sscanf(buf, "%llu", &seconds_since_boot);
215 sysinfo(&info);
216 seconds_since_boot = info.uptime;
217 235
218 return kernel_HZ; 236 return kernel_HZ;
219} 237}
@@ -645,7 +663,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
645 }; 663 };
646#if ENABLE_FEATURE_PS_LONG 664#if ENABLE_FEATURE_PS_LONG
647 time_t now = now; 665 time_t now = now;
648 struct sysinfo info; 666 long uptime;
649#endif 667#endif
650 int opts = 0; 668 int opts = 0;
651 /* If we support any options, parse argv */ 669 /* If we support any options, parse argv */
@@ -705,7 +723,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
705 puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD"); 723 puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD");
706#if ENABLE_FEATURE_PS_LONG 724#if ENABLE_FEATURE_PS_LONG
707 now = time(NULL); 725 now = time(NULL);
708 sysinfo(&info); 726 uptime = get_uptime();
709#endif 727#endif
710 } 728 }
711 else { 729 else {
@@ -737,7 +755,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
737 char tty[2 * sizeof(int)*3 + 2]; 755 char tty[2 * sizeof(int)*3 + 2];
738 char *endp; 756 char *endp;
739 unsigned sut = (p->stime + p->utime) / 100; 757 unsigned sut = (p->stime + p->utime) / 100;
740 unsigned elapsed = info.uptime - (p->start_time / 100); 758 unsigned elapsed = uptime - (p->start_time / 100);
741 time_t start = now - elapsed; 759 time_t start = now - elapsed;
742 struct tm *tm = localtime(&start); 760 struct tm *tm = localtime(&start);
743 761
diff --git a/procps/sysctl.c b/procps/sysctl.c
index 5296d0f58..878656862 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -12,21 +12,23 @@
12 */ 12 */
13 13
14//usage:#define sysctl_trivial_usage 14//usage:#define sysctl_trivial_usage
15//usage: "[OPTIONS] [VALUE]..." 15//usage: "[OPTIONS] [KEY[=VALUE]]..."
16//usage:#define sysctl_full_usage "\n\n" 16//usage:#define sysctl_full_usage "\n\n"
17//usage: "Configure kernel parameters at runtime\n" 17//usage: "Show/set kernel parameters\n"
18//usage: "\n -n Don't print key names"
19//usage: "\n -e Don't warn about unknown keys" 18//usage: "\n -e Don't warn about unknown keys"
20//usage: "\n -w Change sysctl setting" 19//usage: "\n -n Don't show key names"
21//usage: "\n -p FILE Load sysctl settings from FILE (default /etc/sysctl.conf)" 20//usage: "\n -a Show all values"
22//usage: "\n -a Display all values" 21/* Same as -a, no need to show it */
23//usage: "\n -A Display all values in table form" 22/* //usage: "\n -A Show all values in table form" */
23//usage: "\n -w Set values"
24//usage: "\n -p FILE Set values from FILE (default /etc/sysctl.conf)"
25//usage: "\n -q Set values silently"
24//usage: 26//usage:
25//usage:#define sysctl_example_usage 27//usage:#define sysctl_example_usage
26//usage: "sysctl [-n] [-e] variable...\n" 28//usage: "sysctl [-n] [-e] variable...\n"
27//usage: "sysctl [-n] [-e] -w variable=value...\n" 29//usage: "sysctl [-n] [-e] [-q] -w variable=value...\n"
28//usage: "sysctl [-n] [-e] -a\n" 30//usage: "sysctl [-n] [-e] -a\n"
29//usage: "sysctl [-n] [-e] -p file (default /etc/sysctl.conf)\n" 31//usage: "sysctl [-n] [-e] [-q] -p file (default /etc/sysctl.conf)\n"
30//usage: "sysctl [-n] [-e] -A\n" 32//usage: "sysctl [-n] [-e] -A\n"
31 33
32#include "libbb.h" 34#include "libbb.h"
@@ -37,9 +39,11 @@ enum {
37 FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ 39 FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */
38 FLAG_SHOW_ALL = 1 << 3, 40 FLAG_SHOW_ALL = 1 << 3,
39 FLAG_PRELOAD_FILE = 1 << 4, 41 FLAG_PRELOAD_FILE = 1 << 4,
42/* TODO: procps 3.2.8 seems to not require -w for KEY=VAL to work: */
40 FLAG_WRITE = 1 << 5, 43 FLAG_WRITE = 1 << 5,
44 FLAG_QUIET = 1 << 6,
41}; 45};
42#define OPTION_STR "neAapw" 46#define OPTION_STR "neAapwq"
43 47
44static void sysctl_dots_to_slashes(char *name) 48static void sysctl_dots_to_slashes(char *name)
45{ 49{
@@ -144,9 +148,11 @@ static int sysctl_act_on_setting(char *setting)
144//TODO: procps 3.2.7 writes "value\n", note trailing "\n" 148//TODO: procps 3.2.7 writes "value\n", note trailing "\n"
145 xwrite_str(fd, value); 149 xwrite_str(fd, value);
146 close(fd); 150 close(fd);
147 if (option_mask32 & FLAG_SHOW_KEYS) 151 if (!(option_mask32 & FLAG_QUIET)) {
148 printf("%s = ", outname); 152 if (option_mask32 & FLAG_SHOW_KEYS)
149 puts(value); 153 printf("%s = ", outname);
154 puts(value);
155 }
150 } else { 156 } else {
151 char c; 157 char c;
152 158
diff --git a/runit/chpst.c b/runit/chpst.c
index ac296babf..ed72c8b8c 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -91,6 +91,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91//usage: "\n a SIGXCPU after N seconds" 91//usage: "\n a SIGXCPU after N seconds"
92 92
93#include "libbb.h" 93#include "libbb.h"
94#include <sys/resource.h> /* getrlimit */
94 95
95/* 96/*
96Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit. 97Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index d3f69f8f5..1b0b6ab07 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -9,6 +9,8 @@
9 */ 9 */
10 10
11#define _XOPEN_SOURCE 700 11#define _XOPEN_SOURCE 700
12/* On Darwin, this may be needed to get SIGWINCH: */
13#define _DARWIN_C_SOURCE 1
12 14
13#include <sys/ioctl.h> 15#include <sys/ioctl.h>
14#include <sys/wait.h> 16#include <sys/wait.h>
diff --git a/shell/ash.c b/shell/ash.c
index f7c12f8e1..46bf6ed49 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -37,8 +37,9 @@
37 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) 37 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
38 * define DEBUG=2 to compile in and turn on debugging. 38 * define DEBUG=2 to compile in and turn on debugging.
39 * 39 *
40 * When debugging is on, debugging info will be written to ./trace and 40 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
41 * a quit signal will generate a core dump. 41 * debugging info will be written to ./trace and a quit signal
42 * will generate a core dump.
42 */ 43 */
43#define DEBUG 0 44#define DEBUG 0
44/* Tweak debug output verbosity here */ 45/* Tweak debug output verbosity here */
@@ -1955,6 +1956,10 @@ static const struct {
1955 const char *var_text; 1956 const char *var_text;
1956 void (*var_func)(const char *) FAST_FUNC; 1957 void (*var_func)(const char *) FAST_FUNC;
1957} varinit_data[] = { 1958} varinit_data[] = {
1959 /*
1960 * Note: VEXPORT would not work correctly here for NOFORK applets:
1961 * some environment strings may be constant.
1962 */
1958 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, 1963 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1959#if ENABLE_ASH_MAIL 1964#if ENABLE_ASH_MAIL
1960 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, 1965 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
@@ -5401,14 +5406,15 @@ openredirect(union node *redir)
5401 char *fname; 5406 char *fname;
5402 int f; 5407 int f;
5403 5408
5409 fname = redir->nfile.expfname;
5404#if ENABLE_PLATFORM_MINGW32 5410#if ENABLE_PLATFORM_MINGW32
5405 /* Support for /dev/null */ 5411 /* Support for /dev/null */
5406 switch (redir->nfile.type) { 5412 switch (redir->nfile.type) {
5407 case NFROM: 5413 case NFROM:
5408 if (!strcmp(redir->nfile.expfname, "/dev/null")) 5414 if (!strcmp(fname, "/dev/null"))
5409 return open("nul",O_RDWR); 5415 return open("nul",O_RDWR);
5410 if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { 5416 if (!strncmp(fname, "/dev/", 5)) {
5411 ash_msg("Unhandled device %s\n", redir->nfile.expfname); 5417 ash_msg("Unhandled device %s\n", fname);
5412 return -1; 5418 return -1;
5413 } 5419 }
5414 break; 5420 break;
@@ -5417,10 +5423,10 @@ openredirect(union node *redir)
5417 case NTO: 5423 case NTO:
5418 case NCLOBBER: 5424 case NCLOBBER:
5419 case NAPPEND: 5425 case NAPPEND:
5420 if (!strcmp(redir->nfile.expfname, "/dev/null")) 5426 if (!strcmp(fname, "/dev/null"))
5421 return open("nul",O_RDWR); 5427 return open("nul",O_RDWR);
5422 if (!strncmp(redir->nfile.expfname, "/dev/", 5)) { 5428 if (!strncmp(fname, "/dev/", 5)) {
5423 ash_msg("Unhandled device %s\n", redir->nfile.expfname); 5429 ash_msg("Unhandled device %s\n", fname);
5424 return -1; 5430 return -1;
5425 } 5431 }
5426 break; 5432 break;
@@ -5428,13 +5434,11 @@ openredirect(union node *redir)
5428#endif 5434#endif
5429 switch (redir->nfile.type) { 5435 switch (redir->nfile.type) {
5430 case NFROM: 5436 case NFROM:
5431 fname = redir->nfile.expfname;
5432 f = open(fname, O_RDONLY); 5437 f = open(fname, O_RDONLY);
5433 if (f < 0) 5438 if (f < 0)
5434 goto eopen; 5439 goto eopen;
5435 break; 5440 break;
5436 case NFROMTO: 5441 case NFROMTO:
5437 fname = redir->nfile.expfname;
5438 f = open(fname, O_RDWR|O_CREAT, 0666); 5442 f = open(fname, O_RDWR|O_CREAT, 0666);
5439 if (f < 0) 5443 if (f < 0)
5440 goto ecreate; 5444 goto ecreate;
@@ -5445,7 +5449,6 @@ openredirect(union node *redir)
5445#endif 5449#endif
5446 /* Take care of noclobber mode. */ 5450 /* Take care of noclobber mode. */
5447 if (Cflag) { 5451 if (Cflag) {
5448 fname = redir->nfile.expfname;
5449 f = noclobberopen(fname); 5452 f = noclobberopen(fname);
5450 if (f < 0) 5453 if (f < 0)
5451 goto ecreate; 5454 goto ecreate;
@@ -5453,13 +5456,11 @@ openredirect(union node *redir)
5453 } 5456 }
5454 /* FALLTHROUGH */ 5457 /* FALLTHROUGH */
5455 case NCLOBBER: 5458 case NCLOBBER:
5456 fname = redir->nfile.expfname;
5457 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 5459 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5458 if (f < 0) 5460 if (f < 0)
5459 goto ecreate; 5461 goto ecreate;
5460 break; 5462 break;
5461 case NAPPEND: 5463 case NAPPEND:
5462 fname = redir->nfile.expfname;
5463 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5464 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5464 if (f < 0) 5465 if (f < 0)
5465 goto ecreate; 5466 goto ecreate;
@@ -6491,7 +6492,9 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6491 length++; 6492 length++;
6492 goto addquote; 6493 goto addquote;
6493 case CTLVAR: 6494 case CTLVAR:
6495 TRACE(("argstr: evalvar('%s')\n", p));
6494 p = evalvar(p, flags, var_str_list); 6496 p = evalvar(p, flags, var_str_list);
6497 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6495 goto start; 6498 goto start;
6496 case CTLBACKQ: 6499 case CTLBACKQ:
6497 c = '\0'; 6500 c = '\0';
@@ -7199,8 +7202,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7199 patloc = expdest - (char *)stackblock(); 7202 patloc = expdest - (char *)stackblock();
7200 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 7203 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7201 startloc, varflags, 7204 startloc, varflags,
7202//TODO: | EXP_REDIR too? All other such places do it too 7205 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
7203 /* quotes: */ flags & (EXP_FULL | EXP_CASE),
7204 var_str_list) 7206 var_str_list)
7205 ) { 7207 ) {
7206 int amount = expdest - ( 7208 int amount = expdest - (
@@ -7602,6 +7604,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7602 STARTSTACKSTR(expdest); 7604 STARTSTACKSTR(expdest);
7603 ifsfirst.next = NULL; 7605 ifsfirst.next = NULL;
7604 ifslastp = NULL; 7606 ifslastp = NULL;
7607 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7605 argstr(arg->narg.text, flag, 7608 argstr(arg->narg.text, flag,
7606 /* var_str_list: */ arglist ? arglist->list : NULL); 7609 /* var_str_list: */ arglist ? arglist->list : NULL);
7607 p = _STPUTC('\0', expdest); 7610 p = _STPUTC('\0', expdest);
@@ -7610,6 +7613,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7610 return; /* here document expanded */ 7613 return; /* here document expanded */
7611 } 7614 }
7612 p = grabstackstr(p); 7615 p = grabstackstr(p);
7616 TRACE(("expandarg: p:'%s'\n", p));
7613 exparg.lastp = &exparg.list; 7617 exparg.lastp = &exparg.list;
7614 /* 7618 /*
7615 * TODO - EXP_REDIR 7619 * TODO - EXP_REDIR
@@ -7620,8 +7624,10 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7620 exparg.lastp = &exparg.list; 7624 exparg.lastp = &exparg.list;
7621 expandmeta(exparg.list /*, flag*/); 7625 expandmeta(exparg.list /*, flag*/);
7622 } else { 7626 } else {
7623 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 7627 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7624 rmescapes(p, 0); 7628 rmescapes(p, 0);
7629 TRACE(("expandarg: rmescapes:'%s'\n", p));
7630 }
7625 sp = stzalloc(sizeof(*sp)); 7631 sp = stzalloc(sizeof(*sp));
7626 sp->text = p; 7632 sp->text = p;
7627 *exparg.lastp = sp; 7633 *exparg.lastp = sp;
@@ -9090,6 +9096,7 @@ expredir(union node *n)
9090 case NCLOBBER: 9096 case NCLOBBER:
9091 case NAPPEND: 9097 case NAPPEND:
9092 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 9098 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9099 TRACE(("expredir expanded to '%s'\n", fn.list->text));
9093#if ENABLE_ASH_BASH_COMPAT 9100#if ENABLE_ASH_BASH_COMPAT
9094 store_expfname: 9101 store_expfname:
9095#endif 9102#endif
@@ -13343,6 +13350,10 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13343 } 13350 }
13344 } 13351 }
13345 13352
13353 /* "read -s" needs to save/restore termios, can't allow ^C
13354 * to jump out of it.
13355 */
13356 INT_OFF;
13346 r = shell_builtin_read(setvar2, 13357 r = shell_builtin_read(setvar2,
13347 argptr, 13358 argptr,
13348 bltinlookup("IFS"), /* can be NULL */ 13359 bltinlookup("IFS"), /* can be NULL */
@@ -13352,6 +13363,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13352 opt_t, 13363 opt_t,
13353 opt_u 13364 opt_u
13354 ); 13365 );
13366 INT_ON;
13355 13367
13356 if ((uintptr_t)r > 1) 13368 if ((uintptr_t)r > 1)
13357 ash_msg_and_raise_error(r); 13369 ash_msg_and_raise_error(r);
diff --git a/shell/ash_test/ash-redir/redirA.right b/shell/ash_test/ash-redir/redirA.right
new file mode 100644
index 000000000..31406e336
--- /dev/null
+++ b/shell/ash_test/ash-redir/redirA.right
@@ -0,0 +1,2 @@
1tmp11
2tmp11
diff --git a/shell/ash_test/ash-redir/redirA.tests b/shell/ash_test/ash-redir/redirA.tests
new file mode 100755
index 000000000..56833f938
--- /dev/null
+++ b/shell/ash_test/ash-redir/redirA.tests
@@ -0,0 +1,11 @@
1x="tmp11:tmp22"
2
3# Bug was incorrectly expanding variables in >redir
4echo "${x%:*}" >"${x%:*}"
5echo tmp1*
6rm tmp1*
7
8# Also try unquoted
9echo "${x%:*}" >${x%:*}
10echo tmp1*
11rm tmp1*
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 0ffe21e0b..f7503cac5 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -18,6 +18,9 @@
18 */ 18 */
19#include "libbb.h" 19#include "libbb.h"
20#include "shell_common.h" 20#include "shell_common.h"
21#if !ENABLE_PLATFORM_MINGW32
22#include <sys/resource.h> /* getrlimit */
23#endif
21 24
22const char defifsvar[] ALIGN1 = "IFS= \t\n"; 25const char defifsvar[] ALIGN1 = "IFS= \t\n";
23 26
@@ -169,7 +172,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
169 int timeout; 172 int timeout;
170 173
171 if ((bufpos & 0xff) == 0) 174 if ((bufpos & 0xff) == 0)
172 buffer = xrealloc(buffer, bufpos + 0x100); 175 buffer = xrealloc(buffer, bufpos + 0x101);
173 176
174 timeout = -1; 177 timeout = -1;
175 if (end_ms) { 178 if (end_ms) {
diff --git a/shell/shell_common.h b/shell/shell_common.h
index f06bc4120..993ed5951 100644
--- a/shell/shell_common.h
+++ b/shell/shell_common.h
@@ -21,7 +21,7 @@
21 21
22PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 22PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
23 23
24extern const char defifsvar[]; /* "IFS= \t\n" */ 24extern const char defifsvar[] ALIGN1; /* "IFS= \t\n" */
25#define defifs (defifsvar + 4) 25#define defifs (defifsvar + 4)
26 26
27int FAST_FUNC is_well_formed_var_name(const char *s, char terminator); 27int FAST_FUNC is_well_formed_var_name(const char *s, char terminator);
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 5a323047d..f9c3b6b4d 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -16,6 +16,13 @@ testing "awk -F case 5" "awk -F '[#]' '{ print NF }'" "4\n" "" "#abc##zz\n"
16testing "awk -F case 6" "awk -F '[#]' '{ print NF }'" "4\n" "" "z#abc##zz\n" 16testing "awk -F case 6" "awk -F '[#]' '{ print NF }'" "4\n" "" "z#abc##zz\n"
17testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n" 17testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n"
18 18
19# conditions and operators
20testing "awk if operator == " "awk 'BEGIN{if(23==23) print \"foo\"}'" "foo\n" "" ""
21testing "awk if operator != " "awk 'BEGIN{if(23!=23) print \"bar\"}'" "" "" ""
22testing "awk if operator >= " "awk 'BEGIN{if(23>=23) print \"foo\"}'" "foo\n" "" ""
23testing "awk if operator < " "awk 'BEGIN{if(2 < 13) print \"foo\"}'" "foo\n" "" ""
24testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" "" ""
25
19# 4294967295 = 0xffffffff 26# 4294967295 = 0xffffffff
20testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" 27testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n"
21optional DESKTOP 28optional DESKTOP
@@ -36,6 +43,11 @@ testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \
36 "" \ 43 "" \
37 "a--\na--b--\na--b--c--\na--b--c--d--" 44 "a--\na--b--\na--b--c--\na--b--c--d--"
38 45
46testing "awk -F handles escapes" "awk -F'\\x21' '{print \$1}'" \
47 "a\n" \
48 "" \
49 "a!b\n"
50
39# '@(samp|code|file)\{' is an invalid extended regex (unmatched '{'), 51# '@(samp|code|file)\{' is an invalid extended regex (unmatched '{'),
40# but gawk 3.1.5 does not bail out on it. 52# but gawk 3.1.5 does not bail out on it.
41testing "awk gsub falls back to non-extended-regex" \ 53testing "awk gsub falls back to non-extended-regex" \
@@ -205,4 +217,11 @@ end d
205testing "awk handles empty ()" \ 217testing "awk handles empty ()" \
206 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" 218 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""
207 219
220testing "awk FS assignment" "awk '{FS=\":\"; print \$1}'" \
221 "a:b\ne\n" \
222 "" \
223 "a:b c:d\ne:f g:h"
224
225# testing "description" "command" "result" "infile" "stdin"
226
208exit $FAILCOUNT 227exit $FAILCOUNT
diff --git a/testsuite/du/du-k-works b/testsuite/du/du-k-works
index 229a948ee..36dcaa85d 100644
--- a/testsuite/du/du-k-works
+++ b/testsuite/du/du-k-works
@@ -3,4 +3,5 @@ cd du.testdir
3dd if=/dev/zero of=file1 bs=1k count=64 2>/dev/null 3dd if=/dev/zero of=file1 bs=1k count=64 2>/dev/null
4dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null 4dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null
5test x"`busybox du -k .`" = x"80 ." \ 5test x"`busybox du -k .`" = x"80 ." \
6 -o x"`busybox du -k .`" = x"84 ." \
6 -o x"`busybox du -k .`" = x"88 ." 7 -o x"`busybox du -k .`" = x"88 ."
diff --git a/testsuite/mkfs.minix.tests b/testsuite/mkfs.minix.tests
index 8a33c1681..7eecaf230 100755
--- a/testsuite/mkfs.minix.tests
+++ b/testsuite/mkfs.minix.tests
@@ -8,6 +8,14 @@
8 8
9# testing "test name" "options" "expected result" "file input" "stdin" 9# testing "test name" "options" "expected result" "file input" "stdin"
10 10
11# '\n' produces 10 on little endian, but not on big endian
12cr=`echo | od -i | sed 's/.* //g;2d'`
13if [ x"$cr" = x"10" ]; then
14 hash=4f35f7afeba07d56055bed1f29ae20b7
15else
16 hash=5adbc1b3ccd20ca5d0ab5bc1e13ac3fc
17fi
18
11testing "mkfs.minix" \ 19testing "mkfs.minix" \
12 "dd if=/dev/zero of=input bs=1k count=1024 2>/dev/null; mkfs.minix input; md5sum <input" \ 20 "dd if=/dev/zero of=input bs=1k count=1024 2>/dev/null; mkfs.minix input; md5sum <input" \
13"352 inodes\n"\ 21"352 inodes\n"\
@@ -15,7 +23,7 @@ testing "mkfs.minix" \
15"Firstdatazone=15 (15)\n"\ 23"Firstdatazone=15 (15)\n"\
16"Zonesize=1024\n"\ 24"Zonesize=1024\n"\
17"Maxsize=268966912\n"\ 25"Maxsize=268966912\n"\
18"4f35f7afeba07d56055bed1f29ae20b7 -\n" \ 26"$hash -\n" \
19 "" \ 27 "" \
20 "" 28 ""
21 29
diff --git a/testsuite/mount.tests b/testsuite/mount.tests
index c5891be83..a0bc50888 100755
--- a/testsuite/mount.tests
+++ b/testsuite/mount.tests
@@ -36,7 +36,8 @@ testing "mount -o remount,mand" \
36"mount -o loop mount.image1m $testdir "\ 36"mount -o loop mount.image1m $testdir "\
37"&& grep -Fc $testdir </proc/mounts "\ 37"&& grep -Fc $testdir </proc/mounts "\
38"&& mount -o remount,mand $testdir "\ 38"&& mount -o remount,mand $testdir "\
39"&& grep -F $testdir </proc/mounts | grep -c '[, ]mand[, ]'" \ 39"&& grep -F $testdir </proc/mounts | grep -c '[, ]mand[, ]'"\
40"|| grep -F $testdir </proc/mounts" \
40 "1\n""1\n" \ 41 "1\n""1\n" \
41 "" "" 42 "" ""
42 43
@@ -83,4 +84,28 @@ b
83 "" "" 84 "" ""
84SKIP= 85SKIP=
85 86
87
88testing "mount RO loop" "\
89exec 2>&1
90umount -d mount.dir 2>/dev/null
91rmdir mount.dir 2>/dev/null
92mkdir -p mount.dir
93(
94cd mount.dir || { echo 'cd error'; exit 1; }
95mkdir z1 z2 || { echo 'mkdir error'; exit 1; }
96mount -t tmpfs tmpfs z1 || { echo 'mount tmpfs error'; exit 1; }
97dd if=/dev/zero of=z1/e2img count=10 bs=1M 2>/dev/null || { echo 'dd error'; exit 1; }
98mke2fs -F z1/e2img 2>/dev/null >&2 || { echo 'mke2fs error'; exit 1; }
99mount -r -o loop -t ext2 z1/e2img z2 || { echo 'mount -r -o loop error'; exit 1; }
100mount -o remount,ro z1 || { echo 'mount -o remount,ro error'; exit 1; }
101)
102umount -d mount.dir/z2
103##losetup -d /dev/loop*
104umount -d mount.dir/z1
105rm -rf mount.dir
106echo DONE
107" \
108"DONE\n" "" ""
109
110
86exit $FAILCOUNT 111exit $FAILCOUNT
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 9fa8e190c..468565f47 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -52,10 +52,8 @@ testing "sed with empty match" "sed 's/z*//g'" "string\n" "" "string\n"
52testing "sed s//p" "sed -e s/foo/bar/p -e s/bar/baz/p" "bar\nbaz\nbaz\n" \ 52testing "sed s//p" "sed -e s/foo/bar/p -e s/bar/baz/p" "bar\nbaz\nbaz\n" \
53 "" "foo\n" 53 "" "foo\n"
54testing "sed -n s//p" "sed -ne s/abc/def/p" "def\n" "" "abc\n" 54testing "sed -n s//p" "sed -ne s/abc/def/p" "def\n" "" "abc\n"
55test x"$SKIP_KNOWN_BUGS" = x"" && {
56testing "sed s//g (exhaustive)" "sed -e 's/[[:space:]]*/,/g'" ",1,2,3,4,5,\n" \ 55testing "sed s//g (exhaustive)" "sed -e 's/[[:space:]]*/,/g'" ",1,2,3,4,5,\n" \
57 "" "12345\n" 56 "" "12345\n"
58}
59testing "sed s arbitrary delimiter" "sed -e 's woo boing '" "boing\n" "" "woo\n" 57testing "sed s arbitrary delimiter" "sed -e 's woo boing '" "boing\n" "" "woo\n"
60testing "sed s chains" "sed -e s/foo/bar/ -e s/bar/baz/" "baz\n" "" "foo\n" 58testing "sed s chains" "sed -e s/foo/bar/ -e s/bar/baz/" "baz\n" "" "foo\n"
61testing "sed s chains2" "sed -e s/foo/bar/ -e s/baz/nee/" "bar\n" "" "foo\n" 59testing "sed s chains2" "sed -e s/foo/bar/ -e s/baz/nee/" "bar\n" "" "foo\n"
@@ -296,6 +294,22 @@ testing "sed -i finishes ranges correctly" \
296 "sed '1,2d' -i input; echo \$?; cat input" \ 294 "sed '1,2d' -i input; echo \$?; cat input" \
297 "0\n3\n4\n" "1\n2\n3\n4\n" "" 295 "0\n3\n4\n" "1\n2\n3\n4\n" ""
298 296
297testing "sed zero chars match/replace advances correctly 1" \
298 "sed 's/l*/@/g'" \
299 "@h@e@o@\n" "" "helllo\n"
300
301testing "sed zero chars match/replace advances correctly 2" \
302 "sed 's [^ .]* x g'" \
303 "x x.x\n" "" " a.b\n"
304
305testing "sed zero chars match/replace logic must not falsely trigger here 1" \
306 "sed 's/a/A/g'" \
307 "_AAA1AA\n" "" "_aaa1aa\n"
308
309testing "sed zero chars match/replace logic must not falsely trigger here 2" \
310 "sed 's/ *$/_/g'" \
311 "qwerty_\n" "" "qwerty\n"
312
299# testing "description" "commands" "result" "infile" "stdin" 313# testing "description" "commands" "result" "infile" "stdin"
300 314
301exit $FAILCOUNT 315exit $FAILCOUNT
diff --git a/util-linux/Config.src b/util-linux/Config.src
index 57a52cefb..3355e9729 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -762,6 +762,13 @@ config FEATURE_VOLUMEID_XFS
762 help 762 help
763 TODO 763 TODO
764 764
765config FEATURE_VOLUMEID_NILFS
766 bool "nilfs filesystem"
767 default y
768 depends on VOLUMEID
769 help
770 TODO
771
765config FEATURE_VOLUMEID_NTFS 772config FEATURE_VOLUMEID_NTFS
766 bool "ntfs filesystem" 773 bool "ntfs filesystem"
767 default y 774 default y
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index 1b22f3a01..5d2792948 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -75,6 +75,7 @@ struct acpi_event {
75static const struct acpi_event f_evt_tab[] = { 75static const struct acpi_event f_evt_tab[] = {
76 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" }, 76 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" },
77 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" }, 77 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" },
78 { "EV_SW", 0x05, "SW_LID", 0x00, 1, "button/lid LID0 00000080" },
78}; 79};
79 80
80struct acpi_action { 81struct acpi_action {
diff --git a/util-linux/fbset.c b/util-linux/fbset.c
index 196c2aa24..e9aacce4f 100644
--- a/util-linux/fbset.c
+++ b/util-linux/fbset.c
@@ -271,7 +271,7 @@ static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
271 } 271 }
272 p = token[1]; 272 p = token[1];
273 i = index_in_strings( 273 i = index_in_strings(
274 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0", 274 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0rgba\0",
275 token[0]); 275 token[0]);
276 switch (i) { 276 switch (i) {
277 case 0: 277 case 0:
@@ -342,6 +342,30 @@ static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
342 ss(&base->sync, FB_SYNC_EXT, p, "false"); 342 ss(&base->sync, FB_SYNC_EXT, p, "false");
343//bb_info_msg("EXTSYNC[%s]", p); 343//bb_info_msg("EXTSYNC[%s]", p);
344 break; 344 break;
345 case 8: {
346 int red_offset, red_length;
347 int green_offset, green_length;
348 int blue_offset, blue_length;
349 int transp_offset, transp_length;
350
351 sscanf(p, "%d/%d,%d/%d,%d/%d,%d/%d",
352 &red_offset, &red_length,
353 &green_offset, &green_length,
354 &blue_offset, &blue_length,
355 &transp_offset, &transp_length);
356 base->red.offset = red_offset;
357 base->red.length = red_length;
358 base->red.msb_right = 0;
359 base->green.offset = green_offset;
360 base->green.length = green_length;
361 base->green.msb_right = 0;
362 base->blue.offset = blue_offset;
363 base->blue.length = blue_length;
364 base->blue.msb_right = 0;
365 base->transp.offset = transp_offset;
366 base->transp.length = transp_length;
367 base->transp.msb_right = 0;
368 }
345 } 369 }
346 } 370 }
347 return 0; 371 return 0;
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 0a34122b4..79871d30e 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -92,7 +92,9 @@
92//usage: "\n" 92//usage: "\n"
93//usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n" 93//usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n"
94//usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n" 94//usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n"
95//usage: "To activate this feature, create empty /dev/mdev.seq at boot." 95//usage: "To activate this feature, create empty /dev/mdev.seq at boot.\n"
96//usage: "\n"
97//usage: "If /dev/mdev.log file exists, debug log will be appended to it."
96 98
97#include "libbb.h" 99#include "libbb.h"
98#include "xregex.h" 100#include "xregex.h"
@@ -139,10 +141,101 @@
139 * This happens regardless of /sys/class/.../dev existence. 141 * This happens regardless of /sys/class/.../dev existence.
140 */ 142 */
141 143
144/* Kernel's hotplug environment constantly changes.
145 * Here are new cases I observed on 3.1.0:
146 *
147 * Case with $DEVNAME and $DEVICE, not just $DEVPATH:
148 * ACTION=add
149 * BUSNUM=001
150 * DEVICE=/proc/bus/usb/001/003
151 * DEVNAME=bus/usb/001/003
152 * DEVNUM=003
153 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5
154 * DEVTYPE=usb_device
155 * MAJOR=189
156 * MINOR=2
157 * PRODUCT=18d1/4e12/227
158 * SUBSYSTEM=usb
159 * TYPE=0/0/0
160 *
161 * Case with $DEVICE, but no $DEVNAME - apparenty, usb iface notification?
162 * "Please load me a module" thing?
163 * ACTION=add
164 * DEVICE=/proc/bus/usb/001/003
165 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0
166 * DEVTYPE=usb_interface
167 * INTERFACE=8/6/80
168 * MODALIAS=usb:v18D1p4E12d0227dc00dsc00dp00ic08isc06ip50
169 * PRODUCT=18d1/4e12/227
170 * SUBSYSTEM=usb
171 * TYPE=0/0/0
172 *
173 * ACTION=add
174 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5
175 * DEVTYPE=scsi_host
176 * SUBSYSTEM=scsi
177 *
178 * ACTION=add
179 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/scsi_host/host5
180 * SUBSYSTEM=scsi_host
181 *
182 * ACTION=add
183 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0
184 * DEVTYPE=scsi_target
185 * SUBSYSTEM=scsi
186 *
187 * Case with strange $MODALIAS:
188 * ACTION=add
189 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0
190 * DEVTYPE=scsi_device
191 * MODALIAS=scsi:t-0x00
192 * SUBSYSTEM=scsi
193 *
194 * ACTION=add
195 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0
196 * SUBSYSTEM=scsi_disk
197 *
198 * ACTION=add
199 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_device/5:0:0:0
200 * SUBSYSTEM=scsi_device
201 *
202 * Case with explicit $MAJOR/$MINOR (no need to read /sys/$DEVPATH/dev?):
203 * ACTION=add
204 * DEVNAME=bsg/5:0:0:0
205 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/bsg/5:0:0:0
206 * MAJOR=253
207 * MINOR=1
208 * SUBSYSTEM=bsg
209 *
210 * ACTION=add
211 * DEVPATH=/devices/virtual/bdi/8:16
212 * SUBSYSTEM=bdi
213 *
214 * ACTION=add
215 * DEVNAME=sdb
216 * DEVPATH=/block/sdb
217 * DEVTYPE=disk
218 * MAJOR=8
219 * MINOR=16
220 * SUBSYSTEM=block
221 *
222 * Case with ACTION=change:
223 * ACTION=change
224 * DEVNAME=sdb
225 * DEVPATH=/block/sdb
226 * DEVTYPE=disk
227 * DISK_MEDIA_CHANGE=1
228 * MAJOR=8
229 * MINOR=16
230 * SUBSYSTEM=block
231 */
232
233static const char keywords[] ALIGN1 = "add\0remove\0change\0";
234enum { OP_add, OP_remove };
235
142struct rule { 236struct rule {
143 bool keep_matching; 237 bool keep_matching;
144 bool regex_compiled; 238 bool regex_compiled;
145 bool regex_has_slash;
146 mode_t mode; 239 mode_t mode;
147 int maj, min0, min1; 240 int maj, min0, min1;
148 struct bb_uidgid_t ugid; 241 struct bb_uidgid_t ugid;
@@ -154,6 +247,7 @@ struct rule {
154 247
155struct globals { 248struct globals {
156 int root_major, root_minor; 249 int root_major, root_minor;
250 smallint verbose;
157 char *subsystem; 251 char *subsystem;
158#if ENABLE_FEATURE_MDEV_CONF 252#if ENABLE_FEATURE_MDEV_CONF
159 const char *filename; 253 const char *filename;
@@ -245,7 +339,6 @@ static void parse_next_rule(void)
245 } 339 }
246 xregcomp(&G.cur_rule.match, val, REG_EXTENDED); 340 xregcomp(&G.cur_rule.match, val, REG_EXTENDED);
247 G.cur_rule.regex_compiled = 1; 341 G.cur_rule.regex_compiled = 1;
248 G.cur_rule.regex_has_slash = (strchr(val, '/') != NULL);
249 } 342 }
250 343
251 /* 2nd field: uid:gid - device ownership */ 344 /* 2nd field: uid:gid - device ownership */
@@ -366,13 +459,16 @@ static char *build_alias(char *alias, const char *device_name)
366 * after NUL, but we promise to not mangle (IOW: to restore if needed) 459 * after NUL, but we promise to not mangle (IOW: to restore if needed)
367 * path string. 460 * path string.
368 * NB2: "mdev -s" may call us many times, do not leak memory/fds! 461 * NB2: "mdev -s" may call us many times, do not leak memory/fds!
462 *
463 * device_name = $DEVNAME (may be NULL)
464 * path = /sys/$DEVPATH
369 */ 465 */
370static void make_device(char *path, int delete) 466static void make_device(char *device_name, char *path, int operation)
371{ 467{
372 char *device_name, *subsystem_slash_devname;
373 int major, minor, type, len; 468 int major, minor, type, len;
374 469
375 dbg("%s('%s', delete:%d)", __func__, path, delete); 470 if (G.verbose)
471 bb_error_msg("device: %s, %s", device_name, path);
376 472
377 /* Try to read major/minor string. Note that the kernel puts \n after 473 /* Try to read major/minor string. Note that the kernel puts \n after
378 * the data, so we don't need to worry about null terminating the string 474 * the data, so we don't need to worry about null terminating the string
@@ -380,7 +476,7 @@ static void make_device(char *path, int delete)
380 * We also depend on path having writeable space after it. 476 * We also depend on path having writeable space after it.
381 */ 477 */
382 major = -1; 478 major = -1;
383 if (!delete) { 479 if (operation == OP_add) {
384 char *dev_maj_min = path + strlen(path); 480 char *dev_maj_min = path + strlen(path);
385 481
386 strcpy(dev_maj_min, "/dev"); 482 strcpy(dev_maj_min, "/dev");
@@ -391,40 +487,27 @@ static void make_device(char *path, int delete)
391 return; 487 return;
392 /* no "dev" file, but we can still run scripts 488 /* no "dev" file, but we can still run scripts
393 * based on device name */ 489 * based on device name */
394 } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) { 490 } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) {
491 if (G.verbose)
492 bb_error_msg("maj,min: %u,%u", major, minor);
493 } else {
395 major = -1; 494 major = -1;
396 } 495 }
397 } 496 }
398 /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ 497 /* else: for delete, -1 still deletes the node, but < -1 suppresses that */
399 498
400 /* Determine device name, type, major and minor */ 499 /* Determine device name, type, major and minor */
401 device_name = (char*) bb_basename(path); 500 if (!device_name)
501 device_name = (char*) bb_basename(path);
402 /* http://kernel.org/doc/pending/hotplug.txt says that only 502 /* http://kernel.org/doc/pending/hotplug.txt says that only
403 * "/sys/block/..." is for block devices. "/sys/bus" etc is not. 503 * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
404 * But since 2.6.25 block devices are also in /sys/class/block. 504 * But since 2.6.25 block devices are also in /sys/class/block.
405 * We use strstr("/block/") to forestall future surprises. */ 505 * We use strstr("/block/") to forestall future surprises.
506 */
406 type = S_IFCHR; 507 type = S_IFCHR;
407 if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0)) 508 if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0))
408 type = S_IFBLK; 509 type = S_IFBLK;
409 510
410 /* Make path point to "subsystem/device_name" */
411 subsystem_slash_devname = NULL;
412 /* Check for coldplug invocations first */
413 if (strncmp(path, "/sys/block/", 11) == 0) /* legacy case */
414 path += sizeof("/sys/") - 1;
415 else if (strncmp(path, "/sys/class/", 11) == 0)
416 path += sizeof("/sys/class/") - 1;
417 else {
418 /* Example of a hotplug invocation:
419 * SUBSYSTEM="block"
420 * DEVPATH="/sys" + "/devices/virtual/mtd/mtd3/mtdblock3"
421 * ("/sys" is added by mdev_main)
422 * - path does not contain subsystem
423 */
424 subsystem_slash_devname = concat_path_file(G.subsystem, device_name);
425 path = subsystem_slash_devname;
426 }
427
428#if ENABLE_FEATURE_MDEV_CONF 511#if ENABLE_FEATURE_MDEV_CONF
429 G.rule_idx = 0; /* restart from the beginning (think mdev -s) */ 512 G.rule_idx = 0; /* restart from the beginning (think mdev -s) */
430#endif 513#endif
@@ -434,10 +517,10 @@ static void make_device(char *path, int delete)
434 char *command; 517 char *command;
435 char *alias; 518 char *alias;
436 char aliaslink = aliaslink; /* for compiler */ 519 char aliaslink = aliaslink; /* for compiler */
437 const char *node_name; 520 char *node_name;
438 const struct rule *rule; 521 const struct rule *rule;
439 522
440 str_to_match = ""; 523 str_to_match = device_name;
441 524
442 rule = next_rule(); 525 rule = next_rule();
443 526
@@ -455,10 +538,8 @@ static void make_device(char *path, int delete)
455 dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); 538 dbg("getenv('%s'):'%s'", rule->envvar, str_to_match);
456 if (!str_to_match) 539 if (!str_to_match)
457 continue; 540 continue;
458 } else {
459 /* regex to match [subsystem/]device_name */
460 str_to_match = (rule->regex_has_slash ? path : device_name);
461 } 541 }
542 /* else: str_to_match = device_name */
462 543
463 if (rule->regex_compiled) { 544 if (rule->regex_compiled) {
464 int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); 545 int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0);
@@ -537,7 +618,7 @@ static void make_device(char *path, int delete)
537 /* Are we running this command now? 618 /* Are we running this command now?
538 * Run $cmd on delete, @cmd on create, *cmd on both 619 * Run $cmd on delete, @cmd on create, *cmd on both
539 */ 620 */
540 if (s2 - s != delete) { 621 if (s2 - s != (operation == OP_remove) || *s2 == '*') {
541 /* We are here if: '*', 622 /* We are here if: '*',
542 * or: '@' and delete = 0, 623 * or: '@' and delete = 0,
543 * or: '$' and delete = 1 624 * or: '$' and delete = 1
@@ -556,21 +637,30 @@ static void make_device(char *path, int delete)
556 dbg("alias2:'%s'", alias); 637 dbg("alias2:'%s'", alias);
557 } 638 }
558 639
559 if (!delete && major >= 0) { 640 if (operation == OP_add && major >= 0) {
560 dbg("mknod('%s',%o,(%d,%d))", node_name, rule->mode | type, major, minor); 641 char *slash = strrchr(node_name, '/');
642 if (slash) {
643 *slash = '\0';
644 bb_make_directory(node_name, 0755, FILEUTILS_RECUR);
645 *slash = '/';
646 }
647 if (G.verbose)
648 bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type);
561 if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) 649 if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST)
562 bb_perror_msg("can't create '%s'", node_name); 650 bb_perror_msg("can't create '%s'", node_name);
563 if (major == G.root_major && minor == G.root_minor)
564 symlink(node_name, "root");
565 if (ENABLE_FEATURE_MDEV_CONF) { 651 if (ENABLE_FEATURE_MDEV_CONF) {
566 chmod(node_name, rule->mode); 652 chmod(node_name, rule->mode);
567 chown(node_name, rule->ugid.uid, rule->ugid.gid); 653 chown(node_name, rule->ugid.uid, rule->ugid.gid);
568 } 654 }
655 if (major == G.root_major && minor == G.root_minor)
656 symlink(node_name, "root");
569 if (ENABLE_FEATURE_MDEV_RENAME && alias) { 657 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
570 if (aliaslink == '>') { 658 if (aliaslink == '>') {
571//TODO: on devtmpfs, device_name already exists and symlink() fails. 659//TODO: on devtmpfs, device_name already exists and symlink() fails.
572//End result is that instead of symlink, we have two nodes. 660//End result is that instead of symlink, we have two nodes.
573//What should be done? 661//What should be done?
662 if (G.verbose)
663 bb_error_msg("symlink: %s", device_name);
574 symlink(node_name, device_name); 664 symlink(node_name, device_name);
575 } 665 }
576 } 666 }
@@ -582,17 +672,24 @@ static void make_device(char *path, int delete)
582 char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); 672 char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem);
583 putenv(s); 673 putenv(s);
584 putenv(s1); 674 putenv(s1);
675 if (G.verbose)
676 bb_error_msg("running: %s", command);
585 if (system(command) == -1) 677 if (system(command) == -1)
586 bb_perror_msg("can't run '%s'", command); 678 bb_perror_msg("can't run '%s'", command);
587 bb_unsetenv_and_free(s1); 679 bb_unsetenv_and_free(s1);
588 bb_unsetenv_and_free(s); 680 bb_unsetenv_and_free(s);
589 } 681 }
590 682
591 if (delete && major >= -1) { 683 if (operation == OP_remove && major >= -1) {
592 if (ENABLE_FEATURE_MDEV_RENAME && alias) { 684 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
593 if (aliaslink == '>') 685 if (aliaslink == '>') {
686 if (G.verbose)
687 bb_error_msg("unlink: %s", device_name);
594 unlink(device_name); 688 unlink(device_name);
689 }
595 } 690 }
691 if (G.verbose)
692 bb_error_msg("unlink: %s", node_name);
596 unlink(node_name); 693 unlink(node_name);
597 } 694 }
598 695
@@ -605,8 +702,6 @@ static void make_device(char *path, int delete)
605 if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching) 702 if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching)
606 break; 703 break;
607 } /* for (;;) */ 704 } /* for (;;) */
608
609 free(subsystem_slash_devname);
610} 705}
611 706
612/* File callback for /sys/ traversal */ 707/* File callback for /sys/ traversal */
@@ -624,7 +719,7 @@ static int FAST_FUNC fileAction(const char *fileName,
624 719
625 strcpy(scratch, fileName); 720 strcpy(scratch, fileName);
626 scratch[len] = '\0'; 721 scratch[len] = '\0';
627 make_device(scratch, /*delete:*/ 0); 722 make_device(/*DEVNAME:*/ NULL, scratch, OP_add);
628 723
629 return TRUE; 724 return TRUE;
630} 725}
@@ -661,37 +756,45 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
661static void load_firmware(const char *firmware, const char *sysfs_path) 756static void load_firmware(const char *firmware, const char *sysfs_path)
662{ 757{
663 int cnt; 758 int cnt;
664 int firmware_fd, loading_fd, data_fd; 759 int firmware_fd, loading_fd;
665 760
666 /* check for /lib/firmware/$FIRMWARE */ 761 /* check for /lib/firmware/$FIRMWARE */
667 xchdir("/lib/firmware"); 762 xchdir("/lib/firmware");
668 firmware_fd = xopen(firmware, O_RDONLY); 763 firmware_fd = open(firmware, O_RDONLY); /* can fail */
669
670 /* in case we goto out ... */
671 data_fd = -1;
672 764
673 /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ 765 /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */
674 xchdir(sysfs_path); 766 xchdir(sysfs_path);
675 for (cnt = 0; cnt < 30; ++cnt) { 767 for (cnt = 0; cnt < 30; ++cnt) {
676 loading_fd = open("loading", O_WRONLY); 768 loading_fd = open("loading", O_WRONLY);
677 if (loading_fd != -1) 769 if (loading_fd >= 0)
678 goto loading; 770 goto loading;
679 sleep(1); 771 sleep(1);
680 } 772 }
681 goto out; 773 goto out;
682 774
683 loading: 775 loading:
684 /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */ 776 cnt = 0;
685 if (full_write(loading_fd, "1", 1) != 1) 777 if (firmware_fd >= 0) {
686 goto out; 778 int data_fd;
687 779
688 /* load firmware into /sys/$DEVPATH/data */ 780 /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */
689 data_fd = open("data", O_WRONLY); 781 if (full_write(loading_fd, "1", 1) != 1)
690 if (data_fd == -1) 782 goto out;
691 goto out; 783
692 cnt = bb_copyfd_eof(firmware_fd, data_fd); 784 /* load firmware into /sys/$DEVPATH/data */
785 data_fd = open("data", O_WRONLY);
786 if (data_fd < 0)
787 goto out;
788 cnt = bb_copyfd_eof(firmware_fd, data_fd);
789 if (ENABLE_FEATURE_CLEAN_UP)
790 close(data_fd);
791 }
693 792
694 /* tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading" */ 793 /* Tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading"
794 * Note: we emit -1 also if firmware file wasn't found.
795 * There are cases when otherwise kernel would wait for minutes
796 * before timing out.
797 */
695 if (cnt > 0) 798 if (cnt > 0)
696 full_write(loading_fd, "0", 1); 799 full_write(loading_fd, "0", 1);
697 else 800 else
@@ -701,7 +804,6 @@ static void load_firmware(const char *firmware, const char *sysfs_path)
701 if (ENABLE_FEATURE_CLEAN_UP) { 804 if (ENABLE_FEATURE_CLEAN_UP) {
702 close(firmware_fd); 805 close(firmware_fd);
703 close(loading_fd); 806 close(loading_fd);
704 close(data_fd);
705 } 807 }
706} 808}
707 809
@@ -762,9 +864,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
762 char *fw; 864 char *fw;
763 char *seq; 865 char *seq;
764 char *action; 866 char *action;
765 char *env_path; 867 char *env_devname;
766 static const char keywords[] ALIGN1 = "remove\0add\0"; 868 char *env_devpath;
767 enum { OP_remove = 0, OP_add };
768 smalluint op; 869 smalluint op;
769 870
770 /* Hotplug: 871 /* Hotplug:
@@ -773,12 +874,13 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
773 * DEVPATH is like "/block/sda" or "/class/input/mice" 874 * DEVPATH is like "/block/sda" or "/class/input/mice"
774 */ 875 */
775 action = getenv("ACTION"); 876 action = getenv("ACTION");
776 env_path = getenv("DEVPATH"); 877 op = index_in_strings(keywords, action);
878 env_devname = getenv("DEVNAME"); /* can be NULL */
879 env_devpath = getenv("DEVPATH");
777 G.subsystem = getenv("SUBSYSTEM"); 880 G.subsystem = getenv("SUBSYSTEM");
778 if (!action || !env_path /*|| !G.subsystem*/) 881 if (!action || !env_devpath /*|| !G.subsystem*/)
779 bb_show_usage(); 882 bb_show_usage();
780 fw = getenv("FIRMWARE"); 883 fw = getenv("FIRMWARE");
781 op = index_in_strings(keywords, action);
782 /* If it exists, does /dev/mdev.seq match $SEQNUM? 884 /* If it exists, does /dev/mdev.seq match $SEQNUM?
783 * If it does not match, earlier mdev is running 885 * If it does not match, earlier mdev is running
784 * in parallel, and we need to wait */ 886 * in parallel, and we need to wait */
@@ -804,16 +906,25 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
804 } while (--timeout); 906 } while (--timeout);
805 } 907 }
806 908
807 snprintf(temp, PATH_MAX, "/sys%s", env_path); 909 {
910 int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND);
911 if (logfd >= 0) {
912 xmove_fd(logfd, STDERR_FILENO);
913 G.verbose = 1;
914 bb_error_msg("seq: %s action: %s", seq, action);
915 }
916 }
917
918 snprintf(temp, PATH_MAX, "/sys%s", env_devpath);
808 if (op == OP_remove) { 919 if (op == OP_remove) {
809 /* Ignoring "remove firmware". It was reported 920 /* Ignoring "remove firmware". It was reported
810 * to happen and to cause erroneous deletion 921 * to happen and to cause erroneous deletion
811 * of device nodes. */ 922 * of device nodes. */
812 if (!fw) 923 if (!fw)
813 make_device(temp, /*delete:*/ 1); 924 make_device(env_devname, temp, op);
814 } 925 }
815 else if (op == OP_add) { 926 else if (op == OP_add) {
816 make_device(temp, /*delete:*/ 0); 927 make_device(env_devname, temp, op);
817 if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { 928 if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) {
818 if (fw) 929 if (fw)
819 load_firmware(fw, temp); 930 load_firmware(fw, temp);
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index 69b25c946..3258d7eee 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -53,11 +53,6 @@
53#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0 53#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0
54#define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1 54#define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1
55 55
56// from e2fsprogs
57#define s_reserved_gdt_blocks s_padding1
58#define s_mkfs_time s_reserved[0]
59#define s_flags s_reserved[22]
60
61#define EXT2_HASH_HALF_MD4 1 56#define EXT2_HASH_HALF_MD4 1
62#define EXT2_FLAGS_SIGNED_HASH 0x0001 57#define EXT2_FLAGS_SIGNED_HASH 0x0001
63#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 58#define EXT2_FLAGS_UNSIGNED_HASH 0x0002
@@ -482,8 +477,10 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
482 STORE_LE(sb->s_magic, EXT2_SUPER_MAGIC); 477 STORE_LE(sb->s_magic, EXT2_SUPER_MAGIC);
483 STORE_LE(sb->s_inode_size, inodesize); 478 STORE_LE(sb->s_inode_size, inodesize);
484 // set "Required extra isize" and "Desired extra isize" fields to 28 479 // set "Required extra isize" and "Desired extra isize" fields to 28
485 if (inodesize != sizeof(*inode)) 480 if (inodesize != sizeof(*inode)) {
486 STORE_LE(sb->s_reserved[21], 0x001C001C); 481 STORE_LE(sb->s_min_extra_isize, 0x001c);
482 STORE_LE(sb->s_want_extra_isize, 0x001c);
483 }
487 STORE_LE(sb->s_first_ino, EXT2_GOOD_OLD_FIRST_INO); 484 STORE_LE(sb->s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
488 STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE); 485 STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
489 STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE); 486 STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
diff --git a/util-linux/mount.c b/util-linux/mount.c
index f1da30fac..525fdcce9 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -113,6 +113,12 @@
113#ifndef MS_RELATIME 113#ifndef MS_RELATIME
114# define MS_RELATIME (1 << 21) 114# define MS_RELATIME (1 << 21)
115#endif 115#endif
116#ifndef MS_STRICTATIME
117# define MS_STRICTATIME (1 << 24)
118#endif
119
120/* Any ~MS_FOO value has this bit set: */
121#define BB_MS_INVERTED_VALUE (1u << 31)
116 122
117#include "libbb.h" 123#include "libbb.h"
118#if ENABLE_FEATURE_MOUNT_LABEL 124#if ENABLE_FEATURE_MOUNT_LABEL
@@ -218,6 +224,7 @@ static const int32_t mount_options[] = {
218 IF_DESKTOP(/* "user" */ MOUNT_USERS,) 224 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
219 IF_DESKTOP(/* "users" */ MOUNT_USERS,) 225 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
220 /* "_netdev" */ 0, 226 /* "_netdev" */ 0,
227 IF_DESKTOP(/* "comment" */ 0,) /* systemd uses this in fstab */
221 ) 228 )
222 229
223 IF_FEATURE_MOUNT_FLAGS( 230 IF_FEATURE_MOUNT_FLAGS(
@@ -239,6 +246,7 @@ static const int32_t mount_options[] = {
239 /* "nomand" */ ~MS_MANDLOCK, 246 /* "nomand" */ ~MS_MANDLOCK,
240 /* "relatime" */ MS_RELATIME, 247 /* "relatime" */ MS_RELATIME,
241 /* "norelatime" */ ~MS_RELATIME, 248 /* "norelatime" */ ~MS_RELATIME,
249 /* "strictatime" */ MS_STRICTATIME,
242 /* "loud" */ ~MS_SILENT, 250 /* "loud" */ ~MS_SILENT,
243 /* "rbind" */ MS_BIND|MS_RECURSIVE, 251 /* "rbind" */ MS_BIND|MS_RECURSIVE,
244 252
@@ -275,6 +283,7 @@ static const char mount_option_str[] =
275 IF_DESKTOP("user\0") 283 IF_DESKTOP("user\0")
276 IF_DESKTOP("users\0") 284 IF_DESKTOP("users\0")
277 "_netdev\0" 285 "_netdev\0"
286 IF_DESKTOP("comment\0") /* systemd uses this in fstab */
278 ) 287 )
279 IF_FEATURE_MOUNT_FLAGS( 288 IF_FEATURE_MOUNT_FLAGS(
280 // vfs flags 289 // vfs flags
@@ -295,6 +304,7 @@ static const char mount_option_str[] =
295 "nomand\0" 304 "nomand\0"
296 "relatime\0" 305 "relatime\0"
297 "norelatime\0" 306 "norelatime\0"
307 "strictatime\0"
298 "loud\0" 308 "loud\0"
299 "rbind\0" 309 "rbind\0"
300 310
@@ -450,9 +460,9 @@ static void append_mount_options(char **oldopts, const char *newopts)
450 460
451// Use the mount_options list to parse options into flags. 461// Use the mount_options list to parse options into flags.
452// Also update list of unrecognized options if unrecognized != NULL 462// Also update list of unrecognized options if unrecognized != NULL
453static long parse_mount_options(char *options, char **unrecognized) 463static unsigned long parse_mount_options(char *options, char **unrecognized)
454{ 464{
455 long flags = MS_SILENT; 465 unsigned long flags = MS_SILENT;
456 466
457 // Loop through options 467 // Loop through options
458 for (;;) { 468 for (;;) {
@@ -465,15 +475,19 @@ static long parse_mount_options(char *options, char **unrecognized)
465// FIXME: use hasmntopt() 475// FIXME: use hasmntopt()
466 // Find this option in mount_options 476 // Find this option in mount_options
467 for (i = 0; i < ARRAY_SIZE(mount_options); i++) { 477 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
468 if (strcasecmp(option_str, options) == 0) { 478 /* We support "option=" match for "comment=" thingy */
469 long fl = mount_options[i]; 479 unsigned opt_len = strlen(option_str);
470 if (fl < 0) 480 if (strncasecmp(option_str, options, opt_len) == 0
481 && (options[opt_len] == '\0' || options[opt_len] == '=')
482 ) {
483 unsigned long fl = mount_options[i];
484 if (fl & BB_MS_INVERTED_VALUE)
471 flags &= fl; 485 flags &= fl;
472 else 486 else
473 flags |= fl; 487 flags |= fl;
474 goto found; 488 goto found;
475 } 489 }
476 option_str += strlen(option_str) + 1; 490 option_str += opt_len + 1;
477 } 491 }
478 // We did not recognize this option. 492 // We did not recognize this option.
479 // If "unrecognized" is not NULL, append option there. 493 // If "unrecognized" is not NULL, append option there.
@@ -548,7 +562,7 @@ void delete_block_backed_filesystems(void);
548 562
549// Perform actual mount of specific filesystem at specific location. 563// Perform actual mount of specific filesystem at specific location.
550// NB: mp->xxx fields may be trashed on exit 564// NB: mp->xxx fields may be trashed on exit
551static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts) 565static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
552{ 566{
553 int rc = 0; 567 int rc = 0;
554 568
@@ -1080,7 +1094,7 @@ static void error_msg_rpc(const char *msg)
1080} 1094}
1081 1095
1082/* NB: mp->xxx fields may be trashed on exit */ 1096/* NB: mp->xxx fields may be trashed on exit */
1083static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) 1097static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
1084{ 1098{
1085 CLIENT *mclient; 1099 CLIENT *mclient;
1086 char *hostname; 1100 char *hostname;
@@ -1711,7 +1725,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1711 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS. 1725 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1712 * (However, note that then you lose any chances that NFS over IPv6 would work). 1726 * (However, note that then you lose any chances that NFS over IPv6 would work).
1713 */ 1727 */
1714static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) 1728static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
1715{ 1729{
1716 len_and_sockaddr *lsa; 1730 len_and_sockaddr *lsa;
1717 char *opts; 1731 char *opts;
@@ -1753,7 +1767,7 @@ static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1753static int singlemount(struct mntent *mp, int ignore_busy) 1767static int singlemount(struct mntent *mp, int ignore_busy)
1754{ 1768{
1755 int rc = -1; 1769 int rc = -1;
1756 long vfsflags; 1770 unsigned long vfsflags;
1757 char *loopFile = NULL, *filteropts = NULL; 1771 char *loopFile = NULL, *filteropts = NULL;
1758 llist_t *fl = NULL; 1772 llist_t *fl = NULL;
1759 struct stat st; 1773 struct stat st;
@@ -1854,7 +1868,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
1854 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { 1868 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1855 loopFile = bb_simplify_path(mp->mnt_fsname); 1869 loopFile = bb_simplify_path(mp->mnt_fsname);
1856 mp->mnt_fsname = NULL; // will receive malloced loop dev name 1870 mp->mnt_fsname = NULL; // will receive malloced loop dev name
1857 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ 0) < 0) { 1871 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) {
1858 if (errno == EPERM || errno == EACCES) 1872 if (errno == EPERM || errno == EACCES)
1859 bb_error_msg(bb_msg_perm_denied_are_you_root); 1873 bb_error_msg(bb_msg_perm_denied_are_you_root);
1860 else 1874 else
@@ -1992,6 +2006,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
1992 FILE *fstab; 2006 FILE *fstab;
1993 int i, j; 2007 int i, j;
1994 int rc = EXIT_SUCCESS; 2008 int rc = EXIT_SUCCESS;
2009 unsigned long cmdopt_flags;
1995 unsigned opt; 2010 unsigned opt;
1996 struct mntent mtpair[2], *mtcur = mtpair; 2011 struct mntent mtpair[2], *mtcur = mtpair;
1997 IF_NOT_DESKTOP(const int nonroot = 0;) 2012 IF_NOT_DESKTOP(const int nonroot = 0;)
@@ -2066,16 +2081,16 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
2066 // Past this point, we are handling either "mount -a [opts]" 2081 // Past this point, we are handling either "mount -a [opts]"
2067 // or "mount [opts] single_param" 2082 // or "mount [opts] single_param"
2068 2083
2069 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int" 2084 cmdopt_flags = parse_mount_options(cmdopts, NULL);
2070 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags 2085 if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
2071 bb_error_msg_and_die(bb_msg_you_must_be_root); 2086 bb_error_msg_and_die(bb_msg_you_must_be_root);
2072 2087
2073 // If we have a shared subtree flag, don't worry about fstab or mtab. 2088 // If we have a shared subtree flag, don't worry about fstab or mtab.
2074 if (ENABLE_FEATURE_MOUNT_FLAGS 2089 if (ENABLE_FEATURE_MOUNT_FLAGS
2075 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) 2090 && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
2076 ) { 2091 ) {
2077 // verbose_mount(source, target, type, flags, data) 2092 // verbose_mount(source, target, type, flags, data)
2078 rc = verbose_mount("", argv[0], "", i, ""); 2093 rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
2079 if (rc) 2094 if (rc)
2080 bb_simple_perror_msg_and_die(argv[0]); 2095 bb_simple_perror_msg_and_die(argv[0]);
2081 return rc; 2096 return rc;
@@ -2083,7 +2098,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
2083 2098
2084 // Open either fstab or mtab 2099 // Open either fstab or mtab
2085 fstabname = "/etc/fstab"; 2100 fstabname = "/etc/fstab";
2086 if (i & MS_REMOUNT) { 2101 if (cmdopt_flags & MS_REMOUNT) {
2087 // WARNING. I am not sure this matches util-linux's 2102 // WARNING. I am not sure this matches util-linux's
2088 // behavior. It's possible util-linux does not 2103 // behavior. It's possible util-linux does not
2089 // take -o opts from mtab (takes only mount source). 2104 // take -o opts from mtab (takes only mount source).
@@ -2182,7 +2197,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
2182 // End of fstab/mtab is reached. 2197 // End of fstab/mtab is reached.
2183 // Were we looking for something specific? 2198 // Were we looking for something specific?
2184 if (argv[0]) { // yes 2199 if (argv[0]) { // yes
2185 long l; 2200 unsigned long l;
2186 2201
2187 // If we didn't find anything, complain 2202 // If we didn't find anything, complain
2188 if (!mtcur->mnt_fsname) 2203 if (!mtcur->mnt_fsname)
diff --git a/util-linux/rdate.c b/util-linux/rdate.c
index 1f36d8f37..6e35cd519 100644
--- a/util-linux/rdate.c
+++ b/util-linux/rdate.c
@@ -1,7 +1,7 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * The Rdate command will ask a time server for the RFC 868 time 3 * The Rdate command will ask a time server for the RFC 868 time
4 * and optionally set the system time. 4 * and optionally set the system time.
5 * 5 *
6 * by Sterling Huxley <sterling@europa.com> 6 * by Sterling Huxley <sterling@europa.com>
7 * 7 *
@@ -11,9 +11,9 @@
11//usage:#define rdate_trivial_usage 11//usage:#define rdate_trivial_usage
12//usage: "[-sp] HOST" 12//usage: "[-sp] HOST"
13//usage:#define rdate_full_usage "\n\n" 13//usage:#define rdate_full_usage "\n\n"
14//usage: "Get and possibly set the system date and time from a remote HOST\n" 14//usage: "Get and possibly set the system date/time from a remote HOST\n"
15//usage: "\n -s Set the system date and time (default)" 15//usage: "\n -s Set the system date/time (default)"
16//usage: "\n -p Print the date and time" 16//usage: "\n -p Print the date/time"
17 17
18#include "libbb.h" 18#include "libbb.h"
19 19
@@ -35,15 +35,16 @@ static time_t askremotedate(const char *host)
35 35
36 fd = create_and_connect_stream_or_die(host, bb_lookup_port("time", "tcp", 37)); 36 fd = create_and_connect_stream_or_die(host, bb_lookup_port("time", "tcp", 37));
37 37
38 if (safe_read(fd, (void *)&nett, 4) != 4) /* read time from server */ 38 if (safe_read(fd, &nett, 4) != 4) /* read time from server */
39 bb_error_msg_and_die("%s did not send the complete time", host); 39 bb_error_msg_and_die("%s did not send the complete time", host);
40 close(fd); 40 if (ENABLE_FEATURE_CLEAN_UP)
41 close(fd);
41 42
42 /* convert from network byte order to local byte order. 43 /* Convert from network byte order to local byte order.
43 * RFC 868 time is the number of seconds 44 * RFC 868 time is the number of seconds
44 * since 00:00 (midnight) 1 January 1900 GMT 45 * since 00:00 (midnight) 1 January 1900 GMT
45 * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT 46 * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT
46 * Subtract the RFC 868 time to get Linux epoch 47 * Subtract the RFC 868 time to get Linux epoch.
47 */ 48 */
48 49
49 return ntohl(nett) - RFC_868_BIAS; 50 return ntohl(nett) - RFC_868_BIAS;
@@ -53,14 +54,14 @@ int rdate_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
53int rdate_main(int argc UNUSED_PARAM, char **argv) 54int rdate_main(int argc UNUSED_PARAM, char **argv)
54{ 55{
55 time_t remote_time; 56 time_t remote_time;
56 unsigned long flags; 57 unsigned flags;
57 58
58 opt_complementary = "-1"; 59 opt_complementary = "-1";
59 flags = getopt32(argv, "sp"); 60 flags = getopt32(argv, "sp");
60 61
61 remote_time = askremotedate(argv[optind]); 62 remote_time = askremotedate(argv[optind]);
62 63
63 if ((flags & 2) == 0) { 64 if (!(flags & 2)) { /* no -p (-s may be present) */
64 time_t current_time; 65 time_t current_time;
65 66
66 time(&current_time); 67 time(&current_time);
@@ -71,7 +72,7 @@ int rdate_main(int argc UNUSED_PARAM, char **argv)
71 bb_perror_msg_and_die("can't set time of day"); 72 bb_perror_msg_and_die("can't set time of day");
72 } 73 }
73 74
74 if ((flags & 1) == 0) 75 if (flags != 1) /* not lone -s */
75 printf("%s", ctime(&remote_time)); 76 printf("%s", ctime(&remote_time));
76 77
77 return EXIT_SUCCESS; 78 return EXIT_SUCCESS;
diff --git a/util-linux/volume_id/Kbuild.src b/util-linux/volume_id/Kbuild.src
index 70da65482..39a2d8cf4 100644
--- a/util-linux/volume_id/Kbuild.src
+++ b/util-linux/volume_id/Kbuild.src
@@ -31,6 +31,7 @@ lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o
31### lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o 31### lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o
32### lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o 32### lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o
33### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o 33### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o
34lib-$(CONFIG_FEATURE_VOLUMEID_NILFS) += nilfs.o
34lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o 35lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
35lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o 36lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o
36lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o 37lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o
diff --git a/util-linux/volume_id/btrfs.c b/util-linux/volume_id/btrfs.c
index 777b80923..ee71d2e00 100644
--- a/util-linux/volume_id/btrfs.c
+++ b/util-linux/volume_id/btrfs.c
@@ -102,6 +102,7 @@ int FAST_FUNC volume_id_probe_btrfs(struct volume_id *id /*,uint64_t off*/)
102 // N.B.: btrfs natively supports 256 (>VOLUME_ID_LABEL_SIZE) size labels 102 // N.B.: btrfs natively supports 256 (>VOLUME_ID_LABEL_SIZE) size labels
103 volume_id_set_label_string(id, sb->label, VOLUME_ID_LABEL_SIZE); 103 volume_id_set_label_string(id, sb->label, VOLUME_ID_LABEL_SIZE);
104 volume_id_set_uuid(id, sb->fsid, UUID_DCE); 104 volume_id_set_uuid(id, sb->fsid, UUID_DCE);
105 IF_FEATURE_BLKID_TYPE(id->type = "btrfs";)
105 106
106 return 0; 107 return 0;
107} 108}
diff --git a/util-linux/volume_id/ext.c b/util-linux/volume_id/ext.c
index b5194a7b5..97451067f 100644
--- a/util-linux/volume_id/ext.c
+++ b/util-linux/volume_id/ext.c
@@ -19,28 +19,8 @@
19 */ 19 */
20 20
21#include "volume_id_internal.h" 21#include "volume_id_internal.h"
22#include "bb_e2fs_defs.h"
22 23
23struct ext2_super_block {
24 uint32_t inodes_count;
25 uint32_t blocks_count;
26 uint32_t r_blocks_count;
27 uint32_t free_blocks_count;
28 uint32_t free_inodes_count;
29 uint32_t first_data_block;
30 uint32_t log_block_size;
31 uint32_t dummy3[7];
32 uint8_t magic[2];
33 uint16_t state;
34 uint32_t dummy5[8];
35 uint32_t feature_compat;
36 uint32_t feature_incompat;
37 uint32_t feature_ro_compat;
38 uint8_t uuid[16];
39 uint8_t volume_name[16];
40} PACKED;
41
42#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
43#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
44#define EXT_SUPERBLOCK_OFFSET 0x400 24#define EXT_SUPERBLOCK_OFFSET 0x400
45 25
46int FAST_FUNC volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/) 26int FAST_FUNC volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/)
@@ -54,23 +34,27 @@ int FAST_FUNC volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/)
54 if (es == NULL) 34 if (es == NULL)
55 return -1; 35 return -1;
56 36
57 if (es->magic[0] != 0123 || es->magic[1] != 0357) { 37 if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) {
58 dbg("ext: no magic found"); 38 dbg("ext: no magic found");
59 return -1; 39 return -1;
60 } 40 }
61 41
62// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 42// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
63// volume_id_set_label_raw(id, es->volume_name, 16); 43// volume_id_set_label_raw(id, es->volume_name, 16);
64 volume_id_set_label_string(id, es->volume_name, 16); 44 volume_id_set_label_string(id, (void*)es->s_volume_name, 16);
65 volume_id_set_uuid(id, es->uuid, UUID_DCE); 45 volume_id_set_uuid(id, es->s_uuid, UUID_DCE);
66 dbg("ext: label '%s' uuid '%s'", id->label, id->uuid); 46 dbg("ext: label '%s' uuid '%s'", id->label, id->uuid);
67 47
68#if ENABLE_FEATURE_BLKID_TYPE 48#if ENABLE_FEATURE_BLKID_TYPE
69 if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) 49 if ((es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_HUGE_FILE | EXT4_FEATURE_RO_COMPAT_DIR_NLINK))
50 || (es->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_64BIT))
51 ) {
52 id->type = "ext4";
53 }
54 else if (es->s_feature_compat & cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL))
70 id->type = "ext3"; 55 id->type = "ext3";
71 else 56 else
72 id->type = "ext2"; 57 id->type = "ext2";
73#endif 58#endif
74
75 return 0; 59 return 0;
76} 60}
diff --git a/util-linux/volume_id/nilfs.c b/util-linux/volume_id/nilfs.c
new file mode 100644
index 000000000..ffa86d43c
--- /dev/null
+++ b/util-linux/volume_id/nilfs.c
@@ -0,0 +1,96 @@
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5 * Copyright (C) 2012 S-G Bergh <sgb@systemasis.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "volume_id_internal.h"
23
24#define NILFS_UUID_SIZE 16
25#define NILFS_LABEL_SIZE 80
26#define NILFS_SB1_OFFSET 0x400
27#define NILFS_SB2_OFFSET 0x1000
28#define NILFS_MAGIC 0x3434
29
30struct nilfs2_super_block {
31/* 0x00 */ uint32_t s_rev_level; // Major revision level.
32/* 0x04 */ uint16_t s_minor_rev_level; // Minor revision level.
33/* 0x06 */ uint16_t s_magic; // Magic signature.
34/* 0x08 */ uint16_t s_bytes;
35/* 0x0A */ uint16_t s_flags;
36/* 0x0C */ uint32_t s_crc_seed;
37/* 0x10 */ uint32_t s_sum;
38/* 0x14 */ uint32_t s_log_block_size;
39/* 0x18 */ uint64_t s_nsegments;
40/* 0x20 */ uint64_t s_dev_size; // Block device size in bytes.
41/* 0x28 */ uint64_t s_first_data_block;
42/* 0x30 */ uint32_t s_blocks_per_segment;
43/* 0x34 */ uint32_t s_r_segments_percentage;
44/* 0x38 */ uint64_t s_last_cno;
45/* 0x40 */ uint64_t s_last_pseg;
46/* 0x48 */ uint64_t s_last_seq;
47/* 0x50 */ uint64_t s_free_blocks_count;
48/* 0x58 */ uint64_t s_ctime;
49/* 0x60 */ uint64_t s_mtime;
50/* 0x68 */ uint64_t s_wtime;
51/* 0x70 */ uint16_t s_mnt_count;
52/* 0x72 */ uint16_t s_max_mnt_count;
53/* 0x74 */ uint16_t s_state;
54/* 0x76 */ uint16_t s_errors;
55/* 0x78 */ uint64_t s_lastcheck;
56/* 0x80 */ uint32_t s_checkinterval;
57/* 0x84 */ uint32_t s_creator_os;
58/* 0x88 */ uint16_t s_def_resuid;
59/* 0x8A */ uint16_t s_def_resgid;
60/* 0x8C */ uint32_t s_first_ino;
61/* 0x90 */ uint16_t s_inode_size;
62/* 0x92 */ uint16_t s_dat_entry_size;
63/* 0x94 */ uint16_t s_checkpoint_size;
64/* 0x96 */ uint16_t s_segment_usage_size;
65/* 0x98 */ uint8_t s_uuid[NILFS_UUID_SIZE]; // 128-bit UUID for volume.
66/* 0xA8 */ uint8_t s_volume_name[NILFS_LABEL_SIZE]; // Volume label.
67/* 0xF8 */ // ...
68} PACKED;
69
70int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/)
71{
72 struct nilfs2_super_block *sb;
73
74 // Primary super block
75 dbg("nilfs: probing at offset 0x%x", NILFS_SB1_OFFSET);
76
77 sb = volume_id_get_buffer(id, NILFS_SB1_OFFSET, sizeof(*sb));
78
79 if (sb == NULL)
80 return -1;
81
82 if (sb->s_magic != NILFS_MAGIC)
83 return -1;
84
85 // The secondary superblock is not always used, so ignore it for now.
86 // When used it is at 4K from the end of the partition (sb->s_dev_size - NILFS_SB2_OFFSET).
87
88 volume_id_set_label_string(id, sb->s_volume_name, NILFS_LABEL_SIZE < VOLUME_ID_LABEL_SIZE ?
89 NILFS_LABEL_SIZE : VOLUME_ID_LABEL_SIZE);
90 volume_id_set_uuid(id, sb->s_uuid, UUID_DCE);
91
92 if (sb->s_rev_level == 2)
93 IF_FEATURE_BLKID_TYPE(id->type = "nilfs2");
94
95 return 0;
96}
diff --git a/util-linux/volume_id/util.c b/util-linux/volume_id/util.c
index dd75c7ba1..69e43dda8 100644
--- a/util-linux/volume_id/util.c
+++ b/util-linux/volume_id/util.c
@@ -31,25 +31,29 @@ void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum end
31 c = (buf[i+1] << 8) | buf[i]; 31 c = (buf[i+1] << 8) | buf[i];
32 else 32 else
33 c = (buf[i] << 8) | buf[i+1]; 33 c = (buf[i] << 8) | buf[i+1];
34 if (c == 0) { 34 if (c == 0)
35 str[j] = '\0';
36 break; 35 break;
37 } else if (c < 0x80) { 36 if (j+1 >= len)
38 if (j+1 >= len) 37 break;
39 break; 38 if (c < 0x80) {
40 str[j++] = (uint8_t) c; 39 /* 0xxxxxxx */
41 } else if (c < 0x800) {
42 if (j+2 >= len)
43 break;
44 str[j++] = (uint8_t) (0xc0 | (c >> 6));
45 str[j++] = (uint8_t) (0x80 | (c & 0x3f));
46 } else { 40 } else {
47 if (j+3 >= len) 41 uint8_t topbits = 0xc0;
42 if (j+2 >= len)
48 break; 43 break;
49 str[j++] = (uint8_t) (0xe0 | (c >> 12)); 44 if (c < 0x800) {
50 str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); 45 /* 110yyyxx 10xxxxxx */
51 str[j++] = (uint8_t) (0x80 | (c & 0x3f)); 46 } else {
47 if (j+3 >= len)
48 break;
49 /* 1110yyyy 10yyyyxx 10xxxxxx */
50 str[j++] = (uint8_t) (0xe0 | (c >> 12));
51 topbits = 0x80;
52 }
53 str[j++] = (uint8_t) (topbits | ((c >> 6) & 0x3f));
54 c = 0x80 | (c & 0x3f);
52 } 55 }
56 str[j++] = (uint8_t) c;
53 } 57 }
54 str[j] = '\0'; 58 str[j] = '\0';
55} 59}
diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c
index f41d4e0d9..c1d615283 100644
--- a/util-linux/volume_id/volume_id.c
+++ b/util-linux/volume_id/volume_id.c
@@ -130,6 +130,9 @@ static const probe_fptr fs2[] = {
130#if ENABLE_FEATURE_VOLUMEID_UFS 130#if ENABLE_FEATURE_VOLUMEID_UFS
131 volume_id_probe_ufs, 131 volume_id_probe_ufs,
132#endif 132#endif
133#if ENABLE_FEATURE_VOLUMEID_NILFS
134 volume_id_probe_nilfs,
135#endif
133#if ENABLE_FEATURE_VOLUMEID_NTFS 136#if ENABLE_FEATURE_VOLUMEID_NTFS
134 volume_id_probe_ntfs, 137 volume_id_probe_ntfs,
135#endif 138#endif
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h
index 1c64046e5..1c2e0ffa6 100644
--- a/util-linux/volume_id/volume_id_internal.h
+++ b/util-linux/volume_id/volume_id_internal.h
@@ -212,6 +212,8 @@ int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/);
212 212
213//int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id /*,uint64_t off*/); 213//int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id /*,uint64_t off*/);
214 214
215int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/);
216
215int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/); 217int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/);
216 218
217int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/); 219int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/);