From 902d3992922fc8db8495d5fb30a4581711b60c62 Mon Sep 17 00:00:00 2001
From: Alistair Francis <alistair.francis@wdc.com>
Date: Wed, 18 Sep 2019 09:28:50 -0700
Subject: time: Use 64 prefix syscall if we have to

Some 32-bit architectures no longer have the 32-bit time_t syscalls.
Instead they have suffixed syscalls that returns a 64-bit time_t. If
the architecture doesn't have the non-suffixed syscall and is using a
64-bit time_t let's use the suffixed syscall instead.

This fixes build issues when building for RISC-V 32-bit with 5.1+ kernel
headers.

If an architecture only supports the suffixed syscalls, but is still
using a 32-bit time_t report a compilation error. This avoids us have to
deal with converting between 64-bit and 32-bit values. There are
currently no architectures where this is the case.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/time.c | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'libbb')

diff --git a/libbb/time.c b/libbb/time.c
index cab0ad602..b6fcae28b 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -257,7 +257,14 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
  * typically requiring -lrt. We just skip all this mess */
 static void get_mono(struct timespec *ts)
 {
+#if defined(__NR_clock_gettime)
 	if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
+#elif __TIMESIZE == 64
+	if (syscall(__NR_clock_gettime64, CLOCK_MONOTONIC, ts))
+#else
+# error "We currently don't support architectures without " \
+	"the __NR_clock_gettime syscall and 32-bit time_t"
+#endif
 		bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed");
 }
 unsigned long long FAST_FUNC monotonic_ns(void)
-- 
cgit v1.2.3-55-g6feb


From dd4686128290b34d61becaaba88c54d5213f7aa5 Mon Sep 17 00:00:00 2001
From: Martin Lewis <martin.lewis.x84@gmail.com>
Date: Sun, 15 Sep 2019 18:13:28 +0200
Subject: libbb: Converted safe_read to safe_write format

Changed safe_read to be symmetrical to safe_write, it shall
never return EINTR because it calls read multiple times,
the error is considered transient.

function                                             old     new   delta
safe_read                                             44      57     +13

Signed-off-by: Martin Lewis <martin.lewis.x84@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/read.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

(limited to 'libbb')

diff --git a/libbb/read.c b/libbb/read.c
index 5906bc225..a342506a8 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -12,9 +12,17 @@ ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count)
 {
 	ssize_t n;
 
-	do {
+	for (;;) {
 		n = read(fd, buf, count);
-	} while (n < 0 && errno == EINTR);
+		if (n >= 0 || errno != EINTR)
+			break;
+		/* Some callers set errno=0, are upset when they see EINTR.
+		 * Returning EINTR is wrong since we retry read(),
+		 * the "error" was transient.
+		 */
+		errno = 0;
+		/* repeat the read() */
+	}
 
 	return n;
 }
-- 
cgit v1.2.3-55-g6feb


From 7011eca83afc313098f9869eea36742d4506bc02 Mon Sep 17 00:00:00 2001
From: Martin Lewis <martin.lewis.x84@gmail.com>
Date: Sun, 15 Sep 2019 18:51:30 +0200
Subject: replace: count_strstr - Handle an edge case where sub is empty

If sub is empty, avoids an infinite loop.

function                                             old     new   delta
count_strstr                                          45      63     +18

Signed-off-by: Martin Lewis <martin.lewis.x84@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/replace.c | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'libbb')

diff --git a/libbb/replace.c b/libbb/replace.c
index a661d96e6..6183d3e6f 100644
--- a/libbb/replace.c
+++ b/libbb/replace.c
@@ -15,6 +15,10 @@ unsigned FAST_FUNC count_strstr(const char *str, const char *sub)
 	size_t sub_len = strlen(sub);
 	unsigned count = 0;
 
