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 | |
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
342 files changed, 4878 insertions, 2519 deletions
@@ -51,6 +51,19 @@ config EXTRA_COMPAT | |||
51 | some GNU extensions in libc. You probably only need this option | 51 | some GNU extensions in libc. You probably only need this option |
52 | if you plan to run busybox on desktop. | 52 | if you plan to run busybox on desktop. |
53 | 53 | ||
54 | config FEDORA_COMPAT | ||
55 | bool "Building for Fedora distribution" | ||
56 | default n | ||
57 | help | ||
58 | This option makes some tools behave like they do on Fedora. | ||
59 | |||
60 | At the time of this writing (2017-08) this only affects uname: | ||
61 | normally, uname -p (processor) and uname -i (platform) | ||
62 | are shown as "unknown", but with this option uname -p | ||
63 | shows the same string as uname -m (machine type), | ||
64 | and so does uname -i unless machine type is i486/i586/i686 - | ||
65 | then uname -i shows "i386". | ||
66 | |||
54 | config INCLUDE_SUSv2 | 67 | config INCLUDE_SUSv2 |
55 | bool "Enable obsolete features removed before SUSv3" | 68 | bool "Enable obsolete features removed before SUSv3" |
56 | default y | 69 | default y |
@@ -366,13 +379,6 @@ config FEATURE_SYSLOG | |||
366 | #This option is auto-selected when you select any applet which may | 379 | #This option is auto-selected when you select any applet which may |
367 | #send its output to syslog. You do not need to select it manually. | 380 | #send its output to syslog. You do not need to select it manually. |
368 | 381 | ||
369 | config FEATURE_HAVE_RPC | ||
370 | bool #No description makes it a hidden option | ||
371 | default n | ||
372 | #help | ||
373 | #This is automatically selected if any of enabled applets need it. | ||
374 | #You do not need to select it manually. | ||
375 | |||
376 | config PLATFORM_LINUX | 382 | config PLATFORM_LINUX |
377 | bool #No description makes it a hidden option | 383 | bool #No description makes it a hidden option |
378 | default n | 384 | default n |
@@ -721,6 +727,7 @@ source archival/Config.in | |||
721 | source coreutils/Config.in | 727 | source coreutils/Config.in |
722 | source console-tools/Config.in | 728 | source console-tools/Config.in |
723 | source debianutils/Config.in | 729 | source debianutils/Config.in |
730 | source klibc-utils/Config.in | ||
724 | source editors/Config.in | 731 | source editors/Config.in |
725 | source findutils/Config.in | 732 | source findutils/Config.in |
726 | source init/Config.in | 733 | source init/Config.in |
@@ -471,6 +471,7 @@ libs-y := \ | |||
471 | coreutils/ \ | 471 | coreutils/ \ |
472 | coreutils/libcoreutils/ \ | 472 | coreutils/libcoreutils/ \ |
473 | debianutils/ \ | 473 | debianutils/ \ |
474 | klibc-utils/ \ | ||
474 | e2fsprogs/ \ | 475 | e2fsprogs/ \ |
475 | editors/ \ | 476 | editors/ \ |
476 | findutils/ \ | 477 | findutils/ \ |
diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst new file mode 100644 index 000000000..3070a321b --- /dev/null +++ b/NOFORK_NOEXEC.lst | |||
@@ -0,0 +1,431 @@ | |||
1 | Why an applet can't be NOFORK or NOEXEC? | ||
2 | |||
3 | Why can't be NOFORK: | ||
4 | interactive: may wait for user input, ^C has to work | ||
5 | spawner: "tool PROG ARGS" which changes program state and execs - must fork | ||
6 | changes state: e.g. environment, signal handlers | ||
7 | leaks: does not free allocated memory or opened fds | ||
8 | alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies | ||
9 | open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies | ||
10 | talks to network/serial/etc: it's not known how long the delay can be, | ||
11 | it's reasonable to expect it might be many seconds | ||
12 | (even if usually it is not), so ^C has to work | ||
13 | runner: sometimes may run for long(ish) time, and/or works with network: | ||
14 | ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) | ||
15 | |||
16 | "runners" can become eligible after shell is taught ^C to interrupt NOFORKs, | ||
17 | need to be inspected that they do not fall into alloc+xfunc, open+xfunc, | ||
18 | leak categories. | ||
19 | |||
20 | Why can't be NOEXEC: | ||
21 | suid: runs under different uid - must fork+exec | ||
22 | if it's important that /proc/PID/cmdline and comm are correct. | ||
23 | ("pkill sh" killing itself before it kills real "sh" is no fun) | ||
24 | |||
25 | Why shouldn't be NOFORK/NOEXEC: | ||
26 | rare: not started often enough to bother optimizing (example: poweroff) | ||
27 | daemon: runs indefinitely; these are also always fit "rare" category | ||
28 | longterm: often runs for a long time (many seconds), execing makes | ||
29 | memory footprint smaller | ||
30 | complex: no immediately obvious reason why NOFORK wouldn't work, | ||
31 | but does some non-obvoius operations (example: fuser, lsof, losetup); | ||
32 | detailed audit often turns out that it's a leaker | ||
33 | hardware: performs unusual hardware ops which may take long, | ||
34 | or even hang due to hardware or firmware bugs | ||
35 | |||
36 | Interesting example of "interactive" applet which is nevertheless can be | ||
37 | (and is) NOEXEC is "rm". Yes, "rm -i" is interactive - but it's not that typical | ||
38 | for users to keep it waiting for many minutes, whereas running "rm" in shell | ||
39 | is very typical, and speeding up this common use via NOEXEC is useful. | ||
40 | IOW: rm is "interactive", but not "longterm". | ||
41 | |||
42 | Interesting example of an applet which can be NOFORK but if not, | ||
43 | then should not be NOEXEC, is "usleep". As NOFORK, it amount to simply | ||
44 | nanosleep()ing in the calling program (usually shell). No memory wasted. | ||
45 | But if ran as NOEXEC, it would create a potentially long-term process, | ||
46 | which would be taking more memory because it did not exec | ||
47 | and did not free much of the copied memory of the parent | ||
48 | (COW helps with this only as long as parent doesn't modify its memory). | ||
49 | |||
50 | |||
51 | [ - NOFORK | ||
52 | [[ - NOFORK | ||
53 | acpid - daemon | ||
54 | add-shell - noexec. leaks: open+xfunc | ||
55 | addgroup - noexec. leaks | ||
56 | adduser - noexec. leaks | ||
57 | adjtimex - NOFORK | ||
58 | ar - runner | ||
59 | arch - NOFORK | ||
60 | arp - talks to network: arp -n queries DNS | ||
61 | arping - longterm | ||
62 | ash - interactive, longterm | ||
63 | awk - noexec. runner | ||
64 | base64 - runner | ||
65 | basename - NOFORK | ||
66 | beep - longterm: beep -r 999999999 | ||
67 | blkdiscard - noexec. leaks: open+xioctl | ||
68 | blkid - noexec | ||
69 | blockdev - noexec. leaks fd | ||
70 | bootchartd - daemon | ||
71 | brctl - noexec | ||
72 | bunzip2 - runner | ||
73 | bzcat - runner | ||
74 | bzip2 - runner | ||
75 | cal - runner: cal -n9999 | ||
76 | cat - runner: cat HUGEFILE | ||
77 | chat - longterm (when used as intended - talking to modem over stdin/out) | ||
78 | chattr - noexec. runner | ||
79 | chgrp - noexec. runner | ||
80 | chmod - noexec. runner | ||
81 | chown - noexec. runner | ||
82 | chpasswd - longterm? (list of "user:password"s from stdin) | ||
83 | chpst - noexec. spawner | ||
84 | chroot - noexec. spawner | ||
85 | chrt - noexec. spawner | ||
86 | chvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds | ||
87 | cksum - noexec. runner | ||
88 | clear - NOFORK | ||
89 | cmp - runner | ||
90 | comm - runner | ||
91 | conspy - interactive, longterm | ||
92 | cp - noexec. runner | ||
93 | cpio - runner | ||
94 | crond - daemon | ||
95 | crontab - longterm (runs $EDITOR), leaks: open+xasprintf | ||
96 | cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin | ||
97 | cttyhack - noexec. spawner | ||
98 | cut - noexec. runner | ||
99 | date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) | ||
100 | dc - longterm (eats stdin if no params) | ||
101 | dd - noexec. runner | ||
102 | deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds | ||
103 | delgroup - noexec. leaks | ||
104 | deluser - noexec. leaks | ||
105 | depmod - longterm(ish) | ||
106 | devmem - hardware (access to device memory may hang) | ||
107 | df - noexec. leaks: nested allocs | ||
108 | dhcprelay - daemon | ||
109 | diff - runner | ||
110 | dirname - NOFORK | ||
111 | dmesg - runner | ||
112 | dnsd - daemon | ||
113 | dnsdomainname - noexec. talks to network (may query DNS) | ||
114 | dos2unix - noexec. runner | ||
115 | dpkg - runner | ||
116 | du - runner | ||
117 | dumpkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds | ||
118 | dumpleases - noexec. leaks: open+xread | ||
119 | echo - NOFORK | ||
120 | ed - interactive, longterm | ||
121 | egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) | ||
122 | eject - hardware, leaks: open+ioctl_or_perror_and_die, changes state (moves fds) | ||
123 | env - noexec. spawner, changes state (env) | ||
124 | envdir - noexec. spawner | ||
125 | envuidgid - noexec. spawner | ||
126 | expand - runner | ||
127 | expr - noexec. leaks: nested allocs | ||
128 | factor - longterm (eats stdin if no params) | ||
129 | fakeidentd - daemon | ||
130 | false - NOFORK | ||
131 | fatattr - noexec. leaks: open+xioctl, complex | ||
132 | fbset - hardware, leaks: open+xfunc | ||
133 | fbsplash - runner, longterm | ||
134 | fdflush - hardware, leaks: open+ioctl_or_perror_and_die | ||
135 | fdformat - hardware, longterm | ||
136 | fdisk - interactive, longterm | ||
137 | fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds | ||
138 | fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) | ||
139 | find - noexec. runner | ||
140 | findfs - suid | ||
141 | flash_eraseall - hardware | ||
142 | flash_lock - hardware | ||
143 | flash_unlock - hardware | ||
144 | flashcp - hardware | ||
145 | flock - spawner, changes state (file locks), let's play safe and not be noexec | ||
146 | fold - noexec. runner | ||
147 | free - noexec. nofork candidate(struct globals, needs to close /proc/meminfo fd) | ||
148 | freeramdisk - noexec. leaks: open+ioctl_or_perror_and_die | ||
149 | fsck - interactive, longterm | ||
150 | fsck.minix - needs ^C | ||
151 | fsfreeze - noexec. leaks: open+xioctl | ||
152 | fstrim - noexec. leaks: open+xioctl, find_block_device -> readdir+xstrdup | ||
153 | fsync - NOFORK | ||
154 | ftpd - daemon | ||
155 | ftpget - runner | ||
156 | ftpput - runner | ||
157 | fuser - complex | ||
158 | getopt - noexec. leaks: many allocs | ||
159 | getty - interactive, longterm | ||
160 | grep - longterm runner ("CMD | grep ..." may run indefinitely, better to exec to conserve memory) | ||
161 | groups - noexec | ||
162 | gunzip - runner | ||
163 | gzip - runner | ||
164 | halt - rare | ||
165 | hd - noexec. runner | ||
166 | hdparm - hardware | ||
167 | head - noexec. runner | ||
168 | hexdump - noexec. runner | ||
169 | hostid - NOFORK | ||
170 | hostname - noexec. talks to network (hostname -d may query DNS) | ||
171 | httpd - daemon | ||
172 | hush - interactive, longterm | ||
173 | hwclock - hardware (xioctl(RTC_RD_TIME)) | ||
174 | i2cdetect - hardware | ||
175 | i2cdump - hardware | ||
176 | i2cget - hardware | ||
177 | i2cset - hardware | ||
178 | id - noexec | ||
179 | ifconfig - hardware? (mem_start NN io_addr NN irq NN), leaks: xsocket+ioctl_or_perror_and_die | ||
180 | ifenslave - noexec. leaks: xsocket+bb_perror_msg_and_die | ||
181 | ifplugd - daemon | ||
182 | inetd - daemon | ||
183 | init - daemon | ||
184 | inotifyd - daemon | ||
185 | insmod - noexec | ||
186 | install - runner | ||
187 | ionice - noexec. spawner | ||
188 | iostat - longterm: "iostat 1" runs indefinitely | ||
189 | ip - noexec candidate | ||
190 | ipaddr - noexec candidate | ||
191 | ipcalc - noexec. ipcalc -h talks to network | ||
192 | ipcrm - noexec | ||
193 | ipcs - noexec | ||
194 | iplink - noexec candidate | ||
195 | ipneigh - noexec candidate | ||
196 | iproute - noexec candidate | ||
197 | iprule - noexec candidate | ||
198 | iptunnel - noexec candidate | ||
199 | kbd_mode - noexec. leaks: xopen_nonblocking+xioctl | ||
200 | kill - NOFORK | ||
201 | killall - NOFORK | ||
202 | killall5 - NOFORK | ||
203 | klogd - daemon | ||
204 | last - runner (I've got 1300 lines of output when tried it) | ||
205 | less - interactive, longterm | ||
206 | link - NOFORK | ||
207 | linux32 - noexec. spawner | ||
208 | linux64 - noexec. spawner | ||
209 | linuxrc - daemon | ||
210 | ln - noexec | ||
211 | loadfont - noexec. leaks: config_open+bb_error_msg_and_die("map format") | ||
212 | loadkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds | ||
213 | logger - runner | ||
214 | login - suid, interactive, longterm | ||
215 | logname - NOFORK | ||
216 | losetup - noexec. complex | ||
217 | lpd - daemon | ||
218 | lpq - runner | ||
219 | lpr - runner | ||
220 | ls - noexec. runner | ||
221 | lsattr - noexec. runner | ||
222 | lsmod - noexec | ||
223 | lsof - complex | ||
224 | lspci - noexec. too rare to bother for nofork | ||
225 | lsscsi - noexec. too rare to bother for nofork | ||
226 | lsusb - noexec. too rare to bother for nofork | ||
227 | lzcat - runner | ||
228 | lzma - runner | ||
229 | lzop - runner | ||
230 | lzopcat - runner | ||
231 | makedevs - noexec | ||
232 | makemime - runner | ||
233 | man - spawner, interactive, longterm | ||
234 | md5sum - noexec. runner | ||
235 | mdev - daemon | ||
236 | mesg - NOFORK | ||
237 | microcom - interactive, longterm | ||
238 | mkdir - NOFORK | ||
239 | mkdosfs - needs ^C | ||
240 | mke2fs - needs ^C | ||
241 | mkfifo - noexec | ||
242 | mkfs.ext2 - needs ^C | ||
243 | mkfs.minix - needs ^C | ||
244 | mkfs.vfat - needs ^C | ||
245 | mknod - noexec | ||
246 | mkpasswd - noexec. changes state: with --password-fd=N, moves N to stdin | ||
247 | mkswap - needs ^C | ||
248 | mktemp - noexec. leaks: xstrdup+concat_path_file | ||
249 | modinfo - noexec | ||
250 | modprobe - noexec | ||
251 | more - interactive, longterm | ||
252 | mount - suid | ||
253 | mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup | ||
254 | mpstat - longterm: "mpstat 1" runs indefinitely | ||
255 | mt - hardware | ||
256 | mv - noexec candidate, runner | ||
257 | nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die | ||
258 | nbd-client - noexec | ||
259 | nc - runner | ||
260 | netstat - longterm with -c (continuous listing) | ||
261 | nice - noexec. spawner | ||
262 | nl - runner | ||
263 | nmeter - longterm | ||
264 | nohup - noexec. spawner | ||
265 | nproc - NOFORK | ||
266 | ntpd - daemon | ||
267 | od - runner | ||
268 | openvt - longterm: spawns a child and waits for it | ||
269 | partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART) | ||
270 | passwd - suid | ||
271 | paste - noexec. runner | ||
272 | patch - needs ^C | ||
273 | pgrep - must fork+exec to get correct /proc/PID/cmdline and comm field | ||
274 | pidof - must fork+exec to get correct /proc/PID/cmdline and comm field | ||
275 | ping - suid, longterm | ||
276 | ping6 - suid, longterm | ||
277 | pipe_progress - longterm | ||
278 | pivot_root - NOFORK | ||
279 | pkill - must fork+exec to get correct /proc/PID/cmdline and comm field | ||
280 | pmap - noexec candidate, leaks: open+xstrdup | ||
281 | popmaildir - runner | ||
282 | poweroff - rare | ||
283 | powertop - interactive, longterm | ||
284 | printenv - NOFORK | ||
285 | printf - NOFORK | ||
286 | ps - noexec | ||
287 | pscan - talks to network | ||
288 | pstree - noexec | ||
289 | pwd - NOFORK | ||
290 | pwdx - NOFORK | ||
291 | raidautorun - noexec. very simple. leaks: open+xioctl | ||
292 | rdate - talks to network | ||
293 | rdev - noexec. leaks: find_block_device -> readdir+xstrdup | ||
294 | readlink - NOFORK | ||
295 | readprofile - reads /boot/System.map and /proc/profile, better to free more memory by execing? | ||
296 | realpath - NOFORK | ||
297 | reboot - rare | ||
298 | reformime - runner | ||
299 | remove-shell - noexec. leaks: open+xfunc | ||
300 | renice - noexec. nofork candidate(uses getpwnam, is that ok?) | ||
301 | reset - noexec. spawner (execs "stty") | ||
302 | resize - noexec. changes state (signal handlers) | ||
303 | rev - runner | ||
304 | rm - noexec. rm -i interactive | ||
305 | rmdir - NOFORK | ||
306 | rmmod - noexec | ||
307 | route - talks to network (may query DNS to convert IPs to names) | ||
308 | rpm - runner | ||
309 | rpm2cpio - runner | ||
310 | rtcwake - longterm: puts system to sleep, optimizing this for speed is pointless | ||
311 | run-parts - longterm | ||
312 | runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? | ||
313 | runsv - daemon | ||
314 | runsvdir - daemon | ||
315 | rx - runner | ||
316 | script - longterm: pumps script output from slave pty | ||
317 | scriptreplay - longterm: plays back "script" saved output, sleeping as necessary. | ||
318 | sed - runner | ||
319 | sendmail - runner | ||
320 | seq - noexec. runner | ||
321 | setarch - noexec. spawner | ||
322 | setconsole - noexec | ||
323 | setfont - noexec. leaks a lot of stuff | ||
324 | setkeycodes - noexec | ||
325 | setlogcons - noexec | ||
326 | setpriv - spawner, changes state, let's play safe and not be noexec | ||
327 | setserial - noexec | ||
328 | setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec | ||
329 | setuidgid - noexec. spawner | ||
330 | sha1sum - noexec. runner | ||
331 | sha256sum - noexec. runner | ||
332 | sha3sum - noexec. runner | ||
333 | sha512sum - noexec. runner | ||
334 | showkey - interactive, longterm | ||
335 | shred - runner | ||
336 | shuf - noexec. runner | ||
337 | slattach - longterm (may sleep forever), uses bb_common_bufsiz1 | ||
338 | sleep - longterm. Could be nofork, if not the problem of "killall sleep" not killing it. | ||
339 | smemcap - runner | ||
340 | softlimit - noexec. spawner | ||
341 | sort - noexec. runner | ||
342 | split - runner | ||
343 | ssl_client - longterm | ||
344 | start-stop-daemon - not noexec: uses bb_common_bufsiz1 | ||
345 | stat - noexec. nofork candidate(needs fewer allocs) | ||
346 | strings - runner | ||
347 | stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd | ||
348 | su - suid, spawner | ||
349 | sulogin - noexec. spawner | ||
350 | sum - runner | ||
351 | sv - noexec. needs ^C (uses usleep(420000)) | ||
352 | svc - noexec. needs ^C (uses usleep(420000)) | ||
353 | svlogd - daemon | ||
354 | swapoff - longterm: may cause memory pressure, execing is beneficial | ||
355 | swapon - rare | ||
356 | switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode | ||
357 | sync - NOFORK | ||
358 | sysctl - noexec. leaks: xstrdup+xmalloc_read | ||
359 | syslogd - daemon | ||
360 | tac - noexec. runner | ||
361 | tail - runner | ||
362 | tar - runner | ||
363 | taskset - noexec. spawner | ||
364 | tcpsvd - daemon | ||
365 | tee - runner | ||
366 | telnet - interactive, longterm | ||
367 | telnetd - daemon | ||
368 | test - NOFORK | ||
369 | tftp - runner | ||
370 | tftpd - daemon | ||
371 | time - spawner, longterm, changes state (signals) | ||
372 | timeout - spawner, longterm, changes state (signals) | ||
373 | top - interactive, longterm | ||
374 | touch - NOFORK | ||
375 | tr - runner | ||
376 | traceroute - suid, longterm | ||
377 | traceroute6 - suid, longterm | ||
378 | true - NOFORK | ||
379 | truncate - NOFORK | ||
380 | tty - NOFORK | ||
381 | ttysize - NOFORK | ||
382 | tunctl - noexec | ||
383 | tune2fs - noexec. leaks: open+xfunc | ||
384 | ubiattach - hardware | ||
385 | ubidetach - hardware | ||
386 | ubimkvol - hardware | ||
387 | ubirename - hardware | ||
388 | ubirmvol - hardware | ||
389 | ubirsvol - hardware | ||
390 | ubiupdatevol - hardware | ||
391 | udhcpc - daemon | ||
392 | udhcpd - daemon | ||
393 | udpsvd - daemon | ||
394 | uevent - daemon | ||
395 | umount - noexec. leaks: nested xmalloc | ||
396 | uname - NOFORK | ||
397 | uncompress - runner | ||
398 | unexpand - runner | ||
399 | uniq - runner | ||
400 | unix2dos - noexec. runner | ||
401 | unlink - NOFORK | ||
402 | unlzma - runner | ||
403 | unlzop - runner | ||
404 | unxz - runner | ||
405 | unzip - runner | ||
406 | uptime - noexec. nofork candidate(is getutxent ok?) | ||
407 | users - noexec. nofork candidate(is getutxent ok?) | ||
408 | usleep - NOFORK. But what about "killall usleep"? | ||
409 | uudecode - runner | ||
410 | uuencode - runner | ||
411 | vconfig - noexec. leaks: xsocket+ioctl_or_perror_and_die | ||
412 | vi - interactive, longterm | ||
413 | vlock - suid | ||
414 | volname - hardware (reads CDROM, this can take long-ish if need to spin up) | ||
415 | w - noexec. nofork candidate(is getutxent ok?) | ||
416 | wall - suid | ||
417 | watch - longterm | ||
418 | watchdog - daemon | ||
419 | wc - runner | ||
420 | wget - longterm | ||
421 | which - NOFORK | ||
422 | who - noexec. nofork candidate(is getutxent ok?) | ||
423 | whoami - NOFORK | ||
424 | whois - talks to network | ||
425 | xargs - noexec. spawner | ||
426 | xxd - noexec. runner | ||
427 | xz - runner | ||
428 | xzcat - runner | ||
429 | yes - noexec. runner | ||
430 | zcat - runner | ||
431 | zcip - daemon | ||
diff --git a/archival/ar.c b/archival/ar.c index ea36bda88..d113bc6ca 100644 --- a/archival/ar.c +++ b/archival/ar.c | |||
@@ -254,11 +254,16 @@ int ar_main(int argc UNUSED_PARAM, char **argv) | |||
254 | 254 | ||
255 | archive_handle = init_handle(); | 255 | archive_handle = init_handle(); |
256 | 256 | ||
257 | /* --: prepend '-' to the first argument if required */ | 257 | /* prepend '-' to the first argument if required */ |
258 | /* -1: at least one param is reqd */ | 258 | if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') |
259 | /* one of p,t,x[,r] is required */ | 259 | argv[1] = xasprintf("-%s", argv[1]); |
260 | opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r"); | 260 | opt = getopt32(argv, "^" |
261 | opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r")); | 261 | "voc""ptx"IF_FEATURE_AR_CREATE("r") |
262 | "\0" | ||
263 | /* -1: at least one arg is reqd */ | ||
264 | /* one of p,t,x[,r] is required */ | ||
265 | "-1:p:t:x"IF_FEATURE_AR_CREATE(":r") | ||
266 | ); | ||
262 | argv += optind; | 267 | argv += optind; |
263 | 268 | ||
264 | t = opt / FIRST_CMD; | 269 | t = opt / FIRST_CMD; |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index f91dd25eb..34a2e8e96 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -319,7 +319,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) | |||
319 | //config: select FEATURE_GZIP_DECOMPRESS | 319 | //config: select FEATURE_GZIP_DECOMPRESS |
320 | //config: help | 320 | //config: help |
321 | //config: gunzip is used to decompress archives created by gzip. | 321 | //config: gunzip is used to decompress archives created by gzip. |
322 | //config: You can use the `-t' option to test the integrity of | 322 | //config: You can use the '-t' option to test the integrity of |
323 | //config: an archive, without decompressing it. | 323 | //config: an archive, without decompressing it. |
324 | //config: | 324 | //config: |
325 | //config:config ZCAT | 325 | //config:config ZCAT |
@@ -391,9 +391,10 @@ int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
391 | int gunzip_main(int argc UNUSED_PARAM, char **argv) | 391 | int gunzip_main(int argc UNUSED_PARAM, char **argv) |
392 | { | 392 | { |
393 | #if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS | 393 | #if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS |
394 | applet_long_options = gunzip_longopts; | 394 | getopt32long(argv, "cfkvqdtn", gunzip_longopts); |
395 | #endif | 395 | #else |
396 | getopt32(argv, "cfkvqdtn"); | 396 | getopt32(argv, "cfkvqdtn"); |
397 | #endif | ||
397 | argv += optind; | 398 | argv += optind; |
398 | 399 | ||
399 | /* If called as zcat... | 400 | /* If called as zcat... |
diff --git a/archival/bzip2.c b/archival/bzip2.c index 0b9c508df..d578eb7ad 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c | |||
@@ -195,9 +195,11 @@ int bzip2_main(int argc UNUSED_PARAM, char **argv) | |||
195 | * --best alias for -9 | 195 | * --best alias for -9 |
196 | */ | 196 | */ |
197 | 197 | ||
198 | opt_complementary = "s2"; /* -s means -2 (compatibility) */ | 198 | opt = getopt32(argv, "^" |
199 | /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ | 199 | /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ |
200 | opt = getopt32(argv, "cfkv" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789qzs"); | 200 | "cfkv" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789qzs" |
201 | "\0" "s2" /* -s means -2 (compatibility) */ | ||
202 | ); | ||
201 | #if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */ | 203 | #if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */ |
202 | if (opt & 0x30) // -d and/or -t | 204 | if (opt & 0x30) // -d and/or -t |
203 | return bunzip2_main(argc, argv); | 205 | return bunzip2_main(argc, argv); |
diff --git a/archival/cpio.c b/archival/cpio.c index 38bab8257..f2165be3a 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -360,9 +360,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) | |||
360 | char *cpio_owner; | 360 | char *cpio_owner; |
361 | IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) | 361 | IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) |
362 | unsigned opt; | 362 | unsigned opt; |
363 | |||
364 | #if ENABLE_LONG_OPTS | 363 | #if ENABLE_LONG_OPTS |
365 | applet_long_options = | 364 | const char *long_opts = |
366 | "extract\0" No_argument "i" | 365 | "extract\0" No_argument "i" |
367 | "list\0" No_argument "t" | 366 | "list\0" No_argument "t" |
368 | #if ENABLE_FEATURE_CPIO_O | 367 | #if ENABLE_FEATURE_CPIO_O |
@@ -390,9 +389,9 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) | |||
390 | /* -L makes sense only with -o or -p */ | 389 | /* -L makes sense only with -o or -p */ |
391 | 390 | ||
392 | #if !ENABLE_FEATURE_CPIO_O | 391 | #if !ENABLE_FEATURE_CPIO_O |
393 | opt = getopt32(argv, OPTION_STR, &cpio_filename, &cpio_owner); | 392 | opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner); |
394 | #else | 393 | #else |
395 | opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), | 394 | opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts, |
396 | &cpio_filename, &cpio_owner, &cpio_fmt); | 395 | &cpio_filename, &cpio_owner, &cpio_fmt); |
397 | #endif | 396 | #endif |
398 | argv += optind; | 397 | argv += optind; |
diff --git a/archival/dpkg.c b/archival/dpkg.c index 90ad8766c..852e0cac2 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c | |||
@@ -1766,8 +1766,7 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) | |||
1766 | 1766 | ||
1767 | INIT_G(); | 1767 | INIT_G(); |
1768 | 1768 | ||
1769 | IF_LONG_OPTS(applet_long_options = dpkg_longopts); | 1769 | opt = getopt32long(argv, "CilPruF:", dpkg_longopts, &str_f); |
1770 | opt = getopt32(argv, "CilPruF:", &str_f); | ||
1771 | argv += optind; | 1770 | argv += optind; |
1772 | //if (opt & OPT_configure) ... // -C | 1771 | //if (opt & OPT_configure) ... // -C |
1773 | if (opt & OPT_force) { // -F (--force in official dpkg) | 1772 | if (opt & OPT_force) { // -F (--force in official dpkg) |
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c index 029bc4af1..f6bf9eb04 100644 --- a/archival/dpkg_deb.c +++ b/archival/dpkg_deb.c | |||
@@ -80,8 +80,9 @@ int dpkg_deb_main(int argc UNUSED_PARAM, char **argv) | |||
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | /* Must have 1 or 2 args */ | 82 | /* Must have 1 or 2 args */ |
83 | opt_complementary = "-1:?2:c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX"; | 83 | opt = getopt32(argv, "^" "cefXx" |
84 | opt = getopt32(argv, "cefXx"); | 84 | "\0" "-1:?2:c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX" |
85 | ); | ||
85 | argv += optind; | 86 | argv += optind; |
86 | //argc -= optind; | 87 | //argc -= optind; |
87 | 88 | ||
diff --git a/archival/gzip.c b/archival/gzip.c index 4cf34ac28..9c53895e9 100644 --- a/archival/gzip.c +++ b/archival/gzip.c | |||
@@ -2216,11 +2216,12 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) | |||
2216 | SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) | 2216 | SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) |
2217 | + sizeof(struct globals)); | 2217 | + sizeof(struct globals)); |
2218 | 2218 | ||
2219 | #if ENABLE_FEATURE_GZIP_LONG_OPTIONS | ||
2220 | applet_long_options = gzip_longopts; | ||
2221 | #endif | ||
2222 | /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ | 2219 | /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ |
2220 | #if ENABLE_FEATURE_GZIP_LONG_OPTIONS | ||
2221 | opt = getopt32long(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789", gzip_longopts); | ||
2222 | #else | ||
2223 | opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789"); | 2223 | opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789"); |
2224 | #endif | ||
2224 | #if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ | 2225 | #if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ |
2225 | if (opt & 0x30) // -d and/or -t | 2226 | if (opt & 0x30) // -d and/or -t |
2226 | return gunzip_main(argc, argv); | 2227 | return gunzip_main(argc, argv); |
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src index 942e755b9..e1a8a7529 100644 --- a/archival/libarchive/Kbuild.src +++ b/archival/libarchive/Kbuild.src | |||
@@ -12,6 +12,8 @@ COMMON_FILES:= \ | |||
12 | data_extract_all.o \ | 12 | data_extract_all.o \ |
13 | data_extract_to_stdout.o \ | 13 | data_extract_to_stdout.o \ |
14 | \ | 14 | \ |
15 | unsafe_symlink_target.o \ | ||
16 | \ | ||
15 | filter_accept_all.o \ | 17 | filter_accept_all.o \ |
16 | filter_accept_list.o \ | 18 | filter_accept_list.o \ |
17 | filter_accept_reject_list.o \ | 19 | filter_accept_reject_list.o \ |
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 1ce927c2f..e658444e0 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -129,9 +129,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
129 | if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { | 129 | if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { |
130 | /* shared message */ | 130 | /* shared message */ |
131 | bb_perror_msg("can't create %slink '%s' to '%s'", | 131 | bb_perror_msg("can't create %slink '%s' to '%s'", |
132 | "hard", | 132 | "hard", dst_name, hard_link |
133 | dst_name, | ||
134 | hard_link | ||
135 | ); | 133 | ); |
136 | } | 134 | } |
137 | /* Hardlinks have no separate mode/ownership, skip chown/chmod */ | 135 | /* Hardlinks have no separate mode/ownership, skip chown/chmod */ |
@@ -181,7 +179,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
181 | //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) | 179 | //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) |
182 | 180 | ||
183 | /* To avoid a directory traversal attack via symlinks, | 181 | /* To avoid a directory traversal attack via symlinks, |
184 | * for certain link targets postpone creation of symlinks. | 182 | * do not restore symlinks with ".." components |
183 | * or symlinks starting with "/", unless a magic | ||
184 | * envvar is set. | ||
185 | * | 185 | * |
186 | * For example, consider a .tar created via: | 186 | * For example, consider a .tar created via: |
187 | * $ tar cvf bug.tar anything.txt | 187 | * $ tar cvf bug.tar anything.txt |
@@ -199,24 +199,17 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
199 | * | 199 | * |
200 | * Untarring bug.tar would otherwise place evil.py in '/tmp'. | 200 | * Untarring bug.tar would otherwise place evil.py in '/tmp'. |
201 | */ | 201 | */ |
202 | if (file_header->link_target[0] == '/' | 202 | if (!unsafe_symlink_target(file_header->link_target)) { |
203 | || strstr(file_header->link_target, "..") | 203 | res = symlink(file_header->link_target, dst_name); |
204 | ) { | 204 | if (res != 0 |
205 | llist_add_to(&archive_handle->symlink_placeholders, | 205 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
206 | xasprintf("%s%c%s", file_header->name, '\0', file_header->link_target) | 206 | ) { |
207 | ); | 207 | /* shared message */ |
208 | break; | 208 | bb_perror_msg("can't create %slink '%s' to '%s'", |
209 | } | 209 | "sym", |
210 | res = symlink(file_header->link_target, dst_name); | 210 | dst_name, file_header->link_target |
211 | if (res != 0 | 211 | ); |
212 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | 212 | } |
213 | ) { | ||
214 | /* shared message */ | ||
215 | bb_perror_msg("can't create %slink '%s' to '%s'", | ||
216 | "sym", | ||
217 | dst_name, | ||
218 | file_header->link_target | ||
219 | ); | ||
220 | } | 213 | } |
221 | break; | 214 | break; |
222 | case S_IFSOCK: | 215 | case S_IFSOCK: |
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 350e5358a..0be85500c 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c | |||
@@ -37,7 +37,6 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | |||
37 | || !defined(put_unaligned_be32) | 37 | || !defined(put_unaligned_be32) |
38 | # error get_unaligned_le32 accessors are not defined | 38 | # error get_unaligned_le32 accessors are not defined |
39 | #endif | 39 | #endif |
40 | #define get_le32(p) (*(uint32_t*)(p)) | ||
41 | 40 | ||
42 | #include "unxz/xz_dec_bcj.c" | 41 | #include "unxz/xz_dec_bcj.c" |
43 | #include "unxz/xz_dec_lzma2.c" | 42 | #include "unxz/xz_dec_lzma2.c" |
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 641256787..7d912152c 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -251,18 +251,8 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp | |||
251 | return xstate; | 251 | return xstate; |
252 | } | 252 | } |
253 | 253 | ||
254 | /* Used by e.g. rpm which gives us a fd without filename, | 254 | static void fork_transformer_and_free(transformer_state_t *xstate) |
255 | * thus we can't guess the format from filename's extension. | ||
256 | */ | ||
257 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | ||
258 | { | 255 | { |
259 | transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | ||
260 | |||
261 | if (!xstate || !xstate->xformer) { | ||
262 | free(xstate); | ||
263 | return 1; | ||
264 | } | ||
265 | |||
266 | # if BB_MMU | 256 | # if BB_MMU |
267 | fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); | 257 | fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); |
268 | # else | 258 | # else |
@@ -270,13 +260,39 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | |||
270 | * an external unzipper that wants | 260 | * an external unzipper that wants |
271 | * file position at the start of the file. | 261 | * file position at the start of the file. |
272 | */ | 262 | */ |
273 | xlseek(fd, - xstate->signature_skipped, SEEK_CUR); | 263 | xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR); |
274 | xstate->signature_skipped = 0; | 264 | xstate->signature_skipped = 0; |
275 | fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); | 265 | fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); |
276 | # endif | 266 | # endif |
277 | free(xstate); | 267 | free(xstate); |
268 | } | ||
269 | |||
270 | /* Used by e.g. rpm which gives us a fd without filename, | ||
271 | * thus we can't guess the format from filename's extension. | ||
272 | */ | ||
273 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | ||
274 | { | ||
275 | transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | ||
276 | |||
277 | if (!xstate->xformer) { | ||
278 | free(xstate); | ||
279 | return 1; | ||
280 | } | ||
281 | |||
282 | fork_transformer_and_free(xstate); | ||
278 | return 0; | 283 | return 0; |
279 | } | 284 | } |
285 | #if ENABLE_FEATURE_SEAMLESS_LZMA | ||
286 | /* ...and custom version for LZMA */ | ||
287 | void FAST_FUNC setup_lzma_on_fd(int fd) | ||
288 | { | ||
289 | transformer_state_t *xstate = xzalloc(sizeof(*xstate)); | ||
290 | xstate->src_fd = fd; | ||
291 | xstate->xformer = unpack_lzma_stream; | ||
292 | USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";) | ||
293 | fork_transformer_and_free(xstate); | ||
294 | } | ||
295 | #endif | ||
280 | 296 | ||
281 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) | 297 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) |
282 | { | 298 | { |
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c new file mode 100644 index 000000000..441ba8b24 --- /dev/null +++ b/archival/libarchive/unsafe_symlink_target.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
4 | */ | ||
5 | #include "libbb.h" | ||
6 | #include "bb_archive.h" | ||
7 | |||
8 | int FAST_FUNC unsafe_symlink_target(const char *target) | ||
9 | { | ||
10 | const char *dot; | ||
11 | |||
12 | if (target[0] == '/') { | ||
13 | const char *var; | ||
14 | unsafe: | ||
15 | var = getenv("EXTRACT_UNSAFE_SYMLINKS"); | ||
16 | if (var) { | ||
17 | if (LONE_CHAR(var, '1')) | ||
18 | return 0; /* pretend it's safe */ | ||
19 | return 1; /* "UNSAFE!" */ | ||
20 | } | ||
21 | bb_error_msg("skipping unsafe symlink to '%s' in archive," | ||
22 | " set %s=1 to extract", | ||
23 | target, | ||
24 | "EXTRACT_UNSAFE_SYMLINKS" | ||
25 | ); | ||
26 | /* Prevent further messages */ | ||
27 | setenv("EXTRACT_UNSAFE_SYMLINKS", "0", 0); | ||
28 | return 1; /* "UNSAFE!" */ | ||
29 | } | ||
30 | |||
31 | dot = target; | ||
32 | for (;;) { | ||
33 | dot = strchr(dot, '.'); | ||
34 | if (!dot) | ||
35 | return 0; /* safe target */ | ||
36 | |||
37 | /* Is it a path component starting with ".."? */ | ||
38 | if ((dot[1] == '.') | ||
39 | && (dot == target || dot[-1] == '/') | ||
40 | /* Is it exactly ".."? */ | ||
41 | && (dot[2] == '/' || dot[2] == '\0') | ||
42 | ) { | ||
43 | goto unsafe; | ||
44 | } | ||
45 | /* NB: it can even be trailing ".", should only add 1 */ | ||
46 | dot += 1; | ||
47 | } | ||
48 | } | ||
diff --git a/archival/lzop.c b/archival/lzop.c index df18ff170..1bf954f4f 100644 --- a/archival/lzop.c +++ b/archival/lzop.c | |||
@@ -1138,7 +1138,7 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) | |||
1138 | /* -U is "anti -k", invert bit for bbunpack(): */ | 1138 | /* -U is "anti -k", invert bit for bbunpack(): */ |
1139 | option_mask32 ^= OPT_KEEP; | 1139 | option_mask32 ^= OPT_KEEP; |
1140 | /* -k disables -U (if any): */ | 1140 | /* -k disables -U (if any): */ |
1141 | /* opt_complementary = "k-U"; - nope, only handles -Uk, not -kU */ | 1141 | /* opt_complementary "k-U"? - nope, only handles -Uk, not -kU */ |
1142 | if (option_mask32 & OPT_k) | 1142 | if (option_mask32 & OPT_k) |
1143 | option_mask32 |= OPT_KEEP; | 1143 | option_mask32 |= OPT_KEEP; |
1144 | 1144 | ||
diff --git a/archival/rpm.c b/archival/rpm.c index 98039d499..790eeb59d 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
@@ -6,7 +6,6 @@ | |||
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 | |||
10 | //config:config RPM | 9 | //config:config RPM |
11 | //config: bool "rpm (33 kb)" | 10 | //config: bool "rpm (33 kb)" |
12 | //config: default y | 11 | //config: default y |
@@ -14,19 +13,8 @@ | |||
14 | //config: Mini RPM applet - queries and extracts RPM packages. | 13 | //config: Mini RPM applet - queries and extracts RPM packages. |
15 | 14 | ||
16 | //applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) | 15 | //applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) |
17 | //kbuild:lib-$(CONFIG_RPM) += rpm.o | ||
18 | 16 | ||
19 | //usage:#define rpm_trivial_usage | 17 | //kbuild:lib-$(CONFIG_RPM) += rpm.o |
20 | //usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" | ||
21 | //usage:#define rpm_full_usage "\n\n" | ||
22 | //usage: "Manipulate RPM packages\n" | ||
23 | //usage: "\nCommands:" | ||
24 | //usage: "\n -i Install package" | ||
25 | //usage: "\n -qp Query package" | ||
26 | //usage: "\n -qpi Show information" | ||
27 | //usage: "\n -qpl List contents" | ||
28 | //usage: "\n -qpd List documents" | ||
29 | //usage: "\n -qpc List config files" | ||
30 | 18 | ||
31 | #include "libbb.h" | 19 | #include "libbb.h" |
32 | #include "common_bufsiz.h" | 20 | #include "common_bufsiz.h" |
@@ -68,6 +56,8 @@ | |||
68 | #define TAG_DIRINDEXES 1116 | 56 | #define TAG_DIRINDEXES 1116 |
69 | #define TAG_BASENAMES 1117 | 57 | #define TAG_BASENAMES 1117 |
70 | #define TAG_DIRNAMES 1118 | 58 | #define TAG_DIRNAMES 1118 |
59 | #define TAG_PAYLOADCOMPRESSOR 1125 | ||
60 | |||
71 | 61 | ||
72 | #define RPMFILE_CONFIG (1 << 0) | 62 | #define RPMFILE_CONFIG (1 << 0) |
73 | #define RPMFILE_DOC (1 << 1) | 63 | #define RPMFILE_DOC (1 << 1) |
@@ -91,148 +81,145 @@ typedef struct { | |||
91 | 81 | ||
92 | struct globals { | 82 | struct globals { |
93 | void *map; | 83 | void *map; |
94 | rpm_index **mytags; | 84 | rpm_index *mytags; |
95 | int tagcount; | 85 | int tagcount; |
86 | unsigned mapsize, pagesize; | ||
96 | } FIX_ALIASING; | 87 | } FIX_ALIASING; |
97 | #define G (*(struct globals*)bb_common_bufsiz1) | 88 | #define G (*(struct globals*)bb_common_bufsiz1) |
98 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 89 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
99 | 90 | ||
100 | static void extract_cpio(int fd, const char *source_rpm) | 91 | static int rpm_gettags(const char *filename) |
101 | { | ||
102 | archive_handle_t *archive_handle; | ||
103 | |||
104 | if (source_rpm != NULL) { | ||
105 | /* Binary rpm (it was built from some SRPM), install to root */ | ||
106 | xchdir("/"); | ||
107 | } /* else: SRPM, install to current dir */ | ||
108 | |||
109 | /* Initialize */ | ||
110 | archive_handle = init_handle(); | ||
111 | archive_handle->seek = seek_by_read; | ||
112 | archive_handle->action_data = data_extract_all; | ||
113 | #if 0 /* For testing (rpm -i only lists the files in internal cpio): */ | ||
114 | archive_handle->action_header = header_list; | ||
115 | archive_handle->action_data = data_skip; | ||
116 | #endif | ||
117 | archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS | ||
118 | /* compat: overwrite existing files. | ||
119 | * try "rpm -i foo.src.rpm" few times in a row - | ||
120 | * standard rpm will not complain. | ||
121 | */ | ||
122 | | ARCHIVE_REPLACE_VIA_RENAME; | ||
123 | archive_handle->src_fd = fd; | ||
124 | /*archive_handle->offset = 0; - init_handle() did it */ | ||
125 | |||
126 | setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); | ||
127 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | ||
128 | continue; | ||
129 | } | ||
130 | |||
131 | static rpm_index **rpm_gettags(int fd, int *num_tags) | ||
132 | { | 92 | { |
133 | /* We should never need more than 200 (shrink via realloc later) */ | 93 | rpm_index *tags; |
134 | rpm_index **tags = xzalloc(200 * sizeof(tags[0])); | 94 | int fd; |
135 | int pass, tagindex = 0; | 95 | unsigned pass, idx; |
136 | 96 | unsigned storepos; | |
137 | xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ | 97 | |
98 | if (!filename) { /* rpm2cpio w/o filename? */ | ||
99 | filename = bb_msg_standard_output; | ||
100 | fd = 0; | ||
101 | } else { | ||
102 | fd = xopen(filename, O_RDONLY); | ||
103 | } | ||
138 | 104 | ||
105 | storepos = xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ | ||
106 | G.tagcount = 0; | ||
107 | tags = NULL; | ||
108 | idx = 0; | ||
139 | /* 1st pass is the signature headers, 2nd is the main stuff */ | 109 | /* 1st pass is the signature headers, 2nd is the main stuff */ |
140 | for (pass = 0; pass < 2; pass++) { | 110 | for (pass = 0; pass < 2; pass++) { |
141 | struct rpm_header header; | 111 | struct rpm_header header; |
142 | rpm_index *tmpindex; | 112 | unsigned cnt; |
143 | int storepos; | ||
144 | 113 | ||
145 | xread(fd, &header, sizeof(header)); | 114 | xread(fd, &header, sizeof(header)); |
146 | if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) | 115 | if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) |
147 | return NULL; /* Invalid magic, or not version 1 */ | 116 | bb_error_msg_and_die("invalid RPM header magic in '%s'", filename); |
148 | header.size = ntohl(header.size); | 117 | header.size = ntohl(header.size); |
149 | header.entries = ntohl(header.entries); | 118 | cnt = ntohl(header.entries); |
150 | storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16; | 119 | storepos += sizeof(header) + cnt * 16; |
151 | 120 | ||
152 | while (header.entries--) { | 121 | G.tagcount += cnt; |
153 | tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); | 122 | tags = xrealloc(tags, sizeof(tags[0]) * G.tagcount); |
154 | xread(fd, tmpindex, sizeof(*tmpindex)); | 123 | xread(fd, &tags[idx], sizeof(tags[0]) * cnt); |
155 | tmpindex->tag = ntohl(tmpindex->tag); | 124 | while (cnt--) { |
156 | tmpindex->type = ntohl(tmpindex->type); | 125 | rpm_index *tag = &tags[idx]; |
157 | tmpindex->count = ntohl(tmpindex->count); | 126 | tag->tag = ntohl(tag->tag); |
158 | tmpindex->offset = storepos + ntohl(tmpindex->offset); | 127 | tag->type = ntohl(tag->type); |
128 | tag->count = ntohl(tag->count); | ||
129 | tag->offset = storepos + ntohl(tag->offset); | ||
159 | if (pass == 0) | 130 | if (pass == 0) |
160 | tmpindex->tag -= 743; | 131 | tag->tag -= 743; |
132 | idx++; | ||
161 | } | 133 | } |
162 | storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ | ||
163 | /* Skip padding to 8 byte boundary after reading signature headers */ | 134 | /* Skip padding to 8 byte boundary after reading signature headers */ |
164 | if (pass == 0) | 135 | if (pass == 0) |
165 | xlseek(fd, (-storepos) & 0x7, SEEK_CUR); | 136 | while (header.size & 7) |
137 | header.size++; | ||
138 | /* Seek past store */ | ||
139 | storepos = xlseek(fd, header.size, SEEK_CUR); | ||
166 | } | 140 | } |
167 | /* realloc tags to save space */ | 141 | G.mytags = tags; |
168 | tags = xrealloc(tags, tagindex * sizeof(tags[0])); | 142 | |
169 | *num_tags = tagindex; | 143 | /* Map the store */ |
170 | /* All done, leave the file at the start of the gzipped cpio archive */ | 144 | storepos = (storepos + G.pagesize) & -(int)G.pagesize; |
171 | return tags; | 145 | /* remember size for munmap */ |
146 | G.mapsize = storepos; | ||
147 | /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ | ||
148 | G.map = mmap(0, storepos, PROT_READ, MAP_PRIVATE, fd, 0); | ||
149 | if (G.map == MAP_FAILED) | ||
150 | bb_perror_msg_and_die("mmap '%s'", filename); | ||
151 | |||
152 | return fd; | ||
172 | } | 153 | } |
173 | 154 | ||
174 | static int bsearch_rpmtag(const void *key, const void *item) | 155 | static int bsearch_rpmtag(const void *key, const void *item) |
175 | { | 156 | { |
176 | int *tag = (int *)key; | 157 | int *tag = (int *)key; |
177 | rpm_index **tmp = (rpm_index **) item; | 158 | rpm_index *tmp = (rpm_index *) item; |
178 | return (*tag - tmp[0]->tag); | 159 | return (*tag - tmp->tag); |
179 | } | ||
180 | |||
181 | static int rpm_getcount(int tag) | ||
182 | { | ||
183 | rpm_index **found; | ||
184 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | ||
185 | if (!found) | ||
186 | return 0; | ||
187 | return found[0]->count; | ||
188 | } | 160 | } |
189 | 161 | ||
190 | static char *rpm_getstr(int tag, int itemindex) | 162 | static char *rpm_getstr(int tag, int itemindex) |
191 | { | 163 | { |
192 | rpm_index **found; | 164 | rpm_index *found; |
193 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | 165 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); |
194 | if (!found || itemindex >= found[0]->count) | 166 | if (!found || itemindex >= found->count) |
195 | return NULL; | 167 | return NULL; |
196 | if (found[0]->type == RPM_STRING_TYPE | 168 | if (found->type == RPM_STRING_TYPE |
197 | || found[0]->type == RPM_I18NSTRING_TYPE | 169 | || found->type == RPM_I18NSTRING_TYPE |
198 | || found[0]->type == RPM_STRING_ARRAY_TYPE | 170 | || found->type == RPM_STRING_ARRAY_TYPE |
199 | ) { | 171 | ) { |
200 | int n; | 172 | int n; |
201 | char *tmpstr = (char *) G.map + found[0]->offset; | 173 | char *tmpstr = (char *) G.map + found->offset; |
202 | for (n = 0; n < itemindex; n++) | 174 | for (n = 0; n < itemindex; n++) |
203 | tmpstr = tmpstr + strlen(tmpstr) + 1; | 175 | tmpstr = tmpstr + strlen(tmpstr) + 1; |
204 | return tmpstr; | 176 | return tmpstr; |
205 | } | 177 | } |
206 | return NULL; | 178 | return NULL; |
207 | } | 179 | } |
180 | static char *rpm_getstr0(int tag) | ||
181 | { | ||
182 | return rpm_getstr(tag, 0); | ||
183 | } | ||
184 | |||
185 | #if ENABLE_RPM | ||
208 | 186 | ||
209 | static int rpm_getint(int tag, int itemindex) | 187 | static int rpm_getint(int tag, int itemindex) |
210 | { | 188 | { |
211 | rpm_index **found; | 189 | rpm_index *found; |
212 | char *tmpint; | 190 | char *tmpint; |
213 | 191 | ||
214 | /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... | 192 | /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... |
215 | * it's ok to ignore it because tag won't be used as a pointer */ | 193 | * it's ok to ignore it because tag won't be used as a pointer */ |
216 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | 194 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); |
217 | if (!found || itemindex >= found[0]->count) | 195 | if (!found || itemindex >= found->count) |
218 | return -1; | 196 | return -1; |
219 | 197 | ||
220 | tmpint = (char *) G.map + found[0]->offset; | 198 | tmpint = (char *) G.map + found->offset; |
221 | if (found[0]->type == RPM_INT32_TYPE) { | 199 | if (found->type == RPM_INT32_TYPE) { |
222 | tmpint += itemindex*4; | 200 | tmpint += itemindex*4; |
223 | return ntohl(*(int32_t*)tmpint); | 201 | return ntohl(*(int32_t*)tmpint); |
224 | } | 202 | } |
225 | if (found[0]->type == RPM_INT16_TYPE) { | 203 | if (found->type == RPM_INT16_TYPE) { |
226 | tmpint += itemindex*2; | 204 | tmpint += itemindex*2; |
227 | return ntohs(*(int16_t*)tmpint); | 205 | return ntohs(*(int16_t*)tmpint); |
228 | } | 206 | } |
229 | if (found[0]->type == RPM_INT8_TYPE) { | 207 | if (found->type == RPM_INT8_TYPE) { |
230 | tmpint += itemindex; | 208 | tmpint += itemindex; |
231 | return *(int8_t*)tmpint; | 209 | return *(int8_t*)tmpint; |
232 | } | 210 | } |
233 | return -1; | 211 | return -1; |
234 | } | 212 | } |
235 | 213 | ||
214 | static int rpm_getcount(int tag) | ||
215 | { | ||
216 | rpm_index *found; | ||
217 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); | ||
218 | if (!found) | ||
219 | return 0; | ||
220 | return found->count; | ||
221 | } | ||
222 | |||
236 | static void fileaction_dobackup(char *filename, int fileref) | 223 | static void fileaction_dobackup(char *filename, int fileref) |
237 | { | 224 | { |
238 | struct stat oldfile; | 225 | struct stat oldfile; |
@@ -273,11 +260,103 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i | |||
273 | } | 260 | } |
274 | } | 261 | } |
275 | 262 | ||
263 | #if 0 //DEBUG | ||
264 | static void print_all_tags(void) | ||
265 | { | ||
266 | unsigned i = 0; | ||
267 | while (i < G.tagcount) { | ||
268 | rpm_index *tag = &G.mytags[i]; | ||
269 | if (tag->type == RPM_STRING_TYPE | ||
270 | || tag->type == RPM_I18NSTRING_TYPE | ||
271 | || tag->type == RPM_STRING_ARRAY_TYPE | ||
272 | ) { | ||
273 | unsigned n; | ||
274 | char *str = (char *) G.map + tag->offset; | ||
275 | |||
276 | printf("tag[%u] %08x type %08x offset %08x count %d '%s'\n", | ||
277 | i, tag->tag, tag->type, tag->offset, tag->count, str | ||
278 | ); | ||
279 | for (n = 1; n < tag->count; n++) { | ||
280 | str += strlen(str) + 1; | ||
281 | printf("\t'%s'\n", str); | ||
282 | } | ||
283 | } | ||
284 | i++; | ||
285 | } | ||
286 | } | ||
287 | #else | ||
288 | #define print_all_tags() ((void)0) | ||
289 | #endif | ||
290 | |||
291 | static void extract_cpio(int fd, const char *source_rpm) | ||
292 | { | ||
293 | archive_handle_t *archive_handle; | ||
294 | |||
295 | if (source_rpm != NULL) { | ||
296 | /* Binary rpm (it was built from some SRPM), install to root */ | ||
297 | xchdir("/"); | ||
298 | } /* else: SRPM, install to current dir */ | ||
299 | |||
300 | /* Initialize */ | ||
301 | archive_handle = init_handle(); | ||
302 | archive_handle->seek = seek_by_read; | ||
303 | archive_handle->action_data = data_extract_all; | ||
304 | #if 0 /* For testing (rpm -i only lists the files in internal cpio): */ | ||
305 | archive_handle->action_header = header_list; | ||
306 | archive_handle->action_data = data_skip; | ||
307 | #endif | ||
308 | archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS | ||
309 | /* compat: overwrite existing files. | ||
310 | * try "rpm -i foo.src.rpm" few times in a row - | ||
311 | * standard rpm will not complain. | ||
312 | */ | ||
313 | | ARCHIVE_REPLACE_VIA_RENAME; | ||
314 | archive_handle->src_fd = fd; | ||
315 | /*archive_handle->offset = 0; - init_handle() did it */ | ||
316 | |||
317 | setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); | ||
318 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | ||
319 | continue; | ||
320 | } | ||
321 | |||
322 | //usage:#define rpm_trivial_usage | ||
323 | //usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" | ||
324 | //usage:#define rpm_full_usage "\n\n" | ||
325 | //usage: "Manipulate RPM packages\n" | ||
326 | //usage: "\nCommands:" | ||
327 | //usage: "\n -i Install package" | ||
328 | //usage: "\n -qp Query package" | ||
329 | //usage: "\n -qpi Show information" | ||
330 | //usage: "\n -qpl List contents" | ||
331 | //usage: "\n -qpd List documents" | ||
332 | //usage: "\n -qpc List config files" | ||
333 | |||
334 | /* RPM version 4.13.0.1: | ||
335 | * Unlike -q, -i seems to imply -p: -i, -ip and -pi work the same. | ||
336 | * OTOH, with -q order is important: "-piq FILE.rpm" works as -qp, not -qpi | ||
337 | * (IOW: shows only package name, not package info). | ||
338 | * "-iq ARG" works as -q: treats ARG as package name, not a file. | ||
339 | * | ||
340 | * "man rpm" on -l option and options implying it: | ||
341 | * -l, --list List files in package. | ||
342 | * -c, --configfiles List only configuration files (implies -l). | ||
343 | * -d, --docfiles List only documentation files (implies -l). | ||
344 | * -L, --licensefiles List only license files (implies -l). | ||
345 | * --dump Dump file information as follows (implies -l): | ||
346 | * path size mtime digest mode owner group isconfig isdoc rdev symlink | ||
347 | * -s, --state Display the states of files in the package (implies -l). | ||
348 | * The state of each file is one of normal, not installed, or replaced. | ||
349 | * | ||
350 | * Looks like we can switch to getopt32 here: in practice, people | ||
351 | * do place -q first if they intend to use it (misinterpreting "-piq" wouldn't matter). | ||
352 | */ | ||
276 | int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 353 | int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
277 | int rpm_main(int argc, char **argv) | 354 | int rpm_main(int argc, char **argv) |
278 | { | 355 | { |
279 | int opt, func = 0; | 356 | int opt, func = 0; |
280 | const unsigned pagesize = getpagesize(); | 357 | |
358 | INIT_G(); | ||
359 | G.pagesize = getpagesize(); | ||
281 | 360 | ||
282 | while ((opt = getopt(argc, argv, "iqpldc")) != -1) { | 361 | while ((opt = getopt(argc, argv, "iqpldc")) != -1) { |
283 | switch (opt) { | 362 | switch (opt) { |
@@ -289,17 +368,17 @@ int rpm_main(int argc, char **argv) | |||
289 | if (func) bb_show_usage(); | 368 | if (func) bb_show_usage(); |
290 | func = rpm_query; | 369 | func = rpm_query; |
291 | break; | 370 | break; |
292 | case 'p': /* Query a package */ | 371 | case 'p': /* Query a package (IOW: .rpm file, we are not querying RPMDB) */ |
293 | func |= rpm_query_package; | 372 | func |= rpm_query_package; |
294 | break; | 373 | break; |
295 | case 'l': /* List files in a package */ | 374 | case 'l': /* List files in a package */ |
296 | func |= rpm_query_list; | 375 | func |= rpm_query_list; |
297 | break; | 376 | break; |
298 | case 'd': /* List doc files in a package (implies list) */ | 377 | case 'd': /* List doc files in a package (implies -l) */ |
299 | func |= rpm_query_list; | 378 | func |= rpm_query_list; |
300 | func |= rpm_query_list_doc; | 379 | func |= rpm_query_list_doc; |
301 | break; | 380 | break; |
302 | case 'c': /* List config files in a package (implies list) */ | 381 | case 'c': /* List config files in a package (implies -l) */ |
303 | func |= rpm_query_list; | 382 | func |= rpm_query_list; |
304 | func |= rpm_query_list_config; | 383 | func |= rpm_query_list_config; |
305 | break; | 384 | break; |
@@ -313,24 +392,18 @@ int rpm_main(int argc, char **argv) | |||
313 | bb_show_usage(); | 392 | bb_show_usage(); |
314 | } | 393 | } |
315 | 394 | ||
316 | while (*argv) { | 395 | for (;;) { |
317 | int rpm_fd; | 396 | int rpm_fd; |
318 | unsigned mapsize; | ||
319 | const char *source_rpm; | 397 | const char *source_rpm; |
320 | 398 | ||
321 | rpm_fd = xopen(*argv++, O_RDONLY); | 399 | rpm_fd = rpm_gettags(*argv); |
322 | G.mytags = rpm_gettags(rpm_fd, &G.tagcount); | 400 | print_all_tags(); |
323 | if (!G.mytags) | ||
324 | bb_error_msg_and_die("error reading rpm header"); | ||
325 | mapsize = xlseek(rpm_fd, 0, SEEK_CUR); | ||
326 | mapsize = (mapsize + pagesize) & -(int)pagesize; | ||
327 | /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ | ||
328 | G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); | ||
329 | //FIXME: error check? | ||
330 | 401 | ||
331 | source_rpm = rpm_getstr(TAG_SOURCERPM, 0); | 402 | source_rpm = rpm_getstr0(TAG_SOURCERPM); |
332 | 403 | ||
333 | if (func & rpm_install) { | 404 | if (func & rpm_install) { |
405 | /* -i (and not -qi) */ | ||
406 | |||
334 | /* Backup any config files */ | 407 | /* Backup any config files */ |
335 | loop_through_files(TAG_BASENAMES, fileaction_dobackup); | 408 | loop_through_files(TAG_BASENAMES, fileaction_dobackup); |
336 | /* Extact the archive */ | 409 | /* Extact the archive */ |
@@ -338,10 +411,13 @@ int rpm_main(int argc, char **argv) | |||
338 | /* Set the correct file uid/gid's */ | 411 | /* Set the correct file uid/gid's */ |
339 | loop_through_files(TAG_BASENAMES, fileaction_setowngrp); | 412 | loop_through_files(TAG_BASENAMES, fileaction_setowngrp); |
340 | } | 413 | } |
341 | else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { | 414 | else |
415 | if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { | ||
416 | /* -qp */ | ||
417 | |||
342 | if (!(func & (rpm_query_info|rpm_query_list))) { | 418 | if (!(func & (rpm_query_info|rpm_query_list))) { |
343 | /* If just a straight query, just give package name */ | 419 | /* If just a straight query, just give package name */ |
344 | printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); | 420 | printf("%s-%s-%s\n", rpm_getstr0(TAG_NAME), rpm_getstr0(TAG_VERSION), rpm_getstr0(TAG_RELEASE)); |
345 | } | 421 | } |
346 | if (func & rpm_query_info) { | 422 | if (func & rpm_query_info) { |
347 | /* Do the nice printout */ | 423 | /* Do the nice printout */ |
@@ -350,30 +426,33 @@ int rpm_main(int argc, char **argv) | |||
350 | char bdatestring[50]; | 426 | char bdatestring[50]; |
351 | const char *p; | 427 | const char *p; |
352 | 428 | ||
353 | printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); | 429 | printf("%-12s: %s\n", "Name" , rpm_getstr0(TAG_NAME)); |
354 | /* TODO compat: add "Epoch" here */ | 430 | /* TODO compat: add "Epoch" here */ |
355 | printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); | 431 | printf("%-12s: %s\n", "Version" , rpm_getstr0(TAG_VERSION)); |
356 | printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); | 432 | printf("%-12s: %s\n", "Release" , rpm_getstr0(TAG_RELEASE)); |
357 | /* add "Architecture" */ | 433 | /* add "Architecture" */ |
358 | printf("%-12s: %s\n", "Install Date", "(not installed)"); | 434 | /* printf("%-12s: %s\n", "Install Date", "(not installed)"); - we don't know */ |
359 | printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); | 435 | printf("%-12s: %s\n", "Group" , rpm_getstr0(TAG_GROUP)); |
360 | printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); | 436 | printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); |
361 | printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); | 437 | printf("%-12s: %s\n", "License" , rpm_getstr0(TAG_LICENSE)); |
362 | /* add "Signature" */ | 438 | /* add "Signature" */ |
363 | printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); | 439 | printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); |
364 | bdate_time = rpm_getint(TAG_BUILDTIME, 0); | 440 | bdate_time = rpm_getint(TAG_BUILDTIME, 0); |
365 | bdate_ptm = localtime(&bdate_time); | 441 | bdate_ptm = localtime(&bdate_time); |
366 | strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); | 442 | strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); |
367 | printf("%-12s: %s\n", "Build Date" , bdatestring); | 443 | printf("%-12s: %s\n", "Build Date" , bdatestring); |
368 | printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); | 444 | printf("%-12s: %s\n", "Build Host" , rpm_getstr0(TAG_BUILDHOST)); |
369 | p = rpm_getstr(TAG_PREFIXS, 0); | 445 | p = rpm_getstr0(TAG_PREFIXS); |
370 | printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); | 446 | printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); |
371 | /* add "Packager" */ | 447 | /* add "Packager" */ |
372 | p = rpm_getstr(TAG_VENDOR, 0); | 448 | p = rpm_getstr0(TAG_VENDOR); |
373 | printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); | 449 | if (p) /* rpm 4.13.0.1 does not show "(none)" for Vendor: */ |
374 | printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); | 450 | printf("%-12s: %s\n", "Vendor" , p); |
375 | printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); | 451 | p = rpm_getstr0(TAG_URL); |
376 | printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); | 452 | if (p) /* rpm 4.13.0.1 does not show "(none)"/"(null)" for URL: */ |
453 | printf("%-12s: %s\n", "URL" , p); | ||
454 | printf("%-12s: %s\n", "Summary" , rpm_getstr0(TAG_SUMMARY)); | ||
455 | printf("Description :\n%s\n", rpm_getstr0(TAG_DESCRIPTION)); | ||
377 | } | 456 | } |
378 | if (func & rpm_query_list) { | 457 | if (func & rpm_query_list) { |
379 | int count, it, flags; | 458 | int count, it, flags; |
@@ -396,10 +475,85 @@ int rpm_main(int argc, char **argv) | |||
396 | rpm_getstr(TAG_BASENAMES, it)); | 475 | rpm_getstr(TAG_BASENAMES, it)); |
397 | } | 476 | } |
398 | } | 477 | } |
478 | } else { | ||
479 | /* Unsupported (help text shows what we support) */ | ||
480 | bb_show_usage(); | ||
399 | } | 481 | } |
400 | munmap(G.map, mapsize); | 482 | if (!*++argv) |
483 | break; | ||
484 | munmap(G.map, G.mapsize); | ||
401 | free(G.mytags); | 485 | free(G.mytags); |
402 | close(rpm_fd); | 486 | close(rpm_fd); |
403 | } | 487 | } |
488 | |||
404 | return 0; | 489 | return 0; |
405 | } | 490 | } |
491 | |||
492 | #endif /* RPM */ | ||
493 | |||
494 | /* | ||
495 | * Mini rpm2cpio implementation for busybox | ||
496 | * | ||
497 | * Copyright (C) 2001 by Laurence Anderson | ||
498 | * | ||
499 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
500 | */ | ||
501 | //config:config RPM2CPIO | ||
502 | //config: bool "rpm2cpio (20 kb)" | ||
503 | //config: default y | ||
504 | //config: help | ||
505 | //config: Converts a RPM file into a CPIO archive. | ||
506 | |||
507 | //applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
508 | |||
509 | //kbuild:lib-$(CONFIG_RPM2CPIO) += rpm.o | ||
510 | |||
511 | //usage:#define rpm2cpio_trivial_usage | ||
512 | //usage: "PACKAGE.rpm" | ||
513 | //usage:#define rpm2cpio_full_usage "\n\n" | ||
514 | //usage: "Output a cpio archive of the rpm file" | ||
515 | |||
516 | #if ENABLE_RPM2CPIO | ||
517 | |||
518 | /* No getopt required */ | ||
519 | int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
520 | int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | ||
521 | { | ||
522 | const char *str; | ||
523 | int rpm_fd; | ||
524 | |||
525 | INIT_G(); | ||
526 | G.pagesize = getpagesize(); | ||
527 | |||
528 | rpm_fd = rpm_gettags(argv[1]); | ||
529 | |||
530 | //if (SEAMLESS_COMPRESSION) - we do this at the end instead. | ||
531 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | ||
532 | // signal(SIGCHLD, check_errors_in_children); | ||
533 | |||
534 | if (ENABLE_FEATURE_SEAMLESS_LZMA | ||
535 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL | ||
536 | && strcmp(str, "lzma") == 0 | ||
537 | ) { | ||
538 | // lzma compression can't be detected | ||
539 | // set up decompressor without detection | ||
540 | setup_lzma_on_fd(rpm_fd); | ||
541 | } else { | ||
542 | setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); | ||
543 | } | ||
544 | |||
545 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) | ||
546 | bb_error_msg_and_die("error unpacking"); | ||
547 | |||
548 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
549 | close(rpm_fd); | ||
550 | } | ||
551 | |||
552 | if (SEAMLESS_COMPRESSION) { | ||
553 | check_errors_in_children(0); | ||
554 | return bb_got_signal; | ||
555 | } | ||
556 | return EXIT_SUCCESS; | ||
557 | } | ||
558 | |||
559 | #endif /* RPM2CPIO */ | ||
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c deleted file mode 100644 index 3e4a6a249..000000000 --- a/archival/rpm2cpio.c +++ /dev/null | |||
@@ -1,96 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini rpm2cpio implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2001 by Laurence Anderson | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | |||
10 | //config:config RPM2CPIO | ||
11 | //config: bool "rpm2cpio (20 kb)" | ||
12 | //config: default y | ||
13 | //config: help | ||
14 | //config: Converts a RPM file into a CPIO archive. | ||
15 | |||
16 | //applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
17 | //kbuild:lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o | ||
18 | |||
19 | //usage:#define rpm2cpio_trivial_usage | ||
20 | //usage: "package.rpm" | ||
21 | //usage:#define rpm2cpio_full_usage "\n\n" | ||
22 | //usage: "Output a cpio archive of the rpm file" | ||
23 | |||
24 | #include "libbb.h" | ||
25 | #include "bb_archive.h" | ||
26 | #include "rpm.h" | ||
27 | |||
28 | enum { rpm_fd = STDIN_FILENO }; | ||
29 | |||
30 | static unsigned skip_header(void) | ||
31 | { | ||
32 | struct rpm_header header; | ||
33 | unsigned len; | ||
34 | |||
35 | xread(rpm_fd, &header, sizeof(header)); | ||
36 | // if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) { | ||
37 | // bb_error_msg_and_die("invalid RPM header magic"); | ||
38 | // } | ||
39 | // if (header.version != 1) { | ||
40 | // bb_error_msg_and_die("unsupported RPM header version"); | ||
41 | // } | ||
42 | if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) { | ||
43 | bb_error_msg_and_die("invalid RPM header magic or unsupported version"); | ||
44 | // ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER)); | ||
45 | } | ||
46 | |||
47 | /* Seek past index entries, and past store */ | ||
48 | len = 16 * ntohl(header.entries) + ntohl(header.size); | ||
49 | seek_by_jump(rpm_fd, len); | ||
50 | |||
51 | return sizeof(header) + len; | ||
52 | } | ||
53 | |||
54 | /* No getopt required */ | ||
55 | int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
56 | int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | ||
57 | { | ||
58 | struct rpm_lead lead; | ||
59 | unsigned pos; | ||
60 | |||
61 | if (argv[1]) { | ||
62 | xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); | ||
63 | } | ||
64 | xread(rpm_fd, &lead, sizeof(lead)); | ||
65 | |||
66 | /* Just check the magic, the rest is irrelevant */ | ||
67 | if (lead.magic != htonl(RPM_LEAD_MAGIC)) { | ||
68 | bb_error_msg_and_die("invalid RPM magic"); | ||
69 | } | ||
70 | |||
71 | /* Skip the signature header, align to 8 bytes */ | ||
72 | pos = skip_header(); | ||
73 | seek_by_jump(rpm_fd, (-(int)pos) & 7); | ||
74 | |||
75 | /* Skip the main header */ | ||
76 | skip_header(); | ||
77 | |||
78 | //if (SEAMLESS_COMPRESSION) | ||
79 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | ||
80 | // signal(SIGCHLD, check_errors_in_children); | ||
81 | |||
82 | /* This works, but doesn't report uncompress errors (they happen in child) */ | ||
83 | setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); | ||
84 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) | ||
85 | bb_error_msg_and_die("error unpacking"); | ||
86 | |||
87 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
88 | close(rpm_fd); | ||
89 | } | ||
90 | |||
91 | if (SEAMLESS_COMPRESSION) { | ||
92 | check_errors_in_children(0); | ||
93 | return bb_got_signal; | ||
94 | } | ||
95 | return EXIT_SUCCESS; | ||
96 | } | ||
diff --git a/archival/tar.c b/archival/tar.c index d90a5dc4f..503444796 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -278,23 +278,6 @@ static void chksum_and_xwrite(int fd, struct tar_header_t* hp) | |||
278 | xwrite(fd, hp, sizeof(*hp)); | 278 | xwrite(fd, hp, sizeof(*hp)); |
279 | } | 279 | } |
280 | 280 | ||
281 | static void replace_symlink_placeholders(llist_t *list) | ||
282 | { | ||
283 | while (list) { | ||
284 | char *target; | ||
285 | |||
286 | target = list->data + strlen(list->data) + 1; | ||
287 | if (symlink(target, list->data)) { | ||
288 | /* shared message */ | ||
289 | bb_error_msg_and_die("can't create %slink '%s' to '%s'", | ||
290 | "sym", | ||
291 | list->data, target | ||
292 | ); | ||
293 | } | ||
294 | list = list->link; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS | 281 | #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS |
299 | static void writeLongname(int fd, int type, const char *name, int dir) | 282 | static void writeLongname(int fd, int type, const char *name, int dir) |
300 | { | 283 | { |
@@ -969,6 +952,11 @@ static const char tar_longopts[] ALIGN1 = | |||
969 | "exclude\0" Required_argument "\xff" | 952 | "exclude\0" Required_argument "\xff" |
970 | # endif | 953 | # endif |
971 | ; | 954 | ; |
955 | # define GETOPT32 getopt32long | ||
956 | # define LONGOPTS ,tar_longopts | ||
957 | #else | ||
958 | # define GETOPT32 getopt32 | ||
959 | # define LONGOPTS | ||
972 | #endif | 960 | #endif |
973 | 961 | ||
974 | int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 962 | int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -995,21 +983,8 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
995 | tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; | 983 | tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; |
996 | 984 | ||
997 | /* Prepend '-' to the first argument if required */ | 985 | /* Prepend '-' to the first argument if required */ |
998 | opt_complementary = "--:" // first arg is options | 986 | if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') |
999 | "tt:vv:" // count -t,-v | 987 | argv[1] = xasprintf("-%s", argv[1]); |
1000 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM | ||
1001 | "\xff::" // --exclude=PATTERN is a list | ||
1002 | #endif | ||
1003 | IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd | ||
1004 | IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive | ||
1005 | IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive | ||
1006 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | ||
1007 | ":\xf9+" // --strip-components=NUM | ||
1008 | #endif | ||
1009 | ; | ||
1010 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | ||
1011 | applet_long_options = tar_longopts; | ||
1012 | #endif | ||
1013 | #if ENABLE_DESKTOP | 988 | #if ENABLE_DESKTOP |
1014 | /* Lie to buildroot when it starts asking stupid questions. */ | 989 | /* Lie to buildroot when it starts asking stupid questions. */ |
1015 | if (argv[1] && strcmp(argv[1], "--version") == 0) { | 990 | if (argv[1] && strcmp(argv[1], "--version") == 0) { |
@@ -1046,7 +1021,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1046 | } | 1021 | } |
1047 | } | 1022 | } |
1048 | #endif | 1023 | #endif |
1049 | opt = getopt32(argv, | 1024 | opt = GETOPT32(argv, "^" |
1050 | "txC:f:Oopvk" | 1025 | "txC:f:Oopvk" |
1051 | IF_FEATURE_TAR_CREATE( "ch" ) | 1026 | IF_FEATURE_TAR_CREATE( "ch" ) |
1052 | IF_FEATURE_SEAMLESS_BZ2( "j" ) | 1027 | IF_FEATURE_SEAMLESS_BZ2( "j" ) |
@@ -1057,6 +1032,18 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1057 | IF_FEATURE_SEAMLESS_Z( "Z" ) | 1032 | IF_FEATURE_SEAMLESS_Z( "Z" ) |
1058 | IF_FEATURE_TAR_NOPRESERVE_TIME("m") | 1033 | IF_FEATURE_TAR_NOPRESERVE_TIME("m") |
1059 | IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components | 1034 | IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components |
1035 | "\0" | ||
1036 | "tt:vv:" // count -t,-v | ||
1037 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM | ||
1038 | "\xff::" // --exclude=PATTERN is a list | ||
1039 | #endif | ||
1040 | IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd | ||
1041 | IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive | ||
1042 | IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive | ||
1043 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | ||
1044 | ":\xf9+" // --strip-components=NUM | ||
1045 | #endif | ||
1046 | LONGOPTS | ||
1060 | , &base_dir // -C dir | 1047 | , &base_dir // -C dir |
1061 | , &tar_filename // -f filename | 1048 | , &tar_filename // -f filename |
1062 | IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T | 1049 | IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T |
@@ -1280,8 +1267,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1280 | while (get_header_tar(tar_handle) == EXIT_SUCCESS) | 1267 | while (get_header_tar(tar_handle) == EXIT_SUCCESS) |
1281 | bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ | 1268 | bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ |
1282 | 1269 | ||
1283 | replace_symlink_placeholders(tar_handle->symlink_placeholders); | ||
1284 | |||
1285 | /* Check that every file that should have been extracted was */ | 1270 | /* Check that every file that should have been extracted was */ |
1286 | while (tar_handle->accept) { | 1271 | while (tar_handle->accept) { |
1287 | if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) | 1272 | if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) |
diff --git a/archival/unzip.c b/archival/unzip.c index f37ea3519..233487697 100644 --- a/archival/unzip.c +++ b/archival/unzip.c | |||
@@ -371,9 +371,15 @@ static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn) | |||
371 | target[xstate.mem_output_size] = '\0'; | 371 | target[xstate.mem_output_size] = '\0'; |
372 | #endif | 372 | #endif |
373 | } | 373 | } |
374 | if (!unsafe_symlink_target(target)) { | ||
374 | //TODO: libbb candidate | 375 | //TODO: libbb candidate |
375 | if (symlink(target, dst_fn)) | 376 | if (symlink(target, dst_fn)) { |
376 | bb_perror_msg_and_die("can't create symlink '%s'", dst_fn); | 377 | /* shared message */ |
378 | bb_perror_msg_and_die("can't create %slink '%s' to '%s'", | ||
379 | "sym", dst_fn, target | ||
380 | ); | ||
381 | } | ||
382 | } | ||
377 | free(target); | 383 | free(target); |
378 | } | 384 | } |
379 | #endif | 385 | #endif |
diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig index 6ff68a092..415f5a802 100644 --- a/configs/TEST_nommu_defconfig +++ b/configs/TEST_nommu_defconfig | |||
@@ -37,7 +37,6 @@ CONFIG_SELINUX=y | |||
37 | CONFIG_FEATURE_PREFER_APPLETS=y | 37 | CONFIG_FEATURE_PREFER_APPLETS=y |
38 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 38 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
39 | CONFIG_FEATURE_SYSLOG=y | 39 | CONFIG_FEATURE_SYSLOG=y |
40 | CONFIG_FEATURE_HAVE_RPC=y | ||
41 | 40 | ||
42 | # | 41 | # |
43 | # Build Options | 42 | # Build Options |
diff --git a/configs/TEST_noprintf_defconfig b/configs/TEST_noprintf_defconfig index 4b2ef402a..9b378fd55 100644 --- a/configs/TEST_noprintf_defconfig +++ b/configs/TEST_noprintf_defconfig | |||
@@ -47,7 +47,6 @@ CONFIG_FEATURE_PIDFILE=y | |||
47 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 47 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
48 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 48 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
49 | # CONFIG_FEATURE_SYSLOG is not set | 49 | # CONFIG_FEATURE_SYSLOG is not set |
50 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
51 | 50 | ||
52 | # | 51 | # |
53 | # Build Options | 52 | # Build Options |
diff --git a/configs/TEST_rh9_defconfig b/configs/TEST_rh9_defconfig index 52f3e4670..4ac62b9da 100644 --- a/configs/TEST_rh9_defconfig +++ b/configs/TEST_rh9_defconfig | |||
@@ -46,7 +46,6 @@ CONFIG_FEATURE_SUID_CONFIG_QUIET=y | |||
46 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 46 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
47 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 47 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
48 | CONFIG_FEATURE_SYSLOG=y | 48 | CONFIG_FEATURE_SYSLOG=y |
49 | CONFIG_FEATURE_HAVE_RPC=y | ||
50 | 49 | ||
51 | # | 50 | # |
52 | # Build Options | 51 | # Build Options |
diff --git a/configs/android2_defconfig b/configs/android2_defconfig index 9202320a4..03323654d 100644 --- a/configs/android2_defconfig +++ b/configs/android2_defconfig | |||
@@ -49,7 +49,6 @@ CONFIG_LAST_SUPPORTED_WCHAR=0 | |||
49 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 49 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
51 | CONFIG_FEATURE_SYSLOG=y | 51 | CONFIG_FEATURE_SYSLOG=y |
52 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
53 | 52 | ||
54 | # | 53 | # |
55 | # Build Options | 54 | # Build Options |
diff --git a/configs/android_502_defconfig b/configs/android_502_defconfig index 1901bdbb0..6b640bfb7 100644 --- a/configs/android_502_defconfig +++ b/configs/android_502_defconfig | |||
@@ -123,7 +123,6 @@ CONFIG_FEATURE_SUID_CONFIG_QUIET=y | |||
123 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 123 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
124 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 124 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
125 | CONFIG_FEATURE_SYSLOG=y | 125 | CONFIG_FEATURE_SYSLOG=y |
126 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
127 | 126 | ||
128 | # | 127 | # |
129 | # Build Options | 128 | # Build Options |
diff --git a/configs/android_defconfig b/configs/android_defconfig index ea6e8a79e..3b34f37aa 100644 --- a/configs/android_defconfig +++ b/configs/android_defconfig | |||
@@ -49,7 +49,6 @@ CONFIG_LAST_SUPPORTED_WCHAR=0 | |||
49 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 49 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
51 | CONFIG_FEATURE_SYSLOG=y | 51 | CONFIG_FEATURE_SYSLOG=y |
52 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
53 | 52 | ||
54 | # | 53 | # |
55 | # Build Options | 54 | # Build Options |
diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig index 61871fcb1..7f65d544c 100644 --- a/configs/android_ndk_defconfig +++ b/configs/android_ndk_defconfig | |||
@@ -52,7 +52,6 @@ CONFIG_PID_FILE_PATH="" | |||
52 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 52 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
53 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 53 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
54 | CONFIG_FEATURE_SYSLOG=y | 54 | CONFIG_FEATURE_SYSLOG=y |
55 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
56 | 55 | ||
57 | # | 56 | # |
58 | # Build Options | 57 | # Build Options |
diff --git a/configs/cygwin_defconfig b/configs/cygwin_defconfig index 54aa44470..ee370a61d 100644 --- a/configs/cygwin_defconfig +++ b/configs/cygwin_defconfig | |||
@@ -49,7 +49,6 @@ CONFIG_FEATURE_SUID=y | |||
49 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 49 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
51 | CONFIG_FEATURE_SYSLOG=y | 51 | CONFIG_FEATURE_SYSLOG=y |
52 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
53 | 52 | ||
54 | # | 53 | # |
55 | # Build Options | 54 | # Build Options |
diff --git a/configs/freebsd_defconfig b/configs/freebsd_defconfig index fadbca13b..47e705963 100644 --- a/configs/freebsd_defconfig +++ b/configs/freebsd_defconfig | |||
@@ -49,7 +49,6 @@ CONFIG_FEATURE_SUID_CONFIG_QUIET=y | |||
49 | # CONFIG_FEATURE_PREFER_APPLETS is not set | 49 | # CONFIG_FEATURE_PREFER_APPLETS is not set |
50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | 50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" |
51 | CONFIG_FEATURE_SYSLOG=y | 51 | CONFIG_FEATURE_SYSLOG=y |
52 | # CONFIG_FEATURE_HAVE_RPC is not set | ||
53 | 52 | ||
54 | # | 53 | # |
55 | # Build Options | 54 | # Build Options |
diff --git a/console-tools/chvt.c b/console-tools/chvt.c index d8152de6b..75380a90b 100644 --- a/console-tools/chvt.c +++ b/console-tools/chvt.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: This program is used to change to another terminal. | 14 | //config: This program is used to change to another terminal. |
15 | //config: Example: chvt 4 (change to terminal /dev/tty4) | 15 | //config: Example: chvt 4 (change to terminal /dev/tty4) |
16 | 16 | ||
17 | //applet:IF_CHVT(APPLET(chvt, BB_DIR_USR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_CHVT(APPLET_NOEXEC(chvt, chvt, BB_DIR_USR_BIN, BB_SUID_DROP, chvt)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_CHVT) += chvt.o | 19 | //kbuild:lib-$(CONFIG_CHVT) += chvt.o |
20 | 20 | ||
diff --git a/console-tools/clear.c b/console-tools/clear.c index 13eec498b..3cc16257b 100644 --- a/console-tools/clear.c +++ b/console-tools/clear.c | |||
@@ -12,7 +12,7 @@ | |||
12 | //config: help | 12 | //config: help |
13 | //config: This program clears the terminal screen. | 13 | //config: This program clears the terminal screen. |
14 | 14 | ||
15 | //applet:IF_CLEAR(APPLET(clear, BB_DIR_USR_BIN, BB_SUID_DROP)) | 15 | //applet:IF_CLEAR(APPLET_NOFORK(clear, clear, BB_DIR_USR_BIN, BB_SUID_DROP, clear)) |
16 | 16 | ||
17 | //kbuild:lib-$(CONFIG_CLEAR) += clear.o | 17 | //kbuild:lib-$(CONFIG_CLEAR) += clear.o |
18 | 18 | ||
diff --git a/console-tools/deallocvt.c b/console-tools/deallocvt.c index 6ffb1471e..05731fb78 100644 --- a/console-tools/deallocvt.c +++ b/console-tools/deallocvt.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: help | 14 | //config: help |
15 | //config: This program deallocates unused virtual consoles. | 15 | //config: This program deallocates unused virtual consoles. |
16 | 16 | ||
17 | //applet:IF_DEALLOCVT(APPLET(deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_DEALLOCVT(APPLET_NOEXEC(deallocvt, deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP, deallocvt)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_DEALLOCVT) += deallocvt.o | 19 | //kbuild:lib-$(CONFIG_DEALLOCVT) += deallocvt.o |
20 | 20 | ||
diff --git a/console-tools/dumpkmap.c b/console-tools/dumpkmap.c index d4e2cf281..b803e579a 100644 --- a/console-tools/dumpkmap.c +++ b/console-tools/dumpkmap.c | |||
@@ -15,7 +15,8 @@ | |||
15 | //config: This program dumps the kernel's keyboard translation table to | 15 | //config: This program dumps the kernel's keyboard translation table to |
16 | //config: stdout, in binary format. You can then use loadkmap to load it. | 16 | //config: stdout, in binary format. You can then use loadkmap to load it. |
17 | 17 | ||
18 | //applet:IF_DUMPKMAP(APPLET(dumpkmap, BB_DIR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_DUMPKMAP(APPLET_NOEXEC(dumpkmap, dumpkmap, BB_DIR_BIN, BB_SUID_DROP, dumpkmap)) |
19 | /* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ | ||
19 | 20 | ||
20 | //kbuild:lib-$(CONFIG_DUMPKMAP) += dumpkmap.o | 21 | //kbuild:lib-$(CONFIG_DUMPKMAP) += dumpkmap.o |
21 | 22 | ||
@@ -47,8 +48,6 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) | |||
47 | { | 48 | { |
48 | struct kbentry ke; | 49 | struct kbentry ke; |
49 | int i, j, fd; | 50 | int i, j, fd; |
50 | #define flags bb_common_bufsiz1 | ||
51 | setup_common_bufsiz(); | ||
52 | 51 | ||
53 | /* When user accidentally runs "dumpkmap FILE" | 52 | /* When user accidentally runs "dumpkmap FILE" |
54 | * instead of "dumpkmap >FILE", we'd dump binary stuff to tty. | 53 | * instead of "dumpkmap >FILE", we'd dump binary stuff to tty. |
@@ -60,19 +59,8 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) | |||
60 | 59 | ||
61 | fd = get_console_fd_or_die(); | 60 | fd = get_console_fd_or_die(); |
62 | 61 | ||
63 | #if 0 | 62 | #define flags bb_common_bufsiz1 |
64 | write(STDOUT_FILENO, "bkeymap", 7); | 63 | setup_common_bufsiz(); |
65 | /* Here we want to set everything to 0 except for indexes: | ||
66 | * [0-2] [4-6] [8-10] [12] | ||
67 | */ | ||
68 | /*memset(flags, 0x00, MAX_NR_KEYMAPS); - already is */ | ||
69 | memset(flags, 0x01, 13); | ||
70 | flags[3] = flags[7] = flags[11] = 0; | ||
71 | /* dump flags */ | ||
72 | write(STDOUT_FILENO, flags, MAX_NR_KEYMAPS); | ||
73 | #define flags7 flags | ||
74 | #else | ||
75 | /* Same effect */ | ||
76 | /* 0 1 2 3 4 5 6 7 8 9 a b c=12 */ | 64 | /* 0 1 2 3 4 5 6 7 8 9 a b c=12 */ |
77 | memcpy(flags, "bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1", | 65 | memcpy(flags, "bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1", |
78 | /* Can use sizeof, or sizeof-1. sizeof is even, using that */ | 66 | /* Can use sizeof, or sizeof-1. sizeof is even, using that */ |
@@ -80,7 +68,6 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) | |||
80 | ); | 68 | ); |
81 | write(STDOUT_FILENO, flags, 7 + MAX_NR_KEYMAPS); | 69 | write(STDOUT_FILENO, flags, 7 + MAX_NR_KEYMAPS); |
82 | #define flags7 (flags + 7) | 70 | #define flags7 (flags + 7) |
83 | #endif | ||
84 | 71 | ||
85 | for (i = 0; i < 13; i++) { | 72 | for (i = 0; i < 13; i++) { |
86 | if (flags7[i]) { | 73 | if (flags7[i]) { |
diff --git a/console-tools/fgconsole.c b/console-tools/fgconsole.c index 64311f6ea..a353becd5 100644 --- a/console-tools/fgconsole.c +++ b/console-tools/fgconsole.c | |||
@@ -13,7 +13,7 @@ | |||
13 | //config: help | 13 | //config: help |
14 | //config: This program prints active (foreground) console number. | 14 | //config: This program prints active (foreground) console number. |
15 | 15 | ||
16 | //applet:IF_FGCONSOLE(APPLET(fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP)) | 16 | //applet:IF_FGCONSOLE(APPLET_NOEXEC(fgconsole, fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP, fgconsole)) |
17 | 17 | ||
18 | //kbuild:lib-$(CONFIG_FGCONSOLE) += fgconsole.o | 18 | //kbuild:lib-$(CONFIG_FGCONSOLE) += fgconsole.o |
19 | 19 | ||
diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index d81c56e92..f16449dcd 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c | |||
@@ -15,19 +15,19 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: This program reports and sets keyboard mode. | 16 | //config: This program reports and sets keyboard mode. |
17 | 17 | ||
18 | //applet:IF_KBD_MODE(APPLET(kbd_mode, BB_DIR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_KBD_MODE(APPLET_NOEXEC(kbd_mode, kbd_mode, BB_DIR_BIN, BB_SUID_DROP, kbd_mode)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_KBD_MODE) += kbd_mode.o | 20 | //kbuild:lib-$(CONFIG_KBD_MODE) += kbd_mode.o |
21 | 21 | ||
22 | //usage:#define kbd_mode_trivial_usage | 22 | //usage:#define kbd_mode_trivial_usage |
23 | //usage: "[-a|k|s|u] [-C TTY]" | 23 | //usage: "[-a|k|s|u] [-C TTY]" |
24 | //usage:#define kbd_mode_full_usage "\n\n" | 24 | //usage:#define kbd_mode_full_usage "\n\n" |
25 | //usage: "Report or set the keyboard mode\n" | 25 | //usage: "Report or set VT console keyboard mode\n" |
26 | //usage: "\n -a Default (ASCII)" | 26 | //usage: "\n -a Default (ASCII)" |
27 | //usage: "\n -k Medium-raw (keyboard)" | 27 | //usage: "\n -k Medium-raw (keycode)" |
28 | //usage: "\n -s Raw (scancode)" | 28 | //usage: "\n -s Raw (scancode)" |
29 | //usage: "\n -u Unicode (utf-8)" | 29 | //usage: "\n -u Unicode (utf-8)" |
30 | //usage: "\n -C TTY Affect TTY instead of /dev/tty" | 30 | //usage: "\n -C TTY Affect TTY" |
31 | 31 | ||
32 | #include "libbb.h" | 32 | #include "libbb.h" |
33 | #include <linux/kd.h> | 33 | #include <linux/kd.h> |
@@ -43,11 +43,20 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) | |||
43 | }; | 43 | }; |
44 | int fd; | 44 | int fd; |
45 | unsigned opt; | 45 | unsigned opt; |
46 | const char *tty_name = CURRENT_TTY; | 46 | const char *tty_name; |
47 | 47 | ||
48 | opt = getopt32(argv, "sakuC:", &tty_name); | 48 | opt = getopt32(argv, "sakuC:", &tty_name); |
49 | fd = xopen_nonblocking(tty_name); | 49 | if (opt & 0x10) { |
50 | opt &= 0xf; /* clear -C bit, see (*) */ | 50 | opt &= 0xf; /* clear -C bit, see (*) */ |
51 | fd = xopen_nonblocking(tty_name); | ||
52 | } else { | ||
53 | /* kbd-2.0.3 tries in sequence: | ||
54 | * fd#0, /dev/tty, /dev/tty0. | ||
55 | * get_console_fd_or_die: /dev/console, /dev/tty0, /dev/tty. | ||
56 | * kbd-2.0.3 checks KDGKBTYPE, get_console_fd_or_die checks too. | ||
57 | */ | ||
58 | fd = get_console_fd_or_die(); | ||
59 | } | ||
51 | 60 | ||
52 | if (!opt) { /* print current setting */ | 61 | if (!opt) { /* print current setting */ |
53 | const char *mode = "unknown"; | 62 | const char *mode = "unknown"; |
@@ -62,9 +71,19 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) | |||
62 | mode = "mediumraw (keycode)"; | 71 | mode = "mediumraw (keycode)"; |
63 | else if (m == K_UNICODE) | 72 | else if (m == K_UNICODE) |
64 | mode = "Unicode (UTF-8)"; | 73 | mode = "Unicode (UTF-8)"; |
74 | else if (m == 4 /*K_OFF*/) /* kbd-2.0.3 does not show this mode, says "unknown" */ | ||
75 | mode = "off"; | ||
65 | printf("The keyboard is in %s mode\n", mode); | 76 | printf("The keyboard is in %s mode\n", mode); |
66 | } else { | 77 | } else { |
67 | /* here we depend on specific bits assigned to options (*) */ | 78 | /* here we depend on specific bits assigned to options (*) |
79 | * KDSKBMODE constants have these values: | ||
80 | * #define K_RAW 0x00 | ||
81 | * #define K_XLATE 0x01 | ||
82 | * #define K_MEDIUMRAW 0x02 | ||
83 | * #define K_UNICODE 0x03 | ||
84 | * #define K_OFF 0x04 | ||
85 | * (looks like "-ak" together would cause the same effect as -u) | ||
86 | */ | ||
68 | opt = opt & UNICODE ? 3 : opt >> 1; | 87 | opt = opt & UNICODE ? 3 : opt >> 1; |
69 | /* double cast prevents warnings about widening conversion */ | 88 | /* double cast prevents warnings about widening conversion */ |
70 | xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); | 89 | xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); |
diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index 6dc8fa831..81d0c3db4 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c | |||
@@ -51,31 +51,12 @@ | |||
51 | //config: default y | 51 | //config: default y |
52 | //config: depends on LOADFONT || SETFONT | 52 | //config: depends on LOADFONT || SETFONT |
53 | 53 | ||
54 | //applet:IF_LOADFONT(APPLET(loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 54 | //applet:IF_LOADFONT(APPLET_NOEXEC(loadfont, loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP, loadfont)) |
55 | //applet:IF_SETFONT(APPLET(setfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 55 | //applet:IF_SETFONT(APPLET_NOEXEC(setfont, setfont, BB_DIR_USR_SBIN, BB_SUID_DROP, setfont)) |
56 | 56 | ||
57 | //kbuild:lib-$(CONFIG_LOADFONT) += loadfont.o | 57 | //kbuild:lib-$(CONFIG_LOADFONT) += loadfont.o |
58 | //kbuild:lib-$(CONFIG_SETFONT) += loadfont.o | 58 | //kbuild:lib-$(CONFIG_SETFONT) += loadfont.o |
59 | 59 | ||
60 | //usage:#define loadfont_trivial_usage | ||
61 | //usage: "< font" | ||
62 | //usage:#define loadfont_full_usage "\n\n" | ||
63 | //usage: "Load a console font from stdin" | ||
64 | /* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ | ||
65 | //usage: | ||
66 | //usage:#define loadfont_example_usage | ||
67 | //usage: "$ loadfont < /etc/i18n/fontname\n" | ||
68 | //usage: | ||
69 | //usage:#define setfont_trivial_usage | ||
70 | //usage: "FONT [-m MAPFILE] [-C TTY]" | ||
71 | //usage:#define setfont_full_usage "\n\n" | ||
72 | //usage: "Load a console font\n" | ||
73 | //usage: "\n -m MAPFILE Load console screen map" | ||
74 | //usage: "\n -C TTY Affect TTY instead of /dev/tty" | ||
75 | //usage: | ||
76 | //usage:#define setfont_example_usage | ||
77 | //usage: "$ setfont -m koi8-r /etc/i18n/fontname\n" | ||
78 | |||
79 | #include "libbb.h" | 60 | #include "libbb.h" |
80 | #include <sys/kd.h> | 61 | #include <sys/kd.h> |
81 | 62 | ||
@@ -352,6 +333,14 @@ static void do_load(int fd, unsigned char *buffer, size_t len) | |||
352 | 333 | ||
353 | 334 | ||
354 | #if ENABLE_LOADFONT | 335 | #if ENABLE_LOADFONT |
336 | //usage:#define loadfont_trivial_usage | ||
337 | //usage: "< font" | ||
338 | //usage:#define loadfont_full_usage "\n\n" | ||
339 | //usage: "Load a console font from stdin" | ||
340 | /* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ | ||
341 | //usage: | ||
342 | //usage:#define loadfont_example_usage | ||
343 | //usage: "$ loadfont < /etc/i18n/fontname\n" | ||
355 | int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 344 | int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
356 | int loadfont_main(int argc UNUSED_PARAM, char **argv) | 345 | int loadfont_main(int argc UNUSED_PARAM, char **argv) |
357 | { | 346 | { |
@@ -359,8 +348,7 @@ int loadfont_main(int argc UNUSED_PARAM, char **argv) | |||
359 | unsigned char *buffer; | 348 | unsigned char *buffer; |
360 | 349 | ||
361 | // no arguments allowed! | 350 | // no arguments allowed! |
362 | opt_complementary = "=0"; | 351 | getopt32(argv, "^" "" "\0" "=0"); |
363 | getopt32(argv, ""); | ||
364 | 352 | ||
365 | /* | 353 | /* |
366 | * We used to look at the length of the input file | 354 | * We used to look at the length of the input file |
@@ -380,11 +368,9 @@ int loadfont_main(int argc UNUSED_PARAM, char **argv) | |||
380 | } | 368 | } |
381 | #endif | 369 | #endif |
382 | 370 | ||
383 | #if ENABLE_SETFONT | ||
384 | |||
385 | /* | ||
386 | kbd-1.12: | ||
387 | 371 | ||
372 | #if ENABLE_SETFONT | ||
373 | /* kbd-1.12: | ||
388 | setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] | 374 | setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] |
389 | [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console] | 375 | [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console] |
390 | [-hNN] [-v] [-V] | 376 | [-hNN] [-v] [-V] |
@@ -414,8 +400,17 @@ setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] | |||
414 | -v Verbose | 400 | -v Verbose |
415 | -V Version | 401 | -V Version |
416 | */ | 402 | */ |
403 | //usage:#define setfont_trivial_usage | ||
404 | //usage: "FONT [-m MAPFILE] [-C TTY]" | ||
405 | //usage:#define setfont_full_usage "\n\n" | ||
406 | //usage: "Load a console font\n" | ||
407 | //usage: "\n -m MAPFILE Load console screen map" | ||
408 | //usage: "\n -C TTY Affect TTY instead of /dev/tty" | ||
409 | //usage: | ||
410 | //usage:#define setfont_example_usage | ||
411 | //usage: "$ setfont -m koi8-r /etc/i18n/fontname\n" | ||
417 | 412 | ||
418 | #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP | 413 | # if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP |
419 | static int ctoi(char *s) | 414 | static int ctoi(char *s) |
420 | { | 415 | { |
421 | if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0') | 416 | if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0') |
@@ -429,7 +424,7 @@ static int ctoi(char *s) | |||
429 | return -1; | 424 | return -1; |
430 | return xstrtoul(s, 0); | 425 | return xstrtoul(s, 0); |
431 | } | 426 | } |
432 | #endif | 427 | # endif |
433 | 428 | ||
434 | int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 429 | int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
435 | int setfont_main(int argc UNUSED_PARAM, char **argv) | 430 | int setfont_main(int argc UNUSED_PARAM, char **argv) |
@@ -441,8 +436,7 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) | |||
441 | char *mapfilename; | 436 | char *mapfilename; |
442 | const char *tty_name = CURRENT_TTY; | 437 | const char *tty_name = CURRENT_TTY; |
443 | 438 | ||
444 | opt_complementary = "=1"; | 439 | opts = getopt32(argv, "^" "m:C:" "\0" "=1", &mapfilename, &tty_name); |
445 | opts = getopt32(argv, "m:C:", &mapfilename, &tty_name); | ||
446 | argv += optind; | 440 | argv += optind; |
447 | 441 | ||
448 | fd = xopen_nonblocking(tty_name); | 442 | fd = xopen_nonblocking(tty_name); |
@@ -480,7 +474,7 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) | |||
480 | if (len == 2*E_TABSZ) | 474 | if (len == 2*E_TABSZ) |
481 | mode = PIO_UNISCRNMAP; | 475 | mode = PIO_UNISCRNMAP; |
482 | } | 476 | } |
483 | #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP | 477 | # if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP |
484 | // assume textual Unicode console maps: | 478 | // assume textual Unicode console maps: |
485 | // 0x00 U+0000 # NULL (NUL) | 479 | // 0x00 U+0000 # NULL (NUL) |
486 | // 0x01 U+0001 # START OF HEADING (SOH) | 480 | // 0x01 U+0001 # START OF HEADING (SOH) |
@@ -527,7 +521,7 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) | |||
527 | } | 521 | } |
528 | #undef unicodes | 522 | #undef unicodes |
529 | } | 523 | } |
530 | #endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP | 524 | # endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP |
531 | 525 | ||
532 | // do set screen map | 526 | // do set screen map |
533 | xioctl(fd, mode, map); | 527 | xioctl(fd, mode, map); |
diff --git a/console-tools/loadkmap.c b/console-tools/loadkmap.c index 839dc2083..404aba1fb 100644 --- a/console-tools/loadkmap.c +++ b/console-tools/loadkmap.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: This program loads a keyboard translation table from | 14 | //config: This program loads a keyboard translation table from |
15 | //config: standard input. | 15 | //config: standard input. |
16 | 16 | ||
17 | //applet:IF_LOADKMAP(APPLET(loadkmap, BB_DIR_SBIN, BB_SUID_DROP)) | 17 | //applet:IF_LOADKMAP(APPLET_NOEXEC(loadkmap, loadkmap, BB_DIR_SBIN, BB_SUID_DROP, loadkmap)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_LOADKMAP) += loadkmap.o | 19 | //kbuild:lib-$(CONFIG_LOADKMAP) += loadkmap.o |
20 | 20 | ||
diff --git a/console-tools/openvt.c b/console-tools/openvt.c index f3db28367..423122fe9 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c | |||
@@ -99,7 +99,7 @@ static int find_free_vtno(void) | |||
99 | /*xfunc_error_retval = 3; - do we need compat? */ | 99 | /*xfunc_error_retval = 3; - do we need compat? */ |
100 | if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0) | 100 | if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0) |
101 | bb_perror_msg_and_die("can't find open VT"); | 101 | bb_perror_msg_and_die("can't find open VT"); |
102 | // Not really needed, grep for DAEMON_ONLY_SANITIZE | 102 | // Not really needed, grep for DAEMON_CLOSE_EXTRA_FDS |
103 | // if (fd > 2) | 103 | // if (fd > 2) |
104 | // close(fd); | 104 | // close(fd); |
105 | return vtno; | 105 | return vtno; |
@@ -155,7 +155,7 @@ int openvt_main(int argc UNUSED_PARAM, char **argv) | |||
155 | /* Grab new VT */ | 155 | /* Grab new VT */ |
156 | sprintf(vtname, VC_FORMAT, vtno); | 156 | sprintf(vtname, VC_FORMAT, vtno); |
157 | /* (Try to) clean up stray open fds above fd 2 */ | 157 | /* (Try to) clean up stray open fds above fd 2 */ |
158 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL); | 158 | bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); |
159 | close(STDIN_FILENO); | 159 | close(STDIN_FILENO); |
160 | /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */ | 160 | /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */ |
161 | xopen(vtname, O_RDWR); | 161 | xopen(vtname, O_RDWR); |
diff --git a/console-tools/reset.c b/console-tools/reset.c index 04e5b0ca1..f2b900ddb 100644 --- a/console-tools/reset.c +++ b/console-tools/reset.c | |||
@@ -16,7 +16,7 @@ | |||
16 | //config: This program is used to reset the terminal screen, if it | 16 | //config: This program is used to reset the terminal screen, if it |
17 | //config: gets messed up. | 17 | //config: gets messed up. |
18 | 18 | ||
19 | //applet:IF_RESET(APPLET(reset, BB_DIR_USR_BIN, BB_SUID_DROP)) | 19 | //applet:IF_RESET(APPLET_NOEXEC(reset, reset, BB_DIR_USR_BIN, BB_SUID_DROP, reset)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_RESET) += reset.o | 21 | //kbuild:lib-$(CONFIG_RESET) += reset.o |
22 | 22 | ||
diff --git a/console-tools/resize.c b/console-tools/resize.c index 62928a01e..8aa487c41 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c | |||
@@ -23,7 +23,8 @@ | |||
23 | //config: E.g.: | 23 | //config: E.g.: |
24 | //config: COLUMNS=80;LINES=44;export COLUMNS LINES; | 24 | //config: COLUMNS=80;LINES=44;export COLUMNS LINES; |
25 | 25 | ||
26 | //applet:IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP)) | 26 | //applet:IF_RESIZE(APPLET_NOEXEC(resize, resize, BB_DIR_USR_BIN, BB_SUID_DROP, resize)) |
27 | /* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ | ||
27 | 28 | ||
28 | //kbuild:lib-$(CONFIG_RESIZE) += resize.o | 29 | //kbuild:lib-$(CONFIG_RESIZE) += resize.o |
29 | 30 | ||
@@ -63,6 +64,7 @@ int resize_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
63 | */ | 64 | */ |
64 | 65 | ||
65 | tcgetattr(STDERR_FILENO, old_termios_p); /* fiddle echo */ | 66 | tcgetattr(STDERR_FILENO, old_termios_p); /* fiddle echo */ |
67 | //TODO: die if the above fails? | ||
66 | memcpy(&new, old_termios_p, sizeof(new)); | 68 | memcpy(&new, old_termios_p, sizeof(new)); |
67 | new.c_cflag |= (CLOCAL | CREAD); | 69 | new.c_cflag |= (CLOCAL | CREAD); |
68 | new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); | 70 | new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); |
diff --git a/console-tools/setconsole.c b/console-tools/setconsole.c index ad0f756ca..bad2b76e4 100644 --- a/console-tools/setconsole.c +++ b/console-tools/setconsole.c | |||
@@ -12,23 +12,31 @@ | |||
12 | //config: default y | 12 | //config: default y |
13 | //config: select PLATFORM_LINUX | 13 | //config: select PLATFORM_LINUX |
14 | //config: help | 14 | //config: help |
15 | //config: This program redirects the system console to another device, | 15 | //config: Redirect writes to /dev/console to another device, |
16 | //config: like the current tty while logged in via telnet. | 16 | //config: like the current tty while logged in via telnet. |
17 | //config: This does not redirect kernel log, only writes | ||
18 | //config: from user space. | ||
17 | //config: | 19 | //config: |
18 | //config:config FEATURE_SETCONSOLE_LONG_OPTIONS | 20 | //config:config FEATURE_SETCONSOLE_LONG_OPTIONS |
19 | //config: bool "Enable long options" | 21 | //config: bool "Enable long options" |
20 | //config: default y | 22 | //config: default y |
21 | //config: depends on SETCONSOLE && LONG_OPTS | 23 | //config: depends on SETCONSOLE && LONG_OPTS |
22 | 24 | ||
23 | //applet:IF_SETCONSOLE(APPLET(setconsole, BB_DIR_SBIN, BB_SUID_DROP)) | 25 | //applet:IF_SETCONSOLE(APPLET_NOEXEC(setconsole, setconsole, BB_DIR_SBIN, BB_SUID_DROP, setconsole)) |
24 | 26 | ||
25 | //kbuild:lib-$(CONFIG_SETCONSOLE) += setconsole.o | 27 | //kbuild:lib-$(CONFIG_SETCONSOLE) += setconsole.o |
26 | 28 | ||
27 | //usage:#define setconsole_trivial_usage | 29 | //usage:#define setconsole_trivial_usage |
28 | //usage: "[-r" IF_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]" | 30 | //usage: "[-r] [DEVICE]" |
29 | //usage:#define setconsole_full_usage "\n\n" | 31 | //usage:#define setconsole_full_usage "\n\n" |
30 | //usage: "Redirect system console output to DEVICE (default: /dev/tty)\n" | 32 | //usage: "Make writes to /dev/console appear on DEVICE (default: /dev/tty)." |
31 | //usage: "\n -r Reset output to /dev/console" | 33 | //usage: "\n""Does not redirect kernel log output or reads from /dev/console." |
34 | //usage: "\n" | ||
35 | //usage: "\n"" -r Reset: writes to /dev/console go to kernel log tty(s)" | ||
36 | |||
37 | /* It was a bbox-specific invention, but SUSE does have a similar utility. | ||
38 | * SUSE has no -r option, though. | ||
39 | */ | ||
32 | 40 | ||
33 | #include "libbb.h" | 41 | #include "libbb.h" |
34 | 42 | ||
@@ -36,17 +44,10 @@ int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
36 | int setconsole_main(int argc UNUSED_PARAM, char **argv) | 44 | int setconsole_main(int argc UNUSED_PARAM, char **argv) |
37 | { | 45 | { |
38 | const char *device = CURRENT_TTY; | 46 | const char *device = CURRENT_TTY; |
39 | bool reset; | 47 | int reset; |
40 | 48 | ||
41 | #if ENABLE_FEATURE_SETCONSOLE_LONG_OPTIONS | ||
42 | static const char setconsole_longopts[] ALIGN1 = | ||
43 | "reset\0" No_argument "r" | ||
44 | ; | ||
45 | applet_long_options = setconsole_longopts; | ||
46 | #endif | ||
47 | /* at most one non-option argument */ | 49 | /* at most one non-option argument */ |
48 | opt_complementary = "?1"; | 50 | reset = getopt32(argv, "^" "r" "\0" "?1"); |
49 | reset = getopt32(argv, "r"); | ||
50 | 51 | ||
51 | argv += 1 + reset; | 52 | argv += 1 + reset; |
52 | if (*argv) { | 53 | if (*argv) { |
@@ -56,6 +57,9 @@ int setconsole_main(int argc UNUSED_PARAM, char **argv) | |||
56 | device = DEV_CONSOLE; | 57 | device = DEV_CONSOLE; |
57 | } | 58 | } |
58 | 59 | ||
60 | //TODO: fails if TIOCCONS redir is already active to some tty. | ||
61 | //I think SUSE version first does TIOCCONS on /dev/console fd (iow: resets) | ||
62 | //then TIOCCONS to new tty? | ||
59 | xioctl(xopen(device, O_WRONLY), TIOCCONS, NULL); | 63 | xioctl(xopen(device, O_WRONLY), TIOCCONS, NULL); |
60 | return EXIT_SUCCESS; | 64 | return EXIT_SUCCESS; |
61 | } | 65 | } |
diff --git a/console-tools/setkeycodes.c b/console-tools/setkeycodes.c index 543fbe3e0..1363ac9d1 100644 --- a/console-tools/setkeycodes.c +++ b/console-tools/setkeycodes.c | |||
@@ -16,17 +16,16 @@ | |||
16 | //config: This program loads entries into the kernel's scancode-to-keycode | 16 | //config: This program loads entries into the kernel's scancode-to-keycode |
17 | //config: map, allowing unusual keyboards to generate usable keycodes. | 17 | //config: map, allowing unusual keyboards to generate usable keycodes. |
18 | 18 | ||
19 | //applet:IF_SETKEYCODES(APPLET(setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP)) | 19 | //applet:IF_SETKEYCODES(APPLET_NOEXEC(setkeycodes, setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP, setkeycodes)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_SETKEYCODES) += setkeycodes.o | 21 | //kbuild:lib-$(CONFIG_SETKEYCODES) += setkeycodes.o |
22 | 22 | ||
23 | //usage:#define setkeycodes_trivial_usage | 23 | //usage:#define setkeycodes_trivial_usage |
24 | //usage: "SCANCODE KEYCODE..." | 24 | //usage: "{ SCANCODE KEYCODE }..." |
25 | //usage:#define setkeycodes_full_usage "\n\n" | 25 | //usage:#define setkeycodes_full_usage "\n\n" |
26 | //usage: "Set entries into the kernel's scancode-to-keycode map,\n" | 26 | //usage: "Modify kernel's scancode-to-keycode map,\n" |
27 | //usage: "allowing unusual keyboards to generate usable keycodes.\n\n" | 27 | //usage: "allowing unusual keyboards to generate usable keycodes.\n\n" |
28 | //usage: "SCANCODE may be either xx or e0xx (hexadecimal),\n" | 28 | //usage: "SCANCODE is either xx or e0xx (hexadecimal), KEYCODE is decimal." |
29 | //usage: "and KEYCODE is given in decimal." | ||
30 | //usage: | 29 | //usage: |
31 | //usage:#define setkeycodes_example_usage | 30 | //usage:#define setkeycodes_example_usage |
32 | //usage: "$ setkeycodes e030 127\n" | 31 | //usage: "$ setkeycodes e030 127\n" |
@@ -45,7 +44,6 @@ int setkeycodes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
45 | int setkeycodes_main(int argc, char **argv) | 44 | int setkeycodes_main(int argc, char **argv) |
46 | { | 45 | { |
47 | int fd; | 46 | int fd; |
48 | struct kbkeycode a; | ||
49 | 47 | ||
50 | if (!(argc & 1) /* if even */ || argc < 2) { | 48 | if (!(argc & 1) /* if even */ || argc < 2) { |
51 | bb_show_usage(); | 49 | bb_show_usage(); |
@@ -54,7 +52,10 @@ int setkeycodes_main(int argc, char **argv) | |||
54 | fd = get_console_fd_or_die(); | 52 | fd = get_console_fd_or_die(); |
55 | 53 | ||
56 | while (argv[1]) { | 54 | while (argv[1]) { |
57 | int sc = xstrtoul_range(argv[1], 16, 0, 0xe07f); | 55 | struct kbkeycode a; |
56 | int sc; | ||
57 | |||
58 | sc = xstrtoul_range(argv[1], 16, 0, 0xe07f); | ||
58 | if (sc >= 0xe000) { | 59 | if (sc >= 0xe000) { |
59 | sc -= 0xe000; | 60 | sc -= 0xe000; |
60 | sc += 0x0080; | 61 | sc += 0x0080; |
diff --git a/console-tools/setlogcons.c b/console-tools/setlogcons.c index 1b5814eee..6778a4d2b 100644 --- a/console-tools/setlogcons.c +++ b/console-tools/setlogcons.c | |||
@@ -15,14 +15,26 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: This program redirects the output console of kernel messages. | 16 | //config: This program redirects the output console of kernel messages. |
17 | 17 | ||
18 | //applet:IF_SETLOGCONS(APPLET(setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 18 | //applet:IF_SETLOGCONS(APPLET_NOEXEC(setlogcons, setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP, setlogcons)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_SETLOGCONS) += setlogcons.o | 20 | //kbuild:lib-$(CONFIG_SETLOGCONS) += setlogcons.o |
21 | 21 | ||
22 | //usage:#define setlogcons_trivial_usage | 22 | //usage:#define setlogcons_trivial_usage |
23 | //usage: "[N]" | 23 | //usage: "[N]" |
24 | //usage:#define setlogcons_full_usage "\n\n" | 24 | //usage:#define setlogcons_full_usage "\n\n" |
25 | //usage: "Redirect the kernel output to console N. Default:0 (current console)" | 25 | //usage: "Pin kernel output to VT console N. Default:0 (do not pin)" |
26 | |||
27 | // Comment from kernel source: | ||
28 | /* ... | ||
29 | * By default, the kernel messages are always printed on the current virtual | ||
30 | * console. However, the user may modify that default with the | ||
31 | * TIOCL_SETKMSGREDIRECT ioctl call. | ||
32 | * | ||
33 | * This function sets the kernel message console to be @new. It returns the old | ||
34 | * virtual console number. The virtual terminal number 0 (both as parameter and | ||
35 | * return value) means no redirection (i.e. always printed on the currently | ||
36 | * active console). | ||
37 | */ | ||
26 | 38 | ||
27 | #include "libbb.h" | 39 | #include "libbb.h" |
28 | 40 | ||
@@ -33,8 +45,8 @@ int setlogcons_main(int argc UNUSED_PARAM, char **argv) | |||
33 | char fn; | 45 | char fn; |
34 | char subarg; | 46 | char subarg; |
35 | } arg = { | 47 | } arg = { |
36 | 11, /* redirect kernel messages */ | 48 | 11, /* redirect kernel messages (TIOCL_SETKMSGREDIRECT) */ |
37 | 0 /* to specified console (current as default) */ | 49 | 0 |
38 | }; | 50 | }; |
39 | 51 | ||
40 | if (argv[1]) | 52 | if (argv[1]) |
diff --git a/coreutils/cat.c b/coreutils/cat.c index 390254512..7e35fa5ee 100644 --- a/coreutils/cat.c +++ b/coreutils/cat.c | |||
@@ -170,9 +170,11 @@ int cat_main(int argc UNUSED_PARAM, char **argv) | |||
170 | { | 170 | { |
171 | unsigned opts; | 171 | unsigned opts; |
172 | 172 | ||
173 | IF_FEATURE_CATV(opt_complementary = "Aetv"; /* -A == -vet */) | 173 | opts = getopt32(argv, IF_FEATURE_CATV("^") |
174 | /* -u is ignored ("unbuffered") */ | 174 | /* -u is ignored ("unbuffered") */ |
175 | opts = getopt32(argv, IF_FEATURE_CATV("etvA") IF_FEATURE_CATN("nb") "u"); | 175 | IF_FEATURE_CATV("etvA")IF_FEATURE_CATN("nb")"u" |
176 | IF_FEATURE_CATV("\0" "Aetv" /* -A == -vet */) | ||
177 | ); | ||
176 | argv += optind; | 178 | argv += optind; |
177 | 179 | ||
178 | /* Read from stdin if there's nothing else to do. */ | 180 | /* Read from stdin if there's nothing else to do. */ |
diff --git a/coreutils/chmod.c b/coreutils/chmod.c index 2174334d1..88989bf67 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c | |||
@@ -123,8 +123,7 @@ int chmod_main(int argc UNUSED_PARAM, char **argv) | |||
123 | } | 123 | } |
124 | 124 | ||
125 | /* Parse options */ | 125 | /* Parse options */ |
126 | opt_complementary = "-2"; | 126 | getopt32(argv, "^" OPT_STR "\0" "-2"); |
127 | getopt32(argv, ("-"OPT_STR) + 1); /* Reuse string */ | ||
128 | argv += optind; | 127 | argv += optind; |
129 | 128 | ||
130 | /* Restore option-like mode if needed */ | 129 | /* Restore option-like mode if needed */ |
diff --git a/coreutils/chown.c b/coreutils/chown.c index 1bfc725cc..985d18d6f 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c | |||
@@ -55,7 +55,7 @@ | |||
55 | /* This is a NOEXEC applet. Be very careful! */ | 55 | /* This is a NOEXEC applet. Be very careful! */ |
56 | 56 | ||
57 | 57 | ||
58 | #define OPT_STR ("Rh" IF_DESKTOP("vcfLHP")) | 58 | #define OPT_STR "Rh" IF_DESKTOP("vcfLHP") |
59 | #define BIT_RECURSE 1 | 59 | #define BIT_RECURSE 1 |
60 | #define OPT_RECURSE (opt & 1) | 60 | #define OPT_RECURSE (opt & 1) |
61 | #define OPT_NODEREF (opt & 2) | 61 | #define OPT_NODEREF (opt & 2) |
@@ -128,10 +128,10 @@ int chown_main(int argc UNUSED_PARAM, char **argv) | |||
128 | struct param_t param; | 128 | struct param_t param; |
129 | 129 | ||
130 | #if ENABLE_FEATURE_CHOWN_LONG_OPTIONS | 130 | #if ENABLE_FEATURE_CHOWN_LONG_OPTIONS |
131 | applet_long_options = chown_longopts; | 131 | opt = getopt32long(argv, "^" OPT_STR "\0" "=2", chown_longopts); |
132 | #else | ||
133 | opt = getopt32(argv, "^" OPT_STR "\0" "=2"); | ||
132 | #endif | 134 | #endif |
133 | opt_complementary = "-2"; | ||
134 | opt = getopt32(argv, OPT_STR); | ||
135 | argv += optind; | 135 | argv += optind; |
136 | 136 | ||
137 | /* This matches coreutils behavior (almost - see below) */ | 137 | /* This matches coreutils behavior (almost - see below) */ |
diff --git a/coreutils/chroot.c b/coreutils/chroot.c index 44a587fe0..78751df84 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c | |||
@@ -11,9 +11,9 @@ | |||
11 | //config: default y | 11 | //config: default y |
12 | //config: help | 12 | //config: help |
13 | //config: chroot is used to change the root directory and run a command. | 13 | //config: chroot is used to change the root directory and run a command. |
14 | //config: The default command is `/bin/sh'. | 14 | //config: The default command is '/bin/sh'. |
15 | 15 | ||
16 | //applet:IF_CHROOT(APPLET(chroot, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 16 | //applet:IF_CHROOT(APPLET_NOEXEC(chroot, chroot, BB_DIR_USR_SBIN, BB_SUID_DROP, chroot)) |
17 | 17 | ||
18 | //kbuild:lib-$(CONFIG_CHROOT) += chroot.o | 18 | //kbuild:lib-$(CONFIG_CHROOT) += chroot.o |
19 | 19 | ||
@@ -40,6 +40,7 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) | |||
40 | ++argv; | 40 | ++argv; |
41 | if (!*argv) | 41 | if (!*argv) |
42 | bb_show_usage(); | 42 | bb_show_usage(); |
43 | |||
43 | xchroot(*argv); | 44 | xchroot(*argv); |
44 | 45 | ||
45 | ++argv; | 46 | ++argv; |
diff --git a/coreutils/cksum.c b/coreutils/cksum.c index c0cf65d2a..059a33310 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c | |||
@@ -13,6 +13,7 @@ | |||
13 | //config: cksum is used to calculate the CRC32 checksum of a file. | 13 | //config: cksum is used to calculate the CRC32 checksum of a file. |
14 | 14 | ||
15 | //applet:IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) | 15 | //applet:IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) |
16 | /* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ | ||
16 | 17 | ||
17 | //kbuild:lib-$(CONFIG_CKSUM) += cksum.o | 18 | //kbuild:lib-$(CONFIG_CKSUM) += cksum.o |
18 | 19 | ||
diff --git a/coreutils/comm.c b/coreutils/comm.c index 5be11468c..4bee77677 100644 --- a/coreutils/comm.c +++ b/coreutils/comm.c | |||
@@ -62,8 +62,7 @@ int comm_main(int argc UNUSED_PARAM, char **argv) | |||
62 | int i; | 62 | int i; |
63 | int order; | 63 | int order; |
64 | 64 | ||
65 | opt_complementary = "=2"; | 65 | getopt32(argv, "^" "123" "\0" "=2"); |
66 | getopt32(argv, "123"); | ||
67 | argv += optind; | 66 | argv += optind; |
68 | 67 | ||
69 | for (i = 0; i < 2; ++i) { | 68 | for (i = 0; i < 2; ++i) { |
diff --git a/coreutils/cp.c b/coreutils/cp.c index 092e39583..5b34c27e7 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c | |||
@@ -73,15 +73,17 @@ int cp_main(int argc, char **argv) | |||
73 | #endif | 73 | #endif |
74 | }; | 74 | }; |
75 | 75 | ||
76 | // Need at least two arguments | ||
77 | // Soft- and hardlinking doesn't mix | ||
78 | // -P and -d are the same (-P is POSIX, -d is GNU) | ||
79 | // -r and -R are the same | ||
80 | // -R (and therefore -r) turns on -d (coreutils does this) | ||
81 | // -a = -pdR | ||
82 | opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR"; | ||
83 | #if ENABLE_FEATURE_CP_LONG_OPTIONS | 76 | #if ENABLE_FEATURE_CP_LONG_OPTIONS |
84 | applet_long_options = | 77 | flags = getopt32long(argv, "^" |
78 | FILEUTILS_CP_OPTSTR | ||
79 | "\0" | ||
80 | // Need at least two arguments | ||
81 | // Soft- and hardlinking doesn't mix | ||
82 | // -P and -d are the same (-P is POSIX, -d is GNU) | ||
83 | // -r and -R are the same | ||
84 | // -R (and therefore -r) turns on -d (coreutils does this) | ||
85 | // -a = -pdR | ||
86 | "-2:l--s:s--l:Pd:rRd:Rd:apdR", | ||
85 | "archive\0" No_argument "a" | 87 | "archive\0" No_argument "a" |
86 | "force\0" No_argument "f" | 88 | "force\0" No_argument "f" |
87 | "interactive\0" No_argument "i" | 89 | "interactive\0" No_argument "i" |
@@ -94,9 +96,10 @@ int cp_main(int argc, char **argv) | |||
94 | "update\0" No_argument "u" | 96 | "update\0" No_argument "u" |
95 | "remove-destination\0" No_argument "\xff" | 97 | "remove-destination\0" No_argument "\xff" |
96 | "parents\0" No_argument "\xfe" | 98 | "parents\0" No_argument "\xfe" |
97 | ; | 99 | ); |
98 | #endif | 100 | #else |
99 | flags = getopt32(argv, FILEUTILS_CP_OPTSTR); | 101 | flags = getopt32(argv, FILEUTILS_CP_OPTSTR); |
102 | #endif | ||
100 | /* Options of cp from GNU coreutils 6.10: | 103 | /* Options of cp from GNU coreutils 6.10: |
101 | * -a, --archive | 104 | * -a, --archive |
102 | * -f, --force | 105 | * -f, --force |
diff --git a/coreutils/cut.c b/coreutils/cut.c index 6578ce8ce..cdd90ab44 100644 --- a/coreutils/cut.c +++ b/coreutils/cut.c | |||
@@ -42,7 +42,7 @@ | |||
42 | 42 | ||
43 | 43 | ||
44 | /* option vars */ | 44 | /* option vars */ |
45 | static const char optstring[] ALIGN1 = "b:c:f:d:sn"; | 45 | #define OPT_STR "b:c:f:d:sn" |
46 | #define CUT_OPT_BYTE_FLGS (1 << 0) | 46 | #define CUT_OPT_BYTE_FLGS (1 << 0) |
47 | #define CUT_OPT_CHAR_FLGS (1 << 1) | 47 | #define CUT_OPT_CHAR_FLGS (1 << 1) |
48 | #define CUT_OPT_FIELDS_FLGS (1 << 2) | 48 | #define CUT_OPT_FIELDS_FLGS (1 << 2) |
@@ -201,8 +201,11 @@ int cut_main(int argc UNUSED_PARAM, char **argv) | |||
201 | char *sopt, *ltok; | 201 | char *sopt, *ltok; |
202 | unsigned opt; | 202 | unsigned opt; |
203 | 203 | ||
204 | opt_complementary = "b--bcf:c--bcf:f--bcf"; | 204 | opt = getopt32(argv, "^" |
205 | opt = getopt32(argv, optstring, &sopt, &sopt, &sopt, <ok); | 205 | OPT_STR |
206 | "\0" "b--bcf:c--bcf:f--bcf", | ||
207 | &sopt, &sopt, &sopt, <ok | ||
208 | ); | ||
206 | // argc -= optind; | 209 | // argc -= optind; |
207 | argv += optind; | 210 | argv += optind; |
208 | if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS))) | 211 | if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS))) |
diff --git a/coreutils/date.c b/coreutils/date.c index 0fb9f1f00..5b15ce778 100644 --- a/coreutils/date.c +++ b/coreutils/date.c | |||
@@ -58,7 +58,8 @@ | |||
58 | //config: the same format. With it on, 'date DATE' additionally supports | 58 | //config: the same format. With it on, 'date DATE' additionally supports |
59 | //config: MMDDhhmm[[YY]YY][.ss] format. | 59 | //config: MMDDhhmm[[YY]YY][.ss] format. |
60 | 60 | ||
61 | //applet:IF_DATE(APPLET(date, BB_DIR_BIN, BB_SUID_DROP)) | 61 | //applet:IF_DATE(APPLET_NOEXEC(date, date, BB_DIR_BIN, BB_SUID_DROP, date)) |
62 | /* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ | ||
62 | 63 | ||
63 | //kbuild:lib-$(CONFIG_DATE) += date.o | 64 | //kbuild:lib-$(CONFIG_DATE) += date.o |
64 | 65 | ||
@@ -66,7 +67,7 @@ | |||
66 | * date [OPTION]... [+FORMAT] | 67 | * date [OPTION]... [+FORMAT] |
67 | * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] | 68 | * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] |
68 | * -d, --date=STRING | 69 | * -d, --date=STRING |
69 | * display time described by STRING, not `now' | 70 | * display time described by STRING, not 'now' |
70 | * -f, --file=DATEFILE | 71 | * -f, --file=DATEFILE |
71 | * like --date once for each line of DATEFILE | 72 | * like --date once for each line of DATEFILE |
72 | * -r, --reference=FILE | 73 | * -r, --reference=FILE |
@@ -152,12 +153,6 @@ enum { | |||
152 | OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ | 153 | OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ |
153 | }; | 154 | }; |
154 | 155 | ||
155 | static void maybe_set_utc(int opt) | ||
156 | { | ||
157 | if (opt & OPT_UTC) | ||
158 | putenv((char*)"TZ=UTC0"); | ||
159 | } | ||
160 | |||
161 | #if ENABLE_LONG_OPTS | 156 | #if ENABLE_LONG_OPTS |
162 | static const char date_longopts[] ALIGN1 = | 157 | static const char date_longopts[] ALIGN1 = |
163 | "rfc-822\0" No_argument "R" | 158 | "rfc-822\0" No_argument "R" |
@@ -170,6 +165,19 @@ static const char date_longopts[] ALIGN1 = | |||
170 | ; | 165 | ; |
171 | #endif | 166 | #endif |
172 | 167 | ||
168 | /* We are a NOEXEC applet. | ||
169 | * Obstacles to NOFORK: | ||
170 | * - we change env | ||
171 | * - xasprintf result not freed | ||
172 | * - after xasprintf we use other xfuncs | ||
173 | */ | ||
174 | |||
175 | static void maybe_set_utc(int opt) | ||
176 | { | ||
177 | if (opt & OPT_UTC) | ||
178 | putenv((char*)"TZ=UTC0"); | ||
179 | } | ||
180 | |||
173 | int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 181 | int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
174 | int date_main(int argc UNUSED_PARAM, char **argv) | 182 | int date_main(int argc UNUSED_PARAM, char **argv) |
175 | { | 183 | { |
@@ -184,13 +192,16 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
184 | char *filename; | 192 | char *filename; |
185 | char *isofmt_arg = NULL; | 193 | char *isofmt_arg = NULL; |
186 | 194 | ||
187 | opt_complementary = "d--s:s--d" | 195 | opt = getopt32long(argv, "^" |
188 | IF_FEATURE_DATE_ISOFMT(":R--I:I--R"); | 196 | "Rs:ud:r:" |
189 | IF_LONG_OPTS(applet_long_options = date_longopts;) | 197 | IF_FEATURE_DATE_ISOFMT("I::D:") |
190 | opt = getopt32(argv, "Rs:ud:r:" | 198 | "\0" |
191 | IF_FEATURE_DATE_ISOFMT("I::D:"), | 199 | "d--s:s--d" |
200 | IF_FEATURE_DATE_ISOFMT(":R--I:I--R"), | ||
201 | date_longopts, | ||
192 | &date_str, &date_str, &filename | 202 | &date_str, &date_str, &filename |
193 | IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); | 203 | IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt) |
204 | ); | ||
194 | argv += optind; | 205 | argv += optind; |
195 | maybe_set_utc(opt); | 206 | maybe_set_utc(opt); |
196 | 207 | ||
diff --git a/coreutils/dd.c b/coreutils/dd.c index f7f1c9564..9ea4897d5 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c | |||
@@ -19,7 +19,7 @@ | |||
19 | //config: default y | 19 | //config: default y |
20 | //config: depends on DD | 20 | //config: depends on DD |
21 | //config: help | 21 | //config: help |
22 | //config: Sending a SIGUSR1 signal to a running `dd' process makes it | 22 | //config: Sending a SIGUSR1 signal to a running 'dd' process makes it |
23 | //config: print to standard error the number of records read and written | 23 | //config: print to standard error the number of records read and written |
24 | //config: so far, then to resume copying. | 24 | //config: so far, then to resume copying. |
25 | //config: | 25 | //config: |
diff --git a/coreutils/df.c b/coreutils/df.c index 27dd2b5a8..121da970b 100644 --- a/coreutils/df.c +++ b/coreutils/df.c | |||
@@ -33,7 +33,7 @@ | |||
33 | //config: -i Inodes | 33 | //config: -i Inodes |
34 | //config: -B <SIZE> Blocksize | 34 | //config: -B <SIZE> Blocksize |
35 | 35 | ||
36 | //applet:IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP)) | 36 | //applet:IF_DF(APPLET_NOEXEC(df, df, BB_DIR_BIN, BB_SUID_DROP, df)) |
37 | 37 | ||
38 | //kbuild:lib-$(CONFIG_DF) += df.o | 38 | //kbuild:lib-$(CONFIG_DF) += df.o |
39 | 39 | ||
@@ -115,15 +115,18 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
115 | 115 | ||
116 | init_unicode(); | 116 | init_unicode(); |
117 | 117 | ||
118 | opt = getopt32(argv, "^" | ||
119 | "kPT" | ||
120 | IF_FEATURE_DF_FANCY("aiB:") | ||
121 | IF_FEATURE_HUMAN_READABLE("hm") | ||
122 | "\0" | ||
118 | #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY | 123 | #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY |
119 | opt_complementary = "k-mB:m-Bk:B-km"; | 124 | "k-mB:m-Bk:B-km" |
120 | #elif ENABLE_FEATURE_HUMAN_READABLE | 125 | #elif ENABLE_FEATURE_HUMAN_READABLE |
121 | opt_complementary = "k-m:m-k"; | 126 | "k-m:m-k" |
122 | #endif | 127 | #endif |
123 | opt = getopt32(argv, "kPT" | 128 | IF_FEATURE_DF_FANCY(, &chp) |
124 | IF_FEATURE_DF_FANCY("aiB:") | 129 | ); |
125 | IF_FEATURE_HUMAN_READABLE("hm") | ||
126 | IF_FEATURE_DF_FANCY(, &chp)); | ||
127 | if (opt & OPT_MEGA) | 130 | if (opt & OPT_MEGA) |
128 | df_disp_hr = 1024*1024; | 131 | df_disp_hr = 1024*1024; |
129 | 132 | ||
diff --git a/coreutils/dos2unix.c b/coreutils/dos2unix.c index a3d008051..9f098e41e 100644 --- a/coreutils/dos2unix.c +++ b/coreutils/dos2unix.c | |||
@@ -120,8 +120,7 @@ int dos2unix_main(int argc UNUSED_PARAM, char **argv) | |||
120 | } | 120 | } |
121 | 121 | ||
122 | /* -u convert to unix, -d convert to dos */ | 122 | /* -u convert to unix, -d convert to dos */ |
123 | opt_complementary = "u--d:d--u"; /* mutually exclusive */ | 123 | o = getopt32(argv, "^" "du" "\0" "u--d:d--u"); /* mutually exclusive */ |
124 | o = getopt32(argv, "du"); | ||
125 | 124 | ||
126 | /* Do the conversion requested by an argument else do the default | 125 | /* Do the conversion requested by an argument else do the default |
127 | * conversion depending on our name. */ | 126 | * conversion depending on our name. */ |
diff --git a/coreutils/du.c b/coreutils/du.c index 947c46e74..d5ce46cf2 100644 --- a/coreutils/du.c +++ b/coreutils/du.c | |||
@@ -242,8 +242,11 @@ int du_main(int argc UNUSED_PARAM, char **argv) | |||
242 | * ignore -a. This is consistent with -s being equivalent to -d 0. | 242 | * ignore -a. This is consistent with -s being equivalent to -d 0. |
243 | */ | 243 | */ |
244 | #if ENABLE_FEATURE_HUMAN_READABLE | 244 | #if ENABLE_FEATURE_HUMAN_READABLE |
245 | opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s"; | 245 | opt = getopt32(argv, "^" |
246 | opt = getopt32(argv, "aHkLsx" "d:+" "lc" "hm", &G.max_print_depth); | 246 | "aHkLsxd:+lchm" |
247 | "\0" "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s", | ||
248 | &G.max_print_depth | ||
249 | ); | ||
247 | argv += optind; | 250 | argv += optind; |
248 | if (opt & OPT_h_for_humans) { | 251 | if (opt & OPT_h_for_humans) { |
249 | G.disp_unit = 0; | 252 | G.disp_unit = 0; |
@@ -255,8 +258,11 @@ int du_main(int argc UNUSED_PARAM, char **argv) | |||
255 | G.disp_unit = 1024; | 258 | G.disp_unit = 1024; |
256 | } | 259 | } |
257 | #else | 260 | #else |
258 | opt_complementary = "H-L:L-H:s-d:d-s"; | 261 | opt = getopt32(argv, "^" |
259 | opt = getopt32(argv, "aHkLsx" "d:+" "lc", &G.max_print_depth); | 262 | "aHkLsxd:+lc" |
263 | "\0" "H-L:L-H:s-d:d-s", | ||
264 | &G.max_print_depth | ||
265 | ); | ||
260 | argv += optind; | 266 | argv += optind; |
261 | #if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K | 267 | #if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K |
262 | if (opt & OPT_k_kbytes) { | 268 | if (opt & OPT_k_kbytes) { |
diff --git a/coreutils/echo.c b/coreutils/echo.c index af33319a1..e45b90940 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c | |||
@@ -218,7 +218,7 @@ int echo_main(int argc UNUSED_PARAM, char **argv) | |||
218 | * may be used to endorse or promote products derived from this software | 218 | * may be used to endorse or promote products derived from this software |
219 | * without specific prior written permission. | 219 | * without specific prior written permission. |
220 | * | 220 | * |
221 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 221 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
222 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 222 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
223 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 223 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
224 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 224 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/coreutils/env.c b/coreutils/env.c index 8def9c2da..20453e871 100644 --- a/coreutils/env.c +++ b/coreutils/env.c | |||
@@ -30,11 +30,6 @@ | |||
30 | //config: env is used to set an environment variable and run | 30 | //config: env is used to set an environment variable and run |
31 | //config: a command; without options it displays the current | 31 | //config: a command; without options it displays the current |
32 | //config: environment. | 32 | //config: environment. |
33 | //config: | ||
34 | //config:config FEATURE_ENV_LONG_OPTIONS | ||
35 | //config: bool "Enable long options" | ||
36 | //config: default y | ||
37 | //config: depends on ENV && LONG_OPTS | ||
38 | 33 | ||
39 | //applet:IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) | 34 | //applet:IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) |
40 | 35 | ||
@@ -53,23 +48,17 @@ | |||
53 | 48 | ||
54 | #include "libbb.h" | 49 | #include "libbb.h" |
55 | 50 | ||
56 | #if ENABLE_FEATURE_ENV_LONG_OPTIONS | ||
57 | static const char env_longopts[] ALIGN1 = | ||
58 | "ignore-environment\0" No_argument "i" | ||
59 | "unset\0" Required_argument "u" | ||
60 | ; | ||
61 | #endif | ||
62 | |||
63 | int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 51 | int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
64 | int env_main(int argc UNUSED_PARAM, char **argv) | 52 | int env_main(int argc UNUSED_PARAM, char **argv) |
65 | { | 53 | { |
66 | unsigned opts; | 54 | unsigned opts; |
67 | llist_t *unset_env = NULL; | 55 | llist_t *unset_env = NULL; |
68 | 56 | ||
69 | #if ENABLE_FEATURE_ENV_LONG_OPTIONS | 57 | opts = getopt32long(argv, "+iu:+", |
70 | applet_long_options = env_longopts; | 58 | "ignore-environment\0" No_argument "i" |
71 | #endif | 59 | "unset\0" Required_argument "u" |
72 | opts = getopt32(argv, "+iu:+", &unset_env); | 60 | , &unset_env |
61 | ); | ||
73 | argv += optind; | 62 | argv += optind; |
74 | if (argv[0] && LONE_DASH(argv[0])) { | 63 | if (argv[0] && LONE_DASH(argv[0])) { |
75 | opts |= 1; | 64 | opts |= 1; |
@@ -129,7 +118,7 @@ int env_main(int argc UNUSED_PARAM, char **argv) | |||
129 | * may be used to endorse or promote products derived from this software | 118 | * may be used to endorse or promote products derived from this software |
130 | * without specific prior written permission. | 119 | * without specific prior written permission. |
131 | * | 120 | * |
132 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 121 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
133 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 122 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
134 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 123 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
135 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 124 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/coreutils/expand.c b/coreutils/expand.c index 64f2a539d..91084b80b 100644 --- a/coreutils/expand.c +++ b/coreutils/expand.c | |||
@@ -26,21 +26,11 @@ | |||
26 | //config: help | 26 | //config: help |
27 | //config: By default, convert all tabs to spaces. | 27 | //config: By default, convert all tabs to spaces. |
28 | //config: | 28 | //config: |
29 | //config:config FEATURE_EXPAND_LONG_OPTIONS | ||
30 | //config: bool "Enable long options" | ||
31 | //config: default y | ||
32 | //config: depends on EXPAND && LONG_OPTS | ||
33 | //config: | ||
34 | //config:config UNEXPAND | 29 | //config:config UNEXPAND |
35 | //config: bool "unexpand (6 kb)" | 30 | //config: bool "unexpand (6 kb)" |
36 | //config: default y | 31 | //config: default y |
37 | //config: help | 32 | //config: help |
38 | //config: By default, convert only leading sequences of blanks to tabs. | 33 | //config: By default, convert only leading sequences of blanks to tabs. |
39 | //config: | ||
40 | //config:config FEATURE_UNEXPAND_LONG_OPTIONS | ||
41 | //config: bool "Enable long options" | ||
42 | //config: default y | ||
43 | //config: depends on UNEXPAND && LONG_OPTS | ||
44 | 34 | ||
45 | //applet:IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) | 35 | //applet:IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) |
46 | // APPLET_ODDNAME:name main location suid_type help | 36 | // APPLET_ODDNAME:name main location suid_type help |
@@ -53,29 +43,16 @@ | |||
53 | //usage: "[-i] [-t N] [FILE]..." | 43 | //usage: "[-i] [-t N] [FILE]..." |
54 | //usage:#define expand_full_usage "\n\n" | 44 | //usage:#define expand_full_usage "\n\n" |
55 | //usage: "Convert tabs to spaces, writing to stdout\n" | 45 | //usage: "Convert tabs to spaces, writing to stdout\n" |
56 | //usage: IF_FEATURE_EXPAND_LONG_OPTIONS( | ||
57 | //usage: "\n -i,--initial Don't convert tabs after non blanks" | ||
58 | //usage: "\n -t,--tabs N Tabstops every N chars" | ||
59 | //usage: ) | ||
60 | //usage: IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( | ||
61 | //usage: "\n -i Don't convert tabs after non blanks" | 46 | //usage: "\n -i Don't convert tabs after non blanks" |
62 | //usage: "\n -t Tabstops every N chars" | 47 | //usage: "\n -t Tabstops every N chars" |
63 | //usage: ) | ||
64 | 48 | ||
65 | //usage:#define unexpand_trivial_usage | 49 | //usage:#define unexpand_trivial_usage |
66 | //usage: "[-fa][-t N] [FILE]..." | 50 | //usage: "[-fa][-t N] [FILE]..." |
67 | //usage:#define unexpand_full_usage "\n\n" | 51 | //usage:#define unexpand_full_usage "\n\n" |
68 | //usage: "Convert spaces to tabs, writing to stdout\n" | 52 | //usage: "Convert spaces to tabs, writing to stdout\n" |
69 | //usage: IF_FEATURE_UNEXPAND_LONG_OPTIONS( | ||
70 | //usage: "\n -a,--all Convert all blanks" | ||
71 | //usage: "\n -f,--first-only Convert only leading blanks" | ||
72 | //usage: "\n -t,--tabs N Tabstops every N chars" | ||
73 | //usage: ) | ||
74 | //usage: IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( | ||
75 | //usage: "\n -a Convert all blanks" | 53 | //usage: "\n -a Convert all blanks" |
76 | //usage: "\n -f Convert only leading blanks" | 54 | //usage: "\n -f Convert only leading blanks" |
77 | //usage: "\n -t N Tabstops every N chars" | 55 | //usage: "\n -t N Tabstops every N chars" |
78 | //usage: ) | ||
79 | 56 | ||
80 | #include "libbb.h" | 57 | #include "libbb.h" |
81 | #include "unicode.h" | 58 | #include "unicode.h" |
@@ -188,31 +165,24 @@ int expand_main(int argc UNUSED_PARAM, char **argv) | |||
188 | unsigned opt; | 165 | unsigned opt; |
189 | int exit_status = EXIT_SUCCESS; | 166 | int exit_status = EXIT_SUCCESS; |
190 | 167 | ||
191 | #if ENABLE_FEATURE_EXPAND_LONG_OPTIONS | ||
192 | static const char expand_longopts[] ALIGN1 = | ||
193 | /* name, has_arg, val */ | ||
194 | "initial\0" No_argument "i" | ||
195 | "tabs\0" Required_argument "t" | ||
196 | ; | ||
197 | #endif | ||
198 | #if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS | ||
199 | static const char unexpand_longopts[] ALIGN1 = | ||
200 | /* name, has_arg, val */ | ||
201 | "first-only\0" No_argument "i" | ||
202 | "tabs\0" Required_argument "t" | ||
203 | "all\0" No_argument "a" | ||
204 | ; | ||
205 | #endif | ||
206 | init_unicode(); | 168 | init_unicode(); |
207 | 169 | ||
208 | if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { | 170 | if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { |
209 | IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts); | 171 | opt = getopt32long(argv, "it:", |
210 | opt = getopt32(argv, "it:", &opt_t); | 172 | "initial\0" No_argument "i" |
173 | "tabs\0" Required_argument "t" | ||
174 | , &opt_t | ||
175 | ); | ||
211 | } else { | 176 | } else { |
212 | IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts); | 177 | opt = getopt32long(argv, "^" |
213 | /* -t NUM sets also -a */ | 178 | "ft:a" |
214 | opt_complementary = "ta"; | 179 | "\0" |
215 | opt = getopt32(argv, "ft:a", &opt_t); | 180 | "ta" /* -t NUM sets -a */, |
181 | "first-only\0" No_argument "i" | ||
182 | "tabs\0" Required_argument "t" | ||
183 | "all\0" No_argument "a" | ||
184 | , &opt_t | ||
185 | ); | ||
216 | /* -f --first-only is the default */ | 186 | /* -f --first-only is the default */ |
217 | if (!(opt & OPT_ALL)) opt |= OPT_INITIAL; | 187 | if (!(opt & OPT_ALL)) opt |= OPT_INITIAL; |
218 | } | 188 | } |
diff --git a/coreutils/expr.c b/coreutils/expr.c index 0cf2b9bd9..00bcf60d4 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c | |||
@@ -38,7 +38,7 @@ | |||
38 | //config: the applet slightly larger, but will allow computation with very | 38 | //config: the applet slightly larger, but will allow computation with very |
39 | //config: large numbers. | 39 | //config: large numbers. |
40 | 40 | ||
41 | //applet:IF_EXPR(APPLET(expr, BB_DIR_USR_BIN, BB_SUID_DROP)) | 41 | //applet:IF_EXPR(APPLET_NOEXEC(expr, expr, BB_DIR_USR_BIN, BB_SUID_DROP, expr)) |
42 | 42 | ||
43 | //kbuild:lib-$(CONFIG_EXPR) += expr.o | 43 | //kbuild:lib-$(CONFIG_EXPR) += expr.o |
44 | 44 | ||
@@ -118,7 +118,10 @@ struct globals { | |||
118 | char **args; | 118 | char **args; |
119 | } FIX_ALIASING; | 119 | } FIX_ALIASING; |
120 | #define G (*(struct globals*)bb_common_bufsiz1) | 120 | #define G (*(struct globals*)bb_common_bufsiz1) |
121 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 121 | #define INIT_G() do { \ |
122 | setup_common_bufsiz(); \ | ||
123 | /* NB: noexec applet - globals not zeroed */ \ | ||
124 | } while (0) | ||
122 | 125 | ||
123 | /* forward declarations */ | 126 | /* forward declarations */ |
124 | static VALUE *eval(void); | 127 | static VALUE *eval(void); |
diff --git a/coreutils/id.c b/coreutils/id.c index 6043bca61..5a7fb9aaf 100644 --- a/coreutils/id.c +++ b/coreutils/id.c | |||
@@ -170,9 +170,12 @@ int id_main(int argc UNUSED_PARAM, char **argv) | |||
170 | } else { | 170 | } else { |
171 | /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ | 171 | /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ |
172 | /* Don't allow more than one username */ | 172 | /* Don't allow more than one username */ |
173 | opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" | 173 | opt = getopt32(argv, "^" |
174 | IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); | 174 | "rnugG" IF_SELINUX("Z") |
175 | opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); | 175 | "\0" |
176 | "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" | ||
177 | IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G") | ||
178 | ); | ||
176 | } | 179 | } |
177 | 180 | ||
178 | username = argv[optind]; | 181 | username = argv[optind]; |
diff --git a/coreutils/install.c b/coreutils/install.c index a1342bb13..2e4dc257f 100644 --- a/coreutils/install.c +++ b/coreutils/install.c | |||
@@ -55,12 +55,17 @@ static const char install_longopts[] ALIGN1 = | |||
55 | "target-directory\0" Required_argument "t" | 55 | "target-directory\0" Required_argument "t" |
56 | /* autofs build insists of using -b --suffix=.orig */ | 56 | /* autofs build insists of using -b --suffix=.orig */ |
57 | /* TODO? (short option for --suffix is -S) */ | 57 | /* TODO? (short option for --suffix is -S) */ |
58 | #if ENABLE_SELINUX | 58 | # if ENABLE_SELINUX |
59 | "context\0" Required_argument "Z" | 59 | "context\0" Required_argument "Z" |
60 | "preserve_context\0" No_argument "\xff" | 60 | "preserve_context\0" No_argument "\xff" |
61 | "preserve-context\0" No_argument "\xff" | 61 | "preserve-context\0" No_argument "\xff" |
62 | #endif | 62 | # endif |
63 | ; | 63 | ; |
64 | # define GETOPT32 getopt32long | ||
65 | # define LONGOPTS install_longopts, | ||
66 | #else | ||
67 | # define GETOPT32 getopt32 | ||
68 | # define LONGOPTS | ||
64 | #endif | 69 | #endif |
65 | 70 | ||
66 | 71 | ||
@@ -135,15 +140,17 @@ int install_main(int argc, char **argv) | |||
135 | #endif | 140 | #endif |
136 | }; | 141 | }; |
137 | 142 | ||
138 | #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS | ||
139 | applet_long_options = install_longopts; | ||
140 | #endif | ||
141 | opt_complementary = "t--d:d--t:s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); | ||
142 | /* -c exists for backwards compatibility, it's needed */ | 143 | /* -c exists for backwards compatibility, it's needed */ |
143 | /* -b is ignored ("make a backup of each existing destination file") */ | 144 | /* -b is ignored ("make a backup of each existing destination file") */ |
144 | opts = getopt32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"), | 145 | opts = GETOPT32(argv, "^" |
145 | &gid_str, &mode_str, &uid_str, &last | 146 | "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:") |
146 | IF_SELINUX(, &scontext)); | 147 | "\0" |
148 | "t--d:d--t:s--d:d--s" | ||
149 | IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")), | ||
150 | LONGOPTS | ||
151 | &gid_str, &mode_str, &uid_str, &last | ||
152 | IF_SELINUX(, &scontext) | ||
153 | ); | ||
147 | argc -= optind; | 154 | argc -= optind; |
148 | argv += optind; | 155 | argv += optind; |
149 | 156 | ||
diff --git a/coreutils/link.c b/coreutils/link.c index 6e20dafe3..d8d583b7b 100644 --- a/coreutils/link.c +++ b/coreutils/link.c | |||
@@ -27,14 +27,12 @@ | |||
27 | int link_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 27 | int link_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
28 | int link_main(int argc UNUSED_PARAM, char **argv) | 28 | int link_main(int argc UNUSED_PARAM, char **argv) |
29 | { | 29 | { |
30 | opt_complementary = "=2"; /* exactly 2 params */ | 30 | getopt32(argv, "^" "" "\0" "=2"); |
31 | getopt32(argv, ""); | ||
32 | argv += optind; | 31 | argv += optind; |
33 | if (link(argv[0], argv[1]) != 0) { | 32 | if (link(argv[0], argv[1]) != 0) { |
34 | /* shared message */ | 33 | /* shared message */ |
35 | bb_perror_msg_and_die("can't create %slink " | 34 | bb_perror_msg_and_die("can't create %slink '%s' to '%s'", |
36 | "'%s' to '%s'", "hard", | 35 | "hard", argv[1], argv[0] |
37 | argv[1], argv[0] | ||
38 | ); | 36 | ); |
39 | } | 37 | } |
40 | return EXIT_SUCCESS; | 38 | return EXIT_SUCCESS; |
diff --git a/coreutils/ln.c b/coreutils/ln.c index fed96af42..2dda5dae9 100644 --- a/coreutils/ln.c +++ b/coreutils/ln.c | |||
@@ -62,8 +62,7 @@ int ln_main(int argc, char **argv) | |||
62 | struct stat statbuf; | 62 | struct stat statbuf; |
63 | int (*link_func)(const char *, const char *); | 63 | int (*link_func)(const char *, const char *); |
64 | 64 | ||
65 | opt_complementary = "-1"; /* min one arg */ | 65 | opts = getopt32(argv, "^" "sfnbS:vT" "\0" "-1", &suffix); |
66 | opts = getopt32(argv, "sfnbS:vT", &suffix); | ||
67 | 66 | ||
68 | last = argv[argc - 1]; | 67 | last = argv[argc - 1]; |
69 | argv += optind; | 68 | argv += optind; |
diff --git a/coreutils/ls.c b/coreutils/ls.c index 4c0944bb0..9f0462936 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -206,18 +206,18 @@ SPLIT_SUBDIR = 2, | |||
206 | /* -SXvhTw GNU options, busybox optionally supports */ | 206 | /* -SXvhTw GNU options, busybox optionally supports */ |
207 | /* -T WIDTH Ignored (we don't use tabs on output) */ | 207 | /* -T WIDTH Ignored (we don't use tabs on output) */ |
208 | /* -Z SELinux mandated option, busybox optionally supports */ | 208 | /* -Z SELinux mandated option, busybox optionally supports */ |
209 | static const char ls_options[] ALIGN1 = | 209 | #define ls_options \ |
210 | "Cadi1lgnsxAk" /* 12 opts, total 12 */ | 210 | "Cadi1lgnsxAk" /* 12 opts, total 12 */ \ |
211 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ | 211 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ \ |
212 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ | 212 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ \ |
213 | IF_SELINUX("Z") /* 1, 16 */ | 213 | IF_SELINUX("Z") /* 1, 16 */ \ |
214 | "Q" /* 1, 17 */ | 214 | "Q" /* 1, 17 */ \ |
215 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ | 215 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ \ |
216 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ | 216 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ \ |
217 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ | 217 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ \ |
218 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ | 218 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ \ |
219 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ | 219 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ |
220 | ; | 220 | |
221 | enum { | 221 | enum { |
222 | OPT_C = (1 << 0), | 222 | OPT_C = (1 << 0), |
223 | OPT_a = (1 << 1), | 223 | OPT_a = (1 << 1), |
@@ -1093,25 +1093,26 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1093 | #endif | 1093 | #endif |
1094 | 1094 | ||
1095 | /* process options */ | 1095 | /* process options */ |
1096 | IF_LONG_OPTS(applet_long_options = ls_longopts;) | 1096 | opt = getopt32long(argv, "^" |
1097 | opt_complementary = | 1097 | ls_options |
1098 | /* -n and -g imply -l */ | 1098 | "\0" |
1099 | "nl:gl" | 1099 | /* -n and -g imply -l */ |
1100 | /* --full-time implies -l */ | 1100 | "nl:gl" |
1101 | IF_FEATURE_LS_TIMESTAMPS(IF_LONG_OPTS(":\xff""l")) | 1101 | /* --full-time implies -l */ |
1102 | /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: | 1102 | IF_FEATURE_LS_TIMESTAMPS(IF_LONG_OPTS(":\xff""l")) |
1103 | * in some pairs of opts, only last one takes effect: | 1103 | /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: |
1104 | */ | 1104 | * in some pairs of opts, only last one takes effect: |
1105 | IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ | 1105 | */ |
1106 | // ":m-l:l-m" - we don't have -m | 1106 | IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ |
1107 | IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H") | 1107 | // ":m-l:l-m" - we don't have -m |
1108 | ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ | 1108 | IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H") |
1109 | ":C-1:1-C" /* bycols/oneline */ | 1109 | ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ |
1110 | ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ | 1110 | ":C-1:1-C" /* bycols/oneline */ |
1111 | IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ | 1111 | ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ |
1112 | /* -w NUM: */ | 1112 | IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ |
1113 | IF_FEATURE_LS_WIDTH(":w+"); | 1113 | /* -w NUM: */ |
1114 | opt = getopt32(argv, ls_options | 1114 | IF_FEATURE_LS_WIDTH(":w+") |
1115 | , ls_longopts | ||
1115 | IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) | 1116 | IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) |
1116 | IF_FEATURE_LS_COLOR(, &color_opt) | 1117 | IF_FEATURE_LS_COLOR(, &color_opt) |
1117 | ); | 1118 | ); |
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index bcccdd64f..89d6cec0b 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c | |||
@@ -258,15 +258,14 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) | |||
258 | #endif | 258 | #endif |
259 | 259 | ||
260 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { | 260 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { |
261 | /* -s and -w require -c */ | ||
262 | opt_complementary = "s?c:w?c"; | ||
263 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ | 261 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ |
262 | /* -s and -w require -c */ | ||
264 | #if ENABLE_SHA3SUM | 263 | #if ENABLE_SHA3SUM |
265 | if (applet_name[3] == HASH_SHA3) | 264 | if (applet_name[3] == HASH_SHA3) |
266 | flags = getopt32(argv, "scwbta:+", &sha3_width); | 265 | flags = getopt32(argv, "^" "scwbta:+" "\0" "s?c:w?c", &sha3_width); |
267 | else | 266 | else |
268 | #endif | 267 | #endif |
269 | flags = getopt32(argv, "scwbt"); | 268 | flags = getopt32(argv, "^" "scwbt" "\0" "s?c:w?c"); |
270 | } else { | 269 | } else { |
271 | #if ENABLE_SHA3SUM | 270 | #if ENABLE_SHA3SUM |
272 | if (applet_name[3] == HASH_SHA3) | 271 | if (applet_name[3] == HASH_SHA3) |
diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index 22851187c..986353dc6 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c | |||
@@ -18,11 +18,6 @@ | |||
18 | //config: default y | 18 | //config: default y |
19 | //config: help | 19 | //config: help |
20 | //config: mkdir is used to create directories with the specified names. | 20 | //config: mkdir is used to create directories with the specified names. |
21 | //config: | ||
22 | //config:config FEATURE_MKDIR_LONG_OPTIONS | ||
23 | //config: bool "Enable long options" | ||
24 | //config: default y | ||
25 | //config: depends on MKDIR && LONG_OPTS | ||
26 | 21 | ||
27 | //applet:IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) | 22 | //applet:IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) |
28 | 23 | ||
@@ -53,19 +48,6 @@ | |||
53 | 48 | ||
54 | /* This is a NOFORK applet. Be very careful! */ | 49 | /* This is a NOFORK applet. Be very careful! */ |
55 | 50 | ||
56 | #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS | ||
57 | static const char mkdir_longopts[] ALIGN1 = | ||
58 | "mode\0" Required_argument "m" | ||
59 | "parents\0" No_argument "p" | ||
60 | #if ENABLE_SELINUX | ||
61 | "context\0" Required_argument "Z" | ||
62 | #endif | ||
63 | #if ENABLE_FEATURE_VERBOSE | ||
64 | "verbose\0" No_argument "v" | ||
65 | #endif | ||
66 | ; | ||
67 | #endif | ||
68 | |||
69 | int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 51 | int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
70 | int mkdir_main(int argc UNUSED_PARAM, char **argv) | 52 | int mkdir_main(int argc UNUSED_PARAM, char **argv) |
71 | { | 53 | { |
@@ -78,10 +60,17 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) | |||
78 | security_context_t scontext; | 60 | security_context_t scontext; |
79 | #endif | 61 | #endif |
80 | 62 | ||
81 | #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS | 63 | opt = getopt32long(argv, "m:pv" IF_SELINUX("Z:"), |
82 | applet_long_options = mkdir_longopts; | 64 | "mode\0" Required_argument "m" |
83 | #endif | 65 | "parents\0" No_argument "p" |
84 | opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); | 66 | # if ENABLE_SELINUX |
67 | "context\0" Required_argument "Z" | ||
68 | # endif | ||
69 | # if ENABLE_FEATURE_VERBOSE | ||
70 | "verbose\0" No_argument "v" | ||
71 | # endif | ||
72 | , &smode IF_SELINUX(,&scontext) | ||
73 | ); | ||
85 | if (opt & 1) { | 74 | if (opt & 1) { |
86 | mode_t mmode = bb_parse_mode(smode, 0777); | 75 | mode_t mmode = bb_parse_mode(smode, 0777); |
87 | if (mmode == (mode_t)-1) { | 76 | if (mmode == (mode_t)-1) { |
diff --git a/coreutils/mktemp.c b/coreutils/mktemp.c index bfef0b4a6..d4ff883fa 100644 --- a/coreutils/mktemp.c +++ b/coreutils/mktemp.c | |||
@@ -36,7 +36,7 @@ | |||
36 | //config: help | 36 | //config: help |
37 | //config: mktemp is used to create unique temporary files | 37 | //config: mktemp is used to create unique temporary files |
38 | 38 | ||
39 | //applet:IF_MKTEMP(APPLET(mktemp, BB_DIR_BIN, BB_SUID_DROP)) | 39 | //applet:IF_MKTEMP(APPLET_NOEXEC(mktemp, mktemp, BB_DIR_BIN, BB_SUID_DROP, mktemp)) |
40 | 40 | ||
41 | //kbuild:lib-$(CONFIG_MKTEMP) += mktemp.o | 41 | //kbuild:lib-$(CONFIG_MKTEMP) += mktemp.o |
42 | 42 | ||
@@ -80,8 +80,7 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv) | |||
80 | if (!path || path[0] == '\0') | 80 | if (!path || path[0] == '\0') |
81 | path = "/tmp"; | 81 | path = "/tmp"; |
82 | 82 | ||
83 | opt_complementary = "?1"; /* 1 argument max */ | 83 | opts = getopt32(argv, "^" "dqtp:u" "\0" "?1"/*1 arg max*/, &path); |
84 | opts = getopt32(argv, "dqtp:u", &path); | ||
85 | 84 | ||
86 | chp = argv[optind]; | 85 | chp = argv[optind]; |
87 | if (!chp) { | 86 | if (!chp) { |
diff --git a/coreutils/mv.c b/coreutils/mv.c index 147dd3bb2..10cbc506f 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c | |||
@@ -16,11 +16,6 @@ | |||
16 | //config: default y | 16 | //config: default y |
17 | //config: help | 17 | //config: help |
18 | //config: mv is used to move or rename files or directories. | 18 | //config: mv is used to move or rename files or directories. |
19 | //config: | ||
20 | //config:config FEATURE_MV_LONG_OPTIONS | ||
21 | //config: bool "Enable long options" | ||
22 | //config: default y | ||
23 | //config: depends on MV && LONG_OPTS | ||
24 | 19 | ||
25 | //applet:IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) | 20 | //applet:IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) |
26 | 21 | ||
@@ -41,23 +36,6 @@ | |||
41 | #include "libbb.h" | 36 | #include "libbb.h" |
42 | #include "libcoreutils/coreutils.h" | 37 | #include "libcoreutils/coreutils.h" |
43 | 38 | ||
44 | #if ENABLE_FEATURE_MV_LONG_OPTIONS | ||
45 | static const char mv_longopts[] ALIGN1 = | ||
46 | "interactive\0" No_argument "i" | ||
47 | "force\0" No_argument "f" | ||
48 | "no-clobber\0" No_argument "n" | ||
49 | IF_FEATURE_VERBOSE( | ||
50 | "verbose\0" No_argument "v" | ||
51 | ) | ||
52 | ; | ||
53 | #endif | ||
54 | |||
55 | #define OPT_FORCE (1 << 0) | ||
56 | #define OPT_INTERACTIVE (1 << 1) | ||
57 | #define OPT_NOCLOBBER (1 << 2) | ||
58 | #define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) | ||
59 | |||
60 | |||
61 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 39 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
62 | int mv_main(int argc, char **argv) | 40 | int mv_main(int argc, char **argv) |
63 | { | 41 | { |
@@ -69,15 +47,25 @@ int mv_main(int argc, char **argv) | |||
69 | int status = 0; | 47 | int status = 0; |
70 | int copy_flag = 0; | 48 | int copy_flag = 0; |
71 | 49 | ||
72 | #if ENABLE_FEATURE_MV_LONG_OPTIONS | 50 | #define OPT_FORCE (1 << 0) |
73 | applet_long_options = mv_longopts; | 51 | #define OPT_INTERACTIVE (1 << 1) |
74 | #endif | 52 | #define OPT_NOCLOBBER (1 << 2) |
53 | #define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) | ||
75 | /* Need at least two arguments. | 54 | /* Need at least two arguments. |
76 | * If more than one of -f, -i, -n is specified , only the final one | 55 | * If more than one of -f, -i, -n is specified , only the final one |
77 | * takes effect (it unsets previous options). | 56 | * takes effect (it unsets previous options). |
78 | */ | 57 | */ |
79 | opt_complementary = "-2:f-in:i-fn:n-fi"; | 58 | flags = getopt32long(argv, "^" |
80 | flags = getopt32(argv, "finv"); | 59 | "finv" |
60 | "\0" | ||
61 | "-2:f-in:i-fn:n-fi", | ||
62 | "interactive\0" No_argument "i" | ||
63 | "force\0" No_argument "f" | ||
64 | "no-clobber\0" No_argument "n" | ||
65 | IF_FEATURE_VERBOSE( | ||
66 | "verbose\0" No_argument "v" | ||
67 | ) | ||
68 | ); | ||
81 | argc -= optind; | 69 | argc -= optind; |
82 | argv += optind; | 70 | argv += optind; |
83 | last = argv[argc - 1]; | 71 | last = argv[argc - 1]; |
diff --git a/coreutils/nice.c b/coreutils/nice.c index 0bf055299..d6818cf00 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c | |||
@@ -12,7 +12,7 @@ | |||
12 | //config: help | 12 | //config: help |
13 | //config: nice runs a program with modified scheduling priority. | 13 | //config: nice runs a program with modified scheduling priority. |
14 | 14 | ||
15 | //applet:IF_NICE(APPLET(nice, BB_DIR_BIN, BB_SUID_DROP)) | 15 | //applet:IF_NICE(APPLET_NOEXEC(nice, nice, BB_DIR_BIN, BB_SUID_DROP, nice)) |
16 | 16 | ||
17 | //kbuild:lib-$(CONFIG_NICE) += nice.o | 17 | //kbuild:lib-$(CONFIG_NICE) += nice.o |
18 | 18 | ||
diff --git a/coreutils/nl.c b/coreutils/nl.c index 93e78c490..c2f8b1042 100644 --- a/coreutils/nl.c +++ b/coreutils/nl.c | |||
@@ -57,14 +57,13 @@ int nl_main(int argc UNUSED_PARAM, char **argv) | |||
57 | "starting-line-number\0"Required_argument "v" | 57 | "starting-line-number\0"Required_argument "v" |
58 | "number-width\0" Required_argument "w" | 58 | "number-width\0" Required_argument "w" |
59 | ; | 59 | ; |
60 | |||
61 | applet_long_options = nl_longopts; | ||
62 | #endif | 60 | #endif |
63 | ns.width = 6; | 61 | ns.width = 6; |
64 | ns.start = 1; | 62 | ns.start = 1; |
65 | ns.inc = 1; | 63 | ns.inc = 1; |
66 | ns.sep = "\t"; | 64 | ns.sep = "\t"; |
67 | getopt32(argv, "pw:+s:v:+i:+b:", &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); | 65 | getopt32long(argv, "pw:+s:v:+i:+b:", nl_longopts, |
66 | &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); | ||
68 | ns.all = (opt_b[0] == 'a'); | 67 | ns.all = (opt_b[0] == 'a'); |
69 | ns.nonempty = (opt_b[0] == 't'); | 68 | ns.nonempty = (opt_b[0] == 't'); |
70 | ns.empty_str = xasprintf("%*s\n", ns.width + (int)strlen(ns.sep), ""); | 69 | ns.empty_str = xasprintf("%*s\n", ns.width + (int)strlen(ns.sep), ""); |
diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 8e28f9029..8a70ec4df 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c | |||
@@ -15,7 +15,7 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: run a command immune to hangups, with output to a non-tty. | 16 | //config: run a command immune to hangups, with output to a non-tty. |
17 | 17 | ||
18 | //applet:IF_NOHUP(APPLET(nohup, BB_DIR_USR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_NOHUP(APPLET_NOEXEC(nohup, nohup, BB_DIR_USR_BIN, BB_SUID_DROP, nohup)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_NOHUP) += nohup.o | 20 | //kbuild:lib-$(CONFIG_NOHUP) += nohup.o |
21 | 21 | ||
@@ -31,12 +31,12 @@ | |||
31 | 31 | ||
32 | /* Compat info: nohup (GNU coreutils 6.8) does this: | 32 | /* Compat info: nohup (GNU coreutils 6.8) does this: |
33 | # nohup true | 33 | # nohup true |
34 | nohup: ignoring input and appending output to `nohup.out' | 34 | nohup: ignoring input and appending output to 'nohup.out' |
35 | # nohup true 1>/dev/null | 35 | # nohup true 1>/dev/null |
36 | nohup: ignoring input and redirecting stderr to stdout | 36 | nohup: ignoring input and redirecting stderr to stdout |
37 | # nohup true 2>zz | 37 | # nohup true 2>zz |
38 | # cat zz | 38 | # cat zz |
39 | nohup: ignoring input and appending output to `nohup.out' | 39 | nohup: ignoring input and appending output to 'nohup.out' |
40 | # nohup true 2>zz 1>/dev/null | 40 | # nohup true 2>zz 1>/dev/null |
41 | # cat zz | 41 | # cat zz |
42 | nohup: ignoring input | 42 | nohup: ignoring input |
diff --git a/coreutils/nproc.c b/coreutils/nproc.c index 68a831865..336b176ca 100644 --- a/coreutils/nproc.c +++ b/coreutils/nproc.c | |||
@@ -9,7 +9,7 @@ | |||
9 | //config: help | 9 | //config: help |
10 | //config: Print number of CPUs | 10 | //config: Print number of CPUs |
11 | 11 | ||
12 | //applet:IF_NPROC(APPLET(nproc, BB_DIR_USR_BIN, BB_SUID_DROP)) | 12 | //applet:IF_NPROC(APPLET_NOFORK(nproc, nproc, BB_DIR_USR_BIN, BB_SUID_DROP, nproc)) |
13 | 13 | ||
14 | //kbuild:lib-$(CONFIG_NPROC) += nproc.o | 14 | //kbuild:lib-$(CONFIG_NPROC) += nproc.o |
15 | 15 | ||
@@ -28,7 +28,6 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
28 | unsigned long mask[1024]; | 28 | unsigned long mask[1024]; |
29 | unsigned i, count = 0; | 29 | unsigned i, count = 0; |
30 | 30 | ||
31 | //applet_long_options = ...; | ||
32 | //getopt32(argv, ""); | 31 | //getopt32(argv, ""); |
33 | 32 | ||
34 | //if --all, count /sys/devices/system/cpu/cpuN dirs, else: | 33 | //if --all, count /sys/devices/system/cpu/cpuN dirs, else: |
diff --git a/coreutils/od.c b/coreutils/od.c index e3a68435b..9a888dd5f 100644 --- a/coreutils/od.c +++ b/coreutils/od.c | |||
@@ -223,7 +223,7 @@ int od_main(int argc, char **argv) | |||
223 | * may be used to endorse or promote products derived from this software | 223 | * may be used to endorse or promote products derived from this software |
224 | * without specific prior written permission. | 224 | * without specific prior written permission. |
225 | * | 225 | * |
226 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 226 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
227 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 227 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
228 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 228 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
229 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 229 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index 513c8ef37..df7354b7b 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c | |||
@@ -61,8 +61,8 @@ enum { | |||
61 | OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, | 61 | OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | #define OD_GETOPT32() getopt32(argv, \ | 64 | #define OD_GETOPT32() getopt32long(argv, \ |
65 | "A:N:abcdfhij:lot:*vxsS:w:+:", \ | 65 | "A:N:abcdfhij:lot:*vxsS:w:+:", od_longopts, \ |
66 | /* -w with optional param */ \ | 66 | /* -w with optional param */ \ |
67 | /* -S was -s and also had optional parameter */ \ | 67 | /* -S was -s and also had optional parameter */ \ |
68 | /* but in coreutils 6.3 it was renamed and now has */ \ | 68 | /* but in coreutils 6.3 it was renamed and now has */ \ |
@@ -1220,9 +1220,6 @@ int od_main(int argc UNUSED_PARAM, char **argv) | |||
1220 | address_pad_len_char = '7'; | 1220 | address_pad_len_char = '7'; |
1221 | 1221 | ||
1222 | /* Parse command line */ | 1222 | /* Parse command line */ |
1223 | #if ENABLE_LONG_OPTS | ||
1224 | applet_long_options = od_longopts; | ||
1225 | #endif | ||
1226 | opt = OD_GETOPT32(); | 1223 | opt = OD_GETOPT32(); |
1227 | argv += optind; | 1224 | argv += optind; |
1228 | if (opt & OPT_A) { | 1225 | if (opt & OPT_A) { |
diff --git a/coreutils/printf.c b/coreutils/printf.c index d3fc72adb..d1ff183d0 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c | |||
@@ -43,7 +43,7 @@ | |||
43 | //config: default y | 43 | //config: default y |
44 | //config: help | 44 | //config: help |
45 | //config: printf is used to format and print specified strings. | 45 | //config: printf is used to format and print specified strings. |
46 | //config: It's similar to `echo' except it has more options. | 46 | //config: It's similar to 'echo' except it has more options. |
47 | 47 | ||
48 | //applet:IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf)) | 48 | //applet:IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf)) |
49 | 49 | ||
diff --git a/coreutils/readlink.c b/coreutils/readlink.c index 9690290e3..b8e327d11 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c | |||
@@ -20,7 +20,7 @@ | |||
20 | //config: help | 20 | //config: help |
21 | //config: Enable the readlink option (-f). | 21 | //config: Enable the readlink option (-f). |
22 | 22 | ||
23 | //applet:IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) | 23 | //applet:IF_READLINK(APPLET_NOFORK(readlink, readlink, BB_DIR_USR_BIN, BB_SUID_DROP, readlink)) |
24 | 24 | ||
25 | //kbuild:lib-$(CONFIG_READLINK) += readlink.o | 25 | //kbuild:lib-$(CONFIG_READLINK) += readlink.o |
26 | 26 | ||
@@ -71,8 +71,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) | |||
71 | IF_FEATURE_READLINK_FOLLOW( | 71 | IF_FEATURE_READLINK_FOLLOW( |
72 | unsigned opt; | 72 | unsigned opt; |
73 | /* We need exactly one non-option argument. */ | 73 | /* We need exactly one non-option argument. */ |
74 | opt_complementary = "=1"; | 74 | opt = getopt32(argv, "^" "fnvsq" "\0" "=1"); |
75 | opt = getopt32(argv, "fnvsq"); | ||
76 | fname = argv[optind]; | 75 | fname = argv[optind]; |
77 | ) | 76 | ) |
78 | IF_NOT_FEATURE_READLINK_FOLLOW( | 77 | IF_NOT_FEATURE_READLINK_FOLLOW( |
@@ -85,6 +84,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) | |||
85 | if (!(opt & 4)) /* not -v */ | 84 | if (!(opt & 4)) /* not -v */ |
86 | logmode = LOGMODE_NONE; | 85 | logmode = LOGMODE_NONE; |
87 | 86 | ||
87 | /* NOFORK: only one alloc is allowed; must free */ | ||
88 | if (opt & 1) { /* -f */ | 88 | if (opt & 1) { /* -f */ |
89 | buf = xmalloc_realpath(fname); | 89 | buf = xmalloc_realpath(fname); |
90 | } else { | 90 | } else { |
@@ -94,9 +94,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) | |||
94 | if (!buf) | 94 | if (!buf) |
95 | return EXIT_FAILURE; | 95 | return EXIT_FAILURE; |
96 | printf((opt & 2) ? "%s" : "%s\n", buf); | 96 | printf((opt & 2) ? "%s" : "%s\n", buf); |
97 | 97 | free(buf); | |
98 | if (ENABLE_FEATURE_CLEAN_UP) | ||
99 | free(buf); | ||
100 | 98 | ||
101 | fflush_stdout_and_exit(EXIT_SUCCESS); | 99 | fflush_stdout_and_exit(EXIT_SUCCESS); |
102 | } | 100 | } |
diff --git a/coreutils/realpath.c b/coreutils/realpath.c index 6a61c3dc8..f9c630135 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c | |||
@@ -13,7 +13,7 @@ | |||
13 | //config: Return the canonicalized absolute pathname. | 13 | //config: Return the canonicalized absolute pathname. |
14 | //config: This isn't provided by GNU shellutils, but where else does it belong. | 14 | //config: This isn't provided by GNU shellutils, but where else does it belong. |
15 | 15 | ||
16 | //applet:IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP)) | 16 | //applet:IF_REALPATH(APPLET_NOFORK(realpath, realpath, BB_DIR_USR_BIN, BB_SUID_DROP, realpath)) |
17 | 17 | ||
18 | //kbuild:lib-$(CONFIG_REALPATH) += realpath.o | 18 | //kbuild:lib-$(CONFIG_REALPATH) += realpath.o |
19 | 19 | ||
@@ -36,6 +36,7 @@ int realpath_main(int argc UNUSED_PARAM, char **argv) | |||
36 | } | 36 | } |
37 | 37 | ||
38 | do { | 38 | do { |
39 | /* NOFORK: only one alloc is allowed; must free */ | ||
39 | char *resolved_path = xmalloc_realpath(*argv); | 40 | char *resolved_path = xmalloc_realpath(*argv); |
40 | if (resolved_path != NULL) { | 41 | if (resolved_path != NULL) { |
41 | puts(resolved_path); | 42 | puts(resolved_path); |
diff --git a/coreutils/rm.c b/coreutils/rm.c index f91c94570..b68a82dc4 100644 --- a/coreutils/rm.c +++ b/coreutils/rm.c | |||
@@ -16,7 +16,8 @@ | |||
16 | //config: help | 16 | //config: help |
17 | //config: rm is used to remove files or directories. | 17 | //config: rm is used to remove files or directories. |
18 | 18 | ||
19 | //applet:IF_RM(APPLET_NOFORK(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) | 19 | //applet:IF_RM(APPLET_NOEXEC(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) |
20 | /* was NOFORK, but then "rm -i FILE" can't be ^C'ed if run by hush */ | ||
20 | 21 | ||
21 | //kbuild:lib-$(CONFIG_RM) += rm.o | 22 | //kbuild:lib-$(CONFIG_RM) += rm.o |
22 | 23 | ||
@@ -36,7 +37,7 @@ | |||
36 | 37 | ||
37 | #include "libbb.h" | 38 | #include "libbb.h" |
38 | 39 | ||
39 | /* This is a NOFORK applet. Be very careful! */ | 40 | /* This is a NOEXEC applet. Be very careful! */ |
40 | 41 | ||
41 | int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 42 | int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
42 | int rm_main(int argc UNUSED_PARAM, char **argv) | 43 | int rm_main(int argc UNUSED_PARAM, char **argv) |
@@ -45,8 +46,7 @@ int rm_main(int argc UNUSED_PARAM, char **argv) | |||
45 | int flags = 0; | 46 | int flags = 0; |
46 | unsigned opt; | 47 | unsigned opt; |
47 | 48 | ||
48 | opt_complementary = "f-i:i-f"; | 49 | opt = getopt32(argv, "^" "fiRrv" "\0" "f-i:i-f"); |
49 | opt = getopt32(argv, "fiRrv"); | ||
50 | argv += optind; | 50 | argv += optind; |
51 | if (opt & 1) | 51 | if (opt & 1) |
52 | flags |= FILEUTILS_FORCE; | 52 | flags |= FILEUTILS_FORCE; |
diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c index c04ce78f8..955740494 100644 --- a/coreutils/rmdir.c +++ b/coreutils/rmdir.c | |||
@@ -11,14 +11,6 @@ | |||
11 | //config: default y | 11 | //config: default y |
12 | //config: help | 12 | //config: help |
13 | //config: rmdir is used to remove empty directories. | 13 | //config: rmdir is used to remove empty directories. |
14 | //config: | ||
15 | //config:config FEATURE_RMDIR_LONG_OPTIONS | ||
16 | //config: bool "Enable long options" | ||
17 | //config: default y | ||
18 | //config: depends on RMDIR && LONG_OPTS | ||
19 | //config: help | ||
20 | //config: Support long options for the rmdir applet, including | ||
21 | //config: --ignore-fail-on-non-empty for compatibility with GNU rmdir. | ||
22 | 14 | ||
23 | //applet:IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) | 15 | //applet:IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) |
24 | 16 | ||
@@ -31,12 +23,9 @@ | |||
31 | //usage: "[OPTIONS] DIRECTORY..." | 23 | //usage: "[OPTIONS] DIRECTORY..." |
32 | //usage:#define rmdir_full_usage "\n\n" | 24 | //usage:#define rmdir_full_usage "\n\n" |
33 | //usage: "Remove DIRECTORY if it is empty\n" | 25 | //usage: "Remove DIRECTORY if it is empty\n" |
34 | //usage: IF_FEATURE_RMDIR_LONG_OPTIONS( | ||
35 | //usage: "\n -p|--parents Include parents" | ||
36 | //usage: "\n --ignore-fail-on-non-empty" | ||
37 | //usage: ) | ||
38 | //usage: IF_NOT_FEATURE_RMDIR_LONG_OPTIONS( | ||
39 | //usage: "\n -p Include parents" | 26 | //usage: "\n -p Include parents" |
27 | //usage: IF_LONG_OPTS( | ||
28 | //usage: "\n --ignore-fail-on-non-empty" | ||
40 | //usage: ) | 29 | //usage: ) |
41 | //usage: | 30 | //usage: |
42 | //usage:#define rmdir_example_usage | 31 | //usage:#define rmdir_example_usage |
@@ -49,7 +38,7 @@ | |||
49 | 38 | ||
50 | #define PARENTS (1 << 0) | 39 | #define PARENTS (1 << 0) |
51 | #define VERBOSE ((1 << 1) * ENABLE_FEATURE_VERBOSE) | 40 | #define VERBOSE ((1 << 1) * ENABLE_FEATURE_VERBOSE) |
52 | #define IGNORE_NON_EMPTY (1 << 2) | 41 | #define IGNORE_NON_EMPTY ((1 << 2) * ENABLE_LONG_OPTS) |
53 | 42 | ||
54 | int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 43 | int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
55 | int rmdir_main(int argc UNUSED_PARAM, char **argv) | 44 | int rmdir_main(int argc UNUSED_PARAM, char **argv) |
@@ -58,8 +47,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) | |||
58 | int flags; | 47 | int flags; |
59 | char *path; | 48 | char *path; |
60 | 49 | ||
61 | #if ENABLE_FEATURE_RMDIR_LONG_OPTIONS | 50 | flags = getopt32long(argv, "pv", |
62 | static const char rmdir_longopts[] ALIGN1 = | ||
63 | "parents\0" No_argument "p" | 51 | "parents\0" No_argument "p" |
64 | /* Debian etch: many packages fail to be purged or installed | 52 | /* Debian etch: many packages fail to be purged or installed |
65 | * because they desperately want this option: */ | 53 | * because they desperately want this option: */ |
@@ -67,10 +55,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) | |||
67 | IF_FEATURE_VERBOSE( | 55 | IF_FEATURE_VERBOSE( |
68 | "verbose\0" No_argument "v" | 56 | "verbose\0" No_argument "v" |
69 | ) | 57 | ) |
70 | ; | 58 | ); |
71 | applet_long_options = rmdir_longopts; | ||
72 | #endif | ||
73 | flags = getopt32(argv, "pv"); | ||
74 | argv += optind; | 59 | argv += optind; |
75 | 60 | ||
76 | if (!*argv) { | 61 | if (!*argv) { |
@@ -86,7 +71,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) | |||
86 | } | 71 | } |
87 | 72 | ||
88 | if (rmdir(path) < 0) { | 73 | if (rmdir(path) < 0) { |
89 | #if ENABLE_FEATURE_RMDIR_LONG_OPTIONS | 74 | #if ENABLE_LONG_OPTS |
90 | if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) | 75 | if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) |
91 | break; | 76 | break; |
92 | #endif | 77 | #endif |
diff --git a/coreutils/seq.c b/coreutils/seq.c index f36dbb4ec..c26ff06b9 100644 --- a/coreutils/seq.c +++ b/coreutils/seq.c | |||
@@ -12,7 +12,8 @@ | |||
12 | //config: help | 12 | //config: help |
13 | //config: print a sequence of numbers | 13 | //config: print a sequence of numbers |
14 | 14 | ||
15 | //applet:IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) | 15 | //applet:IF_SEQ(APPLET_NOEXEC(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) |
16 | /* was NOFORK, but then "seq 1 999999999" can't be ^C'ed if run by hush */ | ||
16 | 17 | ||
17 | //kbuild:lib-$(CONFIG_SEQ) += seq.o | 18 | //kbuild:lib-$(CONFIG_SEQ) += seq.o |
18 | 19 | ||
@@ -26,7 +27,7 @@ | |||
26 | 27 | ||
27 | #include "libbb.h" | 28 | #include "libbb.h" |
28 | 29 | ||
29 | /* This is a NOFORK applet. Be very careful! */ | 30 | /* This is a NOEXEC applet. Be very careful! */ |
30 | 31 | ||
31 | int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 32 | int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
32 | int seq_main(int argc, char **argv) | 33 | int seq_main(int argc, char **argv) |
diff --git a/coreutils/shuf.c b/coreutils/shuf.c index 403041534..d0caaa2ce 100644 --- a/coreutils/shuf.c +++ b/coreutils/shuf.c | |||
@@ -70,8 +70,11 @@ int shuf_main(int argc, char **argv) | |||
70 | unsigned numlines; | 70 | unsigned numlines; |
71 | char eol; | 71 | char eol; |
72 | 72 | ||
73 | opt_complementary = "e--i:i--e"; /* mutually exclusive */ | 73 | opts = getopt32(argv, "^" |
74 | opts = getopt32(argv, OPT_STR, &opt_i_str, &opt_n_str, &opt_o_str); | 74 | OPT_STR |
75 | "\0" "e--i:i--e"/* mutually exclusive */, | ||
76 | &opt_i_str, &opt_n_str, &opt_o_str | ||
77 | ); | ||
75 | 78 | ||
76 | argc -= optind; | 79 | argc -= optind; |
77 | argv += optind; | 80 | argv += optind; |
diff --git a/coreutils/sort.c b/coreutils/sort.c index 9860dca64..ceea24491 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c | |||
@@ -94,7 +94,7 @@ | |||
94 | */ | 94 | */ |
95 | 95 | ||
96 | /* These are sort types */ | 96 | /* These are sort types */ |
97 | static const char OPT_STR[] ALIGN1 = "ngMucszbrdfimS:T:o:k:*t:"; | 97 | #define OPT_STR "ngMucszbrdfimS:T:o:k:*t:" |
98 | enum { | 98 | enum { |
99 | FLAG_n = 1, /* Numeric sort */ | 99 | FLAG_n = 1, /* Numeric sort */ |
100 | FLAG_g = 2, /* Sort using strtod() */ | 100 | FLAG_g = 2, /* Sort using strtod() */ |
@@ -378,9 +378,11 @@ int sort_main(int argc UNUSED_PARAM, char **argv) | |||
378 | xfunc_error_retval = 2; | 378 | xfunc_error_retval = 2; |
379 | 379 | ||
380 | /* Parse command line options */ | 380 | /* Parse command line options */ |
381 | /* -o and -t can be given at most once */ | 381 | opts = getopt32(argv, "^" |
382 | opt_complementary = "o--o:t--t"; /* -t, -o: at most one of each */ | 382 | OPT_STR |
383 | opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); | 383 | "\0" "o--o:t--t"/*-t, -o: at most one of each*/, |
384 | &str_ignored, &str_ignored, &str_o, &lst_k, &str_t | ||
385 | ); | ||
384 | /* global b strips leading and trailing spaces */ | 386 | /* global b strips leading and trailing spaces */ |
385 | if (opts & FLAG_b) | 387 | if (opts & FLAG_b) |
386 | option_mask32 |= FLAG_bb; | 388 | option_mask32 |= FLAG_bb; |
diff --git a/coreutils/split.c b/coreutils/split.c index d0c63573a..4e1db190c 100644 --- a/coreutils/split.c +++ b/coreutils/split.c | |||
@@ -100,8 +100,11 @@ int split_main(int argc UNUSED_PARAM, char **argv) | |||
100 | 100 | ||
101 | setup_common_bufsiz(); | 101 | setup_common_bufsiz(); |
102 | 102 | ||
103 | opt_complementary = "?2"; /* max 2 args; -a N */ | 103 | opt = getopt32(argv, "^" |
104 | opt = getopt32(argv, "l:b:a:+", &count_p, &count_p, &suffix_len); | 104 | "l:b:a:+" /* -a N */ |
105 | "\0" "?2"/*max 2 args*/, | ||
106 | &count_p, &count_p, &suffix_len | ||
107 | ); | ||
105 | 108 | ||
106 | if (opt & SPLIT_OPT_l) | 109 | if (opt & SPLIT_OPT_l) |
107 | cnt = XATOOFF(count_p); | 110 | cnt = XATOOFF(count_p); |
diff --git a/coreutils/stat.c b/coreutils/stat.c index 96efa1d5d..177ced2f9 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c | |||
@@ -35,7 +35,7 @@ | |||
35 | //config: Without this, stat will not support the '-f' option to display | 35 | //config: Without this, stat will not support the '-f' option to display |
36 | //config: information about filesystem status. | 36 | //config: information about filesystem status. |
37 | 37 | ||
38 | //applet:IF_STAT(APPLET(stat, BB_DIR_BIN, BB_SUID_DROP)) | 38 | //applet:IF_STAT(APPLET_NOEXEC(stat, stat, BB_DIR_BIN, BB_SUID_DROP, stat)) |
39 | 39 | ||
40 | //kbuild:lib-$(CONFIG_STAT) += stat.o | 40 | //kbuild:lib-$(CONFIG_STAT) += stat.o |
41 | 41 | ||
@@ -761,11 +761,13 @@ int stat_main(int argc UNUSED_PARAM, char **argv) | |||
761 | unsigned opts; | 761 | unsigned opts; |
762 | statfunc_ptr statfunc = do_stat; | 762 | statfunc_ptr statfunc = do_stat; |
763 | 763 | ||
764 | opt_complementary = "-1"; /* min one arg */ | 764 | opts = getopt32(argv, "^" |
765 | opts = getopt32(argv, "tL" | 765 | "tL" |
766 | IF_FEATURE_STAT_FILESYSTEM("f") | 766 | IF_FEATURE_STAT_FILESYSTEM("f") |
767 | IF_SELINUX("Z") | 767 | IF_SELINUX("Z") |
768 | IF_FEATURE_STAT_FORMAT("c:", &format) | 768 | IF_FEATURE_STAT_FORMAT("c:") |
769 | "\0" "-1" /* min one arg */ | ||
770 | IF_FEATURE_STAT_FORMAT(,&format) | ||
769 | ); | 771 | ); |
770 | #if ENABLE_FEATURE_STAT_FILESYSTEM | 772 | #if ENABLE_FEATURE_STAT_FILESYSTEM |
771 | if (opts & OPT_FILESYS) /* -f */ | 773 | if (opts & OPT_FILESYS) /* -f */ |
diff --git a/coreutils/stty.c b/coreutils/stty.c index f987fbbcf..57e2cc30d 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c | |||
@@ -25,7 +25,7 @@ | |||
25 | //config: help | 25 | //config: help |
26 | //config: stty is used to change and print terminal line settings. | 26 | //config: stty is used to change and print terminal line settings. |
27 | 27 | ||
28 | //applet:IF_STTY(APPLET(stty, BB_DIR_BIN, BB_SUID_DROP)) | 28 | //applet:IF_STTY(APPLET_NOEXEC(stty, stty, BB_DIR_BIN, BB_SUID_DROP, stty)) |
29 | 29 | ||
30 | //kbuild:lib-$(CONFIG_STTY) += stty.o | 30 | //kbuild:lib-$(CONFIG_STTY) += stty.o |
31 | 31 | ||
@@ -782,12 +782,13 @@ struct globals { | |||
782 | unsigned max_col; | 782 | unsigned max_col; |
783 | /* Current position, to know when to wrap */ | 783 | /* Current position, to know when to wrap */ |
784 | unsigned current_col; | 784 | unsigned current_col; |
785 | char buf[10]; | ||
786 | } FIX_ALIASING; | 785 | } FIX_ALIASING; |
787 | #define G (*(struct globals*)bb_common_bufsiz1) | 786 | #define G (*(struct globals*)bb_common_bufsiz1) |
788 | #define INIT_G() do { \ | 787 | #define INIT_G() do { \ |
788 | setup_common_bufsiz(); \ | ||
789 | G.device_name = bb_msg_standard_input; \ | 789 | G.device_name = bb_msg_standard_input; \ |
790 | G.max_col = 80; \ | 790 | G.max_col = 80; \ |
791 | G.current_col = 0; /* we are noexec, must clear */ \ | ||
791 | } while (0) | 792 | } while (0) |
792 | 793 | ||
793 | static void set_speed_or_die(enum speed_setting type, const char *arg, | 794 | static void set_speed_or_die(enum speed_setting type, const char *arg, |
@@ -1018,6 +1019,8 @@ static void do_display(const struct termios *mode, int all) | |||
1018 | 1019 | ||
1019 | for (i = 0; i != CIDX_min; ++i) { | 1020 | for (i = 0; i != CIDX_min; ++i) { |
1020 | char ch; | 1021 | char ch; |
1022 | char buf10[10]; | ||
1023 | |||
1021 | /* If swtch is the same as susp, don't print both */ | 1024 | /* If swtch is the same as susp, don't print both */ |
1022 | #if VSWTCH == VSUSP | 1025 | #if VSWTCH == VSUSP |
1023 | if (i == CIDX_swtch) | 1026 | if (i == CIDX_swtch) |
@@ -1033,10 +1036,10 @@ static void do_display(const struct termios *mode, int all) | |||
1033 | #endif | 1036 | #endif |
1034 | ch = mode->c_cc[control_info[i].offset]; | 1037 | ch = mode->c_cc[control_info[i].offset]; |
1035 | if (ch == _POSIX_VDISABLE) | 1038 | if (ch == _POSIX_VDISABLE) |
1036 | strcpy(G.buf, "<undef>"); | 1039 | strcpy(buf10, "<undef>"); |
1037 | else | 1040 | else |
1038 | visible(ch, G.buf, 0); | 1041 | visible(ch, buf10, 0); |
1039 | wrapf("%s = %s;", nth_string(control_name, i), G.buf); | 1042 | wrapf("%s = %s;", nth_string(control_name, i), buf10); |
1040 | } | 1043 | } |
1041 | #if VEOF == VMIN | 1044 | #if VEOF == VMIN |
1042 | if ((mode->c_lflag & ICANON) == 0) | 1045 | if ((mode->c_lflag & ICANON) == 0) |
diff --git a/coreutils/sync.c b/coreutils/sync.c index 66445281a..9be47ab64 100644 --- a/coreutils/sync.c +++ b/coreutils/sync.c | |||
@@ -59,8 +59,7 @@ int sync_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | |||
59 | OPT_SYNCFS = (1 << 1), | 59 | OPT_SYNCFS = (1 << 1), |
60 | }; | 60 | }; |
61 | 61 | ||
62 | opt_complementary = "d--f:f--d"; | 62 | opts = getopt32(argv, "^" "df" "\0" "d--f:f--d"); |
63 | opts = getopt32(argv, "df"); | ||
64 | argv += optind; | 63 | argv += optind; |
65 | 64 | ||
66 | /* Handle the no-argument case. */ | 65 | /* Handle the no-argument case. */ |
diff --git a/coreutils/tail.c b/coreutils/tail.c index fd310f422..7335ba11e 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c | |||
@@ -140,9 +140,11 @@ int tail_main(int argc, char **argv) | |||
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | /* -s NUM, -F imlies -f */ | 142 | /* -s NUM, -F imlies -f */ |
143 | IF_FEATURE_FANCY_TAIL(opt_complementary = "Ff";) | 143 | opt = getopt32(argv, IF_FEATURE_FANCY_TAIL("^") |
144 | opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:+vF"), | 144 | "fc:n:"IF_FEATURE_FANCY_TAIL("qs:+vF") |
145 | &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period)); | 145 | IF_FEATURE_FANCY_TAIL("\0" "Ff"), |
146 | &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period) | ||
147 | ); | ||
146 | #define FOLLOW (opt & 0x1) | 148 | #define FOLLOW (opt & 0x1) |
147 | #define COUNT_BYTES (opt & 0x2) | 149 | #define COUNT_BYTES (opt & 0x2) |
148 | //if (opt & 0x1) // -f | 150 | //if (opt & 0x1) // -f |
diff --git a/coreutils/touch.c b/coreutils/touch.c index 11b40d427..857761578 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c | |||
@@ -103,6 +103,11 @@ int touch_main(int argc UNUSED_PARAM, char **argv) | |||
103 | "date\0" Required_argument "d" | 103 | "date\0" Required_argument "d" |
104 | IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") | 104 | IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") |
105 | ; | 105 | ; |
106 | # define GETOPT32 getopt32long | ||
107 | # define LONGOPTS ,touch_longopts | ||
108 | # else | ||
109 | # define GETOPT32 getopt32 | ||
110 | # define LONGOPTS | ||
106 | # endif | 111 | # endif |
107 | char *reference_file = NULL; | 112 | char *reference_file = NULL; |
108 | char *date_str = NULL; | 113 | char *date_str = NULL; |
@@ -112,17 +117,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv) | |||
112 | # define reference_file NULL | 117 | # define reference_file NULL |
113 | # define date_str NULL | 118 | # define date_str NULL |
114 | # define timebuf ((struct timeval*)NULL) | 119 | # define timebuf ((struct timeval*)NULL) |
120 | # define GETOPT32 getopt32 | ||
121 | # define LONGOPTS | ||
115 | #endif | 122 | #endif |
116 | 123 | ||
117 | #if ENABLE_FEATURE_TOUCH_SUSV3 && ENABLE_LONG_OPTS | ||
118 | applet_long_options = touch_longopts; | ||
119 | #endif | ||
120 | /* -d and -t both set time. In coreutils, | 124 | /* -d and -t both set time. In coreutils, |
121 | * accepted data format differs a bit between -d and -t. | 125 | * accepted data format differs a bit between -d and -t. |
122 | * We accept the same formats for both */ | 126 | * We accept the same formats for both */ |
123 | opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") | 127 | opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") |
124 | IF_FEATURE_TOUCH_NODEREF("h") | 128 | IF_FEATURE_TOUCH_NODEREF("h") |
125 | /*ignored:*/ "fma" | 129 | /*ignored:*/ "fma" |
130 | LONGOPTS | ||
126 | IF_FEATURE_TOUCH_SUSV3(, &reference_file) | 131 | IF_FEATURE_TOUCH_SUSV3(, &reference_file) |
127 | IF_FEATURE_TOUCH_SUSV3(, &date_str) | 132 | IF_FEATURE_TOUCH_SUSV3(, &date_str) |
128 | IF_FEATURE_TOUCH_SUSV3(, &date_str) | 133 | IF_FEATURE_TOUCH_SUSV3(, &date_str) |
diff --git a/coreutils/tr.c b/coreutils/tr.c index 64e4efc91..c5872434a 100644 --- a/coreutils/tr.c +++ b/coreutils/tr.c | |||
@@ -298,8 +298,8 @@ int tr_main(int argc UNUSED_PARAM, char **argv) | |||
298 | * In POSIX locale, these are the same. | 298 | * In POSIX locale, these are the same. |
299 | */ | 299 | */ |
300 | 300 | ||
301 | opt_complementary = "-1"; | 301 | /* '+': stop at first non-option */ |
302 | opts = getopt32(argv, "+Ccds"); /* '+': stop at first non-option */ | 302 | opts = getopt32(argv, "^+" "Ccds" "\0" "-1"); |
303 | argv += optind; | 303 | argv += optind; |
304 | 304 | ||
305 | str1_length = expand(*argv++, &str1); | 305 | str1_length = expand(*argv++, &str1); |
diff --git a/coreutils/truncate.c b/coreutils/truncate.c index f67abaf40..f693570aa 100644 --- a/coreutils/truncate.c +++ b/coreutils/truncate.c | |||
@@ -50,8 +50,7 @@ int truncate_main(int argc UNUSED_PARAM, char **argv) | |||
50 | OPT_SIZE = (1 << 1), | 50 | OPT_SIZE = (1 << 1), |
51 | }; | 51 | }; |
52 | 52 | ||
53 | opt_complementary = "s:-1"; | 53 | opts = getopt32(argv, "^" "cs:" "\0" "s:-1", &size_str); |
54 | opts = getopt32(argv, "cs:", &size_str); | ||
55 | 54 | ||
56 | if (!(opts & OPT_NOCREATE)) | 55 | if (!(opts & OPT_NOCREATE)) |
57 | flags |= O_CREAT; | 56 | flags |= O_CREAT; |
diff --git a/coreutils/tty.c b/coreutils/tty.c index 331941a01..18ad7c566 100644 --- a/coreutils/tty.c +++ b/coreutils/tty.c | |||
@@ -13,7 +13,7 @@ | |||
13 | //config: tty is used to print the name of the current terminal to | 13 | //config: tty is used to print the name of the current terminal to |
14 | //config: standard output. | 14 | //config: standard output. |
15 | 15 | ||
16 | //applet:IF_TTY(APPLET(tty, BB_DIR_USR_BIN, BB_SUID_DROP)) | 16 | //applet:IF_TTY(APPLET_NOFORK(tty, tty, BB_DIR_USR_BIN, BB_SUID_DROP, tty)) |
17 | 17 | ||
18 | //kbuild:lib-$(CONFIG_TTY) += tty.o | 18 | //kbuild:lib-$(CONFIG_TTY) += tty.o |
19 | 19 | ||
diff --git a/coreutils/uname.c b/coreutils/uname.c index aad58cab0..bb2d1fe8d 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c | |||
@@ -63,9 +63,9 @@ | |||
63 | //config: help | 63 | //config: help |
64 | //config: Same as uname -m. | 64 | //config: Same as uname -m. |
65 | 65 | ||
66 | //applet:IF_UNAME(APPLET(uname, BB_DIR_BIN, BB_SUID_DROP)) | 66 | // APPLET_NOFORK:name main location suid_type help |
67 | // APPLET_ODDNAME:name main location suid_type help | 67 | //applet:IF_UNAME(APPLET_NOFORK( uname, uname, BB_DIR_BIN, BB_SUID_DROP, uname)) |
68 | //applet:IF_BB_ARCH(APPLET_ODDNAME(arch, uname, BB_DIR_BIN, BB_SUID_DROP, arch)) | 68 | //applet:IF_BB_ARCH(APPLET_NOFORK(arch, uname, BB_DIR_BIN, BB_SUID_DROP, arch)) |
69 | 69 | ||
70 | //kbuild:lib-$(CONFIG_UNAME) += uname.o | 70 | //kbuild:lib-$(CONFIG_UNAME) += uname.o |
71 | //kbuild:lib-$(CONFIG_BB_ARCH) += uname.o | 71 | //kbuild:lib-$(CONFIG_BB_ARCH) += uname.o |
@@ -147,8 +147,7 @@ int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
147 | "operating-system\0" No_argument "o" | 147 | "operating-system\0" No_argument "o" |
148 | ; | 148 | ; |
149 | # endif | 149 | # endif |
150 | IF_LONG_OPTS(applet_long_options = uname_longopts); | 150 | toprint = getopt32long(argv, options, uname_longopts); |
151 | toprint = getopt32(argv, options); | ||
152 | if (argv[optind]) { /* coreutils-6.9 compat */ | 151 | if (argv[optind]) { /* coreutils-6.9 compat */ |
153 | bb_show_usage(); | 152 | bb_show_usage(); |
154 | } | 153 | } |
@@ -183,7 +182,7 @@ int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
183 | strcpy(uname_info.processor, unknown_str); | 182 | strcpy(uname_info.processor, unknown_str); |
184 | strcpy(uname_info.platform, unknown_str); | 183 | strcpy(uname_info.platform, unknown_str); |
185 | strcpy(uname_info.os, CONFIG_UNAME_OSNAME); | 184 | strcpy(uname_info.os, CONFIG_UNAME_OSNAME); |
186 | # if 0 | 185 | # if ENABLE_FEDORA_COMPAT |
187 | /* Fedora does something like this */ | 186 | /* Fedora does something like this */ |
188 | strcpy(uname_info.processor, uname_info.name.machine); | 187 | strcpy(uname_info.processor, uname_info.name.machine); |
189 | strcpy(uname_info.platform, uname_info.name.machine); | 188 | strcpy(uname_info.platform, uname_info.name.machine); |
diff --git a/coreutils/unlink.c b/coreutils/unlink.c index 3322d5b47..56309b1c7 100644 --- a/coreutils/unlink.c +++ b/coreutils/unlink.c | |||
@@ -11,7 +11,7 @@ | |||
11 | //config: help | 11 | //config: help |
12 | //config: unlink deletes a file by calling unlink() | 12 | //config: unlink deletes a file by calling unlink() |
13 | 13 | ||
14 | //applet:IF_UNLINK(APPLET(unlink, BB_DIR_USR_BIN, BB_SUID_DROP)) | 14 | //applet:IF_UNLINK(APPLET_NOFORK(unlink, unlink, BB_DIR_USR_BIN, BB_SUID_DROP, unlink)) |
15 | 15 | ||
16 | //kbuild:lib-$(CONFIG_UNLINK) += unlink.o | 16 | //kbuild:lib-$(CONFIG_UNLINK) += unlink.o |
17 | 17 | ||
@@ -25,8 +25,7 @@ | |||
25 | int unlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 25 | int unlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
26 | int unlink_main(int argc UNUSED_PARAM, char **argv) | 26 | int unlink_main(int argc UNUSED_PARAM, char **argv) |
27 | { | 27 | { |
28 | opt_complementary = "=1"; /* must have exactly 1 param */ | 28 | getopt32(argv, "^" "" "\0" "=1"); |
29 | getopt32(argv, ""); | ||
30 | argv += optind; | 29 | argv += optind; |
31 | xunlink(argv[0]); | 30 | xunlink(argv[0]); |
32 | return 0; | 31 | return 0; |
diff --git a/coreutils/usleep.c b/coreutils/usleep.c index 7c25aada1..684ab781b 100644 --- a/coreutils/usleep.c +++ b/coreutils/usleep.c | |||
@@ -38,6 +38,13 @@ int usleep_main(int argc UNUSED_PARAM, char **argv) | |||
38 | bb_show_usage(); | 38 | bb_show_usage(); |
39 | } | 39 | } |
40 | 40 | ||
41 | /* Safe wrt NOFORK? (noforks are not allowed to run for | ||
42 | * a long time). Try "usleep 99999999" + ^C + "echo $?" | ||
43 | * in hush with FEATURE_SH_NOFORK=y. | ||
44 | * At least on uclibc, usleep() thanslates to nanosleep() | ||
45 | * which returns early on any signal (even caught one), | ||
46 | * and uclibc does not loop back on EINTR. | ||
47 | */ | ||
41 | usleep(xatou(argv[1])); | 48 | usleep(xatou(argv[1])); |
42 | 49 | ||
43 | return EXIT_SUCCESS; | 50 | return EXIT_SUCCESS; |
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c index 4e72e86ee..5ef05ee4d 100644 --- a/coreutils/uudecode.c +++ b/coreutils/uudecode.c | |||
@@ -120,8 +120,7 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) | |||
120 | char *outname = NULL; | 120 | char *outname = NULL; |
121 | char *line; | 121 | char *line; |
122 | 122 | ||
123 | opt_complementary = "?1"; /* 1 argument max */ | 123 | getopt32(argv, "^" "o:" "\0" "?1"/* 1 arg max*/, &outname); |
124 | getopt32(argv, "o:", &outname); | ||
125 | argv += optind; | 124 | argv += optind; |
126 | 125 | ||
127 | if (!argv[0]) | 126 | if (!argv[0]) |
@@ -196,8 +195,7 @@ int base64_main(int argc UNUSED_PARAM, char **argv) | |||
196 | FILE *src_stream; | 195 | FILE *src_stream; |
197 | unsigned opts; | 196 | unsigned opts; |
198 | 197 | ||
199 | opt_complementary = "?1"; /* 1 argument max */ | 198 | opts = getopt32(argv, "^" "d" "\0" "?1"/* 1 arg max*/); |
200 | opts = getopt32(argv, "d"); | ||
201 | argv += optind; | 199 | argv += optind; |
202 | 200 | ||
203 | if (!argv[0]) | 201 | if (!argv[0]) |
diff --git a/coreutils/uuencode.c b/coreutils/uuencode.c index 7164f838a..d6e077430 100644 --- a/coreutils/uuencode.c +++ b/coreutils/uuencode.c | |||
@@ -49,8 +49,7 @@ int uuencode_main(int argc UNUSED_PARAM, char **argv) | |||
49 | 49 | ||
50 | tbl = bb_uuenc_tbl_std; | 50 | tbl = bb_uuenc_tbl_std; |
51 | mode = 0666 & ~umask(0666); | 51 | mode = 0666 & ~umask(0666); |
52 | opt_complementary = "-1:?2"; /* must have 1 or 2 args */ | 52 | if (getopt32(argv, "^" "m" "\0" "-1:?2"/*must have 1 or 2 args*/)) { |
53 | if (getopt32(argv, "m")) { | ||
54 | tbl = bb_uuenc_tbl_base64; | 53 | tbl = bb_uuenc_tbl_base64; |
55 | } | 54 | } |
56 | argv += optind; | 55 | argv += optind; |
diff --git a/coreutils/who.c b/coreutils/who.c index 91f99138c..cfe0c921e 100644 --- a/coreutils/who.c +++ b/coreutils/who.c | |||
@@ -38,10 +38,10 @@ | |||
38 | //config: help | 38 | //config: help |
39 | //config: Print users currently logged on. | 39 | //config: Print users currently logged on. |
40 | 40 | ||
41 | // APPLET_ODDNAME:name main location suid_type help | 41 | // APPLET_NOEXEC:name main location suid_type help |
42 | //applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) | 42 | //applet:IF_USERS(APPLET_NOEXEC(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) |
43 | //applet:IF_W( APPLET_ODDNAME(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) | 43 | //applet:IF_W( APPLET_NOEXEC(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) |
44 | //applet:IF_WHO( APPLET( who, BB_DIR_USR_BIN, BB_SUID_DROP)) | 44 | //applet:IF_WHO( APPLET_NOEXEC(who, who, BB_DIR_USR_BIN, BB_SUID_DROP, who)) |
45 | 45 | ||
46 | //kbuild:lib-$(CONFIG_USERS) += who.o | 46 | //kbuild:lib-$(CONFIG_USERS) += who.o |
47 | //kbuild:lib-$(CONFIG_W) += who.o | 47 | //kbuild:lib-$(CONFIG_W) += who.o |
@@ -117,8 +117,7 @@ int who_main(int argc UNUSED_PARAM, char **argv) | |||
117 | unsigned opt; | 117 | unsigned opt; |
118 | const char *fmt = "%s"; | 118 | const char *fmt = "%s"; |
119 | 119 | ||
120 | opt_complementary = "=0"; | 120 | opt = getopt32(argv, do_who ? "^" "aH" "\0" "=0": "^" "" "\0" "=0"); |
121 | opt = getopt32(argv, do_who ? "aH" : ""); | ||
122 | if ((opt & 2) || do_w) /* -H or we are w */ | 121 | if ((opt & 2) || do_w) /* -H or we are w */ |
123 | puts("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST"); | 122 | puts("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST"); |
124 | 123 | ||
diff --git a/coreutils/yes.c b/coreutils/yes.c index a5a444249..6dc47355e 100644 --- a/coreutils/yes.c +++ b/coreutils/yes.c | |||
@@ -15,9 +15,10 @@ | |||
15 | //config: default y | 15 | //config: default y |
16 | //config: help | 16 | //config: help |
17 | //config: yes is used to repeatedly output a specific string, or | 17 | //config: yes is used to repeatedly output a specific string, or |
18 | //config: the default string `y'. | 18 | //config: the default string 'y'. |
19 | 19 | ||
20 | //applet:IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) | 20 | //applet:IF_YES(APPLET_NOEXEC(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) |
21 | /* was NOFORK, but then yes can't be ^C'ed if run by hush */ | ||
21 | 22 | ||
22 | //kbuild:lib-$(CONFIG_YES) += yes.o | 23 | //kbuild:lib-$(CONFIG_YES) += yes.o |
23 | 24 | ||
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index c6a90a486..e4d61df35 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c | |||
@@ -159,10 +159,15 @@ static const char runparts_longopts[] ALIGN1 = | |||
159 | "reverse\0" No_argument "\xf0" | 159 | "reverse\0" No_argument "\xf0" |
160 | "test\0" No_argument "\xf1" | 160 | "test\0" No_argument "\xf1" |
161 | "exit-on-error\0" No_argument "\xf2" | 161 | "exit-on-error\0" No_argument "\xf2" |
162 | #if ENABLE_FEATURE_RUN_PARTS_FANCY | 162 | # if ENABLE_FEATURE_RUN_PARTS_FANCY |
163 | "list\0" No_argument "\xf3" | 163 | "list\0" No_argument "\xf3" |
164 | #endif | 164 | # endif |
165 | ; | 165 | ; |
166 | # define GETOPT32 getopt32long | ||
167 | # define LONGOPTS ,runparts_longopts | ||
168 | #else | ||
169 | # define GETOPT32 getopt32 | ||
170 | # define LONGOPTS | ||
166 | #endif | 171 | #endif |
167 | 172 | ||
168 | int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 173 | int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -175,12 +180,10 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) | |||
175 | 180 | ||
176 | INIT_G(); | 181 | INIT_G(); |
177 | 182 | ||
178 | #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS | ||
179 | applet_long_options = runparts_longopts; | ||
180 | #endif | ||
181 | /* We require exactly one argument: the directory name */ | 183 | /* We require exactly one argument: the directory name */ |
182 | opt_complementary = "=1"; | 184 | GETOPT32(argv, "^" "a:*u:" "\0" "=1" LONGOPTS, |
183 | getopt32(argv, "a:*u:", &arg_list, &umask_p); | 185 | &arg_list, &umask_p |
186 | ); | ||
184 | 187 | ||
185 | umask(xstrtou_range(umask_p, 8, 0, 07777)); | 188 | umask(xstrtou_range(umask_p, 8, 0, 07777)); |
186 | 189 | ||
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 9d60b2c7f..c8b7fa8f2 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c | |||
@@ -79,6 +79,7 @@ Misc options: | |||
79 | //config: -N|--nicelevel N | 79 | //config: -N|--nicelevel N |
80 | 80 | ||
81 | //applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) | 81 | //applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) |
82 | /* not NOEXEC: uses bb_common_bufsiz1 */ | ||
82 | 83 | ||
83 | //kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o | 84 | //kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o |
84 | 85 | ||
@@ -86,44 +87,15 @@ Misc options: | |||
86 | //usage: "[OPTIONS] [-S|-K] ... [-- ARGS...]" | 87 | //usage: "[OPTIONS] [-S|-K] ... [-- ARGS...]" |
87 | //usage:#define start_stop_daemon_full_usage "\n\n" | 88 | //usage:#define start_stop_daemon_full_usage "\n\n" |
88 | //usage: "Search for matching processes, and then\n" | 89 | //usage: "Search for matching processes, and then\n" |
89 | //usage: "-K: stop all matching processes.\n" | 90 | //usage: "-K: stop all matching processes\n" |
90 | //usage: "-S: start a process unless a matching process is found.\n" | 91 | //usage: "-S: start a process unless a matching process is found\n" |
91 | //usage: IF_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( | ||
92 | //usage: "\nProcess matching:" | ||
93 | //usage: "\n -u,--user USERNAME|UID Match only this user's processes" | ||
94 | //usage: "\n -n,--name NAME Match processes with NAME" | ||
95 | //usage: "\n in comm field in /proc/PID/stat" | ||
96 | //usage: "\n -x,--exec EXECUTABLE Match processes with this command" | ||
97 | //usage: "\n in /proc/PID/{exe,cmdline}" | ||
98 | //usage: "\n -p,--pidfile FILE Match a process with PID from the file" | ||
99 | //usage: "\n All specified conditions must match" | ||
100 | //usage: "\n-S only:" | ||
101 | //usage: "\n -x,--exec EXECUTABLE Program to run" | ||
102 | //usage: "\n -a,--startas NAME Zeroth argument" | ||
103 | //usage: "\n -b,--background Background" | ||
104 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( | ||
105 | //usage: "\n -N,--nicelevel N Change nice level" | ||
106 | //usage: ) | ||
107 | //usage: "\n -c,--chuid USER[:[GRP]] Change to user/group" | ||
108 | //usage: "\n -m,--make-pidfile Write PID to the pidfile specified by -p" | ||
109 | //usage: "\n-K only:" | ||
110 | //usage: "\n -s,--signal SIG Signal to send" | ||
111 | //usage: "\n -t,--test Match only, exit with 0 if a process is found" | ||
112 | //usage: "\nOther:" | ||
113 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( | ||
114 | //usage: "\n -o,--oknodo Exit with status 0 if nothing is done" | ||
115 | //usage: "\n -v,--verbose Verbose" | ||
116 | //usage: ) | ||
117 | //usage: "\n -q,--quiet Quiet" | ||
118 | //usage: ) | ||
119 | //usage: IF_NOT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( | ||
120 | //usage: "\nProcess matching:" | 92 | //usage: "\nProcess matching:" |
121 | //usage: "\n -u USERNAME|UID Match only this user's processes" | 93 | //usage: "\n -u USERNAME|UID Match only this user's processes" |
122 | //usage: "\n -n NAME Match processes with NAME" | 94 | //usage: "\n -n NAME Match processes with NAME" |
123 | //usage: "\n in comm field in /proc/PID/stat" | 95 | //usage: "\n in comm field in /proc/PID/stat" |
124 | //usage: "\n -x EXECUTABLE Match processes with this command" | 96 | //usage: "\n -x EXECUTABLE Match processes with this command" |
125 | //usage: "\n command in /proc/PID/cmdline" | 97 | //usage: "\n command in /proc/PID/cmdline" |
126 | //usage: "\n -p FILE Match a process with PID from the file" | 98 | //usage: "\n -p FILE Match a process with PID from FILE" |
127 | //usage: "\n All specified conditions must match" | 99 | //usage: "\n All specified conditions must match" |
128 | //usage: "\n-S only:" | 100 | //usage: "\n-S only:" |
129 | //usage: "\n -x EXECUTABLE Program to run" | 101 | //usage: "\n -x EXECUTABLE Program to run" |
@@ -132,18 +104,17 @@ Misc options: | |||
132 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( | 104 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( |
133 | //usage: "\n -N N Change nice level" | 105 | //usage: "\n -N N Change nice level" |
134 | //usage: ) | 106 | //usage: ) |
135 | //usage: "\n -c USER[:[GRP]] Change to user/group" | 107 | //usage: "\n -c USER[:[GRP]] Change user/group" |
136 | //usage: "\n -m Write PID to the pidfile specified by -p" | 108 | //usage: "\n -m Write PID to pidfile specified by -p" |
137 | //usage: "\n-K only:" | 109 | //usage: "\n-K only:" |
138 | //usage: "\n -s SIG Signal to send" | 110 | //usage: "\n -s SIG Signal to send" |
139 | //usage: "\n -t Match only, exit with 0 if a process is found" | 111 | //usage: "\n -t Match only, exit with 0 if found" |
140 | //usage: "\nOther:" | 112 | //usage: "\nOther:" |
141 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( | 113 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( |
142 | //usage: "\n -o Exit with status 0 if nothing is done" | 114 | //usage: "\n -o Exit with status 0 if nothing is done" |
143 | //usage: "\n -v Verbose" | 115 | //usage: "\n -v Verbose" |
144 | //usage: ) | 116 | //usage: ) |
145 | //usage: "\n -q Quiet" | 117 | //usage: "\n -q Quiet" |
146 | //usage: ) | ||
147 | 118 | ||
148 | #include <sys/resource.h> | 119 | #include <sys/resource.h> |
149 | 120 | ||
@@ -409,11 +380,11 @@ static const char start_stop_daemon_longopts[] ALIGN1 = | |||
409 | "quiet\0" No_argument "q" | 380 | "quiet\0" No_argument "q" |
410 | "test\0" No_argument "t" | 381 | "test\0" No_argument "t" |
411 | "make-pidfile\0" No_argument "m" | 382 | "make-pidfile\0" No_argument "m" |
412 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY | 383 | # if ENABLE_FEATURE_START_STOP_DAEMON_FANCY |
413 | "oknodo\0" No_argument "o" | 384 | "oknodo\0" No_argument "o" |
414 | "verbose\0" No_argument "v" | 385 | "verbose\0" No_argument "v" |
415 | "nicelevel\0" Required_argument "N" | 386 | "nicelevel\0" Required_argument "N" |
416 | #endif | 387 | # endif |
417 | "startas\0" Required_argument "a" | 388 | "startas\0" Required_argument "a" |
418 | "name\0" Required_argument "n" | 389 | "name\0" Required_argument "n" |
419 | "signal\0" Required_argument "s" | 390 | "signal\0" Required_argument "s" |
@@ -421,10 +392,15 @@ static const char start_stop_daemon_longopts[] ALIGN1 = | |||
421 | "chuid\0" Required_argument "c" | 392 | "chuid\0" Required_argument "c" |
422 | "exec\0" Required_argument "x" | 393 | "exec\0" Required_argument "x" |
423 | "pidfile\0" Required_argument "p" | 394 | "pidfile\0" Required_argument "p" |
424 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY | 395 | # if ENABLE_FEATURE_START_STOP_DAEMON_FANCY |
425 | "retry\0" Required_argument "R" | 396 | "retry\0" Required_argument "R" |
426 | #endif | 397 | # endif |
427 | ; | 398 | ; |
399 | # define GETOPT32 getopt32long | ||
400 | # define LONGOPTS start_stop_daemon_longopts, | ||
401 | #else | ||
402 | # define GETOPT32 getopt32 | ||
403 | # define LONGOPTS | ||
428 | #endif | 404 | #endif |
429 | 405 | ||
430 | int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 406 | int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -445,19 +421,18 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
445 | 421 | ||
446 | INIT_G(); | 422 | INIT_G(); |
447 | 423 | ||
448 | #if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS | 424 | opt = GETOPT32(argv, "^" |
449 | applet_long_options = start_stop_daemon_longopts; | 425 | "KSbqtma:n:s:u:c:x:p:" |
450 | #endif | 426 | IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:") |
451 | 427 | /* -K or -S is required; they are mutually exclusive */ | |
452 | /* -K or -S is required; they are mutually exclusive */ | 428 | /* -p is required if -m is given */ |
453 | /* -p is required if -m is given */ | 429 | /* -xpun (at least one) is required if -K is given */ |
454 | /* -xpun (at least one) is required if -K is given */ | 430 | /* -xa (at least one) is required if -S is given */ |
455 | /* -xa (at least one) is required if -S is given */ | 431 | /* -q turns off -v */ |
456 | /* -q turns off -v */ | 432 | "\0" |
457 | opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa" | 433 | "K:S:K--S:S--K:m?p:K?xpun:S?xa" |
458 | IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"); | 434 | IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), |
459 | opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:" | 435 | LONGOPTS |
460 | IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"), | ||
461 | &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile | 436 | &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile |
462 | IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) | 437 | IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) |
463 | /* We accept and ignore -R <param> / --retry <param> */ | 438 | /* We accept and ignore -R <param> / --retry <param> */ |
@@ -516,6 +491,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
516 | /* DAEMON_DEVNULL_STDIO is superfluous - | 491 | /* DAEMON_DEVNULL_STDIO is superfluous - |
517 | * it's always done by bb_daemonize() */ | 492 | * it's always done by bb_daemonize() */ |
518 | #else | 493 | #else |
494 | /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do | ||
495 | * without: SSD is not itself a daemon, it _execs_ a daemon. | ||
496 | * The usual NOMMU problem of "child can't run indefinitely, | ||
497 | * it must exec" does not bite us: we exec anyway. | ||
498 | */ | ||
519 | pid_t pid = xvfork(); | 499 | pid_t pid = xvfork(); |
520 | if (pid != 0) { | 500 | if (pid != 0) { |
521 | /* parent */ | 501 | /* parent */ |
@@ -525,12 +505,8 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
525 | } | 505 | } |
526 | /* Child */ | 506 | /* Child */ |
527 | setsid(); /* detach from controlling tty */ | 507 | setsid(); /* detach from controlling tty */ |
528 | /* Redirect stdio to /dev/null, close extra FDs. | 508 | /* Redirect stdio to /dev/null, close extra FDs */ |
529 | * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */ | 509 | bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); |
530 | bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | ||
531 | + DAEMON_CLOSE_EXTRA_FDS | ||
532 | + DAEMON_ONLY_SANITIZE, | ||
533 | NULL /* argv, unused */ ); | ||
534 | #endif | 510 | #endif |
535 | } | 511 | } |
536 | if (opt & OPT_MAKEPID) { | 512 | if (opt & OPT_MAKEPID) { |
diff --git a/debianutils/which.c b/debianutils/which.c index 23a481438..fbfd19cdc 100644 --- a/debianutils/which.c +++ b/debianutils/which.c | |||
@@ -12,7 +12,7 @@ | |||
12 | //config: which is used to find programs in your PATH and | 12 | //config: which is used to find programs in your PATH and |
13 | //config: print out their pathnames. | 13 | //config: print out their pathnames. |
14 | 14 | ||
15 | //applet:IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP)) | 15 | //applet:IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)) |
16 | 16 | ||
17 | //kbuild:lib-$(CONFIG_WHICH) += which.o | 17 | //kbuild:lib-$(CONFIG_WHICH) += which.o |
18 | 18 | ||
@@ -37,8 +37,7 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
37 | if (!env_path) | 37 | if (!env_path) |
38 | env_path = bb_default_root_path; | 38 | env_path = bb_default_root_path; |
39 | 39 | ||
40 | opt_complementary = "-1"; /* at least one argument */ | 40 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); |
41 | getopt32(argv, "a"); | ||
42 | argv += optind; | 41 | argv += optind; |
43 | 42 | ||
44 | do { | 43 | do { |
@@ -73,6 +72,8 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
73 | char *tmp; | 72 | char *tmp; |
74 | 73 | ||
75 | path = tmp = xstrdup(env_path); | 74 | path = tmp = xstrdup(env_path); |
75 | //NOFORK FIXME: nested xmallocs (one is inside find_executable()) | ||
76 | //can leak memory on failure | ||
76 | while ((p = find_executable(*argv, &tmp)) != NULL) { | 77 | while ((p = find_executable(*argv, &tmp)) != NULL) { |
77 | missing = 0; | 78 | missing = 0; |
78 | puts(p); | 79 | puts(p); |
diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt index 078e77bce..619d47fb8 100644 --- a/docs/new-applet-HOWTO.txt +++ b/docs/new-applet-HOWTO.txt | |||
@@ -147,17 +147,17 @@ Placement / Directory | |||
147 | 147 | ||
148 | Find the appropriate directory for your new applet. | 148 | Find the appropriate directory for your new applet. |
149 | 149 | ||
150 | Add the kbuild snippet to the .c file: | ||
151 | |||
152 | //kbuild:lib-$(CONFIG_MU) += mu.o | ||
153 | |||
154 | Add the config snippet to the .c file: | 150 | Add the config snippet to the .c file: |
155 | 151 | ||
156 | //config:config MU | 152 | //config:config MU |
157 | //config: bool "MU" | 153 | //config: bool "MU" |
158 | //config: default y | 154 | //config: default y |
159 | //config: help | 155 | //config: help |
160 | //config: Returns an indeterminate value. | 156 | //config: Returns an indeterminate value. |
157 | |||
158 | Add the kbuild snippet to the .c file: | ||
159 | |||
160 | //kbuild:lib-$(CONFIG_MU) += mu.o | ||
161 | 161 | ||
162 | 162 | ||
163 | Usage String(s) | 163 | Usage String(s) |
@@ -168,8 +168,9 @@ This should look like the following: | |||
168 | 168 | ||
169 | //usage:#define mu_trivial_usage | 169 | //usage:#define mu_trivial_usage |
170 | //usage: "[-abcde] FILE..." | 170 | //usage: "[-abcde] FILE..." |
171 | //usage:#define mu_full_usage | 171 | //usage:#define mu_full_usage "\n\n" |
172 | //usage: "Returns an indeterminate value\n" | 172 | //usage: "Returns an indeterminate value" |
173 | //usage: "\n" | ||
173 | //usage: "\n -a First function" | 174 | //usage: "\n -a First function" |
174 | //usage: "\n -b Second function" | 175 | //usage: "\n -b Second function" |
175 | //usage: ... | 176 | //usage: ... |
diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index a24dd9c27..9d210a1c9 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt | |||
@@ -10,13 +10,8 @@ of reimplemented Unix commands, and we can do the same trick | |||
10 | for speeding up busybox shells, and more. NOEXEC and NOFORK applets | 10 | for speeding up busybox shells, and more. NOEXEC and NOFORK applets |
11 | are exactly those applets which are eligible for these tricks. | 11 | are exactly those applets which are eligible for these tricks. |
12 | 12 | ||
13 | Applet will be subject to NOFORK/NOEXEC tricks if it is marked as such | 13 | Applet will be subject to NOFORK/NOEXEC tricks only if it is marked |
14 | in applets.h. FEATURE_PREFER_APPLETS is a config option which | 14 | as such in applets.src.h or in their inline "//applet:" directives. |
15 | globally enables usage of NOFORK/NOEXEC tricks. | ||
16 | If it is enabled, FEATURE_SH_STANDALONE can be enabled too, | ||
17 | and then shells will use NOFORK/NOEXEC tricks for ordinary commands. | ||
18 | NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE | ||
19 | or FEATURE_PREFER_APPLETS. | ||
20 | 15 | ||
21 | In C, if you want to call a program and wait for it, use | 16 | In C, if you want to call a program and wait for it, use |
22 | spawn_and_wait(argv), BB_EXECVP(prog,argv) or BB_EXECLP(prog,argv0,...). | 17 | spawn_and_wait(argv), BB_EXECVP(prog,argv) or BB_EXECLP(prog,argv0,...). |
@@ -24,6 +19,31 @@ They check whether program name is an applet name and optionally | |||
24 | do NOFORK/NOEXEC thing depending on configuration. | 19 | do NOFORK/NOEXEC thing depending on configuration. |
25 | 20 | ||
26 | 21 | ||
22 | Relevant CONFIG options | ||
23 | |||
24 | FEATURE_PREFER_APPLETS | ||
25 | Globally enables NOFORK/NOEXEC tricks for such programs as xargs | ||
26 | and find: | ||
27 | BB_EXECVP(cmd, argv) will try to exec /proc/self/exe | ||
28 | if command's name matches some applet name; | ||
29 | spawn_and_wait(argv) will do NOFORK/NOEXEC tricks | ||
30 | |||
31 | //TODO: the above two things probably should have separate options? | ||
32 | |||
33 | FEATURE_SH_STANDALONE | ||
34 | shells will try to exec /proc/self/exe if command's name matches | ||
35 | some applet name; shells will do NOEXEC trick on NOEXEC applets | ||
36 | |||
37 | //TODO: split (same as for PREFER_APPLETS) | ||
38 | |||
39 | FEATURE_SH_NOFORK | ||
40 | shells will do NOFORK trick on NOFORK applets | ||
41 | |||
42 | NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE, | ||
43 | FEATURE_PREFER_APPLETS or FEATURE_SH_NOFORK. In effect, builtins | ||
44 | are "always NOFORK". | ||
45 | |||
46 | |||
27 | NOEXEC | 47 | NOEXEC |
28 | 48 | ||
29 | NOEXEC applet should work correctly if another applet forks and then | 49 | NOEXEC applet should work correctly if another applet forks and then |
@@ -52,6 +72,9 @@ xargs, find, shells do it (grep for "spawn_and_wait" and | |||
52 | This poses much more serious limitations on what applet can do: | 72 | This poses much more serious limitations on what applet can do: |
53 | 73 | ||
54 | * all NOEXEC limitations apply. | 74 | * all NOEXEC limitations apply. |
75 | * do not run for a long time or wait for user input: | ||
76 | hush shell only handles signals (like ^C) after you return | ||
77 | from APPLET_main(). | ||
55 | * do not ever exit() or exec(). | 78 | * do not ever exit() or exec(). |
56 | - xfuncs are okay. They are using special trick to return | 79 | - xfuncs are okay. They are using special trick to return |
57 | to the caller applet instead of dying when they detect "x" condition. | 80 | to the caller applet instead of dying when they detect "x" condition. |
@@ -61,15 +84,27 @@ This poses much more serious limitations on what applet can do: | |||
61 | * do not use shared global data, or save/restore shared global data | 84 | * do not use shared global data, or save/restore shared global data |
62 | (e.g. bb_common_bufsiz1) prior to returning. | 85 | (e.g. bb_common_bufsiz1) prior to returning. |
63 | - getopt32() is ok to use. You do not need to save/restore option_mask32, | 86 | - getopt32() is ok to use. You do not need to save/restore option_mask32, |
64 | it is already done by core code. | 87 | xfunc_error_retval, and logmode - it is already done by core code. |
65 | * if you allocate memory, you can use xmalloc() only on the very first | 88 | * if you allocate memory, you can use xmalloc() only on the very first |
66 | allocation. All other allocations should use malloc[_or_warn](). | 89 | allocation. All other allocations should use malloc[_or_warn](). |
67 | After first allocation, you cannot use any xfuncs. | 90 | After first allocation, you cannot use any xfuncs. |
68 | Otherwise, failing xfunc will return to caller applet | 91 | Otherwise, failing xfunc will return to caller applet |
69 | without freeing malloced data! | 92 | without freeing malloced data! |
70 | * All allocated data, opened files, signal handlers, termios settings, | 93 | * the same applies to other resources, such as open fds: no xfuncs after |
71 | O_NONBLOCK flags etc should be freed/closed/restored prior to return. | 94 | acquiring them! |
72 | * ... | 95 | * All allocated data, opened files, signal handlers, termios settings |
96 | etc should be freed/closed/restored prior to return. | ||
97 | |||
98 | Currently, ash shell signal handling is implemented in a way that signals | ||
99 | have non-SA_RESTARTed handlers. This means that system calls can | ||
100 | return EINTR. An example of such problem is "yes" applet: | ||
101 | it is implemented so that it has a writing loop, this loop is exited on | ||
102 | any write error, and in the case of user pressing ^C the error was EINTR. | ||
103 | The problem is, the error causes stdout FILE* object to get into error | ||
104 | state, needing clearerr() - or else subsequent shell output will also | ||
105 | not work. ("yes" has been downgraded to NOEXEC, since hush signal handling | ||
106 | does not have this problem - which makes "yes" to not exit on ^C (bug). | ||
107 | But stray EINTRs can be seen in any NOFORK under ash, until ash is fixed). | ||
73 | 108 | ||
74 | NOFORK applets give the most of speed advantage, but are trickiest | 109 | NOFORK applets give the most of speed advantage, but are trickiest |
75 | to implement. In order to minimize amount of bugs and maintenance, | 110 | to implement. In order to minimize amount of bugs and maintenance, |
@@ -79,6 +114,8 @@ frequently executed from shell/find/xargs, particularly in shell | |||
79 | script loops. Applets which mess with signal handlers, termios etc | 114 | script loops. Applets which mess with signal handlers, termios etc |
80 | are probably not worth the effort. | 115 | are probably not worth the effort. |
81 | 116 | ||
117 | Applets which must be interruptible by ^C in shells can not be NOFORKs. | ||
118 | |||
82 | Any NOFORK applet is also a NOEXEC applet. | 119 | Any NOFORK applet is also a NOEXEC applet. |
83 | 120 | ||
84 | 121 | ||
@@ -91,11 +128,11 @@ API to call NOFORK applets is two functions: | |||
91 | 128 | ||
92 | First one is directly used by shells if FEATURE_SH_NOFORK=y. | 129 | First one is directly used by shells if FEATURE_SH_NOFORK=y. |
93 | Second one is used by many applets, but main users are xargs and find. | 130 | Second one is used by many applets, but main users are xargs and find. |
94 | It itself calls run_nofork_applet(), if argv[0] turned out to be a name | 131 | It itself calls run_nofork_applet(), if argv[0] is a name |
95 | of a NOFORK applet. | 132 | of a NOFORK applet. |
96 | 133 | ||
97 | run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval, | 134 | run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval, |
98 | applet_name. Thus, for example, caller does not need to worry about | 135 | logmode, applet_name. Thus, for example, caller does not need to worry about |
99 | option_mask32 getting trashed. | 136 | option_mask32 getting trashed. |
100 | 137 | ||
101 | 138 | ||
@@ -104,22 +141,3 @@ option_mask32 getting trashed. | |||
104 | It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y, | 141 | It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y, |
105 | it does NOEXEC trick. It resets xfunc_error_retval = 1 and | 142 | it does NOEXEC trick. It resets xfunc_error_retval = 1 and |
106 | logmode = LOGMODE_STDIO in the child. | 143 | logmode = LOGMODE_STDIO in the child. |
107 | |||
108 | |||
109 | Relevant CONFIG options | ||
110 | |||
111 | FEATURE_PREFER_APPLETS | ||
112 | BB_EXECVP(cmd, argv) will try to exec /proc/self/exe | ||
113 | if command's name matches some applet name; | ||
114 | spawn_and_wait(argv) will do NOFORK/NOEXEC tricks | ||
115 | |||
116 | //TODO: the above two things probably should have separate options? | ||
117 | |||
118 | FEATURE_SH_STANDALONE | ||
119 | shells will try to exec /proc/self/exe if command's name matches | ||
120 | some applet name; shells will do NOEXEC trick on NOEXEC applets | ||
121 | |||
122 | //TODO: split (same as for PREFER_APPLETS) | ||
123 | |||
124 | FEATURE_SH_NOFORK | ||
125 | shells will do NOFORK trick on NOFORK applets | ||
diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c index 72327d728..76a5253b6 100644 --- a/e2fsprogs/chattr.c +++ b/e2fsprogs/chattr.c | |||
@@ -15,14 +15,17 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: chattr changes the file attributes on a second extended file system. | 16 | //config: chattr changes the file attributes on a second extended file system. |
17 | 17 | ||
18 | //applet:IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_CHATTR(APPLET_NOEXEC(chattr, chattr, BB_DIR_BIN, BB_SUID_DROP, chattr)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o | 20 | //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o |
21 | 21 | ||
22 | //usage:#define chattr_trivial_usage | 22 | //usage:#define chattr_trivial_usage |
23 | //usage: "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..." | 23 | //usage: "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..." |
24 | //usage:#define chattr_full_usage "\n\n" | 24 | //usage:#define chattr_full_usage "\n\n" |
25 | //usage: "Change ext2 file attributes\n" | 25 | //usage: "Change ext2 file attributes\n" |
26 | //usage: "\n -R Recurse" | ||
27 | //usage: "\n -v VER Set version/generation number" | ||
28 | //-V, -f accepted but ignored | ||
26 | //usage: "\nModifiers:" | 29 | //usage: "\nModifiers:" |
27 | //usage: "\n -,+,= Remove/add/set attributes" | 30 | //usage: "\n -,+,= Remove/add/set attributes" |
28 | //usage: "\nAttributes:" | 31 | //usage: "\nAttributes:" |
@@ -37,8 +40,6 @@ | |||
37 | //usage: "\n S Write synchronously" | 40 | //usage: "\n S Write synchronously" |
38 | //usage: "\n t Disable tail-merging of partial blocks with other files" | 41 | //usage: "\n t Disable tail-merging of partial blocks with other files" |
39 | //usage: "\n u Allow file to be undeleted" | 42 | //usage: "\n u Allow file to be undeleted" |
40 | //usage: "\n -R Recurse" | ||
41 | //usage: "\n -v VER Set version/generation number" | ||
42 | 43 | ||
43 | #include "libbb.h" | 44 | #include "libbb.h" |
44 | #include "e2fs_lib.h" | 45 | #include "e2fs_lib.h" |
@@ -52,7 +53,7 @@ struct globals { | |||
52 | unsigned long version; | 53 | unsigned long version; |
53 | unsigned long af; | 54 | unsigned long af; |
54 | unsigned long rf; | 55 | unsigned long rf; |
55 | smallint flags; | 56 | int flags; |
56 | smallint recursive; | 57 | smallint recursive; |
57 | }; | 58 | }; |
58 | 59 | ||
@@ -64,10 +65,11 @@ static unsigned long get_flag(char c) | |||
64 | bb_show_usage(); | 65 | bb_show_usage(); |
65 | } | 66 | } |
66 | 67 | ||
67 | static int decode_arg(const char *arg, struct globals *gp) | 68 | static char** decode_arg(char **argv, struct globals *gp) |
68 | { | 69 | { |
69 | unsigned long *fl; | 70 | unsigned long *fl; |
70 | char opt = *arg++; | 71 | const char *arg = *argv; |
72 | char opt = *arg; | ||
71 | 73 | ||
72 | fl = &gp->af; | 74 | fl = &gp->af; |
73 | if (opt == '-') { | 75 | if (opt == '-') { |
@@ -75,15 +77,43 @@ static int decode_arg(const char *arg, struct globals *gp) | |||
75 | fl = &gp->rf; | 77 | fl = &gp->rf; |
76 | } else if (opt == '+') { | 78 | } else if (opt == '+') { |
77 | gp->flags |= OPT_ADD; | 79 | gp->flags |= OPT_ADD; |
78 | } else if (opt == '=') { | 80 | } else { /* if (opt == '=') */ |
79 | gp->flags |= OPT_SET; | 81 | gp->flags |= OPT_SET; |
80 | } else | 82 | } |
81 | return 0; | ||
82 | 83 | ||
83 | while (*arg) | 84 | while (*++arg) { |
84 | *fl |= get_flag(*arg++); | 85 | if (opt == '-') { |
86 | //e2fsprogs-1.43.1 accepts: | ||
87 | // "-RRR", "-RRRv VER" and even "-ARRRva VER" and "-vvv V1 V2 V3" | ||
88 | // but not "-vVER". | ||
89 | // IOW: options are parsed as part of "remove attrs" strings, | ||
90 | // if "v" is seen, next argv[] is VER, even if more opts/attrs follow in this argv[]! | ||
91 | if (*arg == 'R') { | ||
92 | gp->recursive = 1; | ||
93 | continue; | ||
94 | } | ||
95 | if (*arg == 'V') { | ||
96 | /*"verbose and print program version" (nop for now) */; | ||
97 | continue; | ||
98 | } | ||
99 | if (*arg == 'f') { | ||
100 | /*"suppress most error messages" (nop) */; | ||
101 | continue; | ||
102 | } | ||
103 | if (*arg == 'v') { | ||
104 | if (!*++argv) | ||
105 | bb_show_usage(); | ||
106 | gp->version = xatoul(*argv); | ||
107 | gp->flags |= OPT_SET_VER; | ||
108 | continue; | ||
109 | } | ||
110 | //TODO: "-p PROJECT_NUM" ? | ||
111 | /* not a known option, try as an attribute */ | ||
112 | } | ||
113 | *fl |= get_flag(*arg); | ||
114 | } | ||
85 | 115 | ||
86 | return 1; | 116 | return argv; |
87 | } | 117 | } |
88 | 118 | ||
89 | static void change_attributes(const char *name, struct globals *gp); | 119 | static void change_attributes(const char *name, struct globals *gp); |
@@ -133,7 +163,7 @@ static void change_attributes(const char *name, struct globals *gp) | |||
133 | fsflags &= ~gp->rf; | 163 | fsflags &= ~gp->rf; |
134 | /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ | 164 | /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ |
135 | fsflags |= gp->af; | 165 | fsflags |= gp->af; |
136 | /* What is this? And why it's not done for SET case? */ | 166 | // What is this? And why it's not done for SET case? |
137 | if (!S_ISDIR(st.st_mode)) | 167 | if (!S_ISDIR(st.st_mode)) |
138 | fsflags &= ~EXT2_DIRSYNC_FL; | 168 | fsflags &= ~EXT2_DIRSYNC_FL; |
139 | } | 169 | } |
@@ -149,36 +179,22 @@ int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
149 | int chattr_main(int argc UNUSED_PARAM, char **argv) | 179 | int chattr_main(int argc UNUSED_PARAM, char **argv) |
150 | { | 180 | { |
151 | struct globals g; | 181 | struct globals g; |
152 | char *arg; | ||
153 | 182 | ||
154 | memset(&g, 0, sizeof(g)); | 183 | memset(&g, 0, sizeof(g)); |
155 | 184 | ||
156 | /* parse the args */ | 185 | /* parse the args */ |
157 | while ((arg = *++argv)) { | 186 | for (;;) { |
158 | /* take care of -R and -v <version> */ | 187 | char *arg = *++argv; |
159 | if (arg[0] == '-' | 188 | if (!arg) |
160 | && (arg[1] == 'R' || arg[1] == 'v') | 189 | bb_show_usage(); |
161 | && !arg[2] | 190 | if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=') |
162 | ) { | ||
163 | if (arg[1] == 'R') { | ||
164 | g.recursive = 1; | ||
165 | continue; | ||
166 | } | ||
167 | /* arg[1] == 'v' */ | ||
168 | if (!*++argv) | ||
169 | bb_show_usage(); | ||
170 | g.version = xatoul(*argv); | ||
171 | g.flags |= OPT_SET_VER; | ||
172 | continue; | ||
173 | } | ||
174 | |||
175 | if (!decode_arg(arg, &g)) | ||
176 | break; | 191 | break; |
192 | |||
193 | argv = decode_arg(argv, &g); | ||
177 | } | 194 | } |
195 | /* note: on loop exit, remaining argv[] is never empty */ | ||
178 | 196 | ||
179 | /* run sanity checks on all the arguments given us */ | 197 | /* run sanity checks on all the arguments given us */ |
180 | if (!*argv) | ||
181 | bb_show_usage(); | ||
182 | if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) | 198 | if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) |
183 | bb_error_msg_and_die("= is incompatible with - and +"); | 199 | bb_error_msg_and_die("= is incompatible with - and +"); |
184 | if (g.rf & g.af) | 200 | if (g.rf & g.af) |
diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h index f2ae56f43..ae28c353b 100644 --- a/e2fsprogs/e2fs_lib.h +++ b/e2fsprogs/e2fs_lib.h | |||
@@ -26,7 +26,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f | |||
26 | #define fgetflags(name, flags) fgetsetflags(name, flags, 0) | 26 | #define fgetflags(name, flags) fgetsetflags(name, flags, 0) |
27 | #define fsetflags(name, flags) fgetsetflags(name, NULL, flags) | 27 | #define fsetflags(name, flags) fgetsetflags(name, NULL, flags) |
28 | 28 | ||
29 | /* Must be 1 for compatibility with `int long_format'. */ | 29 | /* Must be 1 for compatibility with 'int long_format'. */ |
30 | #define PFOPT_LONG 1 | 30 | #define PFOPT_LONG 1 |
31 | /* Print file attributes on an ext2 file system */ | 31 | /* Print file attributes on an ext2 file system */ |
32 | void print_e2flags(FILE *f, unsigned long flags, unsigned options); | 32 | void print_e2flags(FILE *f, unsigned long flags, unsigned options); |
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index 756d26832..56c1187c1 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c | |||
@@ -16,7 +16,8 @@ | |||
16 | //config: help | 16 | //config: help |
17 | //config: lsattr lists the file attributes on a second extended file system. | 17 | //config: lsattr lists the file attributes on a second extended file system. |
18 | 18 | ||
19 | //applet:IF_LSATTR(APPLET(lsattr, BB_DIR_BIN, BB_SUID_DROP)) | 19 | //applet:IF_LSATTR(APPLET_NOEXEC(lsattr, lsattr, BB_DIR_BIN, BB_SUID_DROP, lsattr)) |
20 | /* ls is NOEXEC, so we should be too! ;) */ | ||
20 | 21 | ||
21 | //kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o | 22 | //kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o |
22 | 23 | ||
diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c index 95411db5f..a1caf011c 100644 --- a/e2fsprogs/tune2fs.c +++ b/e2fsprogs/tune2fs.c | |||
@@ -13,7 +13,7 @@ | |||
13 | //config: tune2fs allows the system administrator to adjust various tunable | 13 | //config: tune2fs allows the system administrator to adjust various tunable |
14 | //config: filesystem parameters on Linux ext2/ext3 filesystems. | 14 | //config: filesystem parameters on Linux ext2/ext3 filesystems. |
15 | 15 | ||
16 | //applet:IF_TUNE2FS(APPLET(tune2fs, BB_DIR_SBIN, BB_SUID_DROP)) | 16 | //applet:IF_TUNE2FS(APPLET_NOEXEC(tune2fs, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, tune2fs)) |
17 | 17 | ||
18 | //TODO alias to "tune2fs -L LABEL": //applet:IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) | 18 | //TODO alias to "tune2fs -L LABEL": //applet:IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) |
19 | 19 | ||
@@ -71,8 +71,7 @@ int tune2fs_main(int argc UNUSED_PARAM, char **argv) | |||
71 | struct ext2_super_block *sb; | 71 | struct ext2_super_block *sb; |
72 | int fd; | 72 | int fd; |
73 | 73 | ||
74 | opt_complementary = "=1"; | 74 | opts = getopt32(argv, "^" "L:c:i:C:" "\0" "=1", &label, &str_c, &str_i, &str_C); |
75 | opts = getopt32(argv, "L:c:i:C:", &label, &str_c, &str_i, &str_C); | ||
76 | if (!opts) | 75 | if (!opts) |
77 | bb_show_usage(); | 76 | bb_show_usage(); |
78 | argv += optind; // argv[0] -- device | 77 | argv += optind; // argv[0] -- device |
diff --git a/editors/awk.c b/editors/awk.c index 56688d72c..2fc7d6102 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -70,7 +70,11 @@ | |||
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | 72 | ||
73 | #define OPTSTR_AWK \ | 73 | /* "+": stop on first non-option: |
74 | * $ awk 'BEGIN { for(i=1; i<ARGC; ++i) { print i ": " ARGV[i] }}' -argz | ||
75 | * 1: -argz | ||
76 | */ | ||
77 | #define OPTSTR_AWK "+" \ | ||
74 | "F:v:*f:*" \ | 78 | "F:v:*f:*" \ |
75 | IF_FEATURE_AWK_GNU_EXTENSIONS("e:*") \ | 79 | IF_FEATURE_AWK_GNU_EXTENSIONS("e:*") \ |
76 | "W:" | 80 | "W:" |
@@ -230,7 +234,7 @@ typedef struct tsplitter_s { | |||
230 | */ | 234 | */ |
231 | #define TC_LENGTH (1 << 20) | 235 | #define TC_LENGTH (1 << 20) |
232 | #define TC_GETLINE (1 << 21) | 236 | #define TC_GETLINE (1 << 21) |
233 | #define TC_FUNCDECL (1 << 22) /* `function' `func' */ | 237 | #define TC_FUNCDECL (1 << 22) /* 'function' 'func' */ |
234 | #define TC_BEGIN (1 << 23) | 238 | #define TC_BEGIN (1 << 23) |
235 | #define TC_END (1 << 24) | 239 | #define TC_END (1 << 24) |
236 | #define TC_EOF (1 << 25) | 240 | #define TC_EOF (1 << 25) |
diff --git a/editors/cmp.c b/editors/cmp.c index f53d9603c..ec86c0ce2 100644 --- a/editors/cmp.c +++ b/editors/cmp.c | |||
@@ -36,7 +36,7 @@ static const char fmt_differ[] ALIGN1 = "%s %s differ: char %"OFF_FMT"u, line %u | |||
36 | // This fmt_l_opt uses gnu-isms. SUSv3 would be "%.0s%.0s%"OFF_FMT"u %o %o\n" | 36 | // This fmt_l_opt uses gnu-isms. SUSv3 would be "%.0s%.0s%"OFF_FMT"u %o %o\n" |
37 | static const char fmt_l_opt[] ALIGN1 = "%.0s%.0s%"OFF_FMT"u %3o %3o\n"; | 37 | static const char fmt_l_opt[] ALIGN1 = "%.0s%.0s%"OFF_FMT"u %3o %3o\n"; |
38 | 38 | ||
39 | static const char opt_chars[] ALIGN1 = "sl"; | 39 | #define OPT_STR "sl" |
40 | #define CMP_OPT_s (1<<0) | 40 | #define CMP_OPT_s (1<<0) |
41 | #define CMP_OPT_l (1<<1) | 41 | #define CMP_OPT_l (1<<1) |
42 | 42 | ||
@@ -52,11 +52,13 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) | |||
52 | unsigned opt; | 52 | unsigned opt; |
53 | int retval = 0; | 53 | int retval = 0; |
54 | 54 | ||
55 | opt_complementary = "-1" | 55 | opt = getopt32(argv, "^" |
56 | OPT_STR | ||
57 | "\0" "-1" | ||
56 | IF_DESKTOP(":?4") | 58 | IF_DESKTOP(":?4") |
57 | IF_NOT_DESKTOP(":?2") | 59 | IF_NOT_DESKTOP(":?2") |
58 | ":l--s:s--l"; | 60 | ":l--s:s--l" |
59 | opt = getopt32(argv, opt_chars); | 61 | ); |
60 | argv += optind; | 62 | argv += optind; |
61 | 63 | ||
62 | filename1 = *argv; | 64 | filename1 = *argv; |
diff --git a/editors/diff.c b/editors/diff.c index 62f558944..1ff399ffb 100644 --- a/editors/diff.c +++ b/editors/diff.c | |||
@@ -988,6 +988,11 @@ static const char diff_longopts[] ALIGN1 = | |||
988 | "starting-file\0" Required_argument "S" | 988 | "starting-file\0" Required_argument "S" |
989 | "minimal\0" No_argument "d" | 989 | "minimal\0" No_argument "d" |
990 | ; | 990 | ; |
991 | # define GETOPT32 getopt32long | ||
992 | # define LONGOPTS ,diff_longopts | ||
993 | #else | ||
994 | # define GETOPT32 getopt32 | ||
995 | # define LONGOPTS | ||
991 | #endif | 996 | #endif |
992 | 997 | ||
993 | int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 998 | int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -1000,11 +1005,8 @@ int diff_main(int argc UNUSED_PARAM, char **argv) | |||
1000 | INIT_G(); | 1005 | INIT_G(); |
1001 | 1006 | ||
1002 | /* exactly 2 params; collect multiple -L <label>; -U N */ | 1007 | /* exactly 2 params; collect multiple -L <label>; -U N */ |
1003 | opt_complementary = "=2"; | 1008 | GETOPT32(argv, "^" "abdiL:*NqrsS:tTU:+wupBE" "\0" "=2" |
1004 | #if ENABLE_FEATURE_DIFF_LONG_OPTIONS | 1009 | LONGOPTS, |
1005 | applet_long_options = diff_longopts; | ||
1006 | #endif | ||
1007 | getopt32(argv, "abdiL:*NqrsS:tTU:+wupBE", | ||
1008 | &L_arg, &s_start, &opt_U_context); | 1010 | &L_arg, &s_start, &opt_U_context); |
1009 | argv += optind; | 1011 | argv += optind; |
1010 | while (L_arg) | 1012 | while (L_arg) |
diff --git a/editors/ed.c b/editors/ed.c index 7f21ded92..05797692c 100644 --- a/editors/ed.c +++ b/editors/ed.c | |||
@@ -360,7 +360,7 @@ static void addLines(int num) | |||
360 | * 0 on ctrl-C, | 360 | * 0 on ctrl-C, |
361 | * >0 length of input string, including terminating '\n' | 361 | * >0 length of input string, including terminating '\n' |
362 | */ | 362 | */ |
363 | len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); | 363 | len = read_line_input(NULL, "", buf, sizeof(buf)); |
364 | if (len <= 0) { | 364 | if (len <= 0) { |
365 | /* Previously, ctrl-C was exiting to shell. | 365 | /* Previously, ctrl-C was exiting to shell. |
366 | * Now we exit to ed prompt. Is in important? */ | 366 | * Now we exit to ed prompt. Is in important? */ |
@@ -789,7 +789,7 @@ static void doCommands(void) | |||
789 | * 0 on ctrl-C, | 789 | * 0 on ctrl-C, |
790 | * >0 length of input string, including terminating '\n' | 790 | * >0 length of input string, including terminating '\n' |
791 | */ | 791 | */ |
792 | len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); | 792 | len = read_line_input(NULL, ": ", buf, sizeof(buf)); |
793 | if (len <= 0) | 793 | if (len <= 0) |
794 | return; | 794 | return; |
795 | while (len && isspace(buf[--len])) | 795 | while (len && isspace(buf[--len])) |
@@ -892,7 +892,7 @@ static void doCommands(void) | |||
892 | } | 892 | } |
893 | if (!dirty) | 893 | if (!dirty) |
894 | return; | 894 | return; |
895 | len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); | 895 | len = read_line_input(NULL, "Really quit? ", buf, 16); |
896 | /* read error/EOF - no way to continue */ | 896 | /* read error/EOF - no way to continue */ |
897 | if (len < 0) | 897 | if (len < 0) |
898 | return; | 898 | return; |
diff --git a/editors/patch_bbox.c b/editors/patch_bbox.c index aae7b7987..8e09ef488 100644 --- a/editors/patch_bbox.c +++ b/editors/patch_bbox.c | |||
@@ -111,10 +111,9 @@ int patch_main(int argc UNUSED_PARAM, char **argv) | |||
111 | "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ | 111 | "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ |
112 | # endif | 112 | # endif |
113 | ; | 113 | ; |
114 | applet_long_options = patch_longopts; | ||
115 | #endif | 114 | #endif |
116 | /* -f,-E,-g are ignored */ | 115 | /* -f,-E,-g are ignored */ |
117 | opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL); | 116 | opt = getopt32long(argv, "p:i:RN""fEg:", patch_longopts, &p, &i, NULL); |
118 | if (opt & OPT_R) | 117 | if (opt & OPT_R) |
119 | plus = '-'; | 118 | plus = '-'; |
120 | patch_level = xatoi(p); /* can be negative! */ | 119 | patch_level = xatoi(p); /* can be negative! */ |
diff --git a/editors/sed.c b/editors/sed.c index e10078b7c..d6e25aedc 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -68,8 +68,8 @@ | |||
68 | //applet:IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP)) | 68 | //applet:IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP)) |
69 | 69 | ||
70 | //usage:#define sed_trivial_usage | 70 | //usage:#define sed_trivial_usage |
71 | //usage: "[-inrE] [-f FILE]... [-e CMD]... [FILE]...\n" | 71 | //usage: "[-i[SFX]] [-nrE] [-f FILE]... [-e CMD]... [FILE]...\n" |
72 | //usage: "or: sed [-inrE] CMD [FILE]..." | 72 | //usage: "or: sed [-i[SFX]] [-nrE] CMD [FILE]..." |
73 | //usage:#define sed_full_usage "\n\n" | 73 | //usage:#define sed_full_usage "\n\n" |
74 | //usage: " -e CMD Add CMD to sed commands to be executed" | 74 | //usage: " -e CMD Add CMD to sed commands to be executed" |
75 | //usage: "\n -f FILE Add FILE contents to sed commands to be executed" | 75 | //usage: "\n -f FILE Add FILE contents to sed commands to be executed" |
@@ -1512,21 +1512,21 @@ int sed_main(int argc UNUSED_PARAM, char **argv) | |||
1512 | /* do normal option parsing */ | 1512 | /* do normal option parsing */ |
1513 | opt_e = opt_f = NULL; | 1513 | opt_e = opt_f = NULL; |
1514 | opt_i = NULL; | 1514 | opt_i = NULL; |
1515 | opt_complementary = "nn"; /* count -n */ | ||
1516 | |||
1517 | IF_LONG_OPTS(applet_long_options = sed_longopts); | ||
1518 | |||
1519 | /* -i must be first, to match OPT_in_place definition */ | 1515 | /* -i must be first, to match OPT_in_place definition */ |
1520 | /* -E is a synonym of -r: | 1516 | /* -E is a synonym of -r: |
1521 | * GNU sed 4.2.1 mentions it in neither --help | 1517 | * GNU sed 4.2.1 mentions it in neither --help |
1522 | * nor manpage, but does recognize it. | 1518 | * nor manpage, but does recognize it. |
1523 | */ | 1519 | */ |
1524 | opt = getopt32(argv, "i::rEne:*f:*", &opt_i, &opt_e, &opt_f, | 1520 | opt = getopt32long(argv, "^" |
1525 | &G.be_quiet); /* counter for -n */ | 1521 | "i::rEne:*f:*" |
1522 | "\0" "nn"/*count -n*/, | ||
1523 | sed_longopts, | ||
1524 | &opt_i, &opt_e, &opt_f, | ||
1525 | &G.be_quiet); /* counter for -n */ | ||
1526 | //argc -= optind; | 1526 | //argc -= optind; |
1527 | argv += optind; | 1527 | argv += optind; |
1528 | if (opt & OPT_in_place) { // -i | 1528 | if (opt & OPT_in_place) { // -i |
1529 | atexit(cleanup_outname); | 1529 | die_func = cleanup_outname; |
1530 | } | 1530 | } |
1531 | if (opt & (2|4)) | 1531 | if (opt & (2|4)) |
1532 | G.regex_type |= REG_EXTENDED; // -r or -E | 1532 | G.regex_type |= REG_EXTENDED; // -r or -E |
diff --git a/findutils/find.c b/findutils/find.c index 69baf065d..5857a3f44 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * # find file.txt -exec 'echo {}' '{} {}' ';' | 15 | * # find file.txt -exec 'echo {}' '{} {}' ';' |
16 | * find: echo file.txt: No such file or directory | 16 | * find: echo file.txt: No such file or directory |
17 | * # find file.txt -exec 'echo' '{} {}' '; ' | 17 | * # find file.txt -exec 'echo' '{} {}' '; ' |
18 | * find: missing argument to `-exec' | 18 | * find: missing argument to '-exec' |
19 | * # find file.txt -exec 'echo {}' '{} {}' ';' junk | 19 | * # find file.txt -exec 'echo {}' '{} {}' ';' junk |
20 | * find: paths must precede expression | 20 | * find: paths must precede expression |
21 | * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';' | 21 | * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';' |
diff --git a/findutils/grep.c b/findutils/grep.c index 568ab12c2..7c5f73d2f 100644 --- a/findutils/grep.c +++ b/findutils/grep.c | |||
@@ -107,6 +107,7 @@ | |||
107 | //usage:#define fgrep_trivial_usage NOUSAGE_STR | 107 | //usage:#define fgrep_trivial_usage NOUSAGE_STR |
108 | //usage:#define fgrep_full_usage "" | 108 | //usage:#define fgrep_full_usage "" |
109 | 109 | ||
110 | /* -e,-f are lists; -m,-A,-B,-C have numeric param */ | ||
110 | #define OPTSTR_GREP \ | 111 | #define OPTSTR_GREP \ |
111 | "lnqvscFiHhe:*f:*Lorm:+wx" \ | 112 | "lnqvscFiHhe:*f:*Lorm:+wx" \ |
112 | IF_FEATURE_GREP_CONTEXT("A:+B:+C:+") \ | 113 | IF_FEATURE_GREP_CONTEXT("A:+B:+C:+") \ |
@@ -686,11 +687,9 @@ int grep_main(int argc UNUSED_PARAM, char **argv) | |||
686 | 687 | ||
687 | /* do normal option parsing */ | 688 | /* do normal option parsing */ |
688 | #if ENABLE_FEATURE_GREP_CONTEXT | 689 | #if ENABLE_FEATURE_GREP_CONTEXT |
689 | /* -H unsets -h; -C unsets -A,-B; -e,-f are lists; | 690 | /* -H unsets -h; -C unsets -A,-B */ |
690 | * -m,-A,-B,-C have numeric param */ | ||
691 | opt_complementary = "H-h:C-AB"; | ||
692 | opts = getopt32(argv, | 691 | opts = getopt32(argv, |
693 | OPTSTR_GREP, | 692 | "^" OPTSTR_GREP "\0" "H-h:C-AB", |
694 | &pattern_head, &fopt, &max_matches, | 693 | &pattern_head, &fopt, &max_matches, |
695 | &lines_after, &lines_before, &Copt); | 694 | &lines_after, &lines_before, &Copt); |
696 | 695 | ||
@@ -716,9 +715,7 @@ int grep_main(int argc UNUSED_PARAM, char **argv) | |||
716 | } | 715 | } |
717 | #else | 716 | #else |
718 | /* with auto sanity checks */ | 717 | /* with auto sanity checks */ |
719 | /* -H unsets -h; -c,-q or -l unset -n; -e,-f are lists; -m N */ | 718 | getopt32(argv, "^" OPTSTR_GREP "\0" "H-h:c-n:q-n:l-n:", // why trailing ":"? |
720 | opt_complementary = "H-h:c-n:q-n:l-n:"; | ||
721 | getopt32(argv, OPTSTR_GREP, | ||
722 | &pattern_head, &fopt, &max_matches); | 719 | &pattern_head, &fopt, &max_matches); |
723 | #endif | 720 | #endif |
724 | invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ | 721 | invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ |
diff --git a/findutils/xargs.c b/findutils/xargs.c index e5384d14c..97afef039 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -508,13 +508,8 @@ int xargs_main(int argc, char **argv) | |||
508 | 508 | ||
509 | INIT_G(); | 509 | INIT_G(); |
510 | 510 | ||
511 | #if ENABLE_DESKTOP && ENABLE_LONG_OPTS | 511 | opt = getopt32long(argv, OPTION_STR, |
512 | /* For example, Fedora's build system uses --no-run-if-empty */ | 512 | "no-run-if-empty\0" No_argument "r", |
513 | applet_long_options = | ||
514 | "no-run-if-empty\0" No_argument "r" | ||
515 | ; | ||
516 | #endif | ||
517 | opt = getopt32(argv, OPTION_STR, | ||
518 | &max_args, &max_chars, &G.eof_str, &G.eof_str | 513 | &max_args, &max_chars, &G.eof_str, &G.eof_str |
519 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(, &G.repl_str, &G.repl_str) | 514 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(, &G.repl_str, &G.repl_str) |
520 | ); | 515 | ); |
diff --git a/include/bb_archive.h b/include/bb_archive.h index c118fa7ec..acb3c3cbd 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h | |||
@@ -74,9 +74,6 @@ typedef struct archive_handle_t { | |||
74 | /* Currently processed file's header */ | 74 | /* Currently processed file's header */ |
75 | file_header_t *file_header; | 75 | file_header_t *file_header; |
76 | 76 | ||
77 | /* List of symlink placeholders */ | ||
78 | llist_t *symlink_placeholders; | ||
79 | |||
80 | /* Process the header component, e.g. tar -t */ | 77 | /* Process the header component, e.g. tar -t */ |
81 | void FAST_FUNC (*action_header)(const file_header_t *); | 78 | void FAST_FUNC (*action_header)(const file_header_t *); |
82 | 79 | ||
@@ -210,6 +207,7 @@ void seek_by_jump(int fd, off_t amount) FAST_FUNC; | |||
210 | void seek_by_read(int fd, off_t amount) FAST_FUNC; | 207 | void seek_by_read(int fd, off_t amount) FAST_FUNC; |
211 | 208 | ||
212 | const char *strip_unsafe_prefix(const char *str) FAST_FUNC; | 209 | const char *strip_unsafe_prefix(const char *str) FAST_FUNC; |
210 | int unsafe_symlink_target(const char *target) FAST_FUNC; | ||
213 | 211 | ||
214 | void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; | 212 | void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; |
215 | const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; | 213 | const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; |
diff --git a/include/libbb.h b/include/libbb.h index 61ceb6085..6073cbf4a 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -365,7 +365,7 @@ unsigned long long monotonic_ms(void) FAST_FUNC; | |||
365 | unsigned monotonic_sec(void) FAST_FUNC; | 365 | unsigned monotonic_sec(void) FAST_FUNC; |
366 | 366 | ||
367 | extern void chomp(char *s) FAST_FUNC; | 367 | extern void chomp(char *s) FAST_FUNC; |
368 | extern void trim(char *s) FAST_FUNC; | 368 | extern char *trim(char *s) FAST_FUNC; |
369 | extern char *skip_whitespace(const char *) FAST_FUNC; | 369 | extern char *skip_whitespace(const char *) FAST_FUNC; |
370 | extern char *skip_non_whitespace(const char *) FAST_FUNC; | 370 | extern char *skip_non_whitespace(const char *) FAST_FUNC; |
371 | extern char *skip_dev_pfx(const char *tty_name) FAST_FUNC; | 371 | extern char *skip_dev_pfx(const char *tty_name) FAST_FUNC; |
@@ -886,7 +886,7 @@ unsigned bb_clk_tck(void) FAST_FUNC; | |||
886 | 886 | ||
887 | #if SEAMLESS_COMPRESSION | 887 | #if SEAMLESS_COMPRESSION |
888 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ | 888 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ |
889 | extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; | 889 | int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; |
890 | /* Autodetects .gz etc */ | 890 | /* Autodetects .gz etc */ |
891 | extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; | 891 | extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; |
892 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 892 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; |
@@ -895,6 +895,8 @@ extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) | |||
895 | # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); | 895 | # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); |
896 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) | 896 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) |
897 | #endif | 897 | #endif |
898 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ | ||
899 | void setup_lzma_on_fd(int fd) FAST_FUNC; | ||
898 | 900 | ||
899 | extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; | 901 | extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; |
900 | // NB: will return short write on error, not -1, | 902 | // NB: will return short write on error, not -1, |
@@ -1138,9 +1140,15 @@ int wait_for_exitstatus(pid_t pid) FAST_FUNC; | |||
1138 | int spawn_and_wait(char **argv) FAST_FUNC; | 1140 | int spawn_and_wait(char **argv) FAST_FUNC; |
1139 | /* Does NOT check that applet is NOFORK, just blindly runs it */ | 1141 | /* Does NOT check that applet is NOFORK, just blindly runs it */ |
1140 | int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; | 1142 | int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; |
1143 | void run_noexec_applet_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; | ||
1141 | #ifndef BUILD_INDIVIDUAL | 1144 | #ifndef BUILD_INDIVIDUAL |
1142 | extern int find_applet_by_name(const char *name) FAST_FUNC; | 1145 | int find_applet_by_name(const char *name) FAST_FUNC; |
1143 | extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; | 1146 | void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; |
1147 | #endif | ||
1148 | #if defined(__linux__) | ||
1149 | void set_task_comm(const char *comm) FAST_FUNC; | ||
1150 | #else | ||
1151 | # define set_task_comm(name) ((void)0) | ||
1144 | #endif | 1152 | #endif |
1145 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_NOFORK | 1153 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_NOFORK |
1146 | extern int long_running_applet(int applet_no) FAST_FUNC; | 1154 | extern int long_running_applet(int applet_no) FAST_FUNC; |
@@ -1198,21 +1206,26 @@ enum { | |||
1198 | #endif | 1206 | #endif |
1199 | void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC; | 1207 | void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC; |
1200 | void bb_sanitize_stdio(void) FAST_FUNC; | 1208 | void bb_sanitize_stdio(void) FAST_FUNC; |
1209 | #define bb_daemon_helper(arg) bb_daemonize_or_rexec((arg) | DAEMON_ONLY_SANITIZE, NULL) | ||
1201 | /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */ | 1210 | /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */ |
1202 | int sanitize_env_if_suid(void) FAST_FUNC; | 1211 | int sanitize_env_if_suid(void) FAST_FUNC; |
1203 | 1212 | ||
1204 | 1213 | ||
1214 | /* For top, ps. Some argv[i] are replaced by malloced "-opt" strings */ | ||
1215 | void make_all_argv_opts(char **argv) FAST_FUNC; | ||
1205 | char* single_argv(char **argv) FAST_FUNC; | 1216 | char* single_argv(char **argv) FAST_FUNC; |
1206 | extern const char *const bb_argv_dash[]; /* "-", NULL */ | 1217 | extern const char *const bb_argv_dash[]; /* { "-", NULL } */ |
1207 | extern const char *opt_complementary; | ||
1208 | #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG | ||
1209 | #define No_argument "\0" | ||
1210 | #define Required_argument "\001" | ||
1211 | #define Optional_argument "\002" | ||
1212 | extern const char *applet_long_options; | ||
1213 | #endif | ||
1214 | extern uint32_t option_mask32; | 1218 | extern uint32_t option_mask32; |
1215 | extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; | 1219 | uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; |
1220 | # define No_argument "\0" | ||
1221 | # define Required_argument "\001" | ||
1222 | # define Optional_argument "\002" | ||
1223 | #if ENABLE_LONG_OPTS | ||
1224 | uint32_t getopt32long(char **argv, const char *optstring, const char *longopts, ...) FAST_FUNC; | ||
1225 | #else | ||
1226 | #define getopt32long(argv,optstring,longopts,...) \ | ||
1227 | getopt32(argv,optstring,##__VA_ARGS__) | ||
1228 | #endif | ||
1216 | /* BSD-derived getopt() functions require that optind be set to 1 in | 1229 | /* BSD-derived getopt() functions require that optind be set to 1 in |
1217 | * order to reset getopt() state. This used to be generally accepted | 1230 | * order to reset getopt() state. This used to be generally accepted |
1218 | * way of resetting getopt(). However, glibc's getopt() | 1231 | * way of resetting getopt(). However, glibc's getopt() |
@@ -1429,6 +1442,11 @@ enum { | |||
1429 | // keep a copy of current line | 1442 | // keep a copy of current line |
1430 | PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, | 1443 | PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, |
1431 | PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char | 1444 | PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char |
1445 | PARSE_ALT_COMMENTS = 0x00800000, // delim[0] and delim[1] are two different allowed comment chars | ||
1446 | // (so far, delim[0] will only work as comment char for full-line comment) | ||
1447 | // (IOW: it works as if PARSE_EOL_COMMENTS is not set. sysctl applet is okay with this) | ||
1448 | PARSE_WS_COMMENTS = 0x01000000, // comments are recognized even if there is whitespace before | ||
1449 | // ("line start><space><tab><space>#comment" is also comment, not only "line start>#comment") | ||
1432 | // NORMAL is: | 1450 | // NORMAL is: |
1433 | // * remove leading and trailing delimiters and collapse | 1451 | // * remove leading and trailing delimiters and collapse |
1434 | // multiple delimiters into one | 1452 | // multiple delimiters into one |
@@ -1484,6 +1502,21 @@ extern void run_shell(const char *shell, int loginshell, const char **args) NORE | |||
1484 | */ | 1502 | */ |
1485 | const char *get_shell_name(void) FAST_FUNC; | 1503 | const char *get_shell_name(void) FAST_FUNC; |
1486 | 1504 | ||
1505 | unsigned cap_name_to_number(const char *cap) FAST_FUNC; | ||
1506 | void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; | ||
1507 | void drop_capability(int cap_ordinal) FAST_FUNC; | ||
1508 | /* Structures inside "struct caps" are Linux-specific and libcap-specific: */ | ||
1509 | #define DEFINE_STRUCT_CAPS \ | ||
1510 | struct caps { \ | ||
1511 | struct __user_cap_header_struct header; \ | ||
1512 | unsigned u32s; \ | ||
1513 | struct __user_cap_data_struct data[2]; \ | ||
1514 | } | ||
1515 | void getcaps(void *caps) FAST_FUNC; | ||
1516 | |||
1517 | unsigned cap_name_to_number(const char *name) FAST_FUNC; | ||
1518 | void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; | ||
1519 | |||
1487 | #if ENABLE_SELINUX | 1520 | #if ENABLE_SELINUX |
1488 | extern void renew_current_security_context(void) FAST_FUNC; | 1521 | extern void renew_current_security_context(void) FAST_FUNC; |
1489 | extern void set_current_security_context(security_context_t sid) FAST_FUNC; | 1522 | extern void set_current_security_context(security_context_t sid) FAST_FUNC; |
@@ -1668,9 +1701,9 @@ enum { | |||
1668 | * buffer[0] is used as a counter of buffered chars and must be 0 | 1701 | * buffer[0] is used as a counter of buffered chars and must be 0 |
1669 | * on first call. | 1702 | * on first call. |
1670 | * timeout: | 1703 | * timeout: |
1671 | * -2: do not poll for input; | 1704 | * -2: do not poll(-1) for input - read() it, return on EAGAIN at once |
1672 | * -1: poll(-1) (i.e. block); | 1705 | * -1: poll(-1) (i.e. block even on NONBLOCKed fd) |
1673 | * >=0: poll for TIMEOUT milliseconds, return -1/EAGAIN on timeout | 1706 | * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout |
1674 | */ | 1707 | */ |
1675 | int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; | 1708 | int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; |
1676 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; | 1709 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; |
@@ -1686,6 +1719,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; | |||
1686 | # endif | 1719 | # endif |
1687 | typedef struct line_input_t { | 1720 | typedef struct line_input_t { |
1688 | int flags; | 1721 | int flags; |
1722 | int timeout; | ||
1689 | const char *path_lookup; | 1723 | const char *path_lookup; |
1690 | # if MAX_HISTORY | 1724 | # if MAX_HISTORY |
1691 | int cnt_history; | 1725 | int cnt_history; |
@@ -1721,7 +1755,7 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC; | |||
1721 | * 0 on ctrl-C (the line entered is still returned in 'command'), | 1755 | * 0 on ctrl-C (the line entered is still returned in 'command'), |
1722 | * >0 length of input string, including terminating '\n' | 1756 | * >0 length of input string, including terminating '\n' |
1723 | */ | 1757 | */ |
1724 | int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; | 1758 | int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) FAST_FUNC; |
1725 | void show_history(const line_input_t *st) FAST_FUNC; | 1759 | void show_history(const line_input_t *st) FAST_FUNC; |
1726 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 1760 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
1727 | void save_history(line_input_t *st); | 1761 | void save_history(line_input_t *st); |
@@ -1729,7 +1763,7 @@ void save_history(line_input_t *st); | |||
1729 | #else | 1763 | #else |
1730 | #define MAX_HISTORY 0 | 1764 | #define MAX_HISTORY 0 |
1731 | int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; | 1765 | int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; |
1732 | #define read_line_input(state, prompt, command, maxsize, timeout) \ | 1766 | #define read_line_input(state, prompt, command, maxsize) \ |
1733 | read_line_input(prompt, command, maxsize) | 1767 | read_line_input(prompt, command, maxsize) |
1734 | #endif | 1768 | #endif |
1735 | 1769 | ||
diff --git a/include/platform.h b/include/platform.h index 749169b0c..cc22f4fc9 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -277,6 +277,11 @@ typedef uint64_t bb__aliased_uint64_t FIX_ALIASING; | |||
277 | #define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val)) | 277 | #define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val)) |
278 | #define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val)) | 278 | #define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val)) |
279 | 279 | ||
280 | /* unxz needs an aligned fixed-endian accessor. | ||
281 | * (however, the compiler does not realize it's aligned, the cast is still necessary) | ||
282 | */ | ||
283 | #define get_le32(u32p) ({ uint32_t v = *(bb__aliased_uint32_t*)(u32p); SWAP_LE32(v); }) | ||
284 | |||
280 | 285 | ||
281 | /* ---- Size-saving "small" ints (arch-dependent) ----------- */ | 286 | /* ---- Size-saving "small" ints (arch-dependent) ----------- */ |
282 | 287 | ||
diff --git a/klibc-utils/Config.src b/klibc-utils/Config.src new file mode 100644 index 000000000..fe7cb1315 --- /dev/null +++ b/klibc-utils/Config.src | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # For a description of the syntax of this configuration file, | ||
3 | # see scripts/kbuild/config-language.txt. | ||
4 | # | ||
5 | |||
6 | menu "klibc-utils" | ||
7 | |||
8 | INSERT | ||
9 | |||
10 | endmenu | ||
diff --git a/klibc-utils/Kbuild.src b/klibc-utils/Kbuild.src new file mode 100644 index 000000000..6b4fb7470 --- /dev/null +++ b/klibc-utils/Kbuild.src | |||
@@ -0,0 +1,9 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # Licensed under GPLv2, see file LICENSE in this source tree. | ||
6 | |||
7 | lib-y:= | ||
8 | |||
9 | INSERT | ||
diff --git a/klibc-utils/minips.c b/klibc-utils/minips.c new file mode 100644 index 000000000..6003bf57b --- /dev/null +++ b/klibc-utils/minips.c | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017 Denys Vlasenko <vda.linux@googlemail.com> | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | //config:config MINIPS | ||
7 | //config: bool "minips (11 kb)" | ||
8 | //config: default n # for god's sake, just use "ps" name in your scripts | ||
9 | //config: help | ||
10 | //config: Alias to "ps". | ||
11 | |||
12 | /* applet and kbuild hooks are in ps.c */ | ||
diff --git a/klibc-utils/nuke.c b/klibc-utils/nuke.c new file mode 100644 index 000000000..a5d2f8d70 --- /dev/null +++ b/klibc-utils/nuke.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017 Denys Vlasenko <vda.linux@googlemail.com> | ||
3 | * | ||
4 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | //config:config NUKE | ||
7 | //config: bool "nuke" | ||
8 | //config: default y | ||
9 | //config: help | ||
10 | //config: Alias to "rm -rf". | ||
11 | |||
12 | //applet:IF_NUKE(APPLET_NOEXEC(nuke, nuke, BB_DIR_BIN, BB_SUID_DROP, nuke)) | ||
13 | |||
14 | //kbuild:lib-$(CONFIG_NUKE) += nuke.o | ||
15 | |||
16 | //usage:#define nuke_trivial_usage | ||
17 | //usage: "DIR..." | ||
18 | //usage:#define nuke_full_usage "\n\n" | ||
19 | //usage: "Remove DIRs" | ||
20 | |||
21 | #include "libbb.h" | ||
22 | |||
23 | /* This is a NOEXEC applet. Be very careful! */ | ||
24 | |||
25 | int nuke_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
26 | int nuke_main(int argc UNUSED_PARAM, char **argv) | ||
27 | { | ||
28 | // klibc-utils do not check opts, will try to delete "-dir" args | ||
29 | //opt = getopt32(argv, ""); | ||
30 | //argv += optind; | ||
31 | |||
32 | while (*++argv) { | ||
33 | #if 0 | ||
34 | // klibc-utils do not check this, will happily operate on ".." | ||
35 | const char *base = bb_get_last_path_component_strip(*argv); | ||
36 | if (DOT_OR_DOTDOT(base)) { | ||
37 | bb_error_msg("can't remove '.' or '..'"); | ||
38 | continue; | ||
39 | } | ||
40 | #endif | ||
41 | remove_file(*argv, FILEUTILS_FORCE | FILEUTILS_RECUR); | ||
42 | } | ||
43 | |||
44 | // klibc-utils do not indicate errors | ||
45 | return EXIT_SUCCESS; | ||
46 | } | ||
diff --git a/klibc-utils/resume.c b/klibc-utils/resume.c new file mode 100644 index 000000000..de142f350 --- /dev/null +++ b/klibc-utils/resume.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017 Denys Vlasenko <vda.linux@googlemail.com> | ||
3 | * | ||
4 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | //config:config RESUME | ||
7 | //config: bool "resume" | ||
8 | //config: default y | ||
9 | //config: help | ||
10 | //config: Resume from saved "suspend-to-disk" image | ||
11 | |||
12 | //applet:IF_RESUME(APPLET_NOEXEC(resume, resume, BB_DIR_BIN, BB_SUID_DROP, resume)) | ||
13 | |||
14 | //kbuild:lib-$(CONFIG_RESUME) += resume.o | ||
15 | |||
16 | #include "libbb.h" | ||
17 | |||
18 | /* This is a NOEXEC applet. Be very careful! */ | ||
19 | |||
20 | /* name_to_dev_t() in klibc-utils supports extended device name formats, | ||
21 | * apart from the usual case where /dev/NAME already exists. | ||
22 | * | ||
23 | * - device number in hexadecimal represents itself (in dev_t layout). | ||
24 | * - device number in major:minor decimal represents itself. | ||
25 | * - if block device (or partition) with this name is found in sysfs. | ||
26 | * - if /dev/ prefix is not given, it is assumed. | ||
27 | * | ||
28 | * klibc-utils also recognizes these, but they don't work | ||
29 | * for "resume" tool purposes (thus we don't support them (yet?)): | ||
30 | * - /dev/nfs | ||
31 | * - /dev/ram (alias to /dev/ram0) | ||
32 | * - /dev/mtd | ||
33 | */ | ||
34 | static dev_t name_to_dev_t(const char *devname) | ||
35 | { | ||
36 | char devfile[sizeof(int)*3 * 2 + 4]; | ||
37 | char *sysname; | ||
38 | unsigned major_num, minor_num; | ||
39 | struct stat st; | ||
40 | int r; | ||
41 | |||
42 | if (strncmp(devname, "/dev/", 5) != 0) { | ||
43 | char *cptr; | ||
44 | |||
45 | cptr = strchr(devname, ':'); | ||
46 | if (cptr) { | ||
47 | /* Colon-separated decimal device number? */ | ||
48 | *cptr = '\0'; | ||
49 | major_num = bb_strtou(devname, NULL, 10); | ||
50 | if (!errno) | ||
51 | minor_num = bb_strtou(cptr + 1, NULL, 10); | ||
52 | *cptr = ':'; | ||
53 | if (!errno) | ||
54 | return makedev(major_num, minor_num); | ||
55 | } else { | ||
56 | /* Hexadecimal device number? */ | ||
57 | dev_t res = (dev_t) bb_strtoul(devname, NULL, 16); | ||
58 | if (!errno) | ||
59 | return res; | ||
60 | } | ||
61 | |||
62 | devname = xasprintf("/dev/%s", devname); | ||
63 | } | ||
64 | /* Now devname is always "/dev/FOO" */ | ||
65 | |||
66 | if (stat(devname, &st) == 0 && S_ISBLK(st.st_mode)) | ||
67 | return st.st_rdev; | ||
68 | |||
69 | /* Full blockdevs as well as partitions may be visible | ||
70 | * in /sys/class/block/ even if /dev is not populated. | ||
71 | */ | ||
72 | sysname = xasprintf("/sys/class/block/%s/dev", devname + 5); | ||
73 | r = open_read_close(sysname, devfile, sizeof(devfile) - 1); | ||
74 | //free(sysname); | ||
75 | if (r > 0) { | ||
76 | devfile[r] = '\0'; | ||
77 | if (sscanf(devfile, "%u:%u", &major_num, &minor_num) == 2) { | ||
78 | return makedev(major_num, minor_num); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | return (dev_t) 0; | ||
83 | } | ||
84 | |||
85 | //usage:#define resume_trivial_usage | ||
86 | //usage: "BLOCKDEV [OFFSET]" | ||
87 | //usage:#define resume_full_usage "\n" | ||
88 | //usage: "\n""Restore system state from 'suspend-to-disk' data in BLOCKDEV" | ||
89 | |||
90 | int resume_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
91 | int resume_main(int argc UNUSED_PARAM, char **argv) | ||
92 | { | ||
93 | unsigned long long ofs; | ||
94 | dev_t resume_device; | ||
95 | char *s; | ||
96 | int fd; | ||
97 | |||
98 | argv++; | ||
99 | if (!argv[0]) | ||
100 | bb_show_usage(); | ||
101 | |||
102 | resume_device = name_to_dev_t(argv[0]); | ||
103 | if (major(resume_device) == 0) { | ||
104 | bb_error_msg_and_die("invalid resume device: %s", argv[0]); | ||
105 | } | ||
106 | ofs = (argv[1] ? xstrtoull(argv[1], 0) : 0); | ||
107 | |||
108 | fd = xopen("/sys/power/resume", O_WRONLY); | ||
109 | s = xasprintf("%u:%u:%llu", major(resume_device), minor(resume_device), ofs); | ||
110 | |||
111 | xwrite_str(fd, s); | ||
112 | /* if write() returns, resume did not succeed */ | ||
113 | |||
114 | return EXIT_FAILURE; /* klibc-utils exits -1 aka 255 */ | ||
115 | } | ||
diff --git a/klibc-utils/run-init.c b/klibc-utils/run-init.c new file mode 100644 index 000000000..a70d1bfbf --- /dev/null +++ b/klibc-utils/run-init.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * run-init implementation for busybox | ||
3 | * | ||
4 | * Copyright (c) 2017 Denys Vlasenko <vda.linux@gmail.com> | ||
5 | * | ||
6 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
7 | */ | ||
8 | //config:config RUN_INIT | ||
9 | //config: bool "run-init" | ||
10 | //config: default y | ||
11 | //config: select PLATFORM_LINUX | ||
12 | //config: help | ||
13 | //config: The run-init utility is used from initramfs to select a new | ||
14 | //config: root device. Under initramfs, you have to use this instead of | ||
15 | //config: pivot_root. | ||
16 | //config: | ||
17 | //config: Booting with initramfs extracts a gzipped cpio archive into rootfs | ||
18 | //config: (which is a variant of ramfs/tmpfs). Because rootfs can't be moved | ||
19 | //config: or unmounted, pivot_root will not work from initramfs. Instead, | ||
20 | //config: run-init deletes everything out of rootfs (including itself), | ||
21 | //config: does a mount --move that overmounts rootfs with the new root, and | ||
22 | //config: then execs the specified init program. | ||
23 | //config: | ||
24 | //config: util-linux has a similar tool, switch-root. | ||
25 | //config: run-init differs by also having a "-d CAPS_TO_DROP" option. | ||
26 | |||
27 | /* applet and kbuild hooks are in switch_root.c */ | ||
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; |
diff --git a/libpwdgrp/uidgid_get.c b/libpwdgrp/uidgid_get.c index 1199f23f9..283ac78fc 100644 --- a/libpwdgrp/uidgid_get.c +++ b/libpwdgrp/uidgid_get.c | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
diff --git a/loginutils/add-remove-shell.c b/loginutils/add-remove-shell.c index 750b44bd6..6d03de254 100644 --- a/loginutils/add-remove-shell.c +++ b/loginutils/add-remove-shell.c | |||
@@ -19,9 +19,9 @@ | |||
19 | //config: help | 19 | //config: help |
20 | //config: Remove shells from /etc/shells. | 20 | //config: Remove shells from /etc/shells. |
21 | 21 | ||
22 | // APPLET_ODDNAME:name main location suid_type help | 22 | // APPLET_NOEXEC:name main location suid_type help |
23 | //applet:IF_ADD_SHELL( APPLET_ODDNAME(add-shell , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell )) | 23 | //applet:IF_ADD_SHELL( APPLET_NOEXEC(add-shell , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell )) |
24 | //applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell)) | 24 | //applet:IF_REMOVE_SHELL(APPLET_NOEXEC(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell)) |
25 | 25 | ||
26 | //kbuild:lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o | 26 | //kbuild:lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o |
27 | //kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o | 27 | //kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o |
@@ -64,6 +64,7 @@ int add_remove_shell_main(int argc UNUSED_PARAM, char **argv) | |||
64 | if (orig_fp) | 64 | if (orig_fp) |
65 | xfstat(fileno(orig_fp), &sb, orig_fn); | 65 | xfstat(fileno(orig_fp), &sb, orig_fn); |
66 | 66 | ||
67 | |||
67 | new_fn = xasprintf("%s.tmp", orig_fn); | 68 | new_fn = xasprintf("%s.tmp", orig_fn); |
68 | /* | 69 | /* |
69 | * O_TRUNC or O_EXCL? At the first glance, O_EXCL looks better, | 70 | * O_TRUNC or O_EXCL? At the first glance, O_EXCL looks better, |
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c index b197fc149..adef2328d 100644 --- a/loginutils/addgroup.c +++ b/loginutils/addgroup.c | |||
@@ -12,14 +12,10 @@ | |||
12 | //config:config ADDGROUP | 12 | //config:config ADDGROUP |
13 | //config: bool "addgroup (8.2 kb)" | 13 | //config: bool "addgroup (8.2 kb)" |
14 | //config: default y | 14 | //config: default y |
15 | //config: select LONG_OPTS | ||
15 | //config: help | 16 | //config: help |
16 | //config: Utility for creating a new group account. | 17 | //config: Utility for creating a new group account. |
17 | //config: | 18 | //config: |
18 | //config:config FEATURE_ADDGROUP_LONG_OPTIONS | ||
19 | //config: bool "Enable long options" | ||
20 | //config: default y | ||
21 | //config: depends on ADDGROUP && LONG_OPTS | ||
22 | //config: | ||
23 | //config:config FEATURE_ADDUSER_TO_GROUP | 19 | //config:config FEATURE_ADDUSER_TO_GROUP |
24 | //config: bool "Support adding users to groups" | 20 | //config: bool "Support adding users to groups" |
25 | //config: default y | 21 | //config: default y |
@@ -29,7 +25,7 @@ | |||
29 | //config: addgroup will add an existing user to an | 25 | //config: addgroup will add an existing user to an |
30 | //config: existing group. | 26 | //config: existing group. |
31 | 27 | ||
32 | //applet:IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 28 | //applet:IF_ADDGROUP(APPLET_NOEXEC(addgroup, addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP, addgroup)) |
33 | 29 | ||
34 | //kbuild:lib-$(CONFIG_ADDGROUP) += addgroup.o | 30 | //kbuild:lib-$(CONFIG_ADDGROUP) += addgroup.o |
35 | 31 | ||
@@ -131,12 +127,11 @@ static void new_group(char *group, gid_t gid) | |||
131 | #endif | 127 | #endif |
132 | } | 128 | } |
133 | 129 | ||
134 | #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS | 130 | //FIXME: upstream addgroup has no short options! NOT COMPATIBLE! |
135 | static const char addgroup_longopts[] ALIGN1 = | 131 | static const char addgroup_longopts[] ALIGN1 = |
136 | "gid\0" Required_argument "g" | 132 | "gid\0" Required_argument "g" |
137 | "system\0" No_argument "S" | 133 | "system\0" No_argument "S" |
138 | ; | 134 | ; |
139 | #endif | ||
140 | 135 | ||
141 | /* | 136 | /* |
142 | * addgroup will take a login_name as its first parameter. | 137 | * addgroup will take a login_name as its first parameter. |
@@ -155,16 +150,14 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv) | |||
155 | if (geteuid()) { | 150 | if (geteuid()) { |
156 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | 151 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
157 | } | 152 | } |
158 | #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS | ||
159 | applet_long_options = addgroup_longopts; | ||
160 | #endif | ||
161 | /* Syntax: | 153 | /* Syntax: |
162 | * addgroup group | 154 | * addgroup group |
163 | * addgroup -g num group | 155 | * addgroup --gid num group |
164 | * addgroup user group | 156 | * addgroup user group |
165 | * Check for min, max and missing args */ | 157 | * Check for min, max and missing args */ |
166 | opt_complementary = "-1:?2"; | 158 | opts = getopt32long(argv, "^" "g:S" "\0" "-1:?2", addgroup_longopts, |
167 | opts = getopt32(argv, "g:S", &gid); | 159 | &gid |
160 | ); | ||
168 | /* move past the commandline options */ | 161 | /* move past the commandline options */ |
169 | argv += optind; | 162 | argv += optind; |
170 | //argc -= optind; | 163 | //argc -= optind; |
diff --git a/loginutils/adduser.c b/loginutils/adduser.c index ef18278ac..b2b5be5b3 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c | |||
@@ -10,14 +10,10 @@ | |||
10 | //config:config ADDUSER | 10 | //config:config ADDUSER |
11 | //config: bool "adduser (15 kb)" | 11 | //config: bool "adduser (15 kb)" |
12 | //config: default y | 12 | //config: default y |
13 | //config: select LONG_OPTS | ||
13 | //config: help | 14 | //config: help |
14 | //config: Utility for creating a new user account. | 15 | //config: Utility for creating a new user account. |
15 | //config: | 16 | //config: |
16 | //config:config FEATURE_ADDUSER_LONG_OPTIONS | ||
17 | //config: bool "Enable long options" | ||
18 | //config: default y | ||
19 | //config: depends on ADDUSER && LONG_OPTS | ||
20 | //config: | ||
21 | //config:config FEATURE_CHECK_NAMES | 17 | //config:config FEATURE_CHECK_NAMES |
22 | //config: bool "Enable sanity check on user/group names in adduser and addgroup" | 18 | //config: bool "Enable sanity check on user/group names in adduser and addgroup" |
23 | //config: default n | 19 | //config: default n |
@@ -53,7 +49,7 @@ | |||
53 | //config: help | 49 | //config: help |
54 | //config: Last valid system uid or gid for adduser and addgroup | 50 | //config: Last valid system uid or gid for adduser and addgroup |
55 | 51 | ||
56 | //applet:IF_ADDUSER(APPLET(adduser, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 52 | //applet:IF_ADDUSER(APPLET_NOEXEC(adduser, adduser, BB_DIR_USR_SBIN, BB_SUID_DROP, adduser)) |
57 | 53 | ||
58 | //kbuild:lib-$(CONFIG_ADDUSER) += adduser.o | 54 | //kbuild:lib-$(CONFIG_ADDUSER) += adduser.o |
59 | 55 | ||
@@ -148,15 +144,7 @@ static int addgroup_wrapper(struct passwd *p, const char *group_name) | |||
148 | /* Add user to his own group with the first free gid | 144 | /* Add user to his own group with the first free gid |
149 | * found in passwd_study. | 145 | * found in passwd_study. |
150 | */ | 146 | */ |
151 | #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS || !ENABLE_ADDGROUP | ||
152 | /* We try to use --gid, not -g, because "standard" addgroup | ||
153 | * has no short option -g, it has only long --gid. | ||
154 | */ | ||
155 | argv[1] = (char*)"--gid"; | 147 | argv[1] = (char*)"--gid"; |
156 | #else | ||
157 | /* Breaks if system in fact does NOT use busybox addgroup */ | ||
158 | argv[1] = (char*)"-g"; | ||
159 | #endif | ||
160 | argv[2] = utoa(p->pw_gid); | 148 | argv[2] = utoa(p->pw_gid); |
161 | argv[3] = (char*)"--"; | 149 | argv[3] = (char*)"--"; |
162 | argv[4] = p->pw_name; | 150 | argv[4] = p->pw_name; |
@@ -174,7 +162,7 @@ static void passwd_wrapper(const char *login_name) | |||
174 | bb_error_msg_and_die("can't execute passwd, you must set password manually"); | 162 | bb_error_msg_and_die("can't execute passwd, you must set password manually"); |
175 | } | 163 | } |
176 | 164 | ||
177 | #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS | 165 | //FIXME: upstream adduser has no short options! NOT COMPATIBLE! |
178 | static const char adduser_longopts[] ALIGN1 = | 166 | static const char adduser_longopts[] ALIGN1 = |
179 | "home\0" Required_argument "h" | 167 | "home\0" Required_argument "h" |
180 | "gecos\0" Required_argument "g" | 168 | "gecos\0" Required_argument "g" |
@@ -187,7 +175,6 @@ static const char adduser_longopts[] ALIGN1 = | |||
187 | "uid\0" Required_argument "u" | 175 | "uid\0" Required_argument "u" |
188 | "skel\0" Required_argument "k" | 176 | "skel\0" Required_argument "k" |
189 | ; | 177 | ; |
190 | #endif | ||
191 | 178 | ||
192 | /* | 179 | /* |
193 | * adduser will take a login_name as its first parameter. | 180 | * adduser will take a login_name as its first parameter. |
@@ -204,10 +191,6 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) | |||
204 | char *uid; | 191 | char *uid; |
205 | const char *skel = "/etc/skel"; | 192 | const char *skel = "/etc/skel"; |
206 | 193 | ||
207 | #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS | ||
208 | applet_long_options = adduser_longopts; | ||
209 | #endif | ||
210 | |||
211 | /* got root? */ | 194 | /* got root? */ |
212 | if (geteuid()) { | 195 | if (geteuid()) { |
213 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | 196 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
@@ -218,10 +201,15 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) | |||
218 | pw.pw_shell = (char *)get_shell_name(); | 201 | pw.pw_shell = (char *)get_shell_name(); |
219 | pw.pw_dir = NULL; | 202 | pw.pw_dir = NULL; |
220 | 203 | ||
221 | /* at least one and at most two non-option args */ | 204 | opts = getopt32long(argv, "^" |
222 | /* disable interactive passwd for system accounts */ | 205 | "h:g:s:G:DSHu:k:" |
223 | opt_complementary = "-1:?2:SD"; | 206 | /* at least one and at most two non-option args */ |
224 | opts = getopt32(argv, "h:g:s:G:DSHu:k:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid, &skel); | 207 | /* disable interactive passwd for system accounts */ |
208 | "\0" "-1:?2:SD", | ||
209 | adduser_longopts, | ||
210 | &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, | ||
211 | &usegroup, &uid, &skel | ||
212 | ); | ||
225 | if (opts & OPT_UID) | 213 | if (opts & OPT_UID) |
226 | pw.pw_uid = xatou_range(uid, 0, CONFIG_LAST_ID); | 214 | pw.pw_uid = xatou_range(uid, 0, CONFIG_LAST_ID); |
227 | 215 | ||
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c index e390da647..652e4f127 100644 --- a/loginutils/chpasswd.c +++ b/loginutils/chpasswd.c | |||
@@ -61,9 +61,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) | |||
61 | if (getuid() != 0) | 61 | if (getuid() != 0) |
62 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | 62 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
63 | 63 | ||
64 | opt_complementary = "m--ec:e--mc:c--em"; | 64 | opt = getopt32long(argv, "^" "emc:" "\0" "m--ec:e--mc:c--em", |
65 | IF_LONG_OPTS(applet_long_options = chpasswd_longopts;) | 65 | chpasswd_longopts, |
66 | opt = getopt32(argv, "emc:", &algo); | 66 | &algo |
67 | ); | ||
67 | 68 | ||
68 | while ((name = xmalloc_fgetline(stdin)) != NULL) { | 69 | while ((name = xmalloc_fgetline(stdin)) != NULL) { |
69 | char *free_me; | 70 | char *free_me; |
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c index f8906c59a..76138a61f 100644 --- a/loginutils/cryptpw.c +++ b/loginutils/cryptpw.c | |||
@@ -24,9 +24,9 @@ | |||
24 | //config: using the given salt. Debian has this utility under mkpasswd | 24 | //config: using the given salt. Debian has this utility under mkpasswd |
25 | //config: name. Busybox provides mkpasswd as an alias for cryptpw. | 25 | //config: name. Busybox provides mkpasswd as an alias for cryptpw. |
26 | 26 | ||
27 | //applet:IF_CRYPTPW(APPLET(cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP)) | 27 | //applet:IF_CRYPTPW( APPLET_NOEXEC(cryptpw, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, cryptpw)) |
28 | // APPLET_ODDNAME:name main location suid_type help | 28 | // APPLET_NOEXEC:name main location suid_type help |
29 | //applet:IF_MKPASSWD(APPLET_ODDNAME(mkpasswd, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, cryptpw)) | 29 | //applet:IF_MKPASSWD(APPLET_NOEXEC(mkpasswd, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, cryptpw)) |
30 | 30 | ||
31 | //kbuild:lib-$(CONFIG_CRYPTPW) += cryptpw.o | 31 | //kbuild:lib-$(CONFIG_CRYPTPW) += cryptpw.o |
32 | //kbuild:lib-$(CONFIG_MKPASSWD) += cryptpw.o | 32 | //kbuild:lib-$(CONFIG_MKPASSWD) += cryptpw.o |
@@ -106,14 +106,15 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) | |||
106 | "salt\0" Required_argument "S" | 106 | "salt\0" Required_argument "S" |
107 | "method\0" Required_argument "m" | 107 | "method\0" Required_argument "m" |
108 | ; | 108 | ; |
109 | applet_long_options = mkpasswd_longopts; | ||
110 | #endif | 109 | #endif |
111 | fd = STDIN_FILENO; | 110 | fd = STDIN_FILENO; |
112 | opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; | 111 | opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; |
113 | opt_S = NULL; | 112 | opt_S = NULL; |
114 | /* at most two non-option arguments; -P NUM */ | 113 | /* at most two non-option arguments; -P NUM */ |
115 | opt_complementary = "?2"; | 114 | getopt32long(argv, "^" "sP:+S:m:a:" "\0" "?2", |
116 | getopt32(argv, "sP:+S:m:a:", &fd, &opt_S, &opt_m, &opt_m); | 115 | mkpasswd_longopts, |
116 | &fd, &opt_S, &opt_m, &opt_m | ||
117 | ); | ||
117 | argv += optind; | 118 | argv += optind; |
118 | 119 | ||
119 | /* have no idea how to handle -s... */ | 120 | /* have no idea how to handle -s... */ |
diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 3b6bd952d..5ee22d4f1 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c | |||
@@ -28,8 +28,9 @@ | |||
28 | //config: If called with two non-option arguments, deluser | 28 | //config: If called with two non-option arguments, deluser |
29 | //config: or delgroup will remove an user from a specified group. | 29 | //config: or delgroup will remove an user from a specified group. |
30 | 30 | ||
31 | //applet:IF_DELUSER(APPLET(deluser, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 31 | // APPLET_NOEXEC:name main location suid_type help |
32 | //applet:IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) | 32 | //applet:IF_DELUSER( APPLET_NOEXEC(deluser, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, deluser)) |
33 | //applet:IF_DELGROUP(APPLET_NOEXEC(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) | ||
33 | 34 | ||
34 | //kbuild:lib-$(CONFIG_DELUSER) += deluser.o | 35 | //kbuild:lib-$(CONFIG_DELUSER) += deluser.o |
35 | //kbuild:lib-$(CONFIG_DELGROUP) += deluser.o | 36 | //kbuild:lib-$(CONFIG_DELGROUP) += deluser.o |
@@ -67,9 +68,8 @@ int deluser_main(int argc, char **argv) | |||
67 | #else | 68 | #else |
68 | int opt_delhome = 0; | 69 | int opt_delhome = 0; |
69 | if (do_deluser) { | 70 | if (do_deluser) { |
70 | applet_long_options = | 71 | opt_delhome = getopt32long(argv, "", |
71 | "remove-home\0" No_argument "\xff"; | 72 | "remove-home\0" No_argument "\xff"); |
72 | opt_delhome = getopt32(argv, ""); | ||
73 | argv += opt_delhome; | 73 | argv += opt_delhome; |
74 | argc -= opt_delhome; | 74 | argc -= opt_delhome; |
75 | } | 75 | } |
diff --git a/loginutils/getty.c b/loginutils/getty.c index fd5116d08..23e92bc77 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c | |||
@@ -131,7 +131,7 @@ struct globals { | |||
131 | //usage: "\n" | 131 | //usage: "\n" |
132 | //usage: "\nBAUD_RATE of 0 leaves it unchanged" | 132 | //usage: "\nBAUD_RATE of 0 leaves it unchanged" |
133 | 133 | ||
134 | static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:+wn"; | 134 | #define OPT_STR "I:LH:f:hil:mt:+wn" |
135 | #define F_INITSTRING (1 << 0) /* -I */ | 135 | #define F_INITSTRING (1 << 0) /* -I */ |
136 | #define F_LOCAL (1 << 1) /* -L */ | 136 | #define F_LOCAL (1 << 1) /* -L */ |
137 | #define F_FAKEHOST (1 << 2) /* -H */ | 137 | #define F_FAKEHOST (1 << 2) /* -H */ |
@@ -179,8 +179,7 @@ static void parse_args(char **argv) | |||
179 | char *ts; | 179 | char *ts; |
180 | int flags; | 180 | int flags; |
181 | 181 | ||
182 | opt_complementary = "-2"; /* at least 2 args; -t N */ | 182 | flags = getopt32(argv, "^" OPT_STR "\0" "-2"/* at least 2 args*/, |
183 | flags = getopt32(argv, opt_string, | ||
184 | &G.initstring, &G.fakehost, &G.issue, | 183 | &G.initstring, &G.fakehost, &G.issue, |
185 | &G.login, &G.timeout | 184 | &G.login, &G.timeout |
186 | ); | 185 | ); |
diff --git a/loginutils/login.c b/loginutils/login.c index 381468d81..fcdb9592c 100644 --- a/loginutils/login.c +++ b/loginutils/login.c | |||
@@ -350,8 +350,8 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
350 | /* Mandatory paranoia for suid applet: | 350 | /* Mandatory paranoia for suid applet: |
351 | * ensure that fd# 0,1,2 are opened (at least to /dev/null) | 351 | * ensure that fd# 0,1,2 are opened (at least to /dev/null) |
352 | * and any extra open fd's are closed. | 352 | * and any extra open fd's are closed. |
353 | * (The name of the function is misleading. Not daemonizing here.) */ | 353 | */ |
354 | bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); | 354 | bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); |
355 | 355 | ||
356 | username[0] = '\0'; | 356 | username[0] = '\0'; |
357 | opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); | 357 | opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); |
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c index d5a463cac..27ea5dff0 100644 --- a/loginutils/sulogin.c +++ b/loginutils/sulogin.c | |||
@@ -12,7 +12,7 @@ | |||
12 | //config: sulogin is invoked when the system goes into single user | 12 | //config: sulogin is invoked when the system goes into single user |
13 | //config: mode (this is done through an entry in inittab). | 13 | //config: mode (this is done through an entry in inittab). |
14 | 14 | ||
15 | //applet:IF_SULOGIN(APPLET(sulogin, BB_DIR_SBIN, BB_SUID_DROP)) | 15 | //applet:IF_SULOGIN(APPLET_NOEXEC(sulogin, sulogin, BB_DIR_SBIN, BB_SUID_DROP, sulogin)) |
16 | 16 | ||
17 | //kbuild:lib-$(CONFIG_SULOGIN) += sulogin.o | 17 | //kbuild:lib-$(CONFIG_SULOGIN) += sulogin.o |
18 | 18 | ||
@@ -34,7 +34,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) | |||
34 | 34 | ||
35 | /* Note: sulogin is not a suid app. It is meant to be run by init | 35 | /* Note: sulogin is not a suid app. It is meant to be run by init |
36 | * for single user / emergency mode. init starts it as root. | 36 | * for single user / emergency mode. init starts it as root. |
37 | * Normal users (potentially malisious ones) can only run it under | 37 | * Normal users (potentially malicious ones) can only run it under |
38 | * their UID, therefore no paranoia here is warranted: | 38 | * their UID, therefore no paranoia here is warranted: |
39 | * $LD_LIBRARY_PATH in env, TTY = /dev/sda | 39 | * $LD_LIBRARY_PATH in env, TTY = /dev/sda |
40 | * are no more dangerous here than in e.g. cp applet. | 40 | * are no more dangerous here than in e.g. cp applet. |
diff --git a/loginutils/vlock.c b/loginutils/vlock.c index bf46d085c..9e319fe61 100644 --- a/loginutils/vlock.c +++ b/loginutils/vlock.c | |||
@@ -66,8 +66,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) | |||
66 | struct passwd *pw; | 66 | struct passwd *pw; |
67 | 67 | ||
68 | pw = xgetpwuid(getuid()); | 68 | pw = xgetpwuid(getuid()); |
69 | opt_complementary = "=0"; /* no params! */ | 69 | getopt32(argv, "^" "a" "\0" "=0"/* no args!*/); |
70 | getopt32(argv, "a"); | ||
71 | 70 | ||
72 | /* Ignore some signals so that we don't get killed by them */ | 71 | /* Ignore some signals so that we don't get killed by them */ |
73 | bb_signals(0 | 72 | bb_signals(0 |
diff --git a/mailutils/mail.c b/mailutils/mail.c index a7e43c0d1..eceb89071 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c | |||
@@ -6,23 +6,15 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | 7 | * Licensed under GPLv2, see file LICENSE in this source tree. |
8 | */ | 8 | */ |
9 | #include <sys/prctl.h> | ||
9 | #include "libbb.h" | 10 | #include "libbb.h" |
10 | #include "mail.h" | 11 | #include "mail.h" |
11 | 12 | ||
12 | static void kill_helper(void) | ||
13 | { | ||
14 | if (G.helper_pid > 0) { | ||
15 | kill(G.helper_pid, SIGTERM); | ||
16 | G.helper_pid = 0; | ||
17 | } | ||
18 | } | ||
19 | |||
20 | // generic signal handler | 13 | // generic signal handler |
21 | static void signal_handler(int signo) | 14 | static void signal_handler(int signo) |
22 | { | 15 | { |
23 | #define err signo | 16 | #define err signo |
24 | if (SIGALRM == signo) { | 17 | if (SIGALRM == signo) { |
25 | kill_helper(); | ||
26 | bb_error_msg_and_die("timed out"); | 18 | bb_error_msg_and_die("timed out"); |
27 | } | 19 | } |
28 | 20 | ||
@@ -66,16 +58,15 @@ void FAST_FUNC launch_helper(const char **argv) | |||
66 | // child stdout [1] -> parent stdin [0] | 58 | // child stdout [1] -> parent stdin [0] |
67 | 59 | ||
68 | if (!G.helper_pid) { | 60 | if (!G.helper_pid) { |
69 | // child: try to execute connection helper | 61 | // child |
62 | // if parent dies, get SIGTERM | ||
63 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); | ||
64 | // try to execute connection helper | ||
70 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec | 65 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec |
71 | BB_EXECVP_or_die((char**)argv); | 66 | BB_EXECVP_or_die((char**)argv); |
72 | } | 67 | } |
73 | 68 | ||
74 | // parent | 69 | // parent goes on |
75 | // check whether child is alive | ||
76 | //redundant:signal_handler(SIGCHLD); | ||
77 | // child seems OK -> parent goes on | ||
78 | atexit(kill_helper); | ||
79 | } | 70 | } |
80 | 71 | ||
81 | char* FAST_FUNC send_mail_command(const char *fmt, const char *param) | 72 | char* FAST_FUNC send_mail_command(const char *fmt, const char *param) |
diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c index 1695a9bb8..5756eaa76 100644 --- a/mailutils/popmaildir.c +++ b/mailutils/popmaildir.c | |||
@@ -125,9 +125,9 @@ int popmaildir_main(int argc UNUSED_PARAM, char **argv) | |||
125 | INIT_G(); | 125 | INIT_G(); |
126 | 126 | ||
127 | // parse options | 127 | // parse options |
128 | opt_complementary = "-1:dd"; | 128 | opts = getopt32(argv, "^" |
129 | opts = getopt32(argv, | 129 | "bdmVcasTkt:+" "R:+Z:L:+H:+" IF_FEATURE_POPMAILDIR_DELIVERY("M:F:") |
130 | "bdmVcasTkt:+" "R:+Z:L:+H:+" IF_FEATURE_POPMAILDIR_DELIVERY("M:F:"), | 130 | "\0" "-1:dd", |
131 | &timeout, NULL, NULL, NULL, &opt_nlines | 131 | &timeout, NULL, NULL, NULL, &opt_nlines |
132 | IF_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same | 132 | IF_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same |
133 | ); | 133 | ); |
diff --git a/mailutils/reformime.c b/mailutils/reformime.c index 6a0254803..321729e0a 100644 --- a/mailutils/reformime.c +++ b/mailutils/reformime.c | |||
@@ -280,9 +280,9 @@ int reformime_main(int argc UNUSED_PARAM, char **argv) | |||
280 | 280 | ||
281 | // parse options | 281 | // parse options |
282 | // N.B. only -x and -X are supported so far | 282 | // N.B. only -x and -X are supported so far |
283 | opt_complementary = "x--X:X--x"; | 283 | opts = getopt32(argv, "^" |
284 | opts = getopt32(argv, | 284 | "x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:*h:o:O:") |
285 | "x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:*h:o:O:"), | 285 | "\0" "x--X:X--x", |
286 | &opt_prefix | 286 | &opt_prefix |
287 | IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL) | 287 | IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL) |
288 | ); | 288 | ); |
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 346de2712..f440e6319 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c | |||
@@ -166,9 +166,8 @@ static char *angle_address(char *str) | |||
166 | { | 166 | { |
167 | char *s, *e; | 167 | char *s, *e; |
168 | 168 | ||
169 | trim(str); | 169 | e = trim(str); |
170 | e = last_char_is(str, '>'); | 170 | if (e != str && e[-1] == '>') { |
171 | if (e) { | ||
172 | s = strrchr(str, '<'); | 171 | s = strrchr(str, '<'); |
173 | if (s) { | 172 | if (s) { |
174 | *e = '\0'; | 173 | *e = '\0'; |
@@ -257,13 +256,17 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
257 | G.fp0 = xfdopen_for_read(3); | 256 | G.fp0 = xfdopen_for_read(3); |
258 | 257 | ||
259 | // parse options | 258 | // parse options |
260 | // -v is a counter, -H and -S are mutually exclusive, -a is a list | ||
261 | opt_complementary = "vv:H--S:S--H"; | ||
262 | // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect | 259 | // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect |
263 | // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, | 260 | // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, |
264 | // it is still under development. | 261 | // it is still under development. |
265 | opts = getopt32(argv, "tf:o:iw:+H:S:a:*:v", &opt_from, NULL, | 262 | opts = getopt32(argv, "^" |
266 | &timeout, &opt_connect, &opt_connect, &list, &verbose); | 263 | "tf:o:iw:+H:S:a:*:v" |
264 | "\0" | ||
265 | // -v is a counter, -H and -S are mutually exclusive, -a is a list | ||
266 | "vv:H--S:S--H", | ||
267 | &opt_from, NULL, | ||
268 | &timeout, &opt_connect, &opt_connect, &list, &verbose | ||
269 | ); | ||
267 | //argc -= optind; | 270 | //argc -= optind; |
268 | argv += optind; | 271 | argv += optind; |
269 | 272 | ||
diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c index 04ba5636f..c1718e909 100644 --- a/miscutils/adjtimex.c +++ b/miscutils/adjtimex.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables. | 3 | * adjtimex.c - read, and possibly modify, the Linux kernel 'timex' variables. |
4 | * | 4 | * |
5 | * Originally written: October 1997 | 5 | * Originally written: October 1997 |
6 | * Last hack: March 2001 | 6 | * Last hack: March 2001 |
@@ -18,7 +18,7 @@ | |||
18 | //config: Adjtimex reads and optionally sets adjustment parameters for | 18 | //config: Adjtimex reads and optionally sets adjustment parameters for |
19 | //config: the Linux clock adjustment algorithm. | 19 | //config: the Linux clock adjustment algorithm. |
20 | 20 | ||
21 | //applet:IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP)) | 21 | //applet:IF_ADJTIMEX(APPLET_NOFORK(adjtimex, adjtimex, BB_DIR_SBIN, BB_SUID_DROP, adjtimex)) |
22 | 22 | ||
23 | //kbuild:lib-$(CONFIG_ADJTIMEX) += adjtimex.o | 23 | //kbuild:lib-$(CONFIG_ADJTIMEX) += adjtimex.o |
24 | 24 | ||
@@ -90,13 +90,15 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) | |||
90 | unsigned opt; | 90 | unsigned opt; |
91 | char *opt_o, *opt_f, *opt_p, *opt_t; | 91 | char *opt_o, *opt_f, *opt_p, *opt_t; |
92 | struct timex txc; | 92 | struct timex txc; |
93 | int i, ret; | 93 | int ret; |
94 | const char *descript; | 94 | const char *descript; |
95 | 95 | ||
96 | opt_complementary = "=0"; /* no valid non-option parameters */ | 96 | memset(&txc, 0, sizeof(txc)); |
97 | opt = getopt32(argv, "qo:f:p:t:", | 97 | |
98 | &opt_o, &opt_f, &opt_p, &opt_t); | 98 | opt = getopt32(argv, "^" "qo:f:p:t:" |
99 | txc.modes = 0; | 99 | "\0" "=0"/*no valid non-option args*/, |
100 | &opt_o, &opt_f, &opt_p, &opt_t | ||
101 | ); | ||
100 | //if (opt & 0x1) // -q | 102 | //if (opt & 0x1) // -q |
101 | if (opt & 0x2) { // -o | 103 | if (opt & 0x2) { // -o |
102 | txc.offset = xatol(opt_o); | 104 | txc.offset = xatol(opt_o); |
@@ -115,15 +117,19 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) | |||
115 | txc.modes |= ADJ_TICK; | 117 | txc.modes |= ADJ_TICK; |
116 | } | 118 | } |
117 | 119 | ||
118 | ret = adjtimex(&txc); | 120 | /* It's NOFORK applet because the code is very simple: |
121 | * just some printf. No opens, no allocs. | ||
122 | * If you need to make it more complex, feel free to downgrade to NOEXEC | ||
123 | */ | ||
119 | 124 | ||
120 | if (ret < 0) { | 125 | ret = adjtimex(&txc); |
126 | if (ret < 0) | ||
121 | bb_perror_nomsg_and_die(); | 127 | bb_perror_nomsg_and_die(); |
122 | } | ||
123 | 128 | ||
124 | if (!(opt & OPT_quiet)) { | 129 | if (!(opt & OPT_quiet)) { |
125 | const char *sep; | 130 | const char *sep; |
126 | const char *name; | 131 | const char *name; |
132 | int i; | ||
127 | 133 | ||
128 | printf( | 134 | printf( |
129 | " mode: %d\n" | 135 | " mode: %d\n" |
@@ -132,8 +138,9 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) | |||
132 | " maxerror: %ld\n" | 138 | " maxerror: %ld\n" |
133 | " esterror: %ld\n" | 139 | " esterror: %ld\n" |
134 | " status: %d (", | 140 | " status: %d (", |
135 | txc.modes, txc.offset, txc.freq, txc.maxerror, | 141 | txc.modes, txc.offset, txc.freq, txc.maxerror, |
136 | txc.esterror, txc.status); | 142 | txc.esterror, txc.status |
143 | ); | ||
137 | 144 | ||
138 | /* representative output of next code fragment: | 145 | /* representative output of next code fragment: |
139 | * "PLL | PPSTIME" | 146 | * "PLL | PPSTIME" |
@@ -159,9 +166,11 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) | |||
159 | " time.tv_sec: %ld\n" | 166 | " time.tv_sec: %ld\n" |
160 | " time.tv_usec: %ld\n" | 167 | " time.tv_usec: %ld\n" |
161 | " return value: %d (%s)\n", | 168 | " return value: %d (%s)\n", |
162 | txc.constant, | 169 | txc.constant, |
163 | txc.precision, txc.tolerance, txc.tick, | 170 | txc.precision, txc.tolerance, txc.tick, |
164 | (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript); | 171 | (long)txc.time.tv_sec, (long)txc.time.tv_usec, |
172 | ret, descript | ||
173 | ); | ||
165 | } | 174 | } |
166 | 175 | ||
167 | return 0; | 176 | return 0; |
diff --git a/miscutils/chat.c b/miscutils/chat.c index 216a899a0..1446a040c 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c | |||
@@ -82,8 +82,8 @@ | |||
82 | //usage: "EXPECT [SEND [EXPECT [SEND...]]]" | 82 | //usage: "EXPECT [SEND [EXPECT [SEND...]]]" |
83 | //usage:#define chat_full_usage "\n\n" | 83 | //usage:#define chat_full_usage "\n\n" |
84 | //usage: "Useful for interacting with a modem connected to stdin/stdout.\n" | 84 | //usage: "Useful for interacting with a modem connected to stdin/stdout.\n" |
85 | //usage: "A script consists of one or more \"expect-send\" pairs of strings,\n" | 85 | //usage: "A script consists of \"expect-send\" argument pairs.\n" |
86 | //usage: "each pair is a pair of arguments. Example:\n" | 86 | //usage: "Example:\n" |
87 | //usage: "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" | 87 | //usage: "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" |
88 | 88 | ||
89 | #include "libbb.h" | 89 | #include "libbb.h" |
diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 47b9e7207..a0e0d4e4b 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c | |||
@@ -367,7 +367,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) | |||
367 | unsigned ttynum; | 367 | unsigned ttynum; |
368 | int poll_timeout_ms; | 368 | int poll_timeout_ms; |
369 | #if ENABLE_LONG_OPTS | 369 | #if ENABLE_LONG_OPTS |
370 | static const char getopt_longopts[] ALIGN1 = | 370 | static const char conspy_longopts[] ALIGN1 = |
371 | "viewonly\0" No_argument "v" | 371 | "viewonly\0" No_argument "v" |
372 | "createdevice\0" No_argument "c" | 372 | "createdevice\0" No_argument "c" |
373 | "neverquit\0" No_argument "Q" | 373 | "neverquit\0" No_argument "Q" |
@@ -377,8 +377,6 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) | |||
377 | "follow\0" No_argument "f" | 377 | "follow\0" No_argument "f" |
378 | "framebuffer\0" No_argument "F" | 378 | "framebuffer\0" No_argument "F" |
379 | ; | 379 | ; |
380 | |||
381 | applet_long_options = getopt_longopts; | ||
382 | #endif | 380 | #endif |
383 | #define keybuf bb_common_bufsiz1 | 381 | #define keybuf bb_common_bufsiz1 |
384 | setup_common_bufsiz(); | 382 | setup_common_bufsiz(); |
@@ -387,7 +385,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) | |||
387 | strcpy(G.vcsa_name, DEV_VCSA); | 385 | strcpy(G.vcsa_name, DEV_VCSA); |
388 | 386 | ||
389 | // numeric params | 387 | // numeric params |
390 | opts = getopt32(argv, "vcQsndfFx:+y:+", &G.x, &G.y); | 388 | opts = getopt32long(argv, "vcQsndfFx:+y:+", conspy_longopts, &G.x, &G.y); |
391 | argv += optind; | 389 | argv += optind; |
392 | ttynum = 0; | 390 | ttynum = 0; |
393 | if (argv[0]) { | 391 | if (argv[0]) { |
diff --git a/miscutils/crond.c b/miscutils/crond.c index 48e429976..f6580a9d4 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -1021,13 +1021,17 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
1021 | 1021 | ||
1022 | INIT_G(); | 1022 | INIT_G(); |
1023 | 1023 | ||
1024 | /* "-b after -f is ignored", and so on for every pair a-b */ | 1024 | opts = getopt32(argv, "^" |
1025 | opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") | 1025 | "l:L:fbSc:" IF_FEATURE_CROND_D("d:") |
1026 | "\0" | ||
1027 | /* "-b after -f is ignored", and so on for every pair a-b */ | ||
1028 | "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") | ||
1026 | /* -l and -d have numeric param */ | 1029 | /* -l and -d have numeric param */ |
1027 | ":l+" IF_FEATURE_CROND_D(":d+"); | 1030 | ":l+" IF_FEATURE_CROND_D(":d+") |
1028 | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), | 1031 | , |
1029 | &G.log_level, &G.log_filename, &G.crontab_dir_name | 1032 | &G.log_level, &G.log_filename, &G.crontab_dir_name |
1030 | IF_FEATURE_CROND_D(,&G.log_level)); | 1033 | IF_FEATURE_CROND_D(,&G.log_level) |
1034 | ); | ||
1031 | /* both -d N and -l N set the same variable: G.log_level */ | 1035 | /* both -d N and -l N set the same variable: G.log_level */ |
1032 | 1036 | ||
1033 | if (!(opts & OPT_f)) { | 1037 | if (!(opts & OPT_f)) { |
diff --git a/miscutils/crontab.c b/miscutils/crontab.c index 804cb57f2..4787fa08f 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c | |||
@@ -99,8 +99,9 @@ int crontab_main(int argc UNUSED_PARAM, char **argv) | |||
99 | OPT_ler = OPT_l + OPT_e + OPT_r, | 99 | OPT_ler = OPT_l + OPT_e + OPT_r, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | opt_complementary = "?1:dr"; /* max one argument; -d implies -r */ | 102 | opt_ler = getopt32(argv, "^" "u:c:lerd" "\0" "?1:dr"/*max one arg; -d implies -r*/, |
103 | opt_ler = getopt32(argv, "u:c:lerd", &user_name, &crontab_dir); | 103 | &user_name, &crontab_dir |
104 | ); | ||
104 | argv += optind; | 105 | argv += optind; |
105 | 106 | ||
106 | if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */ | 107 | if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */ |
diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index af9ebea24..a6ce41f27 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c | |||
@@ -17,6 +17,7 @@ | |||
17 | //config: This utility is used to erase the whole MTD device. | 17 | //config: This utility is used to erase the whole MTD device. |
18 | 18 | ||
19 | //applet:IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 19 | //applet:IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
20 | /* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ | ||
20 | 21 | ||
21 | //kbuild:lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o | 22 | //kbuild:lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o |
22 | 23 | ||
@@ -81,8 +82,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) | |||
81 | unsigned int flags; | 82 | unsigned int flags; |
82 | char *mtd_name; | 83 | char *mtd_name; |
83 | 84 | ||
84 | opt_complementary = "=1"; | 85 | flags = getopt32(argv, "^" "jNq" "\0" "=1"); |
85 | flags = getopt32(argv, "jNq"); | ||
86 | 86 | ||
87 | mtd_name = argv[optind]; | 87 | mtd_name = argv[optind]; |
88 | fd = xopen(mtd_name, O_RDWR); | 88 | fd = xopen(mtd_name, O_RDWR); |
diff --git a/miscutils/flash_lock_unlock.c b/miscutils/flash_lock_unlock.c index 374eed5f6..6f2c049f4 100644 --- a/miscutils/flash_lock_unlock.c +++ b/miscutils/flash_lock_unlock.c | |||
@@ -20,6 +20,7 @@ | |||
20 | // APPLET_ODDNAME:name main location suid_type help | 20 | // APPLET_ODDNAME:name main location suid_type help |
21 | //applet:IF_FLASH_LOCK( APPLET_ODDNAME(flash_lock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_lock)) | 21 | //applet:IF_FLASH_LOCK( APPLET_ODDNAME(flash_lock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_lock)) |
22 | //applet:IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_unlock)) | 22 | //applet:IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_unlock)) |
23 | /* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ | ||
23 | 24 | ||
24 | //kbuild:lib-$(CONFIG_FLASH_LOCK) += flash_lock_unlock.o | 25 | //kbuild:lib-$(CONFIG_FLASH_LOCK) += flash_lock_unlock.o |
25 | //kbuild:lib-$(CONFIG_FLASH_UNLOCK) += flash_lock_unlock.o | 26 | //kbuild:lib-$(CONFIG_FLASH_UNLOCK) += flash_lock_unlock.o |
diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c index d4ac62df4..858cee194 100644 --- a/miscutils/flashcp.c +++ b/miscutils/flashcp.c | |||
@@ -14,6 +14,7 @@ | |||
14 | //config: This utility is used to copy images into a MTD device. | 14 | //config: This utility is used to copy images into a MTD device. |
15 | 15 | ||
16 | //applet:IF_FLASHCP(APPLET(flashcp, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 16 | //applet:IF_FLASHCP(APPLET(flashcp, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
17 | /* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ | ||
17 | 18 | ||
18 | //kbuild:lib-$(CONFIG_FLASHCP) += flashcp.o | 19 | //kbuild:lib-$(CONFIG_FLASHCP) += flashcp.o |
19 | 20 | ||
@@ -68,8 +69,7 @@ int flashcp_main(int argc UNUSED_PARAM, char **argv) | |||
68 | RESERVE_CONFIG_UBUFFER(buf, BUFSIZE); | 69 | RESERVE_CONFIG_UBUFFER(buf, BUFSIZE); |
69 | RESERVE_CONFIG_UBUFFER(buf2, BUFSIZE); | 70 | RESERVE_CONFIG_UBUFFER(buf2, BUFSIZE); |
70 | 71 | ||
71 | opt_complementary = "=2"; /* exactly 2 non-option args: file, dev */ | 72 | /*opts =*/ getopt32(argv, "^" "v" "\0" "=2"/*exactly 2 non-option args: file,dev*/); |
72 | /*opts =*/ getopt32(argv, "v"); | ||
73 | argv += optind; | 73 | argv += optind; |
74 | // filename = *argv++; | 74 | // filename = *argv++; |
75 | // devicename = *argv; | 75 | // devicename = *argv; |
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index ca2580e92..30f606e8e 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c | |||
@@ -42,6 +42,7 @@ | |||
42 | //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 42 | //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
43 | //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 43 | //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
44 | //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 44 | //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
45 | /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ | ||
45 | 46 | ||
46 | //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o | 47 | //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o |
47 | //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o | 48 | //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o |
@@ -454,14 +455,12 @@ int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
454 | int i2cget_main(int argc UNUSED_PARAM, char **argv) | 455 | int i2cget_main(int argc UNUSED_PARAM, char **argv) |
455 | { | 456 | { |
456 | const unsigned opt_f = (1 << 0), opt_y = (1 << 1); | 457 | const unsigned opt_f = (1 << 0), opt_y = (1 << 1); |
457 | const char *const optstr = "fy"; | ||
458 | 458 | ||
459 | int bus_num, bus_addr, data_addr = -1, status; | 459 | int bus_num, bus_addr, data_addr = -1, status; |
460 | int mode = I2C_SMBUS_BYTE, pec = 0, fd; | 460 | int mode = I2C_SMBUS_BYTE, pec = 0, fd; |
461 | unsigned opts; | 461 | unsigned opts; |
462 | 462 | ||
463 | opt_complementary = "-2:?4"; /* from 2 to 4 args */ | 463 | opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/); |
464 | opts = getopt32(argv, optstr); | ||
465 | argv += optind; | 464 | argv += optind; |
466 | 465 | ||
467 | bus_num = i2c_bus_lookup(argv[0]); | 466 | bus_num = i2c_bus_lookup(argv[0]); |
@@ -543,7 +542,6 @@ int i2cset_main(int argc, char **argv) | |||
543 | { | 542 | { |
544 | const unsigned opt_f = (1 << 0), opt_y = (1 << 1), | 543 | const unsigned opt_f = (1 << 0), opt_y = (1 << 1), |
545 | opt_m = (1 << 2), opt_r = (1 << 3); | 544 | opt_m = (1 << 2), opt_r = (1 << 3); |
546 | const char *const optstr = "fym:r"; | ||
547 | 545 | ||
548 | int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0; | 546 | int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0; |
549 | int val, blen = 0, mask = 0, fd, status; | 547 | int val, blen = 0, mask = 0, fd, status; |
@@ -551,8 +549,7 @@ int i2cset_main(int argc, char **argv) | |||
551 | char *opt_m_arg = NULL; | 549 | char *opt_m_arg = NULL; |
552 | unsigned opts; | 550 | unsigned opts; |
553 | 551 | ||
554 | opt_complementary = "-3"; /* from 3 to ? args */ | 552 | opts = getopt32(argv, "^" "fym:r" "\0" "-3"/*from 3 to ? args*/, &opt_m_arg); |
555 | opts = getopt32(argv, optstr, &opt_m_arg); | ||
556 | argv += optind; | 553 | argv += optind; |
557 | argc -= optind; | 554 | argc -= optind; |
558 | 555 | ||
@@ -904,7 +901,6 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) | |||
904 | { | 901 | { |
905 | const unsigned opt_f = (1 << 0), opt_y = (1 << 1), | 902 | const unsigned opt_f = (1 << 0), opt_y = (1 << 1), |
906 | opt_r = (1 << 2); | 903 | opt_r = (1 << 2); |
907 | const char *const optstr = "fyr:"; | ||
908 | 904 | ||
909 | int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0; | 905 | int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0; |
910 | unsigned first = 0x00, last = 0xff, opts; | 906 | unsigned first = 0x00, last = 0xff, opts; |
@@ -912,8 +908,11 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) | |||
912 | char *opt_r_str, *dash; | 908 | char *opt_r_str, *dash; |
913 | int fd, res; | 909 | int fd, res; |
914 | 910 | ||
915 | opt_complementary = "-2:?3"; /* from 2 to 3 args */ | 911 | opts = getopt32(argv, "^" |
916 | opts = getopt32(argv, optstr, &opt_r_str); | 912 | "fyr:" |
913 | "\0" "-2:?3" /* from 2 to 3 args */, | ||
914 | &opt_r_str | ||
915 | ); | ||
917 | argv += optind; | 916 | argv += optind; |
918 | 917 | ||
919 | bus_num = i2c_bus_lookup(argv[0]); | 918 | bus_num = i2c_bus_lookup(argv[0]); |
@@ -1207,15 +1206,16 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) | |||
1207 | const unsigned opt_y = (1 << 0), opt_a = (1 << 1), | 1206 | const unsigned opt_y = (1 << 0), opt_a = (1 << 1), |
1208 | opt_q = (1 << 2), opt_r = (1 << 3), | 1207 | opt_q = (1 << 2), opt_r = (1 << 3), |
1209 | opt_F = (1 << 4), opt_l = (1 << 5); | 1208 | opt_F = (1 << 4), opt_l = (1 << 5); |
1210 | const char *const optstr = "yaqrFl"; | ||
1211 | 1209 | ||
1212 | int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd; | 1210 | int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd; |
1213 | unsigned first = 0x03, last = 0x77, opts; | 1211 | unsigned first = 0x03, last = 0x77, opts; |
1214 | unsigned long funcs; | 1212 | unsigned long funcs; |
1215 | 1213 | ||
1216 | opt_complementary = "q--r:r--q:" /* mutually exclusive */ | 1214 | opts = getopt32(argv, "^" |
1217 | "?3"; /* up to 3 args */ | 1215 | "yaqrFl" |
1218 | opts = getopt32(argv, optstr); | 1216 | "\0" |
1217 | "q--r:r--q:"/*mutually exclusive*/ "?3"/*up to 3 args*/ | ||
1218 | ); | ||
1219 | argv += optind; | 1219 | argv += optind; |
1220 | 1220 | ||
1221 | if (opts & opt_l) | 1221 | if (opts & opt_l) |
diff --git a/miscutils/lsscsi.c b/miscutils/lsscsi.c index b69ff1eef..d7cd51056 100644 --- a/miscutils/lsscsi.c +++ b/miscutils/lsscsi.c | |||
@@ -16,7 +16,7 @@ | |||
16 | //config: | 16 | //config: |
17 | //config: This version uses sysfs (/sys/bus/scsi/devices) only. | 17 | //config: This version uses sysfs (/sys/bus/scsi/devices) only. |
18 | 18 | ||
19 | //applet:IF_LSSCSI(APPLET(lsscsi, BB_DIR_USR_BIN, BB_SUID_DROP)) | 19 | //applet:IF_LSSCSI(APPLET_NOEXEC(lsscsi, lsscsi, BB_DIR_USR_BIN, BB_SUID_DROP, lsscsi)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_LSSCSI) += lsscsi.o | 21 | //kbuild:lib-$(CONFIG_LSSCSI) += lsscsi.o |
22 | 22 | ||
@@ -37,9 +37,8 @@ static char *get_line(const char *filename, char *buf, unsigned *bufsize_p) | |||
37 | if (sz < 0) | 37 | if (sz < 0) |
38 | sz = 0; | 38 | sz = 0; |
39 | buf[sz] = '\0'; | 39 | buf[sz] = '\0'; |
40 | trim(buf); | ||
41 | 40 | ||
42 | sz = strlen(buf) + 1; | 41 | sz = (trim(buf) - buf) + 1; |
43 | bufsize -= sz; | 42 | bufsize -= sz; |
44 | buf += sz; | 43 | buf += sz; |
45 | buf[0] = '\0'; | 44 | buf[0] = '\0'; |
diff --git a/miscutils/makedevs.c b/miscutils/makedevs.c index c2f86df01..80975c652 100644 --- a/miscutils/makedevs.c +++ b/miscutils/makedevs.c | |||
@@ -38,7 +38,7 @@ | |||
38 | //config: | 38 | //config: |
39 | //config:endchoice | 39 | //config:endchoice |
40 | 40 | ||
41 | //applet:IF_MAKEDEVS(APPLET(makedevs, BB_DIR_SBIN, BB_SUID_DROP)) | 41 | //applet:IF_MAKEDEVS(APPLET_NOEXEC(makedevs, makedevs, BB_DIR_SBIN, BB_SUID_DROP, makedevs)) |
42 | 42 | ||
43 | //kbuild:lib-$(CONFIG_MAKEDEVS) += makedevs.o | 43 | //kbuild:lib-$(CONFIG_MAKEDEVS) += makedevs.o |
44 | 44 | ||
@@ -183,8 +183,7 @@ int makedevs_main(int argc UNUSED_PARAM, char **argv) | |||
183 | char *line = (char *)"-"; | 183 | char *line = (char *)"-"; |
184 | int ret = EXIT_SUCCESS; | 184 | int ret = EXIT_SUCCESS; |
185 | 185 | ||
186 | opt_complementary = "=1"; /* exactly one param */ | 186 | getopt32(argv, "^" "d:" "\0" "=1", &line); |
187 | getopt32(argv, "d:", &line); | ||
188 | argv += optind; | 187 | argv += optind; |
189 | 188 | ||
190 | xchdir(*argv); /* ensure root dir exists */ | 189 | xchdir(*argv); /* ensure root dir exists */ |
diff --git a/miscutils/man.c b/miscutils/man.c index f68784767..68a75c6d7 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -257,8 +257,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
257 | 257 | ||
258 | INIT_G(); | 258 | INIT_G(); |
259 | 259 | ||
260 | opt_complementary = "-1"; /* at least one argument */ | 260 | opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/); |
261 | opt = getopt32(argv, "+aw"); | ||
262 | argv += optind; | 261 | argv += optind; |
263 | 262 | ||
264 | sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); | 263 | sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); |
diff --git a/miscutils/microcom.c b/miscutils/microcom.c index 14b9f3baf..b87f3273f 100644 --- a/miscutils/microcom.c +++ b/miscutils/microcom.c | |||
@@ -74,7 +74,9 @@ int microcom_main(int argc UNUSED_PARAM, char **argv) | |||
74 | unsigned opts; | 74 | unsigned opts; |
75 | 75 | ||
76 | // fetch options | 76 | // fetch options |
77 | opts = getopt32(argv, "Xs:+d:+t:+", &speed, &delay, &timeout); | 77 | opts = getopt32(argv, "^" "Xs:+d:+t:+" "\0" "=1", |
78 | &speed, &delay, &timeout | ||
79 | ); | ||
78 | // argc -= optind; | 80 | // argc -= optind; |
79 | argv += optind; | 81 | argv += optind; |
80 | 82 | ||
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 14b1ed056..80a005821 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c | |||
@@ -123,15 +123,12 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) | |||
123 | const char *opt_s = "0", *opt_f = "-", *opt_l, *opt_bb; | 123 | const char *opt_s = "0", *opt_f = "-", *opt_l, *opt_bb; |
124 | 124 | ||
125 | if (IS_NANDDUMP) { | 125 | if (IS_NANDDUMP) { |
126 | opt_complementary = "=1"; | 126 | opts = getopt32long(argv, "^" "ons:f:l:" "\0" "=1", |
127 | #if ENABLE_LONG_OPTS | 127 | "bb\0" Required_argument "\xff", /* no short equivalent */ |
128 | applet_long_options = | 128 | &opt_s, &opt_f, &opt_l, &opt_bb |
129 | "bb\0" Required_argument "\xff"; /* no short equivalent */ | 129 | ); |
130 | #endif | ||
131 | opts = getopt32(argv, "ons:f:l:", &opt_s, &opt_f, &opt_l, &opt_bb); | ||
132 | } else { /* nandwrite */ | 130 | } else { /* nandwrite */ |
133 | opt_complementary = "-1:?2"; | 131 | opts = getopt32(argv, "^" "pns:" "\0" "-1:?2", &opt_s); |
134 | opts = getopt32(argv, "pns:", &opt_s); | ||
135 | } | 132 | } |
136 | argv += optind; | 133 | argv += optind; |
137 | 134 | ||
diff --git a/miscutils/partprobe.c b/miscutils/partprobe.c index 2c12a7d20..d1ae27348 100644 --- a/miscutils/partprobe.c +++ b/miscutils/partprobe.c | |||
@@ -11,7 +11,7 @@ | |||
11 | //config: help | 11 | //config: help |
12 | //config: Ask kernel to rescan partition table. | 12 | //config: Ask kernel to rescan partition table. |
13 | 13 | ||
14 | //applet:IF_PARTPROBE(APPLET(partprobe, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 14 | //applet:IF_PARTPROBE(APPLET_NOEXEC(partprobe, partprobe, BB_DIR_USR_SBIN, BB_SUID_DROP, partprobe)) |
15 | 15 | ||
16 | //kbuild:lib-$(CONFIG_PARTPROBE) += partprobe.o | 16 | //kbuild:lib-$(CONFIG_PARTPROBE) += partprobe.o |
17 | 17 | ||
diff --git a/miscutils/raidautorun.c b/miscutils/raidautorun.c index ecedf9ce2..caf6e0821 100644 --- a/miscutils/raidautorun.c +++ b/miscutils/raidautorun.c | |||
@@ -15,7 +15,7 @@ | |||
15 | //config: raidautorun tells the kernel md driver to | 15 | //config: raidautorun tells the kernel md driver to |
16 | //config: search and start RAID arrays. | 16 | //config: search and start RAID arrays. |
17 | 17 | ||
18 | //applet:IF_RAIDAUTORUN(APPLET(raidautorun, BB_DIR_SBIN, BB_SUID_DROP)) | 18 | //applet:IF_RAIDAUTORUN(APPLET_NOEXEC(raidautorun, raidautorun, BB_DIR_SBIN, BB_SUID_DROP, raidautorun)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o | 20 | //kbuild:lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o |
21 | 21 | ||
diff --git a/miscutils/runlevel.c b/miscutils/runlevel.c index 6b4742255..0b2098564 100644 --- a/miscutils/runlevel.c +++ b/miscutils/runlevel.c | |||
@@ -21,7 +21,7 @@ | |||
21 | //config: This applet uses utmp but does not rely on busybox supporing | 21 | //config: This applet uses utmp but does not rely on busybox supporing |
22 | //config: utmp on purpose. It is used by e.g. emdebian via /etc/init.d/rc. | 22 | //config: utmp on purpose. It is used by e.g. emdebian via /etc/init.d/rc. |
23 | 23 | ||
24 | //applet:IF_RUNLEVEL(APPLET(runlevel, BB_DIR_SBIN, BB_SUID_DROP)) | 24 | //applet:IF_RUNLEVEL(APPLET_NOEXEC(runlevel, runlevel, BB_DIR_SBIN, BB_SUID_DROP, runlevel)) |
25 | 25 | ||
26 | //kbuild:lib-$(CONFIG_RUNLEVEL) += runlevel.o | 26 | //kbuild:lib-$(CONFIG_RUNLEVEL) += runlevel.o |
27 | 27 | ||
diff --git a/miscutils/setserial.c b/miscutils/setserial.c index 28a1bef18..f217c3beb 100644 --- a/miscutils/setserial.c +++ b/miscutils/setserial.c | |||
@@ -15,7 +15,7 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: Retrieve or set Linux serial port. | 16 | //config: Retrieve or set Linux serial port. |
17 | 17 | ||
18 | //applet:IF_SETSERIAL(APPLET(setserial, BB_DIR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_SETSERIAL(APPLET_NOEXEC(setserial, setserial, BB_DIR_BIN, BB_SUID_DROP, setserial)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o | 20 | //kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o |
21 | 21 | ||
@@ -210,35 +210,35 @@ struct serial_struct { | |||
210 | #endif | 210 | #endif |
211 | 211 | ||
212 | //usage:#define setserial_trivial_usage | 212 | //usage:#define setserial_trivial_usage |
213 | //usage: "[-gabGvzV] DEVICE [PARAMETER [ARG]]..." | 213 | //usage: "[-abGvz] { DEVICE [PARAMETER [ARG]]... | -g DEVICE... }" |
214 | //usage:#define setserial_full_usage "\n\n" | 214 | //usage:#define setserial_full_usage "\n\n" |
215 | //usage: "Request or set Linux serial port information\n" | 215 | //usage: "Print or set serial port parameters" |
216 | //usage: "\n" | 216 | //usage: "\n" |
217 | //usage: " -g Interpret parameters as list of devices for reporting\n" | 217 | //usage: "\n"" -a Print all" |
218 | //usage: " -a Print all available information\n" | 218 | //usage: "\n"" -b Print summary" |
219 | //usage: " -b Print summary information\n" | 219 | //usage: "\n"" -G Print as setserial PARAMETERs" |
220 | //usage: " -G Print in form which can be fed back\n" | 220 | //usage: "\n"" -v Verbose" |
221 | //usage: " to setserial as command line parameters\n" | 221 | //usage: "\n"" -z Zero out serial flags before setting" |
222 | //usage: " -z Zero out serial flags before setting\n" | 222 | //usage: "\n"" -g All args are device names" |
223 | //usage: " -v Verbose\n" | 223 | //usage: "\n" |
224 | //usage: "\n" | 224 | //usage: "\n""PARAMETERs: (* = takes ARG, ^ = can be turned off by preceding ^)" |
225 | //usage: "Parameters: (* = takes an argument, ^ = can be turned off by preceding ^)\n" | 225 | //usage: "\n"" *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait," |
226 | //usage: " *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait,\n" | 226 | //usage: "\n"" ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout," |
227 | //usage: " ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,\n" | 227 | //usage: "\n"" ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig," |
228 | //usage: " ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,\n" | 228 | //usage: "\n"" spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust" |
229 | //usage: " spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust\n" | 229 | //usage: "\n""ARG for uart:" |
230 | //usage: "\n" | 230 | //usage: "\n"" unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750," |
231 | //usage: "UART types:\n" | 231 | //usage: "\n"" 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7," |
232 | //usage: " unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,\n" | 232 | //usage: "\n"" U6_16550A" |
233 | //usage: " 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,\n" | 233 | |
234 | //usage: " U6_16550A" | 234 | // option string is "bGavzgq". "q" is accepted but ignored. |
235 | |||
236 | #define OPT_PRINT_SUMMARY (1 << 0) | 235 | #define OPT_PRINT_SUMMARY (1 << 0) |
237 | #define OPT_PRINT_FEDBACK (1 << 1) | 236 | #define OPT_PRINT_FEDBACK (1 << 1) |
238 | #define OPT_PRINT_ALL (1 << 2) | 237 | #define OPT_PRINT_ALL (1 << 2) |
239 | #define OPT_VERBOSE (1 << 3) | 238 | #define OPT_VERBOSE (1 << 3) |
240 | #define OPT_ZERO (1 << 4) | 239 | #define OPT_ZERO (1 << 4) |
241 | #define OPT_GET (1 << 5) | 240 | #define OPT_LIST_OF_DEVS (1 << 5) |
241 | /*#define OPT_QUIET (1 << 6)*/ | ||
242 | 242 | ||
243 | #define OPT_MODE_MASK \ | 243 | #define OPT_MODE_MASK \ |
244 | (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK) | 244 | (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK) |
@@ -362,7 +362,7 @@ static bool cmd_is_flag(int cmd) | |||
362 | return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST); | 362 | return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST); |
363 | } | 363 | } |
364 | 364 | ||
365 | static bool cmd_need_arg(int cmd) | 365 | static bool cmd_needs_arg(int cmd) |
366 | { | 366 | { |
367 | return (cmd >= CMD_PORT && cmd <= CMD_WAIT); | 367 | return (cmd >= CMD_PORT && cmd <= CMD_WAIT); |
368 | } | 368 | } |
@@ -652,11 +652,9 @@ static int find_cmd(const char *cmd) | |||
652 | static void serial_set(char **arg, int opts) | 652 | static void serial_set(char **arg, int opts) |
653 | { | 653 | { |
654 | struct serial_struct serinfo; | 654 | struct serial_struct serinfo; |
655 | int cmd; | ||
656 | const char *word; | ||
657 | int fd; | 655 | int fd; |
658 | 656 | ||
659 | fd = serial_open(*arg++, /*quiet:*/ false); | 657 | fd = serial_open(*arg, /*quiet:*/ false); |
660 | if (fd < 0) | 658 | if (fd < 0) |
661 | exit(201); | 659 | exit(201); |
662 | 660 | ||
@@ -665,17 +663,20 @@ static void serial_set(char **arg, int opts) | |||
665 | if (opts & OPT_ZERO) | 663 | if (opts & OPT_ZERO) |
666 | serinfo.flags = 0; | 664 | serinfo.flags = 0; |
667 | 665 | ||
668 | while (*arg) { | 666 | while (*++arg) { |
667 | const char *word; | ||
669 | int invert; | 668 | int invert; |
669 | int cmd; | ||
670 | 670 | ||
671 | word = *arg++; | 671 | word = *arg; |
672 | invert = (*word == '^'); | 672 | invert = (word[0] == '^'); |
673 | word += invert; | 673 | word += invert; |
674 | 674 | ||
675 | cmd = find_cmd(word); | 675 | cmd = find_cmd(word); |
676 | 676 | ||
677 | if (*arg == NULL && cmd_need_arg(cmd)) | 677 | if (cmd_needs_arg(cmd)) |
678 | bb_error_msg_and_die(bb_msg_requires_arg, word); | 678 | if (*++arg == NULL) |
679 | bb_error_msg_and_die(bb_msg_requires_arg, word); | ||
679 | 680 | ||
680 | if (invert && !cmd_is_flag(cmd)) | 681 | if (invert && !cmd_is_flag(cmd)) |
681 | bb_error_msg_and_die("can't invert %s", word); | 682 | bb_error_msg_and_die("can't invert %s", word); |
@@ -705,25 +706,25 @@ static void serial_set(char **arg, int opts) | |||
705 | serinfo.flags |= setbits[cmd]; | 706 | serinfo.flags |= setbits[cmd]; |
706 | break; | 707 | break; |
707 | case CMD_PORT: | 708 | case CMD_PORT: |
708 | serinfo.port = get_numeric(*arg++); | 709 | serinfo.port = get_numeric(*arg); |
709 | break; | 710 | break; |
710 | case CMD_IRQ: | 711 | case CMD_IRQ: |
711 | serinfo.irq = get_numeric(*arg++); | 712 | serinfo.irq = get_numeric(*arg); |
712 | break; | 713 | break; |
713 | case CMD_DIVISOR: | 714 | case CMD_DIVISOR: |
714 | serinfo.custom_divisor = get_numeric(*arg++); | 715 | serinfo.custom_divisor = get_numeric(*arg); |
715 | break; | 716 | break; |
716 | case CMD_UART: | 717 | case CMD_UART: |
717 | serinfo.type = get_uart(*arg++); | 718 | serinfo.type = get_uart(*arg); |
718 | break; | 719 | break; |
719 | case CMD_BASE: | 720 | case CMD_BASE: |
720 | serinfo.baud_base = get_numeric(*arg++); | 721 | serinfo.baud_base = get_numeric(*arg); |
721 | break; | 722 | break; |
722 | case CMD_DELAY: | 723 | case CMD_DELAY: |
723 | serinfo.close_delay = get_numeric(*arg++); | 724 | serinfo.close_delay = get_numeric(*arg); |
724 | break; | 725 | break; |
725 | case CMD_WAIT: | 726 | case CMD_WAIT: |
726 | serinfo.closing_wait = get_wait(*arg++); | 727 | serinfo.closing_wait = get_wait(*arg); |
727 | break; | 728 | break; |
728 | case CMD_AUTOCONFIG: | 729 | case CMD_AUTOCONFIG: |
729 | serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo); | 730 | serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo); |
@@ -741,22 +742,22 @@ int setserial_main(int argc UNUSED_PARAM, char **argv) | |||
741 | { | 742 | { |
742 | int opts; | 743 | int opts; |
743 | 744 | ||
744 | opt_complementary = "-1:b-aG:G-ab:a-bG"; | 745 | opts = getopt32(argv, "^" "bGavzgq" "\0" "-1:b-aG:G-ab:a-bG"); |
745 | opts = getopt32(argv, "bGavzg"); | ||
746 | argv += optind; | 746 | argv += optind; |
747 | 747 | ||
748 | if (!argv[1]) /* one arg only? */ | 748 | if (!argv[1]) /* one arg only? (nothing to change?) */ |
749 | opts |= OPT_GET; | 749 | opts |= OPT_LIST_OF_DEVS; /* force display */ |
750 | 750 | ||
751 | if (!(opts & OPT_GET)) { | 751 | if (!(opts & OPT_LIST_OF_DEVS)) { |
752 | serial_set(argv, opts); | 752 | serial_set(argv, opts); |
753 | argv[1] = NULL; | 753 | argv[1] = NULL; |
754 | } | 754 | } |
755 | 755 | ||
756 | if (opts & (OPT_VERBOSE | OPT_GET)) { | 756 | /* -v effect: "after setting params, do not be silent, show them" */ |
757 | if (opts & (OPT_VERBOSE | OPT_LIST_OF_DEVS)) { | ||
757 | do { | 758 | do { |
758 | serial_get(*argv++, opts & OPT_MODE_MASK); | 759 | serial_get(*argv, opts & OPT_MODE_MASK); |
759 | } while (*argv); | 760 | } while (*++argv); |
760 | } | 761 | } |
761 | 762 | ||
762 | return EXIT_SUCCESS; | 763 | return EXIT_SUCCESS; |
diff --git a/miscutils/time.c b/miscutils/time.c index 60fc11f6e..65dbcdcf3 100644 --- a/miscutils/time.c +++ b/miscutils/time.c | |||
@@ -127,13 +127,13 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages) | |||
127 | 127 | ||
128 | /* summarize: Report on the system use of a command. | 128 | /* summarize: Report on the system use of a command. |
129 | 129 | ||
130 | Print the FMT argument except that `%' sequences | 130 | Print the FMT argument except that '%' sequences |
131 | have special meaning, and `\n' and `\t' are translated into | 131 | have special meaning, and '\n' and '\t' are translated into |
132 | newline and tab, respectively, and `\\' is translated into `\'. | 132 | newline and tab, respectively, and '\\' is translated into '\'. |
133 | 133 | ||
134 | The character following a `%' can be: | 134 | The character following a '%' can be: |
135 | (* means the tcsh time builtin also recognizes it) | 135 | (* means the tcsh time builtin also recognizes it) |
136 | % == a literal `%' | 136 | % == a literal '%' |
137 | C == command name and arguments | 137 | C == command name and arguments |
138 | * D == average unshared data size in K (ru_idrss+ru_isrss) | 138 | * D == average unshared data size in K (ru_idrss+ru_isrss) |
139 | * E == elapsed real (wall clock) time in [hour:]min:sec | 139 | * E == elapsed real (wall clock) time in [hour:]min:sec |
@@ -430,9 +430,10 @@ int time_main(int argc UNUSED_PARAM, char **argv) | |||
430 | OPT_f = (1 << 4), | 430 | OPT_f = (1 << 4), |
431 | }; | 431 | }; |
432 | 432 | ||
433 | opt_complementary = "-1"; /* at least one arg */ | ||
434 | /* "+": stop on first non-option */ | 433 | /* "+": stop on first non-option */ |
435 | opt = getopt32(argv, "+vpao:f:", &output_filename, &output_format); | 434 | opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, |
435 | &output_filename, &output_format | ||
436 | ); | ||
436 | argv += optind; | 437 | argv += optind; |
437 | if (opt & OPT_v) | 438 | if (opt & OPT_v) |
438 | output_format = long_format; | 439 | output_format = long_format; |
diff --git a/miscutils/ttysize.c b/miscutils/ttysize.c index 7f6a84308..2c2d4ec33 100644 --- a/miscutils/ttysize.c +++ b/miscutils/ttysize.c | |||
@@ -18,7 +18,7 @@ | |||
18 | //config: error, but returns default 80x24. | 18 | //config: error, but returns default 80x24. |
19 | //config: Usage in shell scripts: width=`ttysize w`. | 19 | //config: Usage in shell scripts: width=`ttysize w`. |
20 | 20 | ||
21 | //applet:IF_TTYSIZE(APPLET(ttysize, BB_DIR_USR_BIN, BB_SUID_DROP)) | 21 | //applet:IF_TTYSIZE(APPLET_NOFORK(ttysize, ttysize, BB_DIR_USR_BIN, BB_SUID_DROP, ttysize)) |
22 | 22 | ||
23 | //kbuild:lib-$(CONFIG_TTYSIZE) += ttysize.o | 23 | //kbuild:lib-$(CONFIG_TTYSIZE) += ttysize.o |
24 | 24 | ||
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index c6ba22adf..d142d1144 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c | |||
@@ -52,6 +52,7 @@ | |||
52 | //applet:IF_UBIRMVOL( APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) | 52 | //applet:IF_UBIRMVOL( APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) |
53 | //applet:IF_UBIRSVOL( APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) | 53 | //applet:IF_UBIRSVOL( APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) |
54 | //applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol)) | 54 | //applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol)) |
55 | /* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ | ||
55 | 56 | ||
56 | //kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o | 57 | //kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o |
57 | //kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o | 58 | //kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o |
@@ -67,23 +68,32 @@ | |||
67 | #endif | 68 | #endif |
68 | #include <mtd/ubi-user.h> | 69 | #include <mtd/ubi-user.h> |
69 | 70 | ||
70 | #define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') | 71 | #define UBI_APPLET_CNT (0 \ |
71 | #define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') | 72 | + ENABLE_UBIATTACH \ |
72 | #define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') | 73 | + ENABLE_UBIDETACH \ |
73 | #define do_rmvol (ENABLE_UBIRMVOL && applet_name[4] == 'm') | 74 | + ENABLE_UBIMKVOL \ |
74 | #define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') | 75 | + ENABLE_UBIRMVOL \ |
75 | #define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u') | 76 | + ENABLE_UBIRSVOL \ |
76 | 77 | + ENABLE_UBIUPDATEVOL \ | |
77 | static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg) | 78 | ) |
79 | |||
80 | #define do_attach (ENABLE_UBIATTACH && (UBI_APPLET_CNT == 1 || applet_name[4] == 't')) | ||
81 | #define do_detach (ENABLE_UBIDETACH && (UBI_APPLET_CNT == 1 || applet_name[4] == 'e')) | ||
82 | #define do_mkvol (ENABLE_UBIMKVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'k')) | ||
83 | #define do_rmvol (ENABLE_UBIRMVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'm')) | ||
84 | #define do_rsvol (ENABLE_UBIRSVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 's')) | ||
85 | #define do_update (ENABLE_UBIUPDATEVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'p')) | ||
86 | |||
87 | static unsigned get_num_from_file(const char *path, unsigned max) | ||
78 | { | 88 | { |
79 | char buf[sizeof(long long)*3]; | 89 | char buf[sizeof(long long)*3]; |
80 | unsigned long long num; | 90 | unsigned long long num; |
81 | 91 | ||
82 | if (open_read_close(path, buf, sizeof(buf)) < 0) | 92 | if (open_read_close(path, buf, sizeof(buf)) < 0) |
83 | bb_perror_msg_and_die(errmsg, path); | 93 | bb_perror_msg_and_die("can't open '%s'", path); |
84 | /* It can be \n terminated, xatoull won't work well */ | 94 | /* It can be \n terminated, xatoull won't work well */ |
85 | if (sscanf(buf, "%llu", &num) != 1 || num > max) | 95 | if (sscanf(buf, "%llu", &num) != 1 || num > max) |
86 | bb_error_msg_and_die(errmsg, path); | 96 | bb_error_msg_and_die("number in '%s' is malformed or too large", path); |
87 | return num; | 97 | return num; |
88 | } | 98 | } |
89 | 99 | ||
@@ -135,20 +145,17 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
135 | #define OPTION_a (1 << 5) | 145 | #define OPTION_a (1 << 5) |
136 | #define OPTION_t (1 << 6) | 146 | #define OPTION_t (1 << 6) |
137 | if (do_mkvol) { | 147 | if (do_mkvol) { |
138 | opt_complementary = "-1"; | 148 | opts = getopt32(argv, "^" "md:+n:+N:s:a:+t:O:+" "\0" "-1", |
139 | opts = getopt32(argv, "md:+n:+N:s:a:+t:O:+", | ||
140 | &dev_num, &vol_id, | 149 | &dev_num, &vol_id, |
141 | &vol_name, &size_bytes_str, &alignment, &type, | 150 | &vol_name, &size_bytes_str, &alignment, &type, |
142 | &vid_hdr_offset | 151 | &vid_hdr_offset |
143 | ); | 152 | ); |
144 | } else | 153 | } else |
145 | if (do_update) { | 154 | if (do_update) { |
146 | opt_complementary = "-1"; | 155 | opts = getopt32(argv, "^" "s:at" "\0" "-1", &size_bytes_str); |
147 | opts = getopt32(argv, "s:at", &size_bytes_str); | ||
148 | opts *= OPTION_s; | 156 | opts *= OPTION_s; |
149 | } else { | 157 | } else { |
150 | opt_complementary = "-1"; | 158 | opts = getopt32(argv, "^" "m:+d:+n:+N:s:a:+t:" "\0" "-1", |
151 | opts = getopt32(argv, "m:+d:+n:+N:s:a:+t:", | ||
152 | &mtd_num, &dev_num, &vol_id, | 159 | &mtd_num, &dev_num, &vol_id, |
153 | &vol_name, &size_bytes_str, &alignment, &type | 160 | &vol_name, &size_bytes_str, &alignment, &type |
154 | ); | 161 | ); |
@@ -217,10 +224,10 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
217 | p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num); | 224 | p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num); |
218 | 225 | ||
219 | strcpy(p, "avail_eraseblocks"); | 226 | strcpy(p, "avail_eraseblocks"); |
220 | leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'"); | 227 | leb_avail = get_num_from_file(path, UINT_MAX); |
221 | 228 | ||
222 | strcpy(p, "eraseblock_size"); | 229 | strcpy(p, "eraseblock_size"); |
223 | leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'"); | 230 | leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK); |
224 | 231 | ||
225 | size_bytes = leb_avail * (unsigned long long)leb_size; | 232 | size_bytes = leb_avail * (unsigned long long)leb_size; |
226 | //if (size_bytes <= 0) | 233 | //if (size_bytes <= 0) |
@@ -232,16 +239,19 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
232 | if (!(opts & OPTION_N)) | 239 | if (!(opts & OPTION_N)) |
233 | bb_error_msg_and_die("name not specified"); | 240 | bb_error_msg_and_die("name not specified"); |
234 | 241 | ||
242 | /* the structure is memset(0) above */ | ||
235 | mkvol_req.vol_id = vol_id; | 243 | mkvol_req.vol_id = vol_id; |
236 | mkvol_req.vol_type = UBI_DYNAMIC_VOLUME; | 244 | mkvol_req.vol_type = UBI_DYNAMIC_VOLUME; |
237 | if ((opts & OPTION_t) && type[0] == 's') | 245 | if ((opts & OPTION_t) && type[0] == 's') |
238 | mkvol_req.vol_type = UBI_STATIC_VOLUME; | 246 | mkvol_req.vol_type = UBI_STATIC_VOLUME; |
239 | mkvol_req.alignment = alignment; | 247 | mkvol_req.alignment = alignment; |
240 | mkvol_req.bytes = size_bytes; /* signed int64_t */ | 248 | mkvol_req.bytes = size_bytes; /* signed int64_t */ |
241 | strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME); | 249 | /* strnlen avoids overflow of 16-bit field (paranoia) */ |
242 | mkvol_req.name_len = strlen(vol_name); | 250 | mkvol_req.name_len = strnlen(vol_name, UBI_MAX_VOLUME_NAME+1); |
243 | if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME) | 251 | if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME) |
244 | bb_error_msg_and_die("volume name too long: '%s'", vol_name); | 252 | bb_error_msg_and_die("volume name too long: '%s'", vol_name); |
253 | /* this is safe: .name[] is UBI_MAX_VOLUME_NAME+1 bytes */ | ||
254 | strcpy(mkvol_req.name, vol_name); | ||
245 | 255 | ||
246 | xioctl(fd, UBI_IOCMKVOL, &mkvol_req); | 256 | xioctl(fd, UBI_IOCMKVOL, &mkvol_req); |
247 | } else | 257 | } else |
@@ -289,7 +299,7 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
289 | } else | 299 | } else |
290 | 300 | ||
291 | //usage:#define ubiupdatevol_trivial_usage | 301 | //usage:#define ubiupdatevol_trivial_usage |
292 | //usage: "[-t | [-s SIZE] IMG_FILE] UBI_DEVICE" | 302 | //usage: "-t UBI_DEVICE | [-s SIZE] UBI_DEVICE IMG_FILE" |
293 | //usage:#define ubiupdatevol_full_usage "\n\n" | 303 | //usage:#define ubiupdatevol_full_usage "\n\n" |
294 | //usage: "Update UBI volume\n" | 304 | //usage: "Update UBI volume\n" |
295 | //usage: "\n -t Truncate to zero size" | 305 | //usage: "\n -t Truncate to zero size" |
@@ -304,24 +314,25 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
304 | xioctl(fd, UBI_IOCVOLUP, &bytes64); | 314 | xioctl(fd, UBI_IOCVOLUP, &bytes64); |
305 | } | 315 | } |
306 | else { | 316 | else { |
307 | struct stat st; | ||
308 | unsigned ubinum, volnum; | 317 | unsigned ubinum, volnum; |
309 | unsigned leb_size; | 318 | unsigned leb_size; |
310 | ssize_t len; | 319 | char *buf; |
311 | char *input_data; | ||
312 | 320 | ||
313 | /* Assume that device is in normal format. */ | 321 | /* Assume that device is in normal format. */ |
314 | /* Removes need for scanning sysfs tree as full libubi does. */ | 322 | /* Removes need for scanning sysfs tree as full libubi does. */ |
315 | if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) | 323 | if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) |
316 | bb_error_msg_and_die("wrong format of UBI device name"); | 324 | bb_error_msg_and_die("UBI device name '%s' is not /dev/ubiN_M", ubi_ctrl); |
317 | 325 | ||
318 | sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum); | 326 | sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum); |
319 | leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'"); | 327 | leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK); |
320 | 328 | ||
321 | if (!(opts & OPTION_s)) { | 329 | if (!*argv) |
322 | if (!*argv) | 330 | bb_show_usage(); |
323 | bb_show_usage(); | 331 | if (NOT_LONE_DASH(*argv)) /* mtd-utils supports "-" as stdin */ |
324 | xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); | 332 | xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); |
333 | |||
334 | if (!(opts & OPTION_s)) { | ||
335 | struct stat st; | ||
325 | xfstat(STDIN_FILENO, &st, *argv); | 336 | xfstat(STDIN_FILENO, &st, *argv); |
326 | size_bytes = st.st_size; | 337 | size_bytes = st.st_size; |
327 | } | 338 | } |
@@ -330,12 +341,24 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
330 | /* this ioctl expects signed int64_t* parameter */ | 341 | /* this ioctl expects signed int64_t* parameter */ |
331 | xioctl(fd, UBI_IOCVOLUP, &bytes64); | 342 | xioctl(fd, UBI_IOCVOLUP, &bytes64); |
332 | 343 | ||
333 | input_data = xmalloc(leb_size); | 344 | /* can't use bb_copyfd_exact_size(): copy in blocks of exactly leb_size */ |
334 | while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) { | 345 | buf = xmalloc(leb_size); |
335 | xwrite(fd, input_data, len); | 346 | while (size_bytes != 0) { |
347 | int len = full_read(STDIN_FILENO, buf, leb_size); | ||
348 | if (len <= 0) { | ||
349 | if (len < 0) | ||
350 | bb_perror_msg_and_die("read error from '%s'", *argv); | ||
351 | break; | ||
352 | } | ||
353 | if ((unsigned)len > size_bytes) { | ||
354 | /* for this case: "ubiupdatevol -s 1024000 $UBIDEV /dev/urandom" */ | ||
355 | len = size_bytes; | ||
356 | } | ||
357 | xwrite(fd, buf, len); | ||
358 | size_bytes -= len; | ||
336 | } | 359 | } |
337 | if (len < 0) | 360 | if (ENABLE_FEATURE_CLEAN_UP) |
338 | bb_perror_msg_and_die("UBI volume update failed"); | 361 | free(buf); |
339 | } | 362 | } |
340 | } | 363 | } |
341 | 364 | ||
diff --git a/miscutils/ubirename.c b/miscutils/ubirename.c index 786c4b9fa..ecc8fe137 100644 --- a/miscutils/ubirename.c +++ b/miscutils/ubirename.c | |||
@@ -14,6 +14,7 @@ | |||
14 | //config: Utility to rename UBI volumes | 14 | //config: Utility to rename UBI volumes |
15 | 15 | ||
16 | //applet:IF_UBIRENAME(APPLET(ubirename, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 16 | //applet:IF_UBIRENAME(APPLET(ubirename, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
17 | /* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ | ||
17 | 18 | ||
18 | //kbuild:lib-$(CONFIG_UBIRENAME) += ubirename.o | 19 | //kbuild:lib-$(CONFIG_UBIRENAME) += ubirename.o |
19 | 20 | ||
@@ -80,9 +81,12 @@ int ubirename_main(int argc, char **argv) | |||
80 | argv += 2; | 81 | argv += 2; |
81 | while (argv[0]) { | 82 | while (argv[0]) { |
82 | rnvol->ents[n].vol_id = ubi_get_volid_by_name(ubi_devnum, argv[0]); | 83 | rnvol->ents[n].vol_id = ubi_get_volid_by_name(ubi_devnum, argv[0]); |
83 | rnvol->ents[n].name_len = strlen(argv[1]); | 84 | |
85 | /* strnlen avoids overflow of 16-bit field (paranoia) */ | ||
86 | rnvol->ents[n].name_len = strnlen(argv[1], sizeof(rnvol->ents[n].name)); | ||
84 | if (rnvol->ents[n].name_len >= sizeof(rnvol->ents[n].name)) | 87 | if (rnvol->ents[n].name_len >= sizeof(rnvol->ents[n].name)) |
85 | bb_error_msg_and_die("new name '%s' is too long", argv[1]); | 88 | bb_error_msg_and_die("new name '%s' is too long", argv[1]); |
89 | |||
86 | strcpy(rnvol->ents[n].name, argv[1]); | 90 | strcpy(rnvol->ents[n].name, argv[1]); |
87 | n++; | 91 | n++; |
88 | argv += 2; | 92 | argv += 2; |
diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index ec06bcb51..392d05646 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c | |||
@@ -101,8 +101,9 @@ int watchdog_main(int argc UNUSED_PARAM, char **argv) | |||
101 | char *st_arg; | 101 | char *st_arg; |
102 | char *ht_arg; | 102 | char *ht_arg; |
103 | 103 | ||
104 | opt_complementary = "=1"; /* must have exactly 1 argument */ | 104 | opts = getopt32(argv, "^" "Ft:T:" "\0" "=1"/*must have exactly 1 arg*/, |
105 | opts = getopt32(argv, "Ft:T:", &st_arg, &ht_arg); | 105 | &st_arg, &ht_arg |
106 | ); | ||
106 | 107 | ||
107 | /* We need to daemonize *before* opening the watchdog as many drivers | 108 | /* We need to daemonize *before* opening the watchdog as many drivers |
108 | * will only allow one process at a time to do so. Since daemonizing | 109 | * will only allow one process at a time to do so. Since daemonizing |
diff --git a/modutils/insmod.c b/modutils/insmod.c index b8ede8a81..4dc0b6608 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c | |||
@@ -13,7 +13,7 @@ | |||
13 | //config: help | 13 | //config: help |
14 | //config: insmod is used to load specified modules in the running kernel. | 14 | //config: insmod is used to load specified modules in the running kernel. |
15 | 15 | ||
16 | //applet:IF_INSMOD(IF_NOT_MODPROBE_SMALL(APPLET(insmod, BB_DIR_SBIN, BB_SUID_DROP))) | 16 | //applet:IF_INSMOD(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(insmod, insmod, BB_DIR_SBIN, BB_SUID_DROP, insmod))) |
17 | 17 | ||
18 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) | 18 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) |
19 | //kbuild:lib-$(CONFIG_INSMOD) += insmod.o modutils.o | 19 | //kbuild:lib-$(CONFIG_INSMOD) += insmod.o modutils.o |
diff --git a/modutils/lsmod.c b/modutils/lsmod.c index 4bf8f8481..84860cd79 100644 --- a/modutils/lsmod.c +++ b/modutils/lsmod.c | |||
@@ -23,7 +23,7 @@ | |||
23 | //config: the format of module-init-tools for Linux kernel 2.6. | 23 | //config: the format of module-init-tools for Linux kernel 2.6. |
24 | //config: Increases size somewhat. | 24 | //config: Increases size somewhat. |
25 | 25 | ||
26 | //applet:IF_LSMOD(IF_NOT_MODPROBE_SMALL(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP))) | 26 | //applet:IF_LSMOD(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(lsmod, lsmod, BB_DIR_SBIN, BB_SUID_DROP, lsmod))) |
27 | 27 | ||
28 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) | 28 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) |
29 | //kbuild:lib-$(CONFIG_LSMOD) += lsmod.o modutils.o | 29 | //kbuild:lib-$(CONFIG_LSMOD) += lsmod.o modutils.o |
diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 371c93991..3f91622a9 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c | |||
@@ -12,7 +12,7 @@ | |||
12 | //config: help | 12 | //config: help |
13 | //config: Show information about a Linux Kernel module | 13 | //config: Show information about a Linux Kernel module |
14 | 14 | ||
15 | //applet:IF_MODINFO(APPLET(modinfo, BB_DIR_SBIN, BB_SUID_DROP)) | 15 | //applet:IF_MODINFO(APPLET_NOEXEC(modinfo, modinfo, BB_DIR_SBIN, BB_SUID_DROP, modinfo)) |
16 | 16 | ||
17 | //kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o | 17 | //kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o |
18 | 18 | ||
@@ -148,8 +148,7 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv) | |||
148 | unsigned i; | 148 | unsigned i; |
149 | 149 | ||
150 | field = NULL; | 150 | field = NULL; |
151 | opt_complementary = "-1"; /* minimum one param */ | 151 | opts = getopt32(argv, "^" "0F:nadlp" "\0" "-1"/*minimum one arg*/, &field); |
152 | opts = getopt32(argv, "0F:nadlp", &field); | ||
153 | /* If no field selected, show all */ | 152 | /* If no field selected, show all */ |
154 | if (!(opts & (OPT_TAGS|OPT_F))) | 153 | if (!(opts & (OPT_TAGS|OPT_F))) |
155 | option_mask32 |= OPT_TAGS; | 154 | option_mask32 |= OPT_TAGS; |
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 053a7df89..a94b0b9a6 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c | |||
@@ -11,12 +11,15 @@ | |||
11 | /* modprobe-small configs are defined in Config.src to ensure better | 11 | /* modprobe-small configs are defined in Config.src to ensure better |
12 | * "make config" order */ | 12 | * "make config" order */ |
13 | 13 | ||
14 | //applet:IF_LSMOD( IF_MODPROBE_SMALL(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP))) | 14 | //applet:IF_LSMOD( IF_MODPROBE_SMALL(APPLET_NOEXEC( lsmod, lsmod, BB_DIR_SBIN, BB_SUID_DROP, lsmod ))) |
15 | //applet:IF_MODPROBE(IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))) | 15 | //applet:IF_MODPROBE(IF_MODPROBE_SMALL(APPLET_NOEXEC( modprobe, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))) |
16 | // APPLET_ODDNAME:name main location suid_type help | 16 | // APPLET_ODDNAME:name main location suid_type help |
17 | //applet:IF_DEPMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod))) | 17 | //applet:IF_DEPMOD( IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod ))) |
18 | //applet:IF_INSMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod))) | 18 | //applet:IF_INSMOD( IF_MODPROBE_SMALL(APPLET_NOEXEC( insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod ))) |
19 | //applet:IF_RMMOD( IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod))) | 19 | //applet:IF_RMMOD( IF_MODPROBE_SMALL(APPLET_NOEXEC( rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod ))) |
20 | /* noexec speeds up boot with many modules loaded (need SH_STANDALONE=y) */ | ||
21 | /* I measured about ~5 times faster insmod */ | ||
22 | /* depmod is not noexec, it runs longer and benefits from memory trimming via exec */ | ||
20 | 23 | ||
21 | //kbuild:lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o | 24 | //kbuild:lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o |
22 | 25 | ||
@@ -985,10 +988,9 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
985 | 988 | ||
986 | #if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD | 989 | #if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD |
987 | /* modprobe, insmod, rmmod require at least one argument */ | 990 | /* modprobe, insmod, rmmod require at least one argument */ |
988 | opt_complementary = "-1"; | ||
989 | /* only -q (quiet) and -r (rmmod), | 991 | /* only -q (quiet) and -r (rmmod), |
990 | * the rest are accepted and ignored (compat) */ | 992 | * the rest are accepted and ignored (compat) */ |
991 | getopt32(argv, "qrfsvwb"); | 993 | getopt32(argv, "^" "qrfsvwb" "\0" "-1"); |
992 | argv += optind; | 994 | argv += optind; |
993 | 995 | ||
994 | if (is_modprobe) { | 996 | if (is_modprobe) { |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 1a7db09f2..59f6d54f3 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -26,7 +26,7 @@ | |||
26 | //config: hardware autodetection scripts to load modules like evdev, frame | 26 | //config: hardware autodetection scripts to load modules like evdev, frame |
27 | //config: buffer drivers etc. | 27 | //config: buffer drivers etc. |
28 | 28 | ||
29 | //applet:IF_MODPROBE(IF_NOT_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))) | 29 | //applet:IF_MODPROBE(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(modprobe, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))) |
30 | 30 | ||
31 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) | 31 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) |
32 | //kbuild:lib-$(CONFIG_MODPROBE) += modprobe.o modutils.o | 32 | //kbuild:lib-$(CONFIG_MODPROBE) += modprobe.o modutils.o |
@@ -133,7 +133,7 @@ | |||
133 | */ | 133 | */ |
134 | #define MODPROBE_OPTS "alrDb" | 134 | #define MODPROBE_OPTS "alrDb" |
135 | /* -a and -D _are_ in fact compatible */ | 135 | /* -a and -D _are_ in fact compatible */ |
136 | #define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl") | 136 | #define MODPROBE_COMPLEMENTARY "q-v:v-q:l--arD:r--alD:a--lr:D--rl" |
137 | //#define MODPROBE_OPTS "acd:lnrt:C:b" | 137 | //#define MODPROBE_OPTS "acd:lnrt:C:b" |
138 | //#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" | 138 | //#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" |
139 | enum { | 139 | enum { |
@@ -566,9 +566,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
566 | 566 | ||
567 | INIT_G(); | 567 | INIT_G(); |
568 | 568 | ||
569 | IF_LONG_OPTS(applet_long_options = modprobe_longopts;) | 569 | opt = getopt32long(argv, "^" INSMOD_OPTS MODPROBE_OPTS "\0" MODPROBE_COMPLEMENTARY, |
570 | opt_complementary = MODPROBE_COMPLEMENTARY; | 570 | modprobe_longopts |
571 | opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); | 571 | INSMOD_ARGS |
572 | ); | ||
572 | argv += optind; | 573 | argv += optind; |
573 | 574 | ||
574 | /* Goto modules location */ | 575 | /* Goto modules location */ |
diff --git a/modutils/modutils-24.c b/modutils/modutils-24.c index 9ce91351d..1a30dd87c 100644 --- a/modutils/modutils-24.c +++ b/modutils/modutils-24.c | |||
@@ -2269,8 +2269,8 @@ static int add_symbols_from(struct obj_file *f, | |||
2269 | 2269 | ||
2270 | #ifdef SYMBOL_PREFIX | 2270 | #ifdef SYMBOL_PREFIX |
2271 | /* Prepend SYMBOL_PREFIX to the symbol's name (the | 2271 | /* Prepend SYMBOL_PREFIX to the symbol's name (the |
2272 | kernel exports `C names', but module object files | 2272 | kernel exports 'C names', but module object files |
2273 | reference `linker names'). */ | 2273 | reference 'linker names'). */ |
2274 | size_t extra = sizeof SYMBOL_PREFIX; | 2274 | size_t extra = sizeof SYMBOL_PREFIX; |
2275 | size_t name_size = strlen(name) + extra; | 2275 | size_t name_size = strlen(name) + extra; |
2276 | if (name_size > name_alloced_size) { | 2276 | if (name_size > name_alloced_size) { |
diff --git a/modutils/rmmod.c b/modutils/rmmod.c index d60e49413..df50e58af 100644 --- a/modutils/rmmod.c +++ b/modutils/rmmod.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: help | 14 | //config: help |
15 | //config: rmmod is used to unload specified modules from the kernel. | 15 | //config: rmmod is used to unload specified modules from the kernel. |
16 | 16 | ||
17 | //applet:IF_RMMOD(IF_NOT_MODPROBE_SMALL(APPLET(rmmod, BB_DIR_SBIN, BB_SUID_DROP))) | 17 | //applet:IF_RMMOD(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(rmmod, rmmod, BB_DIR_SBIN, BB_SUID_DROP, rmmod))) |
18 | 18 | ||
19 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) | 19 | //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) |
20 | //kbuild:lib-$(CONFIG_RMMOD) += rmmod.o modutils.o | 20 | //kbuild:lib-$(CONFIG_RMMOD) += rmmod.o modutils.o |
diff --git a/networking/arping.c b/networking/arping.c index 71672957e..f9967d81e 100644 --- a/networking/arping.c +++ b/networking/arping.c | |||
@@ -295,8 +295,8 @@ int arping_main(int argc UNUSED_PARAM, char **argv) | |||
295 | 295 | ||
296 | sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); | 296 | sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); |
297 | 297 | ||
298 | // Drop suid root privileges | 298 | // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, |
299 | // Need to remove SUID_NEVER from applets.h for this to work | 299 | // drop suid root privileges here: |
300 | //xsetuid(getuid()); | 300 | //xsetuid(getuid()); |
301 | 301 | ||
302 | { | 302 | { |
@@ -306,9 +306,9 @@ int arping_main(int argc UNUSED_PARAM, char **argv) | |||
306 | /* Dad also sets quit_on_reply. | 306 | /* Dad also sets quit_on_reply. |
307 | * Advert also sets unsolicited. | 307 | * Advert also sets unsolicited. |
308 | */ | 308 | */ |
309 | opt_complementary = "=1:Df:AU"; | 309 | opt = getopt32(argv, "^" "DUAqfbc:+w:I:s:" "\0" "=1:Df:AU", |
310 | opt = getopt32(argv, "DUAqfbc:+w:I:s:", | 310 | &count, &str_timeout, &device, &source |
311 | &count, &str_timeout, &device, &source); | 311 | ); |
312 | if (opt & 0x80) /* -w: timeout */ | 312 | if (opt & 0x80) /* -w: timeout */ |
313 | timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; | 313 | timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; |
314 | //if (opt & 0x200) /* -s: source */ | 314 | //if (opt & 0x200) /* -s: source */ |
diff --git a/networking/brctl.c b/networking/brctl.c index 690791e4c..5d5f0af30 100644 --- a/networking/brctl.c +++ b/networking/brctl.c | |||
@@ -39,7 +39,7 @@ | |||
39 | //config: Add support for option which prints the current config: | 39 | //config: Add support for option which prints the current config: |
40 | //config: show | 40 | //config: show |
41 | 41 | ||
42 | //applet:IF_BRCTL(APPLET(brctl, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 42 | //applet:IF_BRCTL(APPLET_NOEXEC(brctl, brctl, BB_DIR_USR_SBIN, BB_SUID_DROP, brctl)) |
43 | 43 | ||
44 | //kbuild:lib-$(CONFIG_BRCTL) += brctl.o | 44 | //kbuild:lib-$(CONFIG_BRCTL) += brctl.o |
45 | 45 | ||
diff --git a/networking/ether-wake.c b/networking/ether-wake.c index 52522e76d..6677f07d5 100644 --- a/networking/ether-wake.c +++ b/networking/ether-wake.c | |||
@@ -212,8 +212,7 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv) | |||
212 | struct whereto_t whereto; /* who to wake up */ | 212 | struct whereto_t whereto; /* who to wake up */ |
213 | 213 | ||
214 | /* handle misc user options */ | 214 | /* handle misc user options */ |
215 | opt_complementary = "=1"; | 215 | flags = getopt32(argv, "^" "bi:p:" "\0" "=1", &ifname, &pass); |
216 | flags = getopt32(argv, "bi:p:", &ifname, &pass); | ||
217 | if (flags & 4) /* -p */ | 216 | if (flags & 4) /* -p */ |
218 | wol_passwd_sz = get_wol_pw(pass, wol_passwd); | 217 | wol_passwd_sz = get_wol_pw(pass, wol_passwd); |
219 | flags &= 1; /* we further interested only in -b [bcast] flag */ | 218 | flags &= 1; /* we further interested only in -b [bcast] flag */ |
diff --git a/networking/ftpd.c b/networking/ftpd.c index c562c2886..8af5acac2 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -1174,17 +1174,20 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
1174 | abs_timeout = 1 * 60 * 60; | 1174 | abs_timeout = 1 * 60 * 60; |
1175 | verbose_S = 0; | 1175 | verbose_S = 0; |
1176 | G.timeout = 2 * 60; | 1176 | G.timeout = 2 * 60; |
1177 | opt_complementary = "vv:SS"; | ||
1178 | #if BB_MMU | 1177 | #if BB_MMU |
1179 | opts = getopt32(argv, "vS" | 1178 | opts = getopt32(argv, "^" "vS" |
1180 | IF_FEATURE_FTPD_WRITE("w") "t:+T:+" IF_FEATURE_FTPD_AUTHENTICATION("a:"), | 1179 | IF_FEATURE_FTPD_WRITE("w") "t:+T:+" IF_FEATURE_FTPD_AUTHENTICATION("a:") |
1180 | "\0" "vv:SS", | ||
1181 | &G.timeout, &abs_timeout, IF_FEATURE_FTPD_AUTHENTICATION(&anon_opt,) | 1181 | &G.timeout, &abs_timeout, IF_FEATURE_FTPD_AUTHENTICATION(&anon_opt,) |
1182 | &G.verbose, &verbose_S); | 1182 | &G.verbose, &verbose_S |
1183 | ); | ||
1183 | #else | 1184 | #else |
1184 | opts = getopt32(argv, "l1AvS" | 1185 | opts = getopt32(argv, "^" "l1AvS" |
1185 | IF_FEATURE_FTPD_WRITE("w") "t:+T:+" IF_FEATURE_FTPD_AUTHENTICATION("a:"), | 1186 | IF_FEATURE_FTPD_WRITE("w") "t:+T:+" IF_FEATURE_FTPD_AUTHENTICATION("a:") |
1187 | "\0" "vv:SS", | ||
1186 | &G.timeout, &abs_timeout, IF_FEATURE_FTPD_AUTHENTICATION(&anon_opt,) | 1188 | &G.timeout, &abs_timeout, IF_FEATURE_FTPD_AUTHENTICATION(&anon_opt,) |
1187 | &G.verbose, &verbose_S); | 1189 | &G.verbose, &verbose_S |
1190 | ); | ||
1188 | if (opts & (OPT_l|OPT_1)) { | 1191 | if (opts & (OPT_l|OPT_1)) { |
1189 | /* Our secret backdoor to ls */ | 1192 | /* Our secret backdoor to ls */ |
1190 | if (fchdir(3) != 0) | 1193 | if (fchdir(3) != 0) |
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c index cb0a96b59..029587aa2 100644 --- a/networking/ftpgetput.c +++ b/networking/ftpgetput.c | |||
@@ -39,37 +39,20 @@ | |||
39 | //usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" | 39 | //usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" |
40 | //usage:#define ftpget_full_usage "\n\n" | 40 | //usage:#define ftpget_full_usage "\n\n" |
41 | //usage: "Download a file via FTP\n" | 41 | //usage: "Download a file via FTP\n" |
42 | //usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( | ||
43 | //usage: "\n -c,--continue Continue previous transfer" | ||
44 | //usage: "\n -v,--verbose Verbose" | ||
45 | //usage: "\n -u,--username USER Username" | ||
46 | //usage: "\n -p,--password PASS Password" | ||
47 | //usage: "\n -P,--port NUM Port" | ||
48 | //usage: ) | ||
49 | //usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( | ||
50 | //usage: "\n -c Continue previous transfer" | 42 | //usage: "\n -c Continue previous transfer" |
51 | //usage: "\n -v Verbose" | 43 | //usage: "\n -v Verbose" |
52 | //usage: "\n -u USER Username" | 44 | //usage: "\n -u USER Username" |
53 | //usage: "\n -p PASS Password" | 45 | //usage: "\n -p PASS Password" |
54 | //usage: "\n -P NUM Port" | 46 | //usage: "\n -P NUM Port" |
55 | //usage: ) | ||
56 | //usage: | 47 | //usage: |
57 | //usage:#define ftpput_trivial_usage | 48 | //usage:#define ftpput_trivial_usage |
58 | //usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" | 49 | //usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" |
59 | //usage:#define ftpput_full_usage "\n\n" | 50 | //usage:#define ftpput_full_usage "\n\n" |
60 | //usage: "Upload a file to a FTP server\n" | 51 | //usage: "Upload a file to a FTP server\n" |
61 | //usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( | ||
62 | //usage: "\n -v,--verbose Verbose" | ||
63 | //usage: "\n -u,--username USER Username" | ||
64 | //usage: "\n -p,--password PASS Password" | ||
65 | //usage: "\n -P,--port NUM Port" | ||
66 | //usage: ) | ||
67 | //usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( | ||
68 | //usage: "\n -v Verbose" | 52 | //usage: "\n -v Verbose" |
69 | //usage: "\n -u USER Username" | 53 | //usage: "\n -u USER Username" |
70 | //usage: "\n -p PASS Password" | 54 | //usage: "\n -p PASS Password" |
71 | //usage: "\n -P NUM Port number" | 55 | //usage: "\n -P NUM Port number" |
72 | //usage: ) | ||
73 | 56 | ||
74 | #include "libbb.h" | 57 | #include "libbb.h" |
75 | #include "common_bufsiz.h" | 58 | #include "common_bufsiz.h" |
@@ -367,12 +350,15 @@ int ftpgetput_main(int argc UNUSED_PARAM, char **argv) | |||
367 | /* | 350 | /* |
368 | * Decipher the command line | 351 | * Decipher the command line |
369 | */ | 352 | */ |
353 | /* must have 2 to 3 params; -v and -c count */ | ||
354 | #define OPTSTRING "^cvu:p:P:" "\0" "-2:?3:vv:cc" | ||
370 | #if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS | 355 | #if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS |
371 | applet_long_options = ftpgetput_longopts; | 356 | getopt32long(argv, OPTSTRING, ftpgetput_longopts, |
357 | #else | ||
358 | getopt32(argv, OPTSTRING, | ||
372 | #endif | 359 | #endif |
373 | opt_complementary = "-2:vv:cc"; /* must have 2 to 3 params; -v and -c count */ | 360 | &user, &password, &port, &verbose_flag, &do_continue |
374 | getopt32(argv, "cvu:p:P:", &user, &password, &port, | 361 | ); |
375 | &verbose_flag, &do_continue); | ||
376 | argv += optind; | 362 | argv += optind; |
377 | 363 | ||
378 | /* We want to do exactly _one_ DNS lookup, since some | 364 | /* We want to do exactly _one_ DNS lookup, since some |
diff --git a/networking/hostname.c b/networking/hostname.c index 4b305d2b6..d87f6562f 100644 --- a/networking/hostname.c +++ b/networking/hostname.c | |||
@@ -22,9 +22,9 @@ | |||
22 | //config: help | 22 | //config: help |
23 | //config: Alias to "hostname -d". | 23 | //config: Alias to "hostname -d". |
24 | 24 | ||
25 | // APPLET_ODDNAME:name main location suid_type help | 25 | // APPLET_NOEXEC:name main location suid_type help |
26 | //applet:IF_DNSDOMAINNAME(APPLET_ODDNAME(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) | 26 | //applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) |
27 | //applet:IF_HOSTNAME(APPLET(hostname, BB_DIR_BIN, BB_SUID_DROP)) | 27 | //applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) |
28 | 28 | ||
29 | //kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o | 29 | //kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o |
30 | //kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o | 30 | //kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o |
@@ -114,7 +114,7 @@ static void do_sethostname(char *s, int isfile) | |||
114 | * { bbox: not supported } | 114 | * { bbox: not supported } |
115 | * -F, --file filename | 115 | * -F, --file filename |
116 | * Read the host name from the specified file. Comments (lines | 116 | * Read the host name from the specified file. Comments (lines |
117 | * starting with a `#') are ignored. | 117 | * starting with a '#') are ignored. |
118 | */ | 118 | */ |
119 | int hostname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 119 | int hostname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
120 | int hostname_main(int argc UNUSED_PARAM, char **argv) | 120 | int hostname_main(int argc UNUSED_PARAM, char **argv) |
@@ -132,8 +132,9 @@ int hostname_main(int argc UNUSED_PARAM, char **argv) | |||
132 | char *buf; | 132 | char *buf; |
133 | char *hostname_str; | 133 | char *hostname_str; |
134 | 134 | ||
135 | #if ENABLE_LONG_OPTS | 135 | /* dnsdomainname from net-tools 1.60, hostname 1.100 (2001-04-14), |
136 | applet_long_options = | 136 | * supports hostname's options too (not just -v as manpage says) */ |
137 | opts = getopt32(argv, "dfisF:v", &hostname_str, | ||
137 | "domain\0" No_argument "d" | 138 | "domain\0" No_argument "d" |
138 | "fqdn\0" No_argument "f" | 139 | "fqdn\0" No_argument "f" |
139 | //Enable if seen in active use in some distro: | 140 | //Enable if seen in active use in some distro: |
@@ -142,12 +143,7 @@ int hostname_main(int argc UNUSED_PARAM, char **argv) | |||
142 | // "short\0" No_argument "s" | 143 | // "short\0" No_argument "s" |
143 | // "verbose\0" No_argument "v" | 144 | // "verbose\0" No_argument "v" |
144 | "file\0" No_argument "F" | 145 | "file\0" No_argument "F" |
145 | ; | 146 | ); |
146 | |||
147 | #endif | ||
148 | /* dnsdomainname from net-tools 1.60, hostname 1.100 (2001-04-14), | ||
149 | * supports hostname's options too (not just -v as manpage says) */ | ||
150 | opts = getopt32(argv, "dfisF:v", &hostname_str); | ||
151 | argv += optind; | 147 | argv += optind; |
152 | buf = safe_gethostname(); | 148 | buf = safe_gethostname(); |
153 | if (ENABLE_DNSDOMAINNAME) { | 149 | if (ENABLE_DNSDOMAINNAME) { |
diff --git a/networking/httpd.c b/networking/httpd.c index 079145757..9369de824 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -2636,17 +2636,19 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2636 | #endif | 2636 | #endif |
2637 | 2637 | ||
2638 | home_httpd = xrealloc_getcwd_or_warn(NULL); | 2638 | home_httpd = xrealloc_getcwd_or_warn(NULL); |
2639 | /* -v counts, -i implies -f */ | ||
2640 | opt_complementary = "vv:if"; | ||
2641 | /* We do not "absolutize" path given by -h (home) opt. | 2639 | /* We do not "absolutize" path given by -h (home) opt. |
2642 | * If user gives relative path in -h, | 2640 | * If user gives relative path in -h, |
2643 | * $SCRIPT_FILENAME will not be set. */ | 2641 | * $SCRIPT_FILENAME will not be set. */ |
2644 | opt = getopt32(argv, "c:d:h:" | 2642 | opt = getopt32(argv, "^" |
2643 | "c:d:h:" | ||
2645 | IF_FEATURE_HTTPD_ENCODE_URL_STR("e:") | 2644 | IF_FEATURE_HTTPD_ENCODE_URL_STR("e:") |
2646 | IF_FEATURE_HTTPD_BASIC_AUTH("r:") | 2645 | IF_FEATURE_HTTPD_BASIC_AUTH("r:") |
2647 | IF_FEATURE_HTTPD_AUTH_MD5("m:") | 2646 | IF_FEATURE_HTTPD_AUTH_MD5("m:") |
2648 | IF_FEATURE_HTTPD_SETUID("u:") | 2647 | IF_FEATURE_HTTPD_SETUID("u:") |
2649 | "p:ifv", | 2648 | "p:ifv" |
2649 | "\0" | ||
2650 | /* -v counts, -i implies -f */ | ||
2651 | "vv:if", | ||
2650 | &opt_c_configFile, &url_for_decode, &home_httpd | 2652 | &opt_c_configFile, &url_for_decode, &home_httpd |
2651 | IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) | 2653 | IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) |
2652 | IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) | 2654 | IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) |
diff --git a/networking/ifenslave.c b/networking/ifenslave.c index 26e5e8cf3..5e769b61d 100644 --- a/networking/ifenslave.c +++ b/networking/ifenslave.c | |||
@@ -105,7 +105,7 @@ | |||
105 | //config: Userspace application to bind several interfaces | 105 | //config: Userspace application to bind several interfaces |
106 | //config: to a logical interface (use with kernel bonding driver). | 106 | //config: to a logical interface (use with kernel bonding driver). |
107 | 107 | ||
108 | //applet:IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP)) | 108 | //applet:IF_IFENSLAVE(APPLET_NOEXEC(ifenslave, ifenslave, BB_DIR_SBIN, BB_SUID_DROP, ifenslave)) |
109 | 109 | ||
110 | //kbuild:lib-$(CONFIG_IFENSLAVE) += ifenslave.o interface.o | 110 | //kbuild:lib-$(CONFIG_IFENSLAVE) += ifenslave.o interface.o |
111 | 111 | ||
@@ -113,10 +113,10 @@ | |||
113 | //usage: "[-cdf] MASTER_IFACE SLAVE_IFACE..." | 113 | //usage: "[-cdf] MASTER_IFACE SLAVE_IFACE..." |
114 | //usage:#define ifenslave_full_usage "\n\n" | 114 | //usage:#define ifenslave_full_usage "\n\n" |
115 | //usage: "Configure network interfaces for parallel routing\n" | 115 | //usage: "Configure network interfaces for parallel routing\n" |
116 | //usage: "\n -c,--change-active Change active slave" | 116 | //usage: "\n -c Change active slave" |
117 | //usage: "\n -d,--detach Remove slave interface from bonding device" | 117 | //usage: "\n -d Remove slave interface from bonding device" |
118 | //usage: "\n -f,--force Force, even if interface is not Ethernet" | 118 | //usage: "\n -f Force, even if interface is not Ethernet" |
119 | /* //usage: "\n -r,--receive-slave Create a receive-only slave" */ | 119 | /* //usage: "\n -r Create a receive-only slave" */ |
120 | //usage: | 120 | //usage: |
121 | //usage:#define ifenslave_example_usage | 121 | //usage:#define ifenslave_example_usage |
122 | //usage: "To create a bond device, simply follow these three steps:\n" | 122 | //usage: "To create a bond device, simply follow these three steps:\n" |
@@ -493,19 +493,15 @@ int ifenslave_main(int argc UNUSED_PARAM, char **argv) | |||
493 | OPT_d = (1 << 1), | 493 | OPT_d = (1 << 1), |
494 | OPT_f = (1 << 2), | 494 | OPT_f = (1 << 2), |
495 | }; | 495 | }; |
496 | #if ENABLE_LONG_OPTS | 496 | |
497 | static const char ifenslave_longopts[] ALIGN1 = | 497 | INIT_G(); |
498 | |||
499 | opt = getopt32long(argv, "cdfa", | ||
498 | "change-active\0" No_argument "c" | 500 | "change-active\0" No_argument "c" |
499 | "detach\0" No_argument "d" | 501 | "detach\0" No_argument "d" |
500 | "force\0" No_argument "f" | 502 | "force\0" No_argument "f" |
501 | /* "all-interfaces\0" No_argument "a" */ | 503 | /* "all-interfaces\0" No_argument "a" */ |
502 | ; | 504 | ); |
503 | |||
504 | applet_long_options = ifenslave_longopts; | ||
505 | #endif | ||
506 | INIT_G(); | ||
507 | |||
508 | opt = getopt32(argv, "cdfa"); | ||
509 | argv += optind; | 505 | argv += optind; |
510 | if (opt & (opt-1)) /* Only one option can be given */ | 506 | if (opt & (opt-1)) /* Only one option can be given */ |
511 | bb_show_usage(); | 507 | bb_show_usage(); |
diff --git a/networking/inetd.c b/networking/inetd.c index 91545d0a3..67984accb 100644 --- a/networking/inetd.c +++ b/networking/inetd.c | |||
@@ -217,7 +217,6 @@ | |||
217 | //config: bool "Support RPC services" | 217 | //config: bool "Support RPC services" |
218 | //config: default n # very rarely used, and needs Sun RPC support in libc | 218 | //config: default n # very rarely used, and needs Sun RPC support in libc |
219 | //config: depends on INETD | 219 | //config: depends on INETD |
220 | //config: select FEATURE_HAVE_RPC | ||
221 | //config: help | 220 | //config: help |
222 | //config: Support Sun-RPC based services | 221 | //config: Support Sun-RPC based services |
223 | 222 | ||
diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 9888a6ff2..cdae8eea8 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c | |||
@@ -31,7 +31,7 @@ | |||
31 | //config: Adds the options hostname, prefix and silent to the output of | 31 | //config: Adds the options hostname, prefix and silent to the output of |
32 | //config: "ipcalc". | 32 | //config: "ipcalc". |
33 | 33 | ||
34 | //applet:IF_IPCALC(APPLET(ipcalc, BB_DIR_BIN, BB_SUID_DROP)) | 34 | //applet:IF_IPCALC(APPLET_NOEXEC(ipcalc, ipcalc, BB_DIR_BIN, BB_SUID_DROP, ipcalc)) |
35 | 35 | ||
36 | //kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o | 36 | //kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o |
37 | 37 | ||
@@ -39,26 +39,14 @@ | |||
39 | //usage: "[OPTIONS] ADDRESS" | 39 | //usage: "[OPTIONS] ADDRESS" |
40 | //usage: IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]" | 40 | //usage: IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]" |
41 | //usage:#define ipcalc_full_usage "\n\n" | 41 | //usage:#define ipcalc_full_usage "\n\n" |
42 | //usage: "Calculate IP network settings from a IP address\n" | 42 | //usage: "Calculate and display network settings from IP address\n" |
43 | //usage: IF_FEATURE_IPCALC_LONG_OPTIONS( | 43 | //usage: "\n -b Broadcast address" |
44 | //usage: "\n -b,--broadcast Display calculated broadcast address" | 44 | //usage: "\n -n Network address" |
45 | //usage: "\n -n,--network Display calculated network address" | 45 | //usage: "\n -m Default netmask for IP" |
46 | //usage: "\n -m,--netmask Display default netmask for IP" | ||
47 | //usage: IF_FEATURE_IPCALC_FANCY( | 46 | //usage: IF_FEATURE_IPCALC_FANCY( |
48 | //usage: "\n -p,--prefix Display the prefix for IP/NETMASK" | 47 | //usage: "\n -p Prefix for IP/NETMASK" |
49 | //usage: "\n -h,--hostname Display first resolved host name" | 48 | //usage: "\n -h Resolved host name" |
50 | //usage: "\n -s,--silent Don't ever display error messages" | 49 | //usage: "\n -s No error messages" |
51 | //usage: ) | ||
52 | //usage: ) | ||
53 | //usage: IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( | ||
54 | //usage: "\n -b Display calculated broadcast address" | ||
55 | //usage: "\n -n Display calculated network address" | ||
56 | //usage: "\n -m Display default netmask for IP" | ||
57 | //usage: IF_FEATURE_IPCALC_FANCY( | ||
58 | //usage: "\n -p Display the prefix for IP/NETMASK" | ||
59 | //usage: "\n -h Display first resolved host name" | ||
60 | //usage: "\n -s Don't ever display error messages" | ||
61 | //usage: ) | ||
62 | //usage: ) | 50 | //usage: ) |
63 | 51 | ||
64 | #include "libbb.h" | 52 | #include "libbb.h" |
@@ -120,6 +108,11 @@ int get_prefix(unsigned long netmask); | |||
120 | "silent\0" No_argument "s" // don’t ever display error messages | 108 | "silent\0" No_argument "s" // don’t ever display error messages |
121 | # endif | 109 | # endif |
122 | ; | 110 | ; |
111 | # define GETOPT32 getopt32long | ||
112 | # define LONGOPTS ,ipcalc_longopts | ||
113 | #else | ||
114 | # define GETOPT32 getopt32 | ||
115 | # define LONGOPTS | ||
123 | #endif | 116 | #endif |
124 | 117 | ||
125 | int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 118 | int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -137,11 +130,11 @@ int ipcalc_main(int argc UNUSED_PARAM, char **argv) | |||
137 | #define ipaddr (s_ipaddr.s_addr) | 130 | #define ipaddr (s_ipaddr.s_addr) |
138 | char *ipstr; | 131 | char *ipstr; |
139 | 132 | ||
140 | #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS | 133 | opt = GETOPT32(argv, "^" |
141 | applet_long_options = ipcalc_longopts; | 134 | "mbn" IF_FEATURE_IPCALC_FANCY("phs") |
142 | #endif | 135 | "\0" "-1:?2"/*min 1, max 2 args*/ |
143 | opt_complementary = "-1:?2"; /* minimum 1 arg, maximum 2 args */ | 136 | LONGOPTS |
144 | opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs")); | 137 | ); |
145 | argv += optind; | 138 | argv += optind; |
146 | if (opt & SILENT) | 139 | if (opt & SILENT) |
147 | logmode = LOGMODE_NONE; /* suppress error_msg() output */ | 140 | logmode = LOGMODE_NONE; /* suppress error_msg() output */ |
diff --git a/networking/nameif.c b/networking/nameif.c index 31ee98a39..1f2695495 100644 --- a/networking/nameif.c +++ b/networking/nameif.c | |||
@@ -40,7 +40,7 @@ | |||
40 | //config: new_interface_name mac=00:80:C8:38:91:B5 | 40 | //config: new_interface_name mac=00:80:C8:38:91:B5 |
41 | //config: new_interface_name 00:80:C8:38:91:B5 | 41 | //config: new_interface_name 00:80:C8:38:91:B5 |
42 | 42 | ||
43 | //applet:IF_NAMEIF(APPLET(nameif, BB_DIR_SBIN, BB_SUID_DROP)) | 43 | //applet:IF_NAMEIF(APPLET_NOEXEC(nameif, nameif, BB_DIR_SBIN, BB_SUID_DROP, nameif)) |
44 | 44 | ||
45 | //kbuild:lib-$(CONFIG_NAMEIF) += nameif.o | 45 | //kbuild:lib-$(CONFIG_NAMEIF) += nameif.o |
46 | 46 | ||
diff --git a/networking/nbd-client.c b/networking/nbd-client.c index a5e25e6aa..cf1857231 100644 --- a/networking/nbd-client.c +++ b/networking/nbd-client.c | |||
@@ -7,7 +7,7 @@ | |||
7 | #include <netinet/tcp.h> | 7 | #include <netinet/tcp.h> |
8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
9 | 9 | ||
10 | //applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient)) | 10 | //applet:IF_NBDCLIENT(APPLET_NOEXEC(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient)) |
11 | 11 | ||
12 | //kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o | 12 | //kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o |
13 | 13 | ||
@@ -43,7 +43,7 @@ | |||
43 | //blocksizes other than 1024 without patches | 43 | //blocksizes other than 1024 without patches |
44 | 44 | ||
45 | int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 45 | int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
46 | int nbdclient_main(int argc, char **argv) | 46 | int nbdclient_main(int argc UNUSED_PARAM, char **argv) |
47 | { | 47 | { |
48 | unsigned long timeout = 0; | 48 | unsigned long timeout = 0; |
49 | #if BB_MMU | 49 | #if BB_MMU |
@@ -61,7 +61,7 @@ int nbdclient_main(int argc, char **argv) | |||
61 | BUILD_BUG_ON(offsetof(struct nbd_header_t, data) != 8+8+8+4); | 61 | BUILD_BUG_ON(offsetof(struct nbd_header_t, data) != 8+8+8+4); |
62 | 62 | ||
63 | // Parse command line stuff (just a stub now) | 63 | // Parse command line stuff (just a stub now) |
64 | if (argc != 4) | 64 | if (!argv[1] || !argv[2] || !argv[3] || argv[4]) |
65 | bb_show_usage(); | 65 | bb_show_usage(); |
66 | 66 | ||
67 | #if !BB_MMU | 67 | #if !BB_MMU |
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 3db784982..64098648a 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -787,11 +787,15 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
787 | e_found: | 787 | e_found: |
788 | 788 | ||
789 | // -g -G -t -r deleted, unimplemented -a deleted too | 789 | // -g -G -t -r deleted, unimplemented -a deleted too |
790 | opt_complementary = "?2:vv:ll"; /* max 2 params; -v and -l are counters; -w N */ | 790 | getopt32(argv, "^" |
791 | getopt32(argv, "np:s:uvw:+" IF_NC_SERVER("lk") | 791 | "np:s:uvw:+"/* -w N */ IF_NC_SERVER("lk") |
792 | IF_NC_EXTRA("i:o:z"), | 792 | IF_NC_EXTRA("i:o:z") |
793 | &str_p, &str_s, &o_wait | 793 | "\0" |
794 | IF_NC_EXTRA(, &str_i, &str_o), &o_verbose IF_NC_SERVER(, &cnt_l)); | 794 | "?2:vv:ll", /* max 2 params; -v and -l are counters */ |
795 | &str_p, &str_s, &o_wait | ||
796 | IF_NC_EXTRA(, &str_i, &str_o) | ||
797 | , &o_verbose IF_NC_SERVER(, &cnt_l) | ||
798 | ); | ||
795 | argv += optind; | 799 | argv += optind; |
796 | #if ENABLE_NC_EXTRA | 800 | #if ENABLE_NC_EXTRA |
797 | if (option_mask32 & OPT_i) /* line-interval time */ | 801 | if (option_mask32 & OPT_i) /* line-interval time */ |
diff --git a/networking/ntpd.c b/networking/ntpd.c index f21f9513d..25fa44389 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -2230,15 +2230,16 @@ static NOINLINE void ntp_init(char **argv) | |||
2230 | 2230 | ||
2231 | /* Parse options */ | 2231 | /* Parse options */ |
2232 | peers = NULL; | 2232 | peers = NULL; |
2233 | opt_complementary = "dd:wn" /* -d: counter; -p: list; -w implies -n */ | 2233 | opts = getopt32(argv, "^" |
2234 | IF_FEATURE_NTPD_SERVER(":Il"); /* -I implies -l */ | ||
2235 | opts = getopt32(argv, | ||
2236 | "nqNx" /* compat */ | 2234 | "nqNx" /* compat */ |
2237 | "wp:*S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */ | 2235 | "wp:*S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */ |
2238 | IF_FEATURE_NTPD_SERVER("I:") /* compat */ | 2236 | IF_FEATURE_NTPD_SERVER("I:") /* compat */ |
2239 | "d" /* compat */ | 2237 | "d" /* compat */ |
2240 | "46aAbgL", /* compat, ignored */ | 2238 | "46aAbgL", /* compat, ignored */ |
2241 | &peers, &G.script_name, | 2239 | "\0" |
2240 | "dd:wn" /* -d: counter; -p: list; -w implies -n */ | ||
2241 | IF_FEATURE_NTPD_SERVER(":Il") /* -I implies -l */ | ||
2242 | , &peers, &G.script_name, | ||
2242 | #if ENABLE_FEATURE_NTPD_SERVER | 2243 | #if ENABLE_FEATURE_NTPD_SERVER |
2243 | &G.if_name, | 2244 | &G.if_name, |
2244 | #endif | 2245 | #endif |
diff --git a/networking/ping.c b/networking/ping.c index 506e7b11b..7460e4414 100644 --- a/networking/ping.c +++ b/networking/ping.c | |||
@@ -340,7 +340,8 @@ static int common_ping_main(sa_family_t af, char **argv) | |||
340 | 340 | ||
341 | /* Full(er) version */ | 341 | /* Full(er) version */ |
342 | 342 | ||
343 | #define OPT_STRING ("qvc:+s:t:+w:+W:+I:np:4" IF_PING6("6")) | 343 | /* -c NUM, -t NUM, -w NUM, -W NUM */ |
344 | #define OPT_STRING "qvc:+s:t:+w:+W:+I:np:4"IF_PING6("6") | ||
344 | enum { | 345 | enum { |
345 | OPT_QUIET = 1 << 0, | 346 | OPT_QUIET = 1 << 0, |
346 | OPT_VERBOSE = 1 << 1, | 347 | OPT_VERBOSE = 1 << 1, |
@@ -863,9 +864,12 @@ static int common_ping_main(int opt, char **argv) | |||
863 | 864 | ||
864 | INIT_G(); | 865 | INIT_G(); |
865 | 866 | ||
866 | /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */ | 867 | opt |= getopt32(argv, "^" |
867 | opt_complementary = "=1:q--v:v--q"; | 868 | OPT_STRING |
868 | opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p); | 869 | /* exactly one arg; -v and -q don't mix */ |
870 | "\0" "=1:q--v:v--q", | ||
871 | &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p | ||
872 | ); | ||
869 | if (opt & OPT_s) | 873 | if (opt & OPT_s) |
870 | datalen = xatou16(str_s); // -s | 874 | datalen = xatou16(str_s); // -s |
871 | if (opt & OPT_I) { // -I | 875 | if (opt & OPT_I) { // -I |
@@ -953,7 +957,7 @@ int ping6_main(int argc UNUSED_PARAM, char **argv) | |||
953 | * may be used to endorse or promote products derived from this software | 957 | * may be used to endorse or promote products derived from this software |
954 | * without specific prior written permission. | 958 | * without specific prior written permission. |
955 | * | 959 | * |
956 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 960 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
957 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 961 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
958 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 962 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
959 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 963 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/networking/pscan.c b/networking/pscan.c index 17985d2c8..95b0a937d 100644 --- a/networking/pscan.c +++ b/networking/pscan.c | |||
@@ -75,8 +75,11 @@ int pscan_main(int argc UNUSED_PARAM, char **argv) | |||
75 | unsigned rtt_4; | 75 | unsigned rtt_4; |
76 | unsigned start, diff; | 76 | unsigned start, diff; |
77 | 77 | ||
78 | opt_complementary = "=1"; /* exactly one non-option */ | 78 | opt = getopt32(argv, "^" |
79 | opt = getopt32(argv, "cbp:P:t:T:", &opt_min_port, &opt_max_port, &opt_timeout, &opt_min_rtt); | 79 | "cbp:P:t:T:" |
80 | "\0" "=1", /* exactly one non-option */ | ||
81 | &opt_min_port, &opt_max_port, &opt_timeout, &opt_min_rtt | ||
82 | ); | ||
80 | argv += optind; | 83 | argv += optind; |
81 | max_port = xatou_range(opt_max_port, 1, 65535); | 84 | max_port = xatou_range(opt_max_port, 1, 65535); |
82 | port = xatou_range(opt_min_port, 1, max_port); | 85 | port = xatou_range(opt_min_port, 1, max_port); |
diff --git a/networking/slattach.c b/networking/slattach.c index 71b5bf427..e0a388926 100644 --- a/networking/slattach.c +++ b/networking/slattach.c | |||
@@ -17,23 +17,23 @@ | |||
17 | //config: default y | 17 | //config: default y |
18 | //config: select PLATFORM_LINUX | 18 | //config: select PLATFORM_LINUX |
19 | //config: help | 19 | //config: help |
20 | //config: slattach is a small utility to attach network interfaces to serial | 20 | //config: slattach configures serial line as SLIP network interface. |
21 | //config: lines. | ||
22 | 21 | ||
23 | //applet:IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP)) | 22 | //applet:IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP)) |
23 | /* shouldn't be NOEXEC: may sleep indefinitely */ | ||
24 | 24 | ||
25 | //kbuild:lib-$(CONFIG_SLATTACH) += slattach.o | 25 | //kbuild:lib-$(CONFIG_SLATTACH) += slattach.o |
26 | 26 | ||
27 | //usage:#define slattach_trivial_usage | 27 | //usage:#define slattach_trivial_usage |
28 | //usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" | 28 | //usage: "[-ehmLF] [-c SCRIPT] [-s BAUD] [-p PROTOCOL] SERIAL_DEVICE" |
29 | //usage:#define slattach_full_usage "\n\n" | 29 | //usage:#define slattach_full_usage "\n\n" |
30 | //usage: "Attach network interface(s) to serial line(s)\n" | 30 | //usage: "Configure serial line as SLIP network interface\n" |
31 | //usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" | 31 | //usage: "\n -p PROT Protocol: slip, cslip (default), slip6, clisp6, adaptive" |
32 | //usage: "\n -s SPD Set line speed" | 32 | //usage: "\n -s BAUD Line speed" |
33 | //usage: "\n -e Exit after initializing device" | 33 | //usage: "\n -e Exit after initialization" |
34 | //usage: "\n -h Exit when the carrier is lost" | 34 | //usage: "\n -h Exit if carrier is lost (else never exits)" |
35 | //usage: "\n -c PROG Run PROG when the line is hung up" | 35 | //usage: "\n -c PROG Run PROG on carrier loss" |
36 | //usage: "\n -m Do NOT initialize the line in raw 8 bits mode" | 36 | //usage: "\n -m Do NOT set raw 8bit mode" |
37 | //usage: "\n -L Enable 3-wire operation" | 37 | //usage: "\n -L Enable 3-wire operation" |
38 | //usage: "\n -F Disable RTS/CTS flow control" | 38 | //usage: "\n -F Disable RTS/CTS flow control" |
39 | 39 | ||
@@ -42,103 +42,53 @@ | |||
42 | #include "libiproute/utils.h" /* invarg_1_to_2() */ | 42 | #include "libiproute/utils.h" /* invarg_1_to_2() */ |
43 | 43 | ||
44 | struct globals { | 44 | struct globals { |
45 | int handle; | ||
46 | int saved_disc; | 45 | int saved_disc; |
47 | struct termios saved_state; | 46 | struct termios saved_state; |
48 | } FIX_ALIASING; | 47 | } FIX_ALIASING; |
49 | #define G (*(struct globals*)bb_common_bufsiz1) | 48 | #define G (*(struct globals*)bb_common_bufsiz1) |
50 | #define handle (G.handle ) | ||
51 | #define saved_disc (G.saved_disc ) | ||
52 | #define saved_state (G.saved_state ) | ||
53 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 49 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
54 | 50 | ||
51 | #define serial_fd 3 | ||
55 | 52 | ||
56 | /* | 53 | static int tcsetattr_serial_or_warn(struct termios *state) |
57 | * Save tty state and line discipline | ||
58 | * | ||
59 | * It is fine here to bail out on errors, since we haven modified anything yet | ||
60 | */ | ||
61 | static void save_state(void) | ||
62 | { | ||
63 | /* Save line status */ | ||
64 | if (tcgetattr(handle, &saved_state) < 0) | ||
65 | bb_perror_msg_and_die("get state"); | ||
66 | |||
67 | /* Save line discipline */ | ||
68 | xioctl(handle, TIOCGETD, &saved_disc); | ||
69 | } | ||
70 | |||
71 | static int set_termios_state_or_warn(struct termios *state) | ||
72 | { | 54 | { |
73 | int ret; | 55 | int ret; |
74 | 56 | ||
75 | ret = tcsetattr(handle, TCSANOW, state); | 57 | ret = tcsetattr(serial_fd, TCSANOW, state); |
76 | if (ret < 0) { | 58 | if (ret != 0) { |
77 | bb_perror_msg("set state"); | 59 | bb_perror_msg("tcsetattr"); |
78 | return 1; /* used as exitcode */ | 60 | return 1; /* used as exitcode */ |
79 | } | 61 | } |
80 | return 0; | 62 | return ret; /* 0 */ |
81 | } | 63 | } |
82 | 64 | ||
83 | /* | ||
84 | * Restore state and line discipline for ALL managed ttys | ||
85 | * | ||
86 | * Restoring ALL managed ttys is the only way to have a single | ||
87 | * hangup delay. | ||
88 | * | ||
89 | * Go on after errors: we want to restore as many controlled ttys | ||
90 | * as possible. | ||
91 | */ | ||
92 | static void restore_state_and_exit(int exitcode) NORETURN; | 65 | static void restore_state_and_exit(int exitcode) NORETURN; |
93 | static void restore_state_and_exit(int exitcode) | 66 | static void restore_state_and_exit(int exitcode) |
94 | { | 67 | { |
95 | struct termios state; | 68 | struct termios state; |
96 | 69 | ||
97 | /* Restore line discipline */ | 70 | /* Restore line discipline */ |
98 | if (ioctl_or_warn(handle, TIOCSETD, &saved_disc) < 0) { | 71 | if (ioctl_or_warn(serial_fd, TIOCSETD, &G.saved_disc)) { |
99 | exitcode = 1; | 72 | exitcode = 1; |
100 | } | 73 | } |
101 | 74 | ||
102 | /* Hangup */ | 75 | /* Hangup */ |
103 | memcpy(&state, &saved_state, sizeof(state)); | 76 | memcpy(&state, &G.saved_state, sizeof(state)); |
104 | cfsetispeed(&state, B0); | 77 | cfsetispeed(&state, B0); |
105 | cfsetospeed(&state, B0); | 78 | cfsetospeed(&state, B0); |
106 | if (set_termios_state_or_warn(&state)) | 79 | exitcode |= tcsetattr_serial_or_warn(&state); |
107 | exitcode = 1; | ||
108 | sleep(1); | 80 | sleep(1); |
109 | 81 | ||
110 | /* Restore line status */ | 82 | /* Restore line status */ |
111 | if (set_termios_state_or_warn(&saved_state)) | 83 | if (tcsetattr_serial_or_warn(&G.saved_state)) |
112 | exit(EXIT_FAILURE); | 84 | exit(EXIT_FAILURE); |
85 | |||
113 | if (ENABLE_FEATURE_CLEAN_UP) | 86 | if (ENABLE_FEATURE_CLEAN_UP) |
114 | close(handle); | 87 | close(serial_fd); |
115 | 88 | ||
116 | exit(exitcode); | 89 | exit(exitcode); |
117 | } | 90 | } |
118 | 91 | ||
119 | /* | ||
120 | * Set tty state, line discipline and encapsulation | ||
121 | */ | ||
122 | static void set_state(struct termios *state, int encap) | ||
123 | { | ||
124 | int disc; | ||
125 | |||
126 | /* Set line status */ | ||
127 | if (set_termios_state_or_warn(state)) | ||
128 | goto bad; | ||
129 | /* Set line discliple (N_SLIP always) */ | ||
130 | disc = N_SLIP; | ||
131 | if (ioctl_or_warn(handle, TIOCSETD, &disc) < 0) { | ||
132 | goto bad; | ||
133 | } | ||
134 | |||
135 | /* Set encapsulation (SLIP, CSLIP, etc) */ | ||
136 | if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) { | ||
137 | bad: | ||
138 | restore_state_and_exit(EXIT_FAILURE); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static void sig_handler(int signo UNUSED_PARAM) | 92 | static void sig_handler(int signo UNUSED_PARAM) |
143 | { | 93 | { |
144 | restore_state_and_exit(EXIT_SUCCESS); | 94 | restore_state_and_exit(EXIT_SUCCESS); |
@@ -155,13 +105,14 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) | |||
155 | "cslip6\0" /* 3 */ | 105 | "cslip6\0" /* 3 */ |
156 | "adaptive\0" /* 8 */ | 106 | "adaptive\0" /* 8 */ |
157 | ; | 107 | ; |
108 | static const int int_N_SLIP = N_SLIP; | ||
158 | 109 | ||
159 | int i, encap, opt; | 110 | int encap, opt, fd; |
160 | struct termios state; | 111 | struct termios state; |
161 | const char *proto = "cslip"; | 112 | const char *proto = "cslip"; |
162 | const char *extcmd; /* Command to execute after hangup */ | 113 | const char *extcmd; /* Command to execute after hangup */ |
163 | const char *baud_str; | 114 | const char *baud_str; |
164 | int baud_code = -1; /* Line baud rate (system code) */ | 115 | int baud_code = baud_code; /* for compiler */ |
165 | 116 | ||
166 | enum { | 117 | enum { |
167 | OPT_p_proto = 1 << 0, | 118 | OPT_p_proto = 1 << 0, |
@@ -177,15 +128,13 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) | |||
177 | INIT_G(); | 128 | INIT_G(); |
178 | 129 | ||
179 | /* Parse command line options */ | 130 | /* Parse command line options */ |
180 | opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd); | 131 | opt = getopt32(argv, "^" "p:s:c:ehmLF" "\0" "=1", |
132 | &proto, &baud_str, &extcmd | ||
133 | ); | ||
181 | /*argc -= optind;*/ | 134 | /*argc -= optind;*/ |
182 | argv += optind; | 135 | argv += optind; |
183 | 136 | ||
184 | if (!*argv) | ||
185 | bb_show_usage(); | ||
186 | |||
187 | encap = index_in_strings(proto_names, proto); | 137 | encap = index_in_strings(proto_names, proto); |
188 | |||
189 | if (encap < 0) | 138 | if (encap < 0) |
190 | invarg_1_to_2(proto, "protocol"); | 139 | invarg_1_to_2(proto, "protocol"); |
191 | if (encap > 3) | 140 | if (encap > 3) |
@@ -198,6 +147,22 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) | |||
198 | invarg_1_to_2(baud_str, "baud rate"); | 147 | invarg_1_to_2(baud_str, "baud rate"); |
199 | } | 148 | } |
200 | 149 | ||
150 | /* Open tty */ | ||
151 | fd = open(*argv, O_RDWR | O_NDELAY); | ||
152 | if (fd < 0) { | ||
153 | char *buf = concat_path_file("/dev", *argv); | ||
154 | fd = xopen(buf, O_RDWR | O_NDELAY); | ||
155 | /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ | ||
156 | free(buf); | ||
157 | } | ||
158 | xmove_fd(fd, serial_fd); | ||
159 | |||
160 | /* Save current tty state */ | ||
161 | if (tcgetattr(serial_fd, &G.saved_state) != 0) | ||
162 | bb_perror_msg_and_die("tcgetattr"); | ||
163 | /* Save line discipline */ | ||
164 | xioctl(serial_fd, TIOCGETD, &G.saved_disc); | ||
165 | |||
201 | /* Trap signals in order to restore tty states upon exit */ | 166 | /* Trap signals in order to restore tty states upon exit */ |
202 | if (!(opt & OPT_e_quit)) { | 167 | if (!(opt & OPT_e_quit)) { |
203 | bb_signals(0 | 168 | bb_signals(0 |
@@ -208,43 +173,37 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) | |||
208 | , sig_handler); | 173 | , sig_handler); |
209 | } | 174 | } |
210 | 175 | ||
211 | /* Open tty */ | ||
212 | handle = open(*argv, O_RDWR | O_NDELAY); | ||
213 | if (handle < 0) { | ||
214 | char *buf = concat_path_file("/dev", *argv); | ||
215 | handle = xopen(buf, O_RDWR | O_NDELAY); | ||
216 | /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ | ||
217 | free(buf); | ||
218 | } | ||
219 | |||
220 | /* Save current tty state */ | ||
221 | save_state(); | ||
222 | |||
223 | /* Configure tty */ | 176 | /* Configure tty */ |
224 | memcpy(&state, &saved_state, sizeof(state)); | 177 | memcpy(&state, &G.saved_state, sizeof(state)); |
225 | if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ | 178 | if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ |
226 | memset(&state.c_cc, 0, sizeof(state.c_cc)); | 179 | memset(&state.c_cc, 0, sizeof(state.c_cc)); |
227 | state.c_cc[VMIN] = 1; | 180 | state.c_cc[VMIN] = 1; |
228 | state.c_iflag = IGNBRK | IGNPAR; | 181 | state.c_iflag = IGNBRK | IGNPAR; |
229 | state.c_oflag = 0; | 182 | /*state.c_oflag = 0;*/ |
230 | state.c_lflag = 0; | 183 | /*state.c_lflag = 0;*/ |
231 | state.c_cflag = CS8 | HUPCL | CREAD | 184 | state.c_cflag = CS8 | HUPCL | CREAD |
232 | | ((opt & OPT_L_local) ? CLOCAL : 0) | 185 | | ((opt & OPT_L_local) ? CLOCAL : 0) |
233 | | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); | 186 | | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); |
234 | cfsetispeed(&state, cfgetispeed(&saved_state)); | 187 | cfsetispeed(&state, cfgetispeed(&G.saved_state)); |
235 | cfsetospeed(&state, cfgetospeed(&saved_state)); | 188 | cfsetospeed(&state, cfgetospeed(&G.saved_state)); |
236 | } | 189 | } |
237 | |||
238 | if (opt & OPT_s_baud) { | 190 | if (opt & OPT_s_baud) { |
239 | cfsetispeed(&state, baud_code); | 191 | cfsetispeed(&state, baud_code); |
240 | cfsetospeed(&state, baud_code); | 192 | cfsetospeed(&state, baud_code); |
241 | } | 193 | } |
242 | 194 | /* Set line status */ | |
243 | set_state(&state, encap); | 195 | if (tcsetattr_serial_or_warn(&state)) |
196 | goto bad; | ||
197 | /* Set line disclipline (N_SLIP always) */ | ||
198 | if (ioctl_or_warn(serial_fd, TIOCSETD, (void*)&int_N_SLIP)) | ||
199 | goto bad; | ||
200 | /* Set encapsulation (SLIP, CSLIP, etc) */ | ||
201 | if (ioctl_or_warn(serial_fd, SIOCSIFENCAP, &encap)) | ||
202 | goto bad; | ||
244 | 203 | ||
245 | /* Exit now if option -e was passed */ | 204 | /* Exit now if option -e was passed */ |
246 | if (opt & OPT_e_quit) | 205 | if (opt & OPT_e_quit) |
247 | return 0; | 206 | return EXIT_SUCCESS; |
248 | 207 | ||
249 | /* If we're not requested to watch, just keep descriptor open | 208 | /* If we're not requested to watch, just keep descriptor open |
250 | * until we are killed */ | 209 | * until we are killed */ |
@@ -254,17 +213,20 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) | |||
254 | 213 | ||
255 | /* Watch line for hangup */ | 214 | /* Watch line for hangup */ |
256 | while (1) { | 215 | while (1) { |
257 | if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) | 216 | int modem_stat; |
258 | goto no_carrier; | 217 | if (ioctl(serial_fd, TIOCMGET, &modem_stat)) |
218 | break; | ||
219 | if (!(modem_stat & TIOCM_CAR)) | ||
220 | break; | ||
259 | sleep(15); | 221 | sleep(15); |
260 | } | 222 | } |
261 | 223 | ||
262 | no_carrier: | ||
263 | |||
264 | /* Execute command on hangup */ | 224 | /* Execute command on hangup */ |
265 | if (opt & OPT_c_extcmd) | 225 | if (opt & OPT_c_extcmd) |
266 | system(extcmd); | 226 | system(extcmd); |
267 | 227 | ||
268 | /* Restore states and exit */ | 228 | /* Restore states and exit */ |
269 | restore_state_and_exit(EXIT_SUCCESS); | 229 | restore_state_and_exit(EXIT_SUCCESS); |
230 | bad: | ||
231 | restore_state_and_exit(EXIT_FAILURE); | ||
270 | } | 232 | } |
diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 270325164..d4c69e0f7 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c | |||
@@ -269,10 +269,11 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
269 | 269 | ||
270 | tcp = (applet_name[0] == 't'); | 270 | tcp = (applet_name[0] == 't'); |
271 | 271 | ||
272 | /* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */ | ||
273 | opt_complementary = "-3:i--i:ph:vv"; | ||
274 | #ifdef SSLSVD | 272 | #ifdef SSLSVD |
275 | opts = getopt32(argv, "+c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:", | 273 | opts = getopt32(argv, "^+" |
274 | "c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:" /* -c NUM, -b NUM */ | ||
275 | /* 3+ args, -i at most once, -p implies -h, -v is a counter */ | ||
276 | "\0" "-3:i--i:ph:vv", | ||
276 | &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, | 277 | &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, |
277 | &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose | 278 | &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose |
278 | ); | 279 | ); |
diff --git a/networking/telnet.c b/networking/telnet.c index 9f191f7ad..1f8a44466 100644 --- a/networking/telnet.c +++ b/networking/telnet.c | |||
@@ -44,7 +44,7 @@ | |||
44 | //config: Setting this option will forward the USER environment variable to the | 44 | //config: Setting this option will forward the USER environment variable to the |
45 | //config: remote host you are connecting to. This is useful when you need to | 45 | //config: remote host you are connecting to. This is useful when you need to |
46 | //config: log into a machine without telling the username (autologin). This | 46 | //config: log into a machine without telling the username (autologin). This |
47 | //config: option enables `-a' and `-l USER' arguments. | 47 | //config: option enables '-a' and '-l USER' options. |
48 | //config: | 48 | //config: |
49 | //config:config FEATURE_TELNET_WIDTH | 49 | //config:config FEATURE_TELNET_WIDTH |
50 | //config: bool "Enable window size autodetection" | 50 | //config: bool "Enable window size autodetection" |
@@ -643,8 +643,10 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) | |||
643 | } | 643 | } |
644 | 644 | ||
645 | #if ENABLE_FEATURE_TELNET_AUTOLOGIN | 645 | #if ENABLE_FEATURE_TELNET_AUTOLOGIN |
646 | if (1 & getopt32(argv, "al:", &G.autologin)) | 646 | if (1 == getopt32(argv, "al:", &G.autologin)) { |
647 | /* Only -a without -l USER picks $USER from envvar */ | ||
647 | G.autologin = getenv("USER"); | 648 | G.autologin = getenv("USER"); |
649 | } | ||
648 | argv += optind; | 650 | argv += optind; |
649 | #else | 651 | #else |
650 | argv++; | 652 | argv++; |
diff --git a/networking/telnetd.c b/networking/telnetd.c index 16c572e8d..a6bafa21d 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -659,13 +659,15 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
659 | #endif | 659 | #endif |
660 | INIT_G(); | 660 | INIT_G(); |
661 | 661 | ||
662 | /* -w NUM, and implies -F. -w and -i don't mix */ | ||
663 | IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:i--w:w--i";) | ||
664 | /* Even if !STANDALONE, we accept (and ignore) -i, thus people | 662 | /* Even if !STANDALONE, we accept (and ignore) -i, thus people |
665 | * don't need to guess whether it's ok to pass -i to us */ | 663 | * don't need to guess whether it's ok to pass -i to us */ |
666 | opt = getopt32(argv, "f:l:Ki" | 664 | opt = getopt32(argv, "^" |
665 | "f:l:Ki" | ||
667 | IF_FEATURE_TELNETD_STANDALONE("p:b:F") | 666 | IF_FEATURE_TELNETD_STANDALONE("p:b:F") |
668 | IF_FEATURE_TELNETD_INETD_WAIT("Sw:+"), | 667 | IF_FEATURE_TELNETD_INETD_WAIT("Sw:+") /* -w NUM */ |
668 | "\0" | ||
669 | /* -w implies -F. -w and -i don't mix */ | ||
670 | IF_FEATURE_TELNETD_INETD_WAIT("wF:i--w:w--i"), | ||
669 | &G.issuefile, &G.loginpath | 671 | &G.issuefile, &G.loginpath |
670 | IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr) | 672 | IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr) |
671 | IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger) | 673 | IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger) |
diff --git a/networking/tftp.c b/networking/tftp.c index 5baa80448..73a9829aa 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -761,15 +761,16 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) | |||
761 | 761 | ||
762 | INIT_G(); | 762 | INIT_G(); |
763 | 763 | ||
764 | /* -p or -g is mandatory, and they are mutually exclusive */ | 764 | IF_GETPUT(opt =) getopt32(argv, "^" |
765 | opt_complementary = "" IF_FEATURE_TFTP_GET("g:") IF_FEATURE_TFTP_PUT("p:") | ||
766 | IF_GETPUT("g--p:p--g:"); | ||
767 | |||
768 | IF_GETPUT(opt =) getopt32(argv, | ||
769 | IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p") | 765 | IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p") |
770 | "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:"), | 766 | "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:") |
767 | "\0" | ||
768 | /* -p or -g is mandatory, and they are mutually exclusive */ | ||
769 | IF_FEATURE_TFTP_GET("g:") IF_FEATURE_TFTP_PUT("p:") | ||
770 | IF_GETPUT("g--p:p--g:"), | ||
771 | &local_file, &remote_file | 771 | &local_file, &remote_file |
772 | IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str)); | 772 | IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str) |
773 | ); | ||
773 | argv += optind; | 774 | argv += optind; |
774 | 775 | ||
775 | # if ENABLE_FEATURE_TFTP_BLOCKSIZE | 776 | # if ENABLE_FEATURE_TFTP_BLOCKSIZE |
diff --git a/networking/traceroute.c b/networking/traceroute.c index a958a2c6c..8b6247482 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -12,12 +12,12 @@ | |||
12 | * this paragraph in its entirety in the documentation or other materials | 12 | * this paragraph in its entirety in the documentation or other materials |
13 | * provided with the distribution, and (3) all advertising materials mentioning | 13 | * provided with the distribution, and (3) all advertising materials mentioning |
14 | * features or use of this software display the following acknowledgement: | 14 | * features or use of this software display the following acknowledgement: |
15 | * ``This product includes software developed by the University of California, | 15 | * ''This product includes software developed by the University of California, |
16 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of | 16 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
17 | * the University nor the names of its contributors may be used to endorse | 17 | * the University nor the names of its contributors may be used to endorse |
18 | * or promote products derived from this software without specific prior | 18 | * or promote products derived from this software without specific prior |
19 | * written permission. | 19 | * written permission. |
20 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | 20 | * THIS SOFTWARE IS PROVIDED ''AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
21 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 21 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
23 | */ | 23 | */ |
@@ -833,9 +833,9 @@ common_traceroute_main(int op, char **argv) | |||
833 | 833 | ||
834 | INIT_G(); | 834 | INIT_G(); |
835 | 835 | ||
836 | /* minimum 1 arg */ | 836 | op |= getopt32(argv, "^" |
837 | opt_complementary = "-1:x-x"; | 837 | OPT_STRING |
838 | op |= getopt32(argv, OPT_STRING | 838 | "\0" "-1:x-x" /* minimum 1 arg */ |
839 | , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str | 839 | , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str |
840 | , &source, &waittime_str, &pausemsecs_str, &first_ttl_str | 840 | , &source, &waittime_str, &pausemsecs_str, &first_ttl_str |
841 | ); | 841 | ); |
diff --git a/networking/tunctl.c b/networking/tunctl.c index 0a26ff7fb..f2dc645a1 100644 --- a/networking/tunctl.c +++ b/networking/tunctl.c | |||
@@ -24,7 +24,7 @@ | |||
24 | //config: Allow to specify owner and group of newly created interface. | 24 | //config: Allow to specify owner and group of newly created interface. |
25 | //config: 340 bytes of pure bloat. Say no here. | 25 | //config: 340 bytes of pure bloat. Say no here. |
26 | 26 | ||
27 | //applet:IF_TUNCTL(APPLET(tunctl, BB_DIR_SBIN, BB_SUID_DROP)) | 27 | //applet:IF_TUNCTL(APPLET_NOEXEC(tunctl, tunctl, BB_DIR_SBIN, BB_SUID_DROP, tunctl)) |
28 | 28 | ||
29 | //kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o | 29 | //kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o |
30 | 30 | ||
@@ -83,10 +83,13 @@ int tunctl_main(int argc UNUSED_PARAM, char **argv) | |||
83 | #endif | 83 | #endif |
84 | }; | 84 | }; |
85 | 85 | ||
86 | opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d | 86 | opts = getopt32(argv, "^" |
87 | opts = getopt32(argv, "f:t:d:" IF_FEATURE_TUNCTL_UG("u:g:b"), | 87 | "f:t:d:" IF_FEATURE_TUNCTL_UG("u:g:b") |
88 | "\0" | ||
89 | "=0:t--d:d--t", // no arguments; t ^ d | ||
88 | &opt_device, &opt_name, &opt_name | 90 | &opt_device, &opt_name, &opt_name |
89 | IF_FEATURE_TUNCTL_UG(, &opt_user, &opt_group)); | 91 | IF_FEATURE_TUNCTL_UG(, &opt_user, &opt_group) |
92 | ); | ||
90 | 93 | ||
91 | // select device | 94 | // select device |
92 | memset(&ifr, 0, sizeof(ifr)); | 95 | memset(&ifr, 0, sizeof(ifr)); |
@@ -153,9 +156,12 @@ int tunctl_main(int argc UNUSED_PARAM, char **argv) | |||
153 | OPT_d = 1 << 2, // delete named interface | 156 | OPT_d = 1 << 2, // delete named interface |
154 | }; | 157 | }; |
155 | 158 | ||
156 | opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d | 159 | opts = getopt32(argv, "^" |
157 | opts = getopt32(argv, "f:t:d:u:g:b", // u, g, b accepted and ignored | 160 | "f:t:d:u:g:b" // u, g, b accepted and ignored |
158 | &opt_device, &opt_name, &opt_name, NULL, NULL); | 161 | "\0" |
162 | "=0:t--d:d--t", // no arguments; t ^ d | ||
163 | &opt_device, &opt_name, &opt_name, NULL, NULL | ||
164 | ); | ||
159 | 165 | ||
160 | // set interface name | 166 | // set interface name |
161 | memset(&ifr, 0, sizeof(ifr)); | 167 | memset(&ifr, 0, sizeof(ifr)); |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 43081efca..849ca1388 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -1101,14 +1101,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1101 | client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; | 1101 | client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; |
1102 | 1102 | ||
1103 | /* Parse command line */ | 1103 | /* Parse command line */ |
1104 | /* O,x: list; -T,-t,-A take numeric param */ | 1104 | opt = getopt32long(argv, "^" |
1105 | IF_UDHCP_VERBOSE(opt_complementary = "vv";) | 1105 | /* O,x: list; -T,-t,-A take numeric param */ |
1106 | IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;) | 1106 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*f" |
1107 | opt = getopt32(argv, "i:np:qRr:s:T:+t:+SA:+O:*ox:*f" | ||
1108 | USE_FOR_MMU("b") | 1107 | USE_FOR_MMU("b") |
1109 | ///IF_FEATURE_UDHCPC_ARPING("a") | 1108 | ///IF_FEATURE_UDHCPC_ARPING("a") |
1110 | IF_FEATURE_UDHCP_PORT("P:") | 1109 | IF_FEATURE_UDHCP_PORT("P:") |
1111 | "v" | 1110 | "v" |
1111 | "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ | ||
1112 | , udhcpc6_longopts | ||
1112 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ | 1113 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ |
1113 | , &client_config.script /* s */ | 1114 | , &client_config.script /* s */ |
1114 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ | 1115 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index ccf04993d..55e0400b9 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -1295,16 +1295,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1295 | str_V = "udhcp "BB_VER; | 1295 | str_V = "udhcp "BB_VER; |
1296 | 1296 | ||
1297 | /* Parse command line */ | 1297 | /* Parse command line */ |
1298 | /* O,x: list; -T,-t,-A take numeric param */ | 1298 | opt = getopt32long(argv, "^" |
1299 | IF_UDHCP_VERBOSE(opt_complementary = "vv";) | 1299 | /* O,x: list; -T,-t,-A take numeric param */ |
1300 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) | 1300 | "CV:H:h:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB" |
1301 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB" | ||
1302 | USE_FOR_MMU("b") | 1301 | USE_FOR_MMU("b") |
1303 | IF_FEATURE_UDHCPC_ARPING("a::") | 1302 | IF_FEATURE_UDHCPC_ARPING("a::") |
1304 | IF_FEATURE_UDHCP_PORT("P:") | 1303 | IF_FEATURE_UDHCP_PORT("P:") |
1305 | "v" | 1304 | "v" |
1305 | "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ | ||
1306 | , udhcpc_longopts | ||
1306 | , &str_V, &str_h, &str_h, &str_F | 1307 | , &str_V, &str_h, &str_h, &str_F |
1307 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ | 1308 | , &client_config.interface, &client_config.pidfile /* i,p */ |
1309 | , &str_r /* r */ | ||
1308 | , &client_config.script /* s */ | 1310 | , &client_config.script /* s */ |
1309 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ | 1311 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ |
1310 | , &list_O | 1312 | , &list_O |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 3a5fc2db7..05ddc8649 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -814,11 +814,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
814 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) | 814 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) |
815 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) | 815 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) |
816 | 816 | ||
817 | opt = getopt32(argv, "^" | ||
818 | "fSI:va:"IF_FEATURE_UDHCP_PORT("P:") | ||
819 | "\0" | ||
817 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 820 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 |
818 | opt_complementary = "vv"; | 821 | "vv" |
819 | #endif | 822 | #endif |
820 | opt = getopt32(argv, "fSI:va:" | ||
821 | IF_FEATURE_UDHCP_PORT("P:") | ||
822 | , &str_I | 823 | , &str_I |
823 | , &str_a | 824 | , &str_a |
824 | IF_FEATURE_UDHCP_PORT(, &str_P) | 825 | IF_FEATURE_UDHCP_PORT(, &str_P) |
diff --git a/networking/udhcp/dumpleases.c b/networking/udhcp/dumpleases.c index dce9084b3..70d2d1434 100644 --- a/networking/udhcp/dumpleases.c +++ b/networking/udhcp/dumpleases.c | |||
@@ -2,7 +2,7 @@ | |||
2 | /* | 2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
4 | */ | 4 | */ |
5 | //applet:IF_DUMPLEASES(APPLET(dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP)) | 5 | //applet:IF_DUMPLEASES(APPLET_NOEXEC(dumpleases, dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP, dumpleases)) |
6 | 6 | ||
7 | //kbuild:lib-$(CONFIG_DUMPLEASES) += dumpleases.o | 7 | //kbuild:lib-$(CONFIG_DUMPLEASES) += dumpleases.o |
8 | 8 | ||
@@ -51,12 +51,15 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) | |||
51 | "decimal\0" No_argument "d" | 51 | "decimal\0" No_argument "d" |
52 | ; | 52 | ; |
53 | 53 | ||
54 | applet_long_options = dumpleases_longopts; | ||
55 | #endif | 54 | #endif |
56 | init_unicode(); | 55 | init_unicode(); |
57 | 56 | ||
58 | opt_complementary = "=0:a--r:r--a"; | 57 | opt = getopt32long(argv, "^" |
59 | opt = getopt32(argv, "arf:d", &file); | 58 | "arf:d" |
59 | "\0" "=0:a--r:r--a", | ||
60 | dumpleases_longopts, | ||
61 | &file | ||
62 | ); | ||
60 | 63 | ||
61 | fd = xopen(file, O_RDONLY); | 64 | fd = xopen(file, O_RDONLY); |
62 | 65 | ||
diff --git a/networking/vconfig.c b/networking/vconfig.c index e6e2872bf..62a483865 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c | |||
@@ -16,7 +16,7 @@ | |||
16 | //config: help | 16 | //config: help |
17 | //config: Creates, removes, and configures VLAN interfaces | 17 | //config: Creates, removes, and configures VLAN interfaces |
18 | 18 | ||
19 | //applet:IF_VCONFIG(APPLET(vconfig, BB_DIR_SBIN, BB_SUID_DROP)) | 19 | //applet:IF_VCONFIG(APPLET_NOEXEC(vconfig, vconfig, BB_DIR_SBIN, BB_SUID_DROP, vconfig)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_VCONFIG) += vconfig.o | 21 | //kbuild:lib-$(CONFIG_VCONFIG) += vconfig.o |
22 | 22 | ||
diff --git a/networking/wget.c b/networking/wget.c index ab9bc1836..0001ddcba 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -1371,6 +1371,11 @@ IF_DESKTOP( "no-clobber\0" No_argument "\xf0") | |||
1371 | IF_DESKTOP( "no-host-directories\0" No_argument "\xf0") | 1371 | IF_DESKTOP( "no-host-directories\0" No_argument "\xf0") |
1372 | IF_DESKTOP( "no-parent\0" No_argument "\xf0") | 1372 | IF_DESKTOP( "no-parent\0" No_argument "\xf0") |
1373 | ; | 1373 | ; |
1374 | # define GETOPT32 getopt32long | ||
1375 | # define LONGOPTS ,wget_longopts | ||
1376 | #else | ||
1377 | # define GETOPT32 getopt32 | ||
1378 | # define LONGOPTS | ||
1374 | #endif | 1379 | #endif |
1375 | 1380 | ||
1376 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS | 1381 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS |
@@ -1387,11 +1392,9 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0") | |||
1387 | G.user_agent = "Wget"; /* "User-Agent" header field */ | 1392 | G.user_agent = "Wget"; /* "User-Agent" header field */ |
1388 | 1393 | ||
1389 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS | 1394 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS |
1390 | applet_long_options = wget_longopts; | ||
1391 | #endif | 1395 | #endif |
1392 | opt_complementary = "-1" /* at least one URL */ | 1396 | GETOPT32(argv, "^" |
1393 | IF_FEATURE_WGET_LONG_OPTIONS(":\xff::"); /* --header is a list */ | 1397 | "cqSO:P:Y:U:T:+" |
1394 | getopt32(argv, "cqSO:P:Y:U:T:+" | ||
1395 | /*ignored:*/ "t:" | 1398 | /*ignored:*/ "t:" |
1396 | /*ignored:*/ "n::" | 1399 | /*ignored:*/ "n::" |
1397 | /* wget has exactly four -n<letter> opts, all of which we can ignore: | 1400 | /* wget has exactly four -n<letter> opts, all of which we can ignore: |
@@ -1402,6 +1405,10 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0") | |||
1402 | * "n::" above says that we accept -n[ARG]. | 1405 | * "n::" above says that we accept -n[ARG]. |
1403 | * Specifying "n:" would be a bug: "-n ARG" would eat ARG! | 1406 | * Specifying "n:" would be a bug: "-n ARG" would eat ARG! |
1404 | */ | 1407 | */ |
1408 | "\0" | ||
1409 | "-1" /* at least one URL */ | ||
1410 | IF_FEATURE_WGET_LONG_OPTIONS(":\xff::") /* --header is a list */ | ||
1411 | LONGOPTS | ||
1405 | , &G.fname_out, &G.dir_prefix, | 1412 | , &G.fname_out, &G.dir_prefix, |
1406 | &G.proxy_flag, &G.user_agent, | 1413 | &G.proxy_flag, &G.user_agent, |
1407 | IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), | 1414 | IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), |
diff --git a/networking/whois.c b/networking/whois.c index 0cb7e5411..fd1cdf43e 100644 --- a/networking/whois.c +++ b/networking/whois.c | |||
@@ -167,8 +167,7 @@ int whois_main(int argc UNUSED_PARAM, char **argv) | |||
167 | int port = 43; | 167 | int port = 43; |
168 | const char *host = "whois.iana.org"; | 168 | const char *host = "whois.iana.org"; |
169 | 169 | ||
170 | opt_complementary = "-1"; | 170 | getopt32(argv, "^" "ih:p:+" "\0" "-1", &host, &port); |
171 | getopt32(argv, "ih:p:+", &host, &port); | ||
172 | argv += optind; | 171 | argv += optind; |
173 | 172 | ||
174 | do { | 173 | do { |
diff --git a/networking/zcip.c b/networking/zcip.c index 94174a165..55440285f 100644 --- a/networking/zcip.c +++ b/networking/zcip.c | |||
@@ -253,8 +253,9 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
253 | #define QUIT (opts & 2) | 253 | #define QUIT (opts & 2) |
254 | // Parse commandline: prog [options] ifname script | 254 | // Parse commandline: prog [options] ifname script |
255 | // exactly 2 args; -v accumulates and implies -f | 255 | // exactly 2 args; -v accumulates and implies -f |
256 | opt_complementary = "=2:vv:vf"; | 256 | opts = getopt32(argv, "^" "fqr:l:v" "\0" "=2:vv:vf", |
257 | opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose); | 257 | &r_opt, &l_opt, &verbose |
258 | ); | ||
258 | #if !BB_MMU | 259 | #if !BB_MMU |
259 | // on NOMMU reexec early (or else we will rerun things twice) | 260 | // on NOMMU reexec early (or else we will rerun things twice) |
260 | if (!FOREGROUND) | 261 | if (!FOREGROUND) |
diff --git a/printutils/lpd.c b/printutils/lpd.c index 3fdba5d2b..662d3a224 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c | |||
@@ -198,9 +198,8 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) | |||
198 | q = p; // next line | 198 | q = p; // next line |
199 | } | 199 | } |
200 | // helper should not talk over network. | 200 | // helper should not talk over network. |
201 | // this call reopens stdio fds to "/dev/null" | 201 | // this call reopens stdio fds to "/dev/null". |
202 | // (no daemonization is done) | 202 | bb_daemon_helper(DAEMON_DEVNULL_STDIO); |
203 | bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); | ||
204 | BB_EXECVP_or_die(argv); | 203 | BB_EXECVP_or_die(argv); |
205 | } | 204 | } |
206 | 205 | ||
diff --git a/procps/free.c b/procps/free.c index 618664e08..b57e4a322 100644 --- a/procps/free.c +++ b/procps/free.c | |||
@@ -15,7 +15,7 @@ | |||
15 | //config: memory in the system, as well as the buffers used by the kernel. | 15 | //config: memory in the system, as well as the buffers used by the kernel. |
16 | //config: The shared memory column should be ignored; it is obsolete. | 16 | //config: The shared memory column should be ignored; it is obsolete. |
17 | 17 | ||
18 | //applet:IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_FREE(APPLET_NOEXEC(free, free, BB_DIR_USR_BIN, BB_SUID_DROP, free)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_FREE) += free.o | 20 | //kbuild:lib-$(CONFIG_FREE) += free.o |
21 | 21 | ||
@@ -47,7 +47,10 @@ struct globals { | |||
47 | #endif | 47 | #endif |
48 | } FIX_ALIASING; | 48 | } FIX_ALIASING; |
49 | #define G (*(struct globals*)bb_common_bufsiz1) | 49 | #define G (*(struct globals*)bb_common_bufsiz1) |
50 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 50 | #define INIT_G() do { \ |
51 | setup_common_bufsiz(); \ | ||
52 | /* NB: noexec applet - globals not zeroed */ \ | ||
53 | } while (0) | ||
51 | 54 | ||
52 | 55 | ||
53 | static unsigned long long scale(unsigned long d) | 56 | static unsigned long long scale(unsigned long d) |
diff --git a/procps/fuser.c b/procps/fuser.c index 2585a4203..418f57b57 100644 --- a/procps/fuser.c +++ b/procps/fuser.c | |||
@@ -299,8 +299,7 @@ int fuser_main(int argc UNUSED_PARAM, char **argv) | |||
299 | break; | 299 | break; |
300 | } | 300 | } |
301 | 301 | ||
302 | opt_complementary = "-1"; /* at least one param */ | 302 | getopt32(argv, "^" OPTION_STRING "\0" "-1"/*at least one arg*/); |
303 | getopt32(argv, OPTION_STRING); | ||
304 | argv += optind; | 303 | argv += optind; |
305 | 304 | ||
306 | pp = argv; | 305 | pp = argv; |
diff --git a/procps/iostat.c b/procps/iostat.c index 6a39c324f..050625f57 100644 --- a/procps/iostat.c +++ b/procps/iostat.c | |||
@@ -418,8 +418,7 @@ int iostat_main(int argc UNUSED_PARAM, char **argv) | |||
418 | 418 | ||
419 | /* Parse and process arguments */ | 419 | /* Parse and process arguments */ |
420 | /* -k and -m are mutually exclusive */ | 420 | /* -k and -m are mutually exclusive */ |
421 | opt_complementary = "k--m:m--k"; | 421 | opt = getopt32(argv, "^" "cdtzkm" "\0" "k--m:m--k"); |
422 | opt = getopt32(argv, "cdtzkm"); | ||
423 | if (!(opt & (OPT_c + OPT_d))) | 422 | if (!(opt & (OPT_c + OPT_d))) |
424 | /* Default is -cd */ | 423 | /* Default is -cd */ |
425 | opt |= OPT_c + OPT_d; | 424 | opt |= OPT_c + OPT_d; |
diff --git a/procps/kill.c b/procps/kill.c index 09beefb2d..0ddae2f70 100644 --- a/procps/kill.c +++ b/procps/kill.c | |||
@@ -32,10 +32,10 @@ | |||
32 | //config: in its own session, so it won't kill the shell that is running | 32 | //config: in its own session, so it won't kill the shell that is running |
33 | //config: the script it was called from. | 33 | //config: the script it was called from. |
34 | 34 | ||
35 | //applet:IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) | 35 | //applet:IF_KILL( APPLET_NOFORK(kill, kill, BB_DIR_BIN, BB_SUID_DROP, kill)) |
36 | // APPLET_ODDNAME:name main location suid_type help | 36 | // APPLET_NOFORK:name main location suid_type help |
37 | //applet:IF_KILLALL( APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) | 37 | //applet:IF_KILLALL( APPLET_NOFORK(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) |
38 | //applet:IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) | 38 | //applet:IF_KILLALL5(APPLET_NOFORK(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) |
39 | 39 | ||
40 | //kbuild:lib-$(CONFIG_KILL) += kill.o | 40 | //kbuild:lib-$(CONFIG_KILL) += kill.o |
41 | //kbuild:lib-$(CONFIG_KILLALL) += kill.o | 41 | //kbuild:lib-$(CONFIG_KILLALL) += kill.o |
@@ -87,7 +87,7 @@ | |||
87 | * + we can't use xfunc here | 87 | * + we can't use xfunc here |
88 | * + we can't use applet_name | 88 | * + we can't use applet_name |
89 | * + we can't use bb_show_usage | 89 | * + we can't use bb_show_usage |
90 | * (Above doesn't apply for killall[5] cases) | 90 | * (doesn't apply for killall[5], still should be careful b/c NOFORK) |
91 | * | 91 | * |
92 | * kill %n gets translated into kill ' -<process group>' by shell (note space!) | 92 | * kill %n gets translated into kill ' -<process group>' by shell (note space!) |
93 | * This is needed to avoid collision with kill -9 ... syntax | 93 | * This is needed to avoid collision with kill -9 ... syntax |
diff --git a/procps/mpstat.c b/procps/mpstat.c index 05a3f3ff3..c6279f9d8 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | //applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP)) | 10 | //applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP)) |
11 | /* shouldn't be noexec: "mpstat INTERVAL" runs indefinitely */ | ||
11 | 12 | ||
12 | //kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o | 13 | //kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o |
13 | 14 | ||
diff --git a/procps/pgrep.c b/procps/pgrep.c index a3ca9e295..a16a6e959 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c | |||
@@ -18,9 +18,13 @@ | |||
18 | //config: help | 18 | //config: help |
19 | //config: Send signals to processes by name. | 19 | //config: Send signals to processes by name. |
20 | 20 | ||
21 | //applet:IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP)) | 21 | //applet:IF_PGREP(APPLET_ODDNAME(pgrep, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pgrep)) |
22 | // APPLET_ODDNAME:name main location suid_type help | 22 | // APPLET_ODDNAME:name main location suid_type help |
23 | //applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) | 23 | //applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) |
24 | /* can't be noexec: can find _itself_ under wrong name, since after fork only, | ||
25 | * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)), | ||
26 | * but cmdline? | ||
27 | */ | ||
24 | 28 | ||
25 | //kbuild:lib-$(CONFIG_PGREP) += pgrep.o | 29 | //kbuild:lib-$(CONFIG_PGREP) += pgrep.o |
26 | //kbuild:lib-$(CONFIG_PKILL) += pgrep.o | 30 | //kbuild:lib-$(CONFIG_PKILL) += pgrep.o |
diff --git a/procps/pidof.c b/procps/pidof.c index 41247a02c..98d7949f8 100644 --- a/procps/pidof.c +++ b/procps/pidof.c | |||
@@ -30,6 +30,10 @@ | |||
30 | //config: of the pidof, in other words the calling shell or shell script. | 30 | //config: of the pidof, in other words the calling shell or shell script. |
31 | 31 | ||
32 | //applet:IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) | 32 | //applet:IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) |
33 | /* can't be noexec: can find _itself_ under wrong name, since after fork only, | ||
34 | * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)), | ||
35 | * but cmdline? | ||
36 | */ | ||
33 | 37 | ||
34 | //kbuild:lib-$(CONFIG_PIDOF) += pidof.o | 38 | //kbuild:lib-$(CONFIG_PIDOF) += pidof.o |
35 | 39 | ||
diff --git a/procps/pmap.c b/procps/pmap.c index c8f728897..5c2d1ad59 100644 --- a/procps/pmap.c +++ b/procps/pmap.c | |||
@@ -18,7 +18,7 @@ | |||
18 | //kbuild:lib-$(CONFIG_PMAP) += pmap.o | 18 | //kbuild:lib-$(CONFIG_PMAP) += pmap.o |
19 | 19 | ||
20 | //usage:#define pmap_trivial_usage | 20 | //usage:#define pmap_trivial_usage |
21 | //usage: "[-xq] PID" | 21 | //usage: "[-xq] PID..." |
22 | //usage:#define pmap_full_usage "\n\n" | 22 | //usage:#define pmap_full_usage "\n\n" |
23 | //usage: "Display process memory usage" | 23 | //usage: "Display process memory usage" |
24 | //usage: "\n" | 24 | //usage: "\n" |
@@ -96,7 +96,7 @@ int pmap_main(int argc UNUSED_PARAM, char **argv) | |||
96 | unsigned opts; | 96 | unsigned opts; |
97 | int ret; | 97 | int ret; |
98 | 98 | ||
99 | opts = getopt32(argv, "xq"); | 99 | opts = getopt32(argv, "^" "xq" "\0" "-1"); /* min one arg */ |
100 | argv += optind; | 100 | argv += optind; |
101 | 101 | ||
102 | ret = 0; | 102 | ret = 0; |
diff --git a/procps/powertop.c b/procps/powertop.c index ebd659bdb..5d522bf91 100644 --- a/procps/powertop.c +++ b/procps/powertop.c | |||
@@ -8,11 +8,6 @@ | |||
8 | * | 8 | * |
9 | * Licensed under GPLv2, see file LICENSE in this source tree. | 9 | * Licensed under GPLv2, see file LICENSE in this source tree. |
10 | */ | 10 | */ |
11 | |||
12 | //applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP)) | ||
13 | |||
14 | //kbuild:lib-$(CONFIG_POWERTOP) += powertop.o | ||
15 | |||
16 | //config:config POWERTOP | 11 | //config:config POWERTOP |
17 | //config: bool "powertop (9.1 kb)" | 12 | //config: bool "powertop (9.1 kb)" |
18 | //config: default y | 13 | //config: default y |
@@ -27,6 +22,10 @@ | |||
27 | //config: Without this, powertop will only refresh display every 10 seconds. | 22 | //config: Without this, powertop will only refresh display every 10 seconds. |
28 | //config: No keyboard commands will work, only ^C to terminate. | 23 | //config: No keyboard commands will work, only ^C to terminate. |
29 | 24 | ||
25 | //applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP)) | ||
26 | |||
27 | //kbuild:lib-$(CONFIG_POWERTOP) += powertop.o | ||
28 | |||
30 | // XXX This should be configurable | 29 | // XXX This should be configurable |
31 | #define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 | 30 | #define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 |
32 | 31 | ||
@@ -718,7 +717,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) | |||
718 | set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG); | 717 | set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG); |
719 | bb_signals(BB_FATAL_SIGS, sig_handler); | 718 | bb_signals(BB_FATAL_SIGS, sig_handler); |
720 | /* So we don't forget to reset term settings */ | 719 | /* So we don't forget to reset term settings */ |
721 | atexit(reset_term); | 720 | die_func = reset_term; |
722 | #endif | 721 | #endif |
723 | 722 | ||
724 | /* Collect initial data */ | 723 | /* Collect initial data */ |
@@ -855,6 +854,9 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) | |||
855 | } /* for (;;) */ | 854 | } /* for (;;) */ |
856 | 855 | ||
857 | bb_putchar('\n'); | 856 | bb_putchar('\n'); |
857 | #if ENABLE_FEATURE_POWERTOP_INTERACTIVE | ||
858 | reset_term(); | ||
859 | #endif | ||
858 | 860 | ||
859 | return EXIT_SUCCESS; | 861 | return EXIT_SUCCESS; |
860 | } | 862 | } |
diff --git a/procps/ps.c b/procps/ps.c index 3e83a3e03..742d1715e 100644 --- a/procps/ps.c +++ b/procps/ps.c | |||
@@ -15,26 +15,26 @@ | |||
15 | //config: ps gives a snapshot of the current processes. | 15 | //config: ps gives a snapshot of the current processes. |
16 | //config: | 16 | //config: |
17 | //config:config FEATURE_PS_WIDE | 17 | //config:config FEATURE_PS_WIDE |
18 | //config: bool "Enable wide output option (-w)" | 18 | //config: bool "Enable wide output (-w)" |
19 | //config: default y | 19 | //config: default y |
20 | //config: depends on PS && !DESKTOP | 20 | //config: depends on (PS || MINIPS) && !DESKTOP |
21 | //config: help | 21 | //config: help |
22 | //config: Support argument 'w' for wide output. | 22 | //config: Support argument 'w' for wide output. |
23 | //config: If given once, 132 chars are printed, and if given more | 23 | //config: If given once, 132 chars are printed, and if given more |
24 | //config: than once, the length is unlimited. | 24 | //config: than once, the length is unlimited. |
25 | //config: | 25 | //config: |
26 | //config:config FEATURE_PS_LONG | 26 | //config:config FEATURE_PS_LONG |
27 | //config: bool "Enable long output option (-l)" | 27 | //config: bool "Enable long output (-l)" |
28 | //config: default y | 28 | //config: default y |
29 | //config: depends on PS && !DESKTOP | 29 | //config: depends on (PS || MINIPS) && !DESKTOP |
30 | //config: help | 30 | //config: help |
31 | //config: Support argument 'l' for long output. | 31 | //config: Support argument 'l' for long output. |
32 | //config: Adds fields PPID, RSS, START, TIME & TTY | 32 | //config: Adds fields PPID, RSS, START, TIME & TTY |
33 | //config: | 33 | //config: |
34 | //config:config FEATURE_PS_TIME | 34 | //config:config FEATURE_PS_TIME |
35 | //config: bool "Support -o time and -o etime output specifiers" | 35 | //config: bool "Enable -o time and -o etime specifiers" |
36 | //config: default y | 36 | //config: default y |
37 | //config: depends on PS && DESKTOP | 37 | //config: depends on (PS || MINIPS) && DESKTOP |
38 | //config: select PLATFORM_LINUX | 38 | //config: select PLATFORM_LINUX |
39 | //config: | 39 | //config: |
40 | //config:config FEATURE_PS_UNUSUAL_SYSTEMS | 40 | //config:config FEATURE_PS_UNUSUAL_SYSTEMS |
@@ -46,13 +46,16 @@ | |||
46 | //config: (if you are on Linux 2.4.0+ and use ELF, you don't need this) | 46 | //config: (if you are on Linux 2.4.0+ and use ELF, you don't need this) |
47 | //config: | 47 | //config: |
48 | //config:config FEATURE_PS_ADDITIONAL_COLUMNS | 48 | //config:config FEATURE_PS_ADDITIONAL_COLUMNS |
49 | //config: bool "Support -o rgroup, -o ruser, -o nice specifiers" | 49 | //config: bool "Enable -o rgroup, -o ruser, -o nice specifiers" |
50 | //config: default y | 50 | //config: default y |
51 | //config: depends on PS && DESKTOP | 51 | //config: depends on (PS || MINIPS) && DESKTOP |
52 | 52 | ||
53 | //applet:IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP)) | 53 | // APPLET_NOEXEC:name main location suid_type help |
54 | //applet:IF_PS( APPLET_NOEXEC(ps, ps, BB_DIR_BIN, BB_SUID_DROP, ps)) | ||
55 | //applet:IF_MINIPS(APPLET_NOEXEC(minips, ps, BB_DIR_BIN, BB_SUID_DROP, ps)) | ||
54 | 56 | ||
55 | //kbuild:lib-$(CONFIG_PS) += ps.o | 57 | //kbuild:lib-$(CONFIG_PS) += ps.o |
58 | //kbuild:lib-$(CONFIG_MINIPS) += ps.o | ||
56 | 59 | ||
57 | //usage:#if ENABLE_DESKTOP | 60 | //usage:#if ENABLE_DESKTOP |
58 | //usage: | 61 | //usage: |
@@ -144,12 +147,6 @@ static unsigned long get_uptime(void) | |||
144 | #endif | 147 | #endif |
145 | 148 | ||
146 | #if ENABLE_DESKTOP | 149 | #if ENABLE_DESKTOP |
147 | |||
148 | #include <sys/times.h> /* for times() */ | ||
149 | #ifndef AT_CLKTCK | ||
150 | # define AT_CLKTCK 17 | ||
151 | #endif | ||
152 | |||
153 | /* TODO: | 150 | /* TODO: |
154 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html | 151 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html |
155 | * specifies (for XSI-conformant systems) following default columns | 152 | * specifies (for XSI-conformant systems) following default columns |
@@ -186,7 +183,9 @@ struct globals { | |||
186 | char *buffer; | 183 | char *buffer; |
187 | unsigned terminal_width; | 184 | unsigned terminal_width; |
188 | #if ENABLE_FEATURE_PS_TIME | 185 | #if ENABLE_FEATURE_PS_TIME |
186 | # if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__) | ||
189 | unsigned kernel_HZ; | 187 | unsigned kernel_HZ; |
188 | # endif | ||
190 | unsigned long seconds_since_boot; | 189 | unsigned long seconds_since_boot; |
191 | #endif | 190 | #endif |
192 | } FIX_ALIASING; | 191 | } FIX_ALIASING; |
@@ -197,91 +196,15 @@ struct globals { | |||
197 | #define need_flags (G.need_flags ) | 196 | #define need_flags (G.need_flags ) |
198 | #define buffer (G.buffer ) | 197 | #define buffer (G.buffer ) |
199 | #define terminal_width (G.terminal_width ) | 198 | #define terminal_width (G.terminal_width ) |
200 | #define kernel_HZ (G.kernel_HZ ) | ||
201 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 199 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
202 | 200 | ||
203 | #if ENABLE_FEATURE_PS_TIME | 201 | #if ENABLE_FEATURE_PS_TIME |
204 | /* for ELF executables, notes are pushed before environment and args */ | 202 | # if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__) |
205 | static uintptr_t find_elf_note(uintptr_t findme) | 203 | # define get_kernel_HZ() (G.kernel_HZ) |
206 | { | 204 | # else |
207 | uintptr_t *ep = (uintptr_t *) environ; | 205 | /* non-ancient Linux standardized on 100 for "times" freq */ |
208 | 206 | # define get_kernel_HZ() ((unsigned)100) | |
209 | while (*ep++) | 207 | # endif |
210 | continue; | ||
211 | while (*ep) { | ||
212 | if (ep[0] == findme) { | ||
213 | return ep[1]; | ||
214 | } | ||
215 | ep += 2; | ||
216 | } | ||
217 | return -1; | ||
218 | } | ||
219 | |||
220 | #if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS | ||
221 | static unsigned get_HZ_by_waiting(void) | ||
222 | { | ||
223 | struct timeval tv1, tv2; | ||
224 | unsigned t1, t2, r, hz; | ||
225 | unsigned cnt = cnt; /* for compiler */ | ||
226 | int diff; | ||
227 | |||
228 | r = 0; | ||
229 | |||
230 | /* Wait for times() to reach new tick */ | ||
231 | t1 = times(NULL); | ||
232 | do { | ||
233 | t2 = times(NULL); | ||
234 | } while (t2 == t1); | ||
235 | gettimeofday(&tv2, NULL); | ||
236 | |||
237 | do { | ||
238 | t1 = t2; | ||
239 | tv1.tv_usec = tv2.tv_usec; | ||
240 | |||
241 | /* Wait exactly one times() tick */ | ||
242 | do { | ||
243 | t2 = times(NULL); | ||
244 | } while (t2 == t1); | ||
245 | gettimeofday(&tv2, NULL); | ||
246 | |||
247 | /* Calculate ticks per sec, rounding up to even */ | ||
248 | diff = tv2.tv_usec - tv1.tv_usec; | ||
249 | if (diff <= 0) diff += 1000000; | ||
250 | hz = 1000000u / (unsigned)diff; | ||
251 | hz = (hz+1) & ~1; | ||
252 | |||
253 | /* Count how many same hz values we saw */ | ||
254 | if (r != hz) { | ||
255 | r = hz; | ||
256 | cnt = 0; | ||
257 | } | ||
258 | cnt++; | ||
259 | } while (cnt < 3); /* exit if saw 3 same values */ | ||
260 | |||
261 | return r; | ||
262 | } | ||
263 | #else | ||
264 | static inline unsigned get_HZ_by_waiting(void) | ||
265 | { | ||
266 | /* Better method? */ | ||
267 | return 100; | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | static unsigned get_kernel_HZ(void) | ||
272 | { | ||
273 | if (kernel_HZ) | ||
274 | return kernel_HZ; | ||
275 | |||
276 | /* Works for ELF only, Linux 2.4.0+ */ | ||
277 | kernel_HZ = find_elf_note(AT_CLKTCK); | ||
278 | if (kernel_HZ == (unsigned)-1) | ||
279 | kernel_HZ = get_HZ_by_waiting(); | ||
280 | |||
281 | G.seconds_since_boot = get_uptime(); | ||
282 | |||
283 | return kernel_HZ; | ||
284 | } | ||
285 | #endif | 208 | #endif |
286 | 209 | ||
287 | /* Print value to buf, max size+1 chars (including trailing '\0') */ | 210 | /* Print value to buf, max size+1 chars (including trailing '\0') */ |
@@ -379,52 +302,71 @@ static void func_tty(char *buf, int size, const procps_status_t *ps) | |||
379 | #endif | 302 | #endif |
380 | 303 | ||
381 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 304 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
382 | |||
383 | static void func_rgroup(char *buf, int size, const procps_status_t *ps) | 305 | static void func_rgroup(char *buf, int size, const procps_status_t *ps) |
384 | { | 306 | { |
385 | safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1); | 307 | safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1); |
386 | } | 308 | } |
387 | |||
388 | static void func_ruser(char *buf, int size, const procps_status_t *ps) | 309 | static void func_ruser(char *buf, int size, const procps_status_t *ps) |
389 | { | 310 | { |
390 | safe_strncpy(buf, get_cached_username(ps->ruid), size+1); | 311 | safe_strncpy(buf, get_cached_username(ps->ruid), size+1); |
391 | } | 312 | } |
392 | |||
393 | static void func_nice(char *buf, int size, const procps_status_t *ps) | 313 | static void func_nice(char *buf, int size, const procps_status_t *ps) |
394 | { | 314 | { |
395 | sprintf(buf, "%*d", size, ps->niceness); | 315 | sprintf(buf, "%*d", size, ps->niceness); |
396 | } | 316 | } |
397 | |||
398 | #endif | 317 | #endif |
399 | 318 | ||
400 | #if ENABLE_FEATURE_PS_TIME | 319 | #if ENABLE_FEATURE_PS_TIME |
320 | static void format_time(char *buf, int size, unsigned long tt) | ||
321 | { | ||
322 | unsigned ff; | ||
401 | 323 | ||
324 | /* Used to show "14453:50" if tt is large. Ugly. | ||
325 | * procps-ng 3.3.10 uses "[[dd-]hh:]mm:ss" format. | ||
326 | * TODO: switch to that? | ||
327 | */ | ||
328 | |||
329 | /* Formatting for 5-char TIME column. | ||
330 | * NB: "size" is not always 5: ELAPSED is wider (7), | ||
331 | * not taking advantage of that (yet?). | ||
332 | */ | ||
333 | ff = tt % 60; | ||
334 | tt /= 60; | ||
335 | if (tt < 60) { | ||
336 | snprintf(buf, size+1, "%2u:%02u", (unsigned)tt, ff); | ||
337 | return; | ||
338 | } | ||
339 | ff = tt % 60; | ||
340 | tt /= 60; | ||
341 | if (tt < 24) { | ||
342 | snprintf(buf, size+1, "%2uh%02u", (unsigned)tt, ff); | ||
343 | return; | ||
344 | } | ||
345 | ff = tt % 24; | ||
346 | tt /= 24; | ||
347 | if (tt < 100) { | ||
348 | snprintf(buf, size+1, "%2ud%02u", (unsigned)tt, ff); | ||
349 | return; | ||
350 | } | ||
351 | snprintf(buf, size+1, "%4lud", tt); | ||
352 | } | ||
402 | static void func_etime(char *buf, int size, const procps_status_t *ps) | 353 | static void func_etime(char *buf, int size, const procps_status_t *ps) |
403 | { | 354 | { |
404 | /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ | 355 | /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ |
405 | unsigned long mm; | 356 | unsigned long mm; |
406 | unsigned ss; | ||
407 | 357 | ||
408 | mm = ps->start_time / get_kernel_HZ(); | 358 | mm = ps->start_time / get_kernel_HZ(); |
409 | /* must be after get_kernel_HZ()! */ | ||
410 | mm = G.seconds_since_boot - mm; | 359 | mm = G.seconds_since_boot - mm; |
411 | ss = mm % 60; | 360 | format_time(buf, size, mm); |
412 | mm /= 60; | ||
413 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
414 | } | 361 | } |
415 | |||
416 | static void func_time(char *buf, int size, const procps_status_t *ps) | 362 | static void func_time(char *buf, int size, const procps_status_t *ps) |
417 | { | 363 | { |
418 | /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ | 364 | /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ |
419 | unsigned long mm; | 365 | unsigned long mm; |
420 | unsigned ss; | ||
421 | 366 | ||
422 | mm = (ps->utime + ps->stime) / get_kernel_HZ(); | 367 | mm = (ps->utime + ps->stime) / get_kernel_HZ(); |
423 | ss = mm % 60; | 368 | format_time(buf, size, mm); |
424 | mm /= 60; | ||
425 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
426 | } | 369 | } |
427 | |||
428 | #endif | 370 | #endif |
429 | 371 | ||
430 | #if ENABLE_SELINUX | 372 | #if ENABLE_SELINUX |
@@ -465,7 +407,7 @@ static const ps_out_t out_spec[] = { | |||
465 | // { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, | 407 | // { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, |
466 | #endif | 408 | #endif |
467 | #if ENABLE_FEATURE_PS_TIME | 409 | #if ENABLE_FEATURE_PS_TIME |
468 | { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, | 410 | { 5 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, |
469 | #endif | 411 | #endif |
470 | #if !ENABLE_PLATFORM_MINGW32 | 412 | #if !ENABLE_PLATFORM_MINGW32 |
471 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, | 413 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, |
@@ -641,6 +583,12 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |||
641 | }; | 583 | }; |
642 | 584 | ||
643 | INIT_G(); | 585 | INIT_G(); |
586 | #if ENABLE_FEATURE_PS_TIME | ||
587 | G.seconds_since_boot = get_uptime(); | ||
588 | # if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__) | ||
589 | G.kernel_HZ = bb_clk_tck(); /* this is sysconf(_SC_CLK_TCK) */ | ||
590 | # endif | ||
591 | #endif | ||
644 | 592 | ||
645 | // POSIX: | 593 | // POSIX: |
646 | // -a Write information for all processes associated with terminals | 594 | // -a Write information for all processes associated with terminals |
@@ -731,9 +679,12 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
731 | # if ENABLE_FEATURE_PS_WIDE | 679 | # if ENABLE_FEATURE_PS_WIDE |
732 | /* -w is a bit complicated */ | 680 | /* -w is a bit complicated */ |
733 | int w_count = 0; | 681 | int w_count = 0; |
734 | opt_complementary = "-:ww"; | 682 | make_all_argv_opts(argv); |
735 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") | 683 | opts = getopt32(argv, "^" |
736 | "w", &w_count); | 684 | IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")"w" |
685 | "\0" "ww", | ||
686 | &w_count | ||
687 | ); | ||
737 | /* if w is given once, GNU ps sets the width to 132, | 688 | /* if w is given once, GNU ps sets the width to 132, |
738 | * if w is given more than once, it is "unlimited" | 689 | * if w is given more than once, it is "unlimited" |
739 | */ | 690 | */ |
@@ -747,7 +698,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
747 | } | 698 | } |
748 | # else | 699 | # else |
749 | /* -w is not supported, only -Z and/or -T */ | 700 | /* -w is not supported, only -Z and/or -T */ |
750 | opt_complementary = "-"; | 701 | make_all_argv_opts(argv); |
751 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); | 702 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); |
752 | # endif | 703 | # endif |
753 | 704 | ||
diff --git a/procps/pstree.c b/procps/pstree.c index 212cda23c..4fda1c21c 100644 --- a/procps/pstree.c +++ b/procps/pstree.c | |||
@@ -9,14 +9,13 @@ | |||
9 | * | 9 | * |
10 | * Licensed under GPLv2, see file LICENSE in this source tree. | 10 | * Licensed under GPLv2, see file LICENSE in this source tree. |
11 | */ | 11 | */ |
12 | |||
13 | //config:config PSTREE | 12 | //config:config PSTREE |
14 | //config: bool "pstree (9.4 kb)" | 13 | //config: bool "pstree (9.4 kb)" |
15 | //config: default y | 14 | //config: default y |
16 | //config: help | 15 | //config: help |
17 | //config: Display a tree of processes. | 16 | //config: Display a tree of processes. |
18 | 17 | ||
19 | //applet:IF_PSTREE(APPLET(pstree, BB_DIR_USR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_PSTREE(APPLET_NOEXEC(pstree, pstree, BB_DIR_USR_BIN, BB_SUID_DROP, pstree)) |
20 | 19 | ||
21 | //kbuild:lib-$(CONFIG_PSTREE) += pstree.o | 20 | //kbuild:lib-$(CONFIG_PSTREE) += pstree.o |
22 | 21 | ||
@@ -387,8 +386,7 @@ int pstree_main(int argc UNUSED_PARAM, char **argv) | |||
387 | 386 | ||
388 | G.output_width = get_terminal_width(0); | 387 | G.output_width = get_terminal_width(0); |
389 | 388 | ||
390 | opt_complementary = "?1"; | 389 | getopt32(argv, "^" "p" "\0" "?1"); |
391 | getopt32(argv, "p"); | ||
392 | argv += optind; | 390 | argv += optind; |
393 | 391 | ||
394 | if (argv[0]) { | 392 | if (argv[0]) { |
diff --git a/procps/pwdx.c b/procps/pwdx.c index dac238950..c72cf804a 100644 --- a/procps/pwdx.c +++ b/procps/pwdx.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: help | 14 | //config: help |
15 | //config: Report current working directory of a process | 15 | //config: Report current working directory of a process |
16 | 16 | ||
17 | //applet:IF_PWDX(APPLET(pwdx, BB_DIR_USR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_PWDX(APPLET_NOFORK(pwdx, pwdx, BB_DIR_USR_BIN, BB_SUID_DROP, pwdx)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_PWDX) += pwdx.o | 19 | //kbuild:lib-$(CONFIG_PWDX) += pwdx.o |
20 | 20 | ||
@@ -28,8 +28,7 @@ | |||
28 | int pwdx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 28 | int pwdx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
29 | int pwdx_main(int argc UNUSED_PARAM, char **argv) | 29 | int pwdx_main(int argc UNUSED_PARAM, char **argv) |
30 | { | 30 | { |
31 | opt_complementary = "-1"; | 31 | getopt32(argv, "^" "" "\0" "-1"); |
32 | getopt32(argv, ""); | ||
33 | argv += optind; | 32 | argv += optind; |
34 | 33 | ||
35 | do { | 34 | do { |
@@ -50,6 +49,7 @@ int pwdx_main(int argc UNUSED_PARAM, char **argv) | |||
50 | 49 | ||
51 | sprintf(buf, "/proc/%u/cwd", pid); | 50 | sprintf(buf, "/proc/%u/cwd", pid); |
52 | 51 | ||
52 | /* NOFORK: only one alloc is allowed; must free */ | ||
53 | s = xmalloc_readlink(buf); | 53 | s = xmalloc_readlink(buf); |
54 | // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" | 54 | // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" |
55 | printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); | 55 | printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); |
diff --git a/procps/sysctl.c b/procps/sysctl.c index b17f5e896..827e09cce 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c | |||
@@ -16,22 +16,22 @@ | |||
16 | //config: help | 16 | //config: help |
17 | //config: Configure kernel parameters at runtime. | 17 | //config: Configure kernel parameters at runtime. |
18 | 18 | ||
19 | //applet:IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP)) | 19 | //applet:IF_BB_SYSCTL(APPLET_NOEXEC(sysctl, sysctl, BB_DIR_SBIN, BB_SUID_DROP, sysctl)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o | 21 | //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o |
22 | 22 | ||
23 | //usage:#define sysctl_trivial_usage | 23 | //usage:#define sysctl_trivial_usage |
24 | //usage: "[OPTIONS] [KEY[=VALUE]]..." | 24 | //usage: "-p [-enq] [FILE...] / [-enqaw] [KEY[=VALUE]]..." |
25 | //usage:#define sysctl_full_usage "\n\n" | 25 | //usage:#define sysctl_full_usage "\n\n" |
26 | //usage: "Show/set kernel parameters\n" | 26 | //usage: "Show/set kernel parameters\n" |
27 | //usage: "\n -p Set values from FILEs (default /etc/sysctl.conf)" | ||
27 | //usage: "\n -e Don't warn about unknown keys" | 28 | //usage: "\n -e Don't warn about unknown keys" |
28 | //usage: "\n -n Don't show key names" | 29 | //usage: "\n -n Don't show key names" |
30 | //usage: "\n -q Quiet" | ||
29 | //usage: "\n -a Show all values" | 31 | //usage: "\n -a Show all values" |
30 | /* Same as -a, no need to show it */ | 32 | /* Same as -a, no need to show it */ |
31 | /* //usage: "\n -A Show all values in table form" */ | 33 | /* //usage: "\n -A Show all values in table form" */ |
32 | //usage: "\n -w Set values" | 34 | //usage: "\n -w Set values" |
33 | //usage: "\n -p FILE Set values from FILE (default /etc/sysctl.conf)" | ||
34 | //usage: "\n -q Set values silently" | ||
35 | //usage: | 35 | //usage: |
36 | //usage:#define sysctl_example_usage | 36 | //usage:#define sysctl_example_usage |
37 | //usage: "sysctl [-n] [-e] variable...\n" | 37 | //usage: "sysctl [-n] [-e] variable...\n" |
@@ -48,7 +48,7 @@ enum { | |||
48 | FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ | 48 | FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ |
49 | FLAG_SHOW_ALL = 1 << 3, | 49 | FLAG_SHOW_ALL = 1 << 3, |
50 | FLAG_PRELOAD_FILE = 1 << 4, | 50 | FLAG_PRELOAD_FILE = 1 << 4, |
51 | /* TODO: procps 3.2.8 seems to not require -w for KEY=VAL to work: */ | 51 | /* NB: procps 3.2.8 does not require -w for KEY=VAL to work, it only rejects non-KEY=VAL form */ |
52 | FLAG_WRITE = 1 << 5, | 52 | FLAG_WRITE = 1 << 5, |
53 | FLAG_QUIET = 1 << 6, | 53 | FLAG_QUIET = 1 << 6, |
54 | }; | 54 | }; |
@@ -104,6 +104,7 @@ static int sysctl_act_on_setting(char *setting) | |||
104 | int fd, retval = EXIT_SUCCESS; | 104 | int fd, retval = EXIT_SUCCESS; |
105 | char *cptr, *outname; | 105 | char *cptr, *outname; |
106 | char *value = value; /* for compiler */ | 106 | char *value = value; /* for compiler */ |
107 | bool writing = (option_mask32 & FLAG_WRITE); | ||
107 | 108 | ||
108 | outname = xstrdup(setting); | 109 | outname = xstrdup(setting); |
109 | 110 | ||
@@ -114,8 +115,10 @@ static int sysctl_act_on_setting(char *setting) | |||
114 | cptr++; | 115 | cptr++; |
115 | } | 116 | } |
116 | 117 | ||
117 | if (option_mask32 & FLAG_WRITE) { | 118 | cptr = strchr(setting, '='); |
118 | cptr = strchr(setting, '='); | 119 | if (cptr) |
120 | writing = 1; | ||
121 | if (writing) { | ||
119 | if (cptr == NULL) { | 122 | if (cptr == NULL) { |
120 | bb_error_msg("error: '%s' must be of the form name=value", | 123 | bb_error_msg("error: '%s' must be of the form name=value", |
121 | outname); | 124 | outname); |
@@ -147,7 +150,7 @@ static int sysctl_act_on_setting(char *setting) | |||
147 | break; | 150 | break; |
148 | default: | 151 | default: |
149 | bb_perror_msg("error %sing key '%s'", | 152 | bb_perror_msg("error %sing key '%s'", |
150 | option_mask32 & FLAG_WRITE ? | 153 | writing ? |
151 | "sett" : "read", | 154 | "sett" : "read", |
152 | outname); | 155 | outname); |
153 | break; | 156 | break; |
@@ -156,7 +159,7 @@ static int sysctl_act_on_setting(char *setting) | |||
156 | goto end; | 159 | goto end; |
157 | } | 160 | } |
158 | 161 | ||
159 | if (option_mask32 & FLAG_WRITE) { | 162 | if (writing) { |
160 | //TODO: procps 3.2.7 writes "value\n", note trailing "\n" | 163 | //TODO: procps 3.2.7 writes "value\n", note trailing "\n" |
161 | xwrite_str(fd, value); | 164 | xwrite_str(fd, value); |
162 | close(fd); | 165 | close(fd); |
@@ -238,23 +241,33 @@ static int sysctl_handle_preload_file(const char *filename) | |||
238 | { | 241 | { |
239 | char *token[2]; | 242 | char *token[2]; |
240 | parser_t *parser; | 243 | parser_t *parser; |
244 | int parse_flags; | ||
241 | 245 | ||
242 | parser = config_open(filename); | 246 | parser = config_open(filename); |
243 | /* Must do it _after_ config_open(): */ | 247 | /* Must do it _after_ config_open(): */ |
244 | xchdir("/proc/sys"); | 248 | xchdir("/proc/sys"); |
245 | /* xchroot("/proc/sys") - if you are paranoid */ | ||
246 | 249 | ||
247 | //TODO: ';' is comment char too | 250 | parse_flags = 0; |
248 | //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value | 251 | parse_flags &= ~PARSE_COLLAPSE; // NO (var==val is not var=val) - treat consecutive delimiters as one |
249 | // (but _whitespace_ from ends should be trimmed first (and we do it right)) | 252 | parse_flags &= ~PARSE_TRIM; // NO - trim leading and trailing delimiters |
250 | //TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") | 253 | parse_flags |= PARSE_GREEDY; // YES - last token takes entire remainder of the line |
251 | // can it be fixed by removing PARSE_COLLAPSE bit? | 254 | parse_flags &= ~PARSE_MIN_DIE; // NO - die if < min tokens found |
252 | while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { | 255 | parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char |
256 | parse_flags |= PARSE_ALT_COMMENTS;// YES - two comment chars: ';' and '#' | ||
257 | /* <space><tab><space>#comment is also comment, not strictly 1st char only */ | ||
258 | parse_flags |= PARSE_WS_COMMENTS; // YES - comments are recognized even if there is whitespace before | ||
259 | while (config_read(parser, token, 2, 2, ";#=", parse_flags)) { | ||
253 | char *tp; | 260 | char *tp; |
261 | |||
262 | trim(token[1]); | ||
263 | tp = trim(token[0]); | ||
254 | sysctl_dots_to_slashes(token[0]); | 264 | sysctl_dots_to_slashes(token[0]); |
255 | tp = xasprintf("%s=%s", token[0], token[1]); | 265 | /* ^^^converted in-place. tp still points to NUL */ |
256 | sysctl_act_recursive(tp); | 266 | /* now, add "=TOKEN1" */ |
257 | free(tp); | 267 | *tp++ = '='; |
268 | overlapping_strcpy(tp, token[1]); | ||
269 | |||
270 | sysctl_act_on_setting(token[0]); | ||
258 | } | 271 | } |
259 | if (ENABLE_FEATURE_CLEAN_UP) | 272 | if (ENABLE_FEATURE_CLEAN_UP) |
260 | config_close(parser); | 273 | config_close(parser); |
@@ -273,12 +286,19 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) | |||
273 | option_mask32 = opt; | 286 | option_mask32 = opt; |
274 | 287 | ||
275 | if (opt & FLAG_PRELOAD_FILE) { | 288 | if (opt & FLAG_PRELOAD_FILE) { |
289 | int cur_dir_fd; | ||
276 | option_mask32 |= FLAG_WRITE; | 290 | option_mask32 |= FLAG_WRITE; |
277 | /* xchdir("/proc/sys") is inside */ | 291 | if (!*argv) |
278 | return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); | 292 | *--argv = (char*)"/etc/sysctl.conf"; |
293 | cur_dir_fd = xopen(".", O_RDONLY | O_DIRECTORY); | ||
294 | do { | ||
295 | /* xchdir("/proc/sys") is inside */ | ||
296 | sysctl_handle_preload_file(*argv); | ||
297 | xfchdir(cur_dir_fd); /* files can be relative, must restore cwd */ | ||
298 | } while (*++argv); | ||
299 | return 0; /* procps-ng 3.3.10 does not flag parse errors */ | ||
279 | } | 300 | } |
280 | xchdir("/proc/sys"); | 301 | xchdir("/proc/sys"); |
281 | /* xchroot("/proc/sys") - if you are paranoid */ | ||
282 | if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { | 302 | if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { |
283 | return sysctl_act_recursive("."); | 303 | return sysctl_act_recursive("."); |
284 | } | 304 | } |
diff --git a/procps/top.c b/procps/top.c index 015d1ab74..f97ded5d6 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -116,7 +116,6 @@ | |||
116 | //kbuild:lib-$(CONFIG_TOP) += top.o | 116 | //kbuild:lib-$(CONFIG_TOP) += top.o |
117 | 117 | ||
118 | #include "libbb.h" | 118 | #include "libbb.h" |
119 | #include "common_bufsiz.h" | ||
120 | 119 | ||
121 | 120 | ||
122 | typedef struct top_status_t { | 121 | typedef struct top_status_t { |
@@ -154,6 +153,8 @@ typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q); | |||
154 | 153 | ||
155 | enum { SORT_DEPTH = 3 }; | 154 | enum { SORT_DEPTH = 3 }; |
156 | 155 | ||
156 | /* Screens wider than this are unlikely */ | ||
157 | enum { LINE_BUF_SIZE = 512 - 64 }; | ||
157 | 158 | ||
158 | struct globals { | 159 | struct globals { |
159 | top_status_t *top; | 160 | top_status_t *top; |
@@ -192,10 +193,9 @@ struct globals { | |||
192 | #if ENABLE_FEATURE_TOP_INTERACTIVE | 193 | #if ENABLE_FEATURE_TOP_INTERACTIVE |
193 | char kbd_input[KEYCODE_BUFFER_SIZE]; | 194 | char kbd_input[KEYCODE_BUFFER_SIZE]; |
194 | #endif | 195 | #endif |
195 | char line_buf[80]; | 196 | char line_buf[LINE_BUF_SIZE]; |
196 | }; //FIX_ALIASING; - large code growth | 197 | }; |
197 | enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; | 198 | #define G (*ptr_to_globals) |
198 | #define G (*(struct globals*)bb_common_bufsiz1) | ||
199 | #define top (G.top ) | 199 | #define top (G.top ) |
200 | #define ntop (G.ntop ) | 200 | #define ntop (G.ntop ) |
201 | #define sort_field (G.sort_field ) | 201 | #define sort_field (G.sort_field ) |
@@ -213,8 +213,7 @@ enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; | |||
213 | #define total_pcpu (G.total_pcpu ) | 213 | #define total_pcpu (G.total_pcpu ) |
214 | #define line_buf (G.line_buf ) | 214 | #define line_buf (G.line_buf ) |
215 | #define INIT_G() do { \ | 215 | #define INIT_G() do { \ |
216 | setup_common_bufsiz(); \ | 216 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
217 | BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ | ||
218 | BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \ | 217 | BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \ |
219 | } while (0) | 218 | } while (0) |
220 | 219 | ||
@@ -1110,15 +1109,14 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1110 | #endif | 1109 | #endif |
1111 | 1110 | ||
1112 | /* all args are options; -n NUM */ | 1111 | /* all args are options; -n NUM */ |
1113 | opt_complementary = "-"; /* options can be specified w/o dash */ | 1112 | make_all_argv_opts(argv); /* options can be specified w/o dash */ |
1114 | col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); | 1113 | col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); |
1115 | #if ENABLE_FEATURE_TOPMEM | 1114 | #if ENABLE_FEATURE_TOPMEM |
1116 | if (col & OPT_m) /* -m (busybox specific) */ | 1115 | if (col & OPT_m) /* -m (busybox specific) */ |
1117 | scan_mask = TOPMEM_MASK; | 1116 | scan_mask = TOPMEM_MASK; |
1118 | #endif | 1117 | #endif |
1119 | if (col & OPT_d) { | 1118 | if (col & OPT_d) { |
1120 | /* work around for "-d 1" -> "-d -1" done by getopt32 | 1119 | /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ |
1121 | * (opt_complementary == "-" does this) */ | ||
1122 | if (str_interval[0] == '-') | 1120 | if (str_interval[0] == '-') |
1123 | str_interval++; | 1121 | str_interval++; |
1124 | /* Need to limit it to not overflow poll timeout */ | 1122 | /* Need to limit it to not overflow poll timeout */ |
@@ -1148,6 +1146,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1148 | else { | 1146 | else { |
1149 | /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ | 1147 | /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ |
1150 | set_termios_to_raw(STDIN_FILENO, &initial_settings, TERMIOS_CLEAR_ISIG); | 1148 | set_termios_to_raw(STDIN_FILENO, &initial_settings, TERMIOS_CLEAR_ISIG); |
1149 | die_func = reset_term; | ||
1151 | } | 1150 | } |
1152 | 1151 | ||
1153 | bb_signals(BB_FATAL_SIGS, sig_catcher); | 1152 | bb_signals(BB_FATAL_SIGS, sig_catcher); |
diff --git a/procps/uptime.c b/procps/uptime.c index 24b2b39df..b0ee8391b 100644 --- a/procps/uptime.c +++ b/procps/uptime.c | |||
@@ -27,7 +27,7 @@ | |||
27 | //config: help | 27 | //config: help |
28 | //config: Display the number of users currently logged on. | 28 | //config: Display the number of users currently logged on. |
29 | 29 | ||
30 | //applet:IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP)) | 30 | //applet:IF_UPTIME(APPLET_NOEXEC(uptime, uptime, BB_DIR_USR_BIN, BB_SUID_DROP, uptime)) |
31 | 31 | ||
32 | //kbuild:lib-$(CONFIG_UPTIME) += uptime.o | 32 | //kbuild:lib-$(CONFIG_UPTIME) += uptime.o |
33 | 33 | ||
diff --git a/procps/watch.c b/procps/watch.c index 2bb7cca90..6fc9f7db7 100644 --- a/procps/watch.c +++ b/procps/watch.c | |||
@@ -62,9 +62,9 @@ int watch_main(int argc UNUSED_PARAM, char **argv) | |||
62 | xopen("/dev/null", O_RDONLY); | 62 | xopen("/dev/null", O_RDONLY); |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | opt_complementary = "-1"; // at least one param; -n NUM | 65 | // "+": stop at first non-option (procps 3.x only); -n NUM |
66 | // "+": stop at first non-option (procps 3.x only) | 66 | // at least one param |
67 | opt = getopt32(argv, "+dtn:+", &period); | 67 | opt = getopt32(argv, "^+" "dtn:+" "\0" "-1", &period); |
68 | argv += optind; | 68 | argv += optind; |
69 | 69 | ||
70 | // watch from both procps 2.x and 3.x does concatenation. Example: | 70 | // watch from both procps 2.x and 3.x does concatenation. Example: |
diff --git a/runit/chpst.c b/runit/chpst.c index 3a2f9e616..3ecb85cba 100644 --- a/runit/chpst.c +++ b/runit/chpst.c | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
@@ -59,12 +59,12 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
59 | //config: help | 59 | //config: help |
60 | //config: Sets soft resource limits as specified by options | 60 | //config: Sets soft resource limits as specified by options |
61 | 61 | ||
62 | //applet:IF_CHPST(APPLET(chpst, BB_DIR_USR_BIN, BB_SUID_DROP)) | 62 | //applet:IF_CHPST( APPLET_NOEXEC(chpst, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, chpst)) |
63 | // APPLET_ODDNAME:name main location suid_type help | 63 | // APPLET_NOEXEC:name main location suid_type help |
64 | //applet:IF_ENVDIR( APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) | 64 | //applet:IF_ENVDIR( APPLET_NOEXEC(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) |
65 | //applet:IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) | 65 | //applet:IF_ENVUIDGID(APPLET_NOEXEC(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) |
66 | //applet:IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, setuidgid)) | 66 | //applet:IF_SETUIDGID(APPLET_NOEXEC(setuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, setuidgid)) |
67 | //applet:IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, softlimit)) | 67 | //applet:IF_SOFTLIMIT(APPLET_NOEXEC(softlimit, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, softlimit)) |
68 | 68 | ||
69 | //kbuild:lib-$(CONFIG_CHPST) += chpst.o | 69 | //kbuild:lib-$(CONFIG_CHPST) += chpst.o |
70 | //kbuild:lib-$(CONFIG_ENVDIR) += chpst.o | 70 | //kbuild:lib-$(CONFIG_ENVDIR) += chpst.o |
@@ -301,9 +301,10 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) | |||
301 | // FIXME: can we live with int-sized limits? | 301 | // FIXME: can we live with int-sized limits? |
302 | // can we live with 40000 days? | 302 | // can we live with 40000 days? |
303 | // if yes -> getopt converts strings to numbers for us | 303 | // if yes -> getopt converts strings to numbers for us |
304 | opt_complementary = "-1"; | 304 | opt = getopt32(argv, "^+" |
305 | opt = getopt32(argv, "+a:+c:+d:+f:+l:+m:+o:+p:+r:+s:+t:+u:U:e:" | 305 | "a:+c:+d:+f:+l:+m:+o:+p:+r:+s:+t:+u:U:e:" |
306 | IF_CHPST("/:n:vP012"), | 306 | IF_CHPST("/:n:vP012") |
307 | "\0" "-1", | ||
307 | &limita, &limitc, &limitd, &limitf, &limitl, | 308 | &limita, &limitc, &limitd, &limitf, &limitl, |
308 | &limitm, &limito, &limitp, &limitr, &limits, &limitt, | 309 | &limitm, &limito, &limitp, &limitr, &limits, &limitt, |
309 | &set_user, &set_user, &env_dir | 310 | &set_user, &set_user, &env_dir |
diff --git a/runit/runit_lib.h b/runit/runit_lib.h index c36ea4ca5..c54561616 100644 --- a/runit/runit_lib.h +++ b/runit/runit_lib.h | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
diff --git a/runit/runsv.c b/runit/runsv.c index ad7d82cb8..a67280b4b 100644 --- a/runit/runsv.c +++ b/runit/runsv.c | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
diff --git a/runit/runsvdir.c b/runit/runsvdir.c index b4f5c303b..11ab40abf 100644 --- a/runit/runsvdir.c +++ b/runit/runsvdir.c | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
@@ -248,10 +248,9 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) | |||
248 | 248 | ||
249 | INIT_G(); | 249 | INIT_G(); |
250 | 250 | ||
251 | opt_complementary = "-1"; | ||
252 | opt_s_argv[0] = NULL; | 251 | opt_s_argv[0] = NULL; |
253 | opt_s_argv[2] = NULL; | 252 | opt_s_argv[2] = NULL; |
254 | getopt32(argv, "Ps:", &opt_s_argv[0]); | 253 | getopt32(argv, "^" "Ps:" "\0" "-1", &opt_s_argv[0]); |
255 | argv += optind; | 254 | argv += optind; |
256 | 255 | ||
257 | i_am_init = (getpid() == 1); | 256 | i_am_init = (getpid() == 1); |
diff --git a/runit/sv.c b/runit/sv.c index 2d5b466bf..1d0809be8 100644 --- a/runit/sv.c +++ b/runit/sv.c | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
@@ -175,8 +175,8 @@ Exit Codes | |||
175 | //config: svc controls the state of services monitored by the runsv supervisor. | 175 | //config: svc controls the state of services monitored by the runsv supervisor. |
176 | //config: It is comaptible with daemontools command with the same name. | 176 | //config: It is comaptible with daemontools command with the same name. |
177 | 177 | ||
178 | //applet:IF_SV(APPLET(sv, BB_DIR_USR_BIN, BB_SUID_DROP)) | 178 | //applet:IF_SV( APPLET_NOEXEC(sv, sv, BB_DIR_USR_BIN, BB_SUID_DROP, sv )) |
179 | //applet:IF_SVC(APPLET(svc, BB_DIR_USR_BIN, BB_SUID_DROP)) | 179 | //applet:IF_SVC(APPLET_NOEXEC(svc, svc, BB_DIR_USR_BIN, BB_SUID_DROP, svc)) |
180 | 180 | ||
181 | //kbuild:lib-$(CONFIG_SV) += sv.o | 181 | //kbuild:lib-$(CONFIG_SV) += sv.o |
182 | //kbuild:lib-$(CONFIG_SVC) += sv.o | 182 | //kbuild:lib-$(CONFIG_SVC) += sv.o |
@@ -193,7 +193,7 @@ struct globals { | |||
193 | /* "Bernstein" time format: unix + 0x400000000000000aULL */ | 193 | /* "Bernstein" time format: unix + 0x400000000000000aULL */ |
194 | uint64_t tstart, tnow; | 194 | uint64_t tstart, tnow; |
195 | svstatus_t svstatus; | 195 | svstatus_t svstatus; |
196 | unsigned islog; | 196 | smallint islog; |
197 | } FIX_ALIASING; | 197 | } FIX_ALIASING; |
198 | #define G (*(struct globals*)bb_common_bufsiz1) | 198 | #define G (*(struct globals*)bb_common_bufsiz1) |
199 | #define acts (G.acts ) | 199 | #define acts (G.acts ) |
@@ -203,7 +203,11 @@ struct globals { | |||
203 | #define tnow (G.tnow ) | 203 | #define tnow (G.tnow ) |
204 | #define svstatus (G.svstatus ) | 204 | #define svstatus (G.svstatus ) |
205 | #define islog (G.islog ) | 205 | #define islog (G.islog ) |
206 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 206 | #define INIT_G() do { \ |
207 | setup_common_bufsiz(); \ | ||
208 | /* need to zero out, svc calls sv() repeatedly */ \ | ||
209 | memset(&G, 0, sizeof(G)); \ | ||
210 | } while (0) | ||
207 | 211 | ||
208 | 212 | ||
209 | #define str_equal(s,t) (strcmp((s), (t)) == 0) | 213 | #define str_equal(s,t) (strcmp((s), (t)) == 0) |
@@ -502,8 +506,9 @@ static int sv(char **argv) | |||
502 | x = getenv("SVWAIT"); | 506 | x = getenv("SVWAIT"); |
503 | if (x) waitsec = xatou(x); | 507 | if (x) waitsec = xatou(x); |
504 | 508 | ||
505 | opt_complementary = "vv"; /* -w N, -v is a counter */ | 509 | getopt32(argv, "^" "w:+v" "\0" "vv" /* -w N, -v is a counter */, |
506 | getopt32(argv, "w:+v", &waitsec, &verbose); | 510 | &waitsec, &verbose |
511 | ); | ||
507 | argv += optind; | 512 | argv += optind; |
508 | action = *argv++; | 513 | action = *argv++; |
509 | if (!action || !*argv) bb_show_usage(); | 514 | if (!action || !*argv) bb_show_usage(); |
@@ -701,8 +706,6 @@ int svc_main(int argc UNUSED_PARAM, char **argv) | |||
701 | const char *optstring; | 706 | const char *optstring; |
702 | unsigned opts; | 707 | unsigned opts; |
703 | 708 | ||
704 | INIT_G(); | ||
705 | |||
706 | optstring = "udopchaitkx"; | 709 | optstring = "udopchaitkx"; |
707 | opts = getopt32(argv, optstring); | 710 | opts = getopt32(argv, optstring); |
708 | argv += optind; | 711 | argv += optind; |
@@ -718,15 +721,16 @@ int svc_main(int argc UNUSED_PARAM, char **argv) | |||
718 | argv[1] = command; | 721 | argv[1] = command; |
719 | command[1] = '\0'; | 722 | command[1] = '\0'; |
720 | 723 | ||
721 | /* getopt32() was already called: | ||
722 | * reset the libc getopt() function, which keeps internal state. | ||
723 | */ | ||
724 | GETOPT_RESET(); | ||
725 | |||
726 | do { | 724 | do { |
727 | if (opts & 1) { | 725 | if (opts & 1) { |
728 | int r; | 726 | int r; |
727 | |||
729 | command[0] = *optstring; | 728 | command[0] = *optstring; |
729 | |||
730 | /* getopt() was already called by getopt32(): | ||
731 | * reset the libc getopt() function's internal state. | ||
732 | */ | ||
733 | GETOPT_RESET(); | ||
730 | r = sv(argv); | 734 | r = sv(argv); |
731 | if (r) | 735 | if (r) |
732 | return 1; | 736 | return 1; |
diff --git a/runit/svlogd.c b/runit/svlogd.c index 8dbf67106..739483356 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c | |||
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: | |||
13 | 3. The name of the author may not be used to endorse or promote products | 13 | 3. The name of the author may not be used to endorse or promote products |
14 | derived from this software without specific prior written permission. | 14 | derived from this software without specific prior written permission. |
15 | 15 | ||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED |
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
@@ -1037,9 +1037,10 @@ int svlogd_main(int argc, char **argv) | |||
1037 | 1037 | ||
1038 | INIT_G(); | 1038 | INIT_G(); |
1039 | 1039 | ||
1040 | opt_complementary = "tt:vv"; | 1040 | opt = getopt32(argv, "^" |
1041 | opt = getopt32(argv, "r:R:l:b:tv", | 1041 | "r:R:l:b:tv" "\0" "tt:vv", |
1042 | &r, &replace, &l, &b, ×tamp, &verbose); | 1042 | &r, &replace, &l, &b, ×tamp, &verbose |
1043 | ); | ||
1043 | if (opt & 1) { // -r | 1044 | if (opt & 1) { // -r |
1044 | repl = r[0]; | 1045 | repl = r[0]; |
1045 | if (!repl || r[1]) | 1046 | if (!repl || r[1]) |
diff --git a/scripts/Makefile.IMA b/scripts/Makefile.IMA index 0eced2982..f155108d7 100644 --- a/scripts/Makefile.IMA +++ b/scripts/Makefile.IMA | |||
@@ -115,6 +115,9 @@ lib-y:= | |||
115 | include debianutils/Kbuild | 115 | include debianutils/Kbuild |
116 | lib-all-y += $(patsubst %,debianutils/%,$(sort $(lib-y))) | 116 | lib-all-y += $(patsubst %,debianutils/%,$(sort $(lib-y))) |
117 | lib-y:= | 117 | lib-y:= |
118 | include klibc-utils/Kbuild | ||
119 | lib-all-y += $(patsubst %,klibc-utils/%,$(sort $(lib-y))) | ||
120 | lib-y:= | ||
118 | include runit/Kbuild | 121 | include runit/Kbuild |
119 | lib-all-y += $(patsubst %,runit/%,$(sort $(lib-y))) | 122 | lib-all-y += $(patsubst %,runit/%,$(sort $(lib-y))) |
120 | lib-y:= | 123 | lib-y:= |
diff --git a/scripts/echo.c b/scripts/echo.c index cb207ae05..8c6b409d3 100644 --- a/scripts/echo.c +++ b/scripts/echo.c | |||
@@ -214,7 +214,7 @@ int main(int argc, char **argv) | |||
214 | * may be used to endorse or promote products derived from this software | 214 | * may be used to endorse or promote products derived from this software |
215 | * without specific prior written permission. | 215 | * without specific prior written permission. |
216 | * | 216 | * |
217 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 217 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
218 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 218 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
219 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 219 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
220 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 220 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/selinux/chcon.c b/selinux/chcon.c index ae87fb554..3ddb2dd46 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c | |||
@@ -13,11 +13,6 @@ | |||
13 | //config: depends on SELINUX | 13 | //config: depends on SELINUX |
14 | //config: help | 14 | //config: help |
15 | //config: Enable support to change the security context of file. | 15 | //config: Enable support to change the security context of file. |
16 | //config: | ||
17 | //config:config FEATURE_CHCON_LONG_OPTIONS | ||
18 | //config: bool "Enable long options" | ||
19 | //config: default y | ||
20 | //config: depends on CHCON && LONG_OPTS | ||
21 | 16 | ||
22 | //applet:IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP)) |
23 | 18 | ||
@@ -26,34 +21,24 @@ | |||
26 | //usage:#define chcon_trivial_usage | 21 | //usage:#define chcon_trivial_usage |
27 | //usage: "[OPTIONS] CONTEXT FILE..." | 22 | //usage: "[OPTIONS] CONTEXT FILE..." |
28 | //usage: "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." | 23 | //usage: "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." |
29 | //usage: IF_FEATURE_CHCON_LONG_OPTIONS( | 24 | //usage: IF_LONG_OPTS( |
30 | //usage: "\n chcon [OPTIONS] --reference=RFILE FILE..." | 25 | //usage: "\n chcon [OPTIONS] --reference=RFILE FILE..." |
31 | //usage: ) | 26 | //usage: ) |
27 | //usage: | ||
32 | //usage:#define chcon_full_usage "\n\n" | 28 | //usage:#define chcon_full_usage "\n\n" |
33 | //usage: "Change the security context of each FILE to CONTEXT\n" | 29 | //usage: "Change the security context of each FILE to CONTEXT\n" |
34 | //usage: IF_FEATURE_CHCON_LONG_OPTIONS( | ||
35 | //usage: "\n -v,--verbose Verbose" | ||
36 | //usage: "\n -c,--changes Report changes made" | ||
37 | //usage: "\n -h,--no-dereference Affect symlinks instead of their targets" | ||
38 | //usage: "\n -f,--silent,--quiet Suppress most error messages" | ||
39 | //usage: "\n --reference RFILE Use RFILE's group instead of using a CONTEXT value" | ||
40 | //usage: "\n -u,--user USER Set user/role/type/range in the target" | ||
41 | //usage: "\n -r,--role ROLE security context" | ||
42 | //usage: "\n -t,--type TYPE" | ||
43 | //usage: "\n -l,--range RANGE" | ||
44 | //usage: "\n -R,--recursive Recurse" | ||
45 | //usage: ) | ||
46 | //usage: IF_NOT_FEATURE_CHCON_LONG_OPTIONS( | ||
47 | //usage: "\n -v Verbose" | 30 | //usage: "\n -v Verbose" |
48 | //usage: "\n -c Report changes made" | 31 | //usage: "\n -c Report changes made" |
49 | //usage: "\n -h Affect symlinks instead of their targets" | 32 | //usage: "\n -h Affect symlinks instead of their targets" |
50 | //usage: "\n -f Suppress most error messages" | 33 | //usage: "\n -f Suppress most error messages" |
34 | //usage: IF_LONG_OPTS( | ||
35 | //usage: "\n --reference RFILE Use RFILE's group instead of using a CONTEXT value" | ||
36 | //usage: ) | ||
51 | //usage: "\n -u USER Set user/role/type/range in the target security context" | 37 | //usage: "\n -u USER Set user/role/type/range in the target security context" |
52 | //usage: "\n -r ROLE" | 38 | //usage: "\n -r ROLE" |
53 | //usage: "\n -t TYPE" | 39 | //usage: "\n -t TYPE" |
54 | //usage: "\n -l RNG" | 40 | //usage: "\n -l RNG" |
55 | //usage: "\n -R Recurse" | 41 | //usage: "\n -R Recurse" |
56 | //usage: ) | ||
57 | 42 | ||
58 | #include <selinux/context.h> | 43 | #include <selinux/context.h> |
59 | 44 | ||
@@ -68,7 +53,7 @@ | |||
68 | #define OPT_TYPE (1<<6) /* 't' */ | 53 | #define OPT_TYPE (1<<6) /* 't' */ |
69 | #define OPT_RANGE (1<<7) /* 'l' */ | 54 | #define OPT_RANGE (1<<7) /* 'l' */ |
70 | #define OPT_VERBOSE (1<<8) /* 'v' */ | 55 | #define OPT_VERBOSE (1<<8) /* 'v' */ |
71 | #define OPT_REFERENCE ((1<<9) * ENABLE_FEATURE_CHCON_LONG_OPTIONS) | 56 | #define OPT_REFERENCE ((1<<9) * ENABLE_LONG_OPTS) |
72 | #define OPT_COMPONENT_SPECIFIED (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE) | 57 | #define OPT_COMPONENT_SPECIFIED (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE) |
73 | 58 | ||
74 | static char *user = NULL; | 59 | static char *user = NULL; |
@@ -157,7 +142,7 @@ skip: | |||
157 | return rc; | 142 | return rc; |
158 | } | 143 | } |
159 | 144 | ||
160 | #if ENABLE_FEATURE_CHCON_LONG_OPTIONS | 145 | #if ENABLE_LONG_OPTS |
161 | static const char chcon_longopts[] ALIGN1 = | 146 | static const char chcon_longopts[] ALIGN1 = |
162 | "recursive\0" No_argument "R" | 147 | "recursive\0" No_argument "R" |
163 | "changes\0" No_argument "c" | 148 | "changes\0" No_argument "c" |
@@ -180,20 +165,21 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) | |||
180 | char *fname; | 165 | char *fname; |
181 | int i, errors = 0; | 166 | int i, errors = 0; |
182 | 167 | ||
183 | #if ENABLE_FEATURE_CHCON_LONG_OPTIONS | 168 | getopt32long(argv, "^" |
184 | applet_long_options = chcon_longopts; | 169 | "Rchfu:r:t:l:v" |
185 | #endif | 170 | "\0" |
186 | opt_complementary = "-1" /* at least 1 param */ | 171 | "-1" /* at least 1 arg */ |
187 | ":?" /* error if exclusivity constraints are violated */ | 172 | ":?" /* error if exclusivity constraints are violated */ |
188 | #if ENABLE_FEATURE_CHCON_LONG_OPTIONS | 173 | #if ENABLE_LONG_OPTS |
189 | ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff" | 174 | ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff" |
190 | #endif | 175 | #endif |
191 | ":f--v:v--f"; /* 'verbose' and 'quiet' are exclusive */ | 176 | ":f--v:v--f" /* 'verbose' and 'quiet' are exclusive */ |
192 | getopt32(argv, "Rchfu:r:t:l:v", | 177 | , chcon_longopts, |
193 | &user, &role, &type, &range, &reference_file); | 178 | &user, &role, &type, &range, &reference_file |
179 | ); | ||
194 | argv += optind; | 180 | argv += optind; |
195 | 181 | ||
196 | #if ENABLE_FEATURE_CHCON_LONG_OPTIONS | 182 | #if ENABLE_LONG_OPTS |
197 | if (option_mask32 & OPT_REFERENCE) { | 183 | if (option_mask32 & OPT_REFERENCE) { |
198 | /* FIXME: lgetfilecon() should be used when '-h' is specified. | 184 | /* FIXME: lgetfilecon() should be used when '-h' is specified. |
199 | * But current implementation follows the original one. */ | 185 | * But current implementation follows the original one. */ |
diff --git a/selinux/matchpathcon.c b/selinux/matchpathcon.c index 3388d0857..e57120d3b 100644 --- a/selinux/matchpathcon.c +++ b/selinux/matchpathcon.c | |||
@@ -58,9 +58,13 @@ int matchpathcon_main(int argc UNUSED_PARAM, char **argv) | |||
58 | unsigned opts; | 58 | unsigned opts; |
59 | char *fcontext, *prefix, *path; | 59 | char *fcontext, *prefix, *path; |
60 | 60 | ||
61 | opt_complementary = "-1" /* at least one param reqd */ | 61 | opts = getopt32(argv, "^" |
62 | ":?:f--p:p--f"; /* mutually exclusive */ | 62 | "nNf:p:V" |
63 | opts = getopt32(argv, "nNf:p:V", &fcontext, &prefix); | 63 | "\0" |
64 | "-1" /* at least one param reqd */ | ||
65 | ":?:f--p:p--f" /* mutually exclusive */ | ||
66 | , &fcontext, &prefix | ||
67 | ); | ||
64 | argv += optind; | 68 | argv += optind; |
65 | 69 | ||
66 | if (opts & OPT_NOT_TRANS) { | 70 | if (opts & OPT_NOT_TRANS) { |
diff --git a/selinux/runcon.c b/selinux/runcon.c index 09082d6c2..a5a394427 100644 --- a/selinux/runcon.c +++ b/selinux/runcon.c | |||
@@ -34,11 +34,6 @@ | |||
34 | //config: depends on SELINUX | 34 | //config: depends on SELINUX |
35 | //config: help | 35 | //config: help |
36 | //config: Enable support to run command in specified security context. | 36 | //config: Enable support to run command in specified security context. |
37 | //config: | ||
38 | //config:config FEATURE_RUNCON_LONG_OPTIONS | ||
39 | //config: bool "Enable long options" | ||
40 | //config: default y | ||
41 | //config: depends on RUNCON && LONG_OPTS | ||
42 | 37 | ||
43 | //applet:IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP)) | 38 | //applet:IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP)) |
44 | 39 | ||
@@ -50,20 +45,11 @@ | |||
50 | //usage:#define runcon_full_usage "\n\n" | 45 | //usage:#define runcon_full_usage "\n\n" |
51 | //usage: "Run PROG in a different security context\n" | 46 | //usage: "Run PROG in a different security context\n" |
52 | //usage: "\n CONTEXT Complete security context\n" | 47 | //usage: "\n CONTEXT Complete security context\n" |
53 | //usage: IF_FEATURE_RUNCON_LONG_OPTIONS( | ||
54 | //usage: "\n -c,--compute Compute process transition context before modifying" | ||
55 | //usage: "\n -t,--type TYPE Type (for same role as parent)" | ||
56 | //usage: "\n -u,--user USER User identity" | ||
57 | //usage: "\n -r,--role ROLE Role" | ||
58 | //usage: "\n -l,--range RNG Levelrange" | ||
59 | //usage: ) | ||
60 | //usage: IF_NOT_FEATURE_RUNCON_LONG_OPTIONS( | ||
61 | //usage: "\n -c Compute process transition context before modifying" | 48 | //usage: "\n -c Compute process transition context before modifying" |
62 | //usage: "\n -t TYPE Type (for same role as parent)" | 49 | //usage: "\n -t TYPE Type (for same role as parent)" |
63 | //usage: "\n -u USER User identity" | 50 | //usage: "\n -u USER User identity" |
64 | //usage: "\n -r ROLE Role" | 51 | //usage: "\n -r ROLE Role" |
65 | //usage: "\n -l RNG Levelrange" | 52 | //usage: "\n -l RNG Levelrange" |
66 | //usage: ) | ||
67 | 53 | ||
68 | #include <selinux/context.h> | 54 | #include <selinux/context.h> |
69 | /* from deprecated <selinux/flask.h>: */ | 55 | /* from deprecated <selinux/flask.h>: */ |
@@ -108,7 +94,7 @@ static context_t runcon_compute_new_context(char *user, char *role, char *type, | |||
108 | return con; | 94 | return con; |
109 | } | 95 | } |
110 | 96 | ||
111 | #if ENABLE_FEATURE_RUNCON_LONG_OPTIONS | 97 | #if ENABLE_LONG_OPTS |
112 | static const char runcon_longopts[] ALIGN1 = | 98 | static const char runcon_longopts[] ALIGN1 = |
113 | "user\0" Required_argument "u" | 99 | "user\0" Required_argument "u" |
114 | "role\0" Required_argument "r" | 100 | "role\0" Required_argument "r" |
@@ -140,11 +126,12 @@ int runcon_main(int argc UNUSED_PARAM, char **argv) | |||
140 | 126 | ||
141 | selinux_or_die(); | 127 | selinux_or_die(); |
142 | 128 | ||
143 | #if ENABLE_FEATURE_RUNCON_LONG_OPTIONS | 129 | opts = getopt32long(argv, "^" |
144 | applet_long_options = runcon_longopts; | 130 | "r:t:u:l:ch" |
145 | #endif | 131 | "\0" "-1", |
146 | opt_complementary = "-1"; | 132 | runcon_longopts, |
147 | opts = getopt32(argv, "r:t:u:l:ch", &role, &type, &user, &range); | 133 | &role, &type, &user, &range |
134 | ); | ||
148 | argv += optind; | 135 | argv += optind; |
149 | 136 | ||
150 | if (!(opts & OPTS_CONTEXT_COMPONENT)) { | 137 | if (!(opts & OPTS_CONTEXT_COMPONENT)) { |
diff --git a/selinux/sestatus.c b/selinux/sestatus.c index daf4b223b..6954aca70 100644 --- a/selinux/sestatus.c +++ b/selinux/sestatus.c | |||
@@ -167,8 +167,7 @@ int sestatus_main(int argc UNUSED_PARAM, char **argv) | |||
167 | const char *pol_path; | 167 | const char *pol_path; |
168 | int rc; | 168 | int rc; |
169 | 169 | ||
170 | opt_complementary = "?0"; /* no arguments are required. */ | 170 | opts = getopt32(argv, "^" "vb" "\0" "=0"/*no arguments*/); |
171 | opts = getopt32(argv, "vb"); | ||
172 | 171 | ||
173 | /* SELinux status: line */ | 172 | /* SELinux status: line */ |
174 | rc = is_selinux_enabled(); | 173 | rc = is_selinux_enabled(); |
diff --git a/selinux/setfiles.c b/selinux/setfiles.c index 01106bd67..8da47d274 100644 --- a/selinux/setfiles.c +++ b/selinux/setfiles.c | |||
@@ -610,17 +610,23 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv) | |||
610 | 610 | ||
611 | set_matchpathcon_flags(matchpathcon_flags); | 611 | set_matchpathcon_flags(matchpathcon_flags); |
612 | 612 | ||
613 | opt_complementary = "vv:v--p:p--v:v--q:q--v"; | ||
614 | /* Option order must match OPT_x definitions! */ | 613 | /* Option order must match OPT_x definitions! */ |
615 | if (applet_name[0] == 'r') { /* restorecon */ | 614 | if (applet_name[0] == 'r') { /* restorecon */ |
616 | flags = getopt32(argv, "de:*f:ilnpqrsvo:FWR", | 615 | flags = getopt32(argv, "^" |
617 | &exclude_dir, &input_filename, &out_filename, &verbose); | 616 | "de:*f:ilnpqrsvo:FWR", |
617 | "\0" "vv:v--p:p--v:v--q:q--v"; | ||
618 | &exclude_dir, &input_filename, &out_filename, | ||
619 | &verbose | ||
620 | ); | ||
618 | } else { /* setfiles */ | 621 | } else { /* setfiles */ |
619 | flags = getopt32(argv, "de:*f:ilnpqr:svo:FW" | 622 | flags = getopt32(argv, "^" |
620 | IF_FEATURE_SETFILES_CHECK_OPTION("c:"), | 623 | "de:*f:ilnpqr:svo:FW" |
624 | IF_FEATURE_SETFILES_CHECK_OPTION("c:"), | ||
625 | "\0" "vv:v--p:p--v:v--q:q--v"; | ||
621 | &exclude_dir, &input_filename, &rootpath, &out_filename, | 626 | &exclude_dir, &input_filename, &rootpath, &out_filename, |
622 | IF_FEATURE_SETFILES_CHECK_OPTION(&policyfile,) | 627 | IF_FEATURE_SETFILES_CHECK_OPTION(&policyfile,) |
623 | &verbose); | 628 | &verbose |
629 | ); | ||
624 | } | 630 | } |
625 | argv += optind; | 631 | argv += optind; |
626 | 632 | ||
@@ -673,7 +679,7 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv) | |||
673 | bb_show_usage(); | 679 | bb_show_usage(); |
674 | xstat(argv[0], &sb); | 680 | xstat(argv[0], &sb); |
675 | if (!S_ISREG(sb.st_mode)) { | 681 | if (!S_ISREG(sb.st_mode)) { |
676 | bb_error_msg_and_die("spec file %s is not a regular file", argv[0]); | 682 | bb_error_msg_and_die("'%s' is not a regular file", argv[0]); |
677 | } | 683 | } |
678 | /* Load the file contexts configuration and check it. */ | 684 | /* Load the file contexts configuration and check it. */ |
679 | rc = matchpathcon_init(argv[0]); | 685 | rc = matchpathcon_init(argv[0]); |
diff --git a/shell/ash.c b/shell/ash.c index 6a572cbc3..ac1ae05fc 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -215,6 +215,9 @@ | |||
215 | #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT | 215 | #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT |
216 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT | 216 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT |
217 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT | 217 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT |
218 | #define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT | ||
219 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT | ||
220 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT | ||
218 | 221 | ||
219 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 | 222 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 |
220 | /* Bionic at least up to version 24 has no glob() */ | 223 | /* Bionic at least up to version 24 has no glob() */ |
@@ -452,7 +455,7 @@ struct globals_misc { | |||
452 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | 455 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ |
453 | #define S_CATCH 2 /* signal is caught */ | 456 | #define S_CATCH 2 /* signal is caught */ |
454 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | 457 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ |
455 | #define S_HARD_IGN 4 /* signal is ignored permanently */ | 458 | #define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */ |
456 | 459 | ||
457 | /* indicates specified signal received */ | 460 | /* indicates specified signal received */ |
458 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 461 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
@@ -1313,6 +1316,10 @@ struct strpush { | |||
1313 | int unget; | 1316 | int unget; |
1314 | }; | 1317 | }; |
1315 | 1318 | ||
1319 | /* | ||
1320 | * The parsefile structure pointed to by the global variable parsefile | ||
1321 | * contains information about the current file being read. | ||
1322 | */ | ||
1316 | struct parsefile { | 1323 | struct parsefile { |
1317 | struct parsefile *prev; /* preceding file on stack */ | 1324 | struct parsefile *prev; /* preceding file on stack */ |
1318 | int linno; /* current line */ | 1325 | int linno; /* current line */ |
@@ -1986,10 +1993,6 @@ nextopt(const char *optstring) | |||
1986 | 1993 | ||
1987 | /* ============ Shell variables */ | 1994 | /* ============ Shell variables */ |
1988 | 1995 | ||
1989 | /* | ||
1990 | * The parsefile structure pointed to by the global variable parsefile | ||
1991 | * contains information about the current file being read. | ||
1992 | */ | ||
1993 | struct shparam { | 1996 | struct shparam { |
1994 | int nparam; /* # of positional parameters (without $0) */ | 1997 | int nparam; /* # of positional parameters (without $0) */ |
1995 | #if ENABLE_ASH_GETOPTS | 1998 | #if ENABLE_ASH_GETOPTS |
@@ -2183,7 +2186,9 @@ extern struct globals_var *const ash_ptr_to_globals_var; | |||
2183 | static void FAST_FUNC | 2186 | static void FAST_FUNC |
2184 | getoptsreset(const char *value) | 2187 | getoptsreset(const char *value) |
2185 | { | 2188 | { |
2186 | shellparam.optind = number(value) ?: 1; | 2189 | shellparam.optind = 1; |
2190 | if (is_number(value)) | ||
2191 | shellparam.optind = number(value) ?: 1; | ||
2187 | shellparam.optoff = -1; | 2192 | shellparam.optoff = -1; |
2188 | } | 2193 | } |
2189 | #endif | 2194 | #endif |
@@ -3751,9 +3756,12 @@ setsignal(int signo) | |||
3751 | #endif | 3756 | #endif |
3752 | } | 3757 | } |
3753 | } | 3758 | } |
3754 | //TODO: if !rootshell, we reset SIGQUIT to DFL, | 3759 | /* if !rootshell, we reset SIGQUIT to DFL, |
3755 | //whereas we have to restore it to what shell got on entry | 3760 | * whereas we have to restore it to what shell got on entry. |
3756 | //from the parent. See comment above | 3761 | * This is handled by the fact that if signal was IGNored on entry, |
3762 | * then cur_act is S_HARD_IGN and we never change its sigaction | ||
3763 | * (see code below). | ||
3764 | */ | ||
3757 | 3765 | ||
3758 | if (signo == SIGCHLD) | 3766 | if (signo == SIGCHLD) |
3759 | new_act = S_CATCH; | 3767 | new_act = S_CATCH; |
@@ -3777,10 +3785,18 @@ setsignal(int signo) | |||
3777 | cur_act = S_IGN; /* don't hard ignore these */ | 3785 | cur_act = S_IGN; /* don't hard ignore these */ |
3778 | } | 3786 | } |
3779 | } | 3787 | } |
3788 | if (act.sa_handler == SIG_DFL && new_act == S_DFL) { | ||
3789 | /* installing SIG_DFL over SIG_DFL is a no-op */ | ||
3790 | /* saves one sigaction call in each "sh -c SCRIPT" invocation */ | ||
3791 | *t = S_DFL; | ||
3792 | return; | ||
3793 | } | ||
3780 | } | 3794 | } |
3781 | if (cur_act == S_HARD_IGN || cur_act == new_act) | 3795 | if (cur_act == S_HARD_IGN || cur_act == new_act) |
3782 | return; | 3796 | return; |
3783 | 3797 | ||
3798 | *t = new_act; | ||
3799 | |||
3784 | act.sa_handler = SIG_DFL; | 3800 | act.sa_handler = SIG_DFL; |
3785 | switch (new_act) { | 3801 | switch (new_act) { |
3786 | case S_CATCH: | 3802 | case S_CATCH: |
@@ -3790,16 +3806,13 @@ setsignal(int signo) | |||
3790 | act.sa_handler = SIG_IGN; | 3806 | act.sa_handler = SIG_IGN; |
3791 | break; | 3807 | break; |
3792 | } | 3808 | } |
3793 | |||
3794 | /* flags and mask matter only if !DFL and !IGN, but we do it | 3809 | /* flags and mask matter only if !DFL and !IGN, but we do it |
3795 | * for all cases for more deterministic behavior: | 3810 | * for all cases for more deterministic behavior: |
3796 | */ | 3811 | */ |
3797 | act.sa_flags = 0; | 3812 | act.sa_flags = 0; //TODO: why not SA_RESTART? |
3798 | sigfillset(&act.sa_mask); | 3813 | sigfillset(&act.sa_mask); |
3799 | 3814 | ||
3800 | sigaction_set(signo, &act); | 3815 | sigaction_set(signo, &act); |
3801 | |||
3802 | *t = new_act; | ||
3803 | } | 3816 | } |
3804 | #else | 3817 | #else |
3805 | #define setsignal(s) | 3818 | #define setsignal(s) |
@@ -5915,12 +5928,10 @@ static void | |||
5915 | redirect(union node *redir, int flags) | 5928 | redirect(union node *redir, int flags) |
5916 | { | 5929 | { |
5917 | struct redirtab *sv; | 5930 | struct redirtab *sv; |
5918 | int sv_pos; | ||
5919 | 5931 | ||
5920 | if (!redir) | 5932 | if (!redir) |
5921 | return; | 5933 | return; |
5922 | 5934 | ||
5923 | sv_pos = 0; | ||
5924 | sv = NULL; | 5935 | sv = NULL; |
5925 | INT_OFF; | 5936 | INT_OFF; |
5926 | if (flags & REDIR_PUSH) | 5937 | if (flags & REDIR_PUSH) |
@@ -8076,8 +8087,9 @@ static int | |||
8076 | patmatch(char *pattern, const char *string) | 8087 | patmatch(char *pattern, const char *string) |
8077 | { | 8088 | { |
8078 | char *p = preglob(pattern, 0); | 8089 | char *p = preglob(pattern, 0); |
8079 | //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string); | 8090 | int r = pmatch(p, string); |
8080 | return pmatch(p, string); | 8091 | //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r); |
8092 | return r; | ||
8081 | } | 8093 | } |
8082 | 8094 | ||
8083 | /* | 8095 | /* |
@@ -8179,7 +8191,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8179 | while (*envp) | 8191 | while (*envp) |
8180 | putenv(*envp++); | 8192 | putenv(*envp++); |
8181 | popredir(/*drop:*/ 1); | 8193 | popredir(/*drop:*/ 1); |
8182 | run_applet_no_and_exit(applet_no, cmd, argv); | 8194 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
8183 | } | 8195 | } |
8184 | /* re-exec ourselves with the new arguments */ | 8196 | /* re-exec ourselves with the new arguments */ |
8185 | execve(bb_busybox_exec_path, argv, envp); | 8197 | execve(bb_busybox_exec_path, argv, envp); |
@@ -10250,6 +10262,15 @@ evalcommand(union node *cmd, int flags) | |||
10250 | expredir(cmd->ncmd.redirect); | 10262 | expredir(cmd->ncmd.redirect); |
10251 | redir_stop = pushredir(cmd->ncmd.redirect); | 10263 | redir_stop = pushredir(cmd->ncmd.redirect); |
10252 | preverrout_fd = 2; | 10264 | preverrout_fd = 2; |
10265 | if (BASH_XTRACEFD && xflag) { | ||
10266 | /* NB: bash closes fd == $BASH_XTRACEFD when it is changed. | ||
10267 | * we do not emulate this. We only use its value. | ||
10268 | */ | ||
10269 | const char *xtracefd = lookupvar("BASH_XTRACEFD"); | ||
10270 | if (xtracefd && is_number(xtracefd)) | ||
10271 | preverrout_fd = atoi(xtracefd); | ||
10272 | |||
10273 | } | ||
10253 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); | 10274 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); |
10254 | 10275 | ||
10255 | path = vpath.var_text; | 10276 | path = vpath.var_text; |
@@ -10383,12 +10404,30 @@ evalcommand(union node *cmd, int flags) | |||
10383 | #endif | 10404 | #endif |
10384 | ) { | 10405 | ) { |
10385 | listsetvar(varlist.list, VEXPORT|VSTACK); | 10406 | listsetvar(varlist.list, VEXPORT|VSTACK); |
10386 | /* run <applet>_main() */ | 10407 | /* |
10408 | * Run <applet>_main(). | ||
10409 | * Signals (^C) can't interrupt here. | ||
10410 | * Otherwise we can mangle stdio or malloc internal state. | ||
10411 | * This makes applets which can run for a long time | ||
10412 | * and/or wait for user input ineligible for NOFORK: | ||
10413 | * for example, "yes" or "rm" (rm -i waits for input). | ||
10414 | */ | ||
10415 | INT_OFF; | ||
10387 | status = run_nofork_applet(applet_no, argv); | 10416 | status = run_nofork_applet(applet_no, argv); |
10417 | /* | ||
10418 | * Try enabling NOFORK for "yes" applet. | ||
10419 | * ^C _will_ stop it (write returns EINTR), | ||
10420 | * but this causes stdout FILE to be stuck | ||
10421 | * and needing clearerr(). What if other applets | ||
10422 | * also can get EINTRs? Do we need to switch | ||
10423 | * our signals to SA_RESTART? | ||
10424 | */ | ||
10425 | /*clearerr(stdout);*/ | ||
10426 | INT_ON; | ||
10388 | break; | 10427 | break; |
10389 | } | 10428 | } |
10390 | #endif | 10429 | #endif |
10391 | /* Can we avoid forking off? For example, very last command | 10430 | /* Can we avoid forking? For example, very last command |
10392 | * in a script or a subshell does not need forking, | 10431 | * in a script or a subshell does not need forking, |
10393 | * we can just exec it. | 10432 | * we can just exec it. |
10394 | */ | 10433 | */ |
@@ -10674,8 +10713,8 @@ preadfd(void) | |||
10674 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 10713 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
10675 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 10714 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
10676 | else { | 10715 | else { |
10677 | int timeout = -1; | ||
10678 | # if ENABLE_ASH_IDLE_TIMEOUT | 10716 | # if ENABLE_ASH_IDLE_TIMEOUT |
10717 | int timeout = -1; | ||
10679 | if (iflag) { | 10718 | if (iflag) { |
10680 | const char *tmout_var = lookupvar("TMOUT"); | 10719 | const char *tmout_var = lookupvar("TMOUT"); |
10681 | if (tmout_var) { | 10720 | if (tmout_var) { |
@@ -10684,12 +10723,13 @@ preadfd(void) | |||
10684 | timeout = -1; | 10723 | timeout = -1; |
10685 | } | 10724 | } |
10686 | } | 10725 | } |
10726 | line_input_state->timeout = timeout; | ||
10687 | # endif | 10727 | # endif |
10688 | # if ENABLE_FEATURE_TAB_COMPLETION | 10728 | # if ENABLE_FEATURE_TAB_COMPLETION |
10689 | line_input_state->path_lookup = pathval(); | 10729 | line_input_state->path_lookup = pathval(); |
10690 | # endif | 10730 | # endif |
10691 | reinit_unicode_for_ash(); | 10731 | reinit_unicode_for_ash(); |
10692 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); | 10732 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); |
10693 | if (nr == 0) { | 10733 | if (nr == 0) { |
10694 | /* ^C pressed, "convert" to SIGINT */ | 10734 | /* ^C pressed, "convert" to SIGINT */ |
10695 | write(STDOUT_FILENO, "^C", 2); | 10735 | write(STDOUT_FILENO, "^C", 2); |
@@ -11399,6 +11439,7 @@ getopts(char *optstr, char *optvar, char **optfirst) | |||
11399 | p = *optnext; | 11439 | p = *optnext; |
11400 | if (p == NULL || *p != '-' || *++p == '\0') { | 11440 | if (p == NULL || *p != '-' || *++p == '\0') { |
11401 | atend: | 11441 | atend: |
11442 | unsetvar("OPTARG"); | ||
11402 | p = NULL; | 11443 | p = NULL; |
11403 | done = 1; | 11444 | done = 1; |
11404 | goto out; | 11445 | goto out; |
@@ -11411,7 +11452,11 @@ getopts(char *optstr, char *optvar, char **optfirst) | |||
11411 | c = *p++; | 11452 | c = *p++; |
11412 | for (q = optstr; *q != c;) { | 11453 | for (q = optstr; *q != c;) { |
11413 | if (*q == '\0') { | 11454 | if (*q == '\0') { |
11414 | if (optstr[0] == ':') { | 11455 | /* OPTERR is a bashism */ |
11456 | const char *cp = lookupvar("OPTERR"); | ||
11457 | if ((cp && LONE_CHAR(cp, '0')) | ||
11458 | || (optstr[0] == ':') | ||
11459 | ) { | ||
11415 | sbuf[0] = c; | 11460 | sbuf[0] = c; |
11416 | /*sbuf[1] = '\0'; - already is */ | 11461 | /*sbuf[1] = '\0'; - already is */ |
11417 | setvar0("OPTARG", sbuf); | 11462 | setvar0("OPTARG", sbuf); |
@@ -11428,7 +11473,11 @@ getopts(char *optstr, char *optvar, char **optfirst) | |||
11428 | 11473 | ||
11429 | if (*++q == ':') { | 11474 | if (*++q == ':') { |
11430 | if (*p == '\0' && (p = *optnext) == NULL) { | 11475 | if (*p == '\0' && (p = *optnext) == NULL) { |
11431 | if (optstr[0] == ':') { | 11476 | /* OPTERR is a bashism */ |
11477 | const char *cp = lookupvar("OPTERR"); | ||
11478 | if ((cp && LONE_CHAR(cp, '0')) | ||
11479 | || (optstr[0] == ':') | ||
11480 | ) { | ||
11432 | sbuf[0] = c; | 11481 | sbuf[0] = c; |
11433 | /*sbuf[1] = '\0'; - already is */ | 11482 | /*sbuf[1] = '\0'; - already is */ |
11434 | setvar0("OPTARG", sbuf); | 11483 | setvar0("OPTARG", sbuf); |
@@ -12571,7 +12620,7 @@ parsesub: { | |||
12571 | STPUTC(c, out); | 12620 | STPUTC(c, out); |
12572 | c = pgetc_eatbnl(); | 12621 | c = pgetc_eatbnl(); |
12573 | } while (isdigit(c)); | 12622 | } while (isdigit(c)); |
12574 | } else if (is_special(c)) { | 12623 | } else { |
12575 | /* $[{[#]]<specialchar>[}] */ | 12624 | /* $[{[#]]<specialchar>[}] */ |
12576 | int cc = c; | 12625 | int cc = c; |
12577 | 12626 | ||
@@ -12589,10 +12638,16 @@ parsesub: { | |||
12589 | cc = '#'; | 12638 | cc = '#'; |
12590 | } | 12639 | } |
12591 | } | 12640 | } |
12641 | |||
12642 | if (!is_special(cc)) { | ||
12643 | if (subtype == VSLENGTH) | ||
12644 | subtype = 0; | ||
12645 | goto badsub; | ||
12646 | } | ||
12647 | |||
12592 | USTPUTC(cc, out); | 12648 | USTPUTC(cc, out); |
12593 | } else { | ||
12594 | goto badsub; | ||
12595 | } | 12649 | } |
12650 | |||
12596 | if (c != '}' && subtype == VSLENGTH) { | 12651 | if (c != '}' && subtype == VSLENGTH) { |
12597 | /* ${#VAR didn't end with } */ | 12652 | /* ${#VAR didn't end with } */ |
12598 | goto badsub; | 12653 | goto badsub; |
@@ -13850,21 +13905,23 @@ static const unsigned char timescmd_str[] ALIGN1 = { | |||
13850 | static int FAST_FUNC | 13905 | static int FAST_FUNC |
13851 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 13906 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
13852 | { | 13907 | { |
13853 | unsigned long clk_tck, s, t; | 13908 | unsigned clk_tck; |
13854 | const unsigned char *p; | 13909 | const unsigned char *p; |
13855 | struct tms buf; | 13910 | struct tms buf; |
13856 | 13911 | ||
13857 | clk_tck = bb_clk_tck(); | 13912 | clk_tck = bb_clk_tck(); |
13858 | times(&buf); | ||
13859 | 13913 | ||
13914 | times(&buf); | ||
13860 | p = timescmd_str; | 13915 | p = timescmd_str; |
13861 | do { | 13916 | do { |
13917 | unsigned sec, frac; | ||
13918 | unsigned long t; | ||
13862 | t = *(clock_t *)(((char *) &buf) + p[1]); | 13919 | t = *(clock_t *)(((char *) &buf) + p[1]); |
13863 | s = t / clk_tck; | 13920 | sec = t / clk_tck; |
13864 | t = t % clk_tck; | 13921 | frac = t % clk_tck; |
13865 | out1fmt("%lum%lu.%03lus%c", | 13922 | out1fmt("%um%u.%03us%c", |
13866 | s / 60, s % 60, | 13923 | sec / 60, sec % 60, |
13867 | (t * 1000) / clk_tck, | 13924 | (frac * 1000) / clk_tck, |
13868 | p[0]); | 13925 | p[0]); |
13869 | p += 2; | 13926 | p += 2; |
13870 | } while (*p); | 13927 | } while (*p); |
@@ -13903,10 +13960,10 @@ letcmd(int argc UNUSED_PARAM, char **argv) | |||
13903 | * -p PROMPT Display PROMPT on stderr (if input is from tty) | 13960 | * -p PROMPT Display PROMPT on stderr (if input is from tty) |
13904 | * -t SECONDS Timeout after SECONDS (tty or pipe only) | 13961 | * -t SECONDS Timeout after SECONDS (tty or pipe only) |
13905 | * -u FD Read from given FD instead of fd 0 | 13962 | * -u FD Read from given FD instead of fd 0 |
13963 | * -d DELIM End on DELIM char, not newline | ||
13906 | * This uses unbuffered input, which may be avoidable in some cases. | 13964 | * This uses unbuffered input, which may be avoidable in some cases. |
13907 | * TODO: bash also has: | 13965 | * TODO: bash also has: |
13908 | * -a ARRAY Read into array[0],[1],etc | 13966 | * -a ARRAY Read into array[0],[1],etc |
13909 | * -d DELIM End on DELIM char, not newline | ||
13910 | * -e Use line editing (tty only) | 13967 | * -e Use line editing (tty only) |
13911 | */ | 13968 | */ |
13912 | static int FAST_FUNC | 13969 | static int FAST_FUNC |
@@ -13916,11 +13973,12 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13916 | char *opt_p = NULL; | 13973 | char *opt_p = NULL; |
13917 | char *opt_t = NULL; | 13974 | char *opt_t = NULL; |
13918 | char *opt_u = NULL; | 13975 | char *opt_u = NULL; |
13976 | char *opt_d = NULL; /* optimized out if !BASH */ | ||
13919 | int read_flags = 0; | 13977 | int read_flags = 0; |
13920 | const char *r; | 13978 | const char *r; |
13921 | int i; | 13979 | int i; |
13922 | 13980 | ||
13923 | while ((i = nextopt("p:u:rt:n:s")) != '\0') { | 13981 | while ((i = nextopt("p:u:rt:n:sd:")) != '\0') { |
13924 | switch (i) { | 13982 | switch (i) { |
13925 | case 'p': | 13983 | case 'p': |
13926 | opt_p = optionarg; | 13984 | opt_p = optionarg; |
@@ -13940,6 +13998,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13940 | case 'u': | 13998 | case 'u': |
13941 | opt_u = optionarg; | 13999 | opt_u = optionarg; |
13942 | break; | 14000 | break; |
14001 | #if BASH_READ_D | ||
14002 | case 'd': | ||
14003 | opt_d = optionarg; | ||
14004 | break; | ||
14005 | #endif | ||
13943 | default: | 14006 | default: |
13944 | break; | 14007 | break; |
13945 | } | 14008 | } |
@@ -13957,12 +14020,15 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13957 | opt_n, | 14020 | opt_n, |
13958 | opt_p, | 14021 | opt_p, |
13959 | opt_t, | 14022 | opt_t, |
13960 | opt_u | 14023 | opt_u, |
14024 | opt_d | ||
13961 | ); | 14025 | ); |
13962 | INT_ON; | 14026 | INT_ON; |
13963 | 14027 | ||
13964 | if ((uintptr_t)r == 1 && errno == EINTR) { | 14028 | if ((uintptr_t)r == 1 && errno == EINTR) { |
13965 | /* to get SIGCHLD: sleep 1 & read x; echo $x */ | 14029 | /* To get SIGCHLD: sleep 1 & read x; echo $x |
14030 | * Correct behavior is to not exit "read" | ||
14031 | */ | ||
13966 | if (pending_sig == 0) | 14032 | if (pending_sig == 0) |
13967 | goto again; | 14033 | goto again; |
13968 | } | 14034 | } |
@@ -14077,7 +14143,8 @@ exitshell(void) | |||
14077 | /* NOTREACHED */ | 14143 | /* NOTREACHED */ |
14078 | } | 14144 | } |
14079 | 14145 | ||
14080 | static void | 14146 | /* Don't inline: conserve stack of caller from having our locals too */ |
14147 | static NOINLINE void | ||
14081 | #if ENABLE_PLATFORM_MINGW32 | 14148 | #if ENABLE_PLATFORM_MINGW32 |
14082 | init(int xp) | 14149 | init(int xp) |
14083 | #else | 14150 | #else |
@@ -14086,8 +14153,9 @@ init(void) | |||
14086 | { | 14153 | { |
14087 | /* we will never free this */ | 14154 | /* we will never free this */ |
14088 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 14155 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
14156 | basepf.linno = 1; | ||
14089 | 14157 | ||
14090 | sigmode[SIGCHLD - 1] = S_DFL; | 14158 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
14091 | setsignal(SIGCHLD); | 14159 | setsignal(SIGCHLD); |
14092 | 14160 | ||
14093 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. | 14161 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. |
@@ -14098,7 +14166,6 @@ init(void) | |||
14098 | { | 14166 | { |
14099 | char **envp; | 14167 | char **envp; |
14100 | const char *p; | 14168 | const char *p; |
14101 | struct stat st1, st2; | ||
14102 | 14169 | ||
14103 | initvar(); | 14170 | initvar(); |
14104 | 14171 | ||
@@ -14204,6 +14271,7 @@ init(void) | |||
14204 | #endif | 14271 | #endif |
14205 | p = lookupvar("PWD"); | 14272 | p = lookupvar("PWD"); |
14206 | if (p) { | 14273 | if (p) { |
14274 | struct stat st1, st2; | ||
14207 | if (p[0] != '/' || stat(p, &st1) || stat(".", &st2) | 14275 | if (p[0] != '/' || stat(p, &st1) || stat(".", &st2) |
14208 | || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino | 14276 | || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino |
14209 | ) { | 14277 | ) { |
@@ -15161,7 +15229,7 @@ sticky_free(void *base) | |||
15161 | * may be used to endorse or promote products derived from this software | 15229 | * may be used to endorse or promote products derived from this software |
15162 | * without specific prior written permission. | 15230 | * without specific prior written permission. |
15163 | * | 15231 | * |
15164 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 15232 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
15165 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 15233 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15166 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 15234 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
15167 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 15235 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/shell/ash_LINENO.patch b/shell/ash_LINENO.patch new file mode 100644 index 000000000..a71549d6a --- /dev/null +++ b/shell/ash_LINENO.patch | |||
@@ -0,0 +1,498 @@ | |||
1 | This patch is a backport from dash of the combination of: | ||
2 | [SHELL] Add preliminary LINENO support | ||
3 | [VAR] Fix varinit ordering that broke fc | ||
4 | [SHELL] Improve LINENO support | ||
5 | |||
6 | Applies cleanly on top of: | ||
7 | commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe | ||
8 | Date: Tue Aug 15 15:44:41 2017 +0200 | ||
9 | |||
10 | Testsuite needs some tweaks (line numbers in some messages change). | ||
11 | |||
12 | Unfortunately, it is somewhat big: | ||
13 | |||
14 | function old new delta | ||
15 | parse_command 1581 1658 +77 | ||
16 | calcsize 203 272 +69 | ||
17 | copynode 195 257 +62 | ||
18 | lookupvar 59 108 +49 | ||
19 | evaltree 494 534 +40 | ||
20 | evalfor 152 187 +35 | ||
21 | evalcase 278 313 +35 | ||
22 | evalcommand 1547 1581 +34 | ||
23 | evalsubshell 169 199 +30 | ||
24 | linenovar - 22 +22 | ||
25 | raise_error_syntax 11 29 +18 | ||
26 | evalfun 266 280 +14 | ||
27 | varinit_data 96 108 +12 | ||
28 | cmdtxt 626 631 +5 | ||
29 | lineno - 4 +4 | ||
30 | funcline - 4 +4 | ||
31 | ash_vmsg 144 141 -3 | ||
32 | startlinno 4 - -4 | ||
33 | funcnest 4 - -4 | ||
34 | xxreadtoken 272 259 -13 | ||
35 | readtoken1 2635 2594 -41 | ||
36 | ------------------------------------------------------------------------------ | ||
37 | (add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65) Total: 445 bytes | ||
38 | text data bss dec hex filename | ||
39 | 912030 563 5844 918437 e03a5 busybox_old | ||
40 | 912473 587 5844 918904 e0578 busybox_unstripped | ||
41 | |||
42 | diff --git a/shell/ash.c b/shell/ash.c | ||
43 | index 703802f..93a3814 100644 | ||
44 | --- a/shell/ash.c | ||
45 | +++ b/shell/ash.c | ||
46 | @@ -312,6 +312,8 @@ struct globals_misc { | ||
47 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | ||
48 | int shlvl; | ||
49 | #define rootshell (!shlvl) | ||
50 | + int errlinno; | ||
51 | + | ||
52 | char *minusc; /* argument to -c option */ | ||
53 | |||
54 | char *curdir; // = nullstr; /* current working directory */ | ||
55 | @@ -389,6 +391,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; | ||
56 | #define job_warning (G_misc.job_warning) | ||
57 | #define rootpid (G_misc.rootpid ) | ||
58 | #define shlvl (G_misc.shlvl ) | ||
59 | +#define errlinno (G_misc.errlinno ) | ||
60 | #define minusc (G_misc.minusc ) | ||
61 | #define curdir (G_misc.curdir ) | ||
62 | #define physdir (G_misc.physdir ) | ||
63 | @@ -723,6 +726,7 @@ union node; | ||
64 | |||
65 | struct ncmd { | ||
66 | smallint type; /* Nxxxx */ | ||
67 | + int linno; | ||
68 | union node *assign; | ||
69 | union node *args; | ||
70 | union node *redirect; | ||
71 | @@ -736,6 +740,7 @@ struct npipe { | ||
72 | |||
73 | struct nredir { | ||
74 | smallint type; | ||
75 | + int linno; | ||
76 | union node *n; | ||
77 | union node *redirect; | ||
78 | }; | ||
79 | @@ -755,6 +760,7 @@ struct nif { | ||
80 | |||
81 | struct nfor { | ||
82 | smallint type; | ||
83 | + int linno; | ||
84 | union node *args; | ||
85 | union node *body; | ||
86 | char *var; | ||
87 | @@ -762,6 +768,7 @@ struct nfor { | ||
88 | |||
89 | struct ncase { | ||
90 | smallint type; | ||
91 | + int linno; | ||
92 | union node *expr; | ||
93 | union node *cases; | ||
94 | }; | ||
95 | @@ -773,6 +780,13 @@ struct nclist { | ||
96 | union node *body; | ||
97 | }; | ||
98 | |||
99 | +struct ndefun { | ||
100 | + smallint type; | ||
101 | + int linno; | ||
102 | + char *text; | ||
103 | + union node *body; | ||
104 | +}; | ||
105 | + | ||
106 | struct narg { | ||
107 | smallint type; | ||
108 | union node *next; | ||
109 | @@ -824,6 +838,7 @@ union node { | ||
110 | struct nfor nfor; | ||
111 | struct ncase ncase; | ||
112 | struct nclist nclist; | ||
113 | + struct ndefun ndefun; | ||
114 | struct narg narg; | ||
115 | struct nfile nfile; | ||
116 | struct ndup ndup; | ||
117 | @@ -1253,7 +1268,6 @@ struct parsefile { | ||
118 | |||
119 | static struct parsefile basepf; /* top level input file */ | ||
120 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | ||
121 | -static int startlinno; /* line # where last token started */ | ||
122 | static char *commandname; /* currently executing command */ | ||
123 | |||
124 | |||
125 | @@ -1267,7 +1281,7 @@ ash_vmsg(const char *msg, va_list ap) | ||
126 | if (strcmp(arg0, commandname)) | ||
127 | fprintf(stderr, "%s: ", commandname); | ||
128 | if (!iflag || g_parsefile->pf_fd > 0) | ||
129 | - fprintf(stderr, "line %d: ", startlinno); | ||
130 | + fprintf(stderr, "line %d: ", errlinno); | ||
131 | } | ||
132 | vfprintf(stderr, msg, ap); | ||
133 | newline_and_flush(stderr); | ||
134 | @@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN; | ||
135 | static void | ||
136 | raise_error_syntax(const char *msg) | ||
137 | { | ||
138 | + errlinno = g_parsefile->linno; | ||
139 | ash_msg_and_raise_error("syntax error: %s", msg); | ||
140 | /* NOTREACHED */ | ||
141 | } | ||
142 | @@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC; | ||
143 | static void change_random(const char *) FAST_FUNC; | ||
144 | #endif | ||
145 | |||
146 | +static int lineno; | ||
147 | +static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO="; | ||
148 | + | ||
149 | static const struct { | ||
150 | int flags; | ||
151 | const char *var_text; | ||
152 | @@ -2014,6 +2032,7 @@ static const struct { | ||
153 | #if ENABLE_ASH_GETOPTS | ||
154 | { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, | ||
155 | #endif | ||
156 | + { VSTRFIXED|VTEXTFIXED , linenovar , NULL }, | ||
157 | #if ENABLE_ASH_RANDOM_SUPPORT | ||
158 | { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, | ||
159 | #endif | ||
160 | @@ -2066,12 +2085,14 @@ extern struct globals_var *const ash_ptr_to_globals_var; | ||
161 | #define vps4 (&vps2)[1] | ||
162 | #if ENABLE_ASH_GETOPTS | ||
163 | # define voptind (&vps4)[1] | ||
164 | +# define vlineno (&voptind)[1] | ||
165 | # if ENABLE_ASH_RANDOM_SUPPORT | ||
166 | -# define vrandom (&voptind)[1] | ||
167 | +# define vrandom (&vlineno)[1] | ||
168 | # endif | ||
169 | #else | ||
170 | +# define vlineno (&vps4)[1] | ||
171 | # if ENABLE_ASH_RANDOM_SUPPORT | ||
172 | -# define vrandom (&vps4)[1] | ||
173 | +# define vrandom (&vlineno)[1] | ||
174 | # endif | ||
175 | #endif | ||
176 | |||
177 | @@ -2209,8 +2230,12 @@ lookupvar(const char *name) | ||
178 | if (v->flags & VDYNAMIC) | ||
179 | v->var_func(NULL); | ||
180 | #endif | ||
181 | - if (!(v->flags & VUNSET)) | ||
182 | + if (!(v->flags & VUNSET)) { | ||
183 | + if (v == &vlineno && v->var_text == linenovar) { | ||
184 | + fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); | ||
185 | + } | ||
186 | return var_end(v->var_text); | ||
187 | + } | ||
188 | } | ||
189 | return NULL; | ||
190 | } | ||
191 | @@ -4783,7 +4808,7 @@ cmdtxt(union node *n) | ||
192 | p = "; done"; | ||
193 | goto dodo; | ||
194 | case NDEFUN: | ||
195 | - cmdputs(n->narg.text); | ||
196 | + cmdputs(n->ndefun.text); | ||
197 | p = "() { ... }"; | ||
198 | goto dotail2; | ||
199 | case NCMD: | ||
200 | @@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n) | ||
201 | funcblocksize = calcsize(funcblocksize, n->nclist.next); | ||
202 | break; | ||
203 | case NDEFUN: | ||
204 | + funcblocksize = calcsize(funcblocksize, n->ndefun.body); | ||
205 | + funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1); | ||
206 | + break; | ||
207 | case NARG: | ||
208 | funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); | ||
209 | funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ | ||
210 | @@ -8626,6 +8654,7 @@ copynode(union node *n) | ||
211 | new->ncmd.redirect = copynode(n->ncmd.redirect); | ||
212 | new->ncmd.args = copynode(n->ncmd.args); | ||
213 | new->ncmd.assign = copynode(n->ncmd.assign); | ||
214 | + new->ncmd.linno = n->ncmd.linno; | ||
215 | break; | ||
216 | case NPIPE: | ||
217 | new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); | ||
218 | @@ -8636,6 +8665,7 @@ copynode(union node *n) | ||
219 | case NSUBSHELL: | ||
220 | new->nredir.redirect = copynode(n->nredir.redirect); | ||
221 | new->nredir.n = copynode(n->nredir.n); | ||
222 | + new->nredir.linno = n->nredir.linno; | ||
223 | break; | ||
224 | case NAND: | ||
225 | case NOR: | ||
226 | @@ -8654,10 +8684,12 @@ copynode(union node *n) | ||
227 | new->nfor.var = nodeckstrdup(n->nfor.var); | ||
228 | new->nfor.body = copynode(n->nfor.body); | ||
229 | new->nfor.args = copynode(n->nfor.args); | ||
230 | + new->nfor.linno = n->nfor.linno; | ||
231 | break; | ||
232 | case NCASE: | ||
233 | new->ncase.cases = copynode(n->ncase.cases); | ||
234 | new->ncase.expr = copynode(n->ncase.expr); | ||
235 | + new->ncase.linno = n->ncase.linno; | ||
236 | break; | ||
237 | case NCLIST: | ||
238 | new->nclist.body = copynode(n->nclist.body); | ||
239 | @@ -8665,6 +8697,10 @@ copynode(union node *n) | ||
240 | new->nclist.next = copynode(n->nclist.next); | ||
241 | break; | ||
242 | case NDEFUN: | ||
243 | + new->ndefun.body = copynode(n->ndefun.body); | ||
244 | + new->ndefun.text = nodeckstrdup(n->ndefun.text); | ||
245 | + new->ndefun.linno = n->ndefun.linno; | ||
246 | + break; | ||
247 | case NARG: | ||
248 | new->narg.backquote = copynodelist(n->narg.backquote); | ||
249 | new->narg.text = nodeckstrdup(n->narg.text); | ||
250 | @@ -8733,7 +8769,7 @@ defun(union node *func) | ||
251 | INT_OFF; | ||
252 | entry.cmdtype = CMDFUNCTION; | ||
253 | entry.u.func = copyfunc(func); | ||
254 | - addcmdentry(func->narg.text, &entry); | ||
255 | + addcmdentry(func->ndefun.text, &entry); | ||
256 | INT_ON; | ||
257 | } | ||
258 | |||
259 | @@ -8743,8 +8779,8 @@ defun(union node *func) | ||
260 | #define SKIPFUNC (1 << 2) | ||
261 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | ||
262 | static int skipcount; /* number of levels to skip */ | ||
263 | -static int funcnest; /* depth of function calls */ | ||
264 | static int loopnest; /* current loop nesting level */ | ||
265 | +static int funcline; /* starting line number of current function, or 0 if not in a function */ | ||
266 | |||
267 | /* Forward decl way out to parsing code - dotrap needs it */ | ||
268 | static int evalstring(char *s, int flags); | ||
269 | @@ -8839,6 +8875,9 @@ evaltree(union node *n, int flags) | ||
270 | status = !evaltree(n->nnot.com, EV_TESTED); | ||
271 | goto setstatus; | ||
272 | case NREDIR: | ||
273 | + errlinno = lineno = n->nredir.linno; | ||
274 | + if (funcline) | ||
275 | + lineno -= funcline - 1; | ||
276 | expredir(n->nredir.redirect); | ||
277 | pushredir(n->nredir.redirect); | ||
278 | status = redirectsafe(n->nredir.redirect, REDIR_PUSH); | ||
279 | @@ -8993,6 +9032,10 @@ evalfor(union node *n, int flags) | ||
280 | struct stackmark smark; | ||
281 | int status = 0; | ||
282 | |||
283 | + errlinno = lineno = n->ncase.linno; | ||
284 | + if (funcline) | ||
285 | + lineno -= funcline - 1; | ||
286 | + | ||
287 | setstackmark(&smark); | ||
288 | arglist.list = NULL; | ||
289 | arglist.lastp = &arglist.list; | ||
290 | @@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags) | ||
291 | struct stackmark smark; | ||
292 | int status = 0; | ||
293 | |||
294 | + errlinno = lineno = n->ncase.linno; | ||
295 | + if (funcline) | ||
296 | + lineno -= funcline - 1; | ||
297 | + | ||
298 | setstackmark(&smark); | ||
299 | arglist.list = NULL; | ||
300 | arglist.lastp = &arglist.list; | ||
301 | @@ -9058,6 +9105,10 @@ evalsubshell(union node *n, int flags) | ||
302 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | ||
303 | int status; | ||
304 | |||
305 | + errlinno = lineno = n->nredir.linno; | ||
306 | + if (funcline) | ||
307 | + lineno -= funcline - 1; | ||
308 | + | ||
309 | expredir(n->nredir.redirect); | ||
310 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | ||
311 | goto nofork; | ||
312 | @@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | ||
313 | struct jmploc *volatile savehandler; | ||
314 | struct jmploc jmploc; | ||
315 | int e; | ||
316 | + int savefuncline; | ||
317 | |||
318 | saveparam = shellparam; | ||
319 | + savefuncline = funcline; | ||
320 | savehandler = exception_handler; | ||
321 | e = setjmp(jmploc.loc); | ||
322 | if (e) { | ||
323 | @@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | ||
324 | exception_handler = &jmploc; | ||
325 | shellparam.malloced = 0; | ||
326 | func->count++; | ||
327 | - funcnest++; | ||
328 | + funcline = func->n.ndefun.linno; | ||
329 | INT_ON; | ||
330 | shellparam.nparam = argc - 1; | ||
331 | shellparam.p = argv + 1; | ||
332 | @@ -9385,11 +9438,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | ||
333 | shellparam.optoff = -1; | ||
334 | #endif | ||
335 | pushlocalvars(); | ||
336 | - evaltree(func->n.narg.next, flags & EV_TESTED); | ||
337 | + evaltree(func->n.ndefun.body, flags & EV_TESTED); | ||
338 | poplocalvars(0); | ||
339 | funcdone: | ||
340 | INT_OFF; | ||
341 | - funcnest--; | ||
342 | + funcline = savefuncline; | ||
343 | freefunc(func); | ||
344 | freeparam(&shellparam); | ||
345 | shellparam = saveparam; | ||
346 | @@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags) | ||
347 | char **nargv; | ||
348 | smallint cmd_is_exec; | ||
349 | |||
350 | + errlinno = lineno = cmd->ncmd.linno; | ||
351 | + if (funcline) | ||
352 | + lineno -= funcline - 1; | ||
353 | + | ||
354 | /* First expand the arguments. */ | ||
355 | TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); | ||
356 | setstackmark(&smark); | ||
357 | @@ -9798,7 +9855,7 @@ evalcommand(union node *cmd, int flags) | ||
358 | *nargv = NULL; | ||
359 | |||
360 | lastarg = NULL; | ||
361 | - if (iflag && funcnest == 0 && argc > 0) | ||
362 | + if (iflag && funcline == 0 && argc > 0) | ||
363 | lastarg = nargv[-1]; | ||
364 | |||
365 | expredir(cmd->ncmd.redirect); | ||
366 | @@ -11317,6 +11374,7 @@ simplecmd(void) | ||
367 | union node *vars, **vpp; | ||
368 | union node **rpp, *redir; | ||
369 | int savecheckkwd; | ||
370 | + int savelinno; | ||
371 | #if BASH_TEST2 | ||
372 | smallint double_brackets_flag = 0; | ||
373 | #endif | ||
374 | @@ -11330,6 +11388,7 @@ simplecmd(void) | ||
375 | rpp = &redir; | ||
376 | |||
377 | savecheckkwd = CHKALIAS; | ||
378 | + savelinno = g_parsefile->linno; | ||
379 | for (;;) { | ||
380 | int t; | ||
381 | checkkwd = savecheckkwd; | ||
382 | @@ -11419,7 +11478,9 @@ simplecmd(void) | ||
383 | } | ||
384 | n->type = NDEFUN; | ||
385 | checkkwd = CHKNL | CHKKWD | CHKALIAS; | ||
386 | - n->narg.next = parse_command(); | ||
387 | + n->ndefun.text = n->narg.text; | ||
388 | + n->ndefun.linno = g_parsefile->linno; | ||
389 | + n->ndefun.body = parse_command(); | ||
390 | return n; | ||
391 | } | ||
392 | IF_BASH_FUNCTION(function_flag = 0;) | ||
393 | @@ -11435,6 +11496,7 @@ simplecmd(void) | ||
394 | *rpp = NULL; | ||
395 | n = stzalloc(sizeof(struct ncmd)); | ||
396 | n->type = NCMD; | ||
397 | + n->ncmd.linno = savelinno; | ||
398 | n->ncmd.args = args; | ||
399 | n->ncmd.assign = vars; | ||
400 | n->ncmd.redirect = redir; | ||
401 | @@ -11450,10 +11512,13 @@ parse_command(void) | ||
402 | union node *redir, **rpp; | ||
403 | union node **rpp2; | ||
404 | int t; | ||
405 | + int savelinno; | ||
406 | |||
407 | redir = NULL; | ||
408 | rpp2 = &redir; | ||
409 | |||
410 | + savelinno = g_parsefile->linno; | ||
411 | + | ||
412 | switch (readtoken()) { | ||
413 | default: | ||
414 | raise_error_unexpected_syntax(-1); | ||
415 | @@ -11504,6 +11569,7 @@ parse_command(void) | ||
416 | raise_error_syntax("bad for loop variable"); | ||
417 | n1 = stzalloc(sizeof(struct nfor)); | ||
418 | n1->type = NFOR; | ||
419 | + n1->nfor.linno = savelinno; | ||
420 | n1->nfor.var = wordtext; | ||
421 | checkkwd = CHKNL | CHKKWD | CHKALIAS; | ||
422 | if (readtoken() == TIN) { | ||
423 | @@ -11544,6 +11610,7 @@ parse_command(void) | ||
424 | case TCASE: | ||
425 | n1 = stzalloc(sizeof(struct ncase)); | ||
426 | n1->type = NCASE; | ||
427 | + n1->ncase.linno = savelinno; | ||
428 | if (readtoken() != TWORD) | ||
429 | raise_error_unexpected_syntax(TWORD); | ||
430 | n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); | ||
431 | @@ -11595,6 +11662,7 @@ parse_command(void) | ||
432 | case TLP: | ||
433 | n1 = stzalloc(sizeof(struct nredir)); | ||
434 | n1->type = NSUBSHELL; | ||
435 | + n1->nredir.linno = savelinno; | ||
436 | n1->nredir.n = list(0); | ||
437 | /*n1->nredir.redirect = NULL; - stzalloc did it */ | ||
438 | t = TRP; | ||
439 | @@ -11628,6 +11696,7 @@ parse_command(void) | ||
440 | if (n1->type != NSUBSHELL) { | ||
441 | n2 = stzalloc(sizeof(struct nredir)); | ||
442 | n2->type = NREDIR; | ||
443 | + n2->nredir.linno = savelinno; | ||
444 | n2->nredir.n = n1; | ||
445 | n1 = n2; | ||
446 | } | ||
447 | @@ -11726,10 +11795,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | ||
448 | IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ | ||
449 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ | ||
450 | int dqvarnest; /* levels of variables expansion within double quotes */ | ||
451 | - | ||
452 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) | ||
453 | |||
454 | - startlinno = g_parsefile->linno; | ||
455 | bqlist = NULL; | ||
456 | quotef = 0; | ||
457 | IF_FEATURE_SH_MATH(prevsyntax = 0;) | ||
458 | @@ -11906,7 +11973,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | ||
459 | if (syntax != BASESYNTAX && eofmark == NULL) | ||
460 | raise_error_syntax("unterminated quoted string"); | ||
461 | if (varnest != 0) { | ||
462 | - startlinno = g_parsefile->linno; | ||
463 | /* { */ | ||
464 | raise_error_syntax("missing '}'"); | ||
465 | } | ||
466 | @@ -12298,7 +12364,6 @@ parsebackq: { | ||
467 | |||
468 | case PEOF: | ||
469 | IF_ASH_ALIAS(case PEOA:) | ||
470 | - startlinno = g_parsefile->linno; | ||
471 | raise_error_syntax("EOF in backquote substitution"); | ||
472 | |||
473 | case '\n': | ||
474 | @@ -12380,8 +12445,6 @@ parsearith: { | ||
475 | * quoted. | ||
476 | * If the token is TREDIR, then we set redirnode to a structure containing | ||
477 | * the redirection. | ||
478 | - * In all cases, the variable startlinno is set to the number of the line | ||
479 | - * on which the token starts. | ||
480 | * | ||
481 | * [Change comment: here documents and internal procedures] | ||
482 | * [Readtoken shouldn't have any arguments. Perhaps we should make the | ||
483 | @@ -12419,7 +12482,6 @@ xxreadtoken(void) | ||
484 | return lasttoken; | ||
485 | } | ||
486 | setprompt_if(needprompt, 2); | ||
487 | - startlinno = g_parsefile->linno; | ||
488 | for (;;) { /* until token or start of word found */ | ||
489 | c = pgetc(); | ||
490 | if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) | ||
491 | @@ -12480,7 +12542,6 @@ xxreadtoken(void) | ||
492 | return lasttoken; | ||
493 | } | ||
494 | setprompt_if(needprompt, 2); | ||
495 | - startlinno = g_parsefile->linno; | ||
496 | for (;;) { /* until token or start of word found */ | ||
497 | c = pgetc(); | ||
498 | switch (c) { | ||
diff --git a/shell/ash_test/ash-getopts/getopt_optarg.right b/shell/ash_test/ash-getopts/getopt_optarg.right new file mode 100644 index 000000000..dff28de57 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_optarg.right | |||
@@ -0,0 +1,18 @@ | |||
1 | *** no OPTIND, optstring:'w:et' args:-q -w e -r -t -y | ||
2 | Illegal option -q | ||
3 | var:'?' OPTIND:2 OPTARG:'' | ||
4 | var:'w' OPTIND:4 OPTARG:'e' | ||
5 | Illegal option -r | ||
6 | var:'?' OPTIND:5 OPTARG:'' | ||
7 | var:'t' OPTIND:6 OPTARG:'' | ||
8 | Illegal option -y | ||
9 | var:'?' OPTIND:7 OPTARG:'' | ||
10 | exited: var:'?' OPTIND:7 OPTARG:'' | ||
11 | *** OPTIND=0, optstring:'w:et' args:-w 1 -w2 -w -e -e -t -t | ||
12 | var:'w' OPTIND:3 OPTARG:'1' | ||
13 | var:'w' OPTIND:4 OPTARG:'2' | ||
14 | var:'w' OPTIND:6 OPTARG:'-e' | ||
15 | var:'e' OPTIND:7 OPTARG:'' | ||
16 | var:'t' OPTIND:8 OPTARG:'' | ||
17 | var:'t' OPTIND:9 OPTARG:'' | ||
18 | exited: var:'?' OPTIND:9 OPTARG:'' | ||
diff --git a/shell/ash_test/ash-getopts/getopt_optarg.tests b/shell/ash_test/ash-getopts/getopt_optarg.tests new file mode 100755 index 000000000..33682e868 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_optarg.tests | |||
@@ -0,0 +1,18 @@ | |||
1 | set -- -q -w e -r -t -y | ||
2 | echo "*** no OPTIND, optstring:'w:et' args:$*" | ||
3 | var=QWERTY | ||
4 | OPTARG=ASDFGH | ||
5 | while getopts "w:et" var; do | ||
6 | echo "var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
7 | OPTARG=ASDFGH | ||
8 | done | ||
9 | echo "exited: var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
10 | |||
11 | set -- -w 1 -w2 -w -e -e -t -t | ||
12 | echo "*** OPTIND=0, optstring:'w:et' args:$*" | ||
13 | OPTIND=0 | ||
14 | while getopts "w:et" var; do | ||
15 | echo "var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
16 | OPTARG=ASDFGH | ||
17 | done | ||
18 | echo "exited: var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
diff --git a/shell/ash_test/ash-getopts/getopt_positional.right b/shell/ash_test/ash-getopts/getopt_positional.right new file mode 100644 index 000000000..37d0ec845 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_positional.right | |||
@@ -0,0 +1,6 @@ | |||
1 | *** no OPTIND, optstring:'we' args:-q -w -e r -t -y | ||
2 | Illegal option -q | ||
3 | var:'?' OPTIND:2 | ||
4 | var:'w' OPTIND:3 | ||
5 | var:'e' OPTIND:4 | ||
6 | exited: var:'?' OPTIND:4 | ||
diff --git a/shell/ash_test/ash-getopts/getopt_positional.tests b/shell/ash_test/ash-getopts/getopt_positional.tests new file mode 100755 index 000000000..a5404a2a0 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_positional.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | set -- -q -w -e r -t -y | ||
2 | echo "*** no OPTIND, optstring:'we' args:$*" | ||
3 | var=QWERTY | ||
4 | while getopts "we" var; do | ||
5 | echo "var:'$var' OPTIND:$OPTIND" | ||
6 | done | ||
7 | # unfortunately, "rc:0" is shown since while's overall exitcode is "success" | ||
8 | echo "exited: var:'$var' OPTIND:$OPTIND" | ||
diff --git a/shell/ash_test/ash-getopts/getopt_silent.right b/shell/ash_test/ash-getopts/getopt_silent.right new file mode 100644 index 000000000..03d4eb149 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_silent.right | |||
@@ -0,0 +1,6 @@ | |||
1 | *** optstring:':ac' args:-a -b -c | ||
2 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
3 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'b' | ||
4 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
5 | 4 rc:1 var:'?' OPTIND:4 OPTARG:'' | ||
6 | 5 rc:1 var:'?' OPTIND:4 OPTARG:'' | ||
diff --git a/shell/ash_test/ash-getopts/getopt_silent.tests b/shell/ash_test/ash-getopts/getopt_silent.tests new file mode 100755 index 000000000..097d7ba85 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_silent.tests | |||
@@ -0,0 +1,23 @@ | |||
1 | # Open Group Base Specifications Issue 7: | ||
2 | # """ | ||
3 | # If an unknown option is met, VAR shall be set to "?". In this case, | ||
4 | # if the first character in optstring is ":", OPTARG shall be set | ||
5 | # to the option character found, but no output shall be written | ||
6 | # to standard error; otherwise, the shell variable OPTARG shall be | ||
7 | # unset and a diagnostic message shall be written to standard error." | ||
8 | # ... | ||
9 | # If an option-argument is missing: | ||
10 | # If the first character of optstring is ":", VAR shall be set to ":" | ||
11 | # and OPTARG shall be set to the option character found. | ||
12 | # """ | ||
13 | |||
14 | echo "*** optstring:':ac' args:-a -b -c" | ||
15 | getopts ":ac" var -a -b -c; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
16 | getopts ":ac" var -a -b -c; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
17 | getopts ":ac" var -a -b -c; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
18 | getopts ":ac" var -a -b -c; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
19 | # Previous line should result in "rc:1", which is normally treated | ||
20 | # in getopts loops as exit condition. | ||
21 | # Nevertheless, let's verify that calling it yet another time doesn't do | ||
22 | # anything weird: | ||
23 | getopts ":ac" var -a -b -c; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
diff --git a/shell/ash_test/ash-getopts/getopt_simple.right b/shell/ash_test/ash-getopts/getopt_simple.right new file mode 100644 index 000000000..07e3c57f5 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_simple.right | |||
@@ -0,0 +1,34 @@ | |||
1 | *** no OPTIND, optstring:'ab' args:-a -b c | ||
2 | var:'a' OPTIND:2 | ||
3 | var:'b' OPTIND:3 | ||
4 | exited: rc:0 var:'?' OPTIND:3 | ||
5 | *** OPTIND=1, optstring:'ab' args:-a -b c | ||
6 | var:'a' OPTIND:2 | ||
7 | var:'b' OPTIND:3 | ||
8 | exited: rc:0 var:'?' OPTIND:3 | ||
9 | *** OPTIND=0, optstring:'ab' args:-a -b c | ||
10 | var:'a' OPTIND:2 | ||
11 | var:'b' OPTIND:3 | ||
12 | exited: rc:0 var:'?' OPTIND:3 | ||
13 | *** unset OPTIND, optstring:'ab' args:-a -b c | ||
14 | var:'a' OPTIND:2 | ||
15 | var:'b' OPTIND:3 | ||
16 | exited: rc:0 var:'?' OPTIND:3 | ||
17 | *** optstring:'ab' args:-a -b c | ||
18 | 1 rc:0 var:'a' OPTIND:2 | ||
19 | 2 rc:0 var:'b' OPTIND:3 | ||
20 | 3 rc:1 var:'?' OPTIND:3 | ||
21 | *** unset OPTIND, optstring:'ab' args:-a c -c -b d | ||
22 | var:'a' OPTIND:2 | ||
23 | exited: rc:0 var:'?' OPTIND:2 | ||
24 | *** unset OPTIND, optstring:'ab' args:-a -c -b d | ||
25 | var:'a' OPTIND:2 | ||
26 | Illegal option -c | ||
27 | var:'?' OPTIND:3 | ||
28 | var:'b' OPTIND:4 | ||
29 | exited: rc:0 var:'?' OPTIND:4 | ||
30 | *** unset OPTIND, OPTERR=0, optstring:'ab' args:-a -c -b d | ||
31 | var:'a' OPTIND:2 | ||
32 | var:'?' OPTIND:3 | ||
33 | var:'b' OPTIND:4 | ||
34 | exited: rc:0 var:'?' OPTIND:4 | ||
diff --git a/shell/ash_test/ash-getopts/getopt_simple.tests b/shell/ash_test/ash-getopts/getopt_simple.tests new file mode 100755 index 000000000..8615ae366 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_simple.tests | |||
@@ -0,0 +1,75 @@ | |||
1 | # Simple usage cases for getopts. | ||
2 | # | ||
3 | # OPTIND is either not touched at all (first loop with getopts, | ||
4 | # relying on shell startup init), or getopts state is reset | ||
5 | # before new loop with "unset OPTIND", "OPTIND=1" or "OPTIND=0". | ||
6 | # | ||
7 | # Each option is a separate argument (no "-abc"). This conceptually | ||
8 | # needs only $OPTIND to hold getopts state. | ||
9 | # | ||
10 | # We check that loop does not stop on unknown option (sets "?"), | ||
11 | # stops on _first_ non-option argument. | ||
12 | |||
13 | echo "*** no OPTIND, optstring:'ab' args:-a -b c" | ||
14 | var=QWERTY | ||
15 | while getopts "ab" var -a -b c; do | ||
16 | echo "var:'$var' OPTIND:$OPTIND" | ||
17 | done | ||
18 | # unfortunately, "rc:0" is shown since while's overall exitcode is "success" | ||
19 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
20 | |||
21 | # Resetting behavior =1 | ||
22 | echo "*** OPTIND=1, optstring:'ab' args:-a -b c" | ||
23 | OPTIND=1 | ||
24 | while getopts "ab" var -a -b c; do | ||
25 | echo "var:'$var' OPTIND:$OPTIND" | ||
26 | done | ||
27 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
28 | |||
29 | # Resetting behavior =0 | ||
30 | echo "*** OPTIND=0, optstring:'ab' args:-a -b c" | ||
31 | OPTIND=0 | ||
32 | while getopts "ab" var -a -b c; do | ||
33 | echo "var:'$var' OPTIND:$OPTIND" | ||
34 | done | ||
35 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
36 | |||
37 | # Resetting behavior "unset" | ||
38 | echo "*** unset OPTIND, optstring:'ab' args:-a -b c" | ||
39 | unset OPTIND | ||
40 | while getopts "ab" var -a -b c; do | ||
41 | echo "var:'$var' OPTIND:$OPTIND" | ||
42 | done | ||
43 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
44 | |||
45 | # What is the final exitcode? | ||
46 | echo "*** optstring:'ab' args:-a -b c" | ||
47 | unset OPTIND | ||
48 | getopts "ab" var -a -b c; echo "1 rc:$? var:'$var' OPTIND:$OPTIND" | ||
49 | getopts "ab" var -a -b c; echo "2 rc:$? var:'$var' OPTIND:$OPTIND" | ||
50 | getopts "ab" var -a -b c; echo "3 rc:$? var:'$var' OPTIND:$OPTIND" | ||
51 | |||
52 | # Where would it stop? c or -c? | ||
53 | echo "*** unset OPTIND, optstring:'ab' args:-a c -c -b d" | ||
54 | unset OPTIND | ||
55 | while getopts "ab" var -a c -c -b d; do | ||
56 | echo "var:'$var' OPTIND:$OPTIND" | ||
57 | done | ||
58 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
59 | |||
60 | # What happens on unknown option? | ||
61 | echo "*** unset OPTIND, optstring:'ab' args:-a -c -b d" | ||
62 | unset OPTIND | ||
63 | while getopts "ab" var -a -c -b d; do | ||
64 | echo "var:'$var' OPTIND:$OPTIND" | ||
65 | done | ||
66 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
67 | |||
68 | # ORTERR=0 suppresses error message? | ||
69 | echo "*** unset OPTIND, OPTERR=0, optstring:'ab' args:-a -c -b d" | ||
70 | unset OPTIND | ||
71 | OPTERR=0 | ||
72 | while getopts "ab" var -a -c -b d; do | ||
73 | echo "var:'$var' OPTIND:$OPTIND" | ||
74 | done | ||
75 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
diff --git a/shell/ash_test/ash-getopts/getopt_test_libc_bug.right b/shell/ash_test/ash-getopts/getopt_test_libc_bug.right new file mode 100644 index 000000000..f6ad4602d --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_test_libc_bug.right | |||
@@ -0,0 +1,26 @@ | |||
1 | *** optstring:'ac' args:-a -b -c -d e | ||
2 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
3 | Illegal option -b | ||
4 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'' | ||
5 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
6 | Illegal option -d | ||
7 | 4 rc:0 var:'?' OPTIND:5 OPTARG:'' | ||
8 | 5 rc:1 var:'?' OPTIND:5 OPTARG:'' | ||
9 | |||
10 | *** optstring:'ac' args:-a -b -c -d e | ||
11 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
12 | Illegal option -b | ||
13 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'' | ||
14 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
15 | Illegal option -d | ||
16 | 4 rc:0 var:'?' OPTIND:5 OPTARG:'' | ||
17 | 5 rc:1 var:'?' OPTIND:5 OPTARG:'' | ||
18 | |||
19 | *** optstring:'ac' args:-a -b -c -d e | ||
20 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
21 | Illegal option -b | ||
22 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'' | ||
23 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
24 | Illegal option -d | ||
25 | 4 rc:0 var:'?' OPTIND:5 OPTARG:'' | ||
26 | 5 rc:1 var:'?' OPTIND:5 OPTARG:'' | ||
diff --git a/shell/ash_test/ash-getopts/getopt_test_libc_bug.tests b/shell/ash_test/ash-getopts/getopt_test_libc_bug.tests new file mode 100755 index 000000000..fcaac81a2 --- /dev/null +++ b/shell/ash_test/ash-getopts/getopt_test_libc_bug.tests | |||
@@ -0,0 +1,38 @@ | |||
1 | # This test can fail with libc with buggy getopt() implementation. | ||
2 | # If getopt() wants to parse multi-option args (-abc), | ||
3 | # it needs to remember a position within current arg. | ||
4 | # | ||
5 | # If this position is kept as a POINTER, not an offset, | ||
6 | # and if argv[] ADDRESSES (not contents!) change, it blows up. | ||
7 | |||
8 | echo "*** optstring:'ac' args:-a -b -c -d e" | ||
9 | getopts "ac" var -a -b -c -d e; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
10 | getopts "ac" var -a -b -c -d e; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
11 | getopts "ac" var -a -b -c -d e; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
12 | getopts "ac" var -a -b -c -d e; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
13 | getopts "ac" var -a -b -c -d e; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
14 | |||
15 | # Above: args are (usually) in the same locations in memory. | ||
16 | # Below: variable allocations change the location. | ||
17 | |||
18 | echo | ||
19 | echo "*** optstring:'ac' args:-a -b -c -d e" | ||
20 | unset OPTIND | ||
21 | OPTARG=QWERTY; getopts "ac" var -a -b -c -d e; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
22 | NEWVAR=NEWVAL; getopts "ac" var -a -b -c -d e; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
23 | VAR111=NEWVAL; getopts "ac" var -a -b -c -d e; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
24 | VAR222=NEWVAL; getopts "ac" var -a -b -c -d e; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
25 | VAR333=NEWVAL; getopts "ac" var -a -b -c -d e; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
26 | |||
27 | # Slightly different attempts to force reallocations | ||
28 | |||
29 | echo | ||
30 | echo "*** optstring:'ac' args:-a -b -c -d e" | ||
31 | unset OPTIND | ||
32 | export OPTARG; getopts "ac" var -a -b -c -d e; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
33 | export NEWVAR; getopts "ac" var -a -b -c -d e; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
34 | export VAR111; getopts "ac" var -a -b -c -d e; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
35 | export VAR222; getopts "ac" var -a -b -c -d e; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
36 | export VAR333; getopts "ac" var -a -b -c -d e; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
37 | |||
38 | # All copies of code above should generate identical output | ||
diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.right b/shell/ash_test/ash-parsing/groups_and_keywords2.right new file mode 100644 index 000000000..3fcbeb662 --- /dev/null +++ b/shell/ash_test/ash-parsing/groups_and_keywords2.right | |||
@@ -0,0 +1,3 @@ | |||
1 | ./groups_and_keywords2.tests: eval: line 1: syntax error: unexpected ")" | ||
2 | Fail:2 | ||
3 | ./groups_and_keywords2.tests: line 8: syntax error: unexpected ")" | ||
diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.tests b/shell/ash_test/ash-parsing/groups_and_keywords2.tests new file mode 100755 index 000000000..ab33b909f --- /dev/null +++ b/shell/ash_test/ash-parsing/groups_and_keywords2.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | # This is an error | ||
2 | (eval 'if() { echo; }') | ||
3 | echo Fail:$? | ||
4 | # ^^^^^^ bash prints 1, but interactively it sets $? = 2 | ||
5 | # we print 2 | ||
6 | |||
7 | # This is an error, and it aborts in script | ||
8 | if() { echo; } | ||
9 | echo Not reached | ||
diff --git a/shell/ash_test/ash-vars/param_expand_assign.right b/shell/ash_test/ash-vars/param_expand_assign.right index 9b07d8cd4..6e9ea1379 100644 --- a/shell/ash_test/ash-vars/param_expand_assign.right +++ b/shell/ash_test/ash-vars/param_expand_assign.right | |||
@@ -1,6 +1,6 @@ | |||
1 | SHELL: line 1: syntax error: bad substitution | 1 | SHELL: line 1: syntax error: bad substitution |
2 | SHELL: line 1: syntax error: bad substitution | 2 | SHELL: line 1: syntax error: bad substitution |
3 | 0 | 3 | SHELL: line 1: syntax error: bad substitution |
4 | 0 | 4 | 0 |
5 | SHELL: line 1: 1: bad variable name | 5 | SHELL: line 1: 1: bad variable name |
6 | SHELL: line 1: 1: bad variable name | 6 | SHELL: line 1: 1: bad variable name |
diff --git a/shell/ash_test/printenv.c b/shell/ash_test/printenv.c index c0c5e197c..c86308d3b 100644 --- a/shell/ash_test/printenv.c +++ b/shell/ash_test/printenv.c | |||
@@ -56,7 +56,7 @@ main (argc, argv) | |||
56 | if (**argv == **envp && strncmp (*envp, *argv, len) == 0) | 56 | if (**argv == **envp && strncmp (*envp, *argv, len) == 0) |
57 | { | 57 | { |
58 | eval = *envp + len; | 58 | eval = *envp + len; |
59 | /* If the environment variable doesn't have an `=', ignore it. */ | 59 | /* If the environment variable doesn't have an '=', ignore it. */ |
60 | if (*eval == '=') | 60 | if (*eval == '=') |
61 | { | 61 | { |
62 | puts (eval + 1); | 62 | puts (eval + 1); |
diff --git a/shell/cttyhack.c b/shell/cttyhack.c index 9004b4763..849fe9e48 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c | |||
@@ -6,7 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | #include "libbb.h" | 7 | #include "libbb.h" |
8 | 8 | ||
9 | //applet:IF_CTTYHACK(APPLET(cttyhack, BB_DIR_BIN, BB_SUID_DROP)) | 9 | //applet:IF_CTTYHACK(APPLET_NOEXEC(cttyhack, cttyhack, BB_DIR_BIN, BB_SUID_DROP, cttyhack)) |
10 | 10 | ||
11 | //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o | 11 | //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o |
12 | 12 | ||
diff --git a/shell/hush.c b/shell/hush.c index 9f946d82f..cdc3a8618 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -48,7 +48,7 @@ | |||
48 | * tilde expansion | 48 | * tilde expansion |
49 | * aliases | 49 | * aliases |
50 | * builtins mandated by standards we don't support: | 50 | * builtins mandated by standards we don't support: |
51 | * [un]alias, command, fc, getopts, times: | 51 | * [un]alias, command, fc: |
52 | * command -v CMD: print "/path/to/CMD" | 52 | * command -v CMD: print "/path/to/CMD" |
53 | * prints "CMD" for builtins | 53 | * prints "CMD" for builtins |
54 | * prints "alias ALIAS='EXPANSION'" for aliases | 54 | * prints "alias ALIAS='EXPANSION'" for aliases |
@@ -58,8 +58,6 @@ | |||
58 | * (can use this to override standalone shell as well) | 58 | * (can use this to override standalone shell as well) |
59 | * -p: use default $PATH | 59 | * -p: use default $PATH |
60 | * command BLTIN: disables special-ness (e.g. errors do not abort) | 60 | * command BLTIN: disables special-ness (e.g. errors do not abort) |
61 | * getopts: getopt() for shells | ||
62 | * times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime | ||
63 | * fc -l[nr] [BEG] [END]: list range of commands in history | 61 | * fc -l[nr] [BEG] [END]: list range of commands in history |
64 | * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands | 62 | * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands |
65 | * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP | 63 | * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP |
@@ -265,6 +263,11 @@ | |||
265 | //config: default y | 263 | //config: default y |
266 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH | 264 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH |
267 | //config: | 265 | //config: |
266 | //config:config HUSH_TIMES | ||
267 | //config: bool "times builtin" | ||
268 | //config: default y | ||
269 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH | ||
270 | //config: | ||
268 | //config:config HUSH_READ | 271 | //config:config HUSH_READ |
269 | //config: bool "read builtin" | 272 | //config: bool "read builtin" |
270 | //config: default y | 273 | //config: default y |
@@ -290,6 +293,11 @@ | |||
290 | //config: default y | 293 | //config: default y |
291 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH | 294 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH |
292 | //config: | 295 | //config: |
296 | //config:config HUSH_GETOPTS | ||
297 | //config: bool "getopts builtin" | ||
298 | //config: default y | ||
299 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH | ||
300 | //config: | ||
293 | //config:config HUSH_MEMLEAK | 301 | //config:config HUSH_MEMLEAK |
294 | //config: bool "memleak builtin (debugging)" | 302 | //config: bool "memleak builtin (debugging)" |
295 | //config: default n | 303 | //config: default n |
@@ -325,6 +333,7 @@ | |||
325 | #if ENABLE_HUSH_CASE | 333 | #if ENABLE_HUSH_CASE |
326 | # include <fnmatch.h> | 334 | # include <fnmatch.h> |
327 | #endif | 335 | #endif |
336 | #include <sys/times.h> | ||
328 | #include <sys/utsname.h> /* for setting $HOSTNAME */ | 337 | #include <sys/utsname.h> /* for setting $HOSTNAME */ |
329 | 338 | ||
330 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ | 339 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ |
@@ -352,6 +361,7 @@ | |||
352 | #define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT | 361 | #define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT |
353 | #define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT | 362 | #define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT |
354 | #define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) | 363 | #define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) |
364 | #define BASH_READ_D ENABLE_HUSH_BASH_COMPAT | ||
355 | 365 | ||
356 | 366 | ||
357 | /* Build knobs */ | 367 | /* Build knobs */ |
@@ -977,6 +987,9 @@ static int builtin_readonly(char **argv) FAST_FUNC; | |||
977 | static int builtin_fg_bg(char **argv) FAST_FUNC; | 987 | static int builtin_fg_bg(char **argv) FAST_FUNC; |
978 | static int builtin_jobs(char **argv) FAST_FUNC; | 988 | static int builtin_jobs(char **argv) FAST_FUNC; |
979 | #endif | 989 | #endif |
990 | #if ENABLE_HUSH_GETOPTS | ||
991 | static int builtin_getopts(char **argv) FAST_FUNC; | ||
992 | #endif | ||
980 | #if ENABLE_HUSH_HELP | 993 | #if ENABLE_HUSH_HELP |
981 | static int builtin_help(char **argv) FAST_FUNC; | 994 | static int builtin_help(char **argv) FAST_FUNC; |
982 | #endif | 995 | #endif |
@@ -1010,6 +1023,9 @@ static int builtin_trap(char **argv) FAST_FUNC; | |||
1010 | #if ENABLE_HUSH_TYPE | 1023 | #if ENABLE_HUSH_TYPE |
1011 | static int builtin_type(char **argv) FAST_FUNC; | 1024 | static int builtin_type(char **argv) FAST_FUNC; |
1012 | #endif | 1025 | #endif |
1026 | #if ENABLE_HUSH_TIMES | ||
1027 | static int builtin_times(char **argv) FAST_FUNC; | ||
1028 | #endif | ||
1013 | static int builtin_true(char **argv) FAST_FUNC; | 1029 | static int builtin_true(char **argv) FAST_FUNC; |
1014 | #if ENABLE_HUSH_UMASK | 1030 | #if ENABLE_HUSH_UMASK |
1015 | static int builtin_umask(char **argv) FAST_FUNC; | 1031 | static int builtin_umask(char **argv) FAST_FUNC; |
@@ -1070,6 +1086,9 @@ static const struct built_in_command bltins1[] = { | |||
1070 | #if ENABLE_HUSH_JOB | 1086 | #if ENABLE_HUSH_JOB |
1071 | BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"), | 1087 | BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"), |
1072 | #endif | 1088 | #endif |
1089 | #if ENABLE_HUSH_GETOPTS | ||
1090 | BLTIN("getopts" , builtin_getopts , NULL), | ||
1091 | #endif | ||
1073 | #if ENABLE_HUSH_HELP | 1092 | #if ENABLE_HUSH_HELP |
1074 | BLTIN("help" , builtin_help , NULL), | 1093 | BLTIN("help" , builtin_help , NULL), |
1075 | #endif | 1094 | #endif |
@@ -1104,6 +1123,9 @@ static const struct built_in_command bltins1[] = { | |||
1104 | #if BASH_SOURCE | 1123 | #if BASH_SOURCE |
1105 | BLTIN("source" , builtin_source , NULL), | 1124 | BLTIN("source" , builtin_source , NULL), |
1106 | #endif | 1125 | #endif |
1126 | #if ENABLE_HUSH_TIMES | ||
1127 | BLTIN("times" , builtin_times , NULL), | ||
1128 | #endif | ||
1107 | #if ENABLE_HUSH_TRAP | 1129 | #if ENABLE_HUSH_TRAP |
1108 | BLTIN("trap" , builtin_trap , "Trap signals"), | 1130 | BLTIN("trap" , builtin_trap , "Trap signals"), |
1109 | #endif | 1131 | #endif |
@@ -1272,7 +1294,7 @@ static void xxfree(void *ptr) | |||
1272 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. | 1294 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. |
1273 | */ | 1295 | */ |
1274 | #if HUSH_DEBUG < 2 | 1296 | #if HUSH_DEBUG < 2 |
1275 | # define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) | 1297 | # define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__) |
1276 | # define syntax_error(lineno, msg) syntax_error(msg) | 1298 | # define syntax_error(lineno, msg) syntax_error(msg) |
1277 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) | 1299 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) |
1278 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) | 1300 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) |
@@ -1280,7 +1302,16 @@ static void xxfree(void *ptr) | |||
1280 | # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) | 1302 | # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) |
1281 | #endif | 1303 | #endif |
1282 | 1304 | ||
1283 | static void die_if_script(unsigned lineno, const char *fmt, ...) | 1305 | static void die_if_script(void) |
1306 | { | ||
1307 | if (!G_interactive_fd) { | ||
1308 | if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */ | ||
1309 | xfunc_error_retval = G.last_exitcode; | ||
1310 | xfunc_die(); | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...) | ||
1284 | { | 1315 | { |
1285 | va_list p; | 1316 | va_list p; |
1286 | 1317 | ||
@@ -1290,8 +1321,7 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) | |||
1290 | va_start(p, fmt); | 1321 | va_start(p, fmt); |
1291 | bb_verror_msg(fmt, p, NULL); | 1322 | bb_verror_msg(fmt, p, NULL); |
1292 | va_end(p); | 1323 | va_end(p); |
1293 | if (!G_interactive_fd) | 1324 | die_if_script(); |
1294 | xfunc_die(); | ||
1295 | } | 1325 | } |
1296 | 1326 | ||
1297 | static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) | 1327 | static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) |
@@ -1300,16 +1330,20 @@ static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) | |||
1300 | bb_error_msg("syntax error: %s", msg); | 1330 | bb_error_msg("syntax error: %s", msg); |
1301 | else | 1331 | else |
1302 | bb_error_msg("syntax error"); | 1332 | bb_error_msg("syntax error"); |
1333 | die_if_script(); | ||
1303 | } | 1334 | } |
1304 | 1335 | ||
1305 | static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) | 1336 | static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) |
1306 | { | 1337 | { |
1307 | bb_error_msg("syntax error at '%s'", msg); | 1338 | bb_error_msg("syntax error at '%s'", msg); |
1339 | die_if_script(); | ||
1308 | } | 1340 | } |
1309 | 1341 | ||
1310 | static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) | 1342 | static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) |
1311 | { | 1343 | { |
1312 | bb_error_msg("syntax error: unterminated %s", s); | 1344 | bb_error_msg("syntax error: unterminated %s", s); |
1345 | //? source4.tests fails: in bash, echo ${^} in script does not terminate the script | ||
1346 | // die_if_script(); | ||
1313 | } | 1347 | } |
1314 | 1348 | ||
1315 | static void syntax_error_unterm_ch(unsigned lineno, char ch) | 1349 | static void syntax_error_unterm_ch(unsigned lineno, char ch) |
@@ -1327,17 +1361,18 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) | |||
1327 | bb_error_msg("hush.c:%u", lineno); | 1361 | bb_error_msg("hush.c:%u", lineno); |
1328 | #endif | 1362 | #endif |
1329 | bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); | 1363 | bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); |
1364 | die_if_script(); | ||
1330 | } | 1365 | } |
1331 | 1366 | ||
1332 | #if HUSH_DEBUG < 2 | 1367 | #if HUSH_DEBUG < 2 |
1333 | # undef die_if_script | 1368 | # undef msg_and_die_if_script |
1334 | # undef syntax_error | 1369 | # undef syntax_error |
1335 | # undef syntax_error_at | 1370 | # undef syntax_error_at |
1336 | # undef syntax_error_unterm_ch | 1371 | # undef syntax_error_unterm_ch |
1337 | # undef syntax_error_unterm_str | 1372 | # undef syntax_error_unterm_str |
1338 | # undef syntax_error_unexpected_ch | 1373 | # undef syntax_error_unexpected_ch |
1339 | #else | 1374 | #else |
1340 | # define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) | 1375 | # define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__) |
1341 | # define syntax_error(msg) syntax_error(__LINE__, msg) | 1376 | # define syntax_error(msg) syntax_error(__LINE__, msg) |
1342 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) | 1377 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) |
1343 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) | 1378 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) |
@@ -1800,7 +1835,7 @@ static void restore_ttypgrp_and__exit(void) | |||
1800 | * echo END_OF_SCRIPT | 1835 | * echo END_OF_SCRIPT |
1801 | * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". | 1836 | * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". |
1802 | * This makes "echo END_OF_SCRIPT" executed twice. | 1837 | * This makes "echo END_OF_SCRIPT" executed twice. |
1803 | * Similar problems can be seen with die_if_script() -> xfunc_die() | 1838 | * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die() |
1804 | * and in `cmd` handling. | 1839 | * and in `cmd` handling. |
1805 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): | 1840 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): |
1806 | */ | 1841 | */ |
@@ -1966,6 +2001,9 @@ static int check_and_run_traps(void) | |||
1966 | break; | 2001 | break; |
1967 | #if ENABLE_HUSH_JOB | 2002 | #if ENABLE_HUSH_JOB |
1968 | case SIGHUP: { | 2003 | case SIGHUP: { |
2004 | //TODO: why are we doing this? ash and dash don't do this, | ||
2005 | //they have no handler for SIGHUP at all, | ||
2006 | //they rely on kernel to send SIGHUP+SIGCONT to orphaned process groups | ||
1969 | struct pipe *job; | 2007 | struct pipe *job; |
1970 | debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig); | 2008 | debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig); |
1971 | /* bash is observed to signal whole process groups, | 2009 | /* bash is observed to signal whole process groups, |
@@ -2411,18 +2449,17 @@ static int get_user_input(struct in_str *i) | |||
2411 | /* buglet: SIGINT will not make new prompt to appear _at once_, | 2449 | /* buglet: SIGINT will not make new prompt to appear _at once_, |
2412 | * only after <Enter>. (^C works immediately) */ | 2450 | * only after <Enter>. (^C works immediately) */ |
2413 | r = read_line_input(G.line_input_state, prompt_str, | 2451 | r = read_line_input(G.line_input_state, prompt_str, |
2414 | G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, | 2452 | G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 |
2415 | /*timeout*/ -1 | ||
2416 | ); | 2453 | ); |
2417 | /* read_line_input intercepts ^C, "convert" it to SIGINT */ | 2454 | /* read_line_input intercepts ^C, "convert" it to SIGINT */ |
2418 | if (r == 0) { | 2455 | if (r == 0) |
2419 | write(STDOUT_FILENO, "^C", 2); | ||
2420 | raise(SIGINT); | 2456 | raise(SIGINT); |
2421 | } | ||
2422 | check_and_run_traps(); | 2457 | check_and_run_traps(); |
2423 | if (r != 0 && !G.flag_SIGINT) | 2458 | if (r != 0 && !G.flag_SIGINT) |
2424 | break; | 2459 | break; |
2425 | /* ^C or SIGINT: repeat */ | 2460 | /* ^C or SIGINT: repeat */ |
2461 | /* bash prints ^C even on real SIGINT (non-kbd generated) */ | ||
2462 | write(STDOUT_FILENO, "^C", 2); | ||
2426 | G.last_exitcode = 128 + SIGINT; | 2463 | G.last_exitcode = 128 + SIGINT; |
2427 | } | 2464 | } |
2428 | if (r < 0) { | 2465 | if (r < 0) { |
@@ -3384,7 +3421,7 @@ static int done_command(struct parse_context *ctx) | |||
3384 | #if 0 /* Instead we emit error message at run time */ | 3421 | #if 0 /* Instead we emit error message at run time */ |
3385 | if (ctx->pending_redirect) { | 3422 | if (ctx->pending_redirect) { |
3386 | /* For example, "cmd >" (no filename to redirect to) */ | 3423 | /* For example, "cmd >" (no filename to redirect to) */ |
3387 | die_if_script("syntax error: %s", "invalid redirect"); | 3424 | syntax_error("invalid redirect"); |
3388 | ctx->pending_redirect = NULL; | 3425 | ctx->pending_redirect = NULL; |
3389 | } | 3426 | } |
3390 | #endif | 3427 | #endif |
@@ -3950,7 +3987,7 @@ static int parse_redirect(struct parse_context *ctx, | |||
3950 | #if 0 /* Instead we emit error message at run time */ | 3987 | #if 0 /* Instead we emit error message at run time */ |
3951 | if (ctx->pending_redirect) { | 3988 | if (ctx->pending_redirect) { |
3952 | /* For example, "cmd > <file" */ | 3989 | /* For example, "cmd > <file" */ |
3953 | die_if_script("syntax error: %s", "invalid redirect"); | 3990 | syntax_error("invalid redirect"); |
3954 | } | 3991 | } |
3955 | #endif | 3992 | #endif |
3956 | /* Set ctx->pending_redirect, so we know what to do at the | 3993 | /* Set ctx->pending_redirect, so we know what to do at the |
@@ -5022,10 +5059,16 @@ static struct pipe *parse_stream(char **pstring, | |||
5022 | else | 5059 | else |
5023 | o_free_unsafe(&ctx.as_string); | 5060 | o_free_unsafe(&ctx.as_string); |
5024 | #endif | 5061 | #endif |
5025 | debug_leave(); | 5062 | if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) { |
5063 | /* Example: bare "{ }", "()" */ | ||
5064 | G.last_exitcode = 2; /* bash compat */ | ||
5065 | syntax_error_unexpected_ch(ch); | ||
5066 | goto parse_error2; | ||
5067 | } | ||
5026 | debug_printf_parse("parse_stream return %p: " | 5068 | debug_printf_parse("parse_stream return %p: " |
5027 | "end_trigger char found\n", | 5069 | "end_trigger char found\n", |
5028 | ctx.list_head); | 5070 | ctx.list_head); |
5071 | debug_leave(); | ||
5029 | return ctx.list_head; | 5072 | return ctx.list_head; |
5030 | } | 5073 | } |
5031 | } | 5074 | } |
@@ -5283,8 +5326,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5283 | /* proper use of this character is caught by end_trigger: | 5326 | /* proper use of this character is caught by end_trigger: |
5284 | * if we see {, we call parse_group(..., end_trigger='}') | 5327 | * if we see {, we call parse_group(..., end_trigger='}') |
5285 | * and it will match } earlier (not here). */ | 5328 | * and it will match } earlier (not here). */ |
5286 | syntax_error_unexpected_ch(ch); | ||
5287 | G.last_exitcode = 2; | 5329 | G.last_exitcode = 2; |
5330 | syntax_error_unexpected_ch(ch); | ||
5288 | goto parse_error2; | 5331 | goto parse_error2; |
5289 | default: | 5332 | default: |
5290 | if (HUSH_DEBUG) | 5333 | if (HUSH_DEBUG) |
@@ -5514,7 +5557,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) | |||
5514 | if (errmsg_p) | 5557 | if (errmsg_p) |
5515 | *errmsg_p = math_state.errmsg; | 5558 | *errmsg_p = math_state.errmsg; |
5516 | if (math_state.errmsg) | 5559 | if (math_state.errmsg) |
5517 | die_if_script(math_state.errmsg); | 5560 | msg_and_die_if_script(math_state.errmsg); |
5518 | return res; | 5561 | return res; |
5519 | } | 5562 | } |
5520 | #endif | 5563 | #endif |
@@ -5781,7 +5824,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5781 | /* in bash, len=-n means strlen()-n */ | 5824 | /* in bash, len=-n means strlen()-n */ |
5782 | len = (arith_t)strlen(val) - beg + len; | 5825 | len = (arith_t)strlen(val) - beg + len; |
5783 | if (len < 0) /* bash compat */ | 5826 | if (len < 0) /* bash compat */ |
5784 | die_if_script("%s: substring expression < 0", var); | 5827 | msg_and_die_if_script("%s: substring expression < 0", var); |
5785 | } | 5828 | } |
5786 | if (len <= 0 || !val || beg >= strlen(val)) { | 5829 | if (len <= 0 || !val || beg >= strlen(val)) { |
5787 | arith_err: | 5830 | arith_err: |
@@ -5795,7 +5838,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5795 | } | 5838 | } |
5796 | debug_printf_varexp("val:'%s'\n", val); | 5839 | debug_printf_varexp("val:'%s'\n", val); |
5797 | #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ | 5840 | #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ |
5798 | die_if_script("malformed ${%s:...}", var); | 5841 | msg_and_die_if_script("malformed ${%s:...}", var); |
5799 | val = NULL; | 5842 | val = NULL; |
5800 | #endif | 5843 | #endif |
5801 | } else { /* one of "-=+?" */ | 5844 | } else { /* one of "-=+?" */ |
@@ -5832,7 +5875,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5832 | exp_word = to_be_freed; | 5875 | exp_word = to_be_freed; |
5833 | if (exp_op == '?') { | 5876 | if (exp_op == '?') { |
5834 | /* mimic bash message */ | 5877 | /* mimic bash message */ |
5835 | die_if_script("%s: %s", | 5878 | msg_and_die_if_script("%s: %s", |
5836 | var, | 5879 | var, |
5837 | exp_word[0] | 5880 | exp_word[0] |
5838 | ? exp_word | 5881 | ? exp_word |
@@ -5849,7 +5892,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5849 | /* ${var=[word]} or ${var:=[word]} */ | 5892 | /* ${var=[word]} or ${var:=[word]} */ |
5850 | if (isdigit(var[0]) || var[0] == '#') { | 5893 | if (isdigit(var[0]) || var[0] == '#') { |
5851 | /* mimic bash message */ | 5894 | /* mimic bash message */ |
5852 | die_if_script("$%s: cannot assign in this way", var); | 5895 | msg_and_die_if_script("$%s: cannot assign in this way", var); |
5853 | val = NULL; | 5896 | val = NULL; |
5854 | } else { | 5897 | } else { |
5855 | char *new_var = xasprintf("%s=%s", var, val); | 5898 | char *new_var = xasprintf("%s=%s", var, val); |
@@ -6698,7 +6741,8 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | |||
6698 | int moved_to; | 6741 | int moved_to; |
6699 | int i; | 6742 | int i; |
6700 | 6743 | ||
6701 | if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { | 6744 | i = 0; |
6745 | if (sq) for (; sq[i].orig_fd >= 0; i++) { | ||
6702 | /* If we collide with an already moved fd... */ | 6746 | /* If we collide with an already moved fd... */ |
6703 | if (fd == sq[i].moved_to) { | 6747 | if (fd == sq[i].moved_to) { |
6704 | sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); | 6748 | sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); |
@@ -6726,7 +6770,8 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd) | |||
6726 | { | 6770 | { |
6727 | int i; | 6771 | int i; |
6728 | 6772 | ||
6729 | if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { | 6773 | i = 0; |
6774 | if (sq) for (; sq[i].orig_fd >= 0; i++) { | ||
6730 | /* If we collide with an already moved fd... */ | 6775 | /* If we collide with an already moved fd... */ |
6731 | if (fd == sq[i].orig_fd) { | 6776 | if (fd == sq[i].orig_fd) { |
6732 | /* Examples: | 6777 | /* Examples: |
@@ -6863,7 +6908,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) | |||
6863 | * "cmd >" (no filename) | 6908 | * "cmd >" (no filename) |
6864 | * "cmd > <file" (2nd redirect starts too early) | 6909 | * "cmd > <file" (2nd redirect starts too early) |
6865 | */ | 6910 | */ |
6866 | die_if_script("syntax error: %s", "invalid redirect"); | 6911 | syntax_error("invalid redirect"); |
6867 | continue; | 6912 | continue; |
6868 | } | 6913 | } |
6869 | mode = redir_table[redir->rd_type].mode; | 6914 | mode = redir_table[redir->rd_type].mode; |
@@ -7363,8 +7408,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
7363 | */ | 7408 | */ |
7364 | close_saved_fds_and_FILE_fds(); | 7409 | close_saved_fds_and_FILE_fds(); |
7365 | //FIXME: should also close saved redir fds | 7410 | //FIXME: should also close saved redir fds |
7411 | /* Without this, "rm -i FILE" can't be ^C'ed: */ | ||
7412 | switch_off_special_sigs(G.special_sig_mask); | ||
7366 | debug_printf_exec("running applet '%s'\n", argv[0]); | 7413 | debug_printf_exec("running applet '%s'\n", argv[0]); |
7367 | run_applet_no_and_exit(a, argv[0], argv); | 7414 | run_noexec_applet_and_exit(a, argv[0], argv); |
7368 | } | 7415 | } |
7369 | # endif | 7416 | # endif |
7370 | /* Re-exec ourselves */ | 7417 | /* Re-exec ourselves */ |
@@ -8045,6 +8092,24 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
8045 | add_vars(old_vars); | 8092 | add_vars(old_vars); |
8046 | /* clean_up_and_ret0: */ | 8093 | /* clean_up_and_ret0: */ |
8047 | restore_redirects(squirrel); | 8094 | restore_redirects(squirrel); |
8095 | /* | ||
8096 | * Try "usleep 99999999" + ^C + "echo $?" | ||
8097 | * with FEATURE_SH_NOFORK=y. | ||
8098 | */ | ||
8099 | if (!funcp) { | ||
8100 | /* It was builtin or nofork. | ||
8101 | * if this would be a real fork/execed program, | ||
8102 | * it should have died if a fatal sig was received. | ||
8103 | * But OTOH, there was no separate process, | ||
8104 | * the sig was sent to _shell_, not to non-existing | ||
8105 | * child. | ||
8106 | * Let's just handle ^C only, this one is obvious: | ||
8107 | * we aren't ok with exitcode 0 when ^C was pressed | ||
8108 | * during builtin/nofork. | ||
8109 | */ | ||
8110 | if (sigismember(&G.pending_set, SIGINT)) | ||
8111 | rcode = 128 + SIGINT; | ||
8112 | } | ||
8048 | clean_up_and_ret1: | 8113 | clean_up_and_ret1: |
8049 | free(argv_expanded); | 8114 | free(argv_expanded); |
8050 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 8115 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
@@ -8060,6 +8125,14 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
8060 | if (rcode == 0) { | 8125 | if (rcode == 0) { |
8061 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", | 8126 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", |
8062 | argv_expanded[0], argv_expanded[1]); | 8127 | argv_expanded[0], argv_expanded[1]); |
8128 | /* | ||
8129 | * Note: signals (^C) can't interrupt here. | ||
8130 | * We remember them and they will be acted upon | ||
8131 | * after applet returns. | ||
8132 | * This makes applets which can run for a long time | ||
8133 | * and/or wait for user input ineligible for NOFORK: | ||
8134 | * for example, "yes" or "rm" (rm -i waits for input). | ||
8135 | */ | ||
8063 | rcode = run_nofork_applet(n, argv_expanded); | 8136 | rcode = run_nofork_applet(n, argv_expanded); |
8064 | } | 8137 | } |
8065 | goto clean_up_and_ret; | 8138 | goto clean_up_and_ret; |
@@ -8491,7 +8564,7 @@ static int run_list(struct pipe *pi) | |||
8491 | G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; | 8564 | G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; |
8492 | G.last_bg_pid_exitcode = 0; | 8565 | G.last_bg_pid_exitcode = 0; |
8493 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); | 8566 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); |
8494 | /* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */ | 8567 | /* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash say 0 */ |
8495 | rcode = EXIT_SUCCESS; | 8568 | rcode = EXIT_SUCCESS; |
8496 | goto check_traps; | 8569 | goto check_traps; |
8497 | } else { | 8570 | } else { |
@@ -8600,6 +8673,10 @@ static void install_sighandlers(unsigned mask) | |||
8600 | */ | 8673 | */ |
8601 | if (sig == SIGCHLD) | 8674 | if (sig == SIGCHLD) |
8602 | continue; | 8675 | continue; |
8676 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. | ||
8677 | * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" | ||
8678 | */ | ||
8679 | //if (sig == SIGHUP) continue; - TODO? | ||
8603 | if (old_handler == SIG_IGN) { | 8680 | if (old_handler == SIG_IGN) { |
8604 | /* oops... restore back to IGN, and record this fact */ | 8681 | /* oops... restore back to IGN, and record this fact */ |
8605 | install_sighandler(sig, old_handler); | 8682 | install_sighandler(sig, old_handler); |
@@ -9381,13 +9458,20 @@ static int FAST_FUNC builtin_read(char **argv) | |||
9381 | char *opt_p = NULL; | 9458 | char *opt_p = NULL; |
9382 | char *opt_t = NULL; | 9459 | char *opt_t = NULL; |
9383 | char *opt_u = NULL; | 9460 | char *opt_u = NULL; |
9461 | char *opt_d = NULL; /* optimized out if !BASH */ | ||
9384 | const char *ifs; | 9462 | const char *ifs; |
9385 | int read_flags; | 9463 | int read_flags; |
9386 | 9464 | ||
9387 | /* "!": do not abort on errors. | 9465 | /* "!": do not abort on errors. |
9388 | * Option string must start with "sr" to match BUILTIN_READ_xxx | 9466 | * Option string must start with "sr" to match BUILTIN_READ_xxx |
9389 | */ | 9467 | */ |
9390 | read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); | 9468 | read_flags = getopt32(argv, |
9469 | #if BASH_READ_D | ||
9470 | "!srn:p:t:u:d:", &opt_n, &opt_p, &opt_t, &opt_u, &opt_d | ||
9471 | #else | ||
9472 | "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u | ||
9473 | #endif | ||
9474 | ); | ||
9391 | if (read_flags == (uint32_t)-1) | 9475 | if (read_flags == (uint32_t)-1) |
9392 | return EXIT_FAILURE; | 9476 | return EXIT_FAILURE; |
9393 | argv += optind; | 9477 | argv += optind; |
@@ -9401,7 +9485,8 @@ static int FAST_FUNC builtin_read(char **argv) | |||
9401 | opt_n, | 9485 | opt_n, |
9402 | opt_p, | 9486 | opt_p, |
9403 | opt_t, | 9487 | opt_t, |
9404 | opt_u | 9488 | opt_u, |
9489 | opt_d | ||
9405 | ); | 9490 | ); |
9406 | 9491 | ||
9407 | if ((uintptr_t)r == 1 && errno == EINTR) { | 9492 | if ((uintptr_t)r == 1 && errno == EINTR) { |
@@ -9786,6 +9871,93 @@ static int FAST_FUNC builtin_shift(char **argv) | |||
9786 | return EXIT_FAILURE; | 9871 | return EXIT_FAILURE; |
9787 | } | 9872 | } |
9788 | 9873 | ||
9874 | #if ENABLE_HUSH_GETOPTS | ||
9875 | static int FAST_FUNC builtin_getopts(char **argv) | ||
9876 | { | ||
9877 | /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html | ||
9878 | |||
9879 | TODO: | ||
9880 | If a required argument is not found, and getopts is not silent, | ||
9881 | a question mark (?) is placed in VAR, OPTARG is unset, and a | ||
9882 | diagnostic message is printed. If getopts is silent, then a | ||
9883 | colon (:) is placed in VAR and OPTARG is set to the option | ||
9884 | character found. | ||
9885 | |||
9886 | Test that VAR is a valid variable name? | ||
9887 | |||
9888 | "Whenever the shell is invoked, OPTIND shall be initialized to 1" | ||
9889 | */ | ||
9890 | char cbuf[2]; | ||
9891 | const char *cp, *optstring, *var; | ||
9892 | int c, exitcode; | ||
9893 | |||
9894 | optstring = *++argv; | ||
9895 | if (!optstring || !(var = *++argv)) { | ||
9896 | bb_error_msg("usage: getopts OPTSTRING VAR [ARGS]"); | ||
9897 | return EXIT_FAILURE; | ||
9898 | } | ||
9899 | |||
9900 | c = 0; | ||
9901 | if (optstring[0] != ':') { | ||
9902 | cp = get_local_var_value("OPTERR"); | ||
9903 | /* 0 if "OPTERR=0", 1 otherwise */ | ||
9904 | c = (!cp || NOT_LONE_CHAR(cp, '0')); | ||
9905 | } | ||
9906 | opterr = c; | ||
9907 | cp = get_local_var_value("OPTIND"); | ||
9908 | optind = cp ? atoi(cp) : 0; | ||
9909 | optarg = NULL; | ||
9910 | cbuf[1] = '\0'; | ||
9911 | |||
9912 | /* getopts stops on first non-option. Add "+" to force that */ | ||
9913 | /*if (optstring[0] != '+')*/ { | ||
9914 | char *s = alloca(strlen(optstring) + 2); | ||
9915 | sprintf(s, "+%s", optstring); | ||
9916 | optstring = s; | ||
9917 | } | ||
9918 | |||
9919 | if (argv[1]) | ||
9920 | argv[0] = G.global_argv[0]; /* for error messages */ | ||
9921 | else | ||
9922 | argv = G.global_argv; | ||
9923 | c = getopt(string_array_len(argv), argv, optstring); | ||
9924 | |||
9925 | /* Set OPTARG */ | ||
9926 | /* Always set or unset, never left as-is, even on exit/error: | ||
9927 | * "If no option was found, or if the option that was found | ||
9928 | * does not have an option-argument, OPTARG shall be unset." | ||
9929 | */ | ||
9930 | cp = optarg; | ||
9931 | if (c == '?') { | ||
9932 | /* If ":optstring" and unknown option is seen, | ||
9933 | * it is stored to OPTARG. | ||
9934 | */ | ||
9935 | if (optstring[1] == ':') { | ||
9936 | cbuf[0] = optopt; | ||
9937 | cp = cbuf; | ||
9938 | } | ||
9939 | } | ||
9940 | if (cp) | ||
9941 | set_local_var_from_halves("OPTARG", cp); | ||
9942 | else | ||
9943 | unset_local_var("OPTARG"); | ||
9944 | |||
9945 | /* Convert -1 to "?" */ | ||
9946 | exitcode = EXIT_SUCCESS; | ||
9947 | if (c < 0) { /* -1: end of options */ | ||
9948 | exitcode = EXIT_FAILURE; | ||
9949 | c = '?'; | ||
9950 | } | ||
9951 | |||
9952 | /* Set VAR and OPTIND */ | ||
9953 | cbuf[0] = c; | ||
9954 | set_local_var_from_halves(var, cbuf); | ||
9955 | set_local_var_from_halves("OPTIND", utoa(optind)); | ||
9956 | |||
9957 | return exitcode; | ||
9958 | } | ||
9959 | #endif | ||
9960 | |||
9789 | static int FAST_FUNC builtin_source(char **argv) | 9961 | static int FAST_FUNC builtin_source(char **argv) |
9790 | { | 9962 | { |
9791 | char *arg_path, *filename; | 9963 | char *arg_path, *filename; |
@@ -10178,6 +10350,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid | |||
10178 | /* So, did we get a signal? */ | 10350 | /* So, did we get a signal? */ |
10179 | sig = check_and_run_traps(); | 10351 | sig = check_and_run_traps(); |
10180 | if (sig /*&& sig != SIGCHLD - always true */) { | 10352 | if (sig /*&& sig != SIGCHLD - always true */) { |
10353 | /* Do this for any (non-ignored) signal, not only for ^C */ | ||
10181 | ret = 128 + sig; | 10354 | ret = 128 + sig; |
10182 | break; | 10355 | break; |
10183 | } | 10356 | } |
@@ -10344,6 +10517,41 @@ static int FAST_FUNC builtin_return(char **argv) | |||
10344 | } | 10517 | } |
10345 | #endif | 10518 | #endif |
10346 | 10519 | ||
10520 | #if ENABLE_HUSH_TIMES | ||
10521 | static int FAST_FUNC builtin_times(char **argv UNUSED_PARAM) | ||
10522 | { | ||
10523 | static const uint8_t times_tbl[] ALIGN1 = { | ||
10524 | ' ', offsetof(struct tms, tms_utime), | ||
10525 | '\n', offsetof(struct tms, tms_stime), | ||
10526 | ' ', offsetof(struct tms, tms_cutime), | ||
10527 | '\n', offsetof(struct tms, tms_cstime), | ||
10528 | 0 | ||
10529 | }; | ||
10530 | const uint8_t *p; | ||
10531 | unsigned clk_tck; | ||
10532 | struct tms buf; | ||
10533 | |||
10534 | clk_tck = bb_clk_tck(); | ||
10535 | |||
10536 | times(&buf); | ||
10537 | p = times_tbl; | ||
10538 | do { | ||
10539 | unsigned sec, frac; | ||
10540 | unsigned long t; | ||
10541 | t = *(clock_t *)(((char *) &buf) + p[1]); | ||
10542 | sec = t / clk_tck; | ||
10543 | frac = t % clk_tck; | ||
10544 | printf("%um%u.%03us%c", | ||
10545 | sec / 60, sec % 60, | ||
10546 | (frac * 1000) / clk_tck, | ||
10547 | p[0]); | ||
10548 | p += 2; | ||
10549 | } while (*p); | ||
10550 | |||
10551 | return EXIT_SUCCESS; | ||
10552 | } | ||
10553 | #endif | ||
10554 | |||
10347 | #if ENABLE_HUSH_MEMLEAK | 10555 | #if ENABLE_HUSH_MEMLEAK |
10348 | static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) | 10556 | static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) |
10349 | { | 10557 | { |
diff --git a/shell/hush_test/hush-getopts/getopt_optarg.right b/shell/hush_test/hush-getopts/getopt_optarg.right new file mode 100644 index 000000000..9dbd8460e --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_optarg.right | |||
@@ -0,0 +1,18 @@ | |||
1 | *** no OPTIND, optstring:'w:et' args:-q -w e -r -t -y | ||
2 | ./getopt_optarg.tests: invalid option -- q | ||
3 | var:'?' OPTIND:2 OPTARG:'' | ||
4 | var:'w' OPTIND:4 OPTARG:'e' | ||
5 | ./getopt_optarg.tests: invalid option -- r | ||
6 | var:'?' OPTIND:5 OPTARG:'' | ||
7 | var:'t' OPTIND:6 OPTARG:'' | ||
8 | ./getopt_optarg.tests: invalid option -- y | ||
9 | var:'?' OPTIND:7 OPTARG:'' | ||
10 | exited: var:'?' OPTIND:7 OPTARG:'' | ||
11 | *** OPTIND=0, optstring:'w:et' args:-w 1 -w2 -w -e -e -t -t | ||
12 | var:'w' OPTIND:3 OPTARG:'1' | ||
13 | var:'w' OPTIND:4 OPTARG:'2' | ||
14 | var:'w' OPTIND:6 OPTARG:'-e' | ||
15 | var:'e' OPTIND:7 OPTARG:'' | ||
16 | var:'t' OPTIND:8 OPTARG:'' | ||
17 | var:'t' OPTIND:9 OPTARG:'' | ||
18 | exited: var:'?' OPTIND:9 OPTARG:'' | ||
diff --git a/shell/hush_test/hush-getopts/getopt_optarg.tests b/shell/hush_test/hush-getopts/getopt_optarg.tests new file mode 100755 index 000000000..881cc7884 --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_optarg.tests | |||
@@ -0,0 +1,24 @@ | |||
1 | ( | ||
2 | |||
3 | set -- -q -w e -r -t -y | ||
4 | echo "*** no OPTIND, optstring:'w:et' args:$*" | ||
5 | var=QWERTY | ||
6 | OPTARG=ASDFGH | ||
7 | while getopts "w:et" var; do | ||
8 | echo "var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
9 | OPTARG=ASDFGH | ||
10 | done | ||
11 | echo "exited: var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
12 | |||
13 | set -- -w 1 -w2 -w -e -e -t -t | ||
14 | echo "*** OPTIND=0, optstring:'w:et' args:$*" | ||
15 | OPTIND=0 | ||
16 | while getopts "w:et" var; do | ||
17 | echo "var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
18 | OPTARG=ASDFGH | ||
19 | done | ||
20 | echo "exited: var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
21 | |||
22 | ) 2>&1 \ | ||
23 | | sed -e 's/ unrecognized option: / invalid option -- /' \ | ||
24 | -e 's/ illegal option -- / invalid option -- /' \ | ||
diff --git a/shell/hush_test/hush-getopts/getopt_positional.right b/shell/hush_test/hush-getopts/getopt_positional.right new file mode 100644 index 000000000..f1c942476 --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_positional.right | |||
@@ -0,0 +1,6 @@ | |||
1 | *** no OPTIND, optstring:'we' args:-q -w -e r -t -y | ||
2 | ./getopt_positional.tests: invalid option -- q | ||
3 | var:'?' OPTIND:2 | ||
4 | var:'w' OPTIND:3 | ||
5 | var:'e' OPTIND:4 | ||
6 | exited: var:'?' OPTIND:4 | ||
diff --git a/shell/hush_test/hush-getopts/getopt_positional.tests b/shell/hush_test/hush-getopts/getopt_positional.tests new file mode 100755 index 000000000..20716bb0c --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_positional.tests | |||
@@ -0,0 +1,13 @@ | |||
1 | ( | ||
2 | |||
3 | set -- -q -w -e r -t -y | ||
4 | echo "*** no OPTIND, optstring:'we' args:$*" | ||
5 | var=QWERTY | ||
6 | while getopts "we" var; do | ||
7 | echo "var:'$var' OPTIND:$OPTIND" | ||
8 | done | ||
9 | echo "exited: var:'$var' OPTIND:$OPTIND" | ||
10 | |||
11 | ) 2>&1 \ | ||
12 | | sed -e 's/ unrecognized option: / invalid option -- /' \ | ||
13 | -e 's/ illegal option -- / invalid option -- /' \ | ||
diff --git a/shell/hush_test/hush-getopts/getopt_silent.right b/shell/hush_test/hush-getopts/getopt_silent.right new file mode 100644 index 000000000..03d4eb149 --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_silent.right | |||
@@ -0,0 +1,6 @@ | |||
1 | *** optstring:':ac' args:-a -b -c | ||
2 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
3 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'b' | ||
4 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
5 | 4 rc:1 var:'?' OPTIND:4 OPTARG:'' | ||
6 | 5 rc:1 var:'?' OPTIND:4 OPTARG:'' | ||
diff --git a/shell/hush_test/hush-getopts/getopt_silent.tests b/shell/hush_test/hush-getopts/getopt_silent.tests new file mode 100755 index 000000000..5f255db7f --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_silent.tests | |||
@@ -0,0 +1,29 @@ | |||
1 | # Open Group Base Specifications Issue 7: | ||
2 | # """ | ||
3 | # If an unknown option is met, VAR shall be set to "?". In this case, | ||
4 | # if the first character in optstring is ":", OPTARG shall be set | ||
5 | # to the option character found, but no output shall be written | ||
6 | # to standard error; otherwise, the shell variable OPTARG shall be | ||
7 | # unset and a diagnostic message shall be written to standard error." | ||
8 | # ... | ||
9 | # If an option-argument is missing: | ||
10 | # If the first character of optstring is ":", VAR shall be set to ":" | ||
11 | # and OPTARG shall be set to the option character found. | ||
12 | # """ | ||
13 | |||
14 | ( | ||
15 | |||
16 | echo "*** optstring:':ac' args:-a -b -c" | ||
17 | getopts ":ac" var -a -b -c; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
18 | getopts ":ac" var -a -b -c; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
19 | getopts ":ac" var -a -b -c; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
20 | getopts ":ac" var -a -b -c; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
21 | # Previous line should result in "rc:1", which is normally treated | ||
22 | # in getopts loops as exit condition. | ||
23 | # Nevertheless, let's verify that calling it yet another time doesn't do | ||
24 | # anything weird: | ||
25 | getopts ":ac" var -a -b -c; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
26 | |||
27 | ) 2>&1 \ | ||
28 | | sed -e 's/ unrecognized option: / invalid option -- /' \ | ||
29 | -e 's/ illegal option -- / invalid option -- /' \ | ||
diff --git a/shell/hush_test/hush-getopts/getopt_simple.right b/shell/hush_test/hush-getopts/getopt_simple.right new file mode 100644 index 000000000..b4855fa1a --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_simple.right | |||
@@ -0,0 +1,34 @@ | |||
1 | *** no OPTIND, optstring:'ab' args:-a -b c | ||
2 | var:'a' OPTIND:2 | ||
3 | var:'b' OPTIND:3 | ||
4 | exited: rc:0 var:'?' OPTIND:3 | ||
5 | *** OPTIND=1, optstring:'ab' args:-a -b c | ||
6 | var:'a' OPTIND:2 | ||
7 | var:'b' OPTIND:3 | ||
8 | exited: rc:0 var:'?' OPTIND:3 | ||
9 | *** OPTIND=0, optstring:'ab' args:-a -b c | ||
10 | var:'a' OPTIND:2 | ||
11 | var:'b' OPTIND:3 | ||
12 | exited: rc:0 var:'?' OPTIND:3 | ||
13 | *** unset OPTIND, optstring:'ab' args:-a -b c | ||
14 | var:'a' OPTIND:2 | ||
15 | var:'b' OPTIND:3 | ||
16 | exited: rc:0 var:'?' OPTIND:3 | ||
17 | *** optstring:'ab' args:-a -b c | ||
18 | 1 rc:0 var:'a' OPTIND:2 | ||
19 | 2 rc:0 var:'b' OPTIND:3 | ||
20 | 3 rc:1 var:'?' OPTIND:3 | ||
21 | *** unset OPTIND, optstring:'ab' args:-a c -c -b d | ||
22 | var:'a' OPTIND:2 | ||
23 | exited: rc:0 var:'?' OPTIND:2 | ||
24 | *** unset OPTIND, optstring:'ab' args:-a -c -b d | ||
25 | var:'a' OPTIND:2 | ||
26 | ./getopt_simple.tests: invalid option -- c | ||
27 | var:'?' OPTIND:3 | ||
28 | var:'b' OPTIND:4 | ||
29 | exited: rc:0 var:'?' OPTIND:4 | ||
30 | *** unset OPTIND, OPTERR=0, optstring:'ab' args:-a -c -b d | ||
31 | var:'a' OPTIND:2 | ||
32 | var:'?' OPTIND:3 | ||
33 | var:'b' OPTIND:4 | ||
34 | exited: rc:0 var:'?' OPTIND:4 | ||
diff --git a/shell/hush_test/hush-getopts/getopt_simple.tests b/shell/hush_test/hush-getopts/getopt_simple.tests new file mode 100755 index 000000000..50718cc98 --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_simple.tests | |||
@@ -0,0 +1,81 @@ | |||
1 | # Simple usage cases for getopts. | ||
2 | # | ||
3 | # OPTIND is either not touched at all (first loop with getopts, | ||
4 | # relying on shell startup init), or getopts state is reset | ||
5 | # before new loop with "unset OPTIND", "OPTIND=1" or "OPTIND=0". | ||
6 | # | ||
7 | # Each option is a separate argument (no "-abc"). This conceptually | ||
8 | # needs only $OPTIND to hold getopts state. | ||
9 | # | ||
10 | # We check that loop does not stop on unknown option (sets "?"), | ||
11 | # stops on _first_ non-option argument. | ||
12 | |||
13 | ( | ||
14 | |||
15 | echo "*** no OPTIND, optstring:'ab' args:-a -b c" | ||
16 | var=QWERTY | ||
17 | while getopts "ab" var -a -b c; do | ||
18 | echo "var:'$var' OPTIND:$OPTIND" | ||
19 | done | ||
20 | # unfortunately, "rc:0" is shown since while's overall exitcode is "success" | ||
21 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
22 | |||
23 | # Resetting behavior =1 | ||
24 | echo "*** OPTIND=1, optstring:'ab' args:-a -b c" | ||
25 | OPTIND=1 | ||
26 | while getopts "ab" var -a -b c; do | ||
27 | echo "var:'$var' OPTIND:$OPTIND" | ||
28 | done | ||
29 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
30 | |||
31 | # Resetting behavior =0 | ||
32 | echo "*** OPTIND=0, optstring:'ab' args:-a -b c" | ||
33 | OPTIND=0 | ||
34 | while getopts "ab" var -a -b c; do | ||
35 | echo "var:'$var' OPTIND:$OPTIND" | ||
36 | done | ||
37 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
38 | |||
39 | # Resetting behavior "unset" | ||
40 | echo "*** unset OPTIND, optstring:'ab' args:-a -b c" | ||
41 | unset OPTIND | ||
42 | while getopts "ab" var -a -b c; do | ||
43 | echo "var:'$var' OPTIND:$OPTIND" | ||
44 | done | ||
45 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
46 | |||
47 | # What is the final exitcode? | ||
48 | echo "*** optstring:'ab' args:-a -b c" | ||
49 | unset OPTIND | ||
50 | getopts "ab" var -a -b c; echo "1 rc:$? var:'$var' OPTIND:$OPTIND" | ||
51 | getopts "ab" var -a -b c; echo "2 rc:$? var:'$var' OPTIND:$OPTIND" | ||
52 | getopts "ab" var -a -b c; echo "3 rc:$? var:'$var' OPTIND:$OPTIND" | ||
53 | |||
54 | # Where would it stop? c or -c? | ||
55 | echo "*** unset OPTIND, optstring:'ab' args:-a c -c -b d" | ||
56 | unset OPTIND | ||
57 | while getopts "ab" var -a c -c -b d; do | ||
58 | echo "var:'$var' OPTIND:$OPTIND" | ||
59 | done | ||
60 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
61 | |||
62 | # What happens on unknown option? | ||
63 | echo "*** unset OPTIND, optstring:'ab' args:-a -c -b d" | ||
64 | unset OPTIND | ||
65 | while getopts "ab" var -a -c -b d; do | ||
66 | echo "var:'$var' OPTIND:$OPTIND" | ||
67 | done | ||
68 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
69 | |||
70 | # ORTERR=0 suppresses error message? | ||
71 | echo "*** unset OPTIND, OPTERR=0, optstring:'ab' args:-a -c -b d" | ||
72 | unset OPTIND | ||
73 | OPTERR=0 | ||
74 | while getopts "ab" var -a -c -b d; do | ||
75 | echo "var:'$var' OPTIND:$OPTIND" | ||
76 | done | ||
77 | echo "exited: rc:$? var:'$var' OPTIND:$OPTIND" | ||
78 | |||
79 | ) 2>&1 \ | ||
80 | | sed -e 's/ unrecognized option: / invalid option -- /' \ | ||
81 | -e 's/ illegal option -- / invalid option -- /' \ | ||
diff --git a/shell/hush_test/hush-getopts/getopt_test_libc_bug.right b/shell/hush_test/hush-getopts/getopt_test_libc_bug.right new file mode 100644 index 000000000..6694e8f0c --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_test_libc_bug.right | |||
@@ -0,0 +1,26 @@ | |||
1 | *** optstring:'ac' args:-a -b -c -d e | ||
2 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
3 | ./getopt_test_libc_bug.tests: invalid option -- b | ||
4 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'' | ||
5 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
6 | ./getopt_test_libc_bug.tests: invalid option -- d | ||
7 | 4 rc:0 var:'?' OPTIND:5 OPTARG:'' | ||
8 | 5 rc:1 var:'?' OPTIND:5 OPTARG:'' | ||
9 | |||
10 | *** optstring:'ac' args:-a -b -c -d e | ||
11 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
12 | ./getopt_test_libc_bug.tests: invalid option -- b | ||
13 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'' | ||
14 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
15 | ./getopt_test_libc_bug.tests: invalid option -- d | ||
16 | 4 rc:0 var:'?' OPTIND:5 OPTARG:'' | ||
17 | 5 rc:1 var:'?' OPTIND:5 OPTARG:'' | ||
18 | |||
19 | *** optstring:'ac' args:-a -b -c -d e | ||
20 | 1 rc:0 var:'a' OPTIND:2 OPTARG:'' | ||
21 | ./getopt_test_libc_bug.tests: invalid option -- b | ||
22 | 2 rc:0 var:'?' OPTIND:3 OPTARG:'' | ||
23 | 3 rc:0 var:'c' OPTIND:4 OPTARG:'' | ||
24 | ./getopt_test_libc_bug.tests: invalid option -- d | ||
25 | 4 rc:0 var:'?' OPTIND:5 OPTARG:'' | ||
26 | 5 rc:1 var:'?' OPTIND:5 OPTARG:'' | ||
diff --git a/shell/hush_test/hush-getopts/getopt_test_libc_bug.tests b/shell/hush_test/hush-getopts/getopt_test_libc_bug.tests new file mode 100755 index 000000000..ab7bc3b09 --- /dev/null +++ b/shell/hush_test/hush-getopts/getopt_test_libc_bug.tests | |||
@@ -0,0 +1,44 @@ | |||
1 | # This test can fail with libc with buggy getopt() implementation. | ||
2 | # If getopt() wants to parse multi-option args (-abc), | ||
3 | # it needs to remember a position within current arg. | ||
4 | # | ||
5 | # If this position is kept as a POINTER, not an offset, | ||
6 | # and if argv[] ADDRESSES (not contents!) change, it blows up. | ||
7 | |||
8 | ( | ||
9 | |||
10 | echo "*** optstring:'ac' args:-a -b -c -d e" | ||
11 | getopts "ac" var -a -b -c -d e; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
12 | getopts "ac" var -a -b -c -d e; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
13 | getopts "ac" var -a -b -c -d e; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
14 | getopts "ac" var -a -b -c -d e; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
15 | getopts "ac" var -a -b -c -d e; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
16 | |||
17 | # Above: args are (usually) in the same locations in memory. | ||
18 | # Below: variable allocations change the location. | ||
19 | |||
20 | echo | ||
21 | echo "*** optstring:'ac' args:-a -b -c -d e" | ||
22 | unset OPTIND | ||
23 | OPTARG=QWERTY; getopts "ac" var -a -b -c -d e; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
24 | NEWVAR=NEWVAL; getopts "ac" var -a -b -c -d e; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
25 | VAR111=NEWVAL; getopts "ac" var -a -b -c -d e; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
26 | VAR222=NEWVAL; getopts "ac" var -a -b -c -d e; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
27 | VAR333=NEWVAL; getopts "ac" var -a -b -c -d e; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
28 | |||
29 | # Slightly different attempts to force reallocations | ||
30 | |||
31 | echo | ||
32 | echo "*** optstring:'ac' args:-a -b -c -d e" | ||
33 | unset OPTIND | ||
34 | export OPTARG; getopts "ac" var -a -b -c -d e; echo "1 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
35 | export NEWVAR; getopts "ac" var -a -b -c -d e; echo "2 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
36 | export VAR111; getopts "ac" var -a -b -c -d e; echo "3 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
37 | export VAR222; getopts "ac" var -a -b -c -d e; echo "4 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
38 | export VAR333; getopts "ac" var -a -b -c -d e; echo "5 rc:$? var:'$var' OPTIND:$OPTIND OPTARG:'$OPTARG'" | ||
39 | |||
40 | # All copies of code above should generate identical output | ||
41 | |||
42 | ) 2>&1 \ | ||
43 | | sed -e 's/ unrecognized option: / invalid option -- /' \ | ||
44 | -e 's/ illegal option -- / invalid option -- /' \ | ||
diff --git a/shell/hush_test/hush-parsing/groups_and_keywords2.right b/shell/hush_test/hush-parsing/groups_and_keywords2.right new file mode 100644 index 000000000..ae74a5db9 --- /dev/null +++ b/shell/hush_test/hush-parsing/groups_and_keywords2.right | |||
@@ -0,0 +1,3 @@ | |||
1 | hush: syntax error: unexpected ) | ||
2 | Fail:2 | ||
3 | hush: syntax error: unexpected ) | ||
diff --git a/shell/hush_test/hush-parsing/groups_and_keywords2.tests b/shell/hush_test/hush-parsing/groups_and_keywords2.tests new file mode 100755 index 000000000..ab33b909f --- /dev/null +++ b/shell/hush_test/hush-parsing/groups_and_keywords2.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | # This is an error | ||
2 | (eval 'if() { echo; }') | ||
3 | echo Fail:$? | ||
4 | # ^^^^^^ bash prints 1, but interactively it sets $? = 2 | ||
5 | # we print 2 | ||
6 | |||
7 | # This is an error, and it aborts in script | ||
8 | if() { echo; } | ||
9 | echo Not reached | ||
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 1dd0edc39..3fbc7c531 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all | |||
@@ -80,7 +80,7 @@ do_test() | |||
80 | case $? in | 80 | case $? in |
81 | 0) echo " ok";; | 81 | 0) echo " ok";; |
82 | 77) echo " skip (feature disabled)";; | 82 | 77) echo " skip (feature disabled)";; |
83 | *) echo " fail"; tret=1;; | 83 | *) echo " fail ($?)"; tret=1;; |
84 | esac | 84 | esac |
85 | done | 85 | done |
86 | exit ${tret} | 86 | exit ${tret} |
diff --git a/shell/math.c b/shell/math.c index 006221b6a..f01f24362 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -743,7 +743,7 @@ arith(arith_state_t *math_state, const char *expr) | |||
743 | * may be used to endorse or promote products derived from this software | 743 | * may be used to endorse or promote products derived from this software |
744 | * without specific prior written permission. | 744 | * without specific prior written permission. |
745 | * | 745 | * |
746 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 746 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
747 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 747 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
748 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 748 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
749 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 749 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/shell/shell_common.c b/shell/shell_common.c index 750adc5d8..bc34de404 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -58,7 +58,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
58 | const char *opt_n, | 58 | const char *opt_n, |
59 | const char *opt_p, | 59 | const char *opt_p, |
60 | const char *opt_t, | 60 | const char *opt_t, |
61 | const char *opt_u | 61 | const char *opt_u, |
62 | const char *opt_d | ||
62 | ) | 63 | ) |
63 | { | 64 | { |
64 | struct pollfd pfd[1]; | 65 | struct pollfd pfd[1]; |
@@ -68,6 +69,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
68 | int nchars; /* -n NUM */ | 69 | int nchars; /* -n NUM */ |
69 | char **pp; | 70 | char **pp; |
70 | char *buffer; | 71 | char *buffer; |
72 | char delim; | ||
71 | struct termios tty, old_tty; | 73 | struct termios tty, old_tty; |
72 | const char *retval; | 74 | const char *retval; |
73 | int bufpos; /* need to be able to hold -1 */ | 75 | int bufpos; /* need to be able to hold -1 */ |
@@ -188,6 +190,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
188 | end_ms += (unsigned)monotonic_ms(); | 190 | end_ms += (unsigned)monotonic_ms(); |
189 | buffer = NULL; | 191 | buffer = NULL; |
190 | bufpos = 0; | 192 | bufpos = 0; |
193 | delim = opt_d ? *opt_d : '\n'; | ||
191 | do { | 194 | do { |
192 | char c; | 195 | char c; |
193 | int timeout; | 196 | int timeout; |
@@ -243,14 +246,14 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
243 | continue; | 246 | continue; |
244 | } | 247 | } |
245 | } | 248 | } |
246 | if (c == '\n') | 249 | if (c == delim) /* '\n' or -d CHAR */ |
247 | break; | 250 | break; |
248 | 251 | ||
249 | /* $IFS splitting. NOT done if we run "read" | 252 | /* $IFS splitting. NOT done if we run "read" |
250 | * without variable names (bash compat). | 253 | * without variable names (bash compat). |
251 | * Thus, "read" and "read REPLY" are not the same. | 254 | * Thus, "read" and "read REPLY" are not the same. |
252 | */ | 255 | */ |
253 | if (argv[0]) { | 256 | if (!opt_d && argv[0]) { |
254 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ | 257 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ |
255 | const char *is_ifs = strchr(ifs, c); | 258 | const char *is_ifs = strchr(ifs, c); |
256 | if (startword && is_ifs) { | 259 | if (startword && is_ifs) { |
diff --git a/shell/shell_common.h b/shell/shell_common.h index a82535c86..875fd9ea7 100644 --- a/shell/shell_common.h +++ b/shell/shell_common.h | |||
@@ -34,6 +34,11 @@ enum { | |||
34 | BUILTIN_READ_SILENT = 1 << 0, | 34 | BUILTIN_READ_SILENT = 1 << 0, |
35 | BUILTIN_READ_RAW = 1 << 1, | 35 | BUILTIN_READ_RAW = 1 << 1, |
36 | }; | 36 | }; |
37 | //TODO? do not provide bashisms if not asked for: | ||
38 | //#if !ENABLE_HUSH_BASH_COMPAT && !ENABLE_ASH_BASH_COMPAT | ||
39 | //#define shell_builtin_read(setvar,argv,ifs,read_flags,n,p,t,u,d) | ||
40 | // shell_builtin_read(setvar,argv,ifs,read_flags) | ||
41 | //#endif | ||
37 | const char* FAST_FUNC | 42 | const char* FAST_FUNC |
38 | shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | 43 | shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), |
39 | char **argv, | 44 | char **argv, |
@@ -42,7 +47,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
42 | const char *opt_n, | 47 | const char *opt_n, |
43 | const char *opt_p, | 48 | const char *opt_p, |
44 | const char *opt_t, | 49 | const char *opt_t, |
45 | const char *opt_u | 50 | const char *opt_u, |
51 | const char *opt_d | ||
46 | ); | 52 | ); |
47 | 53 | ||
48 | int FAST_FUNC | 54 | int FAST_FUNC |
diff --git a/sysklogd/logger.c b/sysklogd/logger.c index 6769a8175..1e0384c09 100644 --- a/sysklogd/logger.c +++ b/sysklogd/logger.c | |||
@@ -77,14 +77,14 @@ static int pencode(char *s) | |||
77 | ; | 77 | ; |
78 | if (*s) { | 78 | if (*s) { |
79 | *s = '\0'; | 79 | *s = '\0'; |
80 | fac = decode(save, facilitynames); | 80 | fac = decode(save, bb_facilitynames); |
81 | if (fac < 0) | 81 | if (fac < 0) |
82 | bb_error_msg_and_die("unknown %s name: %s", "facility", save); | 82 | bb_error_msg_and_die("unknown %s name: %s", "facility", save); |
83 | *s++ = '.'; | 83 | *s++ = '.'; |
84 | } else { | 84 | } else { |
85 | s = save; | 85 | s = save; |
86 | } | 86 | } |
87 | lev = decode(s, prioritynames); | 87 | lev = decode(s, bb_prioritynames); |
88 | if (lev < 0) | 88 | if (lev < 0) |
89 | bb_error_msg_and_die("unknown %s name: %s", "priority", save); | 89 | bb_error_msg_and_die("unknown %s name: %s", "priority", save); |
90 | return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); | 90 | return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); |
@@ -167,7 +167,7 @@ int logger_main(int argc UNUSED_PARAM, char **argv) | |||
167 | * may be used to endorse or promote products derived from this software | 167 | * may be used to endorse or promote products derived from this software |
168 | * without specific prior written permission. | 168 | * without specific prior written permission. |
169 | * | 169 | * |
170 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 170 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
171 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 171 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
172 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 172 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
173 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 173 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 31730a7f9..4265f4f90 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c | |||
@@ -447,7 +447,7 @@ static void parse_syslogdcfg(const char *file) | |||
447 | primap = 0xff; /* all 8 log levels enabled */ | 447 | primap = 0xff; /* all 8 log levels enabled */ |
448 | else { | 448 | else { |
449 | uint8_t priority; | 449 | uint8_t priority; |
450 | code = find_by_name(t, prioritynames); | 450 | code = find_by_name(t, bb_prioritynames); |
451 | if (!code) | 451 | if (!code) |
452 | goto cfgerr; | 452 | goto cfgerr; |
453 | primap = 0; | 453 | primap = 0; |
@@ -480,7 +480,7 @@ static void parse_syslogdcfg(const char *file) | |||
480 | next_facility = strchr(t, ','); | 480 | next_facility = strchr(t, ','); |
481 | if (next_facility) | 481 | if (next_facility) |
482 | *next_facility++ = '\0'; | 482 | *next_facility++ = '\0'; |
483 | code = find_by_name(t, facilitynames); | 483 | code = find_by_name(t, bb_facilitynames); |
484 | if (!code) | 484 | if (!code) |
485 | goto cfgerr; | 485 | goto cfgerr; |
486 | /* "mark" is not a real facility, skip it */ | 486 | /* "mark" is not a real facility, skip it */ |
@@ -797,9 +797,9 @@ static void parse_fac_prio_20(int pri, char *res20) | |||
797 | { | 797 | { |
798 | const CODE *c_pri, *c_fac; | 798 | const CODE *c_pri, *c_fac; |
799 | 799 | ||
800 | c_fac = find_by_val(LOG_FAC(pri) << 3, facilitynames); | 800 | c_fac = find_by_val(LOG_FAC(pri) << 3, bb_facilitynames); |
801 | if (c_fac) { | 801 | if (c_fac) { |
802 | c_pri = find_by_val(LOG_PRI(pri), prioritynames); | 802 | c_pri = find_by_val(LOG_PRI(pri), bb_prioritynames); |
803 | if (c_pri) { | 803 | if (c_pri) { |
804 | snprintf(res20, 20, "%s.%s", c_fac->c_name, c_pri->c_name); | 804 | snprintf(res20, 20, "%s.%s", c_fac->c_name, c_pri->c_name); |
805 | return; | 805 | return; |
@@ -1109,8 +1109,7 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv) | |||
1109 | INIT_G(); | 1109 | INIT_G(); |
1110 | 1110 | ||
1111 | /* No non-option params */ | 1111 | /* No non-option params */ |
1112 | opt_complementary = "=0"; | 1112 | opts = getopt32(argv, "^"OPTION_STR"\0""=0", OPTION_PARAM); |
1113 | opts = getopt32(argv, OPTION_STR, OPTION_PARAM); | ||
1114 | #if ENABLE_FEATURE_REMOTE_LOG | 1113 | #if ENABLE_FEATURE_REMOTE_LOG |
1115 | while (remoteAddrList) { | 1114 | while (remoteAddrList) { |
1116 | remoteHost_t *rh = xzalloc(sizeof(*rh)); | 1115 | remoteHost_t *rh = xzalloc(sizeof(*rh)); |
diff --git a/sysklogd/syslogd_and_logger.c b/sysklogd/syslogd_and_logger.c index 6458a9332..6d06a718b 100644 --- a/sysklogd/syslogd_and_logger.c +++ b/sysklogd/syslogd_and_logger.c | |||
@@ -43,6 +43,17 @@ typedef struct _code { | |||
43 | */ | 43 | */ |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | /* musl decided to be funny and it implements these as giant defines | ||
47 | * of the form: ((CODE *)(const CODE []){ ... }) | ||
48 | * Which works, but causes _every_ function using them | ||
49 | * to have a copy on stack (at least with gcc-6.3.0). | ||
50 | * If we reference them just once, this saves 150 bytes. | ||
51 | * The pointers themselves are optimized out | ||
52 | * (no size change on uclibc). | ||
53 | */ | ||
54 | static const CODE *const bb_prioritynames = prioritynames; | ||
55 | static const CODE *const bb_facilitynames = facilitynames; | ||
56 | |||
46 | #if ENABLE_SYSLOGD | 57 | #if ENABLE_SYSLOGD |
47 | #include "syslogd.c" | 58 | #include "syslogd.c" |
48 | #endif | 59 | #endif |
diff --git a/testsuite/mdev.tests b/testsuite/mdev.tests index 8515aff31..8e53ec564 100755 --- a/testsuite/mdev.tests +++ b/testsuite/mdev.tests | |||
@@ -168,7 +168,7 @@ SKIP= | |||
168 | # continuing to use directory structure from prev test | 168 | # continuing to use directory structure from prev test |
169 | rm -rf mdev.testdir/dev/* | 169 | rm -rf mdev.testdir/dev/* |
170 | echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf | 170 | echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf |
171 | optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH ASH_ECHO | 171 | optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME SH_IS_ASH ASH_ECHO |
172 | testing "mdev command" \ | 172 | testing "mdev command" \ |
173 | "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; | 173 | "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; |
174 | ls -lnR mdev.testdir/dev | $FILTER_LS" \ | 174 | ls -lnR mdev.testdir/dev | $FILTER_LS" \ |
@@ -183,7 +183,7 @@ SKIP= | |||
183 | # continuing to use directory structure from prev test | 183 | # continuing to use directory structure from prev test |
184 | rm -rf mdev.testdir/dev/* | 184 | rm -rf mdev.testdir/dev/* |
185 | echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf | 185 | echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf |
186 | optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH | 186 | optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME SH_IS_ASH |
187 | testing "mdev move and command" \ | 187 | testing "mdev move and command" \ |
188 | "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; | 188 | "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; |
189 | ls -lnR mdev.testdir/dev | $FILTER_LS2" \ | 189 | ls -lnR mdev.testdir/dev | $FILTER_LS2" \ |
diff --git a/testsuite/parse.tests b/testsuite/parse.tests index 904e1a17a..2cbed6f31 100755 --- a/testsuite/parse.tests +++ b/testsuite/parse.tests | |||
@@ -5,13 +5,13 @@ | |||
5 | 5 | ||
6 | . ./testing.sh | 6 | . ./testing.sh |
7 | 7 | ||
8 | COLLAPSE=$(( 0x00010000)) | 8 | COLLAPSE=$(( 0x00010000)) |
9 | TRIM=$(( 0x00020000)) | 9 | TRIM=$(( 0x00020000)) |
10 | GREEDY=$(( 0x00040000)) | 10 | GREEDY=$(( 0x00040000)) |
11 | MIN_DIE=$(( 0x00100000)) | 11 | MIN_DIE=$(( 0x00100000)) |
12 | KEEP_COPY=$((0x00200000)) | 12 | KEEP_COPY=$(( 0x00200000)) |
13 | ESCAPE=$(( 0x00400000)) | 13 | EOL_COMMENTS=$((0x00400000)) |
14 | NORMAL=$(( COLLAPSE | TRIM | GREEDY)) | 14 | NORMAL=$(( COLLAPSE | TRIM | GREEDY | EOL_COMMENTS)) |
15 | 15 | ||
16 | # testing "description" "command" "result" "infile" "stdin" | 16 | # testing "description" "command" "result" "infile" "stdin" |
17 | 17 | ||
@@ -27,6 +27,34 @@ testing "parse notrim" \ | |||
27 | "-" \ | 27 | "-" \ |
28 | " sda 0:0 644 @echo @echo TEST \n" | 28 | " sda 0:0 644 @echo @echo TEST \n" |
29 | 29 | ||
30 | testing "parse comments" \ | ||
31 | "parse -n 4 -m 3 -f $((NORMAL - EOL_COMMENTS)) -" \ | ||
32 | "[sda][0:0][644][@echo @echo TEST #this is not eaten]\n" \ | ||
33 | "-" \ | ||
34 | "\ | ||
35 | # sda 0:0 644 @echo @echo TEST - this gets eaten | ||
36 | sda 0:0 644 @echo @echo TEST #this is not eaten | ||
37 | " | ||
38 | |||
39 | testing "parse bad comment" \ | ||
40 | "parse -n 2 -m 2 -d '#=' -f $((GREEDY)) - 2>&1" \ | ||
41 | "\ | ||
42 | [var][val] | ||
43 | parse: bad line 3: 1 tokens found, 2 needed | ||
44 | [ #this][ok] | ||
45 | [ #this][=ok] | ||
46 | [ #this][=ok=ok=ok=] | ||
47 | " \ | ||
48 | "-" \ | ||
49 | "\ | ||
50 | # this gets eaten | ||
51 | var=val | ||
52 | #this causes error msg | ||
53 | #this=ok | ||
54 | #this==ok | ||
55 | #this==ok=ok=ok= | ||
56 | " | ||
57 | |||
30 | FILE=__parse | 58 | FILE=__parse |
31 | cat >$FILE <<EOF | 59 | cat >$FILE <<EOF |
32 | # | 60 | # |
@@ -96,6 +124,8 @@ cat >$FILE.res <<EOF | |||
96 | [option][dns][129.219.13.81] | 124 | [option][dns][129.219.13.81] |
97 | [option][domain][local] | 125 | [option][domain][local] |
98 | [option][lease][864000] | 126 | [option][lease][864000] |
127 | [option][msstaticroutes][10.0.0.0/8][10.127.0.1] | ||
128 | [option][staticroutes][10.0.0.0/8][10.127.0.1,][10.11.12.0/24][10.11.12.1] | ||
99 | [option][0x08][01020304] | 129 | [option][0x08][01020304] |
100 | EOF | 130 | EOF |
101 | 131 | ||
diff --git a/testsuite/tar.tests b/testsuite/tar.tests index 1675b07b1..b7cd74ca5 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests | |||
@@ -279,7 +279,7 @@ optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_BZ2 | |||
279 | testing "tar does not extract into symlinks" "\ | 279 | testing "tar does not extract into symlinks" "\ |
280 | >>/tmp/passwd && uudecode -o input && tar xf input 2>&1 && rm passwd; cat /tmp/passwd; echo \$? | 280 | >>/tmp/passwd && uudecode -o input && tar xf input 2>&1 && rm passwd; cat /tmp/passwd; echo \$? |
281 | " "\ | 281 | " "\ |
282 | tar: can't create symlink 'passwd' to '/tmp/passwd' | 282 | tar: skipping unsafe symlink to '/tmp/passwd' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract |
283 | 0 | 283 | 0 |
284 | " \ | 284 | " \ |
285 | "" "\ | 285 | "" "\ |
@@ -299,7 +299,7 @@ optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_BZ2 | |||
299 | testing "tar -k does not extract into symlinks" "\ | 299 | testing "tar -k does not extract into symlinks" "\ |
300 | >>/tmp/passwd && uudecode -o input && tar xf input -k 2>&1 && rm passwd; cat /tmp/passwd; echo \$? | 300 | >>/tmp/passwd && uudecode -o input && tar xf input -k 2>&1 && rm passwd; cat /tmp/passwd; echo \$? |
301 | " "\ | 301 | " "\ |
302 | tar: can't create symlink 'passwd' to '/tmp/passwd' | 302 | tar: skipping unsafe symlink to '/tmp/passwd' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract |
303 | 0 | 303 | 0 |
304 | " \ | 304 | " \ |
305 | "" "\ | 305 | "" "\ |
@@ -324,11 +324,11 @@ rm -rf etc usr | |||
324 | ' "\ | 324 | ' "\ |
325 | etc/ssl/certs/3b2716e5.0 | 325 | etc/ssl/certs/3b2716e5.0 |
326 | etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem | 326 | etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem |
327 | tar: skipping unsafe symlink to '/usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract | ||
327 | etc/ssl/certs/f80cc7f6.0 | 328 | etc/ssl/certs/f80cc7f6.0 |
328 | usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt | 329 | usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt |
329 | 0 | 330 | 0 |
330 | etc/ssl/certs/3b2716e5.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem | 331 | etc/ssl/certs/3b2716e5.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem |
331 | etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem -> /usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt | ||
332 | etc/ssl/certs/f80cc7f6.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem | 332 | etc/ssl/certs/f80cc7f6.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem |
333 | " \ | 333 | " \ |
334 | "" "" | 334 | "" "" |
@@ -346,9 +346,9 @@ ls symlink/bb_test_evilfile | |||
346 | ' "\ | 346 | ' "\ |
347 | anything.txt | 347 | anything.txt |
348 | symlink | 348 | symlink |
349 | tar: skipping unsafe symlink to '/tmp' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract | ||
349 | symlink/bb_test_evilfile | 350 | symlink/bb_test_evilfile |
350 | tar: can't create symlink 'symlink' to '/tmp' | 351 | 0 |
351 | 1 | ||
352 | ls: /tmp/bb_test_evilfile: No such file or directory | 352 | ls: /tmp/bb_test_evilfile: No such file or directory |
353 | ls: bb_test_evilfile: No such file or directory | 353 | ls: bb_test_evilfile: No such file or directory |
354 | symlink/bb_test_evilfile | 354 | symlink/bb_test_evilfile |
diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 3c3811752..4f491fa14 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c | |||
@@ -264,8 +264,12 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) | |||
264 | 264 | ||
265 | INIT_G(); | 265 | INIT_G(); |
266 | 266 | ||
267 | opt_complementary = "df:e--e"; | 267 | opts = getopt32(argv, "^" |
268 | opts = getopt32(argv, "c:de:fl:a:M:" IF_FEATURE_PIDFILE("p:") IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"), | 268 | "c:de:fl:a:M:" |
269 | IF_FEATURE_PIDFILE("p:") | ||
270 | IF_FEATURE_ACPID_COMPAT("g:m:s:S:v") | ||
271 | "\0" | ||
272 | "df:e--e", | ||
269 | &opt_dir, &opt_input, &opt_logfile, &opt_action, &opt_map | 273 | &opt_dir, &opt_input, &opt_logfile, &opt_action, &opt_map |
270 | IF_FEATURE_PIDFILE(, &opt_pidfile) | 274 | IF_FEATURE_PIDFILE(, &opt_pidfile) |
271 | IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL) | 275 | IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL) |
diff --git a/util-linux/blkdiscard.c b/util-linux/blkdiscard.c index 8f6a4ab6c..5863f0aab 100644 --- a/util-linux/blkdiscard.c +++ b/util-linux/blkdiscard.c | |||
@@ -11,8 +11,9 @@ | |||
11 | //config: help | 11 | //config: help |
12 | //config: blkdiscard discards sectors on a given device. | 12 | //config: blkdiscard discards sectors on a given device. |
13 | 13 | ||
14 | //applet:IF_BLKDISCARD(APPLET_NOEXEC(blkdiscard, blkdiscard, BB_DIR_USR_BIN, BB_SUID_DROP, blkdiscard)) | ||
15 | |||
14 | //kbuild:lib-$(CONFIG_BLKDISCARD) += blkdiscard.o | 16 | //kbuild:lib-$(CONFIG_BLKDISCARD) += blkdiscard.o |
15 | //applet:IF_BLKDISCARD(APPLET(blkdiscard, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
16 | 17 | ||
17 | //usage:#define blkdiscard_trivial_usage | 18 | //usage:#define blkdiscard_trivial_usage |
18 | //usage: "[-o OFS] [-l LEN] [-s] DEVICE" | 19 | //usage: "[-o OFS] [-l LEN] [-s] DEVICE" |
@@ -44,7 +45,6 @@ int blkdiscard_main(int argc UNUSED_PARAM, char **argv) | |||
44 | uint64_t offset; /* Leaving these two variables out does not */ | 45 | uint64_t offset; /* Leaving these two variables out does not */ |
45 | uint64_t length; /* shrink code size and hampers readability. */ | 46 | uint64_t length; /* shrink code size and hampers readability. */ |
46 | uint64_t range[2]; | 47 | uint64_t range[2]; |
47 | // struct stat st; | ||
48 | int fd; | 48 | int fd; |
49 | 49 | ||
50 | enum { | 50 | enum { |
@@ -53,8 +53,7 @@ int blkdiscard_main(int argc UNUSED_PARAM, char **argv) | |||
53 | OPT_SECURE = (1 << 2), | 53 | OPT_SECURE = (1 << 2), |
54 | }; | 54 | }; |
55 | 55 | ||
56 | opt_complementary = "=1"; | 56 | opts = getopt32(argv, "^" "o:l:s" "\0" "=1", &offset_str, &length_str); |
57 | opts = getopt32(argv, "o:l:s", &offset_str, &length_str); | ||
58 | argv += optind; | 57 | argv += optind; |
59 | 58 | ||
60 | fd = xopen(argv[0], O_RDWR|O_EXCL); | 59 | fd = xopen(argv[0], O_RDWR|O_EXCL); |
diff --git a/util-linux/blkid.c b/util-linux/blkid.c index 0bd701aae..a56b69661 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c | |||
@@ -16,12 +16,12 @@ | |||
16 | //config: | 16 | //config: |
17 | //config:config FEATURE_BLKID_TYPE | 17 | //config:config FEATURE_BLKID_TYPE |
18 | //config: bool "Print filesystem type" | 18 | //config: bool "Print filesystem type" |
19 | //config: default n | 19 | //config: default y |
20 | //config: depends on BLKID | 20 | //config: depends on BLKID |
21 | //config: help | 21 | //config: help |
22 | //config: Show TYPE="filesystem type" | 22 | //config: Show TYPE="filesystem type" |
23 | 23 | ||
24 | //applet:IF_BLKID(APPLET(blkid, BB_DIR_SBIN, BB_SUID_DROP)) | 24 | //applet:IF_BLKID(APPLET_NOEXEC(blkid, blkid, BB_DIR_SBIN, BB_SUID_DROP, blkid)) |
25 | 25 | ||
26 | //kbuild:lib-$(CONFIG_BLKID) += blkid.o | 26 | //kbuild:lib-$(CONFIG_BLKID) += blkid.o |
27 | 27 | ||
diff --git a/util-linux/blockdev.c b/util-linux/blockdev.c index 9e1fef206..e53ade995 100644 --- a/util-linux/blockdev.c +++ b/util-linux/blockdev.c | |||
@@ -11,7 +11,7 @@ | |||
11 | //config: help | 11 | //config: help |
12 | //config: Performs some ioctls with block devices. | 12 | //config: Performs some ioctls with block devices. |
13 | 13 | ||
14 | //applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP)) | 14 | //applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev)) |
15 | 15 | ||
16 | //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o | 16 | //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o |
17 | 17 | ||
diff --git a/util-linux/cal.c b/util-linux/cal.c index 091fdbd2b..10df0ae8b 100644 --- a/util-linux/cal.c +++ b/util-linux/cal.c | |||
@@ -376,7 +376,7 @@ static char *build_row(char *p, unsigned *dp) | |||
376 | * may be used to endorse or promote products derived from this software | 376 | * may be used to endorse or promote products derived from this software |
377 | * without specific prior written permission. | 377 | * without specific prior written permission. |
378 | * | 378 | * |
379 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 379 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
380 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 380 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
381 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 381 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
382 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 382 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/util-linux/chrt.c b/util-linux/chrt.c index 4bc8b6cfa..2712ea3e3 100644 --- a/util-linux/chrt.c +++ b/util-linux/chrt.c | |||
@@ -12,7 +12,7 @@ | |||
12 | //config: manipulate real-time attributes of a process. | 12 | //config: manipulate real-time attributes of a process. |
13 | //config: This requires sched_{g,s}etparam support in your libc. | 13 | //config: This requires sched_{g,s}etparam support in your libc. |
14 | 14 | ||
15 | //applet:IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP)) | 15 | //applet:IF_CHRT(APPLET_NOEXEC(chrt, chrt, BB_DIR_USR_BIN, BB_SUID_DROP, chrt)) |
16 | 16 | ||
17 | //kbuild:lib-$(CONFIG_CHRT) += chrt.o | 17 | //kbuild:lib-$(CONFIG_CHRT) += chrt.o |
18 | 18 | ||
@@ -77,8 +77,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) | |||
77 | int policy = SCHED_RR; | 77 | int policy = SCHED_RR; |
78 | 78 | ||
79 | /* only one policy accepted */ | 79 | /* only one policy accepted */ |
80 | opt_complementary = "r--fo:f--ro:o--rf"; | 80 | opt = getopt32(argv, "^+" "mprfo" "\0" "r--fo:f--ro:o--rf"); |
81 | opt = getopt32(argv, "+mprfo"); | ||
82 | if (opt & OPT_m) { /* print min/max and exit */ | 81 | if (opt & OPT_m) { /* print min/max and exit */ |
83 | show_min_max(SCHED_FIFO); | 82 | show_min_max(SCHED_FIFO); |
84 | show_min_max(SCHED_RR); | 83 | show_min_max(SCHED_RR); |
diff --git a/util-linux/eject.c b/util-linux/eject.c index 8095cbef0..6c30facd2 100644 --- a/util-linux/eject.c +++ b/util-linux/eject.c | |||
@@ -124,8 +124,9 @@ int eject_main(int argc UNUSED_PARAM, char **argv) | |||
124 | unsigned flags; | 124 | unsigned flags; |
125 | const char *device; | 125 | const char *device; |
126 | 126 | ||
127 | opt_complementary = "?1:t--T:T--t"; | 127 | flags = getopt32(argv, "^" "tT"IF_FEATURE_EJECT_SCSI("s") |
128 | flags = getopt32(argv, "tT" IF_FEATURE_EJECT_SCSI("s")); | 128 | "\0" "?1:t--T:T--t" |
129 | ); | ||
129 | device = argv[optind] ? argv[optind] : "/dev/cdrom"; | 130 | device = argv[optind] ? argv[optind] : "/dev/cdrom"; |
130 | 131 | ||
131 | /* We used to do "umount <device>" here, but it was buggy | 132 | /* We used to do "umount <device>" here, but it was buggy |
diff --git a/util-linux/fallocate.c b/util-linux/fallocate.c index 70e7e178f..1a02a322f 100644 --- a/util-linux/fallocate.c +++ b/util-linux/fallocate.c | |||
@@ -82,8 +82,7 @@ int fallocate_main(int argc UNUSED_PARAM, char **argv) | |||
82 | int fd; | 82 | int fd; |
83 | 83 | ||
84 | /* exactly one non-option arg */ | 84 | /* exactly one non-option arg */ |
85 | opt_complementary = "=1"; | 85 | opts = getopt32(argv, "^" "l:o:" "\0" "=1", &str_l, &str_o); |
86 | opts = getopt32(argv, "l:o:", &str_l, &str_o); | ||
87 | if (!(opts & 1)) | 86 | if (!(opts & 1)) |
88 | bb_show_usage(); | 87 | bb_show_usage(); |
89 | 88 | ||
diff --git a/util-linux/fatattr.c b/util-linux/fatattr.c index 9fb566d5a..770b1d2f9 100644 --- a/util-linux/fatattr.c +++ b/util-linux/fatattr.c | |||
@@ -15,7 +15,7 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: fatattr lists or changes the file attributes on a fat file system. | 16 | //config: fatattr lists or changes the file attributes on a fat file system. |
17 | 17 | ||
18 | //applet:IF_FATATTR(APPLET(fatattr, BB_DIR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_FATATTR(APPLET_NOEXEC(fatattr, fatattr, BB_DIR_BIN, BB_SUID_DROP, fatattr)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_FATATTR) += fatattr.o | 20 | //kbuild:lib-$(CONFIG_FATATTR) += fatattr.o |
21 | 21 | ||
diff --git a/util-linux/fdformat.c b/util-linux/fdformat.c index 6faaf1b10..855269c30 100644 --- a/util-linux/fdformat.c +++ b/util-linux/fdformat.c | |||
@@ -66,8 +66,7 @@ int fdformat_main(int argc UNUSED_PARAM, char **argv) | |||
66 | struct floppy_struct param; | 66 | struct floppy_struct param; |
67 | struct format_descr descr; | 67 | struct format_descr descr; |
68 | 68 | ||
69 | opt_complementary = "=1"; /* must have 1 param */ | 69 | verify = !getopt32(argv, "^" "n" "\0" "=1"); |
70 | verify = !getopt32(argv, "n"); | ||
71 | argv += optind; | 70 | argv += optind; |
72 | 71 | ||
73 | xstat(*argv, &st); | 72 | xstat(*argv, &st); |
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index e00f85864..c4318b6c4 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c | |||
@@ -644,7 +644,7 @@ read_line(const char *prompt) | |||
644 | { | 644 | { |
645 | int sz; | 645 | int sz; |
646 | 646 | ||
647 | sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1); | 647 | sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer)); |
648 | if (sz <= 0) | 648 | if (sz <= 0) |
649 | exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ | 649 | exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ |
650 | 650 | ||
@@ -2848,7 +2848,7 @@ xselect(void) | |||
2848 | if (dos_compatible_flag) { | 2848 | if (dos_compatible_flag) { |
2849 | sector_offset = g_sectors; | 2849 | sector_offset = g_sectors; |
2850 | puts("Warning: setting sector offset for DOS " | 2850 | puts("Warning: setting sector offset for DOS " |
2851 | "compatiblity"); | 2851 | "compatibility"); |
2852 | } | 2852 | } |
2853 | update_units(); | 2853 | update_units(); |
2854 | break; | 2854 | break; |
diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c index 89f1f323c..1141b7801 100644 --- a/util-linux/fdisk_osf.c +++ b/util-linux/fdisk_osf.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * may be used to endorse or promote products derived from this software | 18 | * may be used to endorse or promote products derived from this software |
19 | * without specific prior written permission. | 19 | * without specific prior written permission. |
20 | * | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
diff --git a/util-linux/flock.c b/util-linux/flock.c index ec35af18f..dd0bfd430 100644 --- a/util-linux/flock.c +++ b/util-linux/flock.c | |||
@@ -38,17 +38,15 @@ int flock_main(int argc UNUSED_PARAM, char **argv) | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | #if ENABLE_LONG_OPTS | 40 | #if ENABLE_LONG_OPTS |
41 | static const char getopt_longopts[] ALIGN1 = | 41 | static const char flock_longopts[] ALIGN1 = |
42 | "shared\0" No_argument "s" | 42 | "shared\0" No_argument "s" |
43 | "exclusive\0" No_argument "x" | 43 | "exclusive\0" No_argument "x" |
44 | "unlock\0" No_argument "u" | 44 | "unlock\0" No_argument "u" |
45 | "nonblock\0" No_argument "n" | 45 | "nonblock\0" No_argument "n" |
46 | ; | 46 | ; |
47 | applet_long_options = getopt_longopts; | ||
48 | #endif | 47 | #endif |
49 | opt_complementary = "-1"; | ||
50 | 48 | ||
51 | opt = getopt32(argv, "+sxnu"); | 49 | opt = getopt32long(argv, "^+" "sxnu" "\0" "-1", flock_longopts); |
52 | argv += optind; | 50 | argv += optind; |
53 | 51 | ||
54 | if (argv[1]) { | 52 | if (argv[1]) { |
diff --git a/util-linux/freeramdisk.c b/util-linux/freeramdisk.c index 55187cb40..6752e49d8 100644 --- a/util-linux/freeramdisk.c +++ b/util-linux/freeramdisk.c | |||
@@ -33,9 +33,9 @@ | |||
33 | //config: ramdisk. If you have no use for freeing memory from a ramdisk, leave | 33 | //config: ramdisk. If you have no use for freeing memory from a ramdisk, leave |
34 | //config: this disabled. | 34 | //config: this disabled. |
35 | 35 | ||
36 | // APPLET_ODDNAME:name main location suid_type help | 36 | // APPLET_ODDNAME:name main location suid_type help |
37 | //applet:IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush)) | 37 | //applet:IF_FDFLUSH( APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush )) |
38 | //applet:IF_FREERAMDISK(APPLET(freeramdisk, BB_DIR_SBIN, BB_SUID_DROP)) | 38 | //applet:IF_FREERAMDISK(APPLET_NOEXEC(freeramdisk, freeramdisk, BB_DIR_SBIN, BB_SUID_DROP, freeramdisk)) |
39 | 39 | ||
40 | //kbuild:lib-$(CONFIG_FDFLUSH) += freeramdisk.o | 40 | //kbuild:lib-$(CONFIG_FDFLUSH) += freeramdisk.o |
41 | //kbuild:lib-$(CONFIG_FREERAMDISK) += freeramdisk.o | 41 | //kbuild:lib-$(CONFIG_FREERAMDISK) += freeramdisk.o |
@@ -67,8 +67,12 @@ int freeramdisk_main(int argc UNUSED_PARAM, char **argv) | |||
67 | fd = xopen(single_argv(argv), O_RDWR); | 67 | fd = xopen(single_argv(argv), O_RDWR); |
68 | 68 | ||
69 | // Act like freeramdisk, fdflush, or both depending on configuration. | 69 | // Act like freeramdisk, fdflush, or both depending on configuration. |
70 | ioctl_or_perror_and_die(fd, (ENABLE_FREERAMDISK && applet_name[1] == 'r') | 70 | ioctl_or_perror_and_die(fd, |
71 | || !ENABLE_FDFLUSH ? BLKFLSBUF : FDFLUSH, NULL, "%s", argv[1]); | 71 | ((ENABLE_FREERAMDISK && applet_name[1] == 'r') || !ENABLE_FDFLUSH) |
72 | ? BLKFLSBUF | ||
73 | : FDFLUSH, | ||
74 | NULL, "%s", argv[1] | ||
75 | ); | ||
72 | 76 | ||
73 | if (ENABLE_FEATURE_CLEAN_UP) close(fd); | 77 | if (ENABLE_FEATURE_CLEAN_UP) close(fd); |
74 | 78 | ||
diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c index 8c2b7d8de..c4612f251 100644 --- a/util-linux/fsck_minix.c +++ b/util-linux/fsck_minix.c | |||
@@ -173,7 +173,10 @@ struct globals { | |||
173 | 173 | ||
174 | /* Bigger stuff */ | 174 | /* Bigger stuff */ |
175 | struct termios sv_termios; | 175 | struct termios sv_termios; |
176 | char superblock_buffer[BLOCK_SIZE]; | 176 | union { |
177 | char superblock_buffer[BLOCK_SIZE]; | ||
178 | struct minix_superblock Super; | ||
179 | } u; | ||
177 | char add_zone_ind_blk[BLOCK_SIZE]; | 180 | char add_zone_ind_blk[BLOCK_SIZE]; |
178 | char add_zone_dind_blk[BLOCK_SIZE]; | 181 | char add_zone_dind_blk[BLOCK_SIZE]; |
179 | IF_FEATURE_MINIX2(char add_zone_tind_blk[BLOCK_SIZE];) | 182 | IF_FEATURE_MINIX2(char add_zone_tind_blk[BLOCK_SIZE];) |
@@ -207,7 +210,7 @@ struct globals { | |||
207 | #define name_depth (G.name_depth ) | 210 | #define name_depth (G.name_depth ) |
208 | #define name_component (G.name_component ) | 211 | #define name_component (G.name_component ) |
209 | #define sv_termios (G.sv_termios ) | 212 | #define sv_termios (G.sv_termios ) |
210 | #define superblock_buffer (G.superblock_buffer ) | 213 | #define superblock_buffer (G.u.superblock_buffer) |
211 | #define add_zone_ind_blk (G.add_zone_ind_blk ) | 214 | #define add_zone_ind_blk (G.add_zone_ind_blk ) |
212 | #define add_zone_dind_blk (G.add_zone_dind_blk ) | 215 | #define add_zone_dind_blk (G.add_zone_dind_blk ) |
213 | #define add_zone_tind_blk (G.add_zone_tind_blk ) | 216 | #define add_zone_tind_blk (G.add_zone_tind_blk ) |
@@ -247,7 +250,7 @@ enum { | |||
247 | #define Inode1 (((struct minix1_inode *) inode_buffer)-1) | 250 | #define Inode1 (((struct minix1_inode *) inode_buffer)-1) |
248 | #define Inode2 (((struct minix2_inode *) inode_buffer)-1) | 251 | #define Inode2 (((struct minix2_inode *) inode_buffer)-1) |
249 | 252 | ||
250 | #define Super (*(struct minix_superblock *)(superblock_buffer)) | 253 | #define Super (G.u.Super) |
251 | 254 | ||
252 | #if ENABLE_FEATURE_MINIX2 | 255 | #if ENABLE_FEATURE_MINIX2 |
253 | # define ZONES ((unsigned)(version2 ? Super.s_zones : Super.s_nzones)) | 256 | # define ZONES ((unsigned)(version2 ? Super.s_zones : Super.s_nzones)) |
@@ -1232,8 +1235,7 @@ int fsck_minix_main(int argc UNUSED_PARAM, char **argv) | |||
1232 | 1235 | ||
1233 | INIT_G(); | 1236 | INIT_G(); |
1234 | 1237 | ||
1235 | opt_complementary = "=1:ar"; /* one argument; -a assumes -r */ | 1238 | getopt32(argv, "^" OPTION_STR "\0" "=1:ar" /* one arg; -a assumes -r */); |
1236 | getopt32(argv, OPTION_STR); | ||
1237 | argv += optind; | 1239 | argv += optind; |
1238 | device_name = argv[0]; | 1240 | device_name = argv[0]; |
1239 | 1241 | ||
diff --git a/util-linux/fsfreeze.c b/util-linux/fsfreeze.c index 5c10c8044..2e2257337 100644 --- a/util-linux/fsfreeze.c +++ b/util-linux/fsfreeze.c | |||
@@ -13,7 +13,7 @@ | |||
13 | //config: help | 13 | //config: help |
14 | //config: Halt new accesses and flush writes on a mounted filesystem. | 14 | //config: Halt new accesses and flush writes on a mounted filesystem. |
15 | 15 | ||
16 | //applet:IF_FSFREEZE(APPLET(fsfreeze, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 16 | //applet:IF_FSFREEZE(APPLET_NOEXEC(fsfreeze, fsfreeze, BB_DIR_USR_SBIN, BB_SUID_DROP, fsfreeze)) |
17 | 17 | ||
18 | //kbuild:lib-$(CONFIG_FSFREEZE) += fsfreeze.o | 18 | //kbuild:lib-$(CONFIG_FSFREEZE) += fsfreeze.o |
19 | 19 | ||
@@ -36,15 +36,15 @@ int fsfreeze_main(int argc UNUSED_PARAM, char **argv) | |||
36 | unsigned opts; | 36 | unsigned opts; |
37 | int fd; | 37 | int fd; |
38 | 38 | ||
39 | applet_long_options = | ||
40 | "freeze\0" No_argument "\xff" | ||
41 | "unfreeze\0" No_argument "\xfe" | ||
42 | ; | ||
43 | /* exactly one non-option arg: the mountpoint */ | 39 | /* exactly one non-option arg: the mountpoint */ |
44 | /* one of opts is required */ | 40 | /* one of opts is required */ |
45 | /* opts are mutually exclusive */ | 41 | /* opts are mutually exclusive */ |
46 | opt_complementary = "=1:""\xff:\xfe:""\xff--\xfe:\xfe--\xff"; | 42 | opts = getopt32long(argv, "^" |
47 | opts = getopt32(argv, ""); | 43 | "" /* no opts */ |
44 | "\0" "=1:""\xff:\xfe:""\xff--\xfe:\xfe--\xff", | ||
45 | "freeze\0" No_argument "\xff" | ||
46 | "unfreeze\0" No_argument "\xfe" | ||
47 | ); | ||
48 | 48 | ||
49 | fd = xopen(argv[optind], O_RDONLY); | 49 | fd = xopen(argv[optind], O_RDONLY); |
50 | /* Works with NULL arg on linux-4.8.0 */ | 50 | /* Works with NULL arg on linux-4.8.0 */ |
diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c index 6d0d61d92..4acfa567a 100644 --- a/util-linux/fstrim.c +++ b/util-linux/fstrim.c | |||
@@ -15,7 +15,7 @@ | |||
15 | //config: help | 15 | //config: help |
16 | //config: Discard unused blocks on a mounted filesystem. | 16 | //config: Discard unused blocks on a mounted filesystem. |
17 | 17 | ||
18 | //applet:IF_FSTRIM(APPLET(fstrim, BB_DIR_SBIN, BB_SUID_DROP)) | 18 | //applet:IF_FSTRIM(APPLET_NOEXEC(fstrim, fstrim, BB_DIR_SBIN, BB_SUID_DROP, fstrim)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_FSTRIM) += fstrim.o | 20 | //kbuild:lib-$(CONFIG_FSTRIM) += fstrim.o |
21 | 21 | ||
@@ -63,17 +63,17 @@ int fstrim_main(int argc UNUSED_PARAM, char **argv) | |||
63 | }; | 63 | }; |
64 | 64 | ||
65 | #if ENABLE_LONG_OPTS | 65 | #if ENABLE_LONG_OPTS |
66 | static const char getopt_longopts[] ALIGN1 = | 66 | static const char fstrim_longopts[] ALIGN1 = |
67 | "offset\0" Required_argument "o" | 67 | "offset\0" Required_argument "o" |
68 | "length\0" Required_argument "l" | 68 | "length\0" Required_argument "l" |
69 | "minimum\0" Required_argument "m" | 69 | "minimum\0" Required_argument "m" |
70 | "verbose\0" No_argument "v" | 70 | "verbose\0" No_argument "v" |
71 | ; | 71 | ; |
72 | applet_long_options = getopt_longopts; | ||
73 | #endif | 72 | #endif |
74 | 73 | ||
75 | opt_complementary = "=1"; /* exactly one non-option arg: the mountpoint */ | 74 | opts = getopt32long(argv, "^" "o:l:m:v" "\0" "=1", fstrim_longopts, |
76 | opts = getopt32(argv, "o:l:m:v", &arg_o, &arg_l, &arg_m); | 75 | &arg_o, &arg_l, &arg_m |
76 | ); | ||
77 | 77 | ||
78 | memset(&range, 0, sizeof(range)); | 78 | memset(&range, 0, sizeof(range)); |
79 | range.len = ULLONG_MAX; | 79 | range.len = ULLONG_MAX; |
diff --git a/util-linux/getopt.c b/util-linux/getopt.c index cf1bc592f..a151b7e56 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c | |||
@@ -42,32 +42,18 @@ | |||
42 | //config: | 42 | //config: |
43 | //config:config FEATURE_GETOPT_LONG | 43 | //config:config FEATURE_GETOPT_LONG |
44 | //config: bool "Support -l LONGOPTs" | 44 | //config: bool "Support -l LONGOPTs" |
45 | //config: default y if LONG_OPTS | 45 | //config: default y |
46 | //config: depends on GETOPT | 46 | //config: depends on GETOPT && LONG_OPTS |
47 | //config: help | 47 | //config: help |
48 | //config: Enable support for long options (option -l). | 48 | //config: Enable support for long options (option -l). |
49 | 49 | ||
50 | //applet:IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP)) | 50 | //applet:IF_GETOPT(APPLET_NOEXEC(getopt, getopt, BB_DIR_BIN, BB_SUID_DROP, getopt)) |
51 | 51 | ||
52 | //kbuild:lib-$(CONFIG_GETOPT) += getopt.o | 52 | //kbuild:lib-$(CONFIG_GETOPT) += getopt.o |
53 | 53 | ||
54 | //usage:#define getopt_trivial_usage | 54 | //usage:#define getopt_trivial_usage |
55 | //usage: "[OPTIONS] [--] OPTSTRING PARAMS" | 55 | //usage: "[OPTIONS] [--] OPTSTRING PARAMS" |
56 | //usage:#define getopt_full_usage "\n\n" | 56 | //usage:#define getopt_full_usage "\n\n" |
57 | //usage: IF_LONG_OPTS( | ||
58 | //usage: IF_FEATURE_GETOPT_LONG( | ||
59 | //usage: " -a,--alternative Allow long options starting with single -\n" | ||
60 | //usage: " -l,--longoptions LOPT[,...] Long options to recognize\n" | ||
61 | //usage: ) | ||
62 | //usage: " -n,--name PROGNAME The name under which errors are reported" | ||
63 | //usage: "\n -o,--options OPTSTRING Short options to recognize" | ||
64 | //usage: "\n -q,--quiet No error messages on unrecognized options" | ||
65 | //usage: "\n -Q,--quiet-output No normal output" | ||
66 | //usage: "\n -s,--shell SHELL Set shell quoting conventions" | ||
67 | //usage: "\n -T,--test Version test (exits with 4)" | ||
68 | //usage: "\n -u,--unquoted Don't quote output" | ||
69 | //usage: ) | ||
70 | //usage: IF_NOT_LONG_OPTS( | ||
71 | //usage: IF_FEATURE_GETOPT_LONG( | 57 | //usage: IF_FEATURE_GETOPT_LONG( |
72 | //usage: " -a Allow long options starting with single -\n" | 58 | //usage: " -a Allow long options starting with single -\n" |
73 | //usage: " -l LOPT[,...] Long options to recognize\n" | 59 | //usage: " -l LOPT[,...] Long options to recognize\n" |
@@ -79,7 +65,6 @@ | |||
79 | //usage: "\n -s SHELL Set shell quoting conventions" | 65 | //usage: "\n -s SHELL Set shell quoting conventions" |
80 | //usage: "\n -T Version test (exits with 4)" | 66 | //usage: "\n -T Version test (exits with 4)" |
81 | //usage: "\n -u Don't quote output" | 67 | //usage: "\n -u Don't quote output" |
82 | //usage: ) | ||
83 | //usage: IF_FEATURE_GETOPT_LONG( /* example uses -l, needs FEATURE_GETOPT_LONG */ | 68 | //usage: IF_FEATURE_GETOPT_LONG( /* example uses -l, needs FEATURE_GETOPT_LONG */ |
84 | //usage: "\n" | 69 | //usage: "\n" |
85 | //usage: "\nExample:" | 70 | //usage: "\nExample:" |
@@ -411,8 +396,7 @@ int getopt_main(int argc, char **argv) | |||
411 | #if !ENABLE_FEATURE_GETOPT_LONG | 396 | #if !ENABLE_FEATURE_GETOPT_LONG |
412 | opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg); | 397 | opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg); |
413 | #else | 398 | #else |
414 | applet_long_options = getopt_longopts; | 399 | opt = getopt32long(argv, "+o:n:qQs:Tual:*", getopt_longopts, |
415 | opt = getopt32(argv, "+o:n:qQs:Tual:*", | ||
416 | &optstr, &name, &s_arg, &l_arg); | 400 | &optstr, &name, &s_arg, &l_arg); |
417 | /* Effectuate the read options for the applet itself */ | 401 | /* Effectuate the read options for the applet itself */ |
418 | while (l_arg) { | 402 | while (l_arg) { |
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 37e58f2d0..6cf6d0297 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -73,8 +73,9 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
73 | #define OPT_s (1 << 1) | 73 | #define OPT_s (1 << 1) |
74 | #define OPT_a (1 << 2) | 74 | #define OPT_a (1 << 2) |
75 | #define OPT_p (1 << 3) | 75 | #define OPT_p (1 << 3) |
76 | opt_complementary = "?1"; /* 1 argument max */ | 76 | opt = getopt32(argv, "^" "l:s:apg:+c:+" "\0" "?1" /* 1 argument max */, |
77 | opt = getopt32(argv, "l:s:apg:+c:+", &opt_l, &opt_s, &bytes, &cols); | 77 | &opt_l, &opt_s, &bytes, &cols |
78 | ); | ||
78 | argv += optind; | 79 | argv += optind; |
79 | 80 | ||
80 | dumper->dump_vflag = ALL; | 81 | dumper->dump_vflag = ALL; |
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c index 5df56de15..29f51021e 100644 --- a/util-linux/hwclock.c +++ b/util-linux/hwclock.c | |||
@@ -16,11 +16,6 @@ | |||
16 | //config: shutdown in the hardware clock, so the hardware will keep the | 16 | //config: shutdown in the hardware clock, so the hardware will keep the |
17 | //config: correct time when Linux is _not_ running. | 17 | //config: correct time when Linux is _not_ running. |
18 | //config: | 18 | //config: |
19 | //config:config FEATURE_HWCLOCK_LONG_OPTIONS | ||
20 | //config: bool "Support long options (--hctosys,...)" | ||
21 | //config: default y | ||
22 | //config: depends on HWCLOCK && LONG_OPTS | ||
23 | //config: | ||
24 | //config:config FEATURE_HWCLOCK_ADJTIME_FHS | 19 | //config:config FEATURE_HWCLOCK_ADJTIME_FHS |
25 | //config: bool "Use FHS /var/lib/hwclock/adjtime" | 20 | //config: bool "Use FHS /var/lib/hwclock/adjtime" |
26 | //config: default n # util-linux-ng in Fedora 13 still uses /etc/adjtime | 21 | //config: default n # util-linux-ng in Fedora 13 still uses /etc/adjtime |
@@ -293,12 +288,12 @@ static void set_system_clock_timezone(int utc) | |||
293 | } | 288 | } |
294 | 289 | ||
295 | //usage:#define hwclock_trivial_usage | 290 | //usage:#define hwclock_trivial_usage |
296 | //usage: IF_FEATURE_HWCLOCK_LONG_OPTIONS( | 291 | //usage: IF_LONG_OPTS( |
297 | //usage: "[-r|--show] [-s|--hctosys] [-w|--systohc] [-t|--systz]" | 292 | //usage: "[-r|--show] [-s|--hctosys] [-w|--systohc] [--systz]" |
298 | //usage: " [-l|--localtime] [-u|--utc]" | 293 | //usage: " [--localtime] [-u|--utc]" |
299 | //usage: " [-f|--rtc FILE]" | 294 | //usage: " [-f|--rtc FILE]" |
300 | //usage: ) | 295 | //usage: ) |
301 | //usage: IF_NOT_FEATURE_HWCLOCK_LONG_OPTIONS( | 296 | //usage: IF_NOT_LONG_OPTS( |
302 | //usage: "[-r] [-s] [-w] [-t] [-l] [-u] [-f FILE]" | 297 | //usage: "[-r] [-s] [-w] [-t] [-l] [-u] [-f FILE]" |
303 | //usage: ) | 298 | //usage: ) |
304 | //usage:#define hwclock_full_usage "\n\n" | 299 | //usage:#define hwclock_full_usage "\n\n" |
@@ -306,12 +301,18 @@ static void set_system_clock_timezone(int utc) | |||
306 | //usage: "\n -r Show hardware clock time" | 301 | //usage: "\n -r Show hardware clock time" |
307 | //usage: "\n -s Set system time from hardware clock" | 302 | //usage: "\n -s Set system time from hardware clock" |
308 | //usage: "\n -w Set hardware clock from system time" | 303 | //usage: "\n -w Set hardware clock from system time" |
309 | //usage: "\n -t Set in-kernel timezone, correct system time" | 304 | //usage: IF_LONG_OPTS( |
305 | //usage: "\n --systz Set in-kernel timezone, correct system time" | ||
306 | //usage: ) | ||
310 | //usage: "\n if hardware clock is in local time" | 307 | //usage: "\n if hardware clock is in local time" |
311 | //usage: "\n -u Assume hardware clock is kept in UTC" | 308 | //usage: "\n -u Assume hardware clock is kept in UTC" |
312 | //usage: "\n -l Assume hardware clock is kept in local time" | 309 | //usage: IF_LONG_OPTS( |
310 | //usage: "\n --localtime Assume hardware clock is kept in local time" | ||
311 | //usage: ) | ||
313 | //usage: "\n -f FILE Use specified device (e.g. /dev/rtc2)" | 312 | //usage: "\n -f FILE Use specified device (e.g. /dev/rtc2)" |
314 | 313 | ||
314 | //TODO: get rid of incompatible -t and -l aliases to --systz and --localtime | ||
315 | |||
315 | #define HWCLOCK_OPT_LOCALTIME 0x01 | 316 | #define HWCLOCK_OPT_LOCALTIME 0x01 |
316 | #define HWCLOCK_OPT_UTC 0x02 | 317 | #define HWCLOCK_OPT_UTC 0x02 |
317 | #define HWCLOCK_OPT_SHOW 0x04 | 318 | #define HWCLOCK_OPT_SHOW 0x04 |
@@ -327,7 +328,7 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv) | |||
327 | unsigned opt; | 328 | unsigned opt; |
328 | int utc; | 329 | int utc; |
329 | 330 | ||
330 | #if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS | 331 | #if ENABLE_LONG_OPTS |
331 | static const char hwclock_longopts[] ALIGN1 = | 332 | static const char hwclock_longopts[] ALIGN1 = |
332 | "localtime\0" No_argument "l" /* short opt is non-standard */ | 333 | "localtime\0" No_argument "l" /* short opt is non-standard */ |
333 | "utc\0" No_argument "u" | 334 | "utc\0" No_argument "u" |
@@ -337,14 +338,16 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv) | |||
337 | "systz\0" No_argument "t" /* short opt is non-standard */ | 338 | "systz\0" No_argument "t" /* short opt is non-standard */ |
338 | "rtc\0" Required_argument "f" | 339 | "rtc\0" Required_argument "f" |
339 | ; | 340 | ; |
340 | applet_long_options = hwclock_longopts; | ||
341 | #endif | 341 | #endif |
342 | 342 | ||
343 | /* Initialize "timezone" (libc global variable) */ | 343 | /* Initialize "timezone" (libc global variable) */ |
344 | tzset(); | 344 | tzset(); |
345 | 345 | ||
346 | opt_complementary = "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l"; | 346 | opt = getopt32long(argv, |
347 | opt = getopt32(argv, "lurswtf:", &rtcname); | 347 | "^lurswtf:" "\0" "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l", |
348 | hwclock_longopts, | ||
349 | &rtcname | ||
350 | ); | ||
348 | 351 | ||
349 | /* If -u or -l wasn't given check if we are using utc */ | 352 | /* If -u or -l wasn't given check if we are using utc */ |
350 | if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) | 353 | if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) |
diff --git a/util-linux/ionice.c b/util-linux/ionice.c index c7b7f0373..5b9664d25 100644 --- a/util-linux/ionice.c +++ b/util-linux/ionice.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: Set/set program io scheduling class and priority | 14 | //config: Set/set program io scheduling class and priority |
15 | //config: Requires kernel >= 2.6.13 | 15 | //config: Requires kernel >= 2.6.13 |
16 | 16 | ||
17 | //applet:IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_IONICE(APPLET_NOEXEC(ionice, ionice, BB_DIR_BIN, BB_SUID_DROP, ionice)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_IONICE) += ionice.o | 19 | //kbuild:lib-$(CONFIG_IONICE) += ionice.o |
20 | 20 | ||
diff --git a/util-linux/ipcrm.c b/util-linux/ipcrm.c index c51d33143..a93ceee11 100644 --- a/util-linux/ipcrm.c +++ b/util-linux/ipcrm.c | |||
@@ -15,19 +15,10 @@ | |||
15 | //config: communication (IPC) objects and the associated data structures | 15 | //config: communication (IPC) objects and the associated data structures |
16 | //config: from the system. | 16 | //config: from the system. |
17 | 17 | ||
18 | //applet:IF_IPCRM(APPLET(ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_IPCRM(APPLET_NOEXEC(ipcrm, ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP, ipcrm)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_IPCRM) += ipcrm.o | 20 | //kbuild:lib-$(CONFIG_IPCRM) += ipcrm.o |
21 | 21 | ||
22 | //usage:#define ipcrm_trivial_usage | ||
23 | //usage: "[-MQS key] [-mqs id]" | ||
24 | //usage:#define ipcrm_full_usage "\n\n" | ||
25 | //usage: "Upper-case options MQS remove an object by shmkey value.\n" | ||
26 | //usage: "Lower-case options remove an object by shmid value.\n" | ||
27 | //usage: "\n -mM Remove memory segment after last detach" | ||
28 | //usage: "\n -qQ Remove message queue" | ||
29 | //usage: "\n -sS Remove semaphore" | ||
30 | |||
31 | #include "libbb.h" | 22 | #include "libbb.h" |
32 | 23 | ||
33 | /* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */ | 24 | /* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */ |
@@ -94,6 +85,14 @@ static int remove_ids(type_id type, char **argv) | |||
94 | } | 85 | } |
95 | #endif /* IPCRM_LEGACY */ | 86 | #endif /* IPCRM_LEGACY */ |
96 | 87 | ||
88 | //usage:#define ipcrm_trivial_usage | ||
89 | //usage: "[-MQS key] [-mqs id]" | ||
90 | //usage:#define ipcrm_full_usage "\n\n" | ||
91 | //usage: "Upper-case options MQS remove an object by shmkey value.\n" | ||
92 | //usage: "Lower-case options remove an object by shmid value.\n" | ||
93 | //usage: "\n -mM Remove memory segment after last detach" | ||
94 | //usage: "\n -qQ Remove message queue" | ||
95 | //usage: "\n -sS Remove semaphore" | ||
97 | 96 | ||
98 | int ipcrm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 97 | int ipcrm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
99 | int ipcrm_main(int argc, char **argv) | 98 | int ipcrm_main(int argc, char **argv) |
@@ -137,28 +136,20 @@ int ipcrm_main(int argc, char **argv) | |||
137 | #endif /* IPCRM_LEGACY */ | 136 | #endif /* IPCRM_LEGACY */ |
138 | 137 | ||
139 | /* process new syntax to conform with SYSV ipcrm */ | 138 | /* process new syntax to conform with SYSV ipcrm */ |
140 | while ((c = getopt(argc, argv, "q:m:s:Q:M:S:h?")) != -1) { | 139 | while ((c = getopt(argc, argv, "q:m:s:Q:M:S:")) != -1) { |
141 | int result; | 140 | int result; |
142 | int id = 0; | 141 | int id; |
143 | int iskey = isupper(c); | 142 | int iskey; |
144 | |||
145 | /* needed to delete semaphores */ | 143 | /* needed to delete semaphores */ |
146 | union semun arg; | 144 | union semun arg; |
147 | 145 | ||
148 | arg.val = 0; | 146 | if (c == '?') /* option not in the string */ |
149 | |||
150 | if ((c == '?') || (c == 'h')) { | ||
151 | bb_show_usage(); | 147 | bb_show_usage(); |
152 | } | ||
153 | |||
154 | /* we don't need case information any more */ | ||
155 | c = tolower(c); | ||
156 | 148 | ||
157 | /* make sure the option is in range: allowed are q, m, s */ | 149 | id = 0; |
158 | if (c != 'q' && c != 'm' && c != 's') { | 150 | arg.val = 0; |
159 | bb_show_usage(); | ||
160 | } | ||
161 | 151 | ||
152 | iskey = !(c & 0x20); /* uppercase? */ | ||
162 | if (iskey) { | 153 | if (iskey) { |
163 | /* keys are in hex or decimal */ | 154 | /* keys are in hex or decimal */ |
164 | key_t key = xstrtoul(optarg, 0); | 155 | key_t key = xstrtoul(optarg, 0); |
@@ -169,6 +160,7 @@ int ipcrm_main(int argc, char **argv) | |||
169 | continue; | 160 | continue; |
170 | } | 161 | } |
171 | 162 | ||
163 | c |= 0x20; /* lowercase. c is 'q', 'm' or 's' now */ | ||
172 | /* convert key to id */ | 164 | /* convert key to id */ |
173 | id = ((c == 'q') ? msgget(key, 0) : | 165 | id = ((c == 'q') ? msgget(key, 0) : |
174 | (c == 'm') ? shmget(key, 0, 0) : semget(key, 0, 0)); | 166 | (c == 'm') ? shmget(key, 0, 0) : semget(key, 0, 0)); |
diff --git a/util-linux/ipcs.c b/util-linux/ipcs.c index 1404930d4..7092ecd92 100644 --- a/util-linux/ipcs.c +++ b/util-linux/ipcs.c | |||
@@ -15,26 +15,10 @@ | |||
15 | //config: The ipcs utility is used to provide information on the currently | 15 | //config: The ipcs utility is used to provide information on the currently |
16 | //config: allocated System V interprocess (IPC) objects in the system. | 16 | //config: allocated System V interprocess (IPC) objects in the system. |
17 | 17 | ||
18 | //applet:IF_IPCS(APPLET(ipcs, BB_DIR_USR_BIN, BB_SUID_DROP)) | 18 | //applet:IF_IPCS(APPLET_NOEXEC(ipcs, ipcs, BB_DIR_USR_BIN, BB_SUID_DROP, ipcs)) |
19 | 19 | ||
20 | //kbuild:lib-$(CONFIG_IPCS) += ipcs.o | 20 | //kbuild:lib-$(CONFIG_IPCS) += ipcs.o |
21 | 21 | ||
22 | //usage:#define ipcs_trivial_usage | ||
23 | //usage: "[[-smq] -i shmid] | [[-asmq] [-tcplu]]" | ||
24 | //usage:#define ipcs_full_usage "\n\n" | ||
25 | //usage: " -i Show specific resource" | ||
26 | //usage: "\nResource specification:" | ||
27 | //usage: "\n -m Shared memory segments" | ||
28 | //usage: "\n -q Message queues" | ||
29 | //usage: "\n -s Semaphore arrays" | ||
30 | //usage: "\n -a All (default)" | ||
31 | //usage: "\nOutput format:" | ||
32 | //usage: "\n -t Time" | ||
33 | //usage: "\n -c Creator" | ||
34 | //usage: "\n -p Pid" | ||
35 | //usage: "\n -l Limits" | ||
36 | //usage: "\n -u Summary" | ||
37 | |||
38 | /* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */ | 22 | /* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */ |
39 | /* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */ | 23 | /* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */ |
40 | /* X/OPEN tells us to use <sys/{types,ipc,shm}.h> for shmctl() */ | 24 | /* X/OPEN tells us to use <sys/{types,ipc,shm}.h> for shmctl() */ |
@@ -585,6 +569,22 @@ static void print_sem(int semid) | |||
585 | bb_putchar('\n'); | 569 | bb_putchar('\n'); |
586 | } | 570 | } |
587 | 571 | ||
572 | //usage:#define ipcs_trivial_usage | ||
573 | //usage: "[[-smq] -i shmid] | [[-asmq] [-tcplu]]" | ||
574 | //usage:#define ipcs_full_usage "\n\n" | ||
575 | //usage: " -i Show specific resource" | ||
576 | //usage: "\nResource specification:" | ||
577 | //usage: "\n -m Shared memory segments" | ||
578 | //usage: "\n -q Message queues" | ||
579 | //usage: "\n -s Semaphore arrays" | ||
580 | //usage: "\n -a All (default)" | ||
581 | //usage: "\nOutput format:" | ||
582 | //usage: "\n -t Time" | ||
583 | //usage: "\n -c Creator" | ||
584 | //usage: "\n -p Pid" | ||
585 | //usage: "\n -l Limits" | ||
586 | //usage: "\n -u Summary" | ||
587 | |||
588 | int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 588 | int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
589 | int ipcs_main(int argc UNUSED_PARAM, char **argv) | 589 | int ipcs_main(int argc UNUSED_PARAM, char **argv) |
590 | { | 590 | { |
@@ -632,6 +632,10 @@ int ipcs_main(int argc UNUSED_PARAM, char **argv) | |||
632 | flags |= flag_msg | flag_shm | flag_sem; | 632 | flags |= flag_msg | flag_shm | flag_sem; |
633 | bb_putchar('\n'); | 633 | bb_putchar('\n'); |
634 | 634 | ||
635 | if (flags & flag_msg) { | ||
636 | do_msg(); | ||
637 | bb_putchar('\n'); | ||
638 | } | ||
635 | if (flags & flag_shm) { | 639 | if (flags & flag_shm) { |
636 | do_shm(); | 640 | do_shm(); |
637 | bb_putchar('\n'); | 641 | bb_putchar('\n'); |
@@ -640,9 +644,5 @@ int ipcs_main(int argc UNUSED_PARAM, char **argv) | |||
640 | do_sem(); | 644 | do_sem(); |
641 | bb_putchar('\n'); | 645 | bb_putchar('\n'); |
642 | } | 646 | } |
643 | if (flags & flag_msg) { | ||
644 | do_msg(); | ||
645 | bb_putchar('\n'); | ||
646 | } | ||
647 | fflush_stdout_and_exit(EXIT_SUCCESS); | 647 | fflush_stdout_and_exit(EXIT_SUCCESS); |
648 | } | 648 | } |
diff --git a/util-linux/losetup.c b/util-linux/losetup.c index c608de6cc..6b171d710 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c | |||
@@ -15,9 +15,9 @@ | |||
15 | //config: file or block device, and to query the status of a loop device. This | 15 | //config: file or block device, and to query the status of a loop device. This |
16 | //config: version does not currently support enabling data encryption. | 16 | //config: version does not currently support enabling data encryption. |
17 | 17 | ||
18 | //kbuild:lib-$(CONFIG_LOSETUP) += losetup.o | 18 | //applet:IF_LOSETUP(APPLET_NOEXEC(losetup, losetup, BB_DIR_SBIN, BB_SUID_DROP, losetup)) |
19 | 19 | ||
20 | //applet:IF_LOSETUP(APPLET(losetup, BB_DIR_SBIN, BB_SUID_DROP)) | 20 | //kbuild:lib-$(CONFIG_LOSETUP) += losetup.o |
21 | 21 | ||
22 | //usage:#define losetup_trivial_usage | 22 | //usage:#define losetup_trivial_usage |
23 | //usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" | 23 | //usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" |
@@ -57,8 +57,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv) | |||
57 | OPT_r = (1 << 4), /* must be last */ | 57 | OPT_r = (1 << 4), /* must be last */ |
58 | }; | 58 | }; |
59 | 59 | ||
60 | opt_complementary = "?2:d--ofar:a--ofr"; | 60 | opt = getopt32(argv, "^" "do:far" "\0" "?2:d--ofar:a--ofr", &opt_o); |
61 | opt = getopt32(argv, "do:far", &opt_o); | ||
62 | argv += optind; | 61 | argv += optind; |
63 | 62 | ||
64 | /* LOOPDEV */ | 63 | /* LOOPDEV */ |
diff --git a/util-linux/lspci.c b/util-linux/lspci.c index 3877deb67..0000fbfda 100644 --- a/util-linux/lspci.c +++ b/util-linux/lspci.c | |||
@@ -16,7 +16,7 @@ | |||
16 | //config: | 16 | //config: |
17 | //config: This version uses sysfs (/sys/bus/pci/devices) only. | 17 | //config: This version uses sysfs (/sys/bus/pci/devices) only. |
18 | 18 | ||
19 | //applet:IF_LSPCI(APPLET(lspci, BB_DIR_USR_BIN, BB_SUID_DROP)) | 19 | //applet:IF_LSPCI(APPLET_NOEXEC(lspci, lspci, BB_DIR_USR_BIN, BB_SUID_DROP, lspci)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_LSPCI) += lspci.o | 21 | //kbuild:lib-$(CONFIG_LSPCI) += lspci.o |
22 | 22 | ||
diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c index cabf047cf..33639413a 100644 --- a/util-linux/lsusb.c +++ b/util-linux/lsusb.c | |||
@@ -16,7 +16,7 @@ | |||
16 | //config: | 16 | //config: |
17 | //config: This version uses sysfs (/sys/bus/usb/devices) only. | 17 | //config: This version uses sysfs (/sys/bus/usb/devices) only. |
18 | 18 | ||
19 | //applet:IF_LSUSB(APPLET(lsusb, BB_DIR_USR_BIN, BB_SUID_DROP)) | 19 | //applet:IF_LSUSB(APPLET_NOEXEC(lsusb, lsusb, BB_DIR_USR_BIN, BB_SUID_DROP, lsusb)) |
20 | 20 | ||
21 | //kbuild:lib-$(CONFIG_LSUSB) += lsusb.o | 21 | //kbuild:lib-$(CONFIG_LSUSB) += lsusb.o |
22 | 22 | ||
diff --git a/util-linux/mesg.c b/util-linux/mesg.c index c4371eb24..91c05317e 100644 --- a/util-linux/mesg.c +++ b/util-linux/mesg.c | |||
@@ -26,7 +26,7 @@ | |||
26 | //config: If you set this option to N, "mesg y" will enable writing | 26 | //config: If you set this option to N, "mesg y" will enable writing |
27 | //config: by anybody at all. This is not recommended. | 27 | //config: by anybody at all. This is not recommended. |
28 | 28 | ||
29 | //applet:IF_MESG(APPLET(mesg, BB_DIR_USR_BIN, BB_SUID_DROP)) | 29 | //applet:IF_MESG(APPLET_NOFORK(mesg, mesg, BB_DIR_USR_BIN, BB_SUID_DROP, mesg)) |
30 | 30 | ||
31 | //kbuild:lib-$(CONFIG_MESG) += mesg.o | 31 | //kbuild:lib-$(CONFIG_MESG) += mesg.o |
32 | 32 | ||
@@ -60,10 +60,15 @@ int mesg_main(int argc UNUSED_PARAM, char **argv) | |||
60 | bb_show_usage(); | 60 | bb_show_usage(); |
61 | } | 61 | } |
62 | 62 | ||
63 | /* We are a NOFORK applet. | ||
64 | * (Not that it's very useful, but code is trivially NOFORK-safe). | ||
65 | * Play nice. Do not leak anything. | ||
66 | */ | ||
67 | |||
63 | if (!isatty(STDIN_FILENO)) | 68 | if (!isatty(STDIN_FILENO)) |
64 | bb_error_msg_and_die("not a tty"); | 69 | bb_error_msg_and_die("not a tty"); |
65 | 70 | ||
66 | xfstat(STDIN_FILENO, &sb, "stderr"); | 71 | xfstat(STDIN_FILENO, &sb, "stdin"); |
67 | if (c == 0) { | 72 | if (c == 0) { |
68 | puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); | 73 | puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); |
69 | return EXIT_SUCCESS; | 74 | return EXIT_SUCCESS; |
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c index 88647e9d8..69dfcd123 100644 --- a/util-linux/mkfs_minix.c +++ b/util-linux/mkfs_minix.c | |||
@@ -142,7 +142,10 @@ struct globals { | |||
142 | unsigned currently_testing; | 142 | unsigned currently_testing; |
143 | 143 | ||
144 | char root_block[BLOCK_SIZE]; | 144 | char root_block[BLOCK_SIZE]; |
145 | char superblock_buffer[BLOCK_SIZE]; | 145 | union { |
146 | char superblock_buffer[BLOCK_SIZE]; | ||
147 | struct minix_superblock SB; | ||
148 | } u; | ||
146 | char boot_block_buffer[512]; | 149 | char boot_block_buffer[512]; |
147 | unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; | 150 | unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; |
148 | /* check_blocks(): buffer[] was the biggest static in entire bbox */ | 151 | /* check_blocks(): buffer[] was the biggest static in entire bbox */ |
@@ -166,7 +169,7 @@ static ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n) | |||
166 | #define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1) | 169 | #define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1) |
167 | #define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1) | 170 | #define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1) |
168 | 171 | ||
169 | #define SB (*(struct minix_superblock*)G.superblock_buffer) | 172 | #define SB (G.u.SB) |
170 | 173 | ||
171 | #define SB_INODES (SB.s_ninodes) | 174 | #define SB_INODES (SB.s_ninodes) |
172 | #define SB_IMAPS (SB.s_imap_blocks) | 175 | #define SB_IMAPS (SB.s_imap_blocks) |
@@ -234,7 +237,7 @@ static void write_tables(void) | |||
234 | xlseek(dev_fd, BLOCK_SIZE, SEEK_SET); | 237 | xlseek(dev_fd, BLOCK_SIZE, SEEK_SET); |
235 | 238 | ||
236 | msg_eol = "can't write superblock"; | 239 | msg_eol = "can't write superblock"; |
237 | xwrite(dev_fd, G.superblock_buffer, BLOCK_SIZE); | 240 | xwrite(dev_fd, G.u.superblock_buffer, BLOCK_SIZE); |
238 | 241 | ||
239 | msg_eol = "can't write inode map"; | 242 | msg_eol = "can't write inode map"; |
240 | xwrite(dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE); | 243 | xwrite(dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE); |
@@ -541,7 +544,7 @@ static void setup_tables(void) | |||
541 | unsigned sb_zmaps; | 544 | unsigned sb_zmaps; |
542 | unsigned i; | 545 | unsigned i; |
543 | 546 | ||
544 | /* memset(G.superblock_buffer, 0, BLOCK_SIZE); */ | 547 | /* memset(G.u.superblock_buffer, 0, BLOCK_SIZE); */ |
545 | /* memset(G.boot_block_buffer, 0, 512); */ | 548 | /* memset(G.boot_block_buffer, 0, 512); */ |
546 | SB_MAGIC = G.magic; | 549 | SB_MAGIC = G.magic; |
547 | SB_ZONE_SIZE = 0; | 550 | SB_ZONE_SIZE = 0; |
diff --git a/util-linux/mkfs_reiser.c b/util-linux/mkfs_reiser.c index c7d99b018..390aef86c 100644 --- a/util-linux/mkfs_reiser.c +++ b/util-linux/mkfs_reiser.c | |||
@@ -180,8 +180,7 @@ int mkfs_reiser_main(int argc UNUSED_PARAM, char **argv) | |||
180 | 180 | ||
181 | // using global "option_mask32" instead of local "opts": | 181 | // using global "option_mask32" instead of local "opts": |
182 | // we are register starved here | 182 | // we are register starved here |
183 | opt_complementary = "-1"; | 183 | /*opts =*/ getopt32(argv, "^" "b:+j:s:o:t:B:h:u:l:fqd" "\0" "-1", |
184 | /*opts =*/ getopt32(argv, "b:+j:s:o:t:B:h:u:l:fqd", | ||
185 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &label); | 184 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &label); |
186 | argv += optind; // argv[0] -- device | 185 | argv += optind; // argv[0] -- device |
187 | 186 | ||
diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c index f9768ed56..426854b1e 100644 --- a/util-linux/mkfs_vfat.c +++ b/util-linux/mkfs_vfat.c | |||
@@ -269,8 +269,9 @@ int mkfs_vfat_main(int argc UNUSED_PARAM, char **argv) | |||
269 | OPT_v = 1 << 16, // verbose | 269 | OPT_v = 1 << 16, // verbose |
270 | }; | 270 | }; |
271 | 271 | ||
272 | opt_complementary = "-1";//:b+:f+:F+:h+:r+:R+:s+:S+:vv:c--l:l--c"; | 272 | opts = getopt32(argv, "^" |
273 | opts = getopt32(argv, "Ab:cCf:F:h:Ii:l:m:n:r:R:s:S:v", | 273 | "Ab:cCf:F:h:Ii:l:m:n:r:R:s:S:v" |
274 | "\0" "-1", //:b+:f+:F+:h+:r+:R+:s+:S+:vv:c--l:l--c | ||
274 | NULL, NULL, NULL, NULL, NULL, | 275 | NULL, NULL, NULL, NULL, NULL, |
275 | NULL, NULL, &volume_label, NULL, NULL, NULL, NULL); | 276 | NULL, NULL, &volume_label, NULL, NULL, NULL, NULL); |
276 | argv += optind; | 277 | argv += optind; |
diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c index e44e13c0d..71449882d 100644 --- a/util-linux/mkswap.c +++ b/util-linux/mkswap.c | |||
@@ -119,9 +119,8 @@ int mkswap_main(int argc UNUSED_PARAM, char **argv) | |||
119 | 119 | ||
120 | INIT_G(); | 120 | INIT_G(); |
121 | 121 | ||
122 | opt_complementary = "-1"; /* at least one param */ | ||
123 | /* TODO: -p PAGESZ, -U UUID */ | 122 | /* TODO: -p PAGESZ, -U UUID */ |
124 | getopt32(argv, "L:", &label); | 123 | getopt32(argv, "^" "L:" "\0" "-1"/*at least one arg*/, &label); |
125 | argv += optind; | 124 | argv += optind; |
126 | 125 | ||
127 | fd = xopen(argv[0], O_WRONLY); | 126 | fd = xopen(argv[0], O_WRONLY); |
diff --git a/util-linux/mount.c b/util-linux/mount.c index 4d5c2243a..4eade0869 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
@@ -69,7 +69,6 @@ | |||
69 | //config: bool "Support mounting NFS file systems on Linux < 2.6.23" | 69 | //config: bool "Support mounting NFS file systems on Linux < 2.6.23" |
70 | //config: default n | 70 | //config: default n |
71 | //config: depends on MOUNT | 71 | //config: depends on MOUNT |
72 | //config: select FEATURE_HAVE_RPC | ||
73 | //config: select FEATURE_SYSLOG | 72 | //config: select FEATURE_SYSLOG |
74 | //config: help | 73 | //config: help |
75 | //config: Enable mounting of NFS file systems on Linux kernels prior | 74 | //config: Enable mounting of NFS file systems on Linux kernels prior |
@@ -2205,10 +2204,14 @@ int mount_main(int argc UNUSED_PARAM, char **argv) | |||
2205 | 2204 | ||
2206 | // Parse remaining options | 2205 | // Parse remaining options |
2207 | // Max 2 params; -o is a list, -v is a counter | 2206 | // Max 2 params; -o is a list, -v is a counter |
2208 | opt_complementary = "?2" IF_FEATURE_MOUNT_VERBOSE("vv"); | 2207 | opt = getopt32(argv, "^" |
2209 | opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch | 2208 | OPTION_STR |
2210 | IF_FEATURE_MOUNT_OTHERTAB(, &fstabname) | 2209 | "\0" "?2"IF_FEATURE_MOUNT_VERBOSE("vv"), |
2211 | IF_FEATURE_MOUNT_VERBOSE(, &verbose)); | 2210 | &lst_o, &fstype, &O_optmatch |
2211 | IF_FEATURE_MOUNT_OTHERTAB(, &fstabname) | ||
2212 | IF_FEATURE_MOUNT_VERBOSE(, &verbose) | ||
2213 | ); | ||
2214 | |||
2212 | while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o | 2215 | while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o |
2213 | if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r | 2216 | if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r |
2214 | if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w | 2217 | if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w |
diff --git a/util-linux/mountpoint.c b/util-linux/mountpoint.c index b7f048196..6b21a5fb3 100644 --- a/util-linux/mountpoint.c +++ b/util-linux/mountpoint.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: help | 14 | //config: help |
15 | //config: mountpoint checks if the directory is a mountpoint. | 15 | //config: mountpoint checks if the directory is a mountpoint. |
16 | 16 | ||
17 | //applet:IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_MOUNTPOINT(APPLET_NOEXEC(mountpoint, mountpoint, BB_DIR_BIN, BB_SUID_DROP, mountpoint)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o | 19 | //kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o |
20 | 20 | ||
@@ -43,8 +43,7 @@ int mountpoint_main(int argc UNUSED_PARAM, char **argv) | |||
43 | char *arg; | 43 | char *arg; |
44 | int rc, opt; | 44 | int rc, opt; |
45 | 45 | ||
46 | opt_complementary = "=1"; /* must have one argument */ | 46 | opt = getopt32(argv, "^" "qdxn" "\0" "=1"); |
47 | opt = getopt32(argv, "qdxn"); | ||
48 | #define OPT_q (1) | 47 | #define OPT_q (1) |
49 | #define OPT_d (2) | 48 | #define OPT_d (2) |
50 | #define OPT_x (4) | 49 | #define OPT_x (4) |
diff --git a/util-linux/nsenter.c b/util-linux/nsenter.c index 12c86b0ed..d91b0b509 100644 --- a/util-linux/nsenter.c +++ b/util-linux/nsenter.c | |||
@@ -13,14 +13,6 @@ | |||
13 | //config: select PLATFORM_LINUX | 13 | //config: select PLATFORM_LINUX |
14 | //config: help | 14 | //config: help |
15 | //config: Run program with namespaces of other processes. | 15 | //config: Run program with namespaces of other processes. |
16 | //config: | ||
17 | //config:config FEATURE_NSENTER_LONG_OPTS | ||
18 | //config: bool "Enable long options" | ||
19 | //config: default y | ||
20 | //config: depends on NSENTER && LONG_OPTS | ||
21 | //config: help | ||
22 | //config: Support long options for the nsenter applet. This makes | ||
23 | //config: the busybox implementation more compatible with upstream. | ||
24 | 16 | ||
25 | //applet:IF_NSENTER(APPLET(nsenter, BB_DIR_USR_BIN, BB_SUID_DROP)) | 17 | //applet:IF_NSENTER(APPLET(nsenter, BB_DIR_USR_BIN, BB_SUID_DROP)) |
26 | 18 | ||
@@ -28,22 +20,6 @@ | |||
28 | 20 | ||
29 | //usage:#define nsenter_trivial_usage | 21 | //usage:#define nsenter_trivial_usage |
30 | //usage: "[OPTIONS] [PROG [ARGS]]" | 22 | //usage: "[OPTIONS] [PROG [ARGS]]" |
31 | //usage:#if ENABLE_FEATURE_NSENTER_LONG_OPTS | ||
32 | //usage:#define nsenter_full_usage "\n" | ||
33 | //usage: "\n -t,--target PID Target process to get namespaces from" | ||
34 | //usage: "\n -m,--mount[=FILE] Enter mount namespace" | ||
35 | //usage: "\n -u,--uts[=FILE] Enter UTS namespace (hostname etc)" | ||
36 | //usage: "\n -i,--ipc[=FILE] Enter System V IPC namespace" | ||
37 | //usage: "\n -n,--net[=FILE] Enter network namespace" | ||
38 | //usage: "\n -p,--pid[=FILE] Enter pid namespace" | ||
39 | //usage: "\n -U,--user[=FILE] Enter user namespace" | ||
40 | //usage: "\n -S,--setuid UID Set uid in entered namespace" | ||
41 | //usage: "\n -G,--setgid GID Set gid in entered namespace" | ||
42 | //usage: "\n --preserve-credentials Don't touch uids or gids" | ||
43 | //usage: "\n -r,--root[=DIR] Set root directory" | ||
44 | //usage: "\n -w,--wd[=DIR] Set working directory" | ||
45 | //usage: "\n -F,--no-fork Don't fork before exec'ing PROG" | ||
46 | //usage:#else | ||
47 | //usage:#define nsenter_full_usage "\n" | 23 | //usage:#define nsenter_full_usage "\n" |
48 | //usage: "\n -t PID Target process to get namespaces from" | 24 | //usage: "\n -t PID Target process to get namespaces from" |
49 | //usage: "\n -m[FILE] Enter mount namespace" | 25 | //usage: "\n -m[FILE] Enter mount namespace" |
@@ -54,10 +30,12 @@ | |||
54 | //usage: "\n -U[FILE] Enter user namespace" | 30 | //usage: "\n -U[FILE] Enter user namespace" |
55 | //usage: "\n -S UID Set uid in entered namespace" | 31 | //usage: "\n -S UID Set uid in entered namespace" |
56 | //usage: "\n -G GID Set gid in entered namespace" | 32 | //usage: "\n -G GID Set gid in entered namespace" |
33 | //usage: IF_LONG_OPTS( | ||
34 | //usage: "\n --preserve-credentials Don't touch uids or gids" | ||
35 | //usage: ) | ||
57 | //usage: "\n -r[DIR] Set root directory" | 36 | //usage: "\n -r[DIR] Set root directory" |
58 | //usage: "\n -w[DIR] Set working directory" | 37 | //usage: "\n -w[DIR] Set working directory" |
59 | //usage: "\n -F Don't fork before exec'ing PROG" | 38 | //usage: "\n -F Don't fork before exec'ing PROG" |
60 | //usage:#endif | ||
61 | 39 | ||
62 | #include <sched.h> | 40 | #include <sched.h> |
63 | #ifndef CLONE_NEWUTS | 41 | #ifndef CLONE_NEWUTS |
@@ -101,7 +79,7 @@ enum { | |||
101 | OPT_root = 1 << 9, | 79 | OPT_root = 1 << 9, |
102 | OPT_wd = 1 << 10, | 80 | OPT_wd = 1 << 10, |
103 | OPT_nofork = 1 << 11, | 81 | OPT_nofork = 1 << 11, |
104 | OPT_prescred = (1 << 12) * ENABLE_FEATURE_NSENTER_LONG_OPTS, | 82 | OPT_prescred = (1 << 12) * ENABLE_LONG_OPTS, |
105 | }; | 83 | }; |
106 | enum { | 84 | enum { |
107 | NS_USR_POS = 0, | 85 | NS_USR_POS = 0, |
@@ -130,7 +108,7 @@ static const struct namespace_descr ns_list[] = { | |||
130 | */ | 108 | */ |
131 | static const char opt_str[] ALIGN1 = "U::i::u::n::p::m::""t+S+G+r::w::F"; | 109 | static const char opt_str[] ALIGN1 = "U::i::u::n::p::m::""t+S+G+r::w::F"; |
132 | 110 | ||
133 | #if ENABLE_FEATURE_NSENTER_LONG_OPTS | 111 | #if ENABLE_LONG_OPTS |
134 | static const char nsenter_longopts[] ALIGN1 = | 112 | static const char nsenter_longopts[] ALIGN1 = |
135 | "user\0" Optional_argument "U" | 113 | "user\0" Optional_argument "U" |
136 | "ipc\0" Optional_argument "i" | 114 | "ipc\0" Optional_argument "i" |
@@ -190,8 +168,7 @@ int nsenter_main(int argc UNUSED_PARAM, char **argv) | |||
190 | 168 | ||
191 | memset(ns_ctx_list, 0, sizeof(ns_ctx_list)); | 169 | memset(ns_ctx_list, 0, sizeof(ns_ctx_list)); |
192 | 170 | ||
193 | IF_FEATURE_NSENTER_LONG_OPTS(applet_long_options = nsenter_longopts); | 171 | opts = getopt32long(argv, opt_str, nsenter_longopts, |
194 | opts = getopt32(argv, opt_str, | ||
195 | &ns_ctx_list[NS_USR_POS].path, | 172 | &ns_ctx_list[NS_USR_POS].path, |
196 | &ns_ctx_list[NS_IPC_POS].path, | 173 | &ns_ctx_list[NS_IPC_POS].path, |
197 | &ns_ctx_list[NS_UTS_POS].path, | 174 | &ns_ctx_list[NS_UTS_POS].path, |
diff --git a/util-linux/pivot_root.c b/util-linux/pivot_root.c index 331038057..d6a26b912 100644 --- a/util-linux/pivot_root.c +++ b/util-linux/pivot_root.c | |||
@@ -21,7 +21,7 @@ | |||
21 | //config: Note: This is for initrd in linux 2.4. Under initramfs (introduced | 21 | //config: Note: This is for initrd in linux 2.4. Under initramfs (introduced |
22 | //config: in linux 2.6) use switch_root instead. | 22 | //config: in linux 2.6) use switch_root instead. |
23 | 23 | ||
24 | //applet:IF_PIVOT_ROOT(APPLET(pivot_root, BB_DIR_SBIN, BB_SUID_DROP)) | 24 | //applet:IF_PIVOT_ROOT(APPLET_NOFORK(pivot_root, pivot_root, BB_DIR_SBIN, BB_SUID_DROP, pivot_root)) |
25 | 25 | ||
26 | //kbuild:lib-$(CONFIG_PIVOT_ROOT) += pivot_root.o | 26 | //kbuild:lib-$(CONFIG_PIVOT_ROOT) += pivot_root.o |
27 | 27 | ||
@@ -33,7 +33,7 @@ | |||
33 | 33 | ||
34 | #include "libbb.h" | 34 | #include "libbb.h" |
35 | 35 | ||
36 | extern int pivot_root(const char * new_root,const char * put_old); | 36 | extern int pivot_root(const char *new_root, const char *put_old); |
37 | 37 | ||
38 | int pivot_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 38 | int pivot_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
39 | int pivot_root_main(int argc, char **argv) | 39 | int pivot_root_main(int argc, char **argv) |
@@ -41,6 +41,8 @@ int pivot_root_main(int argc, char **argv) | |||
41 | if (argc != 3) | 41 | if (argc != 3) |
42 | bb_show_usage(); | 42 | bb_show_usage(); |
43 | 43 | ||
44 | /* NOFORK applet. Hardly matters wrt performance, but code is trivial */ | ||
45 | |||
44 | if (pivot_root(argv[1], argv[2]) < 0) { | 46 | if (pivot_root(argv[1], argv[2]) < 0) { |
45 | /* prints "pivot_root: <strerror text>" */ | 47 | /* prints "pivot_root: <strerror text>" */ |
46 | bb_perror_nomsg_and_die(); | 48 | bb_perror_nomsg_and_die(); |
diff --git a/util-linux/rdate.c b/util-linux/rdate.c index 14ce591e9..f27294e25 100644 --- a/util-linux/rdate.c +++ b/util-linux/rdate.c | |||
@@ -81,8 +81,7 @@ int rdate_main(int argc UNUSED_PARAM, char **argv) | |||
81 | time_t remote_time; | 81 | time_t remote_time; |
82 | unsigned flags; | 82 | unsigned flags; |
83 | 83 | ||
84 | opt_complementary = "-1"; | 84 | flags = getopt32(argv, "^" "sp" "\0" "-1"); |
85 | flags = getopt32(argv, "sp"); | ||
86 | 85 | ||
87 | remote_time = askremotedate(argv[optind]); | 86 | remote_time = askremotedate(argv[optind]); |
88 | 87 | ||
diff --git a/util-linux/rdev.c b/util-linux/rdev.c index 2ffe07688..7eb7413a8 100644 --- a/util-linux/rdev.c +++ b/util-linux/rdev.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //config: help | 14 | //config: help |
15 | //config: Print the device node associated with the filesystem mounted at '/'. | 15 | //config: Print the device node associated with the filesystem mounted at '/'. |
16 | 16 | ||
17 | //applet:IF_RDEV(APPLET(rdev, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 17 | //applet:IF_RDEV(APPLET_NOEXEC(rdev, rdev, BB_DIR_USR_SBIN, BB_SUID_DROP, rdev)) |
18 | 18 | ||
19 | //kbuild:lib-$(CONFIG_RDEV) += rdev.o | 19 | //kbuild:lib-$(CONFIG_RDEV) += rdev.o |
20 | 20 | ||
diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c index b045657d8..394ece1dd 100644 --- a/util-linux/readprofile.c +++ b/util-linux/readprofile.c | |||
@@ -266,8 +266,10 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv) | |||
266 | printf("%6u %-40s %8.4f\n", | 266 | printf("%6u %-40s %8.4f\n", |
267 | total, "total", total/(double)(fn_add-add0)); | 267 | total, "total", total/(double)(fn_add-add0)); |
268 | 268 | ||
269 | fclose(map); | 269 | if (ENABLE_FEATURE_CLEAN_UP) { |
270 | free(buf); | 270 | fclose(map); |
271 | free(buf); | ||
272 | } | ||
271 | 273 | ||
272 | return EXIT_SUCCESS; | 274 | return EXIT_SUCCESS; |
273 | } | 275 | } |
diff --git a/util-linux/renice.c b/util-linux/renice.c index 23cbca88d..70c494b3d 100644 --- a/util-linux/renice.c +++ b/util-linux/renice.c | |||
@@ -25,7 +25,7 @@ | |||
25 | //config: Renice alters the scheduling priority of one or more running | 25 | //config: Renice alters the scheduling priority of one or more running |
26 | //config: processes. | 26 | //config: processes. |
27 | 27 | ||
28 | //applet:IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP)) | 28 | //applet:IF_RENICE(APPLET_NOEXEC(renice, renice, BB_DIR_USR_BIN, BB_SUID_DROP, renice)) |
29 | 29 | ||
30 | //kbuild:lib-$(CONFIG_RENICE) += renice.o | 30 | //kbuild:lib-$(CONFIG_RENICE) += renice.o |
31 | 31 | ||
diff --git a/util-linux/rtcwake.c b/util-linux/rtcwake.c index 4c47c5369..8ffa4f3a6 100644 --- a/util-linux/rtcwake.c +++ b/util-linux/rtcwake.c | |||
@@ -154,11 +154,11 @@ int rtcwake_main(int argc UNUSED_PARAM, char **argv) | |||
154 | "seconds\0" Required_argument "s" | 154 | "seconds\0" Required_argument "s" |
155 | "time\0" Required_argument "t" | 155 | "time\0" Required_argument "t" |
156 | ; | 156 | ; |
157 | applet_long_options = rtcwake_longopts; | ||
158 | #endif | 157 | #endif |
159 | /* Must have -s or -t, exclusive */ | 158 | opt = getopt32long(argv, |
160 | opt_complementary = "s:t:s--t:t--s"; | 159 | /* Must have -s or -t, exclusive */ |
161 | opt = getopt32(argv, "alud:m:s:t:", &rtcname, &suspend, &opt_seconds, &opt_time); | 160 | "^alud:m:s:t:" "\0" "s:t:s--t:t--s", rtcwake_longopts, |
161 | &rtcname, &suspend, &opt_seconds, &opt_time); | ||
162 | 162 | ||
163 | /* this is the default | 163 | /* this is the default |
164 | if (opt & RTCWAKE_OPT_AUTO) | 164 | if (opt & RTCWAKE_OPT_AUTO) |
diff --git a/util-linux/script.c b/util-linux/script.c index 9eebb51a4..aac77c3ba 100644 --- a/util-linux/script.c +++ b/util-linux/script.c | |||
@@ -21,15 +21,25 @@ | |||
21 | //kbuild:lib-$(CONFIG_SCRIPT) += script.o | 21 | //kbuild:lib-$(CONFIG_SCRIPT) += script.o |
22 | 22 | ||
23 | //usage:#define script_trivial_usage | 23 | //usage:#define script_trivial_usage |
24 | //usage: "[-afq" IF_SCRIPTREPLAY("t") "] [-c PROG] [OUTFILE]" | 24 | //usage: "[-afq] [-t[FILE]] [-c PROG] [OUTFILE]" |
25 | //usage:#define script_full_usage "\n\n" | 25 | //usage:#define script_full_usage "\n\n" |
26 | //usage: " -a Append output" | 26 | //usage: "Default OUTFILE is 'typescript'" |
27 | //usage: "\n" | ||
28 | //usage: "\n -a Append output" | ||
27 | //usage: "\n -c PROG Run PROG, not shell" | 29 | //usage: "\n -c PROG Run PROG, not shell" |
28 | //usage: "\n -f Flush output after each write" | 30 | /* Accepted but has no effect (we never buffer output) */ |
31 | /*//usage: "\n -f Flush output after each write"*/ | ||
29 | //usage: "\n -q Quiet" | 32 | //usage: "\n -q Quiet" |
30 | //usage: IF_SCRIPTREPLAY( | 33 | //usage: "\n -t[FILE] Send timing to stderr or FILE" |
31 | //usage: "\n -t Send timing to stderr" | 34 | |
32 | //usage: ) | 35 | //util-linux-2.28: |
36 | //-e: return exit code of the child | ||
37 | |||
38 | //FYI (reported as bbox bug #2749): | ||
39 | // > script -q -c 'echo -e -n "1\n2\n3\n"' /dev/null </dev/null >123.txt | ||
40 | // > The output file on full-blown ubuntu system contains 6 bytes. | ||
41 | // > Output on Busybox system (arm-linux) contains extra '\r' byte in each line. | ||
42 | //however, in my test, "script" from util-linux-2.28 seems to also add '\r' bytes. | ||
33 | 43 | ||
34 | #include "libbb.h" | 44 | #include "libbb.h" |
35 | #include "common_bufsiz.h" | 45 | #include "common_bufsiz.h" |
@@ -46,6 +56,8 @@ int script_main(int argc UNUSED_PARAM, char **argv) | |||
46 | char pty_line[GETPTY_BUFSIZE]; | 56 | char pty_line[GETPTY_BUFSIZE]; |
47 | struct termios tt, rtt; | 57 | struct termios tt, rtt; |
48 | struct winsize win; | 58 | struct winsize win; |
59 | FILE *timing_fp; | ||
60 | const char *str_t = NULL; | ||
49 | const char *fname = "typescript"; | 61 | const char *fname = "typescript"; |
50 | const char *shell; | 62 | const char *shell; |
51 | char shell_opt[] = "-i"; | 63 | char shell_opt[] = "-i"; |
@@ -59,19 +71,19 @@ int script_main(int argc UNUSED_PARAM, char **argv) | |||
59 | }; | 71 | }; |
60 | 72 | ||
61 | #if ENABLE_LONG_OPTS | 73 | #if ENABLE_LONG_OPTS |
62 | static const char getopt_longopts[] ALIGN1 = | 74 | static const char script_longopts[] ALIGN1 = |
63 | "append\0" No_argument "a" | 75 | "append\0" No_argument "a" |
64 | "command\0" Required_argument "c" | 76 | "command\0" Required_argument "c" |
65 | "flush\0" No_argument "f" | 77 | "flush\0" No_argument "f" |
66 | "quiet\0" No_argument "q" | 78 | "quiet\0" No_argument "q" |
67 | IF_SCRIPTREPLAY("timing\0" No_argument "t") | 79 | "timing\0" Optional_argument "t" |
68 | ; | 80 | ; |
69 | |||
70 | applet_long_options = getopt_longopts; | ||
71 | #endif | 81 | #endif |
72 | 82 | ||
73 | opt_complementary = "?1"; /* max one arg */ | 83 | opt = getopt32long(argv, "^" "ac:fqt::" "\0" "?1"/* max one arg */, |
74 | opt = getopt32(argv, "ac:fq" IF_SCRIPTREPLAY("t") , &shell_arg); | 84 | script_longopts, |
85 | &shell_arg, &str_t | ||
86 | ); | ||
75 | //argc -= optind; | 87 | //argc -= optind; |
76 | argv += optind; | 88 | argv += optind; |
77 | if (argv[0]) { | 89 | if (argv[0]) { |
@@ -87,6 +99,10 @@ int script_main(int argc UNUSED_PARAM, char **argv) | |||
87 | if (!(opt & OPT_q)) { | 99 | if (!(opt & OPT_q)) { |
88 | printf("Script started, file is %s\n", fname); | 100 | printf("Script started, file is %s\n", fname); |
89 | } | 101 | } |
102 | timing_fp = stderr; | ||
103 | if (str_t) { | ||
104 | timing_fp = xfopen_for_write(str_t); | ||
105 | } | ||
90 | 106 | ||
91 | shell = get_shell_name(); | 107 | shell = get_shell_name(); |
92 | 108 | ||
@@ -120,8 +136,9 @@ int script_main(int argc UNUSED_PARAM, char **argv) | |||
120 | /* parent */ | 136 | /* parent */ |
121 | struct pollfd pfd[2]; | 137 | struct pollfd pfd[2]; |
122 | int outfd, count, loop; | 138 | int outfd, count, loop; |
123 | double oldtime = ENABLE_SCRIPTREPLAY ? time(NULL) : 0; | 139 | double oldtime = time(NULL); |
124 | smallint fd_count = 2; | 140 | smallint fd_count = 2; |
141 | |||
125 | #define buf bb_common_bufsiz1 | 142 | #define buf bb_common_bufsiz1 |
126 | setup_common_bufsiz(); | 143 | setup_common_bufsiz(); |
127 | 144 | ||
@@ -151,20 +168,21 @@ int script_main(int argc UNUSED_PARAM, char **argv) | |||
151 | goto restore; | 168 | goto restore; |
152 | } | 169 | } |
153 | if (count > 0) { | 170 | if (count > 0) { |
154 | if (ENABLE_SCRIPTREPLAY && (opt & OPT_t)) { | 171 | if (opt & OPT_t) { |
155 | struct timeval tv; | 172 | struct timeval tv; |
156 | double newtime; | 173 | double newtime; |
157 | 174 | ||
158 | gettimeofday(&tv, NULL); | 175 | gettimeofday(&tv, NULL); |
159 | newtime = tv.tv_sec + (double) tv.tv_usec / 1000000; | 176 | newtime = tv.tv_sec + (double) tv.tv_usec / 1000000; |
160 | fprintf(stderr, "%f %u\n", newtime - oldtime, count); | 177 | fprintf(timing_fp, "%f %u\n", newtime - oldtime, count); |
161 | oldtime = newtime; | 178 | oldtime = newtime; |
162 | } | 179 | } |
163 | full_write(STDOUT_FILENO, buf, count); | 180 | full_write(STDOUT_FILENO, buf, count); |
164 | full_write(outfd, buf, count); | 181 | full_write(outfd, buf, count); |
165 | if (opt & OPT_f) { | 182 | // If we'd be using (buffered) FILE i/o, we'd need this: |
166 | fsync(outfd); | 183 | //if (opt & OPT_f) { |
167 | } | 184 | // fflush(outfd); |
185 | //} | ||
168 | } | 186 | } |
169 | } | 187 | } |
170 | if (pfd[1].revents) { | 188 | if (pfd[1].revents) { |
diff --git a/util-linux/scriptreplay.c b/util-linux/scriptreplay.c index 7e9850103..e3083ab93 100644 --- a/util-linux/scriptreplay.c +++ b/util-linux/scriptreplay.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * pascal.bellard@ads-lu.com | 5 | * pascal.bellard@ads-lu.com |
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 | * | ||
9 | */ | 8 | */ |
10 | //config:config SCRIPTREPLAY | 9 | //config:config SCRIPTREPLAY |
11 | //config: bool "scriptreplay (2.6 kb)" | 10 | //config: bool "scriptreplay (2.6 kb)" |
@@ -19,7 +18,7 @@ | |||
19 | //kbuild:lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o | 18 | //kbuild:lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o |
20 | 19 | ||
21 | //usage:#define scriptreplay_trivial_usage | 20 | //usage:#define scriptreplay_trivial_usage |
22 | //usage: "timingfile [typescript [divisor]]" | 21 | //usage: "TIMINGFILE [TYPESCRIPT [DIVISOR]]" |
23 | //usage:#define scriptreplay_full_usage "\n\n" | 22 | //usage:#define scriptreplay_full_usage "\n\n" |
24 | //usage: "Play back typescripts, using timing information" | 23 | //usage: "Play back typescripts, using timing information" |
25 | 24 | ||
diff --git a/util-linux/setarch.c b/util-linux/setarch.c index d4b568832..520865318 100644 --- a/util-linux/setarch.c +++ b/util-linux/setarch.c | |||
@@ -30,10 +30,10 @@ | |||
30 | //config: help | 30 | //config: help |
31 | //config: Alias to "setarch linux64". | 31 | //config: Alias to "setarch linux64". |
32 | 32 | ||
33 | //applet:IF_SETARCH(APPLET(setarch, BB_DIR_BIN, BB_SUID_DROP)) | 33 | //applet:IF_SETARCH(APPLET_NOEXEC(setarch, setarch, BB_DIR_BIN, BB_SUID_DROP, setarch)) |
34 | // APPLET_ODDNAME:name main location suid_type help | 34 | // APPLET_NOEXEC:name main location suid_type help |
35 | //applet:IF_LINUX32(APPLET_ODDNAME(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) | 35 | //applet:IF_LINUX32(APPLET_NOEXEC(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) |
36 | //applet:IF_LINUX64(APPLET_ODDNAME(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) | 36 | //applet:IF_LINUX64(APPLET_NOEXEC(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) |
37 | 37 | ||
38 | //kbuild:lib-$(CONFIG_SETARCH) += setarch.o | 38 | //kbuild:lib-$(CONFIG_SETARCH) += setarch.o |
39 | //kbuild:lib-$(CONFIG_LINUX32) += setarch.o | 39 | //kbuild:lib-$(CONFIG_LINUX32) += setarch.o |
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c index 0f85428ab..12ab1bd66 100644 --- a/util-linux/setpriv.c +++ b/util-linux/setpriv.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * Copyright (C) 2017 by <assafgordon@gmail.com> | 5 | * Copyright (C) 2017 by <assafgordon@gmail.com> |
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 | * | ||
9 | */ | 8 | */ |
10 | //config:config SETPRIV | 9 | //config:config SETPRIV |
11 | //config: bool "setpriv (3.4 kb)" | 10 | //config: bool "setpriv (3.4 kb)" |
@@ -125,96 +124,10 @@ enum { | |||
125 | }; | 124 | }; |
126 | 125 | ||
127 | #if ENABLE_FEATURE_SETPRIV_CAPABILITIES | 126 | #if ENABLE_FEATURE_SETPRIV_CAPABILITIES |
128 | struct caps { | 127 | DEFINE_STRUCT_CAPS; |
129 | struct __user_cap_header_struct header; | ||
130 | cap_user_data_t data; | ||
131 | int u32s; | ||
132 | }; | ||
133 | |||
134 | # if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES | ||
135 | static const char *const capabilities[] = { | ||
136 | "chown", | ||
137 | "dac_override", | ||
138 | "dac_read_search", | ||
139 | "fowner", | ||
140 | "fsetid", | ||
141 | "kill", | ||
142 | "setgid", | ||
143 | "setuid", | ||
144 | "setpcap", | ||
145 | "linux_immutable", | ||
146 | "net_bind_service", | ||
147 | "net_broadcast", | ||
148 | "net_admin", | ||
149 | "net_raw", | ||
150 | "ipc_lock", | ||
151 | "ipc_owner", | ||
152 | "sys_module", | ||
153 | "sys_rawio", | ||
154 | "sys_chroot", | ||
155 | "sys_ptrace", | ||
156 | "sys_pacct", | ||
157 | "sys_admin", | ||
158 | "sys_boot", | ||
159 | "sys_nice", | ||
160 | "sys_resource", | ||
161 | "sys_time", | ||
162 | "sys_tty_config", | ||
163 | "mknod", | ||
164 | "lease", | ||
165 | "audit_write", | ||
166 | "audit_control", | ||
167 | "setfcap", | ||
168 | "mac_override", | ||
169 | "mac_admin", | ||
170 | "syslog", | ||
171 | "wake_alarm", | ||
172 | "block_suspend", | ||
173 | "audit_read", | ||
174 | }; | ||
175 | # endif /* FEATURE_SETPRIV_CAPABILITY_NAMES */ | ||
176 | 128 | ||
177 | static void getcaps(struct caps *caps) | 129 | static unsigned parse_cap(const char *cap) |
178 | { | 130 | { |
179 | static const uint8_t versions[] = { | ||
180 | _LINUX_CAPABILITY_U32S_3, /* = 2 (fits into byte) */ | ||
181 | _LINUX_CAPABILITY_U32S_2, /* = 2 */ | ||
182 | _LINUX_CAPABILITY_U32S_1, /* = 1 */ | ||
183 | }; | ||
184 | int i; | ||
185 | |||
186 | caps->header.pid = 0; | ||
187 | for (i = 0; i < ARRAY_SIZE(versions); i++) { | ||
188 | caps->header.version = versions[i]; | ||
189 | if (capget(&caps->header, NULL) == 0) | ||
190 | goto got_it; | ||
191 | } | ||
192 | bb_simple_perror_msg_and_die("capget"); | ||
193 | got_it: | ||
194 | |||
195 | switch (caps->header.version) { | ||
196 | case _LINUX_CAPABILITY_VERSION_1: | ||
197 | caps->u32s = _LINUX_CAPABILITY_U32S_1; | ||
198 | break; | ||
199 | case _LINUX_CAPABILITY_VERSION_2: | ||
200 | caps->u32s = _LINUX_CAPABILITY_U32S_2; | ||
201 | break; | ||
202 | case _LINUX_CAPABILITY_VERSION_3: | ||
203 | caps->u32s = _LINUX_CAPABILITY_U32S_3; | ||
204 | break; | ||
205 | default: | ||
206 | bb_error_msg_and_die("unsupported capability version"); | ||
207 | } | ||
208 | |||
209 | caps->data = xmalloc(sizeof(caps->data[0]) * caps->u32s); | ||
210 | if (capget(&caps->header, caps->data) < 0) | ||
211 | bb_simple_perror_msg_and_die("capget"); | ||
212 | } | ||
213 | |||
214 | static void parse_cap(unsigned long *index, const char *cap) | ||
215 | { | ||
216 | unsigned long i; | ||
217 | |||
218 | switch (cap[0]) { | 131 | switch (cap[0]) { |
219 | case '-': | 132 | case '-': |
220 | break; | 133 | break; |
@@ -226,26 +139,7 @@ static void parse_cap(unsigned long *index, const char *cap) | |||
226 | } | 139 | } |
227 | 140 | ||
228 | cap++; | 141 | cap++; |
229 | if ((sscanf(cap, "cap_%lu", &i)) == 1) { | 142 | return cap_name_to_number(cap); |
230 | if (!cap_valid(i)) | ||
231 | bb_error_msg_and_die("unsupported capability '%s'", cap); | ||
232 | *index = i; | ||
233 | return; | ||
234 | } | ||
235 | |||
236 | # if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES | ||
237 | for (i = 0; i < ARRAY_SIZE(capabilities); i++) { | ||
238 | if (strcmp(capabilities[i], cap) != 0) | ||
239 | continue; | ||
240 | |||
241 | if (!cap_valid(i)) | ||
242 | bb_error_msg_and_die("unsupported capability '%s'", cap); | ||
243 | *index = i; | ||
244 | return; | ||
245 | } | ||
246 | # endif | ||
247 | |||
248 | bb_error_msg_and_die("unknown capability '%s'", cap); | ||
249 | } | 143 | } |
250 | 144 | ||
251 | static void set_inh_caps(char *capstring) | 145 | static void set_inh_caps(char *capstring) |
@@ -256,11 +150,11 @@ static void set_inh_caps(char *capstring) | |||
256 | 150 | ||
257 | capstring = strtok(capstring, ","); | 151 | capstring = strtok(capstring, ","); |
258 | while (capstring) { | 152 | while (capstring) { |
259 | unsigned long cap; | 153 | unsigned cap; |
260 | 154 | ||
261 | parse_cap(&cap, capstring); | 155 | cap = parse_cap(capstring); |
262 | if (CAP_TO_INDEX(cap) >= caps.u32s) | 156 | if (CAP_TO_INDEX(cap) >= caps.u32s) |
263 | bb_error_msg_and_die("invalid capability cap"); | 157 | bb_error_msg_and_die("invalid capability '%s'", capstring); |
264 | 158 | ||
265 | if (capstring[0] == '+') | 159 | if (capstring[0] == '+') |
266 | caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); | 160 | caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); |
@@ -269,11 +163,8 @@ static void set_inh_caps(char *capstring) | |||
269 | capstring = strtok(NULL, ","); | 163 | capstring = strtok(NULL, ","); |
270 | } | 164 | } |
271 | 165 | ||
272 | if ((capset(&caps.header, caps.data)) < 0) | 166 | if (capset(&caps.header, caps.data) != 0) |
273 | bb_perror_msg_and_die("capset"); | 167 | bb_perror_msg_and_die("capset"); |
274 | |||
275 | if (ENABLE_FEATURE_CLEAN_UP) | ||
276 | free(caps.data); | ||
277 | } | 168 | } |
278 | 169 | ||
279 | static void set_ambient_caps(char *string) | 170 | static void set_ambient_caps(char *string) |
@@ -282,9 +173,9 @@ static void set_ambient_caps(char *string) | |||
282 | 173 | ||
283 | cap = strtok(string, ","); | 174 | cap = strtok(string, ","); |
284 | while (cap) { | 175 | while (cap) { |
285 | unsigned long index; | 176 | unsigned index; |
286 | 177 | ||
287 | parse_cap(&index, cap); | 178 | index = parse_cap(cap); |
288 | if (cap[0] == '+') { | 179 | if (cap[0] == '+') { |
289 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, index, 0, 0) < 0) | 180 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, index, 0, 0) < 0) |
290 | bb_perror_msg("cap_ambient_raise"); | 181 | bb_perror_msg("cap_ambient_raise"); |
@@ -298,16 +189,7 @@ static void set_ambient_caps(char *string) | |||
298 | #endif /* FEATURE_SETPRIV_CAPABILITIES */ | 189 | #endif /* FEATURE_SETPRIV_CAPABILITIES */ |
299 | 190 | ||
300 | #if ENABLE_FEATURE_SETPRIV_DUMP | 191 | #if ENABLE_FEATURE_SETPRIV_DUMP |
301 | # if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES | 192 | # if !ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES |
302 | static void printf_cap(const char *pfx, unsigned cap_no) | ||
303 | { | ||
304 | if (cap_no < ARRAY_SIZE(capabilities)) { | ||
305 | printf("%s%s", pfx, capabilities[cap_no]); | ||
306 | return; | ||
307 | } | ||
308 | printf("%scap_%u", pfx, cap_no); | ||
309 | } | ||
310 | # else | ||
311 | # define printf_cap(pfx, cap_no) printf("%scap_%u", (pfx), (cap_no)) | 193 | # define printf_cap(pfx, cap_no) printf("%scap_%u", (pfx), (cap_no)) |
312 | # endif | 194 | # endif |
313 | 195 | ||
@@ -396,10 +278,9 @@ static int dump(void) | |||
396 | bb_putchar('\n'); | 278 | bb_putchar('\n'); |
397 | # endif | 279 | # endif |
398 | 280 | ||
399 | if (ENABLE_FEATURE_CLEAN_UP) { | 281 | if (ENABLE_FEATURE_CLEAN_UP) |
400 | IF_FEATURE_SETPRIV_CAPABILITIES(free(caps.data);) | ||
401 | free(gids); | 282 | free(gids); |
402 | } | 283 | |
403 | return EXIT_SUCCESS; | 284 | return EXIT_SUCCESS; |
404 | } | 285 | } |
405 | #endif /* FEATURE_SETPRIV_DUMP */ | 286 | #endif /* FEATURE_SETPRIV_DUMP */ |
@@ -421,9 +302,12 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv) | |||
421 | int opts; | 302 | int opts; |
422 | IF_FEATURE_SETPRIV_CAPABILITIES(char *inh_caps, *ambient_caps;) | 303 | IF_FEATURE_SETPRIV_CAPABILITIES(char *inh_caps, *ambient_caps;) |
423 | 304 | ||
424 | applet_long_options = setpriv_longopts; | 305 | opts = getopt32long(argv, "+" |
425 | opts = getopt32(argv, "+"IF_FEATURE_SETPRIV_DUMP("d") | 306 | IF_FEATURE_SETPRIV_DUMP("d") |
426 | IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:\xfd:", &inh_caps, &ambient_caps)); | 307 | IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:\xfd:"), |
308 | setpriv_longopts | ||
309 | IF_FEATURE_SETPRIV_CAPABILITIES(, &inh_caps, &ambient_caps) | ||
310 | ); | ||
427 | argv += optind; | 311 | argv += optind; |
428 | 312 | ||
429 | #if ENABLE_FEATURE_SETPRIV_DUMP | 313 | #if ENABLE_FEATURE_SETPRIV_DUMP |
diff --git a/util-linux/setsid.c b/util-linux/setsid.c index 60cab2fcf..8385a9115 100644 --- a/util-linux/setsid.c +++ b/util-linux/setsid.c | |||
@@ -37,8 +37,8 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) | |||
37 | { | 37 | { |
38 | unsigned opt; | 38 | unsigned opt; |
39 | 39 | ||
40 | opt_complementary = "-1"; /* at least one arg */ | 40 | /* +: stop on first non-opt */ |
41 | opt = getopt32(argv, "+c"); /* +: stop on first non-opt */ | 41 | opt = getopt32(argv, "^+" "c" "\0" "-1"/* at least one arg */); |
42 | argv += optind; | 42 | argv += optind; |
43 | 43 | ||
44 | /* setsid() is allowed only when we are not a process group leader. | 44 | /* setsid() is allowed only when we are not a process group leader. |
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index 32708934e..080b05e45 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c | |||
@@ -24,22 +24,33 @@ | |||
24 | //config: * Because the Linux kernel uses rootfs internally as the starting | 24 | //config: * Because the Linux kernel uses rootfs internally as the starting |
25 | //config: and ending point for searching through the kernel's doubly linked | 25 | //config: and ending point for searching through the kernel's doubly linked |
26 | //config: list of active mount points. That's why. | 26 | //config: list of active mount points. That's why. |
27 | //config: | ||
28 | // RUN_INIT config item is in klibc-utils | ||
27 | 29 | ||
28 | //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) | 30 | //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) |
31 | // APPLET_ODDNAME:name main location suid_type help | ||
32 | //applet:IF_RUN_INIT( APPLET_ODDNAME(run-init, switch_root, BB_DIR_SBIN, BB_SUID_DROP, run_init)) | ||
29 | 33 | ||
30 | //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o | 34 | //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o |
31 | 35 | //kbuild:lib-$(CONFIG_RUN_INIT) += switch_root.o | |
32 | //usage:#define switch_root_trivial_usage | ||
33 | //usage: "[-c /dev/console] NEW_ROOT NEW_INIT [ARGS]" | ||
34 | //usage:#define switch_root_full_usage "\n\n" | ||
35 | //usage: "Free initramfs and switch to another root fs:\n" | ||
36 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
37 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
38 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
39 | 36 | ||
40 | #include <sys/vfs.h> | 37 | #include <sys/vfs.h> |
41 | #include <sys/mount.h> | 38 | #include <sys/mount.h> |
39 | #if ENABLE_RUN_INIT | ||
40 | # include <sys/prctl.h> | ||
41 | # include <linux/capability.h> | ||
42 | // #include <sys/capability.h> | ||
43 | // This header is in libcap, but the functions are in libc. | ||
44 | // Comment in the header says this above capset/capget: | ||
45 | /* system calls - look to libc for function to system call mapping */ | ||
46 | extern int capset(cap_user_header_t header, cap_user_data_t data); | ||
47 | extern int capget(cap_user_header_t header, const cap_user_data_t data); | ||
48 | // so for bbox, let's just repeat the declarations. | ||
49 | // This way, libcap needs not be installed in build environment. | ||
50 | #endif | ||
51 | |||
42 | #include "libbb.h" | 52 | #include "libbb.h" |
53 | |||
43 | // Make up for header deficiencies | 54 | // Make up for header deficiencies |
44 | #ifndef RAMFS_MAGIC | 55 | #ifndef RAMFS_MAGIC |
45 | # define RAMFS_MAGIC ((unsigned)0x858458f6) | 56 | # define RAMFS_MAGIC ((unsigned)0x858458f6) |
@@ -89,17 +100,125 @@ static void delete_contents(const char *directory, dev_t rootdev) | |||
89 | } | 100 | } |
90 | } | 101 | } |
91 | 102 | ||
103 | #if ENABLE_RUN_INIT | ||
104 | DEFINE_STRUCT_CAPS; | ||
105 | |||
106 | static void drop_capset(int cap_idx) | ||
107 | { | ||
108 | struct caps caps; | ||
109 | |||
110 | getcaps(&caps); | ||
111 | caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx); | ||
112 | if (capset(&caps.header, caps.data) != 0) | ||
113 | bb_perror_msg_and_die("capset"); | ||
114 | } | ||
115 | |||
116 | static void drop_bounding_set(int cap_idx) | ||
117 | { | ||
118 | int ret; | ||
119 | |||
120 | ret = prctl(PR_CAPBSET_READ, cap_idx, 0, 0, 0); | ||
121 | if (ret < 0) | ||
122 | bb_perror_msg_and_die("prctl: %s", "PR_CAPBSET_READ"); | ||
123 | |||
124 | if (ret == 1) { | ||
125 | ret = prctl(PR_CAPBSET_DROP, cap_idx, 0, 0, 0); | ||
126 | if (ret != 0) | ||
127 | bb_perror_msg_and_die("prctl: %s", "PR_CAPBSET_DROP"); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static void drop_usermodehelper(const char *filename, int cap_idx) | ||
132 | { | ||
133 | unsigned lo, hi; | ||
134 | char buf[sizeof(int)*3 * 2 + 8]; | ||
135 | int fd; | ||
136 | int ret; | ||
137 | |||
138 | ret = open_read_close(filename, buf, sizeof(buf) - 1); | ||
139 | if (ret < 0) | ||
140 | return; /* assuming files do not exist */ | ||
141 | |||
142 | buf[ret] = '\0'; | ||
143 | ret = sscanf(buf, "%u %u", &lo, &hi); | ||
144 | if (ret != 2) | ||
145 | bb_perror_msg_and_die("can't parse file '%s'", filename); | ||
146 | |||
147 | if (cap_idx < 32) | ||
148 | lo &= ~(1 << cap_idx); | ||
149 | else | ||
150 | hi &= ~(1 << (cap_idx - 32)); | ||
151 | |||
152 | fd = xopen(filename, O_WRONLY); | ||
153 | fdprintf(fd, "%u %u", lo, hi); | ||
154 | close(fd); | ||
155 | } | ||
156 | |||
157 | static void drop_capabilities(char *string) | ||
158 | { | ||
159 | char *cap; | ||
160 | |||
161 | cap = strtok(string, ","); | ||
162 | while (cap) { | ||
163 | unsigned cap_idx; | ||
164 | |||
165 | cap_idx = cap_name_to_number(cap); | ||
166 | drop_usermodehelper("/proc/sys/kernel/usermodehelper/bset", cap_idx); | ||
167 | drop_usermodehelper("/proc/sys/kernel/usermodehelper/inheritable", cap_idx); | ||
168 | drop_bounding_set(cap_idx); | ||
169 | drop_capset(cap_idx); | ||
170 | bb_error_msg("dropped capability: %s", cap); | ||
171 | cap = strtok(NULL, ","); | ||
172 | } | ||
173 | } | ||
174 | #endif | ||
175 | |||
92 | int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 176 | int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
93 | int switch_root_main(int argc UNUSED_PARAM, char **argv) | 177 | int switch_root_main(int argc UNUSED_PARAM, char **argv) |
94 | { | 178 | { |
95 | char *newroot, *console = NULL; | 179 | char *newroot, *console = NULL; |
96 | struct stat st; | 180 | struct stat st; |
97 | struct statfs stfs; | 181 | struct statfs stfs; |
182 | unsigned dry_run = 0; | ||
98 | dev_t rootdev; | 183 | dev_t rootdev; |
99 | 184 | ||
100 | // Parse args (-c console) | 185 | // Parse args. '+': stop at first non-option |
101 | opt_complementary = "-2"; // minimum 2 params | 186 | if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) { |
102 | getopt32(argv, "+c:", &console); // '+': stop at first non-option | 187 | //usage:#define switch_root_trivial_usage |
188 | //usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" | ||
189 | //usage:#define switch_root_full_usage "\n\n" | ||
190 | //usage: "Free initramfs and switch to another root fs:\n" | ||
191 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
192 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
193 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
194 | getopt32(argv, "^+" | ||
195 | "c:" | ||
196 | "\0" "-2" /* minimum 2 args */, | ||
197 | &console | ||
198 | ); | ||
199 | } else { | ||
200 | #if ENABLE_RUN_INIT | ||
201 | //usage:#define run_init_trivial_usage | ||
202 | //usage: "[-d CAP,CAP...] [-n] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" | ||
203 | //usage:#define run_init_full_usage "\n\n" | ||
204 | //usage: "Free initramfs and switch to another root fs:\n" | ||
205 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
206 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
207 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
208 | //usage: "\n -d CAPS Drop capabilities" | ||
209 | //usage: "\n -n Dry run" | ||
210 | char *cap_list = NULL; | ||
211 | dry_run = getopt32(argv, "^+" | ||
212 | "c:d:n" | ||
213 | "\0" "-2" /* minimum 2 args */, | ||
214 | &console, | ||
215 | &cap_list | ||
216 | ); | ||
217 | dry_run >>= 2; // -n | ||
218 | if (cap_list) | ||
219 | drop_capabilities(cap_list); | ||
220 | #endif | ||
221 | } | ||
103 | argv += optind; | 222 | argv += optind; |
104 | newroot = *argv++; | 223 | newroot = *argv++; |
105 | 224 | ||
@@ -108,9 +227,12 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
108 | xstat("/", &st); | 227 | xstat("/", &st); |
109 | rootdev = st.st_dev; | 228 | rootdev = st.st_dev; |
110 | xstat(".", &st); | 229 | xstat(".", &st); |
111 | if (st.st_dev == rootdev || getpid() != 1) { | 230 | if (st.st_dev == rootdev) { |
112 | // Show usage, it says new root must be a mountpoint | 231 | // Show usage, it says new root must be a mountpoint |
113 | // and we must be PID 1 | 232 | bb_show_usage(); |
233 | } | ||
234 | if (!dry_run && getpid() != 1) { | ||
235 | // Show usage, it says we must be PID 1 | ||
114 | bb_show_usage(); | 236 | bb_show_usage(); |
115 | } | 237 | } |
116 | 238 | ||
@@ -118,7 +240,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
118 | // we mean it. I could make this a CONFIG option, but I would get email | 240 | // we mean it. I could make this a CONFIG option, but I would get email |
119 | // from all the people who WILL destroy their filesystems. | 241 | // from all the people who WILL destroy their filesystems. |
120 | if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) { | 242 | if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) { |
121 | bb_error_msg_and_die("/init is not a regular file"); | 243 | bb_error_msg_and_die("'%s' is not a regular file", "/init"); |
122 | } | 244 | } |
123 | statfs("/", &stfs); // this never fails | 245 | statfs("/", &stfs); // this never fails |
124 | if ((unsigned)stfs.f_type != RAMFS_MAGIC | 246 | if ((unsigned)stfs.f_type != RAMFS_MAGIC |
@@ -127,13 +249,15 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
127 | bb_error_msg_and_die("root filesystem is not ramfs/tmpfs"); | 249 | bb_error_msg_and_die("root filesystem is not ramfs/tmpfs"); |
128 | } | 250 | } |
129 | 251 | ||
130 | // Zap everything out of rootdev | 252 | if (!dry_run) { |
131 | delete_contents("/", rootdev); | 253 | // Zap everything out of rootdev |
254 | delete_contents("/", rootdev); | ||
132 | 255 | ||
133 | // Overmount / with newdir and chroot into it | 256 | // Overmount / with newdir and chroot into it |
134 | if (mount(".", "/", NULL, MS_MOVE, NULL)) { | 257 | if (mount(".", "/", NULL, MS_MOVE, NULL)) { |
135 | // For example, fails when newroot is not a mountpoint | 258 | // For example, fails when newroot is not a mountpoint |
136 | bb_perror_msg_and_die("error moving root"); | 259 | bb_perror_msg_and_die("error moving root"); |
260 | } | ||
137 | } | 261 | } |
138 | xchroot("."); | 262 | xchroot("."); |
139 | // The chdir is needed to recalculate "." and ".." links | 263 | // The chdir is needed to recalculate "." and ".." links |
@@ -149,8 +273,17 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
149 | } | 273 | } |
150 | } | 274 | } |
151 | 275 | ||
152 | // Exec real init | 276 | if (dry_run) { |
153 | execv(argv[0], argv); | 277 | // Does NEW_INIT look like it can be executed? |
278 | //xstat(argv[0], &st); | ||
279 | //if (!S_ISREG(st.st_mode)) | ||
280 | // bb_perror_msg_and_die("'%s' is not a regular file", argv[0]); | ||
281 | if (access(argv[0], X_OK) == 0) | ||
282 | return 0; | ||
283 | } else { | ||
284 | // Exec NEW_INIT | ||
285 | execv(argv[0], argv); | ||
286 | } | ||
154 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | 287 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); |
155 | } | 288 | } |
156 | 289 | ||
diff --git a/util-linux/taskset.c b/util-linux/taskset.c index 9957b1a71..401a1bcb7 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c | |||
@@ -22,7 +22,7 @@ | |||
22 | //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long | 22 | //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long |
23 | //config: in this case. Otherwise, it is limited to sizeof(long). | 23 | //config: in this case. Otherwise, it is limited to sizeof(long). |
24 | 24 | ||
25 | //applet:IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP)) | 25 | //applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset)) |
26 | //kbuild:lib-$(CONFIG_TASKSET) += taskset.o | 26 | //kbuild:lib-$(CONFIG_TASKSET) += taskset.o |
27 | 27 | ||
28 | //usage:#define taskset_trivial_usage | 28 | //usage:#define taskset_trivial_usage |
@@ -123,8 +123,7 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) | |||
123 | * Indeed, util-linux-2.13-pre7 uses: | 123 | * Indeed, util-linux-2.13-pre7 uses: |
124 | * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ | 124 | * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ |
125 | 125 | ||
126 | opt_complementary = "-1"; /* at least 1 arg */ | 126 | opt_p = getopt32(argv, "^+" "p" "\0" "-1" /* at least 1 arg */); |
127 | opt_p = getopt32(argv, "+p"); | ||
128 | argv += optind; | 127 | argv += optind; |
129 | 128 | ||
130 | aff = *argv++; | 129 | aff = *argv++; |
diff --git a/util-linux/uevent.c b/util-linux/uevent.c index 252e8fb64..7ff866cec 100644 --- a/util-linux/uevent.c +++ b/util-linux/uevent.c | |||
@@ -32,7 +32,10 @@ | |||
32 | #define env ((char **)bb_common_bufsiz1) | 32 | #define env ((char **)bb_common_bufsiz1) |
33 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 33 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
34 | enum { | 34 | enum { |
35 | MAX_ENV = COMMON_BUFSIZE / sizeof(env[0]) - 1, | 35 | MAX_ENV = COMMON_BUFSIZE / sizeof(char*) - 1, |
36 | /* sizeof(env[0]) instead of sizeof(char*) | ||
37 | * makes gcc-6.3.0 emit "strict-aliasing" warning. | ||
38 | */ | ||
36 | }; | 39 | }; |
37 | 40 | ||
38 | #ifndef SO_RCVBUFFORCE | 41 | #ifndef SO_RCVBUFFORCE |
diff --git a/util-linux/umount.c b/util-linux/umount.c index 122c0f579..a6405dfcc 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c | |||
@@ -24,7 +24,20 @@ | |||
24 | //config: help | 24 | //config: help |
25 | //config: Support -a option to unmount all currently mounted filesystems. | 25 | //config: Support -a option to unmount all currently mounted filesystems. |
26 | 26 | ||
27 | //applet:IF_UMOUNT(APPLET(umount, BB_DIR_BIN, BB_SUID_DROP)) | 27 | //applet:IF_UMOUNT(APPLET_NOEXEC(umount, umount, BB_DIR_BIN, BB_SUID_DROP, umount)) |
28 | /* | ||
29 | * On one hand, in some weird situations you'd want umount | ||
30 | * to not do anything surprising, to behave as a usual fork+execed executable. | ||
31 | * | ||
32 | * OTOH, there can be situations where execing would not succeed, or even hang | ||
33 | * (say, if executable is on a filesystem which is in trouble and accesses to it | ||
34 | * block in kernel). | ||
35 | * In this case, you might be actually happy if your standalone bbox shell | ||
36 | * does not fork+exec, but only forks and calls umount_main() which it already has! | ||
37 | * Let's go with NOEXEC. | ||
38 | * | ||
39 | * bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. | ||
40 | */ | ||
28 | 41 | ||
29 | //kbuild:lib-$(CONFIG_UMOUNT) += umount.o | 42 | //kbuild:lib-$(CONFIG_UMOUNT) += umount.o |
30 | 43 | ||
diff --git a/util-linux/unshare.c b/util-linux/unshare.c index e7b95c72b..6a3da9f91 100644 --- a/util-linux/unshare.c +++ b/util-linux/unshare.c | |||
@@ -137,7 +137,7 @@ static const struct namespace_descr ns_list[] = { | |||
137 | * we are forced to use "fake" letters for them. | 137 | * we are forced to use "fake" letters for them. |
138 | * '+': stop at first non-option. | 138 | * '+': stop at first non-option. |
139 | */ | 139 | */ |
140 | static const char opt_str[] ALIGN1 = "+muinpU""fr""\xfd::""\xfe:""\xff:"; | 140 | #define OPT_STR "+muinpU""fr""\xfd::""\xfe:""\xff:" |
141 | static const char unshare_longopts[] ALIGN1 = | 141 | static const char unshare_longopts[] ALIGN1 = |
142 | "mount\0" Optional_argument "\xf0" | 142 | "mount\0" Optional_argument "\xf0" |
143 | "uts\0" Optional_argument "\xf1" | 143 | "uts\0" Optional_argument "\xf1" |
@@ -210,7 +210,7 @@ int unshare_main(int argc UNUSED_PARAM, char **argv) | |||
210 | prop_str = PRIVATE_STR; | 210 | prop_str = PRIVATE_STR; |
211 | setgrp_str = NULL; | 211 | setgrp_str = NULL; |
212 | 212 | ||
213 | opt_complementary = | 213 | opts = getopt32long(argv, "^" OPT_STR "\0" |
214 | "\xf0""m" /* long opts (via their "fake chars") imply short opts */ | 214 | "\xf0""m" /* long opts (via their "fake chars") imply short opts */ |
215 | ":\xf1""u" | 215 | ":\xf1""u" |
216 | ":\xf2""i" | 216 | ":\xf2""i" |
@@ -219,16 +219,14 @@ int unshare_main(int argc UNUSED_PARAM, char **argv) | |||
219 | ":\xf5""U" | 219 | ":\xf5""U" |
220 | ":ru" /* --map-root-user or -r implies -u */ | 220 | ":ru" /* --map-root-user or -r implies -u */ |
221 | ":\xfd""m" /* --mount-proc implies -m */ | 221 | ":\xfd""m" /* --mount-proc implies -m */ |
222 | ; | 222 | , unshare_longopts, |
223 | applet_long_options = unshare_longopts; | 223 | &proc_mnt_target, &prop_str, &setgrp_str, |
224 | opts = getopt32(argv, opt_str, | 224 | &ns_ctx_list[NS_MNT_POS].path, |
225 | &proc_mnt_target, &prop_str, &setgrp_str, | 225 | &ns_ctx_list[NS_UTS_POS].path, |
226 | &ns_ctx_list[NS_MNT_POS].path, | 226 | &ns_ctx_list[NS_IPC_POS].path, |
227 | &ns_ctx_list[NS_UTS_POS].path, | 227 | &ns_ctx_list[NS_NET_POS].path, |
228 | &ns_ctx_list[NS_IPC_POS].path, | 228 | &ns_ctx_list[NS_PID_POS].path, |
229 | &ns_ctx_list[NS_NET_POS].path, | 229 | &ns_ctx_list[NS_USR_POS].path |
230 | &ns_ctx_list[NS_PID_POS].path, | ||
231 | &ns_ctx_list[NS_USR_POS].path | ||
232 | ); | 230 | ); |
233 | argv += optind; | 231 | argv += optind; |
234 | //bb_error_msg("opts:0x%x", opts); | 232 | //bb_error_msg("opts:0x%x", opts); |