blob: 151d3a190524c0954ffdbb3ebe00e4bbf01131e4 [file] [log] [blame]
Eric Andersenaad1a882001-03-16 22:47:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 *
Glenn L McGrath2faee7b2003-05-26 14:09:12 +00009 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
Eric Andersenaad1a882001-03-16 22:47:14 +000010 * Permission has been granted to redistribute this code under the GPL.
11 *
Rob Landley73f54702006-05-01 00:53:40 +000012 * Licensed under GPLv2 or later, see file License in this tarball for details.
Eric Andersenaad1a882001-03-16 22:47:14 +000013 */
14
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000015#include "busybox.h"
Robert Grieblc9aca452002-06-04 20:06:25 +000016#include <unistd.h>
Eric Andersen08ff8a42001-03-23 17:02:05 +000017#include <string.h>
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +000018#include <assert.h>
Eric Andersenaad1a882001-03-16 22:47:14 +000019
Denis Vlasenko7c4503d2006-10-23 00:42:24 +000020#if ENABLE_STATIC && defined(__GLIBC__)
Denis Vlasenkodf518922006-10-20 13:42:57 +000021#warning Static linking against glibc produces buggy executables
22#warning (glibc doesn't cope well with ld --gc-sections).
23#warning See http://sources.redhat.com/bugzilla/show_bug.cgi?id=3400
24#warning Note that glibc is utterly unsuitable for static linking anyway.
25#endif
26
Rob Landley7e21d5f2006-04-27 23:34:46 +000027#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
28static const char usage_messages[] =
Eric Andersen674b08a2004-04-06 14:28:35 +000029#define MAKE_USAGE
30#include "usage.h"
Eric Andersen674b08a2004-04-06 14:28:35 +000031#include "applets.h"
Eric Andersen674b08a2004-04-06 14:28:35 +000032;
Eric Andersen674b08a2004-04-06 14:28:35 +000033#undef MAKE_USAGE
Rob Landley73f54702006-05-01 00:53:40 +000034#else
35#define usage_messages 0
Bernhard Reutner-Fischer81901a02006-03-31 18:43:55 +000036#endif /* ENABLE_SHOW_USAGE */
Rob Landley7e21d5f2006-04-27 23:34:46 +000037
Eric Andersen2ccfef22001-03-19 19:30:24 +000038#undef APPLET
39#undef APPLET_NOUSAGE
40#undef PROTOTYPES
41#include "applets.h"
42
Glenn L McGrath7fc504c2004-02-22 11:13:28 +000043static struct BB_applet *applet_using;
Eric Andersenaad1a882001-03-16 22:47:14 +000044
Eric Andersen2ccfef22001-03-19 19:30:24 +000045/* The -1 arises because of the {0,NULL,0,-1} entry above. */
46const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
47
Robert Grieblc9aca452002-06-04 20:06:25 +000048
Robert Grieblc9aca452002-06-04 20:06:25 +000049#ifdef CONFIG_FEATURE_SUID_CONFIG
50
Robert Grieblc9aca452002-06-04 20:06:25 +000051#include <ctype.h>
Robert Grieblc9aca452002-06-04 20:06:25 +000052
Robert Grieblc9aca452002-06-04 20:06:25 +000053#define CONFIG_FILE "/etc/busybox.conf"
54
Glenn L McGrathb37367a2002-08-22 13:12:40 +000055/* applets [] is const, so we have to define this "override" structure */
Bernhard Reutner-Fischer6973abc2005-10-28 09:45:07 +000056static struct BB_suid_config
Glenn L McGrath2faee7b2003-05-26 14:09:12 +000057{
Denis Vlasenko01a74f92006-09-23 16:34:39 +000058 struct BB_applet *m_applet;
Robert Grieblc9aca452002-06-04 20:06:25 +000059
Denis Vlasenko01a74f92006-09-23 16:34:39 +000060 uid_t m_uid;
61 gid_t m_gid;
62 mode_t m_mode;
Glenn L McGrathb37367a2002-08-22 13:12:40 +000063
Denis Vlasenko01a74f92006-09-23 16:34:39 +000064 struct BB_suid_config *m_next;
Bernhard Reutner-Fischer6973abc2005-10-28 09:45:07 +000065} *suid_config;
Robert Grieblc9aca452002-06-04 20:06:25 +000066
Manuel Novoa III 7b565a02004-02-17 10:16:21 +000067static int suid_cfg_readable;
Robert Grieblc9aca452002-06-04 20:06:25 +000068
Glenn L McGrathb37367a2002-08-22 13:12:40 +000069/* check if u is member of group g */
Denis Vlasenko01a74f92006-09-23 16:34:39 +000070static int ingroup(uid_t u, gid_t g)
Robert Grieblc9aca452002-06-04 20:06:25 +000071{
Denis Vlasenko01a74f92006-09-23 16:34:39 +000072 struct group *grp = getgrgid(g);
Glenn L McGrathb37367a2002-08-22 13:12:40 +000073
Denis Vlasenko01a74f92006-09-23 16:34:39 +000074 if (grp) {
75 char **mem;
Glenn L McGrathb37367a2002-08-22 13:12:40 +000076
Denis Vlasenko01a74f92006-09-23 16:34:39 +000077 for (mem = grp->gr_mem; *mem; mem++) {
78 struct passwd *pwd = getpwnam(*mem);
Glenn L McGrathb37367a2002-08-22 13:12:40 +000079
Denis Vlasenko01a74f92006-09-23 16:34:39 +000080 if (pwd && (pwd->pw_uid == u))
81 return 1;
82 }
Robert Grieblc9aca452002-06-04 20:06:25 +000083 }
Denis Vlasenko01a74f92006-09-23 16:34:39 +000084 return 0;
Robert Grieblc9aca452002-06-04 20:06:25 +000085}
86
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +000087/* This should probably be a libbb routine. In that case,
88 * I'd probably rename it to something like bb_trimmed_slice.
89 */
90static char *get_trimmed_slice(char *s, char *e)
91{
92 /* First, consider the value at e to be nul and back up until we
93 * reach a non-space char. Set the char after that (possibly at
94 * the original e) to nul. */
95 while (e-- > s) {
96 if (!isspace(*e)) {
97 break;
98 }
99 }
100 e[1] = 0;
101
102 /* Next, advance past all leading space and return a ptr to the
103 * first non-space char; possibly the terminating nul. */
Rob Landleyea224be2006-06-18 20:20:07 +0000104 return skip_whitespace(s);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000105}
106
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000107
108#define parse_error(x) { err=x; goto pe_label; }
109
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000110/* Don't depend on the tools to combine strings. */
111static const char config_file[] = CONFIG_FILE;
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000112
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000113/* There are 4 chars + 1 nul for each of user/group/other. */
114static const char mode_chars[] = "Ssx-\0Ssx-\0Ttx-";
115
116/* We don't supply a value for the nul, so an index adjustment is
117 * necessary below. Also, we use unsigned short here to save some
118 * space even though these are really mode_t values. */
119static const unsigned short mode_mask[] = {
120 /* SST sst xxx --- */
121 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */
122 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */
123 0, S_IXOTH, S_IXOTH, 0 /* other */
124};
125
126static void parse_config_file(void)
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000127{
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000128 struct BB_suid_config *sct_head;
129 struct BB_suid_config *sct;
130 struct BB_applet *applet;
131 FILE *f;
132 char *err;
133 char *s;
134 char *e;
135 int i, lc, section;
136 char buffer[256];
137 struct stat st;
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000138
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000139 assert(!suid_config); /* Should be set to NULL by bss init. */
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000140
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000141 if ((stat(config_file, &st) != 0) /* No config file? */
142 || !S_ISREG(st.st_mode) /* Not a regular file? */
143 || (st.st_uid != 0) /* Not owned by root? */
144 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000145 || !(f = fopen(config_file, "r")) /* Cannot open? */
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000146 ) {
147 return;
Robert Grieblc9aca452002-06-04 20:06:25 +0000148 }
Glenn L McGrathb37367a2002-08-22 13:12:40 +0000149
Manuel Novoa III 7b565a02004-02-17 10:16:21 +0000150 suid_cfg_readable = 1;
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000151 sct_head = NULL;
152 section = lc = 0;
Robert Grieblc9aca452002-06-04 20:06:25 +0000153
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000154 do {
155 s = buffer;
156
157 if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
158 if (ferror(f)) { /* Make sure it wasn't a read error. */
159 parse_error("reading");
160 }
161 fclose(f);
162 suid_config = sct_head; /* Success, so set the pointer. */
163 return;
164 }
165
166 lc++; /* Got a (partial) line. */
167
168 /* If a line is too long for our buffer, we consider it an error.
169 * The following test does mistreat one corner case though.
170 * If the final line of the file does not end with a newline and
171 * yet exactly fills the buffer, it will be treated as too long
172 * even though there isn't really a problem. But it isn't really
173 * worth adding code to deal with such an unlikely situation, and
174 * we do err on the side of caution. Besides, the line would be
175 * too long if it did end with a newline. */
176 if (!strchr(s, '\n') && !feof(f)) {
177 parse_error("line too long");
178 }
179
180 /* Trim leading and trailing whitespace, ignoring comments, and
181 * check if the resulting string is empty. */
182 if (!*(s = get_trimmed_slice(s, strchrnul(s, '#')))) {
183 continue;
184 }
185
186 /* Check for a section header. */
187
188 if (*s == '[') {
189 /* Unlike the old code, we ignore leading and trailing
190 * whitespace for the section name. We also require that
191 * there are no stray characters after the closing bracket. */
192 if (!(e = strchr(s, ']')) /* Missing right bracket? */
193 || e[1] /* Trailing characters? */
194 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
195 ) {
196 parse_error("section header");
197 }
198 /* Right now we only have one section so just check it.
199 * If more sections are added in the future, please don't
200 * resort to cascading ifs with multiple strcasecmp calls.
201 * That kind of bloated code is all too common. A loop
202 * and a string table would be a better choice unless the
203 * number of sections is very small. */
204 if (strcasecmp(s, "SUID") == 0) {
205 section = 1;
206 continue;
207 }
208 section = -1; /* Unknown section so set to skip. */
209 continue;
210 }
211
212 /* Process sections. */
213
214 if (section == 1) { /* SUID */
215 /* Since we trimmed leading and trailing space above, we're
216 * now looking for strings of the form
217 * <key>[::space::]*=[::space::]*<value>
218 * where both key and value could contain inner whitespace. */
219
220 /* First get the key (an applet name in our case). */
221 if (!!(e = strchr(s, '='))) {
222 s = get_trimmed_slice(s, e);
223 }
224 if (!e || !*s) { /* Missing '=' or empty key. */
225 parse_error("keyword");
226 }
227
228 /* Ok, we have an applet name. Process the rhs if this
229 * applet is currently built in and ignore it otherwise.
230 * Note: This can hide config file bugs which only pop
231 * up when the busybox configuration is changed. */
232 if ((applet = find_applet_by_name(s))) {
233 /* Note: We currently don't check for duplicates!
234 * The last config line for each applet will be the
235 * one used since we insert at the head of the list.
236 * I suppose this could be considered a feature. */
237 sct = xmalloc(sizeof(struct BB_suid_config));
238 sct->m_applet = applet;
239 sct->m_mode = 0;
240 sct->m_next = sct_head;
241 sct_head = sct;
242
243 /* Get the specified mode. */
244
Rob Landleyea224be2006-06-18 20:20:07 +0000245 e = skip_whitespace(e+1);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000246
247 for (i=0 ; i < 3 ; i++) {
248 const char *q;
249 if (!*(q = strchrnul(mode_chars + 5*i, *e++))) {
250 parse_error("mode");
251 }
252 /* Adjust by -i to account for nul. */
253 sct->m_mode |= mode_mask[(q - mode_chars) - i];
254 }
255
256 /* Now get the the user/group info. */
Bernhard Reutner-Fischer7ca61b62006-01-15 14:04:57 +0000257
Rob Landleyea224be2006-06-18 20:20:07 +0000258 s = skip_whitespace(e);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000259
260 /* Note: We require whitespace between the mode and the
261 * user/group info. */
262 if ((s == e) || !(e = strchr(s, '.'))) {
263 parse_error("<uid>.<gid>");
264 }
265 *e++ = 0;
266
267 /* We can't use get_ug_id here since it would exit()
268 * if a uid or gid was not found. Oh well... */
269 {
270 char *e2;
271
272 sct->m_uid = strtoul(s, &e2, 10);
273 if (*e2 || (s == e2)) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000274 struct passwd *pwd = getpwnam(s);
275 if (!pwd) {
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000276 parse_error("user");
277 }
278 sct->m_uid = pwd->pw_uid;
279 }
280
281 sct->m_gid = strtoul(e, &e2, 10);
282 if (*e2 || (e == e2)) {
283 struct group *grp;
284 if (!(grp = getgrnam(e))) {
285 parse_error("group");
286 }
287 sct->m_gid = grp->gr_gid;
288 }
289 }
290 }
291 continue;
292 }
293
294 /* Unknown sections are ignored. */
295
296 /* Encountering configuration lines prior to seeing a
297 * section header is treated as an error. This is how
Eric Andersenaff114c2004-04-14 17:51:38 +0000298 * the old code worked, but it may not be desirable.
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000299 * We may want to simply ignore such lines in case they
300 * are used in some future version of busybox. */
301 if (!section) {
302 parse_error("keyword outside section");
303 }
304
305 } while (1);
306
307 pe_label:
308 fprintf(stderr, "Parse error in %s, line %d: %s\n",
309 config_file, lc, err);
310
311 fclose(f);
312 /* Release any allocated memory before returning. */
313 while (sct_head) {
314 sct = sct_head->m_next;
315 free(sct_head);
316 sct_head = sct;
317 }
318 return;
Robert Grieblc9aca452002-06-04 20:06:25 +0000319}
320
Rob Landley8a7a6782005-09-05 04:13:33 +0000321#else
Rob Landleycc59aae2005-12-07 23:17:28 +0000322#define parse_config_file()
Rob Landley8a7a6782005-09-05 04:13:33 +0000323#endif /* CONFIG_FEATURE_SUID_CONFIG */
324
325#ifdef CONFIG_FEATURE_SUID
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000326static void check_suid(struct BB_applet *applet)
Rob Landley8a7a6782005-09-05 04:13:33 +0000327{
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000328 uid_t ruid = getuid(); /* real [ug]id */
329 uid_t rgid = getgid();
Rob Landley8a7a6782005-09-05 04:13:33 +0000330
331#ifdef CONFIG_FEATURE_SUID_CONFIG
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000332 if (suid_cfg_readable) {
333 struct BB_suid_config *sct;
Rob Landley8a7a6782005-09-05 04:13:33 +0000334
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000335 for (sct = suid_config; sct; sct = sct->m_next) {
336 if (sct->m_applet == applet)
337 break;
338 }
339 if (sct) {
340 mode_t m = sct->m_mode;
Rob Landley8a7a6782005-09-05 04:13:33 +0000341
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000342 if (sct->m_uid == ruid) /* same uid */
343 m >>= 6;
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000344 else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid)) /* same group / in group */
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000345 m >>= 3;
Rob Landley8a7a6782005-09-05 04:13:33 +0000346
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000347 if (!(m & S_IXOTH)) /* is x bit not set ? */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000348 bb_error_msg_and_die("you have no permission to run this applet!");
Rob Landley8a7a6782005-09-05 04:13:33 +0000349
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000350 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { /* *both* have to be set for sgid */
351 xsetgid(sct->m_gid);
352 } else xsetgid(rgid); /* no sgid -> drop */
Rob Landley8a7a6782005-09-05 04:13:33 +0000353
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000354 if (sct->m_mode & S_ISUID) xsetuid(sct->m_uid);
355 else xsetuid(ruid); /* no suid -> drop */
356 } else {
357 /* default: drop all privileges */
358 xsetgid(rgid);
359 xsetuid(ruid);
360 }
361 return;
Rob Landley8a7a6782005-09-05 04:13:33 +0000362 } else {
Rob Landley8a7a6782005-09-05 04:13:33 +0000363#ifndef CONFIG_FEATURE_SUID_CONFIG_QUIET
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000364 static int onetime = 0;
Rob Landley8a7a6782005-09-05 04:13:33 +0000365
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000366 if (!onetime) {
367 onetime = 1;
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000368 fprintf(stderr, "Using fallback suid method\n");
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000369 }
370#endif
Rob Landley8a7a6782005-09-05 04:13:33 +0000371 }
372#endif
Robert Grieblc9aca452002-06-04 20:06:25 +0000373
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000374 if (applet->need_suid == _BB_SUID_ALWAYS) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000375 if (geteuid()) bb_error_msg_and_die("applet requires root privileges!");
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000376 } else if (applet->need_suid == _BB_SUID_NEVER) {
377 xsetgid(rgid); /* drop all privileges */
378 xsetuid(ruid);
379 }
Rob Landley8a7a6782005-09-05 04:13:33 +0000380}
381#else
382#define check_suid(x)
383#endif /* CONFIG_FEATURE_SUID */
384
385
386
Rob Landleye1a0f532006-07-26 15:38:46 +0000387#ifdef CONFIG_FEATURE_COMPRESS_USAGE
Rob Landley8a7a6782005-09-05 04:13:33 +0000388
Rob Landley7e21d5f2006-04-27 23:34:46 +0000389#include "usage_compressed.h"
390#include "unarchive.h"
391
392static const char *unpack_usage_messages(void)
393{
394 int input[2], output[2], pid;
395 char *buf;
396
397 if(pipe(input) < 0 || pipe(output) < 0)
398 exit(1);
399
400 pid = fork();
401 switch (pid) {
402 case -1: /* error */
403 exit(1);
404 case 0: /* child */
405 close(input[1]);
406 close(output[0]);
407 uncompressStream(input[0], output[1]);
408 exit(0);
409 }
410 /* parent */
411
412 close(input[0]);
413 close(output[1]);
414 pid = fork();
415 switch (pid) {
416 case -1: /* error */
417 exit(1);
418 case 0: /* child */
Rob Landley53437472006-07-16 08:14:35 +0000419 full_write(input[1], packed_usage, sizeof(packed_usage));
Rob Landley7e21d5f2006-04-27 23:34:46 +0000420 exit(0);
421 }
422 /* parent */
423 close(input[1]);
424
425 buf = xmalloc(SIZEOF_usage_messages);
Rob Landley53437472006-07-16 08:14:35 +0000426 full_read(output[0], buf, SIZEOF_usage_messages);
Rob Landley7e21d5f2006-04-27 23:34:46 +0000427 return buf;
428}
429
430#else
Rob Landley1801e9c2006-05-03 20:19:14 +0000431#define unpack_usage_messages() usage_messages
Rob Landley7e21d5f2006-04-27 23:34:46 +0000432#endif /* ENABLE_FEATURE_COMPRESS_USAGE */
Rob Landley8a7a6782005-09-05 04:13:33 +0000433
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000434void bb_show_usage(void)
Rob Landley8a7a6782005-09-05 04:13:33 +0000435{
Rob Landley7e21d5f2006-04-27 23:34:46 +0000436 if (ENABLE_SHOW_USAGE) {
437 const char *format_string;
438 const char *usage_string = unpack_usage_messages();
439 int i;
Rob Landley8a7a6782005-09-05 04:13:33 +0000440
Rob Landley7e21d5f2006-04-27 23:34:46 +0000441 for (i = applet_using - applets; i > 0;)
442 if (!*usage_string++) --i;
443
444 format_string = "%s\n\nUsage: %s %s\n\n";
445 if (*usage_string == '\b')
446 format_string = "%s\n\nNo help available.\n\n";
447 fprintf (stderr, format_string, bb_msg_full_version,
448 applet_using->name, usage_string);
Rob Landley8a7a6782005-09-05 04:13:33 +0000449 }
Rob Landley8a7a6782005-09-05 04:13:33 +0000450
Denis Vlasenko40920822006-10-03 20:28:06 +0000451 exit(xfunc_error_retval);
Rob Landley8a7a6782005-09-05 04:13:33 +0000452}
453
Rob Landley53437472006-07-16 08:14:35 +0000454static int applet_name_compare(const void *name, const void *vapplet)
Rob Landley8a7a6782005-09-05 04:13:33 +0000455{
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000456 const struct BB_applet *applet = vapplet;
Rob Landley8a7a6782005-09-05 04:13:33 +0000457
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000458 return strcmp(name, applet->name);
Rob Landley8a7a6782005-09-05 04:13:33 +0000459}
460
461extern const size_t NUM_APPLETS;
462
Rob Landley53437472006-07-16 08:14:35 +0000463struct BB_applet *find_applet_by_name(const char *name)
Rob Landley8a7a6782005-09-05 04:13:33 +0000464{
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000465 return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet),
466 applet_name_compare);
Rob Landley8a7a6782005-09-05 04:13:33 +0000467}
468
Rob Landley53437472006-07-16 08:14:35 +0000469void run_applet_by_name(const char *name, int argc, char **argv)
Rob Landley8a7a6782005-09-05 04:13:33 +0000470{
Rob Landley53437472006-07-16 08:14:35 +0000471 if (ENABLE_FEATURE_SUID_CONFIG) parse_config_file();
Rob Landley8a7a6782005-09-05 04:13:33 +0000472
Rob Landley53437472006-07-16 08:14:35 +0000473 if (!strncmp(name, "busybox", 7)) busybox_main(argc, argv);
Rob Landley8a7a6782005-09-05 04:13:33 +0000474 /* Do a binary search to find the applet entry given the name. */
475 applet_using = find_applet_by_name(name);
Rob Landley53437472006-07-16 08:14:35 +0000476 if (applet_using) {
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000477 applet_name = applet_using->name;
Rob Landley53437472006-07-16 08:14:35 +0000478 if(argc==2 && !strcmp(argv[1], "--help")) bb_show_usage();
479 if(ENABLE_FEATURE_SUID) check_suid(applet_using);
480 exit((*(applet_using->main))(argc, argv));
Rob Landley8a7a6782005-09-05 04:13:33 +0000481 }
482}