From aa4f9a2fd8a077c4e61e78fc397b47e541b0c140 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 28 Jan 2011 19:14:17 +0100
Subject: libbb/copy_file.c: use smallints instead of signed chars

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/copy_file.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'libbb')

diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 57d9dbfdb..9333a8d49 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -78,9 +78,9 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
 	/* NB: each struct stat is ~100 bytes */
 	struct stat source_stat;
 	struct stat dest_stat;
-	signed char retval = 0;
-	signed char dest_exists = 0;
-	signed char ovr;
+	smallint retval = 0;
+	smallint dest_exists = 0;
+	smallint ovr;
 
 /* Inverse of cp -d ("cp without -d") */
 #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
@@ -147,7 +147,6 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
 			return -1;
 		}
 
-		/* Create DEST */
 		if (dest_exists) {
 			if (!S_ISDIR(dest_stat.st_mode)) {
 				bb_error_msg("target '%s' is not a directory", dest);
@@ -156,6 +155,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
 			/* race here: user can substitute a symlink between
 			 * this check and actual creation of files inside dest */
 		} else {
+			/* Create DEST */
 			mode_t mode;
 			saved_umask = umask(0);
 
-- 
cgit v1.2.3-55-g6feb


From 55ae0e9238e1979f0200700ec5dbd0df8d32f7a2 Mon Sep 17 00:00:00 2001
From: Lauri Kasanen <curaga@operamail.com>
Date: Mon, 31 Jan 2011 06:27:35 +0100
Subject: df,find_mount_point: optionally don't ignore rootfs

Signed-off-by: Lauri Kasanen <curaga@operamail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 coreutils/df.c           |  2 +-
 libbb/Config.src         | 19 +++++++++++++++++++
 libbb/find_mount_point.c |  2 +-
 3 files changed, 21 insertions(+), 2 deletions(-)

(limited to 'libbb')

diff --git a/coreutils/df.c b/coreutils/df.c
index af9b77b23..70fd1f4fd 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -160,7 +160,7 @@ int df_main(int argc UNUSED_PARAM, char **argv)
 			}
 
 			/* GNU coreutils 6.10 skips certain mounts, try to be compatible.  */
-			if (strcmp(device, "rootfs") == 0)
+			if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0)
 				continue;
 
 #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
diff --git a/libbb/Config.src b/libbb/Config.src
index 85892d3fe..dfb897d5f 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -161,6 +161,25 @@ config FEATURE_COPYBUF_KB
 	  Bigger buffers will be allocated with mmap, with fallback to 4 kb
 	  stack buffer if mmap fails.
 
+config FEATURE_SKIP_ROOTFS
+	bool "Skip rootfs in mount table"
+	default y
+	help
+	  Ignore rootfs entry in mount table.
+
+	  In Linux, kernel has a special filesystem, rootfs, which is initially
+	  mounted on /. It contains initramfs data, if kernel is configured
+	  to have one. Usually, another file system is mounted over / early
+	  in boot process, and therefore most tools which manipulate
+	  mount table, such as df, will skip rootfs entry.
+
+	  However, some systems do not mount anything on /.
+	  If you need to configure busybox for one of these systems,
+	  you may find useful to turn this option off to make df show
+	  initramfs statistic.
+
+	  Otherwise, choose Y.
+
 config MONOTONIC_SYSCALL
 	bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
 	default n
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 361698a6b..56637ad92 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -43,7 +43,7 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
 		/* rootfs mount in Linux 2.6 exists always,
 		 * and it makes sense to always ignore it.
 		 * Otherwise people can't reference their "real" root! */
-		if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
+		if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
 			continue;
 
 		if (strcmp(name, mountEntry->mnt_dir) == 0
-- 
cgit v1.2.3-55-g6feb


From c71b469f5daceb717e31cc9ce46b0e058e2c57b6 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Wed, 2 Feb 2011 03:28:56 +0100
Subject: libbb: make BB_EXECVP/LP try to exec real binary if there's no
 /proc/self/exe

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/libbb.h            | 12 +++++++-----
 libbb/execable.c           | 10 +++++-----
 libbb/vfork_daemon_rexec.c | 12 ++++++------
 3 files changed, 18 insertions(+), 16 deletions(-)

(limited to 'libbb')

diff --git a/include/libbb.h b/include/libbb.h
index 182b47988..e69e27944 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -867,14 +867,16 @@ int exists_execable(const char *filename) FAST_FUNC;
  * but it may exec busybox and call applet instead of searching PATH.
  */
 #if ENABLE_FEATURE_PREFER_APPLETS
-int bb_execvp(const char *file, char *const argv[]) FAST_FUNC;
-#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
+int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC;
 #define BB_EXECLP(prog,cmd,...) \
-	execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
-		cmd, __VA_ARGS__)
+	do { \
+		if (find_applet_by_name(prog) >= 0) \
+			execlp(bb_busybox_exec_path, cmd, __VA_ARGS__); \
+		execlp(prog, cmd, __VA_ARGS__); \
+	} while (0)
 #else
 #define BB_EXECVP(prog,cmd)     execvp(prog,cmd)
-#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
+#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__)
 #endif
 int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
 
diff --git a/libbb/execable.c b/libbb/execable.c
index d37640007..178a00a5f 100644
--- a/libbb/execable.c
+++ b/libbb/execable.c
@@ -68,12 +68,12 @@ int FAST_FUNC exists_execable(const char *filename)
 }
 
 #if ENABLE_FEATURE_PREFER_APPLETS
-/* just like the real execvp, but try to launch an applet named 'file' first
- */
-int FAST_FUNC bb_execvp(const char *file, char *const argv[])
+/* just like the real execvp, but try to launch an applet named 'file' first */
+int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
 {
-	return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file,
-					argv);
+	if (find_applet_by_name(file) >= 0)
+		execvp(bb_busybox_exec_path, argv);
+	return execvp(file, argv);
 }
 #endif
 
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 5e0fb0d73..cb4781a59 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -182,17 +182,17 @@ int FAST_FUNC spawn_and_wait(char **argv)
 	int a = find_applet_by_name(argv[0]);
 
 	if (a >= 0 && (APPLET_IS_NOFORK(a)
-#if BB_MMU
+# if BB_MMU
 			|| APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
-#endif
+# endif
 	)) {
-#if BB_MMU
+# if BB_MMU
 		if (APPLET_IS_NOFORK(a))
-#endif
+# endif
 		{
 			return run_nofork_applet(a, argv);
 		}
-#if BB_MMU
+# if BB_MMU
 		/* MMU only */
 		/* a->noexec is true */
 		rc = fork();
@@ -201,7 +201,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
 		/* child */
 		xfunc_error_retval = EXIT_FAILURE;
 		run_applet_no_and_exit(a, argv);
-#endif
+# endif
 	}
 #endif /* FEATURE_PREFER_APPLETS */
 	rc = spawn(argv);
-- 
cgit v1.2.3-55-g6feb


From 6307357effb79c8fbc6ccc9d4528c8c1c48a4831 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Wed, 2 Feb 2011 19:05:25 +0100
Subject: move nofork_save_area from libbb.h to vfork_daemon_rexec.c

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/libbb.h            | 11 -----------
 libbb/getopt32.c           |  2 +-
 libbb/vfork_daemon_rexec.c | 48 ++++++++++++++++++----------------------------
 3 files changed, 20 insertions(+), 41 deletions(-)

(limited to 'libbb')

diff --git a/include/libbb.h b/include/libbb.h
index 88dceb11d..a0e23697c 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -911,19 +911,8 @@ pid_t wait_any_nohang(int *wstat) FAST_FUNC;
 int wait4pid(pid_t pid) FAST_FUNC;
 /* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */
 int spawn_and_wait(char **argv) FAST_FUNC;
-struct nofork_save_area {
-	jmp_buf die_jmp;
-	const char *applet_name;
-	uint32_t option_mask32;
-	int die_sleep;
-	uint8_t xfunc_error_retval;
-	smallint saved;
-};
-void save_nofork_data(struct nofork_save_area *save) FAST_FUNC;
-void restore_nofork_data(struct nofork_save_area *save) FAST_FUNC;
 /* Does NOT check that applet is NOFORK, just blindly runs it */
 int run_nofork_applet(int applet_no, char **argv) FAST_FUNC;
-int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) FAST_FUNC;
 
 /* Helpers for daemonization.
  *
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 25bae319e..abd412043 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -531,7 +531,7 @@ getopt32(char **argv, const char *applet_opts, ...)
 
 	/* In case getopt32 was already called:
 	 * reset the libc getopt() function, which keeps internal state.
-	 * run_nofork_applet_prime() does this, but we might end up here
+	 * run_nofork_applet() does this, but we might end up here
 	 * also via gunzip_main() -> gzip_main(). Play safe.
 	 */
 #ifdef __GLIBC__
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index cb4781a59..af938bed3 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -68,17 +68,22 @@ pid_t FAST_FUNC xspawn(char **argv)
 }
 
 #if ENABLE_FEATURE_PREFER_APPLETS
-void FAST_FUNC save_nofork_data(struct nofork_save_area *save)
+struct nofork_save_area {
+	jmp_buf die_jmp;
+	const char *applet_name;
+	uint32_t option_mask32;
+	int die_sleep;
+	uint8_t xfunc_error_retval;
+};
+static void save_nofork_data(struct nofork_save_area *save)
 {
 	memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
 	save->applet_name = applet_name;
 	save->xfunc_error_retval = xfunc_error_retval;
 	save->option_mask32 = option_mask32;
 	save->die_sleep = die_sleep;
-	save->saved = 1;
 }
-
-void FAST_FUNC restore_nofork_data(struct nofork_save_area *save)
+static void restore_nofork_data(struct nofork_save_area *save)
 {
 	memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
 	applet_name = save->applet_name;
@@ -87,19 +92,17 @@ void FAST_FUNC restore_nofork_data(struct nofork_save_area *save)
 	die_sleep = save->die_sleep;
 }
 
