+#include "busybox.h" /* uses applet tables */
+#include "NUM_APPLETS.h"
+
+#define NOFORK_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_NOFORK))
+#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE))
+
+#if defined(__linux__) && (NUM_APPLETS > 1)
+# include <sys/prctl.h>
+# ifndef PR_SET_NAME
+# define PR_SET_NAME 15
+# endif
+# ifndef PR_GET_NAME
+# define PR_GET_NAME 16
+# endif
+void FAST_FUNC set_task_comm(const char *comm)
+{
+ /* okay if too long (truncates) */
+ prctl(PR_SET_NAME, (long)comm, 0, 0, 0);
+}
+#endif
+
+/*
+ * NOFORK/NOEXEC support
+ */
+#if NOFORK_SUPPORT
+static jmp_buf die_jmp;
+static void jump(void)
+{
+ /* Special case. We arrive here if NOFORK applet
+ * calls xfunc, which then decides to die.
+ * We don't die, but instead jump back to caller.
+ * NOFORK applets still cannot carelessly call xfuncs:
+ * p = xmalloc(10);
+ * q = xmalloc(10); // BUG! if this dies, we leak p!
+ */
+ /* | 0x100 allows to pass zero exitcode (longjmp can't pass 0).
+ * This works because exitcodes are bytes,
+ * run_nofork_applet() ensures that by "& 0xff"
+ */
+ longjmp(die_jmp, xfunc_error_retval | 0x100);
+}
+
+struct nofork_save_area {
+ jmp_buf die_jmp;
+ void (*die_func)(void);
+ const char *applet_name;
+ uint32_t option_mask32;
+ smallint logmode;
+ uint8_t xfunc_error_retval;
+};
+static void save_nofork_data(struct nofork_save_area *save)
+{
+ memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
+ save->die_func = die_func;
+ save->applet_name = applet_name;
+ save->option_mask32 = option_mask32;
+ save->logmode = logmode;
+ save->xfunc_error_retval = xfunc_error_retval;
+}
+static void restore_nofork_data(struct nofork_save_area *save)
+{
+ memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
+ die_func = save->die_func;
+ applet_name = save->applet_name;
+ option_mask32 = save->option_mask32;
+ logmode = save->logmode;
+ xfunc_error_retval = save->xfunc_error_retval;
+}
+
+int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
+{
+ int rc, argc;
+ struct nofork_save_area old;
+
+ save_nofork_data(&old);
+
+ logmode = LOGMODE_STDIO;
+ xfunc_error_retval = EXIT_FAILURE;
+ /* In case getopt() was already called:
+ * reset the libc getopt() function, which keeps internal state.
+ * (getopt32() does it itself, but getopt() doesn't (and can't))
+ */
+ GETOPT_RESET();
+
+ argc = string_array_len(argv);
+
+ /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */
+ die_func = jump;
+ rc = setjmp(die_jmp);
+ if (!rc) {
+ /* Some callers (xargs)
+ * need argv untouched because they free argv[i]! */
+ char *tmp_argv[argc+1];
+ memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
+ applet_name = tmp_argv[0];
+ /* Finally we can call NOFORK applet's main() */
+ rc = applet_main[applet_no](argc, tmp_argv);
+ /* Important for shells: `which CMD` was failing */
+ fflush_all();
+ } else {
+ /* xfunc died in NOFORK applet */
+ }
+
+ /* Restoring some globals */
+ restore_nofork_data(&old);
+ /* Other globals can be simply reset to defaults */
+ GETOPT_RESET();
+
+ return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
+}
+#endif
+
+#if NOEXEC_SUPPORT
+void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
+{
+ /* reset some state and run without execing */
+ /* msg_eol = "\n"; - no caller needs this reinited yet */
+ logmode = LOGMODE_STDIO;
+ xfunc_error_retval = EXIT_FAILURE;
+ die_func = NULL;
+ GETOPT_RESET();
+
+//TODO: think pidof, pgrep, pkill!
+//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"),
+//but one from procps-ng-3.3.10 needs more!
+//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!)
+ set_task_comm(name);
+ /* applet_name is set by this function: */
+ run_applet_no_and_exit(a, name, argv);
+}
+#endif