+	/* If sub is empty, avoid an infinite loop */
+	if (sub_len == 0)
+		return strlen(str) + 1;
+
 	while ((str = strstr(str, sub)) != NULL) {
 		count++;
 		str += sub_len;
-- 
cgit v1.2.3-55-g6feb


From 42f454b13b8d972e85acd7f046065ec69af4d206 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 11 Oct 2019 14:11:44 +0200
Subject: dpkg-deb: work around bogus error message when working with XZ
 compressed packages

function                                             old     new   delta
unpack_xz_stream                                    2309    2317      +8
bb_full_fd_action                                    464     472      +8

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 archival/libarchive/decompress_unxz.c | 20 +++++++++++++++++++-
 archival/libarchive/unxz/xz_stream.h  |  2 +-
 libbb/copyfd.c                        | 13 ++++++++-----
 3 files changed, 28 insertions(+), 7 deletions(-)

(limited to 'libbb')

diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index f03341384..3dd9bbf49 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -96,6 +96,24 @@ unpack_xz_stream(transformer_state_t *xstate)
 			 */
 			do {
 				if (membuf[iobuf.in_pos] != 0) {
+					/* There is more data, but is it XZ data?
+					 * Example: dpkg-deb -f busybox_1.30.1-4_amd64.deb
+					 * reads control.tar.xz "control" file
+					 * inside the ar archive, but tar.xz
+					 * extraction code reaches end of xz data,
+					 * reached this code and reads the beginning
+					 * of data.tar.xz's ar header, which isn't xz data,
+					 * and prints "corrupted data".
+					 * The correct solution is to not read
+					 * past nested archive (to simulate EOF).
+					 * This is a workaround:
+					 */
+					if (membuf[iobuf.in_pos] != 0xfd) {
+						/* It's definitely not a xz signature
+						 * (which is 0xfd,"7zXZ",0x00).
+						 */
+						goto end;
+					}
 					xz_dec_reset(state);
 					goto do_run;
 				}
@@ -128,7 +146,7 @@ unpack_xz_stream(transformer_state_t *xstate)
 			break;
 		}
 	}
-
+ end:
 	xz_dec_end(state);
 	free(membuf);
 
diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h
index 66cb5a705..45056e42c 100644
--- a/archival/libarchive/unxz/xz_stream.h
+++ b/archival/libarchive/unxz/xz_stream.h
@@ -25,7 +25,7 @@
 
 #define STREAM_HEADER_SIZE 12
 
-#define HEADER_MAGIC "\3757zXZ"
+#define HEADER_MAGIC "\375""7zXZ"
 #define HEADER_MAGIC_SIZE 6
 
 #define FOOTER_MAGIC "YZ"
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index ae5c26999..d41fd10f0 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -18,7 +18,7 @@
  * was seen to cause largish delays when user tries to ^C a file copy.
  * Let's use a saner size.
  * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB),
- * or else "copy to eof" code will use neddlesly short reads.
+ * or else "copy to eof" code will use needlesly short reads.
  */
 #define SENDFILE_BIGBUF (16*1024*1024)
 
@@ -60,10 +60,13 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
 		ssize_t rd;
 
 		if (sendfile_sz) {
-			rd = sendfile(dst_fd, src_fd, NULL,
-				size > sendfile_sz ? sendfile_sz : size);
-			if (rd >= 0)
-				goto read_ok;
+			/* dst_fd == -1 is a fake, else... */
+			if (dst_fd >= 0) {
+				rd = sendfile(dst_fd, src_fd, NULL,
+					size > sendfile_sz ? sendfile_sz : size);
+				if (rd >= 0)
+					goto read_ok;
+			}
 			sendfile_sz = 0; /* do not try sendfile anymore */
 		}
 #if CONFIG_FEATURE_COPYBUF_KB > 4
-- 
cgit v1.2.3-55-g6feb


From be5a505d771a77c640acc35ceaa470c80e62f954 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 24 Oct 2019 16:26:55 +0200
Subject: Remove syscall wrappers around clock_gettime, closes 12091

12091 "Direct use of __NR_clock_gettime is not time64-safe".

function                                             old     new   delta
runsv_main                                          1698    1712     +14
startservice                                         378     383      +5
get_mono                                              31      25      -6
date_main                                            932     926      -6
gettimeofday_ns                                       17       -     -17
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 2/2 up/down: 19/-29)            Total: -10 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 Makefile.flags   |  6 ++++--
 coreutils/date.c | 16 +++-------------
 libbb/time.c     | 11 +----------
 runit/runsv.c    | 11 +----------
 4 files changed, 9 insertions(+), 35 deletions(-)

(limited to 'libbb')

diff --git a/Makefile.flags b/Makefile.flags
index 6f6142cc5..bea464753 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -129,10 +129,12 @@ endif
 # fall back to using a temp file:
 CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c)
 ifeq ($(CRYPT_AVAILABLE),y)
