cfa60a940d3c08332b0d8842e74f96200d44dce9
[platform/upstream/busybox.git] / libbb / appletlib.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Support for main() which needs to end up in libbusybox, not busybox,
4  * if one builds libbusybox.
5  *
6  * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
7  *
8  * Licensed under GPLv2, see file License in this tarball for details.
9  */
10
11 #include <assert.h>
12 #include "busybox.h"
13
14
15 /* Declare <applet>_main() */
16 #define PROTOTYPES
17 #include "applets.h"
18 #undef PROTOTYPES
19
20 #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
21 /* Define usage_messages[] */
22 static const char usage_messages[] ALIGN1 = ""
23 #define MAKE_USAGE
24 #include "usage.h"
25 #include "applets.h"
26 ;
27 #undef MAKE_USAGE
28 #else
29 #define usage_messages 0
30 #endif /* SHOW_USAGE */
31
32 /* Define struct bb_applet applets[] */
33 #include "applets.h"
34
35 #if ENABLE_FEATURE_SH_STANDALONE
36 /* -1 because last entry is NULL */
37 const unsigned short NUM_APPLETS = ARRAY_SIZE(applets) - 1;
38 #endif
39
40
41 #if ENABLE_FEATURE_COMPRESS_USAGE
42
43 #include "usage_compressed.h"
44 #include "unarchive.h"
45
46 static const char *unpack_usage_messages(void)
47 {
48         char *outbuf = NULL;
49         bunzip_data *bd;
50         int i;
51
52         i = start_bunzip(&bd,
53                         /* src_fd: */ -1,
54                         /* inbuf:  */ packed_usage,
55                         /* len:    */ sizeof(packed_usage));
56         /* read_bunzip can longjmp to start_bunzip, and ultimately
57          * end up here with i != 0 on read data errors! Not trivial */
58         if (!i) {
59                 /* Cannot use xmalloc: will leak bd in NOFORK case! */
60                 outbuf = malloc_or_warn(SIZEOF_usage_messages);
61                 if (outbuf)
62                         read_bunzip(bd, outbuf, SIZEOF_usage_messages);
63         }
64         dealloc_bunzip(bd);
65         return outbuf;
66 }
67 #define dealloc_usage_messages(s) free(s)
68
69 #else
70
71 #define unpack_usage_messages() usage_messages
72 #define dealloc_usage_messages(s) ((void)(s))
73
74 #endif /* FEATURE_COMPRESS_USAGE */
75
76
77 void bb_show_usage(void)
78 {
79         if (ENABLE_SHOW_USAGE) {
80                 const char *format_string;
81                 const char *p;
82                 const char *usage_string = p = unpack_usage_messages();
83                 const struct bb_applet *ap = find_applet_by_name(applet_name);
84                 int i;
85
86                 if (!ap) /* never happens, paranoia */
87                         xfunc_die();
88
89                 i = ap - applets;
90                 while (i) {
91                         while (*p++) continue;
92                         i--;
93                 }
94
95                 fprintf(stderr, "%s multi-call binary\n", bb_banner);
96                 format_string = "\nUsage: %s %s\n\n";
97                 if (*p == '\b')
98                         format_string = "\nNo help available.\n\n";
99                 fprintf(stderr, format_string, applet_name, p);
100                 dealloc_usage_messages((char*)usage_string);
101         }
102         xfunc_die();
103 }
104
105
106 static int applet_name_compare(const void *name, const void *vapplet)
107 {
108         const struct bb_applet *applet = vapplet;
109
110         return strcmp(name, applet->name);
111 }
112
113 const struct bb_applet *find_applet_by_name(const char *name)
114 {
115         /* Do a binary search to find the applet entry given the name. */
116         return bsearch(name, applets, ARRAY_SIZE(applets)-1, sizeof(applets[0]),
117                                 applet_name_compare);
118 }
119
120
121 #ifdef __GLIBC__
122 /* Make it reside in R/W memory: */
123 int *const bb_errno __attribute__ ((section (".data")));
124 #endif
125
126 void bbox_prepare_main(char **argv)
127 {
128 #ifdef __GLIBC__
129         (*(int **)&bb_errno) = __errno_location();
130 #endif
131
132         /* Set locale for everybody except 'init' */
133         if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
134                 setlocale(LC_ALL, "");
135
136 #if ENABLE_FEATURE_INDIVIDUAL
137         /* Redundant for busybox (run_applet_and_exit covers that case)
138          * but needed for "individual applet" mode */
139         if (argv[1] && strcmp(argv[1], "--help") == 0)
140                 bb_show_usage();
141 #endif
142 }