-int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv)
+int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
 {
 	int rc, argc;
+	struct nofork_save_area old;
+
+	save_nofork_data(&old);
 
 	applet_name = APPLET_NAME(applet_no);
 
 	xfunc_error_retval = EXIT_FAILURE;
 
-	/* Special flag for xfunc_die(). If xfunc will "die"
-	 * in NOFORK applet, xfunc_die() sees negative
-	 * die_sleep and longjmp here instead. */
-	die_sleep = -1;
-
 	/* In case getopt() or getopt32() was already called:
 	 * reset the libc getopt() function, which keeps internal state.
 	 *
@@ -129,6 +132,11 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
 	while (argv[argc])
 		argc++;
 
+	/* Special flag for xfunc_die(). If xfunc will "die"
+	 * in NOFORK applet, xfunc_die() sees negative
+	 * die_sleep and longjmp here instead. */
+	die_sleep = -1;
+
 	rc = setjmp(die_jmp);
 	if (!rc) {
 		/* Some callers (xargs)
@@ -137,15 +145,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
 		memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
 		/* Finally we can call NOFORK applet's main() */
 		rc = applet_main[applet_no](argc, tmp_argv);
-
-	/* The whole reason behind nofork_save_area is that <applet>_main
-	 * may exit non-locally! For example, in hush Ctrl-Z tries
-	 * (modulo bugs) to dynamically create a child (backgrounded task)
-	 * if it detects that Ctrl-Z was pressed when a NOFORK was running.
-	 * Testcase: interactive "rm -i".
-	 * Don't fool yourself into thinking "and <applet>_main() returns
-	 * quickly here" and removing "useless" nofork_save_area code. */
-
 	} else { /* xfunc died in NOFORK applet */
 		/* in case they meant to return 0... */
 		if (rc == -2222)
@@ -153,7 +152,7 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
 	}
 
 	/* Restoring some globals */
-	restore_nofork_data(old);
+	restore_nofork_data(&old);
 
 	/* Other globals can be simply reset to defaults */
 #ifdef __GLIBC__
@@ -164,15 +163,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
 
 	return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
 }
-
-int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
-{
-	struct nofork_save_area old;
-
-	/* Saving globals */
-	save_nofork_data(&old);
-	return run_nofork_applet_prime(&old, applet_no, argv);
-}
 #endif /* FEATURE_PREFER_APPLETS */
 
 int FAST_FUNC spawn_and_wait(char **argv)
-- 
cgit v1.2.3-55-g6feb


From b7c9fb27cba3d697e602f8cbf88cde135d8d6c5e Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 3 Feb 2011 00:05:48 +0100
Subject: whitespace fixes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 applets/usage_pod.c                            | 4 ++--
 archival/lzop.c                                | 2 +-
 e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c | 4 ++--
 editors/sed.c                                  | 2 +-
 libbb/crc32.c                                  | 2 +-
 libbb/getopt32.c                               | 8 ++++----
 loginutils/getty.c                             | 2 +-
 modutils/modprobe.c                            | 2 +-
 networking/httpd_ssi.c                         | 4 ++--
 networking/ntpd.c                              | 2 +-
 procps/pstree.c                                | 2 +-
 shell/shell_common.c                           | 6 +++---
 util-linux/flock.c                             | 2 +-
 13 files changed, 21 insertions(+), 21 deletions(-)

(limited to 'libbb')

diff --git a/applets/usage_pod.c b/applets/usage_pod.c
index da0baefc6..0b1c4aadb 100644
--- a/applets/usage_pod.c
+++ b/applets/usage_pod.c
@@ -31,8 +31,8 @@
 #include "usage.h"
 #define MAKE_USAGE(aname, usage) { aname, usage },
 static struct usage_data {
-        const char *aname;
-        const char *usage;
+	const char *aname;
+	const char *usage;
 } usage_array[] = {
 #include "applets.h"
 };
diff --git a/archival/lzop.c b/archival/lzop.c
index 094e78cf9..62455c313 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -401,7 +401,7 @@ struct globals {
 #define INIT_G() do { } while (0)
 //#define G (*ptr_to_globals)
 //#define INIT_G() do {
-//        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
+//	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
 //} while (0)
 
 
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
index b9aab440a..7d37d232d 100644
--- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
@@ -155,8 +155,8 @@ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
 blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
 					struct ext2_inode *inode)
 {
-       return inode->i_blocks -
-	      (inode->i_file_acl ? fs->blocksize >> 9 : 0);
+	return inode->i_blocks -
+		(inode->i_file_acl ? fs->blocksize >> 9 : 0);
 }
 
 
diff --git a/editors/sed.c b/editors/sed.c
index b91acfb7f..d3555243f 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -124,7 +124,7 @@ struct globals {
 } FIX_ALIASING;
 #define G (*(struct globals*)&bb_common_bufsiz1)
 struct BUG_G_too_big {
-        char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+	char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
 };
 #define INIT_G() do { \
 	G.sed_cmd_tail = &G.sed_cmd_head; \
diff --git a/libbb/crc32.c b/libbb/crc32.c
index c63bf0772..ac9836cc9 100644
--- a/libbb/crc32.c
+++ b/libbb/crc32.c
@@ -59,7 +59,7 @@ uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned l
 	const void *end = (uint8_t*)buf + len;
 
 	while (buf != end) {
-                val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
+		val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
 		buf = (uint8_t*)buf + 1;
 	}
 	return val;
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index abd412043..f3f1cfcba 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -80,9 +80,9 @@ const char *applet_long_options
         This struct allows you to define long options:
 
         static const char applet_longopts[] ALIGN1 =
-		//"name\0" has_arg val
-		"verbose\0" No_argument "v"
-		;
+                //"name\0" has_arg val
+                "verbose\0" No_argument "v"
+                ;
         applet_long_options = applet_longopts;
 
         The last member of struct option (val) typically is set to
@@ -226,7 +226,7 @@ Special characters:
         if specified together.  In this case you must set
         opt_complementary = "b--cf:c--bf:f--bc".  If two of the
         mutually exclusive options are found, getopt32 will call
-	bb_show_usage() and die.
+        bb_show_usage() and die.
 
  "x--x" Variation of the above, it means that -x option should occur
         at most once.
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 34f72c465..3f20c8e81 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -334,7 +334,7 @@ static void termios_final(void)
 	 * IMAXBEL Echo BEL on input line too long
 	 * IUTF8   Appears to affect tty's idea of char widths,
 	 *         observed to improve backspacing through Unicode chars
-         */
+	 */
 
 	/* line buffered input (NL or EOL or EOF chars end a line);
 	 * recognize INT/QUIT/SUSP chars;
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index 8d2ccc562..0d28da7ea 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -170,7 +170,7 @@ struct globals {
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define INIT_G() do { } while (0)
 struct BUG_G_too_big {
-        char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+	char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
 };
 
 
diff --git a/networking/httpd_ssi.c b/networking/httpd_ssi.c
index 87f43fcfa..cfe64eb46 100644
--- a/networking/httpd_ssi.c
+++ b/networking/httpd_ssi.c
@@ -52,9 +52,9 @@ httpd_ssi.c -o httpd_ssi
 
 static char* skip_whitespace(char *s)
 {
-        while (*s == ' ' || *s == '\t') ++s;
+	while (*s == ' ' || *s == '\t') ++s;
 
-        return s;
+	return s;
 }
 
 static char line[64 * 1024];
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 8fe529edb..3ed05ba29 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -882,7 +882,7 @@ fit(peer_t *p, double rd)
 //	/* Do we have a loop? */
 //	if (p->refid == p->dstaddr || p->refid == s.refid)
 //		return 0;
-        return 1;
+	return 1;
 }
 static peer_t*
 select_and_cluster(void)
diff --git a/procps/pstree.c b/procps/pstree.c
index ddf5dba59..4cd8cb458 100644
--- a/procps/pstree.c
+++ b/procps/pstree.c
@@ -76,7 +76,7 @@ struct globals {
 };
 #define G (*ptr_to_globals)
 #define INIT_G() do { \
-        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 } while (0)
 
 
diff --git a/shell/shell_common.c b/shell/shell_common.c
index e9effd2d0..f02ed81ea 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -368,9 +368,9 @@ shell_builtin_ulimit(char **argv)
 #endif
 	/* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
 
-        argc = 1;
-        while (argv[argc])
-                argc++;
+	argc = 1;
+	while (argv[argc])
+		argc++;
 
 	opts = 0;
 	while (1) {
diff --git a/util-linux/flock.c b/util-linux/flock.c
index be3d552fa..77fe1f809 100644
--- a/util-linux/flock.c
+++ b/util-linux/flock.c
@@ -19,7 +19,7 @@ int flock_main(int argc UNUSED_PARAM, char **argv)
 	};
 
 #if ENABLE_LONG_OPTS
-        static const char getopt_longopts[] ALIGN1 =
+	static const char getopt_longopts[] ALIGN1 =
 		"shared\0"      No_argument       "s"
 		"exclusive\0"   No_argument       "x"
 		"unlock\0"      No_argument       "u"
-- 
cgit v1.2.3-55-g6feb


From c5d0f15dbd8087f60b377fa9fc18d08698429189 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 3 Feb 2011 14:14:09 +0100
Subject: libbb: spawn should remove child which failed to exec

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/vfork_daemon_rexec.c | 1 +
 1 file changed, 1 insertion(+)

(limited to 'libbb')

diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index af938bed3..a75eafbd3 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -52,6 +52,7 @@ pid_t FAST_FUNC spawn(char **argv)
 	 * Interested party can wait on pid and learn exit code.
 	 * If 111 - then it (most probably) failed to exec */
 	if (failed) {
+		safe_waitpid(pid, NULL, 0); /* prevent zombie */
 		errno = failed;
 		return -1;
 	}
-- 
cgit v1.2.3-55-g6feb


