traceroute: fix help text to not show -6 when traceroute6 is off
[oweals/busybox.git] / libbb / appletlib.c
index 5f6923da494b02ff7568bfe441d3918f578bc4b6..b31532a931be0120b280f2a1192330161387cfd1 100644 (file)
  * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
  */
 
-#include <assert.h>
 #include "busybox.h"
+#include <assert.h>
+#include <malloc.h>
+#include <sys/user.h> /* PAGE_SIZE */
 
 
 /* Declare <applet>_main() */
@@ -55,8 +57,8 @@ static const char usage_messages[] ALIGN1 = ""
 #ifdef SINGLE_APPLET_MAIN
 #undef ENABLE_FEATURE_INDIVIDUAL
 #define ENABLE_FEATURE_INDIVIDUAL 1
-#undef USE_FEATURE_INDIVIDUAL
-#define USE_FEATURE_INDIVIDUAL(...) __VA_ARGS__
+#undef IF_FEATURE_INDIVIDUAL
+#define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
 #endif
 
 
@@ -73,7 +75,7 @@ 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 */
@@ -98,10 +100,10 @@ static const char *unpack_usage_messages(void)
 
 static void full_write2_str(const char *str)
 {
-       full_write(2, str, strlen(str));
+       xwrite_str(STDERR_FILENO, str);
 }
 
-void bb_show_usage(void)
+void FAST_FUNC bb_show_usage(void)
 {
        if (ENABLE_SHOW_USAGE) {
 #ifdef SINGLE_APPLET_STR
@@ -110,13 +112,14 @@ void bb_show_usage(void)
                const char *usage_string = p = unpack_usage_messages();
 
                if (*p == '\b') {
-                       full_write2_str("\nNo help available.\n\n");
+                       full_write2_str("No help available.\n\n");
                } else {
-                       full_write2_str("\nUsage: "SINGLE_APPLET_STR" ");
+                       full_write2_str("Usage: "SINGLE_APPLET_STR" ");
                        full_write2_str(p);
                        full_write2_str("\n\n");
                }
-               dealloc_usage_messages((char*)usage_string);
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       dealloc_usage_messages((char*)usage_string);
 #else
                const char *p;
                const char *usage_string = p = unpack_usage_messages();
@@ -129,7 +132,7 @@ void bb_show_usage(void)
                        ap--;
                }
                full_write2_str(bb_banner);
-               full_write2_str(" multi-call binary\n");
+               full_write2_str(" multi-call binary.\n");
                if (*p == '\b')
                        full_write2_str("\nNo help available.\n\n");
                else {
@@ -139,7 +142,8 @@ void bb_show_usage(void)
                        full_write2_str(p);
                        full_write2_str("\n\n");
                }
-               dealloc_usage_messages((char*)usage_string);
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       dealloc_usage_messages((char*)usage_string);
 #endif
        }
        xfunc_die();
@@ -153,7 +157,7 @@ static int applet_name_compare(const void *name, const void *v)
        return strcmp(name, APPLET_NAME(i));
 }
 #endif