-LDLIBS += m crypt
+LDLIBS += m rt crypt
 else
-LDLIBS += m
+LDLIBS += m rt
 endif
+# libm may be needed for dc, awk, ntpd
+# librt may be needed for clock_gettime()
 
 # libpam may use libpthread, libdl and/or libaudit.
 # On some platforms that requires an explicit -lpthread, -ldl, -laudit.
diff --git a/coreutils/date.c b/coreutils/date.c
index 731241536..f7e9a8d0e 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -33,10 +33,9 @@
 //config:	Enable option (-I) to output an ISO-8601 compliant
 //config:	date/time string.
 //config:
-//config:# defaults to "no": stat's nanosecond field is a bit non-portable
 //config:config FEATURE_DATE_NANO
 //config:	bool "Support %[num]N nanosecond format specifier"
-//config:	default n  # syscall(__NR_clock_gettime) or syscall(__NR_clock_gettime64)
+//config:	default n # stat's nanosecond field is a bit non-portable
 //config:	depends on DATE
 //config:	select PLATFORM_LINUX
 //config:	help
@@ -271,17 +270,8 @@ int date_main(int argc UNUSED_PARAM, char **argv)
 		 */
 #endif
 	} else {
-#if ENABLE_FEATURE_DATE_NANO && defined(__NR_clock_gettime)
-		/* libc has incredibly messy way of doing this,
-		 * typically requiring -lrt. We just skip all this mess */
-		syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts);
-#elif ENABLE_FEATURE_DATE_NANO && __TIMESIZE == 64
-		/* Let's only support the 64 suffix syscalls for 64-bit time_t.
-		 * This simplifies the code for us as we don't need to convert
-		 * between 64-bit and 32-bit. We also don't have a way to
-		 * report overflow errors here.
-		 */
-		syscall(__NR_clock_gettime64, CLOCK_REALTIME, &ts);
+#if ENABLE_FEATURE_DATE_NANO
+		clock_gettime(CLOCK_REALTIME, &ts);
 #else
 		time(&ts.tv_sec);
 #endif
diff --git a/libbb/time.c b/libbb/time.c
index b6fcae28b..e66a9cba8 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -253,18 +253,9 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
 #define CLOCK_MONOTONIC 1
 #endif
 
-/* libc has incredibly messy way of doing this,
- * typically requiring -lrt. We just skip all this mess */
 static void get_mono(struct timespec *ts)
 {
-#if defined(__NR_clock_gettime)
-	if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
-#elif __TIMESIZE == 64
-	if (syscall(__NR_clock_gettime64, CLOCK_MONOTONIC, ts))
-#else
-# error "We currently don't support architectures without " \
-	"the __NR_clock_gettime syscall and 32-bit time_t"
-#endif
+	if (clock_gettime(CLOCK_MONOTONIC, ts))
 		bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed");
 }
 unsigned long long FAST_FUNC monotonic_ns(void)
diff --git a/runit/runsv.c b/runit/runsv.c
index 737909b0e..36d85101e 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -51,18 +51,9 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #if ENABLE_MONOTONIC_SYSCALL
 #include <sys/syscall.h>
 
-/* libc has incredibly messy way of doing this,
- * typically requiring -lrt. We just skip all this mess */
 static void gettimeofday_ns(struct timespec *ts)
 {
-#if defined(__NR_clock_gettime)
-	syscall(__NR_clock_gettime, CLOCK_REALTIME, ts);
-#elif __TIMESIZE == 64
-	syscall(__NR_clock_gettime64, CLOCK_REALTIME, ts);
-#else
-# error "We currently don't support architectures without " \
-	"the __NR_clock_gettime syscall and 32-bit time_t"
-#endif
+	clock_gettime(CLOCK_REALTIME, ts);
 }
 #else
 static void gettimeofday_ns(struct timespec *ts)
-- 
cgit v1.2.3-55-g6feb


From af7169b4a70eb3f60555ced17a40780f70aaaa5c Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 25 Oct 2019 12:12:22 +0200
Subject: clang/llvm 9 fix - do not eliminate a store to a fake "const"