From 66c5b12dbf85142eea257ba6047191d7c0ee43f3 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Tue, 8 Feb 2011 05:07:02 +0100
Subject: ash: fix TMOUT not restoring tty attributes

function                                             old     new   delta
pgetc                                                420     500     +80
readtoken1                                          3202    3239     +37
read_line_input                                     3316    3337     +21
udhcpc_main                                         2610    2630     +20
file_get                                             266     272      +6
expandarg                                            958     963      +5
localcmd                                             257     259      +2
addLines                                              85      87      +2
read_line                                             94      95      +1
ed_main                                             2540    2541      +1
timed_out                                              1       -      -1
lineedit_read_key                                    256     255      -1
alrm_sighandler                                       44       -     -44
cmdloop                                              539     434    -105
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 10/2 up/down: 175/-151)          Total: 24 bytes
   text    data     bss     dec     hex filename
 887379     936   17200  905515   dd12b busybox_old
 887411     936   17192  905539   dd143 busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 editors/ed.c       |  6 ++---
 include/libbb.h    |  5 ++--
 libbb/lineedit.c   | 12 ++++-----
 shell/ash.c        | 73 ++++++++++++++++++++----------------------------------
 shell/hush.c       |  2 +-
 util-linux/fdisk.c |  2 +-
 6 files changed, 39 insertions(+), 61 deletions(-)

(limited to 'libbb')

diff --git a/editors/ed.c b/editors/ed.c
index 859668406..b1b6a8d27 100644
--- a/editors/ed.c
+++ b/editors/ed.c
@@ -129,7 +129,7 @@ static void doCommands(void)
 		 * 0  on ctrl-C,
 		 * >0 length of input string, including terminating '\n'
 		 */
-		len = read_line_input(": ", buf, sizeof(buf), NULL);
+		len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1);
 		if (len <= 0)
 			return;
 		endbuf = &buf[len - 1];
@@ -227,7 +227,7 @@ static void doCommands(void)
 			}
 			if (!dirty)
 				return;
-			len = read_line_input("Really quit? ", buf, 16, NULL);
+			len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1);
 			/* read error/EOF - no way to continue */
 			if (len < 0)
 				return;
@@ -541,7 +541,7 @@ static void addLines(int num)
 		 * 0  on ctrl-C,
 		 * >0 length of input string, including terminating '\n'
 		 */
-		len = read_line_input("", buf, sizeof(buf), NULL);
+		len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1);
 		if (len <= 0) {
 			/* Previously, ctrl-C was exiting to shell.
 			 * Now we exit to ed prompt. Is in important? */
diff --git a/include/libbb.h b/include/libbb.h
index dd82e9754..78b390611 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1403,12 +1403,11 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC;
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-/* NB: ash has timeout code which can be moved into read_line_input, if needed */
-int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state) FAST_FUNC;
+int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
 #else
 #define MAX_HISTORY 0
 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
-#define read_line_input(prompt, command, maxsize, state) \
+#define read_line_input(state, prompt, command, maxsize, timeout) \
 	read_line_input(prompt, command, maxsize)
 #endif
 
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 5dd835cca..afd28b75c 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1809,10 +1809,9 @@ static void win_changed(int nsig)
 	errno = sv_errno;
 }
 
-static int lineedit_read_key(char *read_key_buffer)
+static int lineedit_read_key(char *read_key_buffer, int timeout)
 {
 	int64_t ic;
-	int timeout = -1;
 #if ENABLE_UNICODE_SUPPORT
 	char unicode_buf[MB_CUR_MAX + 1];
 	int unicode_idx = 0;
@@ -1917,7 +1916,7 @@ static int isrtl_str(void)
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
+int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout)
 {
 	int len;
 #if ENABLE_FEATURE_TAB_COMPLETION
@@ -1991,7 +1990,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
 	new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
 	tcsetattr_stdin_TCSANOW(&new_settings);
 
-	/* Now initialize things */
 	previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
 	win_changed(0); /* do initial resizing */
 #if ENABLE_USERNAME_OR_HOMEDIR
@@ -2033,7 +2031,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
 		int32_t ic, ic_raw;
 
 		fflush_all();
-		ic = ic_raw = lineedit_read_key(read_key_buffer);
+		ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
 
 #if ENABLE_FEATURE_EDITING_VI
 		newdelflag = 1;
@@ -2194,7 +2192,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
 		case 'd'|VI_CMDMODE_BIT: {
 			int nc, sc;
 
-			ic = lineedit_read_key(read_key_buffer);
+			ic = lineedit_read_key(read_key_buffer, timeout);
 			if (errno) /* error */
 				goto return_error_indicator;
 			if (ic == ic_raw) { /* "cc", "dd" */
@@ -2258,7 +2256,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
 			break;
 		case 'r'|VI_CMDMODE_BIT:
 //FIXME: unicode case?
-			ic = lineedit_read_key(read_key_buffer);
+			ic = lineedit_read_key(read_key_buffer, timeout);
 			if (errno) /* error */
 				goto return_error_indicator;
 			if (ic < ' ' || ic > 255) {
diff --git a/shell/ash.c b/shell/ash.c
index bdc64790c..aaf21cd6f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -102,8 +102,7 @@
 //config:	default n
 //config:	depends on ASH
 //config:	help
-//config:	  Enables bash-like auto-logout after "$TMOUT" seconds
-//config:	  of idle time.
+//config:	  Enables bash-like auto-logout after $TMOUT seconds of idle time.
 //config:
 //config:config ASH_JOB_CONTROL
 //config:	bool "Job control"
@@ -408,6 +407,9 @@ static const char *var_end(const char *var)
 
 
 /* ============ Interrupts / exceptions */
+
+static void exitshell(void) NORETURN;
+
 /*
  * These macros allow the user to suspend the handling of interrupt signals
  * over a period of time.  This is similar to SIGHOLD or to sigblock, but
@@ -9573,10 +9575,21 @@ preadfd(void)
 	if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
 		nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
 	else {
+		int timeout = -1;
+# if ENABLE_ASH_IDLE_TIMEOUT
+		if (iflag) {
+			const char *tmout_var = lookupvar("TMOUT");
+			if (tmout_var) {
+				timeout = atoi(tmout_var) * 1000;
+				if (timeout <= 0)
+					timeout = -1;
+			}
+		}
+# endif
 # if ENABLE_FEATURE_TAB_COMPLETION
 		line_input_state->path_lookup = pathval();
 # endif
-		nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
+		nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
 		if (nr == 0) {
 			/* Ctrl+C pressed */
 			if (trap[SIGINT]) {
@@ -9587,9 +9600,17 @@ preadfd(void)
 			}
 			goto retry;
 		}
-		if (nr < 0 && errno == 0) {
-			/* Ctrl+D pressed */
-			nr = 0;
+		if (nr < 0) {
+			if (errno == 0) {
+				/* Ctrl+D pressed */
+				nr = 0;
+			}
+# if ENABLE_ASH_IDLE_TIMEOUT
+			else if (errno == EAGAIN && timeout > 0) {
+				printf("\007timed out waiting for input: auto-logout\n");
+				exitshell();
+			}
+# endif
 		}
 	}
 #else
@@ -12056,23 +12077,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv)
 	return exitstatus;
 }
 
-#if ENABLE_ASH_IDLE_TIMEOUT
-static smallint timed_out;
-
-static void alrm_sighandler(int sig UNUSED_PARAM)
-{
-	/* Close stdin, making interactive command reading stop.
-	 * Otherwise, timeout doesn't trigger until <Enter> is pressed.
-	 */
-	int sv = errno;
-	close(0);
-	open("/dev/null", O_RDONLY);
-	errno = sv;
-
-	timed_out = 1;
-}
-#endif
-
 /*
  * Read and execute commands.
  * "Top" is nonzero for the top level command loop;
@@ -12089,20 +12093,6 @@ cmdloop(int top)
 	TRACE(("cmdloop(%d) called\n", top));
 	for (;;) {
 		int skip;
-#if ENABLE_ASH_IDLE_TIMEOUT
-		int tmout_seconds = 0;
-
-		if (top && iflag) {
-			const char *tmout_var = lookupvar("TMOUT");
-			if (tmout_var) {
-				tmout_seconds = atoi(tmout_var);
-				if (tmout_seconds > 0) {
-					signal(SIGALRM, alrm_sighandler);
-					alarm(tmout_seconds);
-				}
-			}
-		}
-#endif
 
 		setstackmark(&smark);
 #if JOBS
@@ -12115,14 +12105,6 @@ cmdloop(int top)
 			chkmail();
 		}
 		n = parsecmd(inter);
-#if ENABLE_ASH_IDLE_TIMEOUT
-		if (timed_out) {
-			printf("\007timed out waiting for input: auto-logout\n");
-			break;
-		}
-		if (tmout_seconds > 0)
-			alarm(0);
-#endif
 #if DEBUG
 		if (DEBUG > 2 && debug && (n != NODE_EOF))
 			showtree(n);
@@ -12850,7 +12832,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
 /*
  * Called to exit the shell.
  */
-static void exitshell(void) NORETURN;
 static void
 exitshell(void)
 {
diff --git a/shell/hush.c b/shell/hush.c
index e857e7464..00ef361cd 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1902,7 +1902,7 @@ static void get_user_input(struct in_str *i)
 		G.flag_SIGINT = 0;
 		/* buglet: SIGINT will not make new prompt to appear _at once_,
 		 * only after <Enter>. (^C will work) */
-		r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state);
+		r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
 		/* catch *SIGINT* etc (^C is handled by read_line_input) */
 		check_and_run_traps(0);
 	} while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index 02785ab85..0b93c22cc 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -548,7 +548,7 @@ read_line(const char *prompt)
 {
 	int sz;
 
-	sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
+	sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
 	if (sz <= 0)
 		exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
 
-- 
cgit v1.2.3-55-g6feb


From df4e16c9af6d6270d91d17d31c6098ecb259e5cc Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 10 Feb 2011 06:29:06 +0100
Subject: wget: use FEATURE_COPYBUF_KB-sized buffer. Much faster for local
 transfers

function                                             old     new   delta
base64enc                                              -      53     +53
gethdr                                               190     200     +10
ftpcmd                                               129     133      +4
progress_meter                                       160     122     -38
retrieve_file_data                                   431     392     -39
base64enc_512                                         46       -     -46
wget_main                                           2456    2220    -236
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 2/3 up/down: 67/-359)          Total: -292 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/Config.src  |   2 +-
 networking/wget.c | 121 +++++++++++++++++++++++++++---------------------------
 2 files changed, 62 insertions(+), 61 deletions(-)

