diff options
author | Ron Yorston <rmy@pobox.com> | 2017-08-22 14:56:12 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2017-08-22 14:56:12 +0100 |
commit | ce9af1cc5ea23f754587448cf35b5120c77bfeef (patch) | |
tree | 69e5eaba5e75ab909ed92d5045393471b8ff3c13 /libbb | |
parent | c170026700eabb10147dd848c45c06995b43a32e (diff) | |
parent | e837a0dbbebf4229306df98fe9ee3b9bb30630c4 (diff) | |
download | busybox-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.c | 15 | ||||
-rw-r--r-- | libbb/bb_pwd.c | 3 | ||||
-rw-r--r-- | libbb/capability.c | 126 | ||||
-rw-r--r-- | libbb/change_identity.c | 2 | ||||
-rw-r--r-- | libbb/copy_file.c | 5 | ||||
-rw-r--r-- | libbb/correct_password.c | 2 | ||||
-rw-r--r-- | libbb/dump.c | 2 | ||||
-rw-r--r-- | libbb/get_console.c | 1 | ||||
-rw-r--r-- | libbb/getopt32.c | 198 | ||||
-rw-r--r-- | libbb/getopt_allopts.c | 27 | ||||
-rw-r--r-- | libbb/lineedit.c | 23 | ||||
-rw-r--r-- | libbb/parse_config.c | 27 | ||||
-rw-r--r-- | libbb/progress.c | 2 | ||||
-rw-r--r-- | libbb/pw_encrypt_des.c | 2 | ||||
-rw-r--r-- | libbb/run_shell.c | 2 | ||||
-rw-r--r-- | libbb/setup_environment.c | 2 | ||||
-rw-r--r-- | libbb/trim.c | 12 | ||||
-rw-r--r-- | libbb/ubi.c | 1 | ||||
-rw-r--r-- | libbb/vfork_daemon_rexec.c | 191 | ||||
-rw-r--r-- | libbb/xfuncs.c | 2 |
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 | |||
35 | struct passwd* FAST_FUNC xgetpwuid(uid_t uid) | 34 | struct 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 | ||
51 | char* FAST_FUNC xuid2uname(uid_t uid) | 51 | char* 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 */ | ||
13 | extern int capset(cap_user_header_t header, cap_user_data_t data); | ||
14 | extern 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 | |||
19 | static 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 | |||
60 | unsigned 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 | |||
80 | void 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 | |||
89 | DEFINE_STRUCT_CAPS; | ||
90 | |||
91 | void 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 | ||
17 | uint32_t | 18 | uint32_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 | ||
101 | const char *applet_long_options | 102 | "^" options string is "^optchars""\0""opt_complementary". |
103 | |||
104 | uint32_t | ||
105 | getopt32long(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 | ||
122 | const char *opt_complementary | 126 | opt_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 | ||
171 | Special characters: | 174 | Special 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+", ¶m); |
263 | getopt32(argv, "p:", ¶m); | ||
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 | ||
323 | const char *const bb_argv_dash[] = { "-", NULL }; | 296 | const char *const bb_argv_dash[] = { "-", NULL }; |
324 | 297 | ||
325 | const char *opt_complementary; | ||
326 | |||
327 | enum { | 298 | enum { |
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 */ | 315 | uint32_t option_mask32; |
345 | #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG | 316 | |
317 | #if ENABLE_LONG_OPTS | ||
346 | static const struct option bb_null_long_options[1] = { | 318 | static const struct option bb_null_long_options[1] = { |
347 | { 0, 0, 0, 0 } | 319 | { 0, 0, 0, 0 } |
348 | }; | 320 | }; |
349 | const 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 | ||
352 | uint32_t option_mask32; | 326 | /* Please keep getopt32 free from xmalloc */ |
353 | 327 | ||
354 | uint32_t FAST_FUNC | 328 | static uint32_t |
355 | getopt32(char **argv, const char *applet_opts, ...) | 329 | vgetopt32(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 | |||
595 | uint32_t FAST_FUNC | ||
596 | getopt32(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 | ||
608 | uint32_t FAST_FUNC | ||
609 | getopt32long(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 | |||
11 | void 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 | */ |
2195 | static int32_t reverse_i_search(void) | 2196 | static 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 | */ |
2321 | int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) | 2322 | int 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 |
162 | int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) | 163 | int 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 | ||
13 | void FAST_FUNC trim(char *s) | 13 | char* 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. */ | ||
24 | pid_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) |
66 | pid_t FAST_FUNC xspawn(char **argv) | 32 | void 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 | ||
76 | static jmp_buf die_jmp; | 43 | static jmp_buf die_jmp; |
77 | static void jump(void) | 44 | static 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 | }; |
99 | static void save_nofork_data(struct nofork_save_area *save) | 68 | static 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 | } |
107 | static void restore_nofork_data(struct nofork_save_area *save) | 77 | static 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 | ||
131 | void 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. */ | ||
157 | pid_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. */ | ||
199 | pid_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 | ||
159 | int FAST_FUNC spawn_and_wait(char **argv) | 207 | int 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 | ||
314 | int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) | 314 | int 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; |