-int find_applet_by_name(const char *name)
+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. */
@@ -178,10 +182,10 @@ int find_applet_by_name(const char *name)
 
 
 void lbb_prepare(const char *applet
-               USE_FEATURE_INDIVIDUAL(, char **argv))
+               IF_FEATURE_INDIVIDUAL(, char **argv))
                                MAIN_EXTERNALLY_VISIBLE;
 void lbb_prepare(const char *applet
-               USE_FEATURE_INDIVIDUAL(, char **argv))
+               IF_FEATURE_INDIVIDUAL(, char **argv))
 {
 #ifdef __GLIBC__
        (*(int **)&bb_errno) = __errno_location();
@@ -196,8 +200,12 @@ void lbb_prepare(const char *applet
 #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) {
+               /* 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
 }
 
@@ -216,9 +224,10 @@ bool re_execed;
 #endif
 
 
-#if !ENABLE_FEATURE_INDIVIDUAL
+/* If not built as a single-applet executable... */
+#if !defined(SINGLE_APPLET_MAIN)
 
-USE_FEATURE_SUID(static uid_t ruid;)  /* real uid */
+IF_FEATURE_SUID(static uid_t ruid;)  /* real uid */
 
 #if ENABLE_FEATURE_SUID_CONFIG
 
@@ -311,7 +320,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;
        }
@@ -494,7 +503,7 @@ 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 */
 
@@ -563,12 +572,12 @@ static void check_suid(int applet_no)
 #endif
  check_need_suid:
 #endif
-       if (APPLET_SUID(applet_no) == _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("must be suid to work properly");
-       } else if (APPLET_SUID(applet_no) == _BB_SUID_NEVER) {
+       } else if (APPLET_SUID(applet_no) == _BB_SUID_DROP) {
                xsetgid(rgid);  /* drop all privileges */
                xsetuid(ruid);
        }
@@ -580,7 +589,8 @@ static void check_suid(int applet_no)
 
 #if ENABLE_FEATURE_INSTALLER
 /* 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,
@@ -597,7 +607,7 @@ static void install_links(const char *busybox, int use_symbolic_links)
 
        int (*lf)(const char *, const char *);
        char *fpc;
-       int i;
+       unsigned i;
        int rc;
 
        lf = link;
@@ -606,7 +616,7 @@ static void install_links(const char *busybox, int use_symbolic_links)
 
        for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
                fpc = concat_path_file(
-                               install_dir[APPLET_INSTALL_LOC(i)],
+                               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);
@@ -618,7 +628,7 @@ static void install_links(const char *busybox, int use_symbolic_links)
        }
 }
 #else
-#define install_links(x,y) ((void)0)
+#define install_links(x,y,z) ((void)0)
 #endif /* FEATURE_INSTALLER */
 
 /* If we were called as "busybox..." */
@@ -627,19 +637,20 @@ static int busybox_main(char **argv)
        if (!argv[1]) {
                /* Called without arguments */
                const char *a;
-               int col, output_width;
+               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 -= MAX_APPLET_NAME_LEN + 8;
 
-               full_write2_str(bb_banner); /* reuse const string... */
-               full_write2_str(" multi-call binary\n"
-                      "Copyright (C) 1998-2008 Erik Andersen, Rob Landley, Denys Vlasenko\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"
@@ -649,34 +660,44 @@ static int busybox_main(char **argv)
                       "\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"
+                      "\twill act like whatever it was invoked as.\n"
                       "\n"
                       "Currently defined functions:\n");
                col = 0;
                a = applet_names;
+               /* prevent last comma to be in the very last pos */
+               output_width--;
                while (*a) {
-                       int len;
-                       if (col > output_width) {
+                       int len2 = strlen(a) + 2;
+                       if (col >= (int)output_width - len2) {
                                full_write2_str(",\n");
                                col = 0;
                        }
-                       full_write2_str(col ? ", " : "\t");
+                       if (col == 0) {
+                               col = 6;
+                               full_write2_str("\t");
+                       } else {
+                               full_write2_str(", ");
+                       }
                        full_write2_str(a);
-                       len = strlen(a);
-                       col += len + 2;
-                       a += len + 1;
+                       col += len2;
+                       a += len2 - 1;
                }
                full_write2_str("\n\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;
        }
 
@@ -702,7 +723,7 @@ static int busybox_main(char **argv)
        xfunc_die();
 }
 
-void run_applet_no_and_exit(int applet_no, char **argv)
+void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
 {
        int argc = 1;
 
@@ -713,14 +734,19 @@ void run_applet_no_and_exit(int applet_no, char **argv)
        xfunc_error_retval = EXIT_FAILURE;
 
        applet_name = APPLET_NAME(applet_no);
-       if (argc == 2 && !strcmp(argv[1], "--help"))
-               bb_show_usage();
+       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_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)
 {
        int applet = find_applet_by_name(name);
        if (applet >= 0)
@@ -729,23 +755,41 @@ void run_applet_and_exit(const char *name, char **argv)
                exit(busybox_main(argv));
 }
 
-#endif /* !ENABLE_FEATURE_INDIVIDUAL */
+#endif /* !defined(SINGLE_APPLET_MAIN) */
 
 
 
 #if ENABLE_BUILD_LIBBUSYBOX
 int lbb_main(char **argv)
 #else
-int main(int argc ATTRIBUTE_UNUSED, char **argv)
+int main(int argc UNUSED_PARAM, char **argv)
 #endif
 {
-#if ENABLE_FEATURE_INDIVIDUAL
+       /* 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 USE_FEATURE_INDIVIDUAL(, argv));
+       lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
        return SINGLE_APPLET_MAIN(argc, argv);
 #else
-       lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
+       lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
 
 #if !BB_MMU
        /* NOMMU re-exec trick sets high-order bit in first byte of name */