(limited to 'libbb')

diff --git a/libbb/Config.src b/libbb/Config.src
index dfb897d5f..18bdc5151 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -156,7 +156,7 @@ config FEATURE_COPYBUF_KB
 	range 1 1024
 	default 4
 	help
-	  Size of buffer used by cp, mv, install etc.
+	  Size of buffer used by cp, mv, install, wget etc.
 	  Buffers which are 4 kb or less will be allocated on stack.
 	  Bigger buffers will be allocated with mmap, with fallback to 4 kb
 	  stack buffer if mmap fails.
diff --git a/networking/wget.c b/networking/wget.c
index 0db9b3365..8e636bd39 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -35,12 +35,16 @@ struct globals {
 #endif
 	smallint chunked;         /* chunked transfer encoding */
 	smallint got_clen;        /* got content-length: from server  */
+	/* Local downloads do benefit from big buffer.
+	 * With 512 byte buffer, it was measured to be
+	 * an order of magnitude slower than with big one.
+	 */
+	uint64_t just_to_align_next_member;
+	char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024];
 } FIX_ALIASING;
-#define G (*(struct globals*)&bb_common_bufsiz1)
-struct BUG_G_too_big {
-	char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
-};
+#define G (*ptr_to_globals)
 #define INIT_G() do { \
+        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 	IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \
 } while (0)
 
@@ -158,14 +162,14 @@ static char *safe_fgets(char *s, int size, FILE *stream)
 }
 
 #if ENABLE_FEATURE_WGET_AUTHENTICATION
-/* Base64-encode character string. buf is assumed to be char buf[512]. */
-static char *base64enc_512(char buf[512], const char *str)
+/* Base64-encode character string. */
+static char *base64enc(const char *str)
 {
 	unsigned len = strlen(str);
-	if (len > 512/4*3 - 10) /* paranoia */
-		len = 512/4*3 - 10;
-	bb_uuencode(buf, str, len, bb_uuenc_tbl_base64);
-	return buf;
+	if (len > sizeof(G.wget_buf)/4*3 - 10) /* paranoia */
+		len = sizeof(G.wget_buf)/4*3 - 10;
+	bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64);
+	return G.wget_buf;
 }
 #endif
 
@@ -191,7 +195,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
 	return fp;
 }
 
-static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
+static int ftpcmd(const char *s1, const char *s2, FILE *fp)
 {
 	int result;
 	if (s1) {
@@ -203,18 +207,18 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
 	do {
 		char *buf_ptr;
 
-		if (fgets(buf, 510, fp) == NULL) {
+		if (fgets(G.wget_buf, sizeof(G.wget_buf)-2, fp) == NULL) {
 			bb_perror_msg_and_die("error getting response");
 		}
-		buf_ptr = strstr(buf, "\r\n");
+		buf_ptr = strstr(G.wget_buf, "\r\n");
 		if (buf_ptr) {
 			*buf_ptr = '\0';
 		}
-	} while (!isdigit(buf[0]) || buf[3] != ' ');
+	} while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
 
-	buf[3] = '\0';
-	result = xatoi_positive(buf);
-	buf[3] = ' ';
+	G.wget_buf[3] = '\0';
+	result = xatoi_positive(G.wget_buf);
+	G.wget_buf[3] = ' ';
 	return result;
 }
 
@@ -278,7 +282,7 @@ static void parse_url(char *src_url, struct host_info *h)
 	sp = h->host;
 }
 
-static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
+static char *gethdr(FILE *fp /*, int *istrunc*/)
 {
 	char *s, *hdrval;
 	int c;
@@ -286,24 +290,24 @@ static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
 	/* *istrunc = 0; */
 
 	/* retrieve header line */
-	if (fgets(buf, bufsiz, fp) == NULL)
+	if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
 		return NULL;
 
 	/* see if we are at the end of the headers */
-	for (s = buf; *s == '\r'; ++s)
+	for (s = G.wget_buf; *s == '\r'; ++s)
 		continue;
 	if (*s == '\n')
 		return NULL;
 
 	/* convert the header name to lower case */
-	for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) {
+	for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) {
 		/* tolower for "A-Z", no-op for "0-9a-z-." */
 		*s = (*s | 0x20);
 	}
 
 	/* verify we are at the end of the header name */
 	if (*s != ':')
-		bb_error_msg_and_die("bad header line: %s", sanitize_string(buf));
+		bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf));
 
 	/* locate the start of the header value */
 	*s++ = '\0';
@@ -366,7 +370,6 @@ static char *URL_escape(const char *str)
 
 static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
 {
-	char buf[512];
 	FILE *sfp;
 	char *str;
 	int port;
@@ -375,8 +378,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
 		target->user = xstrdup("anonymous:busybox@");
 
 	sfp = open_socket(lsa);
-	if (ftpcmd(NULL, NULL, sfp, buf) != 220)
-		bb_error_msg_and_die("%s", sanitize_string(buf+4));
+	if (ftpcmd(NULL, NULL, sfp) != 220)
+		bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4));
 
 	/*
 	 * Splitting username:password pair,
@@ -385,24 +388,24 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
 	str = strchr(target->user, ':');
 	if (str)
 		*str++ = '\0';
-	switch (ftpcmd("USER ", target->user, sfp, buf)) {
+	switch (ftpcmd("USER ", target->user, sfp)) {
 	case 230:
 		break;
 	case 331:
-		if (ftpcmd("PASS ", str, sfp, buf) == 230)
+		if (ftpcmd("PASS ", str, sfp) == 230)
 			break;
 		/* fall through (failed login) */
 	default:
-		bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4));
+		bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4));
 	}
 
-	ftpcmd("TYPE I", NULL, sfp, buf);
+	ftpcmd("TYPE I", NULL, sfp);
 
 	/*
 	 * Querying file size
 	 */
-	if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) {
-		G.content_len = BB_STRTOOFF(buf+4, NULL, 10);
+	if (ftpcmd("SIZE ", target->path, sfp) == 213) {
+		G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
 		if (G.content_len < 0 || errno) {
 			bb_error_msg_and_die("SIZE value is garbage");
 		}
@@ -412,20 +415,20 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
 	/*
 	 * Entering passive mode
 	 */
-	if (ftpcmd("PASV", NULL, sfp, buf) != 227) {
+	if (ftpcmd("PASV", NULL, sfp) != 227) {
  pasv_error:
-		bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf));
+		bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf));
 	}
 	// Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
 	// Server's IP is N1.N2.N3.N4 (we ignore it)
 	// Server's port for data connection is P1*256+P2
-	str = strrchr(buf, ')');
+	str = strrchr(G.wget_buf, ')');
 	if (str) str[0] = '\0';
-	str = strrchr(buf, ',');
+	str = strrchr(G.wget_buf, ',');
 	if (!str) goto pasv_error;
 	port = xatou_range(str+1, 0, 255);
 	*str = '\0';
-	str = strrchr(buf, ',');
+	str = strrchr(G.wget_buf, ',');
 	if (!str) goto pasv_error;
 	port += xatou_range(str+1, 0, 255) * 256;
 	set_nport(lsa, htons(port));
@@ -433,20 +436,19 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
 	*dfpp = open_socket(lsa);
 
 	if (G.beg_range) {
-		sprintf(buf, "REST %"OFF_FMT"u", G.beg_range);
-		if (ftpcmd(buf, NULL, sfp, buf) == 350)
+		sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
+		if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
 			G.content_len -= G.beg_range;
 	}
 
-	if (ftpcmd("RETR ", target->path, sfp, buf) > 150)
-		bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf));
+	if (ftpcmd("RETR ", target->path, sfp) > 150)
+		bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf));
 
 	return sfp;
 }
 
 static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 {
-	char buf[512];
 #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
 # if ENABLE_FEATURE_WGET_TIMEOUT
 	unsigned second_cnt;
@@ -468,9 +470,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 			int n;
 			unsigned rdsz;
 
-			rdsz = sizeof(buf);
+			rdsz = sizeof(G.wget_buf);
 			if (G.got_clen) {
-				if (G.content_len < (off_t)sizeof(buf)) {
+				if (G.content_len < (off_t)sizeof(G.wget_buf)) {
 					if ((int)G.content_len <= 0)
 						break;
 					rdsz = (unsigned)G.content_len;
@@ -493,7 +495,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 				progress_meter(PROGRESS_BUMP);
 			}
 #endif
-			n = safe_fread(buf, rdsz, dfp);
+			n = safe_fread(G.wget_buf, rdsz, dfp);
 			if (n <= 0) {
 				if (ferror(dfp)) {
 					/* perror will not work: ferror doesn't set errno */
@@ -501,7 +503,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 				}
 				break;
 			}
-			xwrite(output_fd, buf, n);
+			xwrite(output_fd, G.wget_buf, n);
 #if ENABLE_FEATURE_WGET_STATUSBAR
 			G.transferred += n;
 			progress_meter(PROGRESS_BUMP);
@@ -513,10 +515,10 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 		if (!G.chunked)
 			break;
 
-		safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
+		safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */
  get_clen:
-		safe_fgets(buf, sizeof(buf), dfp);
-		G.content_len = STRTOOFF(buf, NULL, 16);
+		safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp);
+		G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
 		/* FIXME: error check? */
 		if (G.content_len == 0)
 			break; /* all done! */
@@ -529,7 +531,6 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int wget_main(int argc UNUSED_PARAM, char **argv)
 {
-	char buf[512];
 	struct host_info server, target;
 	len_and_sockaddr *lsa;
 	unsigned opt;
@@ -709,11 +710,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 #if ENABLE_FEATURE_WGET_AUTHENTICATION
 		if (target.user) {
 			fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
-				base64enc_512(buf, target.user));
+				base64enc(target.user));
 		}
 		if (use_proxy && server.user) {
 			fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
-				base64enc_512(buf, server.user));
+				base64enc(server.user));
 		}
 #endif
 
