Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (12 years ago)
Author:
Bruno Cornec
Message:
  • 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:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/applets/applets.c

    r821 r1770  
    1313 */
    1414
     15#include <assert.h>
    1516#include "busybox.h"
    16 #include <unistd.h>
    17 #include <string.h>
    18 #include <assert.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
    1934
    2035#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
    21 static const char usage_messages[] =
     36/* Define usage_messages[] */
     37static const char usage_messages[] ALIGN1 = ""
    2238#define MAKE_USAGE
    2339#include "usage.h"
     
    2743#else
    2844#define usage_messages 0
    29 #endif /* ENABLE_SHOW_USAGE */
    30 
    31 #undef APPLET
    32 #undef APPLET_NOUSAGE
    33 #undef PROTOTYPES
     45#endif /* SHOW_USAGE */
     46
     47/* Define struct bb_applet applets[] */
    3448#include "applets.h"
    35 
    36 static struct BB_applet *applet_using;
    37 
    38 /* The -1 arises because of the {0,NULL,0,-1} entry above. */
    39 const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
    40 
    41 
    42 #ifdef CONFIG_FEATURE_SUID_CONFIG
    43 
    44 #include <ctype.h>
    45 #include "pwd_.h"
    46 #include "grp_.h"
    47 
    48 #define CONFIG_FILE "/etc/busybox.conf"
    49 
    50 /* applets [] is const, so we have to define this "override" structure */
    51 static struct BB_suid_config
    52 {
    53   struct BB_applet *m_applet;
    54 
    55   uid_t m_uid;
    56   gid_t m_gid;
    57   mode_t m_mode;
    58 
    59   struct BB_suid_config *m_next;
     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;
    6071} *suid_config;
    6172
    62 static int suid_cfg_readable;
     73static bool suid_cfg_readable;
    6374
    6475/* check if u is member of group g */
    65 static int ingroup (uid_t u, gid_t g)
    66 {
    67   struct group *grp = getgrgid (g);
    68 
    69   if (grp) {
    70     char **mem;
    71 
    72     for (mem = grp->gr_mem; *mem; mem++) {
    73       struct passwd *pwd = getpwnam (*mem);
    74 
    75       if (pwd && (pwd->pw_uid == u))
    76         return 1;
    77     }
    78   }
    79   return 0;
     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;
    8091}
    8192
     
    93104        }
    94105    }
    95     e[1] = 0;
     106    e[1] = '\0';
    96107
    97108    /* Next, advance past all leading space and return a ptr to the
     
    100111}
    101112
    102 
    103 #define parse_error(x)  { err=x; goto pe_label; }
    104 
    105113/* Don't depend on the tools to combine strings. */
    106 static const char config_file[] = CONFIG_FILE;
    107 
    108 /* There are 4 chars + 1 nul for each of user/group/other. */
    109 static const char mode_chars[] = "Ssx-\0Ssx-\0Ttx-";
     114static const char config_file[] ALIGN1 = "/etc/busybox.conf";
    110115
    111116/* We don't supply a value for the nul, so an index adjustment is
    112117 * necessary below.  Also, we use unsigned short here to save some
    113118 * space even though these are really mode_t values. */
    114 static const unsigned short mode_mask[] = {
    115     /*  SST         sst                 xxx   --- */
     119static const unsigned short mode_mask[] ALIGN2 = {
     120    /*  SST     sst                 xxx         --- */
    116121    S_ISUID,    S_ISUID|S_IXUSR,    S_IXUSR,    0,  /* user */
    117122    S_ISGID,    S_ISGID|S_IXGRP,    S_IXGRP,    0,  /* group */
     
    119124};
    120125
     126#define parse_error(x)  do { errmsg = x; goto pe_label; } while (0)
     127
    121128static void parse_config_file(void)
    122129{
    123130    struct BB_suid_config *sct_head;
    124131    struct BB_suid_config *sct;
    125     struct BB_applet *applet;
     132    const struct bb_applet *applet;
    126133    FILE *f;
    127     char *err;
     134    const char *errmsg;
    128135    char *s;
    129136    char *e;
    130     int i, lc, section;
     137    int i;
     138    unsigned lc;
     139    smallint section;
    131140    char buffer[256];
    132141    struct stat st;
    133142
    134     assert(!suid_config);       /* Should be set to NULL by bss init. */
    135 
    136     if ((stat(config_file, &st) != 0)           /* No config file? */
    137         || !S_ISREG(st.st_mode)                 /* Not a regular file? */
    138         || (st.st_uid != 0)                     /* Not owned by root? */
    139         || (st.st_mode & (S_IWGRP | S_IWOTH))   /* Writable by non-root? */
    140         || !(f = fopen(config_file, "r"))       /* Can not open? */
    141         ) {
     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    ) {
    142155        return;
    143156    }
     
    147160    section = lc = 0;
    148161
    149     do {
     162    while (1) {
    150163        s = buffer;
    151164
     
    175188        /* Trim leading and trailing whitespace, ignoring comments, and
    176189         * check if the resulting string is empty. */
    177         if (!*(s = get_trimmed_slice(s, strchrnul(s, '#')))) {
     190        s = get_trimmed_slice(s, strchrnul(s, '#'));
     191        if (!*s) {
    178192            continue;
    179193        }
     
    185199             * whitespace for the section name.  We also require that
    186200             * there are no stray characters after the closing bracket. */
    187             if (!(e = strchr(s, ']'))   /* Missing right bracket? */
    188                 || e[1]                 /* Trailing characters? */
    189                 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
    190                 ) {
     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            ) {
    191206                parse_error("section header");
    192207            }
     
    214229
    215230            /* First get the key (an applet name in our case). */
    216             if (!!(e = strchr(s, '='))) {
     231            e = strchr(s, '=');
     232            if (e) {
    217233                s = get_trimmed_slice(s, e);
    218234            }
     
    223239            /* Ok, we have an applet name.  Process the rhs if this
    224240             * applet is currently built in and ignore it otherwise.
    225              * Note: This can hide config file bugs which only pop
     241             * Note: this can hide config file bugs which only pop
    226242             * up when the busybox configuration is changed. */
    227             if ((applet = find_applet_by_name(s))) {
     243            applet = find_applet_by_name(s);
     244            if (applet) {
    228245                /* Note: We currently don't check for duplicates!
    229246                 * The last config line for each applet will be the
     
    240257                e = skip_whitespace(e+1);
    241258
    242                 for (i=0 ; i < 3 ; i++) {
     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
    243263                    const char *q;
    244                     if (!*(q = strchrnul(mode_chars + 5*i, *e++))) {
     264                    q = strchrnul(mode_chars + 5*i, *e++);
     265                    if (!*q) {
    245266                        parse_error("mode");
    246267                    }
     
    253274                s = skip_whitespace(e);
    254275
    255                 /* Note: We require whitespace between the mode and the
     276                /* Note: we require whitespace between the mode and the
    256277                 * user/group info. */
    257278                if ((s == e) || !(e = strchr(s, '.'))) {
    258279                    parse_error("<uid>.<gid>");
    259280                }
    260                 *e++ = 0;
     281                *e++ = '\0';
    261282
    262283                /* We can't use get_ug_id here since it would exit()
    263284                 * if a uid or gid was not found.  Oh well... */
    264                 {
    265                     char *e2;
    266 
    267                     sct->m_uid = strtoul(s, &e2, 10);
    268                     if (*e2 || (s == e2)) {
    269                         struct passwd *pwd;
    270                         if (!(pwd = getpwnam(s))) {
    271                             parse_error("user");
    272                         }
    273                         sct->m_uid = pwd->pw_uid;
     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");
    274290                    }
    275 
    276                     sct->m_gid = strtoul(e, &e2, 10);
    277                     if (*e2 || (e == e2)) {
    278                         struct group *grp;
    279                         if (!(grp = getgrnam(e))) {
    280                             parse_error("group");
    281                         }
    282                         sct->m_gid = grp->gr_gid;
     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");
    283300                    }
     301                    sct->m_gid = grp->gr_gid;
    284302                }
    285303            }
     
    298316        }
    299317
    300     } while (1);
     318    } /* while (1) */
    301319
    302320 pe_label:
    303321    fprintf(stderr, "Parse error in %s, line %d: %s\n",
    304             config_file, lc, err);
     322            config_file, lc, errmsg);
    305323
    306324    fclose(f);
     
    311329        sct_head = sct;
    312330    }
    313     return;
    314 }
    315 
     331}
    316332#else
    317 #define parse_config_file()
    318 #endif /* CONFIG_FEATURE_SUID_CONFIG */
    319 
    320 #ifdef CONFIG_FEATURE_SUID
    321 static void check_suid (struct BB_applet *applet)
    322 {
    323   uid_t ruid = getuid ();               /* real [ug]id */
    324   uid_t rgid = getgid ();
    325 
    326 #ifdef CONFIG_FEATURE_SUID_CONFIG
    327   if (suid_cfg_readable) {
    328     struct BB_suid_config *sct;
    329 
    330     for (sct = suid_config; sct; sct = sct->m_next) {
    331       if (sct->m_applet == applet)
    332         break;
    333     }
    334     if (sct) {
    335       mode_t m = sct->m_mode;
    336 
    337       if (sct->m_uid == ruid)       /* same uid */
    338         m >>= 6;
    339       else if ((sct->m_gid == rgid) || ingroup (ruid, sct->m_gid))  /* same group / in group */
    340         m >>= 3;
    341 
    342       if (!(m & S_IXOTH))           /* is x bit not set ? */
    343         bb_error_msg_and_die ("You have no permission to run this applet!");
    344 
    345       if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {     /* *both* have to be set for sgid */
    346         if (setegid (sct->m_gid))
    347           bb_error_msg_and_die
    348             ("BusyBox binary has insufficient rights to set proper GID for applet!");
    349       } else
    350         setgid (rgid);                  /* no sgid -> drop */
    351 
    352       if (sct->m_mode & S_ISUID) {
    353         if (seteuid (sct->m_uid))
    354           bb_error_msg_and_die
    355             ("BusyBox binary has insufficient rights to set proper UID for applet!");
    356       } else
    357         setuid (ruid);                  /* no suid -> drop */
    358     } 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        }
    359359        /* default: drop all privileges */
    360       setgid (rgid);
    361       setuid (ruid);
    362     }
    363     return;
    364   } else {
    365 #ifndef CONFIG_FEATURE_SUID_CONFIG_QUIET
    366     static int onetime = 0;
    367 
    368     if (!onetime) {
    369       onetime = 1;
    370       fprintf (stderr, "Using fallback suid method\n");
    371     }
    372 #endif
    373   }
    374 #endif
    375 
    376   if (applet->need_suid == _BB_SUID_ALWAYS) {
    377     if (geteuid () != 0)
    378       bb_error_msg_and_die ("This applet requires root privileges!");
    379   } else if (applet->need_suid == _BB_SUID_NEVER) {
    380     setgid (rgid);                          /* drop all privileges */
    381     setuid (ruid);
    382   }
     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    }
    383416}
    384417#else
    385 #define check_suid(x)
    386 #endif /* CONFIG_FEATURE_SUID */
    387 
     418#define check_suid(x) ((void)0)
     419#endif /* FEATURE_SUID */
    388420
    389421
     
    395427static const char *unpack_usage_messages(void)
    396428{
    397     int input[2], output[2], pid;
    398     char *buf;
    399 
    400     if(pipe(input) < 0 || pipe(output) < 0)
    401         exit(1);
    402 
    403     pid = fork();
    404     switch (pid) {
    405     case -1: /* error */
    406         exit(1);
    407     case 0: /* child */
    408         close(input[1]);
    409         close(output[0]);
    410         uncompressStream(input[0], output[1]);
    411         exit(0);
    412     }
    413     /* parent */
    414 
    415     close(input[0]);
    416     close(output[1]);
    417     pid = fork();
    418     switch (pid) {
    419     case -1: /* error */
    420         exit(1);
    421     case 0: /* child */
    422         bb_full_write(input[1], packed_usage, sizeof(packed_usage));
    423         exit(0);
    424     }
    425     /* parent */
    426     close(input[1]);
    427 
    428     buf = xmalloc(SIZEOF_usage_messages);
    429     bb_full_read(output[0], buf, SIZEOF_usage_messages);
    430     return buf;
    431 }
     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)
    432449
    433450#else
     451
    434452#define unpack_usage_messages() usage_messages
    435 #endif /* ENABLE_FEATURE_COMPRESS_USAGE */
    436 
    437 void bb_show_usage (void)
     453#define dealloc_usage_messages(s) ((void)(s))
     454
     455#endif /* FEATURE_COMPRESS_USAGE */
     456
     457
     458void bb_show_usage(void)
    438459{
    439460    if (ENABLE_SHOW_USAGE) {
    440461        const char *format_string;
    441         const char *usage_string = unpack_usage_messages();
     462        const char *p;
     463        const char *usage_string = p = unpack_usage_messages();
    442464        int i;
    443465
    444         for (i = applet_using - applets; i > 0;)
    445             if (!*usage_string++) --i;
    446 
    447         format_string = "%s\n\nUsage: %s %s\n\n";
    448         if (*usage_string == '\b')
    449             format_string = "%s\n\nNo help available.\n\n";
    450         fprintf (stderr, format_string, bb_msg_full_version,
    451             applet_using->name, usage_string);
    452     }
    453 
    454   exit (bb_default_error_retval);
    455 }
    456 
    457 static int applet_name_compare (const void *x, const void *y)
    458 {
    459   const char *name = x;
    460   const struct BB_applet *applet = y;
    461 
    462   return strcmp (name, applet->name);
    463 }
    464 
    465 extern const size_t NUM_APPLETS;
    466 
    467 struct BB_applet *find_applet_by_name (const char *name)
    468 {
    469   return bsearch (name, applets, NUM_APPLETS, sizeof (struct BB_applet),
    470                   applet_name_compare);
    471 }
    472 
    473 void run_applet_by_name (const char *name, int argc, char **argv)
    474 {
    475     if(ENABLE_FEATURE_SUID_CONFIG) parse_config_file ();
    476 
    477     if(!strncmp(name, "busybox", 7)) busybox_main(argc, argv);
     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{
    478492    /* Do a binary search to find the applet entry given the name. */
    479     applet_using = find_applet_by_name(name);
    480     if(applet_using) {
    481         bb_applet_name = applet_using->name;
    482         if(argc==2 && !strcmp(argv[1], "--help")) bb_show_usage ();
    483         if(ENABLE_FEATURE_SUID) check_suid (applet_using);
    484         exit ((*(applet_using->main)) (argc, argv));
    485     }
    486 }
     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 TracChangeset for help on using the changeset viewer.