aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Kbuild.src2
-rw-r--r--libbb/appletlib.c166
-rw-r--r--libbb/executable.c11
-rw-r--r--libbb/info_msg.c62
-rw-r--r--libbb/ubi.c43
-rw-r--r--libbb/verror_msg.c29
-rw-r--r--libbb/vfork_daemon_rexec.c3
-rw-r--r--libbb/xfuncs.c12
-rw-r--r--libbb/xfuncs_printf.c22
9 files changed, 254 insertions, 96 deletions
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index e0898565a..0e14e351e 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -43,7 +43,7 @@ lib-y += getopt32.o
43lib-y += get_volsize.o 43lib-y += get_volsize.o
44lib-y += herror_msg.o 44lib-y += herror_msg.o
45lib-y += human_readable.o 45lib-y += human_readable.o
46lib-y += info_msg.o 46lib-y += inet_common.o
47lib-y += inode_hash.o 47lib-y += inode_hash.o
48lib-y += isdirectory.o 48lib-y += isdirectory.o
49lib-y += last_char_is.o 49lib-y += last_char_is.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 1d6a4b274..b71f2dd7e 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -140,32 +140,127 @@ void FAST_FUNC bb_show_usage(void)
140 xfunc_die(); 140 xfunc_die();
141} 141}
142 142
143#if NUM_APPLETS > 8
144static int applet_name_compare(const void *name, const void *idx)
145{
146 int i = (int)(ptrdiff_t)idx - 1;
147 return strcmp(name, APPLET_NAME(i));
148}
149#endif
150int FAST_FUNC find_applet_by_name(const char *name) 143int FAST_FUNC find_applet_by_name(const char *name)
151{ 144{
152#if NUM_APPLETS > 8 145 unsigned i, max;
153 /* Do a binary search to find the applet entry given the name. */ 146 int j;
154 const char *p; 147 const char *p;
155 p = bsearch(name, (void*)(ptrdiff_t)1, ARRAY_SIZE(applet_main), 1, applet_name_compare); 148
156 /* 149/* The commented-out word-at-a-time code is ~40% faster, but +160 bytes.
157 * if (!p) return -1; 150 * "Faster" here saves ~0.5 microsecond of real time - not worth it.
158 * ^^^^^^^^^^^^^^^^^^ the code below will do this if p == NULL :) 151 */
159 */ 152#if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/
160 return (int)(ptrdiff_t)p - 1; 153 uint32_t n32;
154
155 /* Handle all names < 2 chars long early */
156 if (name[0] == '\0')
157 return -1; /* "" is not a valid applet name */
158 if (name[1] == '\0') {
159 if (!ENABLE_TEST)
160 return -1; /* 1-char name is not valid */
161 if (name[0] != ']')
162 return -1; /* 1-char name which isn't "[" is not valid */
163 /* applet "[" is always applet #0: */
164 return 0;
165 }
166#endif
167
168 p = applet_names;
169 i = 0;
170#if KNOWN_APPNAME_OFFSETS <= 0
171 max = NUM_APPLETS;
161#else 172#else
162 /* A version which does not pull in bsearch */ 173 max = NUM_APPLETS * KNOWN_APPNAME_OFFSETS;
163 int i = 0; 174 for (j = ARRAY_SIZE(applet_nameofs)-1; j >= 0; j--) {
164 const char *p = applet_names; 175 const char *pp = applet_names + applet_nameofs[j];
165 while (i < NUM_APPLETS) { 176 if (strcmp(name, pp) >= 0) {
166 if (strcmp(name, p) == 0) 177 //bb_error_msg("name:'%s' >= pp:'%s'", name, pp);
178 p = pp;
179 i = max - NUM_APPLETS;
180 break;
181 }
182 max -= NUM_APPLETS;
183 }
184 max /= (unsigned)KNOWN_APPNAME_OFFSETS;
185 i /= (unsigned)KNOWN_APPNAME_OFFSETS;
186 //bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max);
187#endif
188
189 /* Open-coded linear search without strcmp/strlen calls for speed */
190
191#if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/
192 /* skip "[\0" name, it's surely not it */
193 if (ENABLE_TEST && LONE_CHAR(p, '['))
194 i++, p += 2;
195 /* All remaining applet names in p[] are at least 2 chars long */
196 /* name[] is also at least 2 chars long */
197
198 n32 = (name[0] << 0) | (name[1] << 8) | (name[2] << 16);
199 while (i < max) {
200 uint32_t p32;
201 char ch;
202
203 /* Quickly check match of the first 3 bytes */
204 move_from_unaligned32(p32, p);
205 p += 3;
206 if ((p32 & 0x00ffffff) != n32) {
207 /* Most likely case: 3 first bytes do not match */
208 i++;
209 if ((p32 & 0x00ff0000) == '\0')
210 continue; // p[2] was NUL
211 p++;
212 if ((p32 & 0xff000000) == '\0')
213 continue; // p[3] was NUL
214 /* p[0..3] aren't matching and none is NUL, check the rest */
215 while (*p++ != '\0')
216 continue;
217 continue;
218 }
219
220 /* Unlikely branch: first 3 bytes ([0..2]) match */
221 if ((p32 & 0x00ff0000) == '\0') {
222 /* name is 2-byte long, it is full match */
223 //bb_error_msg("found:'%s' i:%u", name, i);
167 return i; 224 return i;
168 p += strlen(p) + 1; 225 }
226 /* Check remaining bytes [3..NUL] */
227 ch = (p32 >> 24);
228 j = 3;
229 while (ch == name[j]) {
230 if (ch == '\0') {
231 //bb_error_msg("found:'%s' i:%u", name, i);
232 return i;
233 }
234 ch = *++p;
235 j++;
236 }
237 /* Not a match. Skip it, including NUL */
238 while (ch != '\0')
239 ch = *++p;
240 p++;
241 i++;
242 }
243 return -1;
244#else
245 while (i < max) {
246 char ch;
247 j = 0;
248 /* Do we see "name\0" in applet_names[p] position? */
249 while ((ch = *p) == name[j]) {
250 if (ch == '\0') {
251 //bb_error_msg("found:'%s' i:%u", name, i);
252 return i; /* yes */
253 }
254 p++;
255 j++;
256 }
257 /* No.
258 * p => 1st non-matching char in applet_names[],
259 * skip to and including NUL.
260 */
261 while (ch != '\0')
262 ch = *++p;
263 p++;
169 i++; 264 i++;
170 } 265 }
171 return -1; 266 return -1;
@@ -588,6 +683,7 @@ static void install_links(const char *busybox, int use_symbolic_links,
588 * busybox.h::bb_install_loc_t, or else... */ 683 * busybox.h::bb_install_loc_t, or else... */
589 int (*lf)(const char *, const char *); 684 int (*lf)(const char *, const char *);
590 char *fpc; 685 char *fpc;
686 const char *appname = applet_names;
591 unsigned i; 687 unsigned i;
592 int rc; 688 int rc;
593 689
@@ -598,7 +694,7 @@ static void install_links(const char *busybox, int use_symbolic_links,
598 for (i = 0; i < ARRAY_SIZE(applet_main); i++) { 694 for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
599 fpc = concat_path_file( 695 fpc = concat_path_file(
600 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)], 696 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
601 APPLET_NAME(i)); 697 appname);
602 // debug: bb_error_msg("%slinking %s to busybox", 698 // debug: bb_error_msg("%slinking %s to busybox",
603 // use_symbolic_links ? "sym" : "", fpc); 699 // use_symbolic_links ? "sym" : "", fpc);
604 rc = lf(busybox, fpc); 700 rc = lf(busybox, fpc);
@@ -606,6 +702,8 @@ static void install_links(const char *busybox, int use_symbolic_links,
606 bb_simple_perror_msg(fpc); 702 bb_simple_perror_msg(fpc);
607 } 703 }
608 free(fpc); 704 free(fpc);
705 while (*appname++ != '\0')
706 continue;
609 } 707 }
610} 708}
611# else 709# else
@@ -769,7 +867,7 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
769 867
770 /* Reinit some shared global data */ 868 /* Reinit some shared global data */
771 xfunc_error_retval = EXIT_FAILURE; 869 xfunc_error_retval = EXIT_FAILURE;
772 applet_name = APPLET_NAME(applet_no); 870 applet_name = bb_get_last_path_component_nostrip(argv[0]);
773 871
774 /* Special case. POSIX says "test --help" 872 /* Special case. POSIX says "test --help"
775 * should be no different from e.g. "test --foo". 873 * should be no different from e.g. "test --foo".
@@ -800,11 +898,14 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
800 898
801void FAST_FUNC run_applet_and_exit(const char *name, char **argv) 899void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
802{ 900{
803 int applet = find_applet_by_name(name); 901 int applet;
804 if (applet >= 0) 902
805 run_applet_no_and_exit(applet, argv);
806 if (is_prefixed_with(name, "busybox")) 903 if (is_prefixed_with(name, "busybox"))
807 exit(busybox_main(argv)); 904 exit(busybox_main(argv));
905 /* find_applet_by_name() search is more expensive, so goes second */
906 applet = find_applet_by_name(name);
907 if (applet >= 0)
908 run_applet_no_and_exit(applet, argv);
808} 909}
809 910
810#endif /* !defined(SINGLE_APPLET_MAIN) */ 911#endif /* !defined(SINGLE_APPLET_MAIN) */
@@ -817,6 +918,19 @@ int lbb_main(char **argv)
817int main(int argc UNUSED_PARAM, char **argv) 918int main(int argc UNUSED_PARAM, char **argv)
818#endif 919#endif
819{ 920{
921#if 0
922 /* TODO: find a use for a block of memory between end of .bss
923 * and end of page. For example, I'm getting "_end:0x812e698 2408 bytes"
924 * - more than 2k of wasted memory (in this particular build)
925 * *per each running process*!
926 * (If your linker does not generate "_end" name, weak attribute
927 * makes &_end == NULL, end_len == 0 here.)
928 */
929 extern char _end[] __attribute__((weak));
930 unsigned end_len = (-(int)_end) & 0xfff;
931 printf("_end:%p %u bytes\n", &_end, end_len);
932#endif
933
820 /* Tweak malloc for reduced memory consumption */ 934 /* Tweak malloc for reduced memory consumption */
821#ifdef M_TRIM_THRESHOLD 935#ifdef M_TRIM_THRESHOLD
822 /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory 936 /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory
diff --git a/libbb/executable.c b/libbb/executable.c
index 12a48cea3..308c525a3 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -97,10 +97,19 @@ int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
97} 97}
98#endif 98#endif
99 99
100int FAST_FUNC BB_EXECVP_or_die(char **argv) 100void FAST_FUNC BB_EXECVP_or_die(char **argv)
101{ 101{
102 BB_EXECVP(argv[0], argv); 102 BB_EXECVP(argv[0], argv);
103 /* SUSv3-mandated exit codes */ 103 /* SUSv3-mandated exit codes */
104 xfunc_error_retval = (errno == ENOENT) ? 127 : 126; 104 xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
105 bb_perror_msg_and_die("can't execute '%s'", argv[0]); 105 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
106} 106}
107
108/* Typical idiom for applets which exec *optional* PROG [ARGS] */
109void FAST_FUNC exec_prog_or_SHELL(char **argv)
110{
111 if (argv[0]) {
112 BB_EXECVP_or_die(argv);
113 }
114 run_shell(getenv("SHELL"), /*login:*/ 1, NULL, NULL);
115}
diff --git a/libbb/info_msg.c b/libbb/info_msg.c
deleted file mode 100644
index 56ca2efd4..000000000
--- a/libbb/info_msg.c
+++ /dev/null
@@ -1,62 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10#include "libbb.h"
11#if ENABLE_FEATURE_SYSLOG
12# include <syslog.h>
13#endif
14
15void FAST_FUNC bb_info_msg(const char *s, ...)
16{
17#ifdef THIS_ONE_DOESNT_DO_SINGLE_WRITE
18 va_list p;
19 /* va_copy is used because it is not portable
20 * to use va_list p twice */
21 va_list p2;
22
23 va_start(p, s);
24 va_copy(p2, p);
25 if (logmode & LOGMODE_STDIO) {
26 vprintf(s, p);
27 fputs(msg_eol, stdout);
28 }
29# if ENABLE_FEATURE_SYSLOG
30 if (logmode & LOGMODE_SYSLOG)
31 vsyslog(LOG_INFO, s, p2);
32# endif
33 va_end(p2);
34 va_end(p);
35#else
36 int used;
37 char *msg;
38 va_list p;
39
40 if (logmode == 0)
41 return;
42
43 va_start(p, s);
44 used = vasprintf(&msg, s, p);
45 va_end(p);
46 if (used < 0)
47 return;
48
49# if ENABLE_FEATURE_SYSLOG
50 if (logmode & LOGMODE_SYSLOG)
51 syslog(LOG_INFO, "%s", msg);
52# endif
53 if (logmode & LOGMODE_STDIO) {
54 fflush_all();
55 /* used = strlen(msg); - must be true already */
56 msg[used++] = '\n';
57 full_write(STDOUT_FILENO, msg, used);
58 }
59
60 free(msg);
61#endif
62}
diff --git a/libbb/ubi.c b/libbb/ubi.c
new file mode 100644
index 000000000..34595d797
--- /dev/null
+++ b/libbb/ubi.c
@@ -0,0 +1,43 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2016 Denys Vlasenko
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//kbuild:lib-y += ubi.o
10
11#include "libbb.h"
12
13// from ubi-media.h
14#define UBI_MAX_VOLUME_NAME 127
15#define UBI_MAX_VOLUMES 128
16
17unsigned FAST_FUNC ubi_devnum_from_devname(const char *str)
18{
19 unsigned ubi_devnum;
20
21 if (sscanf(str, "/dev/ubi%u", &ubi_devnum) != 1)
22 bb_error_msg_and_die("not an UBI device: '%s'", str);
23 return ubi_devnum;
24}
25
26int FAST_FUNC ubi_get_volid_by_name(unsigned ubi_devnum, const char *vol_name)
27{
28 unsigned i;
29
30 for (i = 0; i < UBI_MAX_VOLUMES; i++) {
31 char buf[UBI_MAX_VOLUME_NAME + 1];
32 char fname[sizeof("/sys/class/ubi/ubi%u_%u/name") + 2 * sizeof(int)*3];
33
34 sprintf(fname, "/sys/class/ubi/ubi%u_%u/name", ubi_devnum, i);
35 if (open_read_close(fname, buf, sizeof(buf)) <= 0)
36 continue;
37
38 strchrnul(buf, '\n')[0] = '\0';
39 if (strcmp(vol_name, buf) == 0)
40 return i;
41 }
42 bb_error_msg_and_die("volume '%s' not found", vol_name);
43}
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
index 0ef2a311f..22c30357b 100644
--- a/libbb/verror_msg.c
+++ b/libbb/verror_msg.c
@@ -20,6 +20,7 @@ const char *msg_eol = "\n";
20void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) 20void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
21{ 21{
22 char *msg, *msg1; 22 char *msg, *msg1;
23 char stack_msg[80];
23 int applet_len, strerr_len, msgeol_len, used; 24 int applet_len, strerr_len, msgeol_len, used;
24 25
25 if (!logmode) 26 if (!logmode)
@@ -28,6 +29,27 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
28 if (!s) /* nomsg[_and_die] uses NULL fmt */ 29 if (!s) /* nomsg[_and_die] uses NULL fmt */
29 s = ""; /* some libc don't like printf(NULL) */ 30 s = ""; /* some libc don't like printf(NULL) */
30 31
32 applet_len = strlen(applet_name) + 2; /* "applet: " */
33 strerr_len = strerr ? strlen(strerr) : 0;
34 msgeol_len = strlen(msg_eol);
35
36 /* This costs ~90 bytes of code, but avoids costly
37 * malloc()[in vasprintf]+realloc()+memmove()+free() in 99% of cases.
38 * ~40% speedup.
39 */
40 if ((int)sizeof(stack_msg) - applet_len > 0) {
41 va_list p2;
42
43 /* It is not portable to use va_list twice, need to va_copy it */
44 va_copy(p2, p);
45 used = vsnprintf(stack_msg + applet_len, (int)sizeof(stack_msg) - applet_len, s, p2);
46 va_end(p2);
47 msg = stack_msg;
48 used += applet_len;
49 if (used < (int)sizeof(stack_msg) - 3 - msgeol_len - strerr_len)
50 goto add_pfx_and_sfx;
51 }
52
31 used = vasprintf(&msg, s, p); 53 used = vasprintf(&msg, s, p);
32 if (used < 0) 54 if (used < 0)
33 return; 55 return;
@@ -37,9 +59,6 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
37 * This is needed for e.g. httpd logging, when multiple 59 * This is needed for e.g. httpd logging, when multiple
38 * children can produce log messages simultaneously. */ 60 * children can produce log messages simultaneously. */
39 61
40 applet_len = strlen(applet_name) + 2; /* "applet: " */
41 strerr_len = strerr ? strlen(strerr) : 0;
42 msgeol_len = strlen(msg_eol);
43 /* can't use xrealloc: it calls error_msg on failure, 62 /* can't use xrealloc: it calls error_msg on failure,
44 * that may result in a recursion */ 63 * that may result in a recursion */
45 /* +3 is for ": " before strerr and for terminating NUL */ 64 /* +3 is for ": " before strerr and for terminating NUL */
@@ -52,6 +71,7 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
52 /* TODO: maybe use writev instead of memmoving? Need full_writev? */ 71 /* TODO: maybe use writev instead of memmoving? Need full_writev? */
53 memmove(msg + applet_len, msg, used); 72 memmove(msg + applet_len, msg, used);
54 used += applet_len; 73 used += applet_len;
74 add_pfx_and_sfx:
55 strcpy(msg, applet_name); 75 strcpy(msg, applet_name);
56 msg[applet_len - 2] = ':'; 76 msg[applet_len - 2] = ':';
57 msg[applet_len - 1] = ' '; 77 msg[applet_len - 1] = ' ';
@@ -76,7 +96,8 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
76 syslog(syslog_level, "%s", msg + applet_len); 96 syslog(syslog_level, "%s", msg + applet_len);
77 } 97 }
78#endif 98#endif
79 free(msg); 99 if (msg != stack_msg)
100 free(msg);
80} 101}
81 102
82#ifdef VERSION_WITH_WRITEV 103#ifdef VERSION_WITH_WRITEV
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 2d3204507..f488f8e0c 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -118,8 +118,6 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
118 118
119 save_nofork_data(&old); 119 save_nofork_data(&old);
120 120
121 applet_name = APPLET_NAME(applet_no);
122
123 xfunc_error_retval = EXIT_FAILURE; 121 xfunc_error_retval = EXIT_FAILURE;
124 122
125 /* In case getopt() or getopt32() was already called: 123 /* In case getopt() or getopt32() was already called:
@@ -159,6 +157,7 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
159 * need argv untouched because they free argv[i]! */ 157 * need argv untouched because they free argv[i]! */
160 char *tmp_argv[argc+1]; 158 char *tmp_argv[argc+1];
161 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); 159 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
160 applet_name = tmp_argv[0];
162 /* Finally we can call NOFORK applet's main() */ 161 /* Finally we can call NOFORK applet's main() */
163 rc = applet_main[applet_no](argc, tmp_argv); 162 rc = applet_main[applet_no](argc, tmp_argv);
164 } else { 163 } else {
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 206edb4a0..3f9a84ad4 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -315,3 +315,15 @@ int FAST_FUNC wait4pid(pid_t pid)
315 return WTERMSIG(status) + 0x180; 315 return WTERMSIG(status) + 0x180;
316 return 0; 316 return 0;
317} 317}
318
319// Useful when we do know that pid is valid, and we just want to wait
320// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
321int FAST_FUNC wait_for_exitstatus(pid_t pid)
322{
323 int exit_status, n;
324
325 n = safe_waitpid(pid, &exit_status, 0);
326 if (n < 0)
327 bb_perror_msg_and_die("waitpid");
328 return exit_status;
329}
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 73488908d..e9222f690 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -390,6 +390,12 @@ void FAST_FUNC xchdir(const char *path)
390 bb_perror_msg_and_die("can't change directory to '%s'", path); 390 bb_perror_msg_and_die("can't change directory to '%s'", path);
391} 391}
392 392
393void FAST_FUNC xfchdir(int fd)
394{
395 if (fchdir(fd))
396 bb_perror_msg_and_die("fchdir");
397}
398
393void FAST_FUNC xchroot(const char *path) 399void FAST_FUNC xchroot(const char *path)
394{ 400{
395 if (chroot(path)) 401 if (chroot(path))
@@ -653,3 +659,19 @@ pid_t FAST_FUNC xfork(void)
653 return pid; 659 return pid;
654} 660}
655#endif 661#endif
662
663void FAST_FUNC xvfork_parent_waits_and_exits(void)
664{
665 pid_t pid;
666
667 fflush_all();
668 pid = xvfork();
669 if (pid > 0) {
670 /* Parent */
671 int exit_status = wait_for_exitstatus(pid);
672 if (WIFSIGNALED(exit_status))
673 kill_myself_with_sig(WTERMSIG(exit_status));
674 _exit(WEXITSTATUS(exit_status));
675 }
676 /* Child continues */
677}