source: MondoRescue/branches/stable/mindi-busybox/applets/applets.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 17.5 KB
Line 
1/* 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 *
9 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
10 * Permission has been granted to redistribute this code under the GPL.
11 *
12 * Licensed under GPLv2 or later, see file License in this tarball for details.
13 */
14
15#include <assert.h>
16#include "busybox.h"
17
18/* Apparently uclibc defines __GLIBC__ (compat trick?). Oh well. */
19#if ENABLE_STATIC && defined(__GLIBC__) && !defined(__UCLIBC__)
20#warning Static linking against glibc produces buggy executables
21#warning (glibc does not cope well with ld --gc-sections).
22#warning See sources.redhat.com/bugzilla/show_bug.cgi?id=3400
23#warning Note that glibc is unsuitable for static linking anyway.
24#warning If you still want to do it, remove -Wl,--gc-sections
25#warning from top-level Makefile and remove this warning.
26#error Aborting compilation.
27#endif
28
29
30/* Declare <applet>_main() */
31#define PROTOTYPES
32#include "applets.h"
33#undef PROTOTYPES
34
35#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
36/* Define usage_messages[] */
37static const char usage_messages[] ALIGN1 = ""
38#define MAKE_USAGE
39#include "usage.h"
40#include "applets.h"
41;
42#undef MAKE_USAGE
43#else
44#define usage_messages 0
45#endif /* SHOW_USAGE */
46
47/* Define struct bb_applet applets[] */
48#include "applets.h"
49/* The -1 arises because of the {0,NULL,0,-1} entry. */
50
51#if ENABLE_FEATURE_SH_STANDALONE
52const unsigned short NUM_APPLETS = ARRAY_SIZE(applets);
53#endif
54const struct bb_applet *current_applet;
55const char *applet_name ATTRIBUTE_EXTERNALLY_VISIBLE;
56#if !BB_MMU
57bool re_execed;
58#endif
59
60USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
61
62#if ENABLE_FEATURE_SUID_CONFIG
63
64/* applets[] is const, so we have to define this "override" structure */
65static struct BB_suid_config {
66 const struct bb_applet *m_applet;
67 uid_t m_uid;
68 gid_t m_gid;
69 mode_t m_mode;
70 struct BB_suid_config *m_next;
71} *suid_config;
72
73static bool suid_cfg_readable;
74
75/* check if u is member of group g */
76static int ingroup(uid_t u, gid_t g)
77{
78 struct group *grp = getgrgid(g);
79
80 if (grp) {
81 char **mem;
82
83 for (mem = grp->gr_mem; *mem; mem++) {
84 struct passwd *pwd = getpwnam(*mem);
85
86 if (pwd && (pwd->pw_uid == u))
87 return 1;
88 }
89 }
90 return 0;
91}
92
93/* 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. */
110 return skip_whitespace(s);
111}
112
113/* Don't depend on the tools to combine strings. */
114static const char config_file[] ALIGN1 = "/etc/busybox.conf";
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[] ALIGN2 = {
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
126#define parse_error(x) do { errmsg = x; goto pe_label; } while (0)
127
128static void parse_config_file(void)
129{
130 struct BB_suid_config *sct_head;
131 struct BB_suid_config *sct;
132 const struct bb_applet *applet;
133 FILE *f;
134 const char *errmsg;
135 char *s;
136 char *e;
137 int i;
138 unsigned lc;
139 smallint section;
140 char buffer[256];
141 struct stat st;
142
143 assert(!suid_config); /* Should be set to NULL by bss init. */
144
145 ruid = getuid();
146 if (ruid == 0) /* run by root - don't need to even read config file */
147 return;
148
149 if ((stat(config_file, &st) != 0) /* No config file? */
150 || !S_ISREG(st.st_mode) /* Not a regular file? */
151 || (st.st_uid != 0) /* Not owned by root? */
152 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
153 || !(f = fopen(config_file, "r")) /* Cannot open? */
154 ) {
155 return;
156 }
157
158 suid_cfg_readable = 1;
159 sct_head = NULL;
160 section = lc = 0;
161
162 while (1) {
163 s = buffer;
164
165 if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
166 if (ferror(f)) { /* Make sure it wasn't a read error. */
167 parse_error("reading");
168 }
169 fclose(f);
170 suid_config = sct_head; /* Success, so set the pointer. */
171 return;
172 }
173
174 lc++; /* Got a (partial) line. */
175
176 /* If a line is too long for our buffer, we consider it an error.
177 * The following test does mistreat one corner case though.
178 * If the final line of the file does not end with a newline and
179 * yet exactly fills the buffer, it will be treated as too long
180 * even though there isn't really a problem. But it isn't really
181 * worth adding code to deal with such an unlikely situation, and
182 * we do err on the side of caution. Besides, the line would be
183 * too long if it did end with a newline. */
184 if (!strchr(s, '\n') && !feof(f)) {
185 parse_error("line too long");
186 }
187
188 /* Trim leading and trailing whitespace, ignoring comments, and
189 * check if the resulting string is empty. */
190 s = get_trimmed_slice(s, strchrnul(s, '#'));
191 if (!*s) {
192 continue;
193 }
194
195 /* Check for a section header. */
196
197 if (*s == '[') {
198 /* Unlike the old code, we ignore leading and trailing
199 * whitespace for the section name. We also require that
200 * there are no stray characters after the closing bracket. */
201 e = strchr(s, ']');
202 if (!e /* Missing right bracket? */
203 || e[1] /* Trailing characters? */
204 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
205 ) {
206 parse_error("section header");
207 }
208 /* Right now we only have one section so just check it.
209 * If more sections are added in the future, please don't
210 * resort to cascading ifs with multiple strcasecmp calls.
211 * That kind of bloated code is all too common. A loop
212 * and a string table would be a better choice unless the
213 * number of sections is very small. */
214 if (strcasecmp(s, "SUID") == 0) {
215 section = 1;
216 continue;
217 }
218 section = -1; /* Unknown section so set to skip. */
219 continue;
220 }
221
222 /* Process sections. */
223
224 if (section == 1) { /* SUID */
225 /* Since we trimmed leading and trailing space above, we're
226 * now looking for strings of the form
227 * <key>[::space::]*=[::space::]*<value>
228 * where both key and value could contain inner whitespace. */
229
230 /* First get the key (an applet name in our case). */
231 e = strchr(s, '=');
232 if (e) {
233 s = get_trimmed_slice(s, e);
234 }
235 if (!e || !*s) { /* Missing '=' or empty key. */
236 parse_error("keyword");
237 }
238
239 /* Ok, we have an applet name. Process the rhs if this
240 * applet is currently built in and ignore it otherwise.
241 * Note: this can hide config file bugs which only pop
242 * up when the busybox configuration is changed. */
243 applet = find_applet_by_name(s);
244 if (applet) {
245 /* Note: We currently don't check for duplicates!
246 * The last config line for each applet will be the
247 * one used since we insert at the head of the list.
248 * I suppose this could be considered a feature. */
249 sct = xmalloc(sizeof(struct BB_suid_config));
250 sct->m_applet = applet;
251 sct->m_mode = 0;
252 sct->m_next = sct_head;
253 sct_head = sct;
254
255 /* Get the specified mode. */
256
257 e = skip_whitespace(e+1);
258
259 for (i = 0; i < 3; i++) {
260 /* There are 4 chars + 1 nul for each of user/group/other. */
261 static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-";
262
263 const char *q;
264 q = strchrnul(mode_chars + 5*i, *e++);
265 if (!*q) {
266 parse_error("mode");
267 }
268 /* Adjust by -i to account for nul. */
269 sct->m_mode |= mode_mask[(q - mode_chars) - i];
270 }
271
272 /* Now get the the user/group info. */
273
274 s = skip_whitespace(e);
275
276 /* Note: we require whitespace between the mode and the
277 * user/group info. */
278 if ((s == e) || !(e = strchr(s, '.'))) {
279 parse_error("<uid>.<gid>");
280 }
281 *e++ = '\0';
282
283 /* We can't use get_ug_id here since it would exit()
284 * if a uid or gid was not found. Oh well... */
285 sct->m_uid = bb_strtoul(s, NULL, 10);
286 if (errno) {
287 struct passwd *pwd = getpwnam(s);
288 if (!pwd) {
289 parse_error("user");
290 }
291 sct->m_uid = pwd->pw_uid;
292 }
293
294 sct->m_gid = bb_strtoul(e, NULL, 10);
295 if (errno) {
296 struct group *grp;
297 grp = getgrnam(e);
298 if (!grp) {
299 parse_error("group");
300 }
301 sct->m_gid = grp->gr_gid;
302 }
303 }
304 continue;
305 }
306
307 /* Unknown sections are ignored. */
308
309 /* Encountering configuration lines prior to seeing a
310 * section header is treated as an error. This is how
311 * the old code worked, but it may not be desirable.
312 * We may want to simply ignore such lines in case they
313 * are used in some future version of busybox. */
314 if (!section) {
315 parse_error("keyword outside section");
316 }
317
318 } /* while (1) */
319
320 pe_label:
321 fprintf(stderr, "Parse error in %s, line %d: %s\n",
322 config_file, lc, errmsg);
323
324 fclose(f);
325 /* Release any allocated memory before returning. */
326 while (sct_head) {
327 sct = sct_head->m_next;
328 free(sct_head);
329 sct_head = sct;
330 }
331}
332#else
333static inline void parse_config_file(void)
334{
335 USE_FEATURE_SUID(ruid = getuid();)
336}
337#endif /* FEATURE_SUID_CONFIG */
338
339
340#if ENABLE_FEATURE_SUID
341static void check_suid(const struct bb_applet *applet)
342{
343 gid_t rgid; /* real gid */
344
345 if (ruid == 0) /* set by parse_config_file() */
346 return; /* run by root - no need to check more */
347 rgid = getgid();
348
349#if ENABLE_FEATURE_SUID_CONFIG
350 if (suid_cfg_readable) {
351 uid_t uid;
352 struct BB_suid_config *sct;
353 mode_t m;
354
355 for (sct = suid_config; sct; sct = sct->m_next) {
356 if (sct->m_applet == applet)
357 goto found;
358 }
359 /* default: drop all privileges */
360 xsetgid(rgid);
361 xsetuid(ruid);
362 return;
363 found:
364 m = sct->m_mode;
365 if (sct->m_uid == ruid)
366 /* same uid */
367 m >>= 6;
368 else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid))
369 /* same group / in group */
370 m >>= 3;
371
372 if (!(m & S_IXOTH)) /* is x bit not set ? */
373 bb_error_msg_and_die("you have no permission to run this applet!");
374
375 /* _both_ sgid and group_exec have to be set for setegid */
376 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
377 rgid = sct->m_gid;
378 /* else (no setegid) we will set egid = rgid */
379
380 /* We set effective AND saved ids. If saved-id is not set
381 * like we do below, seteiud(0) can still later succeed! */
382 if (setresgid(-1, rgid, rgid))
383 bb_perror_msg_and_die("setresgid");
384
385 /* do we have to set effective uid? */
386 uid = ruid;
387 if (sct->m_mode & S_ISUID)
388 uid = sct->m_uid;
389 /* else (no seteuid) we will set euid = ruid */
390
391 if (setresuid(-1, uid, uid))
392 bb_perror_msg_and_die("setresuid");
393 return;
394 }
395#if !ENABLE_FEATURE_SUID_CONFIG_QUIET
396 {
397 static bool onetime = 0;
398
399 if (!onetime) {
400 onetime = 1;
401 fprintf(stderr, "Using fallback suid method\n");
402 }
403 }
404#endif
405#endif
406
407 if (applet->need_suid == _BB_SUID_ALWAYS) {
408 /* Real uid is not 0. If euid isn't 0 too, suid bit
409 * is most probably not set on our executable */
410 if (geteuid())
411 bb_error_msg_and_die("applet requires root privileges!");
412 } else if (applet->need_suid == _BB_SUID_NEVER) {
413 xsetgid(rgid); /* drop all privileges */
414 xsetuid(ruid);
415 }
416}
417#else
418#define check_suid(x) ((void)0)
419#endif /* FEATURE_SUID */
420
421
422#if ENABLE_FEATURE_COMPRESS_USAGE
423
424#include "usage_compressed.h"
425#include "unarchive.h"
426
427static const char *unpack_usage_messages(void)
428{
429 char *outbuf = NULL;
430 bunzip_data *bd;
431 int i;
432
433 i = start_bunzip(&bd,
434 /* src_fd: */ -1,
435 /* inbuf: */ packed_usage,
436 /* len: */ sizeof(packed_usage));
437 /* read_bunzip can longjmp to start_bunzip, and ultimately
438 * end up here with i != 0 on read data errors! Not trivial */
439 if (!i) {
440 /* Cannot use xmalloc: will leak bd in NOFORK case! */
441 outbuf = malloc_or_warn(SIZEOF_usage_messages);
442 if (outbuf)
443 read_bunzip(bd, outbuf, SIZEOF_usage_messages);
444 }
445 dealloc_bunzip(bd);
446 return outbuf;
447}
448#define dealloc_usage_messages(s) free(s)
449
450#else
451
452#define unpack_usage_messages() usage_messages
453#define dealloc_usage_messages(s) ((void)(s))
454
455#endif /* FEATURE_COMPRESS_USAGE */
456
457
458void bb_show_usage(void)
459{
460 if (ENABLE_SHOW_USAGE) {
461 const char *format_string;
462 const char *p;
463 const char *usage_string = p = unpack_usage_messages();
464 int i;
465
466 i = current_applet - applets;
467 while (i) {
468 while (*p++) continue;
469 i--;
470 }
471
472 fprintf(stderr, "%s multi-call binary\n", bb_banner);
473 format_string = "\nUsage: %s %s\n\n";
474 if (*p == '\b')
475 format_string = "\nNo help available.\n\n";
476 fprintf(stderr, format_string, applet_name, p);
477 dealloc_usage_messages((char*)usage_string);
478 }
479 xfunc_die();
480}
481
482
483static int applet_name_compare(const void *name, const void *vapplet)
484{
485 const struct bb_applet *applet = vapplet;
486
487 return strcmp(name, applet->name);
488}
489
490const struct bb_applet *find_applet_by_name(const char *name)
491{
492 /* Do a binary search to find the applet entry given the name. */
493 return bsearch(name, applets, ARRAY_SIZE(applets)-1, sizeof(applets[0]),
494 applet_name_compare);
495}
496
497
498#if ENABLE_FEATURE_INSTALLER
499/* create (sym)links for each applet */
500static void install_links(const char *busybox, int use_symbolic_links)
501{
502 /* directory table
503 * this should be consistent w/ the enum,
504 * busybox.h::bb_install_loc_t, or else... */
505 static const char usr_bin [] ALIGN1 = "/usr/bin";
506 static const char usr_sbin[] ALIGN1 = "/usr/sbin";
507 static const char *const install_dir[] = {
508 &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
509 &usr_bin [4], /* "/bin" */
510 &usr_sbin[4], /* "/sbin" */
511 usr_bin,
512 usr_sbin
513 };
514
515 int (*lf)(const char *, const char *) = link;
516 char *fpc;
517 int i;
518 int rc;
519
520 if (use_symbolic_links)
521 lf = symlink;
522
523 for (i = 0; applets[i].name != NULL; i++) {
524 fpc = concat_path_file(
525 install_dir[applets[i].install_loc],
526 applets[i].name);
527 rc = lf(busybox, fpc);
528 if (rc != 0 && errno != EEXIST) {
529 bb_perror_msg("%s", fpc);
530 }
531 free(fpc);
532 }
533}
534#else
535#define install_links(x,y) ((void)0)
536#endif /* FEATURE_INSTALLER */
537
538
539/* If we were called as "busybox..." */
540static int busybox_main(char **argv)
541{
542 if (!argv[1]) {
543 /* Called without arguments */
544 const struct bb_applet *a;
545 int col, output_width;
546 help:
547 output_width = 80;
548 if (ENABLE_FEATURE_AUTOWIDTH) {
549 /* Obtain the terminal width */
550 get_terminal_width_height(0, &output_width, NULL);
551 }
552 /* leading tab and room to wrap */
553 output_width -= sizeof("start-stop-daemon, ") + 8;
554
555 printf("%s multi-call binary\n", bb_banner); /* reuse const string... */
556 printf("Copyright (C) 1998-2006  Erik Andersen, Rob Landley, and others.\n"
557 "Licensed under GPLv2.  See source distribution for full notice.\n"
558 "\n"
559 "Usage: busybox [function] [arguments]...\n"
560 " or: [function] [arguments]...\n"
561 "\n"
562 "\tBusyBox is a multi-call binary that combines many common Unix\n"
563 "\tutilities into a single executable. Most people will create a\n"
564 "\tlink to busybox for each function they wish to use and BusyBox\n"
565 "\twill act like whatever it was invoked as!\n"
566 "\nCurrently defined functions:\n");
567 col = 0;
568 a = applets;
569 while (a->name) {
570 if (col > output_width) {
571 puts(",");
572 col = 0;
573 }
574 col += printf("%s%s", (col ? ", " : "\t"), a->name);
575 a++;
576 }
577 puts("\n");
578 return 0;
579 }
580
581 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
582 const char *busybox;
583 busybox = xmalloc_readlink(bb_busybox_exec_path);
584 if (!busybox)
585 busybox = bb_busybox_exec_path;
586 /* -s makes symlinks */
587 install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0);
588 return 0;
589 }
590
591 if (strcmp(argv[1], "--help") == 0) {
592 /* "busybox --help [<applet>]" */
593 if (!argv[2])
594 goto help;
595 /* convert to "<applet> --help" */
596 argv[0] = argv[2];
597 argv[2] = NULL;
598 } else {
599 /* "busybox <applet> arg1 arg2 ..." */
600 argv++;
601 }
602 /* we want "<argv[0]>: applet not found", not "busybox: ..." */
603 applet_name = argv[0];
604 run_applet_and_exit(argv[0], argv);
605 bb_error_msg_and_die("applet not found");
606}
607
608void run_current_applet_and_exit(char **argv)
609{
610 int argc = 1;
611
612 while (argv[argc])
613 argc++;
614
615 /* Reinit some shared global data */
616 optind = 1;
617 xfunc_error_retval = EXIT_FAILURE;
618
619 applet_name = current_applet->name;
620 if (argc == 2 && !strcmp(argv[1], "--help"))
621 bb_show_usage();
622 if (ENABLE_FEATURE_SUID)
623 check_suid(current_applet);
624 exit(current_applet->main(argc, argv));
625}
626
627void run_applet_and_exit(const char *name, char **argv)
628{
629 current_applet = find_applet_by_name(name);
630 if (current_applet)
631 run_current_applet_and_exit(argv);
632 if (!strncmp(name, "busybox", 7))
633 exit(busybox_main(argv));
634}
635
636
637#ifdef __GLIBC__
638/* Make it reside in R/W memory: */
639int *const bb_errno __attribute__ ((section (".data")));
640#endif
641
642int main(int argc, char **argv)
643{
644#ifdef __GLIBC__
645 (*(int **)&bb_errno) = __errno_location();
646#endif
647
648#if !BB_MMU
649 /* NOMMU re-exec trick sets high-order bit in first byte of name */
650 if (argv[0][0] & 0x80) {
651 re_execed = 1;
652 argv[0][0] &= 0x7f;
653 }
654#endif
655 applet_name = argv[0];
656 if (applet_name[0] == '-')
657 applet_name++;
658 applet_name = bb_basename(applet_name);
659
660 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
661
662 /* Set locale for everybody except 'init' */
663 if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
664 setlocale(LC_ALL, "");
665
666 run_applet_and_exit(applet_name, argv);
667 bb_error_msg_and_die("applet not found");
668}
Note: See TracBrowser for help on using the repository browser.