blob: 7245ecedcbfe94ea0c626fa96a8a0abdfb6b13b9 [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
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +000015#include <assert.h>
Denis Vlasenkoc7ba8b92007-02-03 17:27:14 +000016#include "busybox.h"
17
18#define PROTOTYPES
19#include "applets.h"
20#undef PROTOTYPES
21
Eric Andersenaad1a882001-03-16 22:47:14 +000022
Denis Vlasenko07159f02006-11-09 00:00:12 +000023/* Apparently uclibc defines __GLIBC__ (compat trick?). Oh well. */
24#if ENABLE_STATIC && defined(__GLIBC__) && !defined(__UCLIBC__)
Denis Vlasenkodf518922006-10-20 13:42:57 +000025#warning Static linking against glibc produces buggy executables
Denis Vlasenko067e3f02006-11-10 23:25:53 +000026#warning (glibc does not cope well with ld --gc-sections).
Denis Vlasenkoafea46b2006-10-29 19:37:13 +000027#warning See sources.redhat.com/bugzilla/show_bug.cgi?id=3400
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +000028#warning Note that glibc is unsuitable for static linking anyway.
29#warning If you still want to do it, remove -Wl,--gc-sections
30#warning from top-level Makefile and remove this warning.
Denis Vlasenkodf518922006-10-20 13:42:57 +000031#endif
32
Rob Landley7e21d5f2006-04-27 23:34:46 +000033#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
34static const char usage_messages[] =
Eric Andersen674b08a2004-04-06 14:28:35 +000035#define MAKE_USAGE
36#include "usage.h"
Eric Andersen674b08a2004-04-06 14:28:35 +000037#include "applets.h"
Eric Andersen674b08a2004-04-06 14:28:35 +000038;
Eric Andersen674b08a2004-04-06 14:28:35 +000039#undef MAKE_USAGE
Rob Landley73f54702006-05-01 00:53:40 +000040#else
41#define usage_messages 0
Bernhard Reutner-Fischer81901a02006-03-31 18:43:55 +000042#endif /* ENABLE_SHOW_USAGE */
Rob Landley7e21d5f2006-04-27 23:34:46 +000043
Eric Andersen2ccfef22001-03-19 19:30:24 +000044#undef APPLET
45#undef APPLET_NOUSAGE
46#undef PROTOTYPES
47#include "applets.h"
48
Glenn L McGrath7fc504c2004-02-22 11:13:28 +000049static struct BB_applet *applet_using;
Eric Andersenaad1a882001-03-16 22:47:14 +000050
Eric Andersen2ccfef22001-03-19 19:30:24 +000051/* The -1 arises because of the {0,NULL,0,-1} entry above. */
Denis Vlasenko0ee39992006-12-24 15:23:28 +000052const unsigned short NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
Eric Andersen2ccfef22001-03-19 19:30:24 +000053
Robert Grieblc9aca452002-06-04 20:06:25 +000054
Robert Grieblc9aca452002-06-04 20:06:25 +000055#ifdef CONFIG_FEATURE_SUID_CONFIG
56
Robert Grieblc9aca452002-06-04 20:06:25 +000057#include <ctype.h>
Robert Grieblc9aca452002-06-04 20:06:25 +000058
Robert Grieblc9aca452002-06-04 20:06:25 +000059#define CONFIG_FILE "/etc/busybox.conf"
60
Glenn L McGrathb37367a2002-08-22 13:12:40 +000061/* applets [] is const, so we have to define this "override" structure */
Bernhard Reutner-Fischer6973abc2005-10-28 09:45:07 +000062static struct BB_suid_config
Glenn L McGrath2faee7b2003-05-26 14:09:12 +000063{
Denis Vlasenko01a74f92006-09-23 16:34:39 +000064 struct BB_applet *m_applet;
Robert Grieblc9aca452002-06-04 20:06:25 +000065
Denis Vlasenko01a74f92006-09-23 16:34:39 +000066 uid_t m_uid;
67 gid_t m_gid;
68 mode_t m_mode;
Glenn L McGrathb37367a2002-08-22 13:12:40 +000069
Denis Vlasenko01a74f92006-09-23 16:34:39 +000070 struct BB_suid_config *m_next;
Bernhard Reutner-Fischer6973abc2005-10-28 09:45:07 +000071} *suid_config;
Robert Grieblc9aca452002-06-04 20:06:25 +000072
Manuel Novoa III 7b565a02004-02-17 10:16:21 +000073static int suid_cfg_readable;
Robert Grieblc9aca452002-06-04 20:06:25 +000074
Glenn L McGrathb37367a2002-08-22 13:12:40 +000075/* check if u is member of group g */
Denis Vlasenko01a74f92006-09-23 16:34:39 +000076static int ingroup(uid_t u, gid_t g)
Robert Grieblc9aca452002-06-04 20:06:25 +000077{
Denis Vlasenko01a74f92006-09-23 16:34:39 +000078 struct group *grp = getgrgid(g);
Glenn L McGrathb37367a2002-08-22 13:12:40 +000079
Denis Vlasenko01a74f92006-09-23 16:34:39 +000080 if (grp) {
81 char **mem;
Glenn L McGrathb37367a2002-08-22 13:12:40 +000082
Denis Vlasenko01a74f92006-09-23 16:34:39 +000083 for (mem = grp->gr_mem; *mem; mem++) {
84 struct passwd *pwd = getpwnam(*mem);
Glenn L McGrathb37367a2002-08-22 13:12:40 +000085
Denis Vlasenko01a74f92006-09-23 16:34:39 +000086 if (pwd && (pwd->pw_uid == u))
87 return 1;
88 }
Robert Grieblc9aca452002-06-04 20:06:25 +000089 }
Denis Vlasenko01a74f92006-09-23 16:34:39 +000090 return 0;
Robert Grieblc9aca452002-06-04 20:06:25 +000091}
92
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +000093/* This should probably be a libbb routine. In that case,
94 * I'd probably rename it to something like bb_trimmed_slice.
95 */
96static char *get_trimmed_slice(char *s, char *e)
97{
98 /* First, consider the value at e to be nul and back up until we
99 * reach a non-space char. Set the char after that (possibly at
100 * the original e) to nul. */
101 while (e-- > s) {
102 if (!isspace(*e)) {
103 break;
104 }
105 }
106 e[1] = 0;
107
108 /* Next, advance past all leading space and return a ptr to the
109 * first non-space char; possibly the terminating nul. */
Rob Landleyea224be2006-06-18 20:20:07 +0000110 return skip_whitespace(s);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000111}
112
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000113
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000114#define parse_error(x) do { errmsg = x; goto pe_label; } while(0)
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000115
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000116/* Don't depend on the tools to combine strings. */
117static const char config_file[] = CONFIG_FILE;
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000118
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000119/* There are 4 chars + 1 nul for each of user/group/other. */
120static const char mode_chars[] = "Ssx-\0Ssx-\0Ttx-";
121
122/* We don't supply a value for the nul, so an index adjustment is
123 * necessary below. Also, we use unsigned short here to save some
124 * space even though these are really mode_t values. */
125static const unsigned short mode_mask[] = {
126 /* SST sst xxx --- */
127 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */
128 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */
129 0, S_IXOTH, S_IXOTH, 0 /* other */
130};
131
132static void parse_config_file(void)
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000133{
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000134 struct BB_suid_config *sct_head;
135 struct BB_suid_config *sct;
136 struct BB_applet *applet;
137 FILE *f;
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000138 const char *errmsg;
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000139 char *s;
140 char *e;
141 int i, lc, section;
142 char buffer[256];
143 struct stat st;
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000144
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000145 assert(!suid_config); /* Should be set to NULL by bss init. */
Glenn L McGrath2faee7b2003-05-26 14:09:12 +0000146
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000147 if ((stat(config_file, &st) != 0) /* No config file? */
148 || !S_ISREG(st.st_mode) /* Not a regular file? */
149 || (st.st_uid != 0) /* Not owned by root? */
150 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000151 || !(f = fopen(config_file, "r")) /* Cannot open? */
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000152 ) {
153 return;
Robert Grieblc9aca452002-06-04 20:06:25 +0000154 }
Glenn L McGrathb37367a2002-08-22 13:12:40 +0000155
Manuel Novoa III 7b565a02004-02-17 10:16:21 +0000156 suid_cfg_readable = 1;
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000157 sct_head = NULL;
158 section = lc = 0;
Robert Grieblc9aca452002-06-04 20:06:25 +0000159
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000160 do {
161 s = buffer;
162
163 if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
164 if (ferror(f)) { /* Make sure it wasn't a read error. */
165 parse_error("reading");
166 }
167 fclose(f);
168 suid_config = sct_head; /* Success, so set the pointer. */
169 return;
170 }
171
172 lc++; /* Got a (partial) line. */
173
174 /* If a line is too long for our buffer, we consider it an error.
175 * The following test does mistreat one corner case though.
176 * If the final line of the file does not end with a newline and
177 * yet exactly fills the buffer, it will be treated as too long
178 * even though there isn't really a problem. But it isn't really
179 * worth adding code to deal with such an unlikely situation, and
180 * we do err on the side of caution. Besides, the line would be
181 * too long if it did end with a newline. */
182 if (!strchr(s, '\n') && !feof(f)) {
183 parse_error("line too long");
184 }
185
186 /* Trim leading and trailing whitespace, ignoring comments, and
187 * check if the resulting string is empty. */
188 if (!*(s = get_trimmed_slice(s, strchrnul(s, '#')))) {
189 continue;
190 }
191
192 /* Check for a section header. */
193
194 if (*s == '[') {
195 /* Unlike the old code, we ignore leading and trailing
196 * whitespace for the section name. We also require that
197 * there are no stray characters after the closing bracket. */
198 if (!(e = strchr(s, ']')) /* Missing right bracket? */
199 || e[1] /* Trailing characters? */
200 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
201 ) {
202 parse_error("section header");
203 }
204 /* Right now we only have one section so just check it.
205 * If more sections are added in the future, please don't
206 * resort to cascading ifs with multiple strcasecmp calls.
207 * That kind of bloated code is all too common. A loop
208 * and a string table would be a better choice unless the
209 * number of sections is very small. */
210 if (strcasecmp(s, "SUID") == 0) {
211 section = 1;
212 continue;
213 }
214 section = -1; /* Unknown section so set to skip. */
215 continue;
216 }
217
218 /* Process sections. */
219
220 if (section == 1) { /* SUID */
221 /* Since we trimmed leading and trailing space above, we're
222 * now looking for strings of the form
223 * <key>[::space::]*=[::space::]*<value>
224 * where both key and value could contain inner whitespace. */
225
226 /* First get the key (an applet name in our case). */
227 if (!!(e = strchr(s, '='))) {
228 s = get_trimmed_slice(s, e);
229 }
230 if (!e || !*s) { /* Missing '=' or empty key. */
231 parse_error("keyword");
232 }
233
234 /* Ok, we have an applet name. Process the rhs if this
235 * applet is currently built in and ignore it otherwise.
236 * Note: This can hide config file bugs which only pop
237 * up when the busybox configuration is changed. */
238 if ((applet = find_applet_by_name(s))) {
239 /* Note: We currently don't check for duplicates!
240 * The last config line for each applet will be the
241 * one used since we insert at the head of the list.
242 * I suppose this could be considered a feature. */
243 sct = xmalloc(sizeof(struct BB_suid_config));
244 sct->m_applet = applet;
245 sct->m_mode = 0;
246 sct->m_next = sct_head;
247 sct_head = sct;
248
249 /* Get the specified mode. */
250
Rob Landleyea224be2006-06-18 20:20:07 +0000251 e = skip_whitespace(e+1);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000252
253 for (i=0 ; i < 3 ; i++) {
254 const char *q;
255 if (!*(q = strchrnul(mode_chars + 5*i, *e++))) {
256 parse_error("mode");
257 }
258 /* Adjust by -i to account for nul. */
259 sct->m_mode |= mode_mask[(q - mode_chars) - i];
260 }
261
262 /* Now get the the user/group info. */
Bernhard Reutner-Fischer7ca61b62006-01-15 14:04:57 +0000263
Rob Landleyea224be2006-06-18 20:20:07 +0000264 s = skip_whitespace(e);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000265
266 /* Note: We require whitespace between the mode and the
267 * user/group info. */
268 if ((s == e) || !(e = strchr(s, '.'))) {
269 parse_error("<uid>.<gid>");
270 }
271 *e++ = 0;
272
273 /* We can't use get_ug_id here since it would exit()
274 * if a uid or gid was not found. Oh well... */
275 {
276 char *e2;
277
278 sct->m_uid = strtoul(s, &e2, 10);
279 if (*e2 || (s == e2)) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000280 struct passwd *pwd = getpwnam(s);
281 if (!pwd) {
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000282 parse_error("user");
283 }
284 sct->m_uid = pwd->pw_uid;
285 }
286
287 sct->m_gid = strtoul(e, &e2, 10);
288 if (*e2 || (e == e2)) {
289 struct group *grp;
290 if (!(grp = getgrnam(e))) {
291 parse_error("group");
292 }
293 sct->m_gid = grp->gr_gid;
294 }
295 }
296 }
297 continue;
298 }
299
300 /* Unknown sections are ignored. */
301
302 /* Encountering configuration lines prior to seeing a
303 * section header is treated as an error. This is how
Eric Andersenaff114c2004-04-14 17:51:38 +0000304 * the old code worked, but it may not be desirable.
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000305 * We may want to simply ignore such lines in case they
306 * are used in some future version of busybox. */
307 if (!section) {
308 parse_error("keyword outside section");
309 }
310
311 } while (1);
312
313 pe_label:
314 fprintf(stderr, "Parse error in %s, line %d: %s\n",
Denis Vlasenkoa41fdf32007-01-29 22:51:00 +0000315 config_file, lc, errmsg);
Manuel Novoa III 31b98dd2004-02-01 10:03:05 +0000316
317 fclose(f);
318 /* Release any allocated memory before returning. */
319 while (sct_head) {
320 sct = sct_head->m_next;
321 free(sct_head);
322 sct_head = sct;
323 }
Robert Grieblc9aca452002-06-04 20:06:25 +0000324}
325
Rob Landley8a7a6782005-09-05 04:13:33 +0000326#else
Denis Vlasenko218f2f42007-01-24 22:02:01 +0000327#define parse_config_file() ((void)0)
Rob Landley8a7a6782005-09-05 04:13:33 +0000328#endif /* CONFIG_FEATURE_SUID_CONFIG */
329
330#ifdef CONFIG_FEATURE_SUID
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000331static void check_suid(struct BB_applet *applet)
Rob Landley8a7a6782005-09-05 04:13:33 +0000332{
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000333 uid_t ruid = getuid(); /* real [ug]id */
334 uid_t rgid = getgid();
Rob Landley8a7a6782005-09-05 04:13:33 +0000335
336#ifdef CONFIG_FEATURE_SUID_CONFIG
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000337 if (suid_cfg_readable) {
338 struct BB_suid_config *sct;
Rob Landley8a7a6782005-09-05 04:13:33 +0000339
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000340 for (sct = suid_config; sct; sct = sct->m_next) {
341 if (sct->m_applet == applet)
342 break;
343 }
344 if (sct) {
345 mode_t m = sct->m_mode;
Rob Landley8a7a6782005-09-05 04:13:33 +0000346
Denis Vlasenko218f2f42007-01-24 22:02:01 +0000347 if (sct->m_uid == ruid)
348 /* same uid */
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000349 m >>= 6;
Denis Vlasenko218f2f42007-01-24 22:02:01 +0000350 else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid))
351 /* same group / in group */
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000352 m >>= 3;
Rob Landley8a7a6782005-09-05 04:13:33 +0000353
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000354 if (!(m & S_IXOTH)) /* is x bit not set ? */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000355 bb_error_msg_and_die("you have no permission to run this applet!");
Rob Landley8a7a6782005-09-05 04:13:33 +0000356
Denis Vlasenko218f2f42007-01-24 22:02:01 +0000357 if (sct->m_gid != 0) {
358 /* _both_ have to be set for sgid */
359 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
360 xsetgid(sct->m_gid);
361 } else xsetgid(rgid); /* no sgid -> drop */
362 }
363 if (sct->m_uid != 0) {
364 if (sct->m_mode & S_ISUID) xsetuid(sct->m_uid);
365 else xsetuid(ruid); /* no suid -> drop */
366 }
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000367 } else {
368 /* default: drop all privileges */
369 xsetgid(rgid);
370 xsetuid(ruid);
371 }
372 return;
Rob Landley8a7a6782005-09-05 04:13:33 +0000373 } else {
Rob Landley8a7a6782005-09-05 04:13:33 +0000374#ifndef CONFIG_FEATURE_SUID_CONFIG_QUIET
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000375 static int onetime = 0;
Rob Landley8a7a6782005-09-05 04:13:33 +0000376
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000377 if (!onetime) {
378 onetime = 1;
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000379 fprintf(stderr, "Using fallback suid method\n");
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000380 }
381#endif
Rob Landley8a7a6782005-09-05 04:13:33 +0000382 }
383#endif
Robert Grieblc9aca452002-06-04 20:06:25 +0000384
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000385 if (applet->need_suid == _BB_SUID_ALWAYS) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000386 if (geteuid()) bb_error_msg_and_die("applet requires root privileges!");
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000387 } else if (applet->need_suid == _BB_SUID_NEVER) {
388 xsetgid(rgid); /* drop all privileges */
389 xsetuid(ruid);
390 }
Rob Landley8a7a6782005-09-05 04:13:33 +0000391}
392#else
393#define check_suid(x)
394#endif /* CONFIG_FEATURE_SUID */
395
396
397
Rob Landleye1a0f532006-07-26 15:38:46 +0000398#ifdef CONFIG_FEATURE_COMPRESS_USAGE
Rob Landley8a7a6782005-09-05 04:13:33 +0000399
Rob Landley7e21d5f2006-04-27 23:34:46 +0000400#include "usage_compressed.h"
401#include "unarchive.h"
402
403static const char *unpack_usage_messages(void)
404{
405 int input[2], output[2], pid;
406 char *buf;
407
408 if(pipe(input) < 0 || pipe(output) < 0)
409 exit(1);
410
411 pid = fork();
412 switch (pid) {
413 case -1: /* error */
414 exit(1);
415 case 0: /* child */
416 close(input[1]);
417 close(output[0]);
418 uncompressStream(input[0], output[1]);
419 exit(0);
420 }
421 /* parent */
422
423 close(input[0]);
424 close(output[1]);
425 pid = fork();
426 switch (pid) {
427 case -1: /* error */
428 exit(1);
429 case 0: /* child */
Rob Landley53437472006-07-16 08:14:35 +0000430 full_write(input[1], packed_usage, sizeof(packed_usage));
Rob Landley7e21d5f2006-04-27 23:34:46 +0000431 exit(0);
432 }
433 /* parent */
434 close(input[1]);
435
436 buf = xmalloc(SIZEOF_usage_messages);
Rob Landley53437472006-07-16 08:14:35 +0000437 full_read(output[0], buf, SIZEOF_usage_messages);
Rob Landley7e21d5f2006-04-27 23:34:46 +0000438 return buf;
439}
440
441#else
Rob Landley1801e9c2006-05-03 20:19:14 +0000442#define unpack_usage_messages() usage_messages
Rob Landley7e21d5f2006-04-27 23:34:46 +0000443#endif /* ENABLE_FEATURE_COMPRESS_USAGE */
Rob Landley8a7a6782005-09-05 04:13:33 +0000444
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000445void bb_show_usage(void)
Rob Landley8a7a6782005-09-05 04:13:33 +0000446{
Rob Landley7e21d5f2006-04-27 23:34:46 +0000447 if (ENABLE_SHOW_USAGE) {
448 const char *format_string;
449 const char *usage_string = unpack_usage_messages();
450 int i;
Rob Landley8a7a6782005-09-05 04:13:33 +0000451
Rob Landley7e21d5f2006-04-27 23:34:46 +0000452 for (i = applet_using - applets; i > 0;)
453 if (!*usage_string++) --i;
454
455 format_string = "%s\n\nUsage: %s %s\n\n";
456 if (*usage_string == '\b')
457 format_string = "%s\n\nNo help available.\n\n";
Denis Vlasenko92258542006-11-01 10:25:35 +0000458 fprintf(stderr, format_string, bb_msg_full_version,
Rob Landley7e21d5f2006-04-27 23:34:46 +0000459 applet_using->name, usage_string);
Rob Landley8a7a6782005-09-05 04:13:33 +0000460 }
Rob Landley8a7a6782005-09-05 04:13:33 +0000461
Denis Vlasenko40920822006-10-03 20:28:06 +0000462 exit(xfunc_error_retval);
Rob Landley8a7a6782005-09-05 04:13:33 +0000463}
464
Rob Landley53437472006-07-16 08:14:35 +0000465static int applet_name_compare(const void *name, const void *vapplet)
Rob Landley8a7a6782005-09-05 04:13:33 +0000466{
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000467 const struct BB_applet *applet = vapplet;
Rob Landley8a7a6782005-09-05 04:13:33 +0000468
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000469 return strcmp(name, applet->name);
Rob Landley8a7a6782005-09-05 04:13:33 +0000470}
471
Rob Landley53437472006-07-16 08:14:35 +0000472struct BB_applet *find_applet_by_name(const char *name)
Rob Landley8a7a6782005-09-05 04:13:33 +0000473{
Denis Vlasenko01a74f92006-09-23 16:34:39 +0000474 return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet),
475 applet_name_compare);
Rob Landley8a7a6782005-09-05 04:13:33 +0000476}
477
Rob Landley53437472006-07-16 08:14:35 +0000478void run_applet_by_name(const char *name, int argc, char **argv)
Rob Landley8a7a6782005-09-05 04:13:33 +0000479{
Denis Vlasenko0ee39992006-12-24 15:23:28 +0000480 if (ENABLE_FEATURE_SUID_CONFIG)
481 parse_config_file();
Rob Landley8a7a6782005-09-05 04:13:33 +0000482
Denis Vlasenko0ee39992006-12-24 15:23:28 +0000483 if (!strncmp(name, "busybox", 7))
484 exit(busybox_main(argc, argv));
Rob Landley8a7a6782005-09-05 04:13:33 +0000485 /* Do a binary search to find the applet entry given the name. */
486 applet_using = find_applet_by_name(name);
Rob Landley53437472006-07-16 08:14:35 +0000487 if (applet_using) {
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000488 applet_name = applet_using->name;
Denis Vlasenko0ee39992006-12-24 15:23:28 +0000489 if (argc == 2 && !strcmp(argv[1], "--help"))
490 bb_show_usage();
491 if (ENABLE_FEATURE_SUID)
492 check_suid(applet_using);
493 exit(applet_using->main(argc, argv));
Rob Landley8a7a6782005-09-05 04:13:33 +0000494 }
495}