aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-22 13:15:08 +0000
committerRon Yorston <rmy@pobox.com>2012-03-22 13:15:08 +0000
commitc0d4367d6b581eb5989c02815880cf0fa2851ae8 (patch)
tree868c266e627e2d7f65ba5a4d5f98a1c421453181 /libbb
parentf6bad5ef766b0447158e3de2f55c35f1f6cecb58 (diff)
parentda4441c44f6efccb6f7b7588404d9c6bfb7b6af8 (diff)
downloadbusybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.tar.gz
busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.tar.bz2
busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.zip
Merge commit 'da4441c44f6efccb6f7b7588404d9c6bfb7b6af8' into merge
Conflicts: libbb/vfork_daemon_rexec.c networking/wget.c procps/ps.c
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.src21
-rw-r--r--libbb/copy_file.c8
-rw-r--r--libbb/crc32.c2
-rw-r--r--libbb/execable.c10
-rw-r--r--libbb/find_mount_point.c2
-rw-r--r--libbb/getopt32.c10
-rw-r--r--libbb/lineedit.c12
-rw-r--r--libbb/messages.c2
-rw-r--r--libbb/platform.c11
-rw-r--r--libbb/progress.c179
-rw-r--r--libbb/systemd_support.c2
-rw-r--r--libbb/vfork_daemon_rexec.c61
12 files changed, 196 insertions, 124 deletions
diff --git a/libbb/Config.src b/libbb/Config.src
index 85892d3fe..18bdc5151 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -156,11 +156,30 @@ config FEATURE_COPYBUF_KB
156 range 1 1024 156 range 1 1024
157 default 4 157 default 4
158 help 158 help
159 Size of buffer used by cp, mv, install etc. 159 Size of buffer used by cp, mv, install, wget etc.
160 Buffers which are 4 kb or less will be allocated on stack. 160 Buffers which are 4 kb or less will be allocated on stack.
161 Bigger buffers will be allocated with mmap, with fallback to 4 kb 161 Bigger buffers will be allocated with mmap, with fallback to 4 kb
162 stack buffer if mmap fails. 162 stack buffer if mmap fails.
163 163
164config FEATURE_SKIP_ROOTFS
165 bool "Skip rootfs in mount table"
166 default y
167 help
168 Ignore rootfs entry in mount table.
169
170 In Linux, kernel has a special filesystem, rootfs, which is initially
171 mounted on /. It contains initramfs data, if kernel is configured
172 to have one. Usually, another file system is mounted over / early
173 in boot process, and therefore most tools which manipulate
174 mount table, such as df, will skip rootfs entry.
175
176 However, some systems do not mount anything on /.
177 If you need to configure busybox for one of these systems,
178 you may find useful to turn this option off to make df show
179 initramfs statistic.
180
181 Otherwise, choose Y.
182
164config MONOTONIC_SYSCALL 183config MONOTONIC_SYSCALL
165 bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" 184 bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
166 default n 185 default n
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index adbc2dea3..48aaf481d 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)
78 /* NB: each struct stat is ~100 bytes */ 78 /* NB: each struct stat is ~100 bytes */
79 struct stat source_stat; 79 struct stat source_stat;
80 struct stat dest_stat; 80 struct stat dest_stat;
81 signed char retval = 0; 81 smallint retval = 0;
82 signed char dest_exists = 0; 82 smallint dest_exists = 0;
83 signed char ovr; 83 smallint ovr;
84 84
85/* Inverse of cp -d ("cp without -d") */ 85/* Inverse of cp -d ("cp without -d") */
86#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) 86#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
@@ -157,7 +157,6 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
157 } 157 }
158#endif 158#endif
159 159
160 /* Create DEST */
161 if (dest_exists) { 160 if (dest_exists) {
162 if (!S_ISDIR(dest_stat.st_mode)) { 161 if (!S_ISDIR(dest_stat.st_mode)) {
163 bb_error_msg("target '%s' is not a directory", dest); 162 bb_error_msg("target '%s' is not a directory", dest);
@@ -166,6 +165,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
166 /* race here: user can substitute a symlink between 165 /* race here: user can substitute a symlink between
167 * this check and actual creation of files inside dest */ 166 * this check and actual creation of files inside dest */
168 } else { 167 } else {
168 /* Create DEST */
169 mode_t mode; 169 mode_t mode;
170 saved_umask = umask(0); 170 saved_umask = umask(0);
171 171
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
59 const void *end = (uint8_t*)buf + len; 59 const void *end = (uint8_t*)buf + len;
60 60
61 while (buf != end) { 61 while (buf != end) {
62 val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); 62 val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
63 buf = (uint8_t*)buf + 1; 63 buf = (uint8_t*)buf + 1;
64 } 64 }
65 return val; 65 return val;
diff --git a/libbb/execable.c b/libbb/execable.c
index 3b144a730..e35dad208 100644
--- a/libbb/execable.c
+++ b/libbb/execable.c
@@ -101,12 +101,12 @@ int FAST_FUNC exists_execable(const char *filename)
101} 101}
102 102
103#if ENABLE_FEATURE_PREFER_APPLETS 103#if ENABLE_FEATURE_PREFER_APPLETS
104/* just like the real execvp, but try to launch an applet named 'file' first 104/* just like the real execvp, but try to launch an applet named 'file' first */
105 */ 105int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
106int FAST_FUNC bb_execvp(const char *file, char *const argv[])
107{ 106{
108 return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file, 107 if (find_applet_by_name(file) >= 0)
109 argv); 108 execvp(bb_busybox_exec_path, argv);
109 return execvp(file, argv);
110} 110}
111#endif 111#endif
112 112
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)
43 /* rootfs mount in Linux 2.6 exists always, 43 /* rootfs mount in Linux 2.6 exists always,
44 * and it makes sense to always ignore it. 44 * and it makes sense to always ignore it.
45 * Otherwise people can't reference their "real" root! */ 45 * Otherwise people can't reference their "real" root! */
46 if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0) 46 if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
47 continue; 47 continue;
48 48
49 if (strcmp(name, mountEntry->mnt_dir) == 0 49 if (strcmp(name, mountEntry->mnt_dir) == 0
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 187cb3a79..053ffc349 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -80,9 +80,9 @@ const char *applet_long_options
80 This struct allows you to define long options: 80 This struct allows you to define long options:
81 81
82 static const char applet_longopts[] ALIGN1 = 82 static const char applet_longopts[] ALIGN1 =
83 //"name\0" has_arg val 83 //"name\0" has_arg val
84 "verbose\0" No_argument "v" 84 "verbose\0" No_argument "v"
85 ; 85 ;
86 applet_long_options = applet_longopts; 86 applet_long_options = applet_longopts;
87 87
88 The last member of struct option (val) typically is set to 88 The last member of struct option (val) typically is set to
@@ -226,7 +226,7 @@ Special characters:
226 if specified together. In this case you must set 226 if specified together. In this case you must set
227 opt_complementary = "b--cf:c--bf:f--bc". If two of the 227 opt_complementary = "b--cf:c--bf:f--bc". If two of the
228 mutually exclusive options are found, getopt32 will call 228 mutually exclusive options are found, getopt32 will call
229 bb_show_usage() and die. 229 bb_show_usage() and die.
230 230
231 "x--x" Variation of the above, it means that -x option should occur 231 "x--x" Variation of the above, it means that -x option should occur
232 at most once. 232 at most once.
@@ -531,7 +531,7 @@ getopt32(char **argv, const char *applet_opts, ...)
531 531
532 /* In case getopt32 was already called: 532 /* In case getopt32 was already called:
533 * reset the libc getopt() function, which keeps internal state. 533 * reset the libc getopt() function, which keeps internal state.
534 * run_nofork_applet_prime() does this, but we might end up here 534 * run_nofork_applet() does this, but we might end up here
535 * also via gunzip_main() -> gzip_main(). Play safe. 535 * also via gunzip_main() -> gzip_main(). Play safe.
536 */ 536 */
537#if defined(__GLIBC__) || ENABLE_PLATFORM_MINGW32 537#if defined(__GLIBC__) || ENABLE_PLATFORM_MINGW32
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index f9658711a..92ecc330a 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1817,10 +1817,9 @@ static void win_changed(int nsig)
1817 errno = sv_errno; 1817 errno = sv_errno;
1818} 1818}
1819 1819
1820static int lineedit_read_key(char *read_key_buffer) 1820static int lineedit_read_key(char *read_key_buffer, int timeout)
1821{ 1821{
1822 int64_t ic; 1822 int64_t ic;
1823 int timeout = -1;
1824#if ENABLE_UNICODE_SUPPORT 1823#if ENABLE_UNICODE_SUPPORT
1825 char unicode_buf[MB_CUR_MAX + 1]; 1824 char unicode_buf[MB_CUR_MAX + 1];
1826 int unicode_idx = 0; 1825 int unicode_idx = 0;
@@ -1925,7 +1924,7 @@ static int isrtl_str(void)
1925 * 0 on ctrl-C (the line entered is still returned in 'command'), 1924 * 0 on ctrl-C (the line entered is still returned in 'command'),
1926 * >0 length of input string, including terminating '\n' 1925 * >0 length of input string, including terminating '\n'
1927 */ 1926 */
1928int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st) 1927int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout)
1929{ 1928{
1930 int len; 1929 int len;
1931#if ENABLE_FEATURE_TAB_COMPLETION 1930#if ENABLE_FEATURE_TAB_COMPLETION
@@ -2006,7 +2005,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2006 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 2005 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
2007 tcsetattr_stdin_TCSANOW(&new_settings); 2006 tcsetattr_stdin_TCSANOW(&new_settings);
2008 2007
2009 /* Now initialize things */
2010 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); 2008 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
2011 win_changed(0); /* do initial resizing */ 2009 win_changed(0); /* do initial resizing */
2012#if ENABLE_USERNAME_OR_HOMEDIR 2010#if ENABLE_USERNAME_OR_HOMEDIR
@@ -2048,7 +2046,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2048 int32_t ic, ic_raw; 2046 int32_t ic, ic_raw;
2049 2047
2050 fflush_all(); 2048 fflush_all();
2051 ic = ic_raw = lineedit_read_key(read_key_buffer); 2049 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2052 2050
2053#if ENABLE_FEATURE_EDITING_VI 2051#if ENABLE_FEATURE_EDITING_VI
2054 newdelflag = 1; 2052 newdelflag = 1;
@@ -2209,7 +2207,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2209 case 'd'|VI_CMDMODE_BIT: { 2207 case 'd'|VI_CMDMODE_BIT: {
2210 int nc, sc; 2208 int nc, sc;
2211 2209
2212 ic = lineedit_read_key(read_key_buffer); 2210 ic = lineedit_read_key(read_key_buffer, timeout);
2213 if (errno) /* error */ 2211 if (errno) /* error */
2214 goto return_error_indicator; 2212 goto return_error_indicator;
2215 if (ic == ic_raw) { /* "cc", "dd" */ 2213 if (ic == ic_raw) { /* "cc", "dd" */
@@ -2273,7 +2271,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2273 break; 2271 break;
2274 case 'r'|VI_CMDMODE_BIT: 2272 case 'r'|VI_CMDMODE_BIT:
2275//FIXME: unicode case? 2273//FIXME: unicode case?
2276 ic = lineedit_read_key(read_key_buffer); 2274 ic = lineedit_read_key(read_key_buffer, timeout);
2277 if (errno) /* error */ 2275 if (errno) /* error */
2278 goto return_error_indicator; 2276 goto return_error_indicator;
2279 if (ic < ' ' || ic > 255) { 2277 if (ic < ' ' || ic > 255) {
diff --git a/libbb/messages.c b/libbb/messages.c
index 9e7bd0fef..ef42b30d7 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -22,7 +22,7 @@
22const char bb_banner[] ALIGN1 = BANNER; 22const char bb_banner[] ALIGN1 = BANNER;
23 23
24 24
25const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted"; 25const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory";
26const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'"; 26const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'";
27const char bb_msg_unknown[] ALIGN1 = "(unknown)"; 27const char bb_msg_unknown[] ALIGN1 = "(unknown)";
28const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket"; 28const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket";
diff --git a/libbb/platform.c b/libbb/platform.c
index 30d06e3a7..1441a84ac 100644
--- a/libbb/platform.c
+++ b/libbb/platform.c
@@ -147,3 +147,14 @@ char* FAST_FUNC strsep(char **stringp, const char *delim)
147 return start; 147 return start;
148} 148}
149#endif 149#endif
150
151#ifndef HAVE_STPCPY
152char* FAST_FUNC stpcpy(char *p, const char *to_add)
153{
154 while ((*p = *to_add) != '\0') {
155 p++;
156 to_add++;
157 }
158 return p;
159}
160#endif
diff --git a/libbb/progress.c b/libbb/progress.c
index 40608b047..df43dad5c 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -52,101 +52,154 @@ static unsigned int get_tty2_width(void)
52 return width; 52 return width;
53} 53}
54 54
55void FAST_FUNC bb_progress_init(bb_progress_t *p) 55void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile)
56{ 56{
57#if ENABLE_UNICODE_SUPPORT
58 init_unicode();
59 p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20);
60#else
61 p->curfile = curfile;
62#endif
57 p->start_sec = monotonic_sec(); 63 p->start_sec = monotonic_sec();
58 p->lastupdate_sec = p->start_sec; 64 p->last_update_sec = p->start_sec;
59 p->lastsize = 0; 65 p->last_change_sec = p->start_sec;
60 p->inited = 1; 66 p->last_size = 0;
61} 67}
62 68
69/* File already had beg_size bytes.
70 * Then we started downloading.
71 * We downloaded "transferred" bytes so far.
72 * Download is expected to stop when total size (beg_size + transferred)
73 * will be "totalsize" bytes.
74 * If totalsize == 0, then it is unknown.
75 */
63void FAST_FUNC bb_progress_update(bb_progress_t *p, 76void FAST_FUNC bb_progress_update(bb_progress_t *p,
64 const char *curfile, 77 uoff_t beg_size,
65 off_t beg_range, 78 uoff_t transferred,
66 off_t transferred, 79 uoff_t totalsize)
67 off_t totalsize)
68{ 80{
69 uoff_t beg_and_transferred; 81 uoff_t beg_and_transferred;
70 unsigned since_last_update, elapsed; 82 unsigned since_last_update, elapsed;
71 unsigned ratio; 83 int barlength;
72 int barlength, i; 84 int kiloscale;
73 85
74 /* totalsize == 0 if it is unknown */ 86 //transferred = 1234; /* use for stall detection testing */
87 //totalsize = 0; /* use for unknown size download testing */
75 88
76 elapsed = monotonic_sec(); 89 elapsed = monotonic_sec();
77 since_last_update = elapsed - p->lastupdate_sec; 90 since_last_update = elapsed - p->last_update_sec;
78 /* Do not update on every call 91 p->last_update_sec = elapsed;
79 * (we can be called on every network read!) */
80 if (since_last_update == 0 && !totalsize)
81 return;
82 92
83 beg_and_transferred = beg_range + transferred; 93 if (totalsize != 0 && transferred >= totalsize - beg_size) {
84 ratio = 100; 94 /* Last call. Do not skip this update */
85 if (beg_and_transferred < totalsize) { 95 transferred = totalsize - beg_size; /* sanitize just in case */
86 /* Do not update on every call 96 }
87 * (we can be called on every network read!) */ 97 else if (since_last_update == 0) {
88 if (since_last_update == 0) 98 /*
89 return; 99 * Do not update on every call
90 /* long long helps to have it working even if !LFS */ 100 * (we can be called on every network read!)
91 ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize; 101 */
102 return;
92 } 103 }
93 104
94#if ENABLE_UNICODE_SUPPORT 105 kiloscale = 0;
95 init_unicode(); 106 /*
96 { 107 * Scale sizes down if they are close to overflowing.
97 char *buf = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20); 108 * This allows calculations like (100 * transferred / totalsize)
98 fprintf(stderr, "\r%s%4u%% ", buf, ratio); 109 * without risking overflow: we guarantee 10 highest bits to be 0.
99 free(buf); 110 * Introduced error is less than 1 / 2^12 ~= 0.025%
111 */
112 if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) {
113 /*
114 * 64-bit CPU || small off_t: in either case,
115 * >> is cheap, single-word operation.
116 * ... || strange off_t: also use this code
117 * (it is safe, just suboptimal wrt code size),
118 * because 32/64 optimized one works only for 64-bit off_t.
119 */
120 if (totalsize >= (1 << 22)) {
121 totalsize >>= 10;
122 beg_size >>= 10;
123 transferred >>= 10;
124 kiloscale = 1;
125 }
126 } else {
127 /* 32-bit CPU and 64-bit off_t.
128 * Use a 40-bit shift, it is easier to do on 32-bit CPU.
129 */
130 if (totalsize >= (uoff_t)(1ULL << 54)) {
131 totalsize = (uint32_t)(totalsize >> 32) >> 8;
132 beg_size = (uint32_t)(beg_size >> 32) >> 8;
133 transferred = (uint32_t)(transferred >> 32) >> 8;
134 kiloscale = 4;
135 }
100 } 136 }
101#else
102 fprintf(stderr, "\r%-20.20s%4u%% ", curfile, ratio);
103#endif
104 137
105 barlength = get_tty2_width() - 49; 138 if (ENABLE_UNICODE_SUPPORT)
106 if (barlength > 0) { 139 fprintf(stderr, "\r%s", p->curfile);
107 /* god bless gcc for variable arrays :) */ 140 else
108 char buf[barlength + 1]; 141 fprintf(stderr, "\r%-20.20s", p->curfile);
109 unsigned stars = (unsigned)barlength * ratio / (unsigned)100; 142
110 memset(buf, ' ', barlength); 143 beg_and_transferred = beg_size + transferred;
111 buf[barlength] = '\0'; 144
112 memset(buf, '*', stars); 145 if (totalsize != 0) {
113 fprintf(stderr, "|%s|", buf); 146 unsigned ratio = 100 * beg_and_transferred / totalsize;
147 fprintf(stderr, "%4u%%", ratio);
148
149 barlength = get_tty2_width() - 49;
150 if (barlength > 0) {
151 /* god bless gcc for variable arrays :) */
152 char buf[barlength + 1];
153 unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
154 memset(buf, ' ', barlength);
155 buf[barlength] = '\0';
156 memset(buf, '*', stars);
157 fprintf(stderr, " |%s|", buf);
158 }
114 } 159 }
115 160
116 i = 0;
117 while (beg_and_transferred >= 100000) { 161 while (beg_and_transferred >= 100000) {
118 i++;
119 beg_and_transferred >>= 10; 162 beg_and_transferred >>= 10;
163 kiloscale++;
120 } 164 }
121 /* see http://en.wikipedia.org/wiki/Tera */ 165 /* see http://en.wikipedia.org/wiki/Tera */
122 fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]); 166 fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
123#define beg_and_transferred dont_use_beg_and_transferred_below 167#define beg_and_transferred dont_use_beg_and_transferred_below()
124 168
125 if (transferred > p->lastsize) { 169 since_last_update = elapsed - p->last_change_sec;
126 p->lastupdate_sec = elapsed; 170 if ((unsigned)transferred != p->last_size) {
127 p->lastsize = transferred; 171 p->last_change_sec = elapsed;
172 p->last_size = (unsigned)transferred;
128 if (since_last_update >= STALLTIME) { 173 if (since_last_update >= STALLTIME) {
129 /* We "cut off" these seconds from elapsed time 174 /* We "cut out" these seconds from elapsed time
130 * by adjusting start time */ 175 * by adjusting start time */
131 p->start_sec += since_last_update; 176 p->start_sec += since_last_update;
132 } 177 }
133 since_last_update = 0; /* we are un-stalled now */ 178 since_last_update = 0; /* we are un-stalled now */
134 } 179 }
180
135 elapsed -= p->start_sec; /* now it's "elapsed since start" */ 181 elapsed -= p->start_sec; /* now it's "elapsed since start" */
136 182
137 if (since_last_update >= STALLTIME) { 183 if (since_last_update >= STALLTIME) {
138 fprintf(stderr, " - stalled -"); 184 fprintf(stderr, " - stalled -");
185 } else if (!totalsize || !transferred || (int)elapsed < 0) {
186 fprintf(stderr, " --:--:-- ETA");
139 } else { 187 } else {
140 off_t to_download = totalsize - beg_range; 188 unsigned eta, secs, hours;
141 if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { 189
142 fprintf(stderr, "--:--:-- ETA"); 190 totalsize -= beg_size; /* now it's "total to upload" */
143 } else { 191
144 /* to_download / (transferred/elapsed) - elapsed: */ 192 /* Estimated remaining time =
145 /* (long long helps to have working ETA even if !LFS) */ 193 * estimated_sec_to_dl_totalsize_bytes - elapsed_sec =
146 unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed; 194 * totalsize / average_bytes_sec_so_far - elapsed =
147 unsigned secs = eta % 3600; 195 * totalsize / (transferred/elapsed) - elapsed =
148 unsigned hours = eta / 3600; 196 * totalsize * elapsed / transferred - elapsed
149 fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); 197 */
150 } 198 eta = totalsize * elapsed / transferred - elapsed;
199 if (eta >= 1000*60*60)
200 eta = 1000*60*60 - 1;
201 secs = eta % 3600;
202 hours = eta / 3600;
203 fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60);
151 } 204 }
152} 205}
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 @@
33//config: If you plan to use busybox daemons on a system where daemons 33//config: If you plan to use busybox daemons on a system where daemons
34//config: are controlled by systemd, enable this option. 34//config: are controlled by systemd, enable this option.
35//config: If you don't use systemd, it is still safe to enable it, 35//config: If you don't use systemd, it is still safe to enable it,
36//config: but yhe downside is increased code size. 36//config: but the downside is increased code size.
37 37
38//kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o 38//kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o
39 39
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 1fbb1bba9..5d8056bd6 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -55,6 +55,7 @@ pid_t FAST_FUNC spawn(char **argv)
55 * Interested party can wait on pid and learn exit code. 55 * Interested party can wait on pid and learn exit code.
56 * If 111 - then it (most probably) failed to exec */ 56 * If 111 - then it (most probably) failed to exec */
57 if (failed) { 57 if (failed) {
58 safe_waitpid(pid, NULL, 0); /* prevent zombie */
58 errno = failed; 59 errno = failed;
59 return -1; 60 return -1;
60 } 61 }
@@ -71,17 +72,22 @@ pid_t FAST_FUNC xspawn(char **argv)
71} 72}
72 73
73#if ENABLE_FEATURE_PREFER_APPLETS 74#if ENABLE_FEATURE_PREFER_APPLETS
74void FAST_FUNC save_nofork_data(struct nofork_save_area *save) 75struct nofork_save_area {
76 jmp_buf die_jmp;
77 const char *applet_name;
78 uint32_t option_mask32;
79 int die_sleep;
80 uint8_t xfunc_error_retval;
81};
82static void save_nofork_data(struct nofork_save_area *save)
75{ 83{
76 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); 84 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
77 save->applet_name = applet_name; 85 save->applet_name = applet_name;
78 save->xfunc_error_retval = xfunc_error_retval; 86 save->xfunc_error_retval = xfunc_error_retval;
79 save->option_mask32 = option_mask32; 87 save->option_mask32 = option_mask32;
80 save->die_sleep = die_sleep; 88 save->die_sleep = die_sleep;
81 save->saved = 1;
82} 89}
83 90static void restore_nofork_data(struct nofork_save_area *save)
84void FAST_FUNC restore_nofork_data(struct nofork_save_area *save)
85{ 91{
86 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); 92 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
87 applet_name = save->applet_name; 93 applet_name = save->applet_name;
@@ -90,19 +96,17 @@ void FAST_FUNC restore_nofork_data(struct nofork_save_area *save)
90 die_sleep = save->die_sleep; 96 die_sleep = save->die_sleep;
91} 97}
92 98
93int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) 99int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
94{ 100{
95 int rc, argc; 101 int rc, argc;
102 struct nofork_save_area old;
103
104 save_nofork_data(&old);
96 105
97 applet_name = APPLET_NAME(applet_no); 106 applet_name = APPLET_NAME(applet_no);
98 107
99 xfunc_error_retval = EXIT_FAILURE; 108 xfunc_error_retval = EXIT_FAILURE;
100 109
101 /* Special flag for xfunc_die(). If xfunc will "die"
102 * in NOFORK applet, xfunc_die() sees negative
103 * die_sleep and longjmp here instead. */
104 die_sleep = -1;
105
106 /* In case getopt() or getopt32() was already called: 110 /* In case getopt() or getopt32() was already called:
107 * reset the libc getopt() function, which keeps internal state. 111 * reset the libc getopt() function, which keeps internal state.
108 * 112 *
@@ -132,6 +136,11 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
132 while (argv[argc]) 136 while (argv[argc])
133 argc++; 137 argc++;
134 138
139 /* Special flag for xfunc_die(). If xfunc will "die"
140 * in NOFORK applet, xfunc_die() sees negative
141 * die_sleep and longjmp here instead. */
142 die_sleep = -1;
143
135 rc = setjmp(die_jmp); 144 rc = setjmp(die_jmp);
136 if (!rc) { 145 if (!rc) {
137 /* Some callers (xargs) 146 /* Some callers (xargs)
@@ -140,15 +149,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
140 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); 149 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
141 /* Finally we can call NOFORK applet's main() */ 150 /* Finally we can call NOFORK applet's main() */
142 rc = applet_main[applet_no](argc, tmp_argv); 151 rc = applet_main[applet_no](argc, tmp_argv);
143
144 /* The whole reason behind nofork_save_area is that <applet>_main
145 * may exit non-locally! For example, in hush Ctrl-Z tries
146 * (modulo bugs) to dynamically create a child (backgrounded task)
147 * if it detects that Ctrl-Z was pressed when a NOFORK was running.
148 * Testcase: interactive "rm -i".
149 * Don't fool yourself into thinking "and <applet>_main() returns
150 * quickly here" and removing "useless" nofork_save_area code. */
151
152 } else { /* xfunc died in NOFORK applet */ 152 } else { /* xfunc died in NOFORK applet */
153 /* in case they meant to return 0... */ 153 /* in case they meant to return 0... */
154 if (rc == -2222) 154 if (rc == -2222)
@@ -156,7 +156,7 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
156 } 156 }
157 157
158 /* Restoring some globals */ 158 /* Restoring some globals */
159 restore_nofork_data(old); 159 restore_nofork_data(&old);
160 160
161 /* Other globals can be simply reset to defaults */ 161 /* Other globals can be simply reset to defaults */
162#ifdef __GLIBC__ 162#ifdef __GLIBC__
@@ -167,15 +167,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n
167 167
168 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ 168 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
169} 169}
170
171int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
172{
173 struct nofork_save_area old;
174
175 /* Saving globals */
176 save_nofork_data(&old);
177 return run_nofork_applet_prime(&old, applet_no, argv);
178}
179#endif /* FEATURE_PREFER_APPLETS */ 170#endif /* FEATURE_PREFER_APPLETS */
180 171
181int FAST_FUNC spawn_and_wait(char **argv) 172int FAST_FUNC spawn_and_wait(char **argv)
@@ -185,17 +176,17 @@ int FAST_FUNC spawn_and_wait(char **argv)
185 int a = find_applet_by_name(argv[0]); 176 int a = find_applet_by_name(argv[0]);
186 177
187 if (a >= 0 && (APPLET_IS_NOFORK(a) 178 if (a >= 0 && (APPLET_IS_NOFORK(a)
188#if BB_MMU 179# if BB_MMU
189 || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ 180 || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
190#endif 181# endif
191 )) { 182 )) {
192#if BB_MMU 183# if BB_MMU
193 if (APPLET_IS_NOFORK(a)) 184 if (APPLET_IS_NOFORK(a))
194#endif 185# endif
195 { 186 {
196 return run_nofork_applet(a, argv); 187 return run_nofork_applet(a, argv);
197 } 188 }
198#if BB_MMU && !ENABLE_PLATFORM_MINGW32 189# if BB_MMU && !ENABLE_PLATFORM_MINGW32
199 /* MMU only */ 190 /* MMU only */
200 /* a->noexec is true */ 191 /* a->noexec is true */
201 rc = fork(); 192 rc = fork();
@@ -204,7 +195,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
204 /* child */ 195 /* child */
205 xfunc_error_retval = EXIT_FAILURE; 196 xfunc_error_retval = EXIT_FAILURE;
206 run_applet_no_and_exit(a, argv); 197 run_applet_no_and_exit(a, argv);
207#endif 198# endif
208 } 199 }
209#endif /* FEATURE_PREFER_APPLETS */ 200#endif /* FEATURE_PREFER_APPLETS */
210 rc = spawn(argv); 201 rc = spawn(argv);