summaryrefslogtreecommitdiff
path: root/libbb/appletlib.c
blob: cfa60a940d3c08332b0d8842e74f96200d44dce9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* vi: set sw=4 ts=4: */
/*
 * Support for main() which needs to end up in libbusybox, not busybox,
 * if one builds libbusybox.
 *
 * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
 *
 * Licensed under GPLv2, see file License in this tarball for details.
 */

#include <assert.h>
#include "busybox.h"


/* Declare <applet>_main() */
#define PROTOTYPES
#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;
#endif


#if ENABLE_FEATURE_COMPRESS_USAGE

#include "usage_compressed.h"
#include "unarchive.h"

static const char *unpack_usage_messages(void)
{
	char *outbuf = NULL;
	bunzip_data *bd;
	int i;

	i = start_bunzip(&bd,
			/* src_fd: */ -1,
			/* inbuf:  */ 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);
		if (outbuf)
			read_bunzip(bd, outbuf, SIZEOF_usage_messages);
	}
	dealloc_bunzip(bd);
	return outbuf;
}
#define dealloc_usage_messages(s) free(s)

#else

#define unpack_usage_messages() usage_messages
#define dealloc_usage_messages(s) ((void)(s))

#endif /* FEATURE_COMPRESS_USAGE */


void bb_show_usage(void)
{
	if (ENABLE_SHOW_USAGE) {
		const char *format_string;
		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();

		i = ap - applets;
		while (i) {
			while (*p++) continue;
			i--;
		}

		fprintf(stderr, "%s multi-call binary\n", bb_banner);
		format_string = "\nUsage: %s %s\n\n";
		if (*p == '\b')
			format_string = "\nNo help available.\n\n";
		fprintf(stderr, format_string, applet_name, p);
		dealloc_usage_messages((char*)usage_string);
	}
	xfunc_die();
}


static int applet_name_compare(const void *name, const void *vapplet)
{
	const struct bb_applet *applet = vapplet;

	return strcmp(name, applet->name);
}

const struct bb_applet *find_applet_by_name(const char *name)
{
	/* 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);
}


#ifdef __GLIBC__
/* Make it reside in R/W memory: */
int *const bb_errno __attribute__ ((section (".data")));
#endif

void bbox_prepare_main(char **argv)
{
#ifdef __GLIBC__
	(*(int **)&bb_errno) = __errno_location();
#endif

	/* Set locale for everybody except 'init' */
	if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
		setlocale(LC_ALL, "");

#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();
#endif
}