This is *much* better (9 kbytes better) than dropping "*const"
optimization trick.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 coreutils/test.c  |  2 +-
 include/libbb.h   | 22 +++++++++++++++++++++-
 libbb/appletlib.c |  2 +-
 libbb/lineedit.c  |  2 +-
 shell/ash.c       |  6 +++---
 5 files changed, 27 insertions(+), 7 deletions(-)

(limited to 'libbb')

diff --git a/coreutils/test.c b/coreutils/test.c
index 868ffbecb..a08986130 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -411,7 +411,7 @@ extern struct test_statics *const test_ptr_to_statics;
 #define leaving         (S.leaving      )
 
 #define INIT_S() do { \
-	(*(struct test_statics**)&test_ptr_to_statics) = xzalloc(sizeof(S)); \
+	(*(struct test_statics**)not_const_pp(&test_ptr_to_statics)) = xzalloc(sizeof(S)); \
 	barrier(); \
 } while (0)
 #define DEINIT_S() do { \
diff --git a/include/libbb.h b/include/libbb.h
index 111d1b790..05a560977 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -2153,12 +2153,32 @@ struct globals;
  * Magic prevents ptr_to_globals from going into rodata.
  * If you want to assign a value, use SET_PTR_TO_GLOBALS(x) */
 extern struct globals *const ptr_to_globals;
+
+#if defined(__clang_major__) && __clang_major__ >= 9
+/* Clang/llvm drops assignment to "constant" storage. Silently.
+ * Needs serious convincing to not eliminate the store.
+ */
+static ALWAYS_INLINE void* not_const_pp(const void *p)
+{
+	void *pp;
+	__asm__ __volatile__(
+		"# forget that p points to const"
+		: /*outputs*/ "=r" (pp)
+		: /*inputs*/ "0" (p)
+	);
+	return pp;
+}
+#else
+static ALWAYS_INLINE void* not_const_pp(const void *p) { return (void*)p; }
+#endif
+
 /* At least gcc 3.4.6 on mipsel system needs optimization barrier */
 #define barrier() __asm__ __volatile__("":::"memory")
 #define SET_PTR_TO_GLOBALS(x) do { \
-	(*(struct globals**)&ptr_to_globals) = (void*)(x); \
+	(*(struct globals**)not_const_pp(&ptr_to_globals)) = (void*)(x); \
 	barrier(); \
 } while (0)
