mv: implement -n option
[oweals/busybox.git] / libbb / appletlib.c
index 953f1e7e5e7b36711f10fa43c61da4817b57a0b9..b32ff8808ca1a120ead2efd0cb92e2e079073831 100644 (file)
@@ -7,13 +7,35 @@
  * here, please feel free to acknowledge your work.
  *
  * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
- * Permission has been granted to redistribute this code under the GPL.
+ * Permission has been granted to redistribute this code under GPL.
  *
- * Licensed under GPLv2 or later, see file License in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 
-#include <assert.h>
+/* We are trying to not use printf, this benefits the case when selected
+ * applets are really simple. Example:
+ *
+ * $ ./busybox
+ * ...
+ * Currently defined functions:
+ *         basename, false, true
+ *
+ * $ size busybox
+ *    text    data     bss     dec     hex filename
+ *    4473      52      72    4597    11f5 busybox
+ *
+ * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
+ */
 #include "busybox.h"
+#include <assert.h>
+#include <malloc.h>
+/* Try to pull in PAGE_SIZE */
+#ifdef __linux__
+# include <sys/user.h>
+#endif
+#ifdef __GNU__ /* Hurd */
+# include <mach/vm_param.h>
+#endif
 
 
 /* Declare <applet>_main() */
 #include "applets.h"
 #undef PROTOTYPES
 
-#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
-/* Define usage_messages[] */
-static const char usage_messages[] ALIGN1 = ""
-#define MAKE_USAGE
-#include "usage.h"
-#include "applets.h"
-;
-#undef MAKE_USAGE
-#else
-#define usage_messages 0
-#endif /* SHOW_USAGE */
-
-/* Define struct bb_applet applets[] */
-#include "applets.h"
 
-#if ENABLE_FEATURE_SH_STANDALONE
-/* -1 because last entry is NULL */
-const unsigned short NUM_APPLETS = ARRAY_SIZE(applets) - 1;
+/* Include generated applet names, pointers to <applet>_main, etc */
+#include "applet_tables.h"
+/* ...and if applet_tables generator says we have only one applet... */
+#ifdef SINGLE_APPLET_MAIN
+# undef ENABLE_FEATURE_INDIVIDUAL
+# define ENABLE_FEATURE_INDIVIDUAL 1
+# undef IF_FEATURE_INDIVIDUAL
+# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
 #endif
 
 
-#if ENABLE_FEATURE_COMPRESS_USAGE
-
 #include "usage_compressed.h"
-#include "unarchive.h"
 
+#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
+static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
+#else
+# define usage_messages 0
+#endif
+
+#if ENABLE_FEATURE_COMPRESS_USAGE
+
+static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
+# include "unarchive.h"
 static const char *unpack_usage_messages(void)
 {
        char *outbuf = NULL;
@@ -55,83 +75,118 @@ static const char *unpack_usage_messages(void)
 
        i = start_bunzip(&bd,
                        /* src_fd: */ -1,
-                       /* inbuf:  */ packed_usage,
+                       /* inbuf:  */ (void *)packed_usage,
                        /* len:    */ sizeof(packed_usage));
        /* read_bunzip can longjmp to start_bunzip, and ultimately
         * end up here with i != 0 on read data errors! Not trivial */
        if (!i) {
                /* Cannot use xmalloc: will leak bd in NOFORK case! */
-               outbuf = malloc_or_warn(SIZEOF_usage_messages);
+               outbuf = malloc_or_warn(sizeof(UNPACKED_USAGE));
                if (outbuf)
-                       read_bunzip(bd, outbuf, SIZEOF_usage_messages);
+                       read_bunzip(bd, outbuf, sizeof(UNPACKED_USAGE));
        }
        dealloc_bunzip(bd);
        return outbuf;
 }
-#define dealloc_usage_messages(s) free(s)
+# define dealloc_usage_messages(s) free(s)
 
 #else
 