@@ -743,10 +744,10 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 		 * Retrieve HTTP response line and check for "200" status code.
 		 */
  read_response:
-		if (fgets(buf, sizeof(buf), sfp) == NULL)
+		if (fgets(G.wget_buf, sizeof(G.wget_buf), sfp) == NULL)
 			bb_error_msg_and_die("no response from server");
 
-		str = buf;
+		str = G.wget_buf;
 		str = skip_non_whitespace(str);
 		str = skip_whitespace(str);
 		// FIXME: no error check
@@ -755,7 +756,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 		switch (status) {
 		case 0:
 		case 100:
-			while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL)
+			while (gethdr(sfp /*, &n*/) != NULL)
 				/* eat all remaining headers */;
 			goto read_response;
 		case 200:
@@ -795,13 +796,13 @@ However, in real world it was observed that some web servers
 				break;
 			/* fall through */
 		default:
-			bb_error_msg_and_die("server returned error: %s", sanitize_string(buf));
+			bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf));
 		}
 
 		/*
 		 * Retrieve HTTP headers.
 		 */
-		while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) {
+		while ((str = gethdr(sfp /*, &n*/)) != NULL) {
 			/* gethdr converted "FOO:" string to lowercase */
 			smalluint key;
 			/* strip trailing whitespace */
@@ -810,7 +811,7 @@ However, in real world it was observed that some web servers
 				*s = '\0';
 				s--;
 			}
-			key = index_in_strings(keywords, buf) + 1;
+			key = index_in_strings(keywords, G.wget_buf) + 1;
 			if (key == KEY_content_length) {
 				G.content_len = BB_STRTOOFF(str, NULL, 10);
 				if (G.content_len < 0 || errno) {
@@ -881,9 +882,9 @@ However, in real world it was observed that some web servers
 	if (dfp != sfp) {
 		/* It's ftp. Close it properly */
 		fclose(dfp);
-		if (ftpcmd(NULL, NULL, sfp, buf) != 226)
-			bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4));
-		/* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */
+		if (ftpcmd(NULL, NULL, sfp) != 226)
+			bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4));
+		/* ftpcmd("QUIT", NULL, sfp); - why bother? */
 	}
 
 	return EXIT_SUCCESS;
-- 
cgit v1.2.3-55-g6feb


From dee0fc9da1b53efc4c5e0596428dda556995bc26 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 10 Feb 2011 10:01:49 +0100
Subject: save 10 bytes on strings

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/messages.c  | 2 +-
 networking/wget.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'libbb')

diff --git a/libbb/messages.c b/libbb/messages.c
index 2acbc3bca..fad82c9da 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -22,7 +22,7 @@
 const char bb_banner[] ALIGN1 = BANNER;
 
 
-const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted";
+const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory";
 const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'";
 const char bb_msg_unknown[] ALIGN1 = "(unknown)";
 const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket";
diff --git a/networking/wget.c b/networking/wget.c
index 8028f1230..74d90040f 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -192,7 +192,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
 	/* hopefully it understands what ESPIPE means... */
 	fp = fdopen(xconnect_stream(lsa), "r+");
 	if (fp == NULL)
-		bb_perror_msg_and_die("fdopen");
+		bb_perror_msg_and_die(bb_msg_memory_exhausted);
 
 	return fp;
 }
-- 
cgit v1.2.3-55-g6feb


From 805aa9fec923109e90c87eda2f116ee2fa5fe962 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 10 Feb 2011 14:25:51 +0100
Subject: progress bar: better overflow protection; more precise bar

function                                             old     new   delta
bb_progress_update                                   639     749    +110

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/libbb.h  |  5 +++--
 libbb/progress.c | 54 +++++++++++++++++++++++++++++++-----------------------
 2 files changed, 34 insertions(+), 25 deletions(-)

(limited to 'libbb')

diff --git a/include/libbb.h b/include/libbb.h
index d390e6840..c0178801f 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1592,8 +1592,9 @@ typedef struct bb_progress_t {
 
 void bb_progress_init(bb_progress_t *p) FAST_FUNC;
 void bb_progress_update(bb_progress_t *p, const char *curfile,
-			off_t beg_range, off_t transferred,
-			off_t totalsize) FAST_FUNC;
+			uoff_t beg_range,
+			uoff_t transferred,
+			uoff_t totalsize) FAST_FUNC;
 
 extern const char *applet_name;
 
diff --git a/libbb/progress.c b/libbb/progress.c
index 40608b047..ced04ac32 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -62,35 +62,45 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p)
 
 void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		const char *curfile,
-		off_t beg_range,
-		off_t transferred,
-		off_t totalsize)
+		uoff_t beg_range,
+		uoff_t transferred,
+		uoff_t totalsize)
 {
 	uoff_t beg_and_transferred;
 	unsigned since_last_update, elapsed;
 	unsigned ratio;
-	int barlength, i;
+	int barlength;
+	int kiloscale;
 
 	/* totalsize == 0 if it is unknown */
 
+	beg_and_transferred = beg_range + transferred;
+
 	elapsed = monotonic_sec();
 	since_last_update = elapsed - p->lastupdate_sec;
 	/* Do not update on every call
 	 * (we can be called on every network read!) */
-	if (since_last_update == 0 && !totalsize)
+	if (since_last_update == 0 && beg_and_transferred < totalsize)
 		return;
 
-	beg_and_transferred = beg_range + transferred;
-	ratio = 100;
-	if (beg_and_transferred < totalsize) {
-		/* Do not update on every call
-		 * (we can be called on every network read!) */
-		if (since_last_update == 0)
-			return;
-		/* long long helps to have it working even if !LFS */
-		ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize;
+	/* Scale sizes down if they are close to overflowing.
+	 * If off_t is only 32 bits, this allows calculations
+	 * like (100 * transferred / totalsize) without risking overflow.
+	 * Introduced error is < 0.1%
+	 */
+	kiloscale = 0;
+	if (totalsize >= (1 << 20)) {
+		totalsize >>= 10;
+		beg_range >>= 10;
+		transferred >>= 10;
+		beg_and_transferred >>= 10;
+		kiloscale++;
 	}
 
+	if (beg_and_transferred >= totalsize)
+		beg_and_transferred = totalsize;
+
+	ratio = 100 * beg_and_transferred / totalsize;
 #if ENABLE_UNICODE_SUPPORT
 	init_unicode();
 	{
@@ -106,21 +116,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	if (barlength > 0) {
 		/* god bless gcc for variable arrays :) */
 		char buf[barlength + 1];
-		unsigned stars = (unsigned)barlength * ratio / (unsigned)100;
+		unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
 		memset(buf, ' ', barlength);
 		buf[barlength] = '\0';
 		memset(buf, '*', stars);
 		fprintf(stderr, "|%s|", buf);
 	}
 
-	i = 0;
 	while (beg_and_transferred >= 100000) {
-		i++;
+		kiloscale++;
 		beg_and_transferred >>= 10;
 	}
 	/* see http://en.wikipedia.org/wiki/Tera */
-	fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]);
-#define beg_and_transferred dont_use_beg_and_transferred_below
+	fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
+#define beg_and_transferred dont_use_beg_and_transferred_below()
 
 	if (transferred > p->lastsize) {
 		p->lastupdate_sec = elapsed;
@@ -137,13 +146,12 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	if (since_last_update >= STALLTIME) {
 		fprintf(stderr, " - stalled -");
 	} else {
-		off_t to_download = totalsize - beg_range;
-		if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) {
+		uoff_t to_download = totalsize - beg_range;
+		if (!totalsize || (int)elapsed <= 0 || transferred > to_download) {
 			fprintf(stderr, "--:--:-- ETA");
 		} else {
 			/* to_download / (transferred/elapsed) - elapsed: */
-			/* (long long helps to have working ETA even if !LFS) */
-			unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed;
+			unsigned eta = to_download * elapsed / transferred - elapsed;
 			unsigned secs = eta % 3600;
 			unsigned hours = eta / 3600;
 			fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60);
-- 
cgit v1.2.3-55-g6feb


From f836f01cc3eb39e5e4c7186f50b456b57fae2010 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 10 Feb 2011 23:02:28 +0100
Subject: wget: shrink progress meter code; strink wget and add debug logging

function                                             old     new   delta
fgets_and_trim                                         -      73     +73
retrieve_file_data                                   367     349     -18
bb_progress_update                                   723     699     -24
wget_main                                           2220    2190     -30
ftpcmd                                               133      87     -46
gethdr                                               200     153     -47
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/5 up/down: 73/-165)           Total: -92 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/progress.c  | 95 +++++++++++++++++++++++++++++++++++++------------------
 networking/wget.c | 74 +++++++++++++++++++++++--------------------
 2 files changed, 105 insertions(+), 64 deletions(-)

(limited to 'libbb')

diff --git a/libbb/progress.c b/libbb/progress.c
index ced04ac32..a490b8390 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -60,9 +60,16 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p)
 	p->inited = 1;
 }
 
+/* File already had beg_size bytes.
+ * Then we started downloading.
+ * We downloaded "transferred" bytes so far.
+ * Download is expected to stop when total size (beg_size + transferred)
+ * will be "totalsize" bytes.
+ * If totalsize == 0, then it is unknown.
+ */
 void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		const char *curfile,
