aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2017-08-22 14:56:12 +0100
committerRon Yorston <rmy@pobox.com>2017-08-22 14:56:12 +0100
commitce9af1cc5ea23f754587448cf35b5120c77bfeef (patch)
tree69e5eaba5e75ab909ed92d5045393471b8ff3c13 /libbb
parentc170026700eabb10147dd848c45c06995b43a32e (diff)
parente837a0dbbebf4229306df98fe9ee3b9bb30630c4 (diff)
downloadbusybox-w32-ce9af1cc5ea23f754587448cf35b5120c77bfeef.tar.gz
busybox-w32-ce9af1cc5ea23f754587448cf35b5120c77bfeef.tar.bz2
busybox-w32-ce9af1cc5ea23f754587448cf35b5120c77bfeef.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb')
-rw-r--r--libbb/appletlib.c15
-rw-r--r--libbb/bb_pwd.c3
-rw-r--r--libbb/capability.c126
-rw-r--r--libbb/change_identity.c2
-rw-r--r--libbb/copy_file.c5
-rw-r--r--libbb/correct_password.c2
-rw-r--r--libbb/dump.c2
-rw-r--r--libbb/get_console.c1
-rw-r--r--libbb/getopt32.c198
-rw-r--r--libbb/getopt_allopts.c27
-rw-r--r--libbb/lineedit.c23
-rw-r--r--libbb/parse_config.c27
-rw-r--r--libbb/progress.c2
-rw-r--r--libbb/pw_encrypt_des.c2
-rw-r--r--libbb/run_shell.c2
-rw-r--r--libbb/setup_environment.c2
-rw-r--r--libbb/trim.c12
-rw-r--r--libbb/ubi.c1
-rw-r--r--libbb/vfork_daemon_rexec.c191
-rw-r--r--libbb/xfuncs.c2
20 files changed, 419 insertions, 226 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 401475f18..6330b6f8b 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -34,14 +34,6 @@
34# include <malloc.h> /* for mallopt */ 34# include <malloc.h> /* for mallopt */
35#endif 35#endif
36 36
37#include <sys/prctl.h>
38#ifndef PR_SET_NAME
39#define PR_SET_NAME 15
40#endif
41#ifndef PR_GET_NAME
42#define PR_GET_NAME 16
43#endif
44
45/* Declare <applet>_main() */ 37/* Declare <applet>_main() */
46#define PROTOTYPES 38#define PROTOTYPES
47#include "applets.h" 39#include "applets.h"
@@ -985,8 +977,6 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar
985{ 977{
986 int argc = string_array_len(argv); 978 int argc = string_array_len(argv);
987 979
988 /* Reinit some shared global data */
989 xfunc_error_retval = EXIT_FAILURE;
990 /* 980 /*
991 * We do not use argv[0]: do not want to repeat massaging of 981 * We do not use argv[0]: do not want to repeat massaging of
992 * "-/sbin/halt" -> "halt", for example. 982 * "-/sbin/halt" -> "halt", for example.
@@ -1163,15 +1153,14 @@ int main(int argc UNUSED_PARAM, char **argv)
1163 } 1153 }
1164 applet_name = bb_basename(applet_name); 1154 applet_name = bb_basename(applet_name);
1165 1155
1166# if defined(__linux__)
1167 /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */ 1156 /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */
1168 if (ENABLE_FEATURE_SH_STANDALONE 1157 if (ENABLE_FEATURE_SH_STANDALONE
1169 || ENABLE_FEATURE_PREFER_APPLETS 1158 || ENABLE_FEATURE_PREFER_APPLETS
1170 || !BB_MMU 1159 || !BB_MMU
1171 ) { 1160 ) {
1172 prctl(PR_SET_NAME, (long)applet_name, 0, 0, 0); 1161 if (NUM_APPLETS > 1)
1162 set_task_comm(applet_name);
1173 } 1163 }
1174# endif
1175 1164
1176 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ 1165 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
1177 run_applet_and_exit(applet_name, argv); 1166 run_applet_and_exit(applet_name, argv);
diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c
index 4829b723a..dca0a150b 100644
--- a/libbb/bb_pwd.c
+++ b/libbb/bb_pwd.c
@@ -31,9 +31,9 @@ struct group* FAST_FUNC xgetgrnam(const char *name)
31 return gr; 31 return gr;
32} 32}
33 33
34
35struct passwd* FAST_FUNC xgetpwuid(uid_t uid) 34struct passwd* FAST_FUNC xgetpwuid(uid_t uid)
36{ 35{
36 /* Note: used in nofork applets (whoami), be careful not to leak anything */
37 struct passwd *pw = getpwuid(uid); 37 struct passwd *pw = getpwuid(uid);
38 if (!pw) 38 if (!pw)
39 bb_error_msg_and_die("unknown uid %u", (unsigned)uid); 39 bb_error_msg_and_die("unknown uid %u", (unsigned)uid);
@@ -50,6 +50,7 @@ struct group* FAST_FUNC xgetgrgid(gid_t gid)
50 50
51char* FAST_FUNC xuid2uname(uid_t uid) 51char* FAST_FUNC xuid2uname(uid_t uid)
52{ 52{
53 /* Note: used in nofork applets (whoami), be careful not to leak anything */
53 struct passwd *pw = xgetpwuid(uid); 54 struct passwd *pw = xgetpwuid(uid);
54 return pw->pw_name; 55 return pw->pw_name;
55} 56}
diff --git a/libbb/capability.c b/libbb/capability.c
new file mode 100644
index 000000000..f60062bfc
--- /dev/null
+++ b/libbb/capability.c
@@ -0,0 +1,126 @@
1/*
2 * Copyright (C) 2017 by <assafgordon@gmail.com>
3 *
4 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 */
6//kbuild:lib-$(CONFIG_PLATFORM_LINUX) += capability.o
7
8#include <linux/capability.h>
9// #include <sys/capability.h>
10// This header is in libcap, but the functions are in libc.
11// Comment in the header says this above capset/capget:
12/* system calls - look to libc for function to system call mapping */
13extern int capset(cap_user_header_t header, cap_user_data_t data);
14extern int capget(cap_user_header_t header, const cap_user_data_t data);
15// so for bbox, let's just repeat the declarations.
16// This way, libcap needs not be installed in build environment.
17#include "libbb.h"
18
19static const char *const capabilities[] = {
20 "chown",
21 "dac_override",
22 "dac_read_search",
23 "fowner",
24 "fsetid",
25 "kill",
26 "setgid",
27 "setuid",
28 "setpcap",
29 "linux_immutable",
30 "net_bind_service",
31 "net_broadcast",
32 "net_admin",
33 "net_raw",
34 "ipc_lock",
35 "ipc_owner",
36 "sys_module",
37 "sys_rawio",
38 "sys_chroot",
39 "sys_ptrace",
40 "sys_pacct",
41 "sys_admin",
42 "sys_boot",
43 "sys_nice",
44 "sys_resource",
45 "sys_time",
46 "sys_tty_config",
47 "mknod",
48 "lease",
49 "audit_write",
50 "audit_control",
51 "setfcap",
52 "mac_override",
53 "mac_admin",
54 "syslog",
55 "wake_alarm",
56 "block_suspend",
57 "audit_read",
58};
59
60unsigned FAST_FUNC cap_name_to_number(const char *cap)
61{
62 unsigned i, n;
63
64 if ((sscanf(cap, "cap_%u", &n)) == 1) {
65 i = n;
66 goto found;
67 }
68 for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
69 if (strcasecmp(capabilities[i], cap) != 0)
70 goto found;
71 }
72 bb_error_msg_and_die("unknown capability '%s'", cap);
73
74 found:
75 if (!cap_valid(i))
76 bb_error_msg_and_die("unknown capability '%s'", cap);
77 return i;
78}
79
80void FAST_FUNC printf_cap(const char *pfx, unsigned cap_no)
81{
82 if (cap_no < ARRAY_SIZE(capabilities)) {
83 printf("%s%s", pfx, capabilities[cap_no]);
84 return;
85 }
86 printf("%scap_%u", pfx, cap_no);
87}
88
89DEFINE_STRUCT_CAPS;
90
91void FAST_FUNC getcaps(void *arg)
92{
93 static const uint8_t versions[] = {
94 _LINUX_CAPABILITY_U32S_3, /* = 2 (fits into byte) */
95 _LINUX_CAPABILITY_U32S_2, /* = 2 */
96 _LINUX_CAPABILITY_U32S_1, /* = 1 */
97 };
98 int i;
99 struct caps *caps = arg;
100
101 caps->header.pid = 0;
102 for (i = 0; i < ARRAY_SIZE(versions); i++) {
103 caps->header.version = versions[i];
104 if (capget(&caps->header, NULL) == 0)
105 goto got_it;
106 }
107 bb_simple_perror_msg_and_die("capget");
108 got_it:
109
110 switch (caps->header.version) {
111 case _LINUX_CAPABILITY_VERSION_1:
112 caps->u32s = _LINUX_CAPABILITY_U32S_1;
113 break;
114 case _LINUX_CAPABILITY_VERSION_2:
115 caps->u32s = _LINUX_CAPABILITY_U32S_2;
116 break;
117 case _LINUX_CAPABILITY_VERSION_3:
118 caps->u32s = _LINUX_CAPABILITY_U32S_3;
119 break;
120 default:
121 bb_error_msg_and_die("unsupported capability version");
122 }
123
124 if (capget(&caps->header, caps->data) != 0)
125 bb_simple_perror_msg_and_die("capget");
126}
diff --git a/libbb/change_identity.c b/libbb/change_identity.c
index d48d86326..431f72c8c 100644
--- a/libbb/change_identity.c
+++ b/libbb/change_identity.c
@@ -15,7 +15,7 @@
15 * may be used to endorse or promote products derived from this software 15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission. 16 * without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND 18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE 21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index cb6d12359..5372d8680 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -374,7 +374,10 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
374 int r = symlink(lpath, dest); 374 int r = symlink(lpath, dest);
375 free(lpath); 375 free(lpath);
376 if (r < 0) { 376 if (r < 0) {
377 bb_perror_msg("can't create symlink '%s'", dest); 377 /* shared message */
378 bb_perror_msg("can't create %slink '%s' to '%s'",
379 "sym", dest, lpath
380 );
378 return -1; 381 return -1;
379 } 382 }
380 if (flags & FILEUTILS_PRESERVE_STATUS) 383 if (flags & FILEUTILS_PRESERVE_STATUS)
diff --git a/libbb/correct_password.c b/libbb/correct_password.c
index f4635a5bc..51928f68d 100644
--- a/libbb/correct_password.c
+++ b/libbb/correct_password.c
@@ -15,7 +15,7 @@
15 * may be used to endorse or promote products derived from this software 15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission. 16 * without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND 18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE 21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/dump.c b/libbb/dump.c
index 211a1ed9e..e23b71294 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -828,7 +828,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
828 * may be used to endorse or promote products derived from this software 828 * may be used to endorse or promote products derived from this software
829 * without specific prior written permission. 829 * without specific prior written permission.
830 * 830 *
831 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 831 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
832 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 832 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
833 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 833 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
834 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 834 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/get_console.c b/libbb/get_console.c
index 9b6407bd0..96b339ca7 100644
--- a/libbb/get_console.c
+++ b/libbb/get_console.c
@@ -64,7 +64,6 @@ int FAST_FUNC get_console_fd_or_die(void)
64 } 64 }
65 65
66 bb_error_msg_and_die("can't open console"); 66 bb_error_msg_and_die("can't open console");
67 /*return fd; - total failure */
68} 67}
69 68
70/* From <linux/vt.h> */ 69/* From <linux/vt.h> */
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 80f4cc060..f778c6e89 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -6,12 +6,13 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9#if ENABLE_LONG_OPTS
10#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
11# include <getopt.h> 10# include <getopt.h>
12#endif 11#endif
13#include "libbb.h" 12#include "libbb.h"
14 13
14//kbuild:lib-y += getopt32.o
15
15/* Documentation 16/* Documentation
16 17
17uint32_t 18uint32_t
@@ -95,20 +96,23 @@ getopt32(char **argv, const char *applet_opts, ...)
95 env -i ls -d / 96 env -i ls -d /
96 Here we want env to process just the '-i', not the '-d'. 97 Here we want env to process just the '-i', not the '-d'.
97 98
98 "!" Report bad option, missing required options, 99 "!" Report bad options, missing required options,
99 inconsistent options with all-ones return value (instead of abort). 100 inconsistent options with all-ones return value (instead of abort).
100 101
101const char *applet_long_options 102 "^" options string is "^optchars""\0""opt_complementary".
103
104uint32_t
105getopt32long(char **argv, const char *applet_opts, const char *logopts...)
102 106
103 This struct allows you to define long options: 107 This allows you to define long options:
104 108
105 static const char applet_longopts[] ALIGN1 = 109 static const char applet_longopts[] ALIGN1 =
106 //"name\0" has_arg val 110 //"name\0" has_arg val
107 "verbose\0" No_argument "v" 111 "verbose\0" No_argument "v"
108 ; 112 ;
109 applet_long_options = applet_longopts; 113 opt = getopt32long(argv, applet_opts, applet_longopts, ...);
110 114
111 The last member of struct option (val) typically is set to 115 The last element (val) typically is set to
112 matching short option from applet_opts. If there is no matching 116 matching short option from applet_opts. If there is no matching
113 char in applet_opts, then: 117 char in applet_opts, then:
114 - return bit has next position after short options 118 - return bit has next position after short options
@@ -119,7 +123,7 @@ const char *applet_long_options
119 config process and not a required feature. The current standard 123 config process and not a required feature. The current standard
120 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. 124 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
121 125
122const char *opt_complementary 126opt_complementary - option modifiers.
123 127
124 ":" The colon (":") is used to separate groups of two or more chars 128 ":" The colon (":") is used to separate groups of two or more chars
125 and/or groups of chars and special characters (stating some 129 and/or groups of chars and special characters (stating some
@@ -130,8 +134,7 @@ const char *opt_complementary
130 Their flags will be turned on if the main option is found even 134 Their flags will be turned on if the main option is found even
131 if they are not specified on the command line. For example: 135 if they are not specified on the command line. For example:
132 136
133 opt_complementary = "abc"; 137 flags = getopt32(argv, "^abcd""\0""abc")
134 flags = getopt32(argv, "abcd")
135 138
136 If getopt() finds "-a" on the command line, then 139 If getopt() finds "-a" on the command line, then
137 getopt32's return value will be as if "-a -b -c" were 140 getopt32's return value will be as if "-a -b -c" were
@@ -144,8 +147,7 @@ const char *opt_complementary
144 if w is given more than once, it is "unlimited" 147 if w is given more than once, it is "unlimited"
145 148
146 int w_counter = 0; // must be initialized! 149 int w_counter = 0; // must be initialized!
147 opt_complementary = "ww"; 150 getopt32(argv, "^w""\0""ww", &w_counter);
148 getopt32(argv, "w", &w_counter);
149 if (w_counter) 151 if (w_counter)
150 width = (w_counter == 1) ? 132 : INT_MAX; 152 width = (w_counter == 1) ? 132 : INT_MAX;
151 else 153 else
@@ -160,8 +162,9 @@ const char *opt_complementary
160 162
161 llist_t *my_b = NULL; 163 llist_t *my_b = NULL;
162 int verbose_level = 0; 164 int verbose_level = 0;
163 opt_complementary = "vv:b-c:c-b"; 165 f = getopt32(argv, "^vb:*c"
164 f = getopt32(argv, "vb:*c", &my_b, &verbose_level); 166 "\0""vv:b-c:c-b"
167 , &my_b, &verbose_level);
165 if (f & 2) // -c after -b unsets -b flag 168 if (f & 2) // -c after -b unsets -b flag
166 while (my_b) dosomething_with(llist_pop(&my_b)); 169 while (my_b) dosomething_with(llist_pop(&my_b));
167 if (my_b) // but llist is stored if -b is specified 170 if (my_b) // but llist is stored if -b is specified
@@ -170,31 +173,6 @@ const char *opt_complementary
170 173
171Special characters: 174Special characters:
172 175
173 "-" A group consisting of just a dash forces all arguments
174 to be treated as options, even if they have no leading dashes.
175 Next char in this case can't be a digit (0-9), use ':' or end of line.
176 Example:
177
178 opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work,
179 getopt32(argv, "wx"); // but is less readable
180
181 This makes it possible to use options without a dash (./program w x)
182 as well as with a dash (./program -x).
183
184 NB: getopt32() will leak a small amount of memory if you use
185 this option! Do not use it if there is a possibility of recursive
186 getopt32() calls.
187
188 "--" A double dash at the beginning of opt_complementary means the
189 argv[1] string should always be treated as options, even if it isn't
190 prefixed with a "-". This is useful for special syntax in applets
191 such as "ar" and "tar":
192 tar xvf foo.tar
193
194 NB: getopt32() will leak a small amount of memory if you use
195 this option! Do not use it if there is a possibility of recursive
196 getopt32() calls.
197
198 "-N" A dash as the first char in a opt_complementary group followed 176 "-N" A dash as the first char in a opt_complementary group followed
199 by a single digit (0-9) means that at least N non-option 177 by a single digit (0-9) means that at least N non-option
200 arguments must be present on the command line 178 arguments must be present on the command line
@@ -222,7 +200,7 @@ Special characters:
222 getopt32 finds -s, then -d is unset or if it finds -d 200 getopt32 finds -s, then -d is unset or if it finds -d
223 then -s is unset. (Note: busybox implements the GNU 201 then -s is unset. (Note: busybox implements the GNU
224 "--max-depth" option as "-d".) To obtain this behavior, you 202 "--max-depth" option as "-d".) To obtain this behavior, you
225 set opt_complementary = "s-d:d-s". Only one flag value is 203 set opt_complementary to "s-d:d-s". Only one flag value is
226 added to getopt32's return value depending on the 204 added to getopt32's return value depending on the
227 position of the options on the command line. If one of the 205 position of the options on the command line. If one of the
228 two options requires an argument pointer (":" in applet_opts 206 two options requires an argument pointer (":" in applet_opts
@@ -230,8 +208,7 @@ Special characters:
230 208
231 char *smax_print_depth; 209 char *smax_print_depth;
232 210
233 opt_complementary = "s-d:d-s:x-x"; 211 opt = getopt32(argv, "^sd:x""\0""s-d:d-s:x-x", &smax_print_depth);
234 opt = getopt32(argv, "sd:x", &smax_print_depth);
235 212
236 if (opt & 2) 213 if (opt & 2)
237 max_print_depth = atoi(smax_print_depth); 214 max_print_depth = atoi(smax_print_depth);
@@ -247,7 +224,7 @@ Special characters:
247 The cut applet must have only one type of list specified, so 224 The cut applet must have only one type of list specified, so
248 -b, -c and -f are mutually exclusive and should raise an error 225 -b, -c and -f are mutually exclusive and should raise an error
249 if specified together. In this case you must set 226 if specified together. In this case you must set
250 opt_complementary = "b--cf:c--bf:f--bc". If two of the 227 opt_complementary to "b--cf:c--bf:f--bc". If two of the
251 mutually exclusive options are found, getopt32 will call 228 mutually exclusive options are found, getopt32 will call
252 bb_show_usage() and die. 229 bb_show_usage() and die.
253 230
@@ -259,8 +236,7 @@ Special characters:
259 with xatoi_positive() - allowed range is 0..INT_MAX. 236 with xatoi_positive() - allowed range is 0..INT_MAX.
260 237
261 int param; // "unsigned param;" will also work 238 int param; // "unsigned param;" will also work
262 opt_complementary = "p+"; 239 getopt32(argv, "^p:""\0""p+", &param);
263 getopt32(argv, "p:", &param);
264 240
265 "o::" A double colon after a char in opt_complementary means that the 241 "o::" A double colon after a char in opt_complementary means that the
266 option can occur multiple times. Each occurrence will be saved as 242 option can occur multiple times. Each occurrence will be saved as
@@ -275,8 +251,7 @@ Special characters:
275 (this pointer must be initializated to NULL if the list is empty 251 (this pointer must be initializated to NULL if the list is empty
276 as required by llist_add_to_end(llist_t **old_head, char *new_item).) 252 as required by llist_add_to_end(llist_t **old_head, char *new_item).)
277 253
278 opt_complementary = "e::"; 254 getopt32(argv, "^e:""\0""e::", &patterns);
279 getopt32(argv, "e:", &patterns);
280 255
281 $ grep -e user -e root /etc/passwd 256 $ grep -e user -e root /etc/passwd
282 root:x:0:0:root:/root:/bin/bash 257 root:x:0:0:root:/root:/bin/bash
@@ -294,8 +269,7 @@ Special characters:
294 For example from "id" applet: 269 For example from "id" applet:
295 270
296 // Don't allow -n -r -rn -ug -rug -nug -rnug 271 // Don't allow -n -r -rn -ug -rug -nug -rnug
297 opt_complementary = "r?ug:n?ug:u--g:g--u"; 272 flags = getopt32(argv, "^rnug""\0""r?ug:n?ug:u--g:g--u");
298 flags = getopt32(argv, "rnug");
299 273
300 This example allowed only: 274 This example allowed only:
301 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng 275 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
@@ -306,8 +280,7 @@ Special characters:
306 For example from "start-stop-daemon" applet: 280 For example from "start-stop-daemon" applet:
307 281
308 // Don't allow -KS -SK, but -S or -K is required 282 // Don't allow -KS -SK, but -S or -K is required
309 opt_complementary = "K:S:K--S:S--K"; 283 flags = getopt32(argv, "^KS...""\0""K:S:K--S:S--K");
310 flags = getopt32(argv, "KS...);
311 284
312 285
313 Don't forget to use ':'. For example, "?322-22-23X-x-a" 286 Don't forget to use ':'. For example, "?322-22-23X-x-a"
@@ -322,8 +295,6 @@ Special characters:
322 295
323const char *const bb_argv_dash[] = { "-", NULL }; 296const char *const bb_argv_dash[] = { "-", NULL };
324 297
325const char *opt_complementary;
326
327enum { 298enum {
328 PARAM_STRING, 299 PARAM_STRING,
329 PARAM_LIST, 300 PARAM_LIST,
@@ -341,58 +312,63 @@ typedef struct {
341 int *counter; 312 int *counter;
342} t_complementary; 313} t_complementary;
343 314
344/* You can set applet_long_options for parse called long options */ 315uint32_t option_mask32;
345#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 316
317#if ENABLE_LONG_OPTS
346static const struct option bb_null_long_options[1] = { 318static const struct option bb_null_long_options[1] = {
347 { 0, 0, 0, 0 } 319 { 0, 0, 0, 0 }
348}; 320};
349const char *applet_long_options; 321#else
322#define vgetopt32(argv,applet_opts,applet_long_options,p) \
323 vgetopt32(argv,applet_opts,p)
350#endif 324#endif
351 325
352uint32_t option_mask32; 326/* Please keep getopt32 free from xmalloc */
353 327
354uint32_t FAST_FUNC 328static uint32_t
355getopt32(char **argv, const char *applet_opts, ...) 329vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, va_list p)
356{ 330{
357 int argc; 331 int argc;
358 unsigned flags = 0; 332 unsigned flags = 0;
359 unsigned requires = 0; 333 unsigned requires = 0;
334 unsigned len;
360 t_complementary complementary[33]; /* last stays zero-filled */ 335 t_complementary complementary[33]; /* last stays zero-filled */
361 char first_char; 336 char dont_die_flag;
362 int c; 337 int c;
363 const unsigned char *s; 338 const unsigned char *s;
339 const char *opt_complementary;
364 t_complementary *on_off; 340 t_complementary *on_off;
365 va_list p; 341#if ENABLE_LONG_OPTS
366#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
367 const struct option *l_o; 342 const struct option *l_o;
368 struct option *long_options = (struct option *) &bb_null_long_options; 343 struct option *long_options = (struct option *) &bb_null_long_options;
369#endif 344#endif
370 unsigned trigger; 345 unsigned trigger;
371 char **pargv;
372 int min_arg = 0; 346 int min_arg = 0;
373 int max_arg = -1; 347 int max_arg = -1;
374
375#define SHOW_USAGE_IF_ERROR 1
376#define ALL_ARGV_IS_OPTS 2
377#define FIRST_ARGV_IS_OPT 4
378
379 int spec_flgs = 0; 348 int spec_flgs = 0;
380 349
381 /* skip 0: some applets cheat: they do not actually HAVE argv[0] */ 350#define SHOW_USAGE_IF_ERROR 1
382 argc = 1 + string_array_len(argv + 1);
383
384 va_start(p, applet_opts);
385 351
386 on_off = complementary; 352 on_off = complementary;
387 memset(on_off, 0, sizeof(complementary)); 353 memset(on_off, 0, sizeof(complementary));
388 354
389 applet_opts = strcpy(alloca(strlen(applet_opts) + 1), applet_opts); 355 len = strlen(applet_opts);
390 356
391 /* skip bbox extension */ 357 /* skip bbox extension */
392 first_char = applet_opts[0]; 358 opt_complementary = NULL;
393 if (first_char == '!') 359 if (applet_opts[0] == '^') {
360 applet_opts++;
361 /* point it past terminating NUL */
362 opt_complementary = applet_opts + len;
363 }
364
365 /* skip another bbox extension */
366 dont_die_flag = applet_opts[0];
367 if (dont_die_flag == '!')
394 applet_opts++; 368 applet_opts++;
395 369
370 applet_opts = strcpy(alloca(len + 1), applet_opts);
371
396 /* skip GNU extension */ 372 /* skip GNU extension */
397 s = (const unsigned char *)applet_opts; 373 s = (const unsigned char *)applet_opts;
398 if (*s == '+' || *s == '-') 374 if (*s == '+' || *s == '-')
@@ -419,7 +395,7 @@ getopt32(char **argv, const char *applet_opts, ...)
419 c++; 395 c++;
420 } 396 }
421 397
422#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 398#if ENABLE_LONG_OPTS
423 if (applet_long_options) { 399 if (applet_long_options) {
424 const char *optstr; 400 const char *optstr;
425 unsigned i, count; 401 unsigned i, count;
@@ -458,14 +434,11 @@ getopt32(char **argv, const char *applet_opts, ...)
458 c++; 434 c++;
459 next_long: ; 435 next_long: ;
460 } 436 }
461 /* Make it unnecessary to clear applet_long_options
462 * by hand after each call to getopt32
463 */
464 applet_long_options = NULL;
465 } 437 }
466#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */ 438#endif /* ENABLE_LONG_OPTS */
467 439
468 for (s = (const unsigned char *)opt_complementary; s && *s; s++) { 440 s = (const unsigned char *)opt_complementary;
441 if (s) for (; *s; s++) {
469 t_complementary *pair; 442 t_complementary *pair;
470 unsigned *pair_switch; 443 unsigned *pair_switch;
471 444
@@ -482,13 +455,7 @@ getopt32(char **argv, const char *applet_opts, ...)
482 continue; 455 continue;
483 } 456 }
484 if (*s == '-') { 457 if (*s == '-') {
485 if (c < '0' || c > '9') { 458 if (c >= '0' && c <= '9') {
486 if (c == '-') {
487 spec_flgs |= FIRST_ARGV_IS_OPT;
488 s++;
489 } else
490 spec_flgs |= ALL_ARGV_IS_OPTS;
491 } else {
492 min_arg = c - '0'; 459 min_arg = c - '0';
493 s++; 460 s++;
494 } 461 }
@@ -548,26 +515,6 @@ getopt32(char **argv, const char *applet_opts, ...)
548 } 515 }
549 s--; 516 s--;
550 } 517 }
551 opt_complementary = NULL;
552 va_end(p);
553
554 if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) {
555 pargv = argv + 1;
556 while (*pargv) {
557 if (pargv[0][0] != '-' && pargv[0][0] != '\0') {
558 /* Can't use alloca: opts with params will
559 * return pointers to stack!
560 * NB: we leak these allocations... */
561 char *pp = xmalloc(strlen(*pargv) + 2);
562 *pp = '-';
563 strcpy(pp + 1, *pargv);
564 *pargv = pp;
565 }
566 if (!(spec_flgs & ALL_ARGV_IS_OPTS))
567 break;
568 pargv++;
569 }
570 }
571 518
572 /* In case getopt32 was already called: 519 /* In case getopt32 was already called:
573 * reset the libc getopt() function, which keeps internal state. 520 * reset the libc getopt() function, which keeps internal state.
@@ -576,11 +523,14 @@ getopt32(char **argv, const char *applet_opts, ...)
576 */ 523 */
577 GETOPT_RESET(); 524 GETOPT_RESET();
578 525
526 /* skip 0: some applets cheat: they do not actually HAVE argv[0] */
527 argc = 1 + string_array_len(argv + 1);
528
579 /* Note: just "getopt() <= 0" will not work well for 529 /* Note: just "getopt() <= 0" will not work well for
580 * "fake" short options, like this one: 530 * "fake" short options, like this one:
581 * wget $'-\203' "Test: test" http://kernel.org/ 531 * wget $'-\203' "Test: test" http://kernel.org/
582 * (supposed to act as --header, but doesn't) */ 532 * (supposed to act as --header, but doesn't) */
583#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 533#if ENABLE_LONG_OPTS
584 while ((c = getopt_long(argc, argv, applet_opts, 534 while ((c = getopt_long(argc, argv, applet_opts,
585 long_options, NULL)) != -1) { 535 long_options, NULL)) != -1) {
586#else 536#else
@@ -637,7 +587,33 @@ getopt32(char **argv, const char *applet_opts, ...)
637 return flags; 587 return flags;
638 588
639 error: 589 error:
640 if (first_char != '!') 590 if (dont_die_flag != '!')
641 bb_show_usage(); 591 bb_show_usage();
642 return (int32_t)-1; 592 return (int32_t)-1;
643} 593}
594
595uint32_t FAST_FUNC
596getopt32(char **argv, const char *applet_opts, ...)
597{
598 uint32_t opt;
599 va_list p;
600
601 va_start(p, applet_opts);
602 opt = vgetopt32(argv, applet_opts, NULL, p);
603 va_end(p);
604 return opt;
605}
606
607#if ENABLE_LONG_OPTS
608uint32_t FAST_FUNC
609getopt32long(char **argv, const char *applet_opts, const char *longopts, ...)
610{
611 uint32_t opt;
612 va_list p;
613
614 va_start(p, longopts);
615 opt = vgetopt32(argv, applet_opts, longopts, p);
616 va_end(p);
617 return opt;
618}
619#endif
diff --git a/libbb/getopt_allopts.c b/libbb/getopt_allopts.c
new file mode 100644
index 000000000..a67d2b70e
--- /dev/null
+++ b/libbb/getopt_allopts.c
@@ -0,0 +1,27 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2017 Denys Vlasenko
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */
7#include "libbb.h"
8
9//kbuild:lib-y += getopt_allopts.o
10
11void FAST_FUNC make_all_argv_opts(char **argv)
12{
13 /* Note: we skip argv[0] */
14 while (*++argv) {
15 char *p;
16
17 if (argv[0][0] == '-')
18 continue;
19 /* Neither top nor ps care if "" arg turns into "-" */
20 /*if (argv[0][0] == '\0')
21 continue;*/
22 p = xmalloc(strlen(*argv) + 2);
23 *p = '-';
24 strcpy(p + 1, *argv);
25 *argv = p;
26 }
27}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 051a39b2e..c2b0a3842 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1320,6 +1320,7 @@ line_input_t* FAST_FUNC new_line_input_t(int flags)
1320{ 1320{
1321 line_input_t *n = xzalloc(sizeof(*n)); 1321 line_input_t *n = xzalloc(sizeof(*n));
1322 n->flags = flags; 1322 n->flags = flags;
1323 n->timeout = -1;
1323#if MAX_HISTORY > 0 1324#if MAX_HISTORY > 0
1324 n->max_history = MAX_HISTORY; 1325 n->max_history = MAX_HISTORY;
1325#endif 1326#endif
@@ -2192,7 +2193,7 @@ enum {
2192 * Backspace deletes last matched char. 2193 * Backspace deletes last matched char.
2193 * Control keys exit search and return to normal editing (at current history line). 2194 * Control keys exit search and return to normal editing (at current history line).
2194 */ 2195 */
2195static int32_t reverse_i_search(void) 2196static int32_t reverse_i_search(int timeout)
2196{ 2197{
2197 char match_buf[128]; /* for user input */ 2198 char match_buf[128]; /* for user input */
2198 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 2199 char read_key_buffer[KEYCODE_BUFFER_SIZE];
@@ -2214,8 +2215,8 @@ static int32_t reverse_i_search(void)
2214 int h; 2215 int h;
2215 unsigned match_buf_len = strlen(match_buf); 2216 unsigned match_buf_len = strlen(match_buf);
2216 2217
2217//FIXME: correct timeout? 2218//FIXME: correct timeout? (i.e. count it down?)
2218 ic = lineedit_read_key(read_key_buffer, -1); 2219 ic = lineedit_read_key(read_key_buffer, timeout);
2219 2220
2220 switch (ic) { 2221 switch (ic) {
2221 case CTRL('R'): /* searching for the next match */ 2222 case CTRL('R'): /* searching for the next match */
@@ -2318,9 +2319,10 @@ static int32_t reverse_i_search(void)
2318 * (in both cases the cursor remains on the input line, '\n' is not printed) 2319 * (in both cases the cursor remains on the input line, '\n' is not printed)
2319 * >0 length of input string, including terminating '\n' 2320 * >0 length of input string, including terminating '\n'
2320 */ 2321 */
2321int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) 2322int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize)
2322{ 2323{
2323 int len; 2324 int len;
2325 int timeout;
2324#if ENABLE_FEATURE_TAB_COMPLETION 2326#if ENABLE_FEATURE_TAB_COMPLETION
2325 smallint lastWasTab = 0; 2327 smallint lastWasTab = 0;
2326#endif 2328#endif
@@ -2366,8 +2368,15 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2366 maxsize = MAX_LINELEN; 2368 maxsize = MAX_LINELEN;
2367 S.maxsize = maxsize; 2369 S.maxsize = maxsize;
2368 2370
2369 /* With zero flags, no other fields are ever used */ 2371 timeout = -1;
2370 state = st ? st : (line_input_t*) &const_int_0; 2372 /* Make state->flags == 0 if st is NULL.
2373 * With zeroed flags, no other fields are ever referenced.
2374 */
2375 state = (line_input_t*) &const_int_0;
2376 if (st) {
2377 state = st;
2378 timeout = st->timeout;
2379 }
2371#if MAX_HISTORY > 0 2380#if MAX_HISTORY > 0
2372# if ENABLE_FEATURE_EDITING_SAVEHISTORY 2381# if ENABLE_FEATURE_EDITING_SAVEHISTORY
2373 if (state->hist_file) 2382 if (state->hist_file)
@@ -2584,7 +2593,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2584 } 2593 }
2585#if ENABLE_FEATURE_REVERSE_SEARCH 2594#if ENABLE_FEATURE_REVERSE_SEARCH
2586 case CTRL('R'): 2595 case CTRL('R'):
2587 ic = ic_raw = reverse_i_search(); 2596 ic = ic_raw = reverse_i_search(timeout);
2588 goto again; 2597 goto again;
2589#endif 2598#endif
2590 2599
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index 307ae2cd2..8701b010c 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -42,8 +42,9 @@ int parse_main(int argc UNUSED_PARAM, char **argv)
42 int mintokens = 0, ntokens = 128; 42 int mintokens = 0, ntokens = 128;
43 unsigned noout; 43 unsigned noout;
44 44
45 opt_complementary = "-1"; 45 noout = 1 & getopt32(argv, "^" "xn:+m:+d:f:+" "\0" "-1",
46 noout = 1 & getopt32(argv, "xn:+m:+d:f:+", &ntokens, &mintokens, &delims, &flags); 46 &ntokens, &mintokens, &delims, &flags
47 );
47 //argc -= optind; 48 //argc -= optind;
48 argv += optind; 49 argv += optind;
49 50
@@ -161,13 +162,18 @@ mintokens > 0 make config_read() print error message if less than mintokens
161#undef config_read 162#undef config_read
162int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) 163int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims)
163{ 164{
164 char *line; 165 char *line, *p;
165 int ntokens, mintokens; 166 int ntokens, mintokens;
166 int t; 167 int t;
168 char alt_comment_ch;
167 169
168 if (!parser) 170 if (!parser)
169 return 0; 171 return 0;
170 172
173 alt_comment_ch = '\0';
174 if (flags & PARSE_ALT_COMMENTS)
175 alt_comment_ch = *delims++;
176
171 ntokens = (uint8_t)flags; 177 ntokens = (uint8_t)flags;
172 mintokens = (uint8_t)(flags >> 8); 178 mintokens = (uint8_t)(flags >> 8);
173 179
@@ -184,7 +190,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
184 if (flags & PARSE_TRIM) 190 if (flags & PARSE_TRIM)
185 line += strspn(line, delims + 1); 191 line += strspn(line, delims + 1);
186 192
187 if (line[0] == '\0' || line[0] == delims[0]) 193 p = line;
194 if (flags & PARSE_WS_COMMENTS)
195 p = skip_whitespace(p);
196 if (p[0] == '\0' || p[0] == delims[0] || p[0] == alt_comment_ch)
188 goto again; 197 goto again;
189 198
190 if (flags & PARSE_KEEP_COPY) { 199 if (flags & PARSE_KEEP_COPY) {
@@ -201,10 +210,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
201 /* Combine remaining arguments? */ 210 /* Combine remaining arguments? */
202 if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) { 211 if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) {
203 /* Vanilla token, find next delimiter */ 212 /* Vanilla token, find next delimiter */
204 line += strcspn(line, delims[0] ? delims : delims + 1); 213 line += strcspn(line, (delims[0] && (flags & PARSE_EOL_COMMENTS)) ? delims : delims + 1);
205 } else { 214 } else {
206 /* Combining, find comment char if any */ 215 /* Combining, find comment char if any */
207 line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0'); 216 line = strchrnul(line, (flags & PARSE_EOL_COMMENTS) ? delims[0] : '\0');
208 217
209 /* Trim any extra delimiters from the end */ 218 /* Trim any extra delimiters from the end */
210 if (flags & PARSE_TRIM) { 219 if (flags & PARSE_TRIM) {
@@ -214,10 +223,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
214 } 223 }
215 224
216 /* Token not terminated? */ 225 /* Token not terminated? */
217 if (*line == delims[0]) 226 if ((flags & PARSE_EOL_COMMENTS) && *line == delims[0])
218 *line = '\0'; 227 *line = '\0'; /* ends with comment char: this line is done */
219 else if (*line != '\0') 228 else if (*line != '\0')
220 *line++ = '\0'; 229 *line++ = '\0'; /* token is done, continue parsing line */
221 230
222#if 0 /* unused so far */ 231#if 0 /* unused so far */
223 if (flags & PARSE_ESCAPE) { 232 if (flags & PARSE_ESCAPE) {
diff --git a/libbb/progress.c b/libbb/progress.c
index 3c2f01667..64e6529ac 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -25,7 +25,7 @@
25 * may be used to endorse or promote products derived from this software 25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission. 26 * without specific prior written permission.
27 * 27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index c8e02ddff..19a9ab15b 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -24,7 +24,7 @@
24 * may be used to endorse or promote products derived from this software 24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission. 25 * without specific prior written permission.
26 * 26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/run_shell.c b/libbb/run_shell.c
index b6b9360e8..3bb58bb6f 100644
--- a/libbb/run_shell.c
+++ b/libbb/run_shell.c
@@ -15,7 +15,7 @@
15 * may be used to endorse or promote products derived from this software 15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission. 16 * without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND 18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE 21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c
index 944ac5538..7ac22cd92 100644
--- a/libbb/setup_environment.c
+++ b/libbb/setup_environment.c
@@ -15,7 +15,7 @@
15 * may be used to endorse or promote products derived from this software 15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission. 16 * without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND 18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE 21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
diff --git a/libbb/trim.c b/libbb/trim.c
index 16cb4fbb0..e47fec74e 100644
--- a/libbb/trim.c
+++ b/libbb/trim.c
@@ -10,9 +10,10 @@
10 10
11#include "libbb.h" 11#include "libbb.h"
12 12
13void FAST_FUNC trim(char *s) 13char* FAST_FUNC trim(char *s)
14{ 14{
15 size_t len = strlen(s); 15 size_t len = strlen(s);
16 size_t old = len;
16 17
17 /* trim trailing whitespace */ 18 /* trim trailing whitespace */
18 while (len && isspace(s[len-1])) 19 while (len && isspace(s[len-1]))
@@ -26,5 +27,12 @@ void FAST_FUNC trim(char *s)
26 memmove(s, nws, len); 27 memmove(s, nws, len);
27 } 28 }
28 } 29 }
29 s[len] = '\0'; 30
31 s += len;
32 /* If it was a "const char*" which does not need trimming,
33 * avoid superfluous store */
34 if (old != len)
35 *s = '\0';
36
37 return s;
30} 38}
diff --git a/libbb/ubi.c b/libbb/ubi.c
index 34595d797..a90016acf 100644
--- a/libbb/ubi.c
+++ b/libbb/ubi.c
@@ -35,6 +35,7 @@ int FAST_FUNC ubi_get_volid_by_name(unsigned ubi_devnum, const char *vol_name)
35 if (open_read_close(fname, buf, sizeof(buf)) <= 0) 35 if (open_read_close(fname, buf, sizeof(buf)) <= 0)
36 continue; 36 continue;
37 37
38 buf[UBI_MAX_VOLUME_NAME] = '\0';
38 strchrnul(buf, '\n')[0] = '\0'; 39 strchrnul(buf, '\n')[0] = '\0';
39 if (strcmp(vol_name, buf) == 0) 40 if (strcmp(vol_name, buf) == 0)
40 return i; 41 return i;
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 4b3ed5a3b..eca2fabf5 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -14,78 +14,46 @@
14 * 14 *
15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 15 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
16 */ 16 */
17#include <sys/prctl.h>
18#ifndef PR_SET_NAME
19#define PR_SET_NAME 15
20#endif
21#ifndef PR_GET_NAME
22#define PR_GET_NAME 16
23#endif
17 24
18#include "busybox.h" /* uses applet tables */ 25#include "busybox.h" /* uses applet tables */
19#include "NUM_APPLETS.h" 26#include "NUM_APPLETS.h"
20 27
21#if !ENABLE_PLATFORM_MINGW32 28#define NOFORK_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_NOFORK))
22/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 29#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE))
23 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
24pid_t FAST_FUNC spawn(char **argv)
25{
26 /* Compiler should not optimize stores here */
27 volatile int failed;
28 pid_t pid;
29
30 fflush_all();
31
32 /* Be nice to nommu machines. */
33 failed = 0;
34 pid = vfork();
35 if (pid < 0) /* error */
36 return pid;
37 if (!pid) { /* child */
38 /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
39 BB_EXECVP(argv[0], argv);
40
41 /* We are (maybe) sharing a stack with blocked parent,
42 * let parent know we failed and then exit to unblock parent
43 * (but don't run atexit() stuff, which would screw up parent.)
44 */
45 failed = errno;
46 /* mount, for example, does not want the message */
47 /*bb_perror_msg("can't execute '%s'", argv[0]);*/
48 _exit(111);
49 }
50 /* parent */
51 /* Unfortunately, this is not reliable: according to standards
52 * vfork() can be equivalent to fork() and we won't see value
53 * of 'failed'.
54 * Interested party can wait on pid and learn exit code.
55 * If 111 - then it (most probably) failed to exec */
56 if (failed) {
57 safe_waitpid(pid, NULL, 0); /* prevent zombie */
58 errno = failed;
59 return -1;
60 }
61 return pid;
62}
63#endif
64 30
65/* Die with an error message if we can't spawn a child process. */ 31#if defined(__linux__) && (NUM_APPLETS > 1)
66pid_t FAST_FUNC xspawn(char **argv) 32void FAST_FUNC set_task_comm(const char *comm)
67{ 33{
68 pid_t pid = spawn(argv); 34 /* okay if too long (truncates) */
69 if (pid < 0) 35 prctl(PR_SET_NAME, (long)comm, 0, 0, 0);
70 bb_simple_perror_msg_and_die(*argv);
71 return pid;
72} 36}
37#endif
73 38
74#if ENABLE_FEATURE_PREFER_APPLETS \ 39/*
75 || ENABLE_FEATURE_SH_NOFORK 40 * NOFORK/NOEXEC support
41 */
42#if NOFORK_SUPPORT
76static jmp_buf die_jmp; 43static jmp_buf die_jmp;
77static void jump(void) 44static void jump(void)
78{ 45{
79 /* Special case. We arrive here if NOFORK applet 46 /* Special case. We arrive here if NOFORK applet
80 * calls xfunc, which then decides to die. 47 * calls xfunc, which then decides to die.
81 * We don't die, but jump instead back to caller. 48 * We don't die, but instead jump back to caller.
82 * NOFORK applets still cannot carelessly call xfuncs: 49 * NOFORK applets still cannot carelessly call xfuncs:
83 * p = xmalloc(10); 50 * p = xmalloc(10);
84 * q = xmalloc(10); // BUG! if this dies, we leak p! 51 * q = xmalloc(10); // BUG! if this dies, we leak p!
85 */ 52 */
86 /* | 0x100 allows to pass zero exitcode (longjmp can't pass 0). 53 /* | 0x100 allows to pass zero exitcode (longjmp can't pass 0).
87 * This works because exitcodes are bytes, 54 * This works because exitcodes are bytes,
88 * run_nofork_applet() ensures that by "& 0xff" */ 55 * run_nofork_applet() ensures that by "& 0xff"
56 */
89 longjmp(die_jmp, xfunc_error_retval | 0x100); 57 longjmp(die_jmp, xfunc_error_retval | 0x100);
90} 58}
91 59
@@ -94,6 +62,7 @@ struct nofork_save_area {
94 void (*die_func)(void); 62 void (*die_func)(void);
95 const char *applet_name; 63 const char *applet_name;
96 uint32_t option_mask32; 64 uint32_t option_mask32;
65 smallint logmode;
97 uint8_t xfunc_error_retval; 66 uint8_t xfunc_error_retval;
98}; 67};
99static void save_nofork_data(struct nofork_save_area *save) 68static void save_nofork_data(struct nofork_save_area *save)
@@ -102,6 +71,7 @@ static void save_nofork_data(struct nofork_save_area *save)
102 save->die_func = die_func; 71 save->die_func = die_func;
103 save->applet_name = applet_name; 72 save->applet_name = applet_name;
104 save->option_mask32 = option_mask32; 73 save->option_mask32 = option_mask32;
74 save->logmode = logmode;
105 save->xfunc_error_retval = xfunc_error_retval; 75 save->xfunc_error_retval = xfunc_error_retval;
106} 76}
107static void restore_nofork_data(struct nofork_save_area *save) 77static void restore_nofork_data(struct nofork_save_area *save)
@@ -110,6 +80,7 @@ static void restore_nofork_data(struct nofork_save_area *save)
110 die_func = save->die_func; 80 die_func = save->die_func;
111 applet_name = save->applet_name; 81 applet_name = save->applet_name;
112 option_mask32 = save->option_mask32; 82 option_mask32 = save->option_mask32;
83 logmode = save->logmode;
113 xfunc_error_retval = save->xfunc_error_retval; 84 xfunc_error_retval = save->xfunc_error_retval;
114} 85}
115 86
@@ -120,16 +91,15 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
120 91
121 save_nofork_data(&old); 92 save_nofork_data(&old);
122 93
94 logmode = LOGMODE_STDIO;
123 xfunc_error_retval = EXIT_FAILURE; 95 xfunc_error_retval = EXIT_FAILURE;
124 96 /* In case getopt() was already called:
125 /* In case getopt() or getopt32() was already called:
126 * reset the libc getopt() function, which keeps internal state. 97 * reset the libc getopt() function, which keeps internal state.
98 * (getopt32() does it itself, but getopt() doesn't (and can't))
127 */ 99 */
128 GETOPT_RESET(); 100 GETOPT_RESET();
129 101
130 argc = 1; 102 argc = string_array_len(argv);
131 while (argv[argc])
132 argc++;
133 103
134 /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */ 104 /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */
135 die_func = jump; 105 die_func = jump;
@@ -142,19 +112,97 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
142 applet_name = tmp_argv[0]; 112 applet_name = tmp_argv[0];
143 /* Finally we can call NOFORK applet's main() */ 113 /* Finally we can call NOFORK applet's main() */
144 rc = applet_main[applet_no](argc, tmp_argv); 114 rc = applet_main[applet_no](argc, tmp_argv);
115 /* Important for shells: `which CMD` was failing */
116 fflush_all();
145 } else { 117 } else {
146 /* xfunc died in NOFORK applet */ 118 /* xfunc died in NOFORK applet */
147 } 119 }
148 120
149 /* Restoring some globals */ 121 /* Restoring some globals */
150 restore_nofork_data(&old); 122 restore_nofork_data(&old);
151
152 /* Other globals can be simply reset to defaults */ 123 /* Other globals can be simply reset to defaults */
153 GETOPT_RESET(); 124 GETOPT_RESET();
154 125
155 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ 126 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
156} 127}
157#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ 128#endif
129
130#if NOEXEC_SUPPORT
131void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
132{
133 /* reset some state and run without execing */
134 /* msg_eol = "\n"; - no caller needs this reinited yet */
135 logmode = LOGMODE_STDIO;
136 xfunc_error_retval = EXIT_FAILURE;
137 die_func = NULL;
138 GETOPT_RESET();
139
140//TODO: think pidof, pgrep, pkill!
141//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"),
142//but one from procps-ng-3.3.10 needs more!
143//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!)
144 set_task_comm(name);
145 /* applet_name is set by this function: */
146 run_applet_no_and_exit(a, name, argv);
147}
148#endif
149
150/*
151 * Higher-level code, hiding optional NOFORK/NOEXEC trickery.
152 */
153
154#if !ENABLE_PLATFORM_MINGW32
155/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
156 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
157pid_t FAST_FUNC spawn(char **argv)
158{
159 /* Compiler should not optimize stores here */
160 volatile int failed;
161 pid_t pid;
162
163 fflush_all();
164
165 /* Be nice to nommu machines. */
166 failed = 0;
167 pid = vfork();
168 if (pid < 0) /* error */
169 return pid;
170 if (!pid) { /* child */
171 /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
172 BB_EXECVP(argv[0], argv);
173
174 /* We are (maybe) sharing a stack with blocked parent,
175 * let parent know we failed and then exit to unblock parent
176 * (but don't run atexit() stuff, which would screw up parent.)
177 */
178 failed = errno;
179 /* mount, for example, does not want the message */
180 /*bb_perror_msg("can't execute '%s'", argv[0]);*/
181 _exit(111);
182 }
183 /* parent */
184 /* Unfortunately, this is not reliable: according to standards
185 * vfork() can be equivalent to fork() and we won't see value
186 * of 'failed'.
187 * Interested party can wait on pid and learn exit code.
188 * If 111 - then it (most probably) failed to exec */
189 if (failed) {
190 safe_waitpid(pid, NULL, 0); /* prevent zombie */
191 errno = failed;
192 return -1;
193 }
194 return pid;
195}
196#endif
197
198/* Die with an error message if we can't spawn a child process. */
199pid_t FAST_FUNC xspawn(char **argv)
200{
201 pid_t pid = spawn(argv);
202 if (pid < 0)
203 bb_simple_perror_msg_and_die(*argv);
204 return pid;
205}
158 206
159int FAST_FUNC spawn_and_wait(char **argv) 207int FAST_FUNC spawn_and_wait(char **argv)
160{ 208{
@@ -174,21 +222,12 @@ int FAST_FUNC spawn_and_wait(char **argv)
174 return wait4pid(rc); 222 return wait4pid(rc);
175 223
176 /* child */ 224 /* child */
177 /* reset some state and run without execing */ 225 run_noexec_applet_and_exit(a, argv[0], argv);
178
179 /* msg_eol = "\n"; - no caller needs this reinited yet */
180 logmode = LOGMODE_STDIO;
181 /* die_func = NULL; - needed if the caller is a shell,
182 * init, or a NOFORK applet. But none of those call us
183 * as of yet (and that should probably always stay true).
184 */
185 /* xfunc_error_retval and applet_name are init by: */
186 run_applet_no_and_exit(a, argv[0], argv);
187 } 226 }
188# endif 227# endif
189# endif 228# endif
190 } 229 }
191#endif /* FEATURE_PREFER_APPLETS */ 230#endif
192 rc = spawn(argv); 231 rc = spawn(argv);
193 return wait4pid(rc); 232 return wait4pid(rc);
194} 233}
@@ -209,6 +248,9 @@ pid_t FAST_FUNC fork_or_rexec(char **argv)
209 /* Maybe we are already re-execed and come here again? */ 248 /* Maybe we are already re-execed and come here again? */
210 if (re_execed) 249 if (re_execed)
211 return 0; 250 return 0;
251
252 /* fflush_all(); ? - so far all callers had no buffered output to flush */
253
212 pid = xvfork(); 254 pid = xvfork();
213 if (pid) /* parent */ 255 if (pid) /* parent */
214 return pid; 256 return pid;
@@ -245,8 +287,11 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
245 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ 287 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
246 288
247 if (!(flags & DAEMON_ONLY_SANITIZE)) { 289 if (!(flags & DAEMON_ONLY_SANITIZE)) {
290
291 /* fflush_all(); - add it in fork_or_rexec() if necessary */
292
248 if (fork_or_rexec(argv)) 293 if (fork_or_rexec(argv))
249 exit(EXIT_SUCCESS); /* parent */ 294 _exit(EXIT_SUCCESS); /* parent */
250 /* if daemonizing, detach from stdio & ctty */ 295 /* if daemonizing, detach from stdio & ctty */
251 setsid(); 296 setsid();
252 dup2(fd, 0); 297 dup2(fd, 0);
@@ -258,7 +303,7 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
258 * Prevent this: stop being a session leader. 303 * Prevent this: stop being a session leader.
259 */ 304 */
260 if (fork_or_rexec(argv)) 305 if (fork_or_rexec(argv))
261 exit(EXIT_SUCCESS); /* parent */ 306 _exit(EXIT_SUCCESS); /* parent */
262 } 307 }
263 } 308 }
264 while (fd > 2) { 309 while (fd > 2) {
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 98d3531d6..1b3a1667b 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -313,7 +313,7 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
313 313
314int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) 314int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags)
315{ 315{
316//TODO: lineedit, microcom and less might be adapted to use this too: 316//TODO: lineedit, microcom, slattach, less might be adapted to use this too:
317// grep for "tcsetattr" 317// grep for "tcsetattr"
318 318
319 struct termios newterm; 319 struct termios newterm;