+
 #define FREE_PTR_TO_GLOBALS() do { \
 	if (ENABLE_FEATURE_CLEAN_UP) { \
 		free(ptr_to_globals); \
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 9fa17cfa1..f842e73cc 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -304,7 +304,7 @@ void lbb_prepare(const char *applet
 		IF_FEATURE_INDIVIDUAL(, char **argv))
 {
 #ifdef __GLIBC__
-	(*(int **)&bb_errno) = __errno_location();
+	(*(int **)not_const_pp(&bb_errno)) = __errno_location();
 	barrier();
 #endif
 	applet_name = applet;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index fbabc6c12..b1ec52b88 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -203,7 +203,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
 #define delbuf           (S.delbuf          )
 
 #define INIT_S() do { \
-	(*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
+	(*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \
 	barrier(); \
 	cmdedit_termw = 80; \
 	IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
diff --git a/shell/ash.c b/shell/ash.c
index c5588ea66..4b5eafa7c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -489,7 +489,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
 #define random_gen  (G_misc.random_gen )
 #define backgndpid  (G_misc.backgndpid )
 #define INIT_G_misc() do { \
-	(*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
+	(*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \
 	barrier(); \
 	curdir = nullstr; \
 	physdir = nullstr; \
@@ -1542,7 +1542,7 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
 #define g_stacknleft (G_memstack.g_stacknleft)
 #define stackbase    (G_memstack.stackbase   )
 #define INIT_G_memstack() do { \
-	(*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
+	(*(struct globals_memstack**)not_const_pp(&ash_ptr_to_globals_memstack)) = xzalloc(sizeof(G_memstack)); \
 	barrier(); \
 	g_stackp = &stackbase; \
 	g_stacknxt = stackbase.space; \
@@ -2165,7 +2165,7 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
 #endif
 #define INIT_G_var() do { \
 	unsigned i; \
-	(*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
+	(*(struct globals_var**)not_const_pp(&ash_ptr_to_globals_var)) = xzalloc(sizeof(G_var)); \
 	barrier(); \
 	for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
 		varinit[i].flags    = varinit_data[i].flags; \
-- 
cgit v1.2.3-55-g6feb


From f39a71817ead331b664bc658ac26dec4ec3b75bc Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 25 Oct 2019 17:40:57 +0200
Subject: read_key(): placate "warning: shifting a negative signed value is
 undefined"

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/read_key.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'libbb')

diff --git a/libbb/read_key.c b/libbb/read_key.c
index 951786869..03b7da656 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -259,7 +259,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
 
 			buffer[-1] = 0;
 			/* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
-			col |= (((-1 << 15) | row) << 16);
+			row |= ((unsigned)(-1) << 15);
+			col |= (row << 16);
 			/* Return it in high-order word */
 			return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
 		}
-- 
cgit v1.2.3-55-g6feb


From d3539be8f27b8cbfdfee460fe08299158f08bcd9 Mon Sep 17 00:00:00 2001
From: Alistair Francis <alistair.francis@wdc.com>
Date: Tue, 19 Nov 2019 13:06:40 +0100
Subject: Remove stime() function calls

stime() has been deprecated in glibc 2.31 and replaced with
clock_settime(). Let's replace the stime() function calls with
clock_settime() in preperation.

function                                             old     new   delta
rdate_main                                           197     224     +27
clock_settime                                          -      27     +27
date_main                                            926     941     +15
stime                                                 37       -     -37
------------------------------------------------------------------------------
(add/remove: 2/2 grow/shrink: 2/0 up/down: 69/-37)             Total: 32 bytes

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 coreutils/date.c         | 6 +++++-
 libbb/missing_syscalls.c | 8 --------
 util-linux/rdate.c       | 8 ++++++--
 3 files changed, 11 insertions(+), 11 deletions(-)

(limited to 'libbb')

diff --git a/coreutils/date.c b/coreutils/date.c
index f7e9a8d0e..b9b7fd2cb 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -276,6 +276,9 @@ int date_main(int argc UNUSED_PARAM, char **argv)
 		time(&ts.tv_sec);
 #endif
 	}
+#if !ENABLE_FEATURE_DATE_NANO
+	ts.tv_nsec = 0;
+#endif
 	localtime_r(&ts.tv_sec, &tm_time);
 
 	/* If date string is given, update tm_time, and maybe set date */
@@ -298,9 +301,10 @@ int date_main(int argc UNUSED_PARAM, char **argv)
 		if (date_str[0] != '@')
 			tm_time.tm_isdst = -1;
 		ts.tv_sec = validate_tm_time(date_str, &tm_time);
+		ts.tv_nsec = 0;
 
 		/* if setting time, set it */
-		if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) {
+		if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) {
 			bb_simple_perror_msg("can't set date");
 		}
 	}
diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c
index 87cf59b3d..dc40d9155 100644
--- a/libbb/missing_syscalls.c
+++ b/libbb/missing_syscalls.c
@@ -15,14 +15,6 @@ pid_t getsid(pid_t pid)
 	return syscall(__NR_getsid, pid);
 }
 
-int stime(const time_t *t)
-{
-	struct timeval tv;
-	tv.tv_sec = *t;
-	tv.tv_usec = 0;
-	return settimeofday(&tv, NULL);
-}
-
 int sethostname(const char *name, size_t len)
 {
 	return syscall(__NR_sethostname, name, len);
diff --git a/util-linux/rdate.c b/util-linux/rdate.c
index 41aade5ea..bb1dc519a 100644
--- a/util-linux/rdate.c
+++ b/util-linux/rdate.c
@@ -95,9 +95,13 @@ int rdate_main(int argc UNUSED_PARAM, char **argv)
 	if (!(flags & 2)) { /* no -p (-s may be present) */
 		if (time(NULL) == remote_time)
 			bb_simple_error_msg("current time matches remote time");
-		else
-			if (stime(&remote_time) < 0)
+		else {
+			struct timespec ts;
+			ts.tv_sec = remote_time;
+			ts.tv_nsec = 0;
+			if (clock_settime(CLOCK_REALTIME, &ts) < 0)
 				bb_simple_perror_msg_and_die("can't set time of day");
+		}
 	}
 
 	if (flags != 1) /* not lone -s */
-- 
cgit v1.2.3-55-g6feb