-		uoff_t beg_range,
+		uoff_t beg_size,
 		uoff_t transferred,
 		uoff_t totalsize)
 {
@@ -72,32 +79,53 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	int barlength;
 	int kiloscale;
 
-	/* totalsize == 0 if it is unknown */
-
-	beg_and_transferred = beg_range + transferred;
+	beg_and_transferred = beg_size + transferred;
 
 	elapsed = monotonic_sec();
 	since_last_update = elapsed - p->lastupdate_sec;
-	/* Do not update on every call
-	 * (we can be called on every network read!) */
+	/*
+	 * Do not update on every call
+	 * (we can be called on every network read!)
+	 */
 	if (since_last_update == 0 && beg_and_transferred < totalsize)
 		return;
 
-	/* Scale sizes down if they are close to overflowing.
-	 * If off_t is only 32 bits, this allows calculations
-	 * like (100 * transferred / totalsize) without risking overflow.
-	 * Introduced error is < 0.1%
-	 */
 	kiloscale = 0;
-	if (totalsize >= (1 << 20)) {
-		totalsize >>= 10;
-		beg_range >>= 10;
-		transferred >>= 10;
-		beg_and_transferred >>= 10;
-		kiloscale++;
+	/*
+	 * Scale sizes down if they are close to overflowing.
+	 * This allows calculations like (100 * transferred / totalsize)
+	 * without risking overflow: we guarantee 10 highest bits to be 0.
+	 * Introduced error is less than 1 / 2^12 ~= 0.025%
+	 */
+	if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) {
+		/*
+		 * 64-bit CPU || small off_t: in either case,
+		 * >> is cheap, single-word operation.
+		 * ... || strange off_t: also use this code (it is safe,
+		 * even if suboptimal), because 32/64 optimized one
+		 * works only for 64-bit off_t.
+		 */
+		if (totalsize >= (1 << 22)) {
+			totalsize >>= 10;
+			beg_size >>= 10;
+			transferred >>= 10;
+			beg_and_transferred >>= 10;
+			kiloscale = 1;
+		}
+	} else {
+		/* 32-bit CPU and 64-bit off_t.
+		 * Pick a shift (40 bits) which is easier to do on 32-bit CPU.
+		 */
+		if (totalsize >= (uoff_t)(1ULL << 54)) {
+			totalsize = (uint32_t)(totalsize >> 32) >> 8;
+			beg_size = (uint32_t)(beg_size >> 32) >> 8;
+			transferred = (uint32_t)(transferred >> 32) >> 8;
+			beg_and_transferred = (uint32_t)(beg_and_transferred >> 32) >> 8;
+			kiloscale = 4;
+		}
 	}
 
-	if (beg_and_transferred >= totalsize)
+	if (beg_and_transferred > totalsize)
 		beg_and_transferred = totalsize;
 
 	ratio = 100 * beg_and_transferred / totalsize;
@@ -124,14 +152,14 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	}
 
 	while (beg_and_transferred >= 100000) {
-		kiloscale++;
 		beg_and_transferred >>= 10;
+		kiloscale++;
 	}
 	/* see http://en.wikipedia.org/wiki/Tera */
 	fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
 #define beg_and_transferred dont_use_beg_and_transferred_below()
 
-	if (transferred > p->lastsize) {
+	if (transferred != p->lastsize) {
 		p->lastupdate_sec = elapsed;
 		p->lastsize = transferred;
 		if (since_last_update >= STALLTIME) {
@@ -141,20 +169,27 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		}
 		since_last_update = 0; /* we are un-stalled now */
 	}
+
 	elapsed -= p->start_sec; /* now it's "elapsed since start" */
 
 	if (since_last_update >= STALLTIME) {
 		fprintf(stderr, " - stalled -");
+	} else if (!totalsize || !transferred || (int)elapsed <= 0) {
+		fprintf(stderr, "--:--:-- ETA");
 	} else {
-		uoff_t to_download = totalsize - beg_range;
-		if (!totalsize || (int)elapsed <= 0 || transferred > to_download) {
-			fprintf(stderr, "--:--:-- ETA");
-		} else {
-			/* to_download / (transferred/elapsed) - elapsed: */
-			unsigned eta = to_download * elapsed / transferred - elapsed;
-			unsigned secs = eta % 3600;
-			unsigned hours = eta / 3600;
-			fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60);
-		}
+		unsigned eta, secs, hours;
+
+		totalsize -= beg_size; /* now it's "total to upload" */
+
+		/* Estimated remaining time =
+		 * estimated_sec_to_dl_totalsize_bytes - elapsed_sec =
+		 * totalsize / average_bytes_sec_so_far - elapsed =
+		 * totalsize / (transferred/elapsed) - elapsed =
+		 * totalsize * elapsed / transferred - elapsed
+		 */
+		eta = totalsize * elapsed / transferred - elapsed;
+		secs = eta % 3600;
+		hours = eta / 3600;
+		fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60);
 	}
 }
diff --git a/networking/wget.c b/networking/wget.c
index 931882fde..d81426e8d 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -10,6 +10,10 @@
  */
 #include "libbb.h"
 
+//#define log_io(...) bb_error_msg(__VA_ARGS__)
+#define log_io(...) ((void)0)
+
+
 struct host_info {
 	// May be used if we ever will want to free() all xstrdup()s...
 	/* char *allocated; */
@@ -197,25 +201,39 @@ static FILE *open_socket(len_and_sockaddr *lsa)
 	return fp;
 }
 
+/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */
+static char fgets_and_trim(FILE *fp)
+{
+	char c;
+	char *buf_ptr;
+
+	if (fgets(G.wget_buf, sizeof(G.wget_buf) - 1, fp) == NULL)
+		bb_perror_msg_and_die("error getting response");
+
+	buf_ptr = strchrnul(G.wget_buf, '\n');
+	c = *buf_ptr;
+	*buf_ptr = '\0';
+	buf_ptr = strchrnul(G.wget_buf, '\r');
+	*buf_ptr = '\0';
+
+	log_io("< %s", G.wget_buf);
+
+	return c;
+}
+
 static int ftpcmd(const char *s1, const char *s2, FILE *fp)
 {
 	int result;
 	if (s1) {
-		if (!s2) s2 = "";
+		if (!s2)
+			s2 = "";
 		fprintf(fp, "%s%s\r\n", s1, s2);
 		fflush(fp);
+		log_io("> %s%s", s1, s2);
 	}
 
 	do {
-		char *buf_ptr;
-
-		if (fgets(G.wget_buf, sizeof(G.wget_buf)-2, fp) == NULL) {
-			bb_perror_msg_and_die("error getting response");
-		}
-		buf_ptr = strstr(G.wget_buf, "\r\n");
-		if (buf_ptr) {
-			*buf_ptr = '\0';
-		}
+		fgets_and_trim(fp);
 	} while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
 
 	G.wget_buf[3] = '\0';
@@ -284,7 +302,7 @@ static void parse_url(char *src_url, struct host_info *h)
 	sp = h->host;
 }
 
-static char *gethdr(FILE *fp /*, int *istrunc*/)
+static char *gethdr(FILE *fp)
 {
 	char *s, *hdrval;
 	int c;
@@ -292,19 +310,16 @@ static char *gethdr(FILE *fp /*, int *istrunc*/)
 	/* *istrunc = 0; */
 
 	/* retrieve header line */
-	if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
-		return NULL;
+	c = fgets_and_trim(fp);
 
-	/* see if we are at the end of the headers */
-	for (s = G.wget_buf; *s == '\r'; ++s)
-		continue;
-	if (*s == '\n')
+	/* end of the headers? */
+	if (G.wget_buf[0] == '\0')
 		return NULL;
 
 	/* convert the header name to lower case */
 	for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) {
 		/* tolower for "A-Z", no-op for "0-9a-z-." */
-		*s = (*s | 0x20);
+		*s |= 0x20;
 	}
 
 	/* verify we are at the end of the header name */
@@ -315,20 +330,12 @@ static char *gethdr(FILE *fp /*, int *istrunc*/)
 	*s++ = '\0';
 	hdrval = skip_whitespace(s);
 
-	/* locate the end of header */
-	while (*s && *s != '\r' && *s != '\n')
-		++s;
-
-	/* end of header found */
-	if (*s) {
-		*s = '\0';
-		return hdrval;
+	if (c != '\n') {
+		/* Rats! The buffer isn't big enough to hold the entire header value */
+		while (c = getc(fp), c != EOF && c != '\n')
+			continue;
 	}
 
-	/* Rats! The buffer isn't big enough to hold the entire header value */
-	while (c = getc(fp), c != EOF && c != '\n')
-		continue;
-	/* *istrunc = 1; */
 	return hdrval;
 }
 
@@ -520,9 +527,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 		if (!G.chunked)
 			break;
 
-		fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */
+		fgets_and_trim(dfp); /* This is a newline */
  get_clen:
-		fgets(G.wget_buf, sizeof(G.wget_buf), dfp);
+		fgets_and_trim(dfp);
 		G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
 		/* FIXME: error check? */
 		if (G.content_len == 0)
@@ -757,8 +764,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 		 * Retrieve HTTP response line and check for "200" status code.
 		 */
  read_response:
-		if (fgets(G.wget_buf, sizeof(G.wget_buf), sfp) == NULL)
-			bb_error_msg_and_die("no response from server");
+		fgets_and_trim(sfp);
 
 		str = G.wget_buf;
 		str = skip_non_whitespace(str);
-- 
cgit v1.2.3-55-g6feb


From 838d4bb0cd0805e1671073627d86baf100af021b Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 10 Feb 2011 23:35:52 +0100
Subject: progress meter: display >999 hours ETA correctly

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/progress.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'libbb')

diff --git a/libbb/progress.c b/libbb/progress.c
index a490b8390..3999e0f38 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -156,7 +156,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		kiloscale++;
 	}
 	/* see http://en.wikipedia.org/wiki/Tera */
