blob: c58f5a83f139ef0fe78bcfff3f2f78a238df8f5c
1 | NOEXEC and NOFORK applets. |
2 | |
3 | Unix shells traditionally execute some commands internally in the attempt |
4 | to dramatically speed up execution. It will be slow as hell if for every |
5 | "echo blah" shell will fork and exec /bin/echo. To this end, shells |
6 | have to _reimplement_ these commands internally. |
7 | |
8 | Busybox is unique in this regard because it already is a collection |
9 | of reimplemented Unix commands, and we can do the same trick |
10 | for speeding up busybox shells, and more. NOEXEC and NOFORK applets |
11 | are exactly those applets which are eligible for these tricks. |
12 | |
13 | Applet will be subject to NOFORK/NOEXEC tricks if it is marked as such |
14 | in applets.h. FEATURE_PREFER_APPLETS is a config option which |
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 | |
21 | 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,...). |
23 | They check whether program name is an applet name and optionally |
24 | do NOFORK/NOEXEC thing depending on configuration. |
25 | |
26 | |
27 | NOEXEC |
28 | |
29 | NOEXEC applet should work correctly if another applet forks and then |
30 | executes exit(<applet>_main(argc,argv)) in the child. The rules |
31 | roughly are: |
32 | |
33 | * do not expect shared global variables/buffers to be in their |
34 | "initialized" state. Examples: xfunc_error_retval can be != 1, |
35 | bb_common_bufsiz1 can be scribbled over, ... |
36 | * do not expect that stdio wasn't used before. Calling set[v]buf() |
37 | can be disastrous. |
38 | * ... |
39 | |
40 | NOEXEC applets save only one half of fork+exec overhead. |
41 | NOEXEC trick is disabled for NOMMU build. |
42 | |
43 | |
44 | NOFORK |
45 | |
46 | NOFORK applet should work correctly if another applet simply runs |
47 | <applet>_main(argc,argv) and then continues with its business. |
48 | xargs, find, shells do it (grep for "spawn_and_wait" and |
49 | "run_nofork_applet" to find more users). |
50 | |
51 | This poses much more serious limitations on what applet can do: |
52 | |
53 | * all NOEXEC limitations apply. |
54 | * do not ever exit() or exec(). |
55 | - xfuncs are okay. They are using special trick to return |
56 | to the caller applet instead of dying when they detect "x" condition. |
57 | - you may "exit" to caller applet by calling xfunc_die(). Return value |
58 | is taken from xfunc_error_retval. |
59 | - fflush_stdout_and_exit(n) is ok to use. |
60 | * do not use shared global data, or save/restore shared global data |
61 | (e.g. bb_common_bufsiz1) prior to returning. |
62 | - getopt32() is ok to use. You do not need to save/restore option_mask32, |
63 | it is already done by core code. |
64 | * if you allocate memory, you can use xmalloc() only on the very first |
65 | allocation. All other allocations should use malloc[_or_warn](). |
66 | After first allocation, you cannot use any xfuncs. |
67 | Otherwise, failing xfunc will return to caller applet |
68 | without freeing malloced data! |
69 | * All allocated data, opened files, signal handlers, termios settings, |
70 | O_NONBLOCK flags etc should be freed/closed/restored prior to return. |
71 | * ... |
72 | |
73 | NOFORK applets give the most of speed advantage, but are trickiest |
74 | to implement. In order to minimize amount of bugs and maintenance, |
75 | prime candidates for NOFORK-ification are those applets which |
76 | are small and easy to audit, and those which are more likely to be |
77 | frequently executed from shell/find/xargs, particularly in shell |
78 | script loops. Applets which mess with signal handlers, termios etc |
79 | are probably not worth the effort. |
80 | |
81 | Any NOFORK applet is also a NOEXEC applet. |
82 | |
83 | |
84 | Relevant CONFIG options |
85 | |
86 | FEATURE_PREFER_APPLETS |
87 | BB_EXECVP(cmd, argv) will try to exec /proc/self/exe |
88 | if command's name matches some applet name |
89 | applet tables will contain NOFORK/NOEXEC bits |
90 | spawn_and_wait(argv) will do NOFORK/NOEXEC tricks |
91 | |
92 | FEATURE_SH_STANDALONE (needs FEATURE_PREFER_APPLETS=y) |
93 | shells will try to exec /proc/self/exe if command's name matches |
94 | some applet name |
95 | shells will do NOEXEC trick on NOEXEC applets |
96 | |
97 | FEATURE_SH_NOFORK (needs FEATURE_PREFER_APPLETS=y) |
98 | shells will do NOFORK trick on NOFORK applets |
99 |