-#define unpack_usage_messages() usage_messages
-#define dealloc_usage_messages(s) ((void)(s))
+# define unpack_usage_messages() usage_messages
+# define dealloc_usage_messages(s) ((void)(s))
 
 #endif /* FEATURE_COMPRESS_USAGE */
 
 
-void bb_show_usage(void)
+void FAST_FUNC bb_show_usage(void)
 {
        if (ENABLE_SHOW_USAGE) {
-               const char *format_string;
+#ifdef SINGLE_APPLET_STR
+               /* Imagine that this applet is "true". Dont suck in printf! */
                const char *p;
                const char *usage_string = p = unpack_usage_messages();
-               const struct bb_applet *ap = find_applet_by_name(applet_name);
-               int i;
 
-               if (!ap) /* never happens, paranoia */
-                       xfunc_die();
+               if (*p == '\b') {
+                       full_write2_str("No help available.\n\n");
+               } else {
+                       full_write2_str("Usage: "SINGLE_APPLET_STR" ");
+                       full_write2_str(p);
+                       full_write2_str("\n\n");
+               }
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       dealloc_usage_messages((char*)usage_string);
+#else
+               const char *p;
+               const char *usage_string = p = unpack_usage_messages();
+               int ap = find_applet_by_name(applet_name);
 
-               i = ap - applets;
-               while (i) {
+               if (ap < 0) /* never happens, paranoia */
+                       xfunc_die();
+               while (ap) {
                        while (*p++) continue;
-                       i--;
+                       ap--;
                }
-
-               fprintf(stderr, "%s multi-call binary\n", bb_banner);
-               format_string = "\nUsage: %s %s\n\n";
+               full_write2_str(bb_banner);
+               full_write2_str(" multi-call binary.\n");
                if (*p == '\b')
-                       format_string = "\nNo help available.\n\n";
-               fprintf(stderr, format_string, applet_name, p);
-               dealloc_usage_messages((char*)usage_string);
+                       full_write2_str("\nNo help available.\n\n");
+               else {
+                       full_write2_str("\nUsage: ");
+                       full_write2_str(applet_name);
+                       full_write2_str(" ");
+                       full_write2_str(p);
+                       full_write2_str("\n\n");
+               }
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       dealloc_usage_messages((char*)usage_string);
+#endif
        }
        xfunc_die();
 }
 
-
-static int applet_name_compare(const void *name, const void *vapplet)
+#if NUM_APPLETS > 8
+/* NB: any char pointer will work as well, not necessarily applet_names */
+static int applet_name_compare(const void *name, const void *v)
 {
-       const struct bb_applet *applet = vapplet;
-
-       return strcmp(name, applet->name);
+       int i = (const char *)v - applet_names;
+       return strcmp(name, APPLET_NAME(i));
 }
-
-const struct bb_applet *find_applet_by_name(const char *name)
+#endif
+int FAST_FUNC find_applet_by_name(const char *name)
 {
+#if NUM_APPLETS > 8
        /* Do a binary search to find the applet entry given the name. */
-       return bsearch(name, applets, ARRAY_SIZE(applets)-1, sizeof(applets[0]),
-                               applet_name_compare);
+       const char *p;
+       p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
+       if (!p)
+               return -1;
+       return p - applet_names;
+#else
+       /* A version which does not pull in bsearch */
+       int i = 0;
+       const char *p = applet_names;
+       while (i < NUM_APPLETS) {
+               if (strcmp(name, p) == 0)
+                       return i;
+               p += strlen(p) + 1;
+               i++;
+       }
+       return -1;
+#endif
 }
 
 
-#ifdef __GLIBC__
-/* Make it reside in R/W memory: */
-int *const bb_errno __attribute__ ((section (".data")));
-#endif
-
-void lbb_prepare(char **argv)
+void lbb_prepare(const char *applet
+               IF_FEATURE_INDIVIDUAL(, char **argv))
+                               MAIN_EXTERNALLY_VISIBLE;
+void lbb_prepare(const char *applet
+               IF_FEATURE_INDIVIDUAL(, char **argv))
 {
 #ifdef __GLIBC__
        (*(int **)&bb_errno) = __errno_location();
+       barrier();
 #endif
+       applet_name = applet;
 
        /* Set locale for everybody except 'init' */
        if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
@@ -140,8 +195,16 @@ void lbb_prepare(char **argv)
 #if ENABLE_FEATURE_INDIVIDUAL
        /* Redundant for busybox (run_applet_and_exit covers that case)
         * but needed for "individual applet" mode */
-       if (argv[1] && strcmp(argv[1], "--help") == 0)
-               bb_show_usage();
+       if (argv[1]
+        && !argv[2]
+        && strcmp(argv[1], "--help") == 0
+        && strncmp(applet, "busybox", 7) != 0
+       ) {
+               /* Special case. POSIX says "test --help"
+                * should be no different from e.g. "test --foo".  */
+               if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
+                       bb_show_usage();
+       }
 #endif
 }
 
@@ -159,13 +222,17 @@ const char *applet_name;
 bool re_execed;
 #endif
 
-USE_FEATURE_SUID(static uid_t ruid;)  /* real uid */
+
+/* If not built as a single-applet executable... */
+#if !defined(SINGLE_APPLET_MAIN)
+
+IF_FEATURE_SUID(static uid_t ruid;)  /* real uid */
 
 #if ENABLE_FEATURE_SUID_CONFIG
 
 /* applets[] is const, so we have to define this "override" structure */
 static struct BB_suid_config {
-       const struct bb_applet *m_applet;
+       int m_applet;
        uid_t m_uid;
        gid_t m_gid;
        mode_t m_mode;
@@ -231,7 +298,7 @@ static void parse_config_file(void)
 {
        struct BB_suid_config *sct_head;
        struct BB_suid_config *sct;
-       const struct bb_applet *applet;
+       int applet_no;
        FILE *f;
        const char *errmsg;
        char *s;
@@ -252,7 +319,7 @@ static void parse_config_file(void)
         || !S_ISREG(st.st_mode)                /* Not a regular file? */
         || (st.st_uid != 0)                    /* Not owned by root? */
         || (st.st_mode & (S_IWGRP | S_IWOTH))  /* Writable by non-root? */
-        || !(f = fopen(config_file, "r"))      /* Cannot open? */
+        || !(f = fopen_for_read(config_file))      /* Cannot open? */
        ) {
                return;
        }
@@ -265,6 +332,7 @@ static void parse_config_file(void)
                s = buffer;
 
                if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
+// why?
                        if (ferror(f)) {   /* Make sure it wasn't a read error. */
                                parse_error("reading");
                        }
@@ -342,14 +410,14 @@ static void parse_config_file(void)
                         * applet is currently built in and ignore it otherwise.
                         * Note: this can hide config file bugs which only pop
                         * up when the busybox configuration is changed. */
-                       applet = find_applet_by_name(s);
-                       if (applet) {
+                       applet_no = find_applet_by_name(s);
+                       if (applet_no >= 0) {
                                /* Note: We currently don't check for duplicates!
                                 * The last config line for each applet will be the
                                 * one used since we insert at the head of the list.
                                 * I suppose this could be considered a feature. */
                                sct = xmalloc(sizeof(struct BB_suid_config));
-                               sct->m_applet = applet;
+                               sct->m_applet = applet_no;
                                sct->m_mode = 0;
                                sct->m_next = sct_head;
                                sct_head = sct;
@@ -434,13 +502,13 @@ static void parse_config_file(void)
 #else
 static inline void parse_config_file(void)
 {
-       USE_FEATURE_SUID(ruid = getuid();)
+       IF_FEATURE_SUID(ruid = getuid();)
 }
 #endif /* FEATURE_SUID_CONFIG */
 
 
 #if ENABLE_FEATURE_SUID
-static void check_suid(const struct bb_applet *applet)
+static void check_suid(int applet_no)
 {
        gid_t rgid;  /* real gid */
 
@@ -455,13 +523,10 @@ static void check_suid(const struct bb_applet *applet)
                mode_t m;
 
                for (sct = suid_config; sct; sct = sct->m_next) {
-                       if (sct->m_applet == applet)
+                       if (sct->m_applet == applet_no)
                                goto found;
                }
-               /* default: drop all privileges */
-               xsetgid(rgid);
-               xsetuid(ruid);
-               return;
+               goto check_need_suid;
  found:
                m = sct->m_mode;
                if (sct->m_uid == ruid)
@@ -504,14 +569,14 @@ static void check_suid(const struct bb_applet *applet)
                }
        }
 #endif
+ check_need_suid:
 #endif
-
-       if (applet->need_suid == _BB_SUID_ALWAYS) {
+       if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) {
                /* Real uid is not 0. If euid isn't 0 too, suid bit
                 * is most probably not set on our executable */
                if (geteuid())
-                       bb_error_msg_and_die("applet requires root privileges!");
-       } else if (applet->need_suid == _BB_SUID_NEVER) {
+                       bb_error_msg_and_die("must be suid to work properly");
+       } else if (APPLET_SUID(applet_no) == _BB_SUID_DROP) {
                xsetgid(rgid);  /* drop all privileges */
                xsetuid(ruid);
        }
@@ -522,34 +587,41 @@ static void check_suid(const struct bb_applet *applet)
 
 
 #if ENABLE_FEATURE_INSTALLER
+static const char usr_bin [] ALIGN1 = "/usr/bin/";
+static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
+static const char *const install_dir[] = {
+       &usr_bin [8], /* "/" */
+       &usr_bin [4], /* "/bin/" */
+       &usr_sbin[4]  /* "/sbin/" */
+# if !ENABLE_INSTALL_NO_USR
+       ,usr_bin
+       ,usr_sbin
+# endif
+};
+
+
 /* create (sym)links for each applet */
-static void install_links(const char *busybox, int use_symbolic_links)
+static void install_links(const char *busybox, int use_symbolic_links,
+               char *custom_install_dir)
 {
        /* directory table
         * this should be consistent w/ the enum,
         * busybox.h::bb_install_loc_t, or else... */
-       static const char usr_bin [] ALIGN1 = "/usr/bin";
-       static const char usr_sbin[] ALIGN1 = "/usr/sbin";
-       static const char *const install_dir[] = {
-               &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
-               &usr_bin [4], /* "/bin" */
-               &usr_sbin[4], /* "/sbin" */
-               usr_bin,
-               usr_sbin
-       };
-
-       int (*lf)(const char *, const char *) = link;
+       int (*lf)(const char *, const char *);
        char *fpc;
-       int i;
+       unsigned i;
        int rc;
 
+       lf = link;
        if (use_symbolic_links)
                lf = symlink;
 
-       for (i = 0; applets[i].name != NULL; i++) {
+       for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
                fpc = concat_path_file(
-                               install_dir[applets[i].install_loc],
-                               applets[i].name);
+                               custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
+                               APPLET_NAME(i));
+               // debug: bb_error_msg("%slinking %s to busybox",
+               //              use_symbolic_links ? "sym" : "", fpc);
                rc = lf(busybox, fpc);
                if (rc != 0 && errno != EEXIST) {
                        bb_simple_perror_msg(fpc);
@@ -558,58 +630,95 @@ static void install_links(const char *busybox, int use_symbolic_links)
        }
 }
 #else
-#define install_links(x,y) ((void)0)
-#endif /* FEATURE_INSTALLER */
+# define install_links(x,y,z) ((void)0)
+#endif
 
 /* If we were called as "busybox..." */
 static int busybox_main(char **argv)
 {
        if (!argv[1]) {
                /* Called without arguments */
-               const struct bb_applet *a;
-               int col, output_width;
+               const char *a;
+               int col;
+               unsigned output_width;
  help:
                output_width = 80;
                if (ENABLE_FEATURE_AUTOWIDTH) {
                        /* Obtain the terminal width */
                        get_terminal_width_height(0, &output_width, NULL);
                }
-               /* leading tab and room to wrap */
-               output_width -= sizeof("start-stop-daemon, ") + 8;
-
-               printf("%s multi-call binary\n", bb_banner); /* reuse const string... */
-               printf("Copyright (C) 1998-2006 Erik Andersen, Rob Landley, and others.\n"
-                      "Licensed under GPLv2. See source distribution for full notice.\n"
-                      "\n"
-                      "Usage: busybox [function] [arguments]...\n"
-                      "   or: [function] [arguments]...\n"
-                      "\n"
-                      "\tBusyBox is a multi-call binary that combines many common Unix\n"
-                      "\tutilities into a single executable.  Most people will create a\n"
-                      "\tlink to busybox for each function they wish to use and BusyBox\n"
-                      "\twill act like whatever it was invoked as!\n"
-                      "\nCurrently defined functions:\n");
+
+               dup2(1, 2);
+               full_write2_str(bb_banner); /* reuse const string */
+               full_write2_str(" multi-call binary.\n"); /* reuse */
+               full_write2_str(
+                       "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n"
+                       "and others. Licensed under GPLv2.\n"
+                       "See source distribution for full notice.\n"
+                       "\n"
+                       "Usage: busybox [function] [arguments]...\n"
+                       "   or: busybox --list[-full]\n"
+                       "   or: function [arguments]...\n"
+                       "\n"
+                       "\tBusyBox is a multi-call binary that combines many common Unix\n"
+                       "\tutilities into a single executable.  Most people will create a\n"
+                       "\tlink to busybox for each function they wish to use and BusyBox\n"
+                       "\twill act like whatever it was invoked as.\n"
+                       "\n"
+                       "Currently defined functions:\n"
+               );
                col = 0;
-               a = applets;
-               while (a->name) {
-                       if (col > output_width) {
-                               puts(",");
+               a = applet_names;
+               /* prevent last comma to be in the very last pos */
+               output_width--;
+               while (*a) {
+                       int len2 = strlen(a) + 2;
+                       if (col >= (int)output_width - len2) {
+                               full_write2_str(",\n");
                                col = 0;
                        }
-                       col += printf("%s%s", (col ? ", " : "\t"), a->name);
-                       a++;
+                       if (col == 0) {
+                               col = 6;
+                               full_write2_str("\t");
+                       } else {
+                               full_write2_str(", ");
+                       }
+                       full_write2_str(a);
+                       col += len2;
+                       a += len2 - 1;
+               }
+               full_write2_str("\n\n");
+               return 0;
+       }
+
+       if (strncmp(argv[1], "--list", 6) == 0) {
+               unsigned i = 0;
+               const char *a = applet_names;
+               dup2(1, 2);
+               while (*a) {
+#if ENABLE_FEATURE_INSTALLER
+                       if (argv[1][6]) /* --list-path? */
+                               full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
+#endif
+                       full_write2_str(a);
+                       full_write2_str("\n");
+                       i++;
+                       a += strlen(a) + 1;
                }
-               puts("\n");
                return 0;
        }
 
        if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
+               int use_symbolic_links;
                const char *busybox;
                busybox = xmalloc_readlink(bb_busybox_exec_path);
                if (!busybox)
                        busybox = bb_busybox_exec_path;
-               /* -s makes symlinks */
-               install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0);
+               /* busybox --install [-s] [DIR]: */
+               /* -s: make symlinks */
+               /* DIR: directory to install links to */
+               use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++);
+               install_links(busybox, use_symbolic_links, argv[2]);
                return 0;
        }
 
@@ -628,10 +737,14 @@ static int busybox_main(char **argv)
         * "#!/bin/busybox"-style wrappers */
        applet_name = bb_get_last_path_component_nostrip(argv[0]);
        run_applet_and_exit(applet_name, argv);
-       bb_error_msg_and_die("applet not found");
+
+       /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+       full_write2_str(applet_name);
+       full_write2_str(": applet not found\n");
+       xfunc_die();
 }
 
-void run_appletstruct_and_exit(const struct bb_applet *applet, char **argv)
+void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
 {
        int argc = 1;
 
@@ -639,34 +752,65 @@ void run_appletstruct_and_exit(const struct bb_applet *applet, char **argv)
                argc++;
 
        /* Reinit some shared global data */
-       optind = 1;
        xfunc_error_retval = EXIT_FAILURE;
 
-       applet_name = applet->name;
-       if (argc == 2 && !strcmp(argv[1], "--help"))
-               bb_show_usage();
+       applet_name = APPLET_NAME(applet_no);
+       if (argc == 2 && strcmp(argv[1], "--help") == 0) {
+               /* Special case. POSIX says "test --help"
+                * should be no different from e.g. "test --foo".  */
+//TODO: just compare applet_no with APPLET_NO_test
+               if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
+                       bb_show_usage();
+       }
        if (ENABLE_FEATURE_SUID)
-               check_suid(applet);
-       exit(applet->main(argc, argv));
+               check_suid(applet_no);
+       exit(applet_main[applet_no](argc, argv));
 }
 
-void run_applet_and_exit(const char *name, char **argv)
+void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
 {
-       const struct bb_applet *applet = find_applet_by_name(name);
-       if (applet)
-               run_appletstruct_and_exit(applet, argv);
+       int applet = find_applet_by_name(name);
+       if (applet >= 0)
+               run_applet_no_and_exit(applet, argv);
        if (!strncmp(name, "busybox", 7))
                exit(busybox_main(argv));
 }
 
+#endif /* !defined(SINGLE_APPLET_MAIN) */
+
+
 
 #if ENABLE_BUILD_LIBBUSYBOX
-int lbb_main(int argc, char **argv)
+int lbb_main(char **argv)
 #else
-int main(int argc, char **argv)
+int main(int argc UNUSED_PARAM, char **argv)
 #endif
 {
-       lbb_prepare(argv);
+       /* Tweak malloc for reduced memory consumption */
+#ifndef PAGE_SIZE
+# define PAGE_SIZE (4*1024) /* guess */
+#endif
+#ifdef M_TRIM_THRESHOLD
+       /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory
+        * to keep before releasing to the OS
+        * Default is way too big: 256k
+        */
+       mallopt(M_TRIM_THRESHOLD, 2 * PAGE_SIZE);
+#endif
+#ifdef M_MMAP_THRESHOLD
+       /* M_MMAP_THRESHOLD is the request size threshold for using mmap()
+        * Default is too big: 256k
+        */
+       mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256);
+#endif
+
+#if defined(SINGLE_APPLET_MAIN)
+       /* Only one applet is selected by the user! */
+       /* applet_names in this case is just "applet\0\0" */
+       lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
+       return SINGLE_APPLET_MAIN(argc, argv);
+#else
+       lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
 
 #if !BB_MMU
        /* NOMMU re-exec trick sets high-order bit in first byte of name */
@@ -683,5 +827,10 @@ int main(int argc, char **argv)
        parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
 
        run_applet_and_exit(applet_name, argv);
-       bb_error_msg_and_die("applet not found");
+
+       /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+       full_write2_str(applet_name);
+       full_write2_str(": applet not found\n");
+       xfunc_die();
+#endif
 }