-	fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
+	fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
 #define beg_and_transferred dont_use_beg_and_transferred_below()
 
 	if (transferred != p->lastsize) {
@@ -173,9 +173,9 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	elapsed -= p->start_sec; /* now it's "elapsed since start" */
 
 	if (since_last_update >= STALLTIME) {
-		fprintf(stderr, " - stalled -");
+		fprintf(stderr, "  - stalled -");
 	} else if (!totalsize || !transferred || (int)elapsed <= 0) {
-		fprintf(stderr, "--:--:-- ETA");
+		fprintf(stderr, " --:--:-- ETA");
 	} else {
 		unsigned eta, secs, hours;
 
@@ -188,8 +188,10 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		 * totalsize * elapsed / transferred - elapsed
 		 */
 		eta = totalsize * elapsed / transferred - elapsed;
+		if (eta >= 1000*60*60)
+			eta = 1000*60*60 - 1;
 		secs = eta % 3600;
 		hours = eta / 3600;
-		fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60);
+		fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60);
 	}
 }
-- 
cgit v1.2.3-55-g6feb


From e52e67cb512e775fd83ca399cc807c363ba59dcc Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 11 Feb 2011 12:59:11 +0100
Subject: libbb/progress.c: make sure we never get negative ETA

function                                             old     new   delta
bb_progress_update                                   738     733      -5

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 libbb/progress.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

(limited to 'libbb')

diff --git a/libbb/progress.c b/libbb/progress.c
index 3999e0f38..1062e9a0d 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -79,16 +79,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	int barlength;
 	int kiloscale;
 
-	beg_and_transferred = beg_size + transferred;
-
 	elapsed = monotonic_sec();
 	since_last_update = elapsed - p->lastupdate_sec;
-	/*
-	 * Do not update on every call
-	 * (we can be called on every network read!)
-	 */
-	if (since_last_update == 0 && beg_and_transferred < totalsize)
+
+	if (totalsize != 0 && transferred >= totalsize - beg_size) {
+		/* Last call. Do not skip this update */
+		transferred = totalsize - beg_size; /* sanitize just in case */
+	}
+	else if (since_last_update == 0) {
+		/*
+		 * Do not update on every call
+		 * (we can be called on every network read!)
+		 */
 		return;
+	}
 
 	kiloscale = 0;
 	/*
@@ -101,32 +105,29 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		/*
 		 * 64-bit CPU || small off_t: in either case,
 		 * >> is cheap, single-word operation.
-		 * ... || strange off_t: also use this code (it is safe,
-		 * even if suboptimal), because 32/64 optimized one
-		 * works only for 64-bit off_t.
+		 * ... || strange off_t: also use this code
+		 * (it is safe, just suboptimal wrt code size),
+		 * because 32/64 optimized one works only for 64-bit off_t.
 		 */
 		if (totalsize >= (1 << 22)) {
 			totalsize >>= 10;
 			beg_size >>= 10;
 			transferred >>= 10;
-			beg_and_transferred >>= 10;
 			kiloscale = 1;
 		}
 	} else {
 		/* 32-bit CPU and 64-bit off_t.
-		 * Pick a shift (40 bits) which is easier to do on 32-bit CPU.
+		 * Use a 40-bit shift, it is easier to do on 32-bit CPU.
 		 */
 		if (totalsize >= (uoff_t)(1ULL << 54)) {
 			totalsize = (uint32_t)(totalsize >> 32) >> 8;
 			beg_size = (uint32_t)(beg_size >> 32) >> 8;
 			transferred = (uint32_t)(transferred >> 32) >> 8;
-			beg_and_transferred = (uint32_t)(beg_and_transferred >> 32) >> 8;
 			kiloscale = 4;
 		}
 	}
 
-	if (beg_and_transferred > totalsize)
-		beg_and_transferred = totalsize;
+	beg_and_transferred = beg_size + transferred;
 
 	ratio = 100 * beg_and_transferred / totalsize;
 #if ENABLE_UNICODE_SUPPORT
@@ -163,7 +164,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		p->lastupdate_sec = elapsed;
 		p->lastsize = transferred;
 		if (since_last_update >= STALLTIME) {
-			/* We "cut off" these seconds from elapsed time
+			/* We "cut out" these seconds from elapsed time
 			 * by adjusting start time */
 			p->start_sec += since_last_update;
 		}
-- 
cgit v1.2.3-55-g6feb


From d55e13964916af6a083be881bffdb493af287c1d Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 11 Feb 2011 18:56:13 +0100
Subject: progress meter: move file name to bb_progress_t. +20 bytes

We were doing expensive unicode conversion on every update

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/libbb.h   | 12 +++++++++---
 libbb/progress.c  | 24 +++++++++++-------------
 networking/tftp.c | 10 +++++-----
 networking/wget.c |  4 ++--
 4 files changed, 27 insertions(+), 23 deletions(-)

(limited to 'libbb')

diff --git a/include/libbb.h b/include/libbb.h
index c0178801f..7581cd4c4 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1587,15 +1587,21 @@ typedef struct bb_progress_t {
 	off_t lastsize;
 	unsigned lastupdate_sec;
 	unsigned start_sec;
-	smallint inited;
+	const char *curfile;
 } bb_progress_t;
 
-void bb_progress_init(bb_progress_t *p) FAST_FUNC;
-void bb_progress_update(bb_progress_t *p, const char *curfile,
+#define is_bb_progress_inited(p) ((p)->curfile != NULL)
+#define bb_progress_free(p) do { \
+	if (ENABLE_UNICODE_SUPPORT) free((char*)((p)->curfile)); \
+	(p)->curfile = NULL; \
+} while (0)
+void bb_progress_init(bb_progress_t *p, const char *curfile) FAST_FUNC;
+void bb_progress_update(bb_progress_t *p,
 			uoff_t beg_range,
 			uoff_t transferred,
 			uoff_t totalsize) FAST_FUNC;
 
+
 extern const char *applet_name;
 
 /* Some older linkers don't perform string merging, we used to have common strings
diff --git a/libbb/progress.c b/libbb/progress.c
index 1062e9a0d..1d260dd08 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -52,12 +52,17 @@ static unsigned int get_tty2_width(void)
 	return width;
 }
 
-void FAST_FUNC bb_progress_init(bb_progress_t *p)
+void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile)
 {
+#if ENABLE_UNICODE_SUPPORT
+	init_unicode();
+	p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20);
+#else
+	p->curfile = curfile;
+#endif
 	p->start_sec = monotonic_sec();
 	p->lastupdate_sec = p->start_sec;
 	p->lastsize = 0;
-	p->inited = 1;
 }
 
 /* File already had beg_size bytes.
@@ -68,7 +73,6 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p)
  * If totalsize == 0, then it is unknown.
  */
 void FAST_FUNC bb_progress_update(bb_progress_t *p,
-		const char *curfile,
 		uoff_t beg_size,
 		uoff_t transferred,
 		uoff_t totalsize)
@@ -130,16 +134,10 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	beg_and_transferred = beg_size + transferred;
 
 	ratio = 100 * beg_and_transferred / totalsize;
