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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 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.