-#if ENABLE_UNICODE_SUPPORT
-	init_unicode();
-	{
-		char *buf = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20);
-		fprintf(stderr, "\r%s%4u%% ", buf, ratio);
-		free(buf);
-	}
-#else
-	fprintf(stderr, "\r%-20.20s%4u%% ", curfile, ratio);
-#endif
+	if (ENABLE_UNICODE_SUPPORT)
+		fprintf(stderr, "\r%s%4u%% ", p->curfile, ratio);
+	else
+		fprintf(stderr, "\r%-20.20s%4u%% ", p->curfile, ratio);
 
 	barlength = get_tty2_width() - 49;
 	if (barlength > 0) {
diff --git a/networking/tftp.c b/networking/tftp.c
index fcd933f6a..2a3991755 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -107,19 +107,19 @@ struct BUG_G_too_big {
 #if ENABLE_FEATURE_TFTP_PROGRESS_BAR
 static void tftp_progress_update(void)
 {
-	bb_progress_update(&G.pmt, G.file, 0, G.pos, G.size);
+	bb_progress_update(&G.pmt, 0, G.pos, G.size);
 }
 static void tftp_progress_init(void)
 {
-	bb_progress_init(&G.pmt);
+	bb_progress_init(&G.pmt, G.file);
 	tftp_progress_update();
 }
 static void tftp_progress_done(void)
 {
-	if (G.pmt.inited) {
+	if (is_bb_progress_inited(&G.pmt)) {
 		tftp_progress_update();
 		bb_putchar_stderr('\n');
-		G.pmt.inited = 0;
+		bb_progress_free(p);
 	}
 }
 #else
@@ -445,7 +445,7 @@ static int tftp_protocol(
 #if ENABLE_FEATURE_TFTP_PROGRESS_BAR
 		if (ENABLE_TFTP && remote_file) /* tftp */
 			G.pos = (block_nr - 1) * (uoff_t)blksize;
-		if (G.pmt.inited)
+		if (is_bb_progress_inited(&G.pmt))
 			tftp_progress_update();
 #endif
 		/* Was it final ACK? then exit */
diff --git a/networking/wget.c b/networking/wget.c
index d81426e8d..f2d7daf2f 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -81,9 +81,9 @@ static void progress_meter(int flag)
 		return;
 
 	if (flag == PROGRESS_START)
-		bb_progress_init(&G.pmt);
+		bb_progress_init(&G.pmt, G.curfile);
 
-	bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred,
+	bb_progress_update(&G.pmt, G.beg_range, G.transferred,
 			   G.chunked ? 0 : G.beg_range + G.transferred + G.content_len);
 
 	if (flag == PROGRESS_END) {
-- 
cgit v1.2.3-55-g6feb


From ab8d00d64fc23602875952c08c030f05f206686c Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 11 Feb 2011 19:09:30 +0100
Subject: progress meter: fix bugs found in stall detection and unknown size
 logic

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/libbb.h   |  5 +++--
 libbb/progress.c  | 55 ++++++++++++++++++++++++++++++++-----------------------
 networking/tftp.c |  2 +-
 3 files changed, 36 insertions(+), 26 deletions(-)

(limited to 'libbb')

diff --git a/include/libbb.h b/include/libbb.h
index 7581cd4c4..65c319402 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1584,8 +1584,9 @@ int print_flags_separated(const int *masks, const char *labels,
 int print_flags(const masks_labels_t *ml, int flags) FAST_FUNC;
 
 typedef struct bb_progress_t {
-	off_t lastsize;
-	unsigned lastupdate_sec;
+	unsigned last_size;
+	unsigned last_update_sec;
+	unsigned last_change_sec;
 	unsigned start_sec;
 	const char *curfile;
 } bb_progress_t;
diff --git a/libbb/progress.c b/libbb/progress.c
index 1d260dd08..df43dad5c 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -61,8 +61,9 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile)
 	p->curfile = curfile;
 #endif
 	p->start_sec = monotonic_sec();
-	p->lastupdate_sec = p->start_sec;
-	p->lastsize = 0;
+	p->last_update_sec = p->start_sec;
+	p->last_change_sec = p->start_sec;
+	p->last_size = 0;
 }
 
 /* File already had beg_size bytes.
@@ -79,12 +80,15 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 {
 	uoff_t beg_and_transferred;
 	unsigned since_last_update, elapsed;
-	unsigned ratio;
 	int barlength;
 	int kiloscale;
 
+	//transferred = 1234; /* use for stall detection testing */
+	//totalsize = 0; /* use for unknown size download testing */
+
 	elapsed = monotonic_sec();
-	since_last_update = elapsed - p->lastupdate_sec;
+	since_last_update = elapsed - p->last_update_sec;
+	p->last_update_sec = elapsed;
 
 	if (totalsize != 0 && transferred >= totalsize - beg_size) {
 		/* Last call. Do not skip this update */
@@ -131,23 +135,27 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 		}
 	}
 
-	beg_and_transferred = beg_size + transferred;
-
-	ratio = 100 * beg_and_transferred / totalsize;
 	if (ENABLE_UNICODE_SUPPORT)
-		fprintf(stderr, "\r%s%4u%% ", p->curfile, ratio);
+		fprintf(stderr, "\r%s", p->curfile);
 	else
-		fprintf(stderr, "\r%-20.20s%4u%% ", p->curfile, ratio);
-
-	barlength = get_tty2_width() - 49;
-	if (barlength > 0) {
-		/* god bless gcc for variable arrays :) */
-		char buf[barlength + 1];
-		unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
-		memset(buf, ' ', barlength);
-		buf[barlength] = '\0';
-		memset(buf, '*', stars);
-		fprintf(stderr, "|%s|", buf);
+		fprintf(stderr, "\r%-20.20s", p->curfile);
+
+	beg_and_transferred = beg_size + transferred;
+
+	if (totalsize != 0) {
+		unsigned ratio = 100 * beg_and_transferred / totalsize;
+		fprintf(stderr, "%4u%%", ratio);
+
+		barlength = get_tty2_width() - 49;
+		if (barlength > 0) {
+			/* god bless gcc for variable arrays :) */
+			char buf[barlength + 1];
+			unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
+			memset(buf, ' ', barlength);
+			buf[barlength] = '\0';
+			memset(buf, '*', stars);
+			fprintf(stderr, " |%s|", buf);
+		}
 	}
 
 	while (beg_and_transferred >= 100000) {
@@ -158,9 +166,10 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 	fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
 #define beg_and_transferred dont_use_beg_and_transferred_below()
 
-	if (transferred != p->lastsize) {
-		p->lastupdate_sec = elapsed;
-		p->lastsize = transferred;
+	since_last_update = elapsed - p->last_change_sec;
+	if ((unsigned)transferred != p->last_size) {
+		p->last_change_sec = elapsed;
+		p->last_size = (unsigned)transferred;
 		if (since_last_update >= STALLTIME) {
 			/* We "cut out" these seconds from elapsed time
 			 * by adjusting start time */
@@ -173,7 +182,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
 
 	if (since_last_update >= STALLTIME) {
 		fprintf(stderr, "  - stalled -");
-	} else if (!totalsize || !transferred || (int)elapsed <= 0) {
+	} else if (!totalsize || !transferred || (int)elapsed < 0) {
 		fprintf(stderr, " --:--:-- ETA");
 	} else {
 		unsigned eta, secs, hours;
diff --git a/networking/tftp.c b/networking/tftp.c
index 2a3991755..35cf0dbd9 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -119,7 +119,7 @@ static void tftp_progress_done(void)
 	if (is_bb_progress_inited(&G.pmt)) {
 		tftp_progress_update();
 		bb_putchar_stderr('\n');
-		bb_progress_free(p);
+		bb_progress_free(&G.pmt);
 	}
 }
 #else
-- 
cgit v1.2.3-55-g6feb


From 0b8a7723c7351533826283c07b37cf2daa77ecf8 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Sat, 12 Feb 2011 01:56:25 +0100
Subject: typo fix

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

(limited to 'libbb')

diff --git a/libbb/systemd_support.c b/libbb/systemd_support.c
index 981296dbb..542a3efff 100644
--- a/libbb/systemd_support.c
+++ b/libbb/systemd_support.c
@@ -33,7 +33,7 @@
 //config:	  If you plan to use busybox daemons on a system where daemons
 //config:	  are controlled by systemd, enable this option.
 //config:	  If you don't use systemd, it is still safe to enable it,
-//config:	  but yhe downside is increased code size.
+//config:	  but the downside is increased code size.
 
 //kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o
 
-- 
cgit v1.2.3-55-g6feb


From dc50676cce35cdba3ecba3870c3f752408d6db70 Mon Sep 17 00:00:00 2001
From: Dan Fandrich <dan@coneharvesters.com>
Date: Sat, 12 Feb 2011 22:26:57 -0800
Subject: Move stpcpy replacement function into libbb

Signed-off-by: Dan Fandrich <dan@coneharvesters.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/platform.h |  8 ++++++++
 libbb/platform.c   | 11 +++++++++++
 runit/runsv.c      | 24 +++++++-----------------
 3 files changed, 26 insertions(+), 17 deletions(-)

(limited to 'libbb')

diff --git a/include/platform.h b/include/platform.h
index 00ebe563b..e390e58e2 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -18,6 +18,7 @@
 #define HAVE_PTSNAME_R 1
 #define HAVE_SETBIT 1
 #define HAVE_SIGHANDLER_T 1
+#define HAVE_STPCPY 1
 #define HAVE_STRCASESTR 1
 #define HAVE_STRCHRNUL 1
 #define HAVE_STRSEP 1
@@ -356,6 +357,8 @@ typedef unsigned smalluint;
 #  define ADJ_TICK MOD_CLKB
 # endif
 
+# undef HAVE_STPCPY
+
 #else
 
 # define bb_setpgrp() setpgrp()
@@ -376,6 +379,7 @@ typedef unsigned smalluint;
 # undef HAVE_MEMRCHR
 # undef HAVE_MKDTEMP
 # undef HAVE_SETBIT
+# undef HAVE_STPCPY
 # undef HAVE_STRCASESTR
 # undef HAVE_STRCHRNUL
 # undef HAVE_STRSEP
@@ -413,6 +417,10 @@ extern char *mkdtemp(char *template) FAST_FUNC;
 typedef void (*sighandler_t)(int);
 #endif
 
+#ifndef HAVE_STPCPY
+extern char *stpcpy(char *p, const char *to_add) FAST_FUNC;
+#endif
+
 #ifndef HAVE_STRCASESTR
 extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC;
 #endif
diff --git a/libbb/platform.c b/libbb/platform.c
index ccde2bf02..fe7ce1567 100644
--- a/libbb/platform.c
+++ b/libbb/platform.c
@@ -134,3 +134,14 @@ char* FAST_FUNC strsep(char **stringp, const char *delim)
 	return start;
 }
 #endif
+
+#ifndef HAVE_STPCPY
+char* FAST_FUNC stpcpy(char *p, const char *to_add)
+{
+	while ((*p = *to_add) != '\0') {
+		p++;
+		to_add++;
+	}
+	return p;
+}
+#endif
diff --git a/runit/runsv.c b/runit/runsv.c
index ebb031837..e76572daa 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -139,16 +139,6 @@ static void s_term(int sig_no UNUSED_PARAM)
 	write(selfpipe.wr, "", 1); /* XXX */
 }
 
-/* libbb candidate */
-static char *bb_stpcpy(char *p, const char *to_add)
-{
-	while ((*p = *to_add) != '\0') {
-		p++;
-		to_add++;
-	}
-	return p;
-}
-
 static int open_trunc_or_warn(const char *name)
 {
 	/* Why O_NDELAY? */
@@ -192,26 +182,26 @@ static void update_status(struct svdir *s)
 		char *p = stat_buf;
 		switch (s->state) {
 		case S_DOWN:
-			p = bb_stpcpy(p, "down");
+			p = stpcpy(p, "down");
 			break;
 		case S_RUN:
-			p = bb_stpcpy(p, "run");
+			p = stpcpy(p, "run");
 			break;
 		case S_FINISH:
-			p = bb_stpcpy(p, "finish");
+			p = stpcpy(p, "finish");
 			break;
 		}
 		if (s->ctrl & C_PAUSE)
-			p = bb_stpcpy(p, ", paused");
+			p = stpcpy(p, ", paused");
 		if (s->ctrl & C_TERM)
-			p = bb_stpcpy(p, ", got TERM");
+			p = stpcpy(p, ", got TERM");
 		if (s->state != S_DOWN)
 			switch (s->sd_want) {
 			case W_DOWN:
-				p = bb_stpcpy(p, ", want down");
+				p = stpcpy(p, ", want down");
 				break;
 			case W_EXIT:
-				p = bb_stpcpy(p, ", want exit");
+				p = stpcpy(p, ", want exit");
 				break;
 			}
 		*p++ = '\n';
-- 
cgit v1.2.3-55-g6feb