Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
Location:
branches/2.2.9/mindi-busybox/libbb
Files:
37 added
94 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/libbb/Config.in

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    56
    67menu "Busybox Library Tuning"
     8
     9
    710
    811config PASSWORD_MINLEN
     
    1417
    1518config MD5_SIZE_VS_SPEED
    16     int " MD5: Trade Bytes for Speed"
     19    int "MD5: Trade bytes for speed (0:fast, 3:slow)"
    1720    default 2
    1821    range 0 3
     
    2932config FEATURE_FAST_TOP
    3033    bool "Faster /proc scanning code (+100 bytes)"
    31     default n
     34    default y
    3235    help
    3336      This option makes top (and ps) ~20% faster (or 20% less CPU hungry),
     
    4245      instead of IP/mask pairs in route command.
    4346
     47config FEATURE_USE_TERMIOS
     48    bool "Use termios to manipulate the screen"
     49    default y
     50    depends on MORE || TOP || POWERTOP
     51    help
     52      This option allows utilities such as 'more' and 'top' to determine
     53      the size of the screen. If you leave this disabled, your utilities
     54      that display things on the screen will be especially primitive and
     55      will be unable to determine the current screen size, and will be
     56      unable to move the cursor.
     57
    4458config FEATURE_EDITING
    4559    bool "Command line editing"
    46     default n
     60    default y
    4761    help
    4862      Enable line editing (mainly for shell command line).
     
    5872      benefits from smaller stack usage.
    5973
    60 config FEATURE_EDITING_FANCY_KEYS
    61     bool "Additional editing keys"
    62     default n
    63     depends on FEATURE_EDITING
    64     help
    65       Enable additonal editing keys (Ctrl-E, Ctrl-U etc).
    66       Arrow keys, Home/End/Delete and Ctrl-W work even without this option.
    67 
    6874config FEATURE_EDITING_VI
    6975    bool "vi-style line editing commands"
     
    7177    depends on FEATURE_EDITING
    7278    help
    73       Enable vi-style line editing.  In shells, this mode can be
     79      Enable vi-style line editing. In shells, this mode can be
    7480      turned on and off with "set -o vi" and "set +o vi".
    7581
     
    7783    int "History size"
    7884    range 0 99999
    79     default 15
     85    default 255
    8086    depends on FEATURE_EDITING
    8187    help
     
    8490config FEATURE_EDITING_SAVEHISTORY
    8591    bool "History saving"
    86     default n
    87     depends on ASH && FEATURE_EDITING
     92    default y
     93    depends on FEATURE_EDITING
    8894    help
    89       Enable history saving in ash shell.
     95      Enable history saving in shells.
    9096
    9197config FEATURE_TAB_COMPLETION
    9298    bool "Tab completion"
    93     default n
     99    default y
    94100    depends on FEATURE_EDITING
    95101    help
     
    105111config FEATURE_EDITING_FANCY_PROMPT
    106112    bool "Fancy shell prompts"
    107     default n
     113    default y
    108114    depends on FEATURE_EDITING
    109115    help
     
    111117      \$ and escape codes.
    112118
     119config FEATURE_EDITING_ASK_TERMINAL
     120    bool "Query cursor position from terminal"
     121    default n
     122    depends on FEATURE_EDITING
     123    help
     124      Allow usage of "ESC [ 6 n" sequence. Terminal answers back with
     125      current cursor position. This information is used to make line
     126      editing more robust in some cases.
     127      If you are not sure whether your terminals respond to this code
     128      correctly, or want to save on code size (about 400 bytes),
     129      then do not turn this option on.
     130
     131config FEATURE_NON_POSIX_CP
     132    bool "Non-POSIX, but safer, copying to special nodes"
     133    default y
     134    help
     135      With this option, "cp file symlink" will delete symlink
     136      and create a regular file. This does not conform to POSIX,
     137      but prevents a symlink attack.
     138      Similarly, "cp file device" will not send file's data
     139      to the device.
     140
     141config FEATURE_VERBOSE_CP_MESSAGE
     142    bool "Give more precise messages when copy fails (cp, mv etc)"
     143    default n
     144    help
     145      Error messages with this feature enabled:
     146        $ cp file /does_not_exist/file
     147        cp: cannot create '/does_not_exist/file': Path does not exist
     148        $ cp file /vmlinuz/file
     149        cp: cannot stat '/vmlinuz/file': Path has non-directory component
     150      If this feature is not enabled, they will be, respectively:
     151        cp: cannot create '/does_not_exist/file': No such file or directory
     152        cp: cannot stat '/vmlinuz/file': Not a directory
     153      This will cost you ~60 bytes.
     154
     155config FEATURE_COPYBUF_KB
     156    int "Copy buffer size, in kilobytes"
     157    range 1 1024
     158    default 4
     159    help
     160      Size of buffer used by cp, mv, install etc.
     161      Buffers which are 4 kb or less will be allocated on stack.
     162      Bigger buffers will be allocated with mmap, with fallback to 4 kb
     163      stack buffer if mmap fails.
     164
    113165config MONOTONIC_SYSCALL
    114166    bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
    115     default y
     167    default n
     168    depends on PLATFORM_LINUX
    116169    help
    117170      Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring
     
    128181      (e.g. VT_DISALLOCATE rather than 0x5608). If disabled this
    129182      saves about 1400 bytes.
     183
     184config FEATURE_HWIB
     185    bool "Support infiniband HW"
     186    default y
     187    help
     188      Support for printing infiniband addresses in
     189      network applets.
     190
    130191endmenu
  • branches/2.2.9/mindi-busybox/libbb/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2, see the file LICENSE in this tarball.
     6# Licensed under GPLv2, see file LICENSE in this source tree.
     7
     8libbb/appletlib.o: include/usage_compressed.h
    69
    710lib-y:=
    811
     12
     13
     14lib-y += appletlib.o
    915lib-y += ask_confirmation.o
    1016lib-y += bb_askpass.o
    1117lib-y += bb_basename.o
     18lib-y += bb_bswap_64.o
    1219lib-y += bb_do_delay.o
    1320lib-y += bb_pwd.o
     21lib-y += bb_qsort.o
     22#lib-y += bb_strtod.o
    1423lib-y += bb_strtonum.o
    1524lib-y += change_identity.o
     
    2635lib-y += device_open.o
    2736lib-y += dump.o
    28 lib-y += error_msg.o
    29 lib-y += error_msg_and_die.o
    3037lib-y += execable.o
    3138lib-y += fclose_nonstdin.o
     
    3946lib-y += get_line_from_file.o
    4047lib-y += getopt32.o
     48lib-y += getpty.o
     49lib-y += get_volsize.o
    4150lib-y += herror_msg.o
    42 lib-y += herror_msg_and_die.o
    4351lib-y += human_readable.o
    4452lib-y += inet_common.o
     
    4856lib-y += kernel_version.o
    4957lib-y += last_char_is.o
    50 lib-y += lineedit.o
     58lib-y += lineedit.o lineedit_ptr_hack.o
    5159lib-y += llist.o
    5260lib-y += login.o
     
    5462lib-y += makedev.o
    5563lib-y += match_fstype.o
    56 lib-y += md5.o
     64lib-y += hash_md5_sha.o
     65# Alternative (disabled) MD5 implementation
     66#lib-y += hash_md5prime.o
    5767lib-y += messages.o
    5868lib-y += mode_string.o
    59 lib-y += mtab_file.o
    6069lib-y += obscure.o
    6170lib-y += parse_mode.o
     71lib-y += parse_config.o
    6272lib-y += perror_msg.o
    63 lib-y += perror_msg_and_die.o
    6473lib-y += perror_nomsg.o
    6574lib-y += perror_nomsg_and_die.o
    6675lib-y += pidfile.o
     76lib-y += platform.o
     77lib-y += printable.o
     78lib-y += printable_string.o
     79lib-y += print_flags.o
    6780lib-y += process_escape_sequence.o
    6881lib-y += procps.o
     82lib-y += progress.o
     83lib-y += ptr_to_globals.o
    6984lib-y += read.o
     85lib-y += read_printf.o
     86lib-y += read_key.o
    7087lib-y += recursive_action.o
    7188lib-y += remove_file.o
    72 lib-y += restricted_shell.o
    7389lib-y += run_shell.o
     90lib-y += safe_gethostname.o
     91lib-y += safe_poll.o
    7492lib-y += safe_strncpy.o
    7593lib-y += safe_write.o
    7694lib-y += setup_environment.o
    77 lib-y += sha1.o
     95lib-y += signals.o
    7896lib-y += simplify_path.o
     97lib-y += single_argv.o
    7998lib-y += skip_whitespace.o
    8099lib-y += speed_table.o
    81100lib-y += str_tolower.o
     101lib-y += strrstr.o
    82102lib-y += time.o
    83103lib-y += trim.o
     
    91111lib-y += wfopen.o
    92112lib-y += wfopen_input.o
     113lib-y += write.o
    93114lib-y += xatonum.o
    94115lib-y += xconnect.o
    95116lib-y += xfuncs.o
     117lib-y += xfuncs_printf.o
     118lib-y += xfunc_die.o
    96119lib-y += xgetcwd.o
    97120lib-y += xgethostbyname.o
    98121lib-y += xreadlink.o
     122lib-y += xrealloc_vector.o
    99123
    100 # conditionally compiled objects:
     124lib-$(CONFIG_FEATURE_UTMP) += utmp.o
     125
     126# A mix of optimizations (why build stuff we know won't be used)
     127# and objects which may fail to build (SELinux on selinux-less system)
     128lib-$(CONFIG_SELINUX) += selinux_common.o
     129lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
     130lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
     131lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
     132
     133lib-$(CONFIG_LOSETUP) += loop.o
    101134lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o
    102 lib-$(CONFIG_LOSETUP) += loop.o
    103 lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
    104 lib-$(CONFIG_PASSWD) += pw_encrypt.o crypt_make_salt.o update_passwd.o
    105 lib-$(CONFIG_CHPASSWD) += pw_encrypt.o crypt_make_salt.o update_passwd.o
    106 lib-$(CONFIG_CRYPTPW) += pw_encrypt.o crypt_make_salt.o
     135
     136lib-$(CONFIG_ADDGROUP) += update_passwd.o
     137lib-$(CONFIG_ADDUSER) += update_passwd.o
     138lib-$(CONFIG_DELGROUP) += update_passwd.o
     139lib-$(CONFIG_DELUSER) += update_passwd.o
     140
     141lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o
     142lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o
     143lib-$(CONFIG_CRYPTPW) += pw_encrypt.o
    107144lib-$(CONFIG_SULOGIN) += pw_encrypt.o
     145lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o
     146lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o
     147lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o
    108148lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o
    109 lib-$(CONFIG_VLOCK) += correct_password.o
    110 lib-$(CONFIG_SU) += correct_password.o
    111 lib-$(CONFIG_LOGIN) += correct_password.o
     149
    112150lib-$(CONFIG_DF) += find_mount_point.o
    113151lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o
    114 lib-$(CONFIG_SELINUX) += selinux_common.o
     152lib-$(CONFIG_MKFS_EXT2) += find_mount_point.o
     153lib-$(CONFIG_MKFS_REISER) += find_mount_point.o
     154lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o
     155lib-$(CONFIG_MOUNT) += find_mount_point.o
     156
     157lib-$(CONFIG_HWCLOCK) += rtc.o
     158lib-$(CONFIG_RTCWAKE) += rtc.o
     159
     160lib-$(CONFIG_IOSTAT) += get_cpu_count.o
     161lib-$(CONFIG_MPSTAT) += get_cpu_count.o
     162lib-$(CONFIG_POWERTOP) += get_cpu_count.o
    115163
    116164# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
     
    124172lib-$(CONFIG_MDEV) += xregcomp.o
    125173lib-$(CONFIG_LESS) += xregcomp.o
     174lib-$(CONFIG_PGREP) += xregcomp.o
     175lib-$(CONFIG_PKILL) += xregcomp.o
    126176lib-$(CONFIG_DEVFSD) += xregcomp.o
    127177lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o
  • branches/2.2.9/mindi-busybox/libbb/README

    r821 r2725  
    99    Erik Andersen
    1010    <andersen@codepoet.org>
    11 
  • branches/2.2.9/mindi-busybox/libbb/ask_confirmation.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1111 * return 1.  Otherwise return 0.
    1212 */
    13 
    1413#include "libbb.h"
    1514
    16 int bb_ask_confirmation(void)
     15int FAST_FUNC bb_ask_confirmation(void)
    1716{
    18     int retval = 0;
    19     int first = 1;
     17    char first = 0;
    2018    int c;
    2119
    2220    while (((c = getchar()) != EOF) && (c != '\n')) {
    23         /* Make sure we get the actual function call for isspace,
    24          * as speed is not critical here. */
    25         if (first && !(isspace)(c)) {
    26             --first;
    27             if ((c == 'y') || (c == 'Y')) {
    28                 ++retval;
    29             }
     21        if (first == 0 && !isblank(c)) {
     22            first = c|0x20;
    3023        }
    3124    }
    3225
    33     return retval;
     26    return first == 'y';
    3427}
  • branches/2.2.9/mindi-busybox/libbb/bb_askpass.c

    r1765 r2725  
    66 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    10 
    11 #include <termios.h>
    1210
    1311#include "libbb.h"
    1412
    1513/* do nothing signal handler */
    16 static void askpass_timeout(int ATTRIBUTE_UNUSED ignore)
     14static void askpass_timeout(int UNUSED_PARAM ignore)
    1715{
    1816}
    1917
    20 char *bb_askpass(int timeout, const char * prompt)
     18char* FAST_FUNC bb_ask_stdin(const char *prompt)
     19{
     20    return bb_ask(STDIN_FILENO, 0, prompt);
     21}
     22char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
    2123{
    2224    /* Was static char[BIGNUM] */
     
    2628    char *ret;
    2729    int i;
    28     struct sigaction sa;
    29     struct termios old, new;
     30    struct sigaction sa, oldsa;
     31    struct termios tio, oldtio;
     32
     33    tcgetattr(fd, &oldtio);
     34    tcflush(fd, TCIFLUSH);
     35    tio = oldtio;
     36#ifndef IUCLC
     37# define IUCLC 0
     38#endif
     39    tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
     40    tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
     41    tcsetattr(fd, TCSANOW, &tio);
     42
     43    memset(&sa, 0, sizeof(sa));
     44    /* sa.sa_flags = 0; - no SA_RESTART! */
     45    /* SIGINT and SIGALRM will interrupt reads below */
     46    sa.sa_handler = askpass_timeout;
     47    sigaction(SIGINT, &sa, &oldsa);
     48    if (timeout) {
     49        sigaction_set(SIGALRM, &sa);
     50        alarm(timeout);
     51    }
     52
     53    fputs(prompt, stdout);
     54    fflush_all();
    3055
    3156    if (!passwd)
    3257        passwd = xmalloc(sizeof_passwd);
    33     memset(passwd, 0, sizeof_passwd);
    34 
    35     tcgetattr(STDIN_FILENO, &old);
    36     tcflush(STDIN_FILENO, TCIFLUSH);
    37 
    38     fputs(prompt, stdout);
    39     fflush(stdout);
    40 
    41     tcgetattr(STDIN_FILENO, &new);
    42     new.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
    43     new.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
    44     tcsetattr(STDIN_FILENO, TCSANOW, &new);
    45 
    46     if (timeout) {
    47         sa.sa_flags = 0;
    48         sa.sa_handler = askpass_timeout;
    49         sigaction(SIGALRM, &sa, NULL);
    50         alarm(timeout);
    51     }
    52 
    53     ret = NULL;
    54     /* On timeout, read will hopefully be interrupted by SIGALRM,
    55      * and we return NULL */
    56     if (read(STDIN_FILENO, passwd, sizeof_passwd-1) > 0) {
    57         ret = passwd;
    58         i = 0;
    59         /* Last byte is guaranteed to be 0
    60            (read did not overwrite it) */
    61         do {
    62             if (passwd[i] == '\r' || passwd[i] == '\n')
    63                 passwd[i] = '\0';
    64         } while (passwd[i++]);
     58    ret = passwd;
     59    i = 0;
     60    while (1) {
     61        int r = read(fd, &ret[i], 1);
     62        if (r < 0) {
     63            /* read is interrupted by timeout or ^C */
     64            ret = NULL;
     65            break;
     66        }
     67        if (r == 0 /* EOF */
     68         || ret[i] == '\r' || ret[i] == '\n' /* EOL */
     69         || ++i == sizeof_passwd-1 /* line limit */
     70        ) {
     71            ret[i] = '\0';
     72            break;
     73        }
    6574    }
    6675
     
    6877        alarm(0);
    6978    }
    70 
    71     tcsetattr(STDIN_FILENO, TCSANOW, &old);
    72     putchar('\n');
    73     fflush(stdout);
     79    sigaction_set(SIGINT, &oldsa);
     80    tcsetattr(fd, TCSANOW, &oldtio);
     81    bb_putchar('\n');
     82    fflush_all();
    7483    return ret;
    7584}
  • branches/2.2.9/mindi-busybox/libbb/bb_basename.c

    r1765 r2725  
    33 * Utility routines.
    44 *
    5  * Copyright (C) 2007 Denis Vlasenko
     5 * Copyright (C) 2007 Denys Vlasenko
    66 *
    7  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 const char *bb_basename(const char *name)
     12const char* FAST_FUNC bb_basename(const char *name)
    1313{
    1414    const char *cp = strrchr(name, '/');
  • branches/2.2.9/mindi-busybox/libbb/bb_do_delay.c

    r1765 r2725  
    55 * Copyright (C) 2005 by Tito Ragusa <tito-wolit@tiscali.it>
    66 *
    7  * Licensed under the GPL v2, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 void bb_do_delay(int seconds)
     12void FAST_FUNC bb_do_delay(int seconds)
    1313{
    1414    time_t start, now;
    1515
    16     time(&start);
    17     now = start;
    18     while (difftime(now, start) < seconds) {
     16    start = time(NULL);
     17    do {
    1918        sleep(seconds);
    20         time(&now);
    21     }
     19        now = time(NULL);
     20    } while ((now - start) < seconds);
    2221}
  • branches/2.2.9/mindi-busybox/libbb/bb_pwd.c

    r1765 r2725  
    44 *
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
     6 * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
    67 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    89 */
    910
    1011#include "libbb.h"
    1112
    12 #define assert(x) ((void)0)
     13/* TODO: maybe change API to return malloced data?
     14 * This will allow to stop using libc functions returning
     15 * pointers to static data (getpwuid)
     16 */
    1317
    14 /* internal function for bb_getpwuid and bb_getgrgid */
    15 /* Hacked by Tito Ragusa (c) 2004 <farmatito@tiscali.it> to make it more
    16  * flexible:
    17  *
    18  * bufsize > 0:      If idname is not NULL it is copied to buffer,
    19  *                   and buffer is returned. Else id as string is written
    20  *                   to buffer, and NULL is returned.
    21  *
    22  * bufsize == 0:     idname is returned.
    23  *
    24  * bufsize < 0:      If idname is not NULL it is returned.
    25  *                   Else an error message is printed and the program exits.
    26  */
    27 static char* bb_getug(char *buffer, int bufsize, char *idname, long id, char prefix)
     18struct passwd* FAST_FUNC xgetpwnam(const char *name)
    2819{
    29     if (bufsize > 0) {
    30         assert(buffer != NULL);
    31         if (idname) {
    32             return safe_strncpy(buffer, idname, bufsize);
    33         }
    34         snprintf(buffer, bufsize, "%ld", id);
    35     } else if (bufsize < 0 && !idname) {
    36         bb_error_msg_and_die("unknown %cid %ld", prefix, id);
    37     }
    38     return idname;
     20    struct passwd *pw = getpwnam(name);
     21    if (!pw)
     22        bb_error_msg_and_die("unknown user %s", name);
     23    return pw;
    3924}
    4025
    41 /* bb_getpwuid, bb_getgrgid:
    42  * bb_getXXXid(buf, bufsz, id) - copy user/group name or id
    43  *               as a string to buf, return user/group name or NULL
    44  * bb_getXXXid(NULL, 0, id) - return user/group name or NULL
    45  * bb_getXXXid(NULL, -1, id) - return user/group name or exit
    46  */
    47 /* gets a username given a uid */
    48 char* bb_getpwuid(char *name, int bufsize, long uid)
     26struct group* FAST_FUNC xgetgrnam(const char *name)
    4927{
    50     struct passwd *myuser = getpwuid(uid);
    51 
    52     return bb_getug(name, bufsize,
    53             (myuser ? myuser->pw_name : (char*)myuser),
    54             uid, 'u');
    55 }
    56 /* gets a groupname given a gid */
    57 char* bb_getgrgid(char *group, int bufsize, long gid)
    58 {
    59     struct group *mygroup = getgrgid(gid);
    60 
    61     return bb_getug(group, bufsize,
    62             (mygroup ? mygroup->gr_name : (char*)mygroup),
    63             gid, 'g');
     28    struct group *gr = getgrnam(name);
     29    if (!gr)
     30        bb_error_msg_and_die("unknown group %s", name);
     31    return gr;
    6432}
    6533
    66 /* returns a gid given a group name */
    67 long xgroup2gid(const char *name)
     34
     35struct passwd* FAST_FUNC xgetpwuid(uid_t uid)
     36{
     37    struct passwd *pw = getpwuid(uid);
     38    if (!pw)
     39        bb_error_msg_and_die("unknown uid %u", (unsigned)uid);
     40    return pw;
     41}
     42
     43struct group* FAST_FUNC xgetgrgid(gid_t gid)
     44{
     45    struct group *gr = getgrgid(gid);
     46    if (!gr)
     47        bb_error_msg_and_die("unknown gid %u", (unsigned)gid);
     48    return gr;
     49}
     50
     51char* FAST_FUNC xuid2uname(uid_t uid)
     52{
     53    struct passwd *pw = xgetpwuid(uid);
     54    return pw->pw_name;
     55}
     56
     57char* FAST_FUNC xgid2group(gid_t gid)
     58{
     59    struct group *gr = xgetgrgid(gid);
     60    return gr->gr_name;
     61}
     62
     63char* FAST_FUNC uid2uname(uid_t uid)
     64{
     65    struct passwd *pw = getpwuid(uid);
     66    return (pw) ? pw->pw_name : NULL;
     67}
     68
     69char* FAST_FUNC gid2group(gid_t gid)
     70{
     71    struct group *gr = getgrgid(gid);
     72    return (gr) ? gr->gr_name : NULL;
     73}
     74
     75char* FAST_FUNC uid2uname_utoa(long uid)
     76{
     77    char *name = uid2uname(uid);
     78    return (name) ? name : utoa(uid);
     79}
     80
     81char* FAST_FUNC gid2group_utoa(long gid)
     82{
     83    char *name = gid2group(gid);
     84    return (name) ? name : utoa(gid);
     85}
     86
     87long FAST_FUNC xuname2uid(const char *name)
     88{
     89    struct passwd *myuser;
     90
     91    myuser = xgetpwnam(name);
     92    return myuser->pw_uid;
     93}
     94
     95long FAST_FUNC xgroup2gid(const char *name)
    6896{
    6997    struct group *mygroup;
    7098
    71     mygroup = getgrnam(name);
    72     if (mygroup == NULL)
    73         bb_error_msg_and_die("unknown group name: %s", name);
    74 
     99    mygroup = xgetgrnam(name);
    75100    return mygroup->gr_gid;
    76101}
    77102
    78 /* returns a uid given a username */
    79 long xuname2uid(const char *name)
    80 {
    81     struct passwd *myuser;
    82 
    83     myuser = getpwnam(name);
    84     if (myuser == NULL)
    85         bb_error_msg_and_die("unknown user name: %s", name);
    86 
    87     return myuser->pw_uid;
    88 }
    89 
    90 unsigned long get_ug_id(const char *s,
    91         long (*xname2id)(const char *))
     103unsigned long FAST_FUNC get_ug_id(const char *s,
     104        long FAST_FUNC (*xname2id)(const char *))
    92105{
    93106    unsigned long r;
  • branches/2.2.9/mindi-busybox/libbb/bb_strtonum.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1111
    1212/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
    13  * errno = EINVAL if value was not '\0' terminated, but othervise ok
     13 * errno = EINVAL if value was not '\0' terminated, but otherwise ok
    1414 *    Return value is still valid, caller should just check whether end[0]
    1515 *    is a valid terminating char for particular case. OTOH, if caller
     
    1919 * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
    2020 *    return value is all-ones in this case.
     21 *
     22 * Test code:
     23 * char *endptr;
     24 * const char *minus = "-";
     25 * errno = 0;
     26 * bb_strtoi(minus, &endptr, 0); // must set ERANGE
     27 * printf("minus:%p endptr:%p errno:%d EINVAL:%d\n", minus, endptr, errno, EINVAL);
     28 * errno = 0;
     29 * bb_strtoi("-0-", &endptr, 0); // must set EINVAL and point to second '-'
     30 * printf("endptr[0]:%c errno:%d EINVAL:%d\n", endptr[0], errno, EINVAL);
    2131 */
    2232
     
    3040{
    3141    if (endp) *endp = endptr;
    32 
    33     /* Check for the weird "feature":
    34      * a "-" string is apparently a valid "number" for strto[u]l[l]!
    35      * It returns zero and errno is 0! :( */
    36     if (endptr[-1] == '-')
    37         return ret_ERANGE();
    3842
    3943    /* errno is already set to ERANGE by strtoXXX if value overflowed */
     
    4953
    5054
    51 unsigned long long bb_strtoull(const char *arg, char **endp, int base)
     55unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base)
    5256{
    5357    unsigned long long v;
     
    6468}
    6569
    66 long long bb_strtoll(const char *arg, char **endp, int base)
     70long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base)
    6771{
    6872    unsigned long long v;
    6973    char *endptr;
    7074
    71     if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
     75    /* Check for the weird "feature":
     76     * a "-" string is apparently a valid "number" for strto[u]l[l]!
     77     * It returns zero and errno is 0! :( */
     78    char first = (arg[0] != '-' ? arg[0] : arg[1]);
     79    if (!isalnum(first)) return ret_ERANGE();
     80
    7281    errno = 0;
    7382    v = strtoll(arg, &endptr, base);
     
    7685
    7786#if ULONG_MAX != ULLONG_MAX
    78 unsigned long bb_strtoul(const char *arg, char **endp, int base)
     87unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base)
    7988{
    8089    unsigned long v;
     
    8796}
    8897
    89 long bb_strtol(const char *arg, char **endp, int base)
     98long FAST_FUNC bb_strtol(const char *arg, char **endp, int base)
    9099{
    91100    long v;
    92101    char *endptr;
    93102
    94     if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
     103    char first = (arg[0] != '-' ? arg[0] : arg[1]);
     104    if (!isalnum(first)) return ret_ERANGE();
     105
    95106    errno = 0;
    96107    v = strtol(arg, &endptr, base);
     
    100111
    101112#if UINT_MAX != ULONG_MAX
    102 unsigned bb_strtou(const char *arg, char **endp, int base)
     113unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base)
    103114{
    104115    unsigned long v;
     
    112123}
    113124
    114 int bb_strtoi(const char *arg, char **endp, int base)
     125int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base)
    115126{
    116127    long v;
    117128    char *endptr;
    118129
    119     if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
     130    char first = (arg[0] != '-' ? arg[0] : arg[1]);
     131    if (!isalnum(first)) return ret_ERANGE();
     132
    120133    errno = 0;
    121134    v = strtol(arg, &endptr, base);
     
    125138}
    126139#endif
    127 
    128 /* Floating point */
    129 
    130 #if 0
    131 
    132 #include <math.h>  /* just for HUGE_VAL */
    133 #define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9)
    134 double bb_strtod(const char *arg, char **endp)
    135 {
    136     double v;
    137     char *endptr;
    138 
    139     if (arg[0] != '-' && NOT_DIGIT(arg[0])) goto err;
    140     errno = 0;
    141     v = strtod(arg, &endptr);
    142     if (endp) *endp = endptr;
    143     if (endptr[0]) {
    144         /* "1234abcg" or out-of-range? */
    145         if (isalnum(endptr[0]) || errno) {
    146  err:
    147             errno = ERANGE;
    148             return HUGE_VAL;
    149         }
    150         /* good number, just suspicious terminator */
    151         errno = EINVAL;
    152     }
    153     return v;
    154 }
    155 
    156 #endif
  • branches/2.2.9/mindi-busybox/libbb/change_identity.c

    r1765 r2725  
    3131#include "libbb.h"
    3232
    33 
    3433/* Become the user and group(s) specified by PW.  */
    35 const char *change_identity_e2str(const struct passwd *pw)
     34void FAST_FUNC change_identity(const struct passwd *pw)
    3635{
    3736    if (initgroups(pw->pw_name, pw->pw_gid) == -1)
    38         return "cannot set groups";
    39     endgrent(); /* ?? */
     37        bb_perror_msg_and_die("can't set groups");
     38    endgrent(); /* helps to close a fd used internally by libc */
    4039    xsetgid(pw->pw_gid);
    4140    xsetuid(pw->pw_uid);
    42     return NULL;
    4341}
    44 
    45 void change_identity(const struct passwd *pw)
    46 {
    47     const char *err_msg = change_identity_e2str(pw);
    48 
    49     if (err_msg)
    50         bb_perror_msg_and_die("%s", err_msg);
    51 }
  • branches/2.2.9/mindi-busybox/libbb/chomp.c

    r1765 r2725  
    66 * If you wrote this, please acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
    1111#include "libbb.h"
    1212
    13 void chomp(char *s)
     13void FAST_FUNC chomp(char *s)
    1414{
    1515    char *lc = last_char_is(s, '\n');
  • branches/2.2.9/mindi-busybox/libbb/compare_string_array.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
    55
     
    88/* returns the array index of the string */
    99/* (index of first match is returned, or -1) */
    10 int index_in_str_array(const char *const string_array[], const char *key)
     10int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key)
    1111{
    1212    int i;
     
    2020}
    2121
    22 int index_in_strings(const char *strings, const char *key)
     22int FAST_FUNC index_in_strings(const char *strings, const char *key)
    2323{
    2424    int idx = 0;
    2525
    26     while (strings[0]) {
     26    while (*strings) {
    2727        if (strcmp(strings, key) == 0) {
    2828            return idx;
     
    3737/* (index of first match is returned, or -1) */
    3838#ifdef UNUSED
    39 int index_in_substr_array(const char *const string_array[], const char *key)
     39int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key)
    4040{
    4141    int i;
     
    5252#endif
    5353
    54 int index_in_substrings(const char *strings, const char *key)
     54int FAST_FUNC index_in_substrings(const char *strings, const char *key)
    5555{
    56     int len = strlen(key);
     56    int matched_idx = -1;
     57    const int len = strlen(key);
    5758
    5859    if (len) {
    5960        int idx = 0;
    60         while (strings[0]) {
     61        while (*strings) {
    6162            if (strncmp(strings, key, len) == 0) {
    62                 return idx;
     63                if (strings[len] == '\0')
     64                    return idx; /* exact match */
     65                if (matched_idx >= 0)
     66                    return -1; /* ambiguous match */
     67                matched_idx = idx;
    6368            }
    6469            strings += strlen(strings) + 1; /* skip NUL */
     
    6671        }
    6772    }
    68     return -1;
     73    return matched_idx;
    6974}
     75
     76const char* FAST_FUNC nth_string(const char *strings, int n)
     77{
     78    while (n) {
     79        n--;
     80        strings += strlen(strings) + 1;
     81    }
     82    return strings;
     83}
     84
     85#ifdef UNUSED_SO_FAR /* only brctl.c needs it yet */
     86/* Returns 0 for no, 1 for yes or a negative value on error.  */
     87smallint FAST_FUNC yesno(const char *str)
     88{
     89    static const char no_yes[] ALIGN1 =
     90        "0\0" "off\0" "no\0"
     91        "1\0" "on\0" "yes\0";
     92    int ret = index_in_substrings(no_yes, str);
     93    return ret / 3;
     94}
     95#endif
  • branches/2.2.9/mindi-busybox/libbb/concat_path_file.c

    r1765 r2725  
    66 * If you wrote this, please acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
    11 /* concatenate path and file name to new allocation buffer,
    12  * not adding '/' if path name already has '/'
    13 */
     11/* Concatenate path and filename to new allocated buffer.
     12 * Add '/' only as needed (no duplicate // are produced).
     13 * If path is NULL, it is assumed to be "/".
     14 * filename should not be NULL.
     15 */
    1416
    1517#include "libbb.h"
    1618
    17 char *concat_path_file(const char *path, const char *filename)
     19char* FAST_FUNC concat_path_file(const char *path, const char *filename)
    1820{
    1921    char *lc;
  • branches/2.2.9/mindi-busybox/libbb/concat_subpath_file.c

    r1765 r2725  
    55 * Copyright (C) (C) 2003  Vladimir Oleynik  <dzo@simtreas.ru>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1616#include "libbb.h"
    1717
    18 char *concat_subpath_file(const char *path, const char *f)
     18char* FAST_FUNC concat_subpath_file(const char *path, const char *f)
    1919{
    2020    if (f && DOT_OR_DOTDOT(f))
  • branches/2.2.9/mindi-busybox/libbb/copy_file.c

    r1765 r2725  
    66 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    9  *
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    109 */
    11 
    1210#include "libbb.h"
    1311
     12// FEATURE_NON_POSIX_CP:
     13//
    1414// POSIX: if exists and -i, ask (w/o -i assume yes).
    1515// Then open w/o EXCL (yes, not unlink!).
    1616// If open still fails and -f, try unlink, then try open again.
    1717// Result: a mess:
    18 // If dest is a softlink, we overwrite softlink's destination!
     18// If dest is a (sym)link, we overwrite link destination!
    1919// (or fail, if it points to dir/nonexistent location/etc).
    2020// This is strange, but POSIX-correct.
    2121// coreutils cp has --remove-destination to override this...
    22 //
    23 // NB: we have special code which still allows for "cp file /dev/node"
    24 // to work POSIX-ly (the only realistic case where it makes sense)
    25 
    26 #define DO_POSIX_CP 0  /* 1 - POSIX behavior, 0 - safe behavior */
    27 
    28 // errno must be set to relevant value ("why we cannot create dest?")
    29 // for POSIX mode to give reasonable error message
     22
     23/* Called if open of destination, link creation etc fails.
     24 * errno must be set to relevant value ("why we cannot create dest?")
     25 * to give reasonable error message */
    3026static int ask_and_unlink(const char *dest, int flags)
    3127{
    32 #if DO_POSIX_CP
     28    int e = errno;
     29
     30#if !ENABLE_FEATURE_NON_POSIX_CP
    3331    if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
    34         // Either it exists, or the *path* doesnt exist
    35         bb_perror_msg("cannot create '%s'", dest);
     32        /* Either it exists, or the *path* doesnt exist */
     33        bb_perror_msg("can't create '%s'", dest);
    3634        return -1;
    3735    }
    3836#endif
    39     // If !DO_POSIX_CP, act as if -f is always in effect - we don't want
    40     // "cannot create" msg, we want unlink to be done (silently unless -i).
    41 
    42     // TODO: maybe we should do it only if ctty is present?
     37    // else: act as if -f is always in effect.
     38    // We don't want "can't create" msg, we want unlink to be done
     39    // (silently unless -i). Why? POSIX cp usually succeeds with
     40    // O_TRUNC open of existing file, and user is left ignorantly happy.
     41    // With above block unconditionally enabled, non-POSIX cp
     42    // will complain a lot more than POSIX one.
     43
     44    /* TODO: maybe we should do it only if ctty is present? */
    4345    if (flags & FILEUTILS_INTERACTIVE) {
    4446        // We would not do POSIX insanity. -i asks,
     
    4850        fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
    4951        if (!bb_ask_confirmation())
    50             return 0; // not allowed to overwrite
     52            return 0; /* not allowed to overwrite */
    5153    }
    5254    if (unlink(dest) < 0) {
    53         bb_perror_msg("cannot remove '%s'", dest);
    54         return -1; // error
    55     }
    56     return 1; // ok (to try again)
     55#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
     56        if (e == errno && e == ENOENT) {
     57            /* e == ENOTDIR is similar: path has non-dir component,
     58             * but in this case we don't even reach copy_file() */
     59            bb_error_msg("can't create '%s': Path does not exist", dest);
     60            return -1; /* error */
     61        }
     62#endif
     63        errno = e; /* do not use errno from unlink */
     64        bb_perror_msg("can't create '%s'", dest);
     65        return -1; /* error */
     66    }
     67    return 1; /* ok (to try again) */
    5768}
    5869
     
    6273 *    (failures to preserve mode/owner/times are not reported in exit code)
    6374 */
    64 int copy_file(const char *source, const char *dest, int flags)
     75int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
    6576{
    6677    /* This is a recursive function, try to minimize stack usage */
     
    7283    signed char ovr;
    7384
    74 #define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE)
     85/* Inverse of cp -d ("cp without -d") */
     86#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
    7587
    7688    if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
    77         // This may be a dangling symlink.
    78         // Making [sym]links to dangling symlinks works, so...
     89        /* This may be a dangling symlink.
     90         * Making [sym]links to dangling symlinks works, so... */
    7991        if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
    8092            goto make_links;
    81         bb_perror_msg("cannot stat '%s'", source);
     93        bb_perror_msg("can't stat '%s'", source);
    8294        return -1;
    8395    }
     
    8597    if (lstat(dest, &dest_stat) < 0) {
    8698        if (errno != ENOENT) {
    87             bb_perror_msg("cannot stat '%s'", dest);
     99            bb_perror_msg("can't stat '%s'", dest);
    88100            return -1;
    89101        }
     
    103115        if (lgetfilecon(source, &con) >= 0) {
    104116            if (setfscreatecon(con) < 0) {
    105                 bb_perror_msg("cannot set setfscreatecon %s", con);
     117                bb_perror_msg("can't set setfscreatecon %s", con);
    106118                freecon(con);
    107119                return -1;
     
    110122            setfscreatecon_or_die(NULL);
    111123        } else {
    112             bb_perror_msg("cannot lgetfilecon %s", source);
     124            bb_perror_msg("can't lgetfilecon %s", source);
    113125            return -1;
    114126        }
     
    155167            if (mkdir(dest, mode) < 0) {
    156168                umask(saved_umask);
    157                 bb_perror_msg("cannot create directory '%s'", dest);
     169                bb_perror_msg("can't create directory '%s'", dest);
    158170                return -1;
    159171            }
     
    161173            /* need stat info for add_to_ino_dev_hashtable */
    162174            if (lstat(dest, &dest_stat) < 0) {
    163                 bb_perror_msg("cannot stat '%s'", dest);
     175                bb_perror_msg("can't stat '%s'", dest);
    164176                return -1;
    165177            }
     
    183195                continue;
    184196            new_dest = concat_path_file(dest, d->d_name);
    185             if (copy_file(new_source, new_dest, flags) < 0)
     197            if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0)
    186198                retval = -1;
    187199            free(new_source);
     
    193205         && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
    194206        ) {
    195             bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
     207            bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
    196208            /* retval = -1; - WRONG! copy *WAS* made */
    197209        }
     
    202214        int (*lf)(const char *oldpath, const char *newpath);
    203215 make_links:
    204         // Hmm... maybe
    205         // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
    206         // (but realpath returns NULL on dangling symlinks...)
     216        /* Hmm... maybe
     217         * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
     218         * (but realpath returns NULL on dangling symlinks...) */
    207219        lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
    208220        if (lf(source, dest) < 0) {
     
    211223                return ovr;
    212224            if (lf(source, dest) < 0) {
    213                 bb_perror_msg("cannot create link '%s'", dest);
     225                bb_perror_msg("can't create link '%s'", dest);
    214226                return -1;
    215227            }
    216228        }
    217229        /* _Not_ jumping to preserve_mode_ugid_time:
    218          * hard/softlinks don't have those */
     230         * (sym)links don't have those */
    219231        return 0;
    220232    }
    221233
    222     if (S_ISREG(source_stat.st_mode)
    223      /* DEREF uses stat, which never returns S_ISLNK() == true. */
     234    if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */
     235        !(flags & FILEUTILS_RECUR)
     236        /* "cp [-opts] regular_file thing2" */
     237     || S_ISREG(source_stat.st_mode)
     238     /* DEREF uses stat, which never returns S_ISLNK() == true.
     239      * So the below is never true: */
    224240     /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
    225241    ) {
    226242        int src_fd;
    227243        int dst_fd;
     244        mode_t new_mode;
     245
     246        if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) {
     247            /* "cp -d symlink dst": create a link */
     248            goto dont_cat;
     249        }
    228250
    229251        if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
     
    236258                        return ovr;
    237259                    if (link(link_target, dest) < 0) {
    238                         bb_perror_msg("cannot create link '%s'", dest);
     260                        bb_perror_msg("can't create link '%s'", dest);
    239261                        return -1;
    240262                    }
     
    249271            return -1;
    250272
    251         /* POSIX way is a security problem versus symlink attacks,
    252          * we do it only for non-symlinks, and only for non-recursive,
    253          * non-interactive cp. NB: it is still racy
    254          * for "cp file /home/bad_user/file" case
    255          * (user can rm file and create a link to /etc/passwd) */
    256         if (DO_POSIX_CP
    257          || (dest_exists && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE))
    258              && !S_ISLNK(dest_stat.st_mode))
    259         ) {
    260             dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode);
    261         } else  /* safe way: */
    262             dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode);
     273        /* Do not try to open with weird mode fields */
     274        new_mode = source_stat.st_mode;
     275        if (!S_ISREG(source_stat.st_mode))
     276            new_mode = 0666;
     277
     278        // POSIX way is a security problem versus (sym)link attacks
     279        if (!ENABLE_FEATURE_NON_POSIX_CP) {
     280            dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
     281        } else { /* safe way: */
     282            dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
     283        }
    263284        if (dst_fd == -1) {
    264285            ovr = ask_and_unlink(dest, flags);
     
    268289            }
    269290            /* It shouldn't exist. If it exists, do not open (symlink attack?) */
    270             dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode);
     291            dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
    271292            if (dst_fd < 0) {
    272293                close(src_fd);
     
    276297
    277298#if ENABLE_SELINUX
    278         if (((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT)
    279             || (flags & FILEUTILS_SET_SECURITY_CONTEXT))
     299        if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT))
    280300         && is_selinux_enabled() > 0
    281301        ) {
     
    297317        if (bb_copyfd_eof(src_fd, dst_fd) == -1)
    298318            retval = -1;
    299         /* Ok, writing side I can understand... */
     319        /* Careful with writing... */
    300320        if (close(dst_fd) < 0) {
    301             bb_perror_msg("cannot close '%s'", dest);
     321            bb_perror_msg("error writing to '%s'", dest);
    302322            retval = -1;
    303323        }
    304324        /* ...but read size is already checked by bb_copyfd_eof */
    305325        close(src_fd);
     326        /* "cp /dev/something new_file" should not
     327         * copy mode of /dev/something */
     328        if (!S_ISREG(source_stat.st_mode))
     329            return retval;
    306330        goto preserve_mode_ugid_time;
    307331    }
     332 dont_cat:
    308333
    309334    /* Source is a symlink or a special file */
     
    321346            free(lpath);
    322347            if (r < 0) {
    323                 bb_perror_msg("cannot create symlink '%s'", dest);
     348                bb_perror_msg("can't create symlink '%s'", dest);
    324349                return -1;
    325350            }
    326351            if (flags & FILEUTILS_PRESERVE_STATUS)
    327352                if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
    328                     bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
     353                    bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
    329354        }
    330355        /* _Not_ jumping to preserve_mode_ugid_time:
     
    336361    ) {
    337362        if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
    338             bb_perror_msg("cannot create '%s'", dest);
     363            bb_perror_msg("can't create '%s'", dest);
    339364            return -1;
    340365        }
     
    350375    /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
    351376    ) {
    352         struct utimbuf times;
    353 
    354         times.actime = source_stat.st_atime;
    355         times.modtime = source_stat.st_mtime;
     377        struct timeval times[2];
     378
     379        times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime;
     380        times[1].tv_usec = times[0].tv_usec = 0;
    356381        /* BTW, utimes sets usec-precision time - just FYI */
    357         if (utime(dest, &times) < 0)
    358             bb_perror_msg("cannot preserve %s of '%s'", "times", dest);
     382        if (utimes(dest, times) < 0)
     383            bb_perror_msg("can't preserve %s of '%s'", "times", dest);
    359384        if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
    360385            source_stat.st_mode &= ~(S_ISUID | S_ISGID);
    361             bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
     386            bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
    362387        }
    363388        if (chmod(dest, source_stat.st_mode) < 0)
    364             bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
     389            bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
    365390    }
    366391
  • branches/2.2.9/mindi-busybox/libbb/copyfd.c

    r1765 r2725  
    55 * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 #if BUFSIZ < 4096
    13 #undef BUFSIZ
    14 #define BUFSIZ 4096
    15 #endif
    16 
    17 /* Used by NOFORK applets (e.g. cat) - must not use xmalloc */
    18 
     12/* Used by NOFORK applets (e.g. cat) - must not use xmalloc.
     13 * size < 0 means "ignore write errors", used by tar --to-command
     14 * size = 0 means "copy till EOF"
     15 */
    1916static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
    2017{
    2118    int status = -1;
    2219    off_t total = 0;
    23     char buffer[BUFSIZ];
     20    bool continue_on_write_error = 0;
     21#if CONFIG_FEATURE_COPYBUF_KB <= 4
     22    char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
     23    enum { buffer_size = sizeof(buffer) };
     24#else
     25    char *buffer;
     26    int buffer_size;
     27#endif
     28
     29    if (size < 0) {
     30        size = -size;
     31        continue_on_write_error = 1;
     32    }
     33
     34#if CONFIG_FEATURE_COPYBUF_KB > 4
     35    if (size > 0 && size <= 4 * 1024)
     36        goto use_small_buf;
     37    /* We want page-aligned buffer, just in case kernel is clever
     38     * and can do page-aligned io more efficiently */
     39    buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
     40            PROT_READ | PROT_WRITE,
     41            MAP_PRIVATE | MAP_ANON,
     42            /* ignored: */ -1, 0);
     43    buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
     44    if (buffer == MAP_FAILED) {
     45 use_small_buf:
     46        buffer = alloca(4 * 1024);
     47        buffer_size = 4 * 1024;
     48    }
     49#endif
    2450
    2551    if (src_fd < 0)
     
    2753
    2854    if (!size) {
    29         size = BUFSIZ;
     55        size = buffer_size;
    3056        status = 1; /* copy until eof */
    3157    }
     
    3460        ssize_t rd;
    3561
    36         rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);
     62        rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
    3763
    3864        if (!rd) { /* eof - all done */
     
    4874            ssize_t wr = full_write(dst_fd, buffer, rd);
    4975            if (wr < rd) {
    50                 bb_perror_msg(bb_msg_write_error);
    51                 break;
     76                if (!continue_on_write_error) {
     77                    bb_perror_msg(bb_msg_write_error);
     78                    break;
     79                }
     80                dst_fd = -1;
    5281            }
    5382        }
     
    6392    }
    6493 out:
     94
     95#if CONFIG_FEATURE_COPYBUF_KB > 4
     96    if (buffer_size != 4 * 1024)
     97        munmap(buffer, buffer_size);
     98#endif
    6599    return status ? -1 : total;
    66100}
     
    68102
    69103#if 0
    70 void complain_copyfd_and_die(off_t sz)
     104void FAST_FUNC complain_copyfd_and_die(off_t sz)
    71105{
    72106    if (sz != -1)
     
    77111#endif
    78112
    79 off_t bb_copyfd_size(int fd1, int fd2, off_t size)
     113off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size)
    80114{
    81115    if (size) {
     
    85119}
    86120
    87 void bb_copyfd_exact_size(int fd1, int fd2, off_t size)
     121void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size)
    88122{
    89123    off_t sz = bb_copyfd_size(fd1, fd2, size);
    90     if (sz == size)
     124    if (sz == (size >= 0 ? size : -size))
    91125        return;
    92126    if (sz != -1)
     
    96130}
    97131
    98 off_t bb_copyfd_eof(int fd1, int fd2)
     132off_t FAST_FUNC bb_copyfd_eof(int fd1, int fd2)
    99133{
    100134    return bb_full_fd_action(fd1, fd2, 0);
  • branches/2.2.9/mindi-busybox/libbb/correct_password.c

    r1765 r2725  
    3737 * NULL pw means "just fake it for login with bad username" */
    3838
    39 int correct_password(const struct passwd *pw)
     39int FAST_FUNC correct_password(const struct passwd *pw)
    4040{
    4141    char *unencrypted, *encrypted;
    4242    const char *correct;
     43    int r;
     44#if ENABLE_FEATURE_SHADOWPASSWDS
     45    /* Using _r function to avoid pulling in static buffers */
     46    struct spwd spw;
     47    char buffer[256];
     48#endif
    4349
    4450    /* fake salt. crypt() can choke otherwise. */
     
    5157#if ENABLE_FEATURE_SHADOWPASSWDS
    5258    if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
    53         /* Using _r function to avoid pulling in static buffers */
    54         struct spwd spw;
    55         struct spwd *result;
    56         char buffer[256];
    57         correct = (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result)) ? "aa" : spw.sp_pwdp;
     59        /* getspnam_r may return 0 yet set result to NULL.
     60         * At least glibc 2.4 does this. Be extra paranoid here. */
     61        struct spwd *result = NULL;
     62        r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
     63        correct = (r || !result) ? "aa" : result->sp_pwdp;
    5864    }
    5965#endif
     
    6369
    6470 fake_it:
    65     unencrypted = bb_askpass(0, "Password: ");
     71    unencrypted = bb_ask_stdin("Password: ");
    6672    if (!unencrypted) {
    6773        return 0;
    6874    }
    69     encrypted = crypt(unencrypted, correct);
     75    encrypted = pw_encrypt(unencrypted, correct, 1);
     76    r = (strcmp(encrypted, correct) == 0);
     77    free(encrypted);
    7078    memset(unencrypted, 0, strlen(unencrypted));
    71     return strcmp(encrypted, correct) == 0;
     79    return r;
    7280}
  • branches/2.2.9/mindi-busybox/libbb/crc32.c

    r1765 r2725  
    1313 * endian = 1: big-endian
    1414 * endian = 0: little-endian
     15 *
     16 * Licensed under GPLv2, see file LICENSE in this source tree.
    1517 */
    1618
    1719#include "libbb.h"
    1820
    19 uint32_t *crc32_filltable(uint32_t *crc_table, int endian)
     21uint32_t *global_crc32_table;
     22
     23uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian)
    2024{
    2125    uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320;
     
    3943    return crc_table - 256;
    4044}
     45
     46uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
     47{
     48    const void *end = (uint8_t*)buf + len;
     49
     50    while (buf != end) {
     51        val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf];
     52        buf = (uint8_t*)buf + 1;
     53    }
     54    return val;
     55}
     56
     57uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
     58{
     59    const void *end = (uint8_t*)buf + len;
     60
     61    while (buf != end) {
     62                val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
     63        buf = (uint8_t*)buf + 1;
     64    }
     65    return val;
     66}
  • branches/2.2.9/mindi-busybox/libbb/create_icmp6_socket.c

    r1765 r2725  
    33 * Utility routines.
    44 *
    5  * create raw socket for icmp (IPv6 version) protocol test permission
     5 * create raw socket for icmp (IPv6 version) protocol
    66 * and drop root privileges if running setuid
    77 *
     8 * Licensed under GPLv2, see file LICENSE in this source tree.
    89 */
    910
    10 //#include <sys/types.h>
    11 //#include <netdb.h>
    12 //#include <sys/socket.h>
    1311#include "libbb.h"
    1412
    1513#if ENABLE_FEATURE_IPV6
    16 int create_icmp6_socket(void)
     14int FAST_FUNC create_icmp6_socket(void)
    1715{
     16    int sock;
     17#if 0
    1818    struct protoent *proto;
    19     int sock;
    20 
    2119    proto = getprotobyname("ipv6-icmp");
    2220    /* if getprotobyname failed, just silently force
     
    2422    sock = socket(AF_INET6, SOCK_RAW,
    2523            (proto ? proto->p_proto : IPPROTO_ICMPV6));
     24#else
     25    sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
     26#endif
    2627    if (sock < 0) {
    2728        if (errno == EPERM)
  • branches/2.2.9/mindi-busybox/libbb/create_icmp_socket.c

    r1765 r2725  
    33 * Utility routines.
    44 *
    5  * create raw socket for icmp protocol test permission
     5 * create raw socket for icmp protocol
    66 * and drop root privileges if running setuid
    77 *
     8 * Licensed under GPLv2, see file LICENSE in this source tree.
    89 */
    910
    10 //#include <sys/types.h>
    11 //#include <netdb.h>
    12 //#include <sys/socket.h>
    1311#include "libbb.h"
    1412
    15 int create_icmp_socket(void)
     13int FAST_FUNC create_icmp_socket(void)
    1614{
     15    int sock;
     16#if 0
    1717    struct protoent *proto;
    18     int sock;
    19 
    2018    proto = getprotobyname("icmp");
    2119    /* if getprotobyname failed, just silently force
     
    2321    sock = socket(AF_INET, SOCK_RAW,
    2422            (proto ? proto->p_proto : 1)); /* 1 == ICMP */
     23#else
     24    sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
     25#endif
    2526    if (sock < 0) {
    2627        if (errno == EPERM)
  • branches/2.2.9/mindi-busybox/libbb/default_error_retval.c

    r1765 r2725  
    33 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    66 */
    77
     
    1616#include "libbb.h"
    1717
    18 int xfunc_error_retval = EXIT_FAILURE;
     18uint8_t xfunc_error_retval = EXIT_FAILURE;
  • branches/2.2.9/mindi-busybox/libbb/device_open.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1111
    1212/* try to open up the specified device */
    13 int device_open(const char *device, int mode)
     13int FAST_FUNC device_open(const char *device, int mode)
    1414{
    15     int m, f, fd = -1;
     15    int m, f, fd;
    1616
    1717    m = mode | O_NONBLOCK;
     
    1919    /* Retry up to 5 times */
    2020    /* TODO: explain why it can't be considered insane */
    21     for (f = 0; f < 5; f++)
    22         if ((fd = open(device, m, 0600)) >= 0)
     21    for (f = 0; f < 5; f++) {
     22        fd = open(device, m, 0600);
     23        if (fd >= 0)
    2324            break;
     25    }
    2426    if (fd < 0)
    2527        return fd;
  • branches/2.2.9/mindi-busybox/libbb/dump.c

    r1765 r2725  
    55 *
    66 * Copyright (c) 1989
    7  *  The Regents of the University of California.  All rights reserved.
     7 * The Regents of the University of California.  All rights reserved.
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 *
    1111 * Original copyright notice is retained at the end of this file.
     
    1515#include "dump.h"
    1616
    17 enum _vflag bb_dump_vflag = FIRST;
    18 FS *bb_dump_fshead;             /* head of format strings */
    19 static FU *endfu;
    20 static char **_argv;
    21 static off_t savaddress;    /* saved address/offset in stream */
    22 static off_t eaddress;  /* end address */
    23 static off_t address;   /* address/offset in stream */
    24 off_t bb_dump_skip;             /* bytes to skip */
    25 static int exitval;         /* final exit value */
    26 int bb_dump_blocksize;          /* data block size */
    27 int bb_dump_length = -1;        /* max bytes to read */
    28 
    2917static const char index_str[] ALIGN1 = ".#-+ 0123456789";
    3018
     
    3422static const char lcc[] ALIGN1 = "diouxX";
    3523
    36 int bb_dump_size(FS * fs)
     24
     25typedef struct priv_dumper_t {
     26    dumper_t pub;
     27
     28    char **argv;
     29    FU *endfu;
     30    off_t savaddress;        /* saved address/offset in stream */
     31    off_t eaddress;          /* end address */
     32    off_t address;           /* address/offset in stream */
     33    int blocksize;
     34    smallint exitval;        /* final exit value */
     35
     36    /* former statics */
     37    smallint next__done;
     38    smallint get__ateof; // = 1;
     39    unsigned char *get__curp;
     40    unsigned char *get__savp;
     41} priv_dumper_t;
     42
     43dumper_t* FAST_FUNC alloc_dumper(void)
     44{
     45    priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
     46    dumper->pub.dump_length = -1;
     47    dumper->pub.dump_vflag = FIRST;
     48    dumper->get__ateof = 1;
     49    return &dumper->pub;
     50}
     51
     52
     53static NOINLINE int bb_dump_size(FS *fs)
    3754{
    3855    FU *fu;
     
    5269                continue;
    5370            /*
    54              * bb_dump_skip any special chars -- save precision in
     71             * skip any special chars -- save precision in
    5572             * case it's a %s format.
    5673             */
     
    5875            if (*fmt == '.' && isdigit(*++fmt)) {
    5976                prec = atoi(fmt);
    60                 while (isdigit(*++fmt));
    61             }
    62             if (!(p = strchr(size_conv_str + 12, *fmt))) {
     77                while (isdigit(*++fmt))
     78                    continue;
     79            }
     80            p = strchr(size_conv_str + 12, *fmt);
     81            if (!p) {
    6382                if (*fmt == 's') {
    6483                    bcnt += prec;
     
    7897}
    7998
    80 static void rewrite(FS * fs)
     99static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
    81100{
    82101    enum { NOTOKAY, USEBCNT, USEPREC } sokay;
     
    95114        for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
    96115            /* NOSTRICT */
    97             /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
     116            /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/
    98117            pr = xzalloc(sizeof(PR));
    99118            if (!fu->nextpr)
    100119                fu->nextpr = pr;
    101120            /* ignore nextpr -- its unused inside the loop and is
    102              * uninitialized 1st time thru.
     121             * uninitialized 1st time through.
    103122             */
    104123
    105             /* bb_dump_skip preceding text and up to the next % sign */
    106             for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
     124            /* skip preceding text and up to the next % sign */
     125            for (p1 = fmtp; *p1 && *p1 != '%'; ++p1)
     126                continue;
    107127
    108128            /* only text in the string */
     
    119139            if (fu->bcnt) {
    120140                sokay = USEBCNT;
    121                 /* bb_dump_skip to conversion character */
    122                 for (++p1; strchr(index_str, *p1); ++p1);
     141                /* skip to conversion character */
     142                for (++p1; strchr(index_str, *p1); ++p1)
     143                    continue;
    123144            } else {
    124                 /* bb_dump_skip any special chars, field width */
    125                 while (strchr(index_str + 1, *++p1));
     145                /* skip any special chars, field width */
     146                while (strchr(index_str + 1, *++p1))
     147                    continue;
    126148                if (*p1 == '.' && isdigit(*++p1)) {
    127149                    sokay = USEPREC;
    128150                    prec = atoi(p1);
    129                     while (isdigit(*++p1));
     151                    while (isdigit(*++p1))
     152                        continue;
    130153                } else
    131154                    sokay = NOTOKAY;
    132155            }
    133156
    134             p2 = p1 + 1;    /* set end pointer */
     157            p2 = p1 + 1; /* set end pointer */
    135158
    136159            /*
     
    139162             * pbb_dump_adding for end of data.
    140163             */
    141 
    142164            if (*p1 == 'c') {
    143165                pr->flags = F_CHAR;
    144             DO_BYTE_COUNT_1:
     166 DO_BYTE_COUNT_1:
    145167                byte_count_str = "\001";
    146             DO_BYTE_COUNT:
     168 DO_BYTE_COUNT:
    147169                if (fu->bcnt) {
    148170                    do {
     
    160182                ++p2;
    161183                ++p1;
    162             DO_INT_CONV:
     184 DO_INT_CONV:
    163185                {
    164186                    const char *e;
    165                     if (!(e = strchr(lcc, *p1))) {
     187                    e = strchr(lcc, *p1);
     188                    if (!e) {
    166189                        goto DO_BAD_CONV_CHAR;
    167190                    }
     
    186209                } else if (sokay == USEPREC) {
    187210                    pr->bcnt = prec;
    188                 } else {    /* NOTOKAY */
     211                } else {   /* NOTOKAY */
    189212                    bb_error_msg_and_die("%%s requires a precision or a byte count");
    190213                }
     
    193216                switch (p1[1]) {
    194217                case 'A':
    195                     endfu = fu;
     218                    dumper->endfu = fu;
    196219                    fu->flags |= F_IGNORE;
    197220                    /* FALLTHROUGH */
     
    220243                }
    221244            } else {
    222             DO_BAD_CONV_CHAR:
     245 DO_BAD_CONV_CHAR:
    223246                bb_error_msg_and_die("bad conversion character %%%s", p1);
    224247            }
     
    232255            pr->fmt = xstrdup(fmtp);
    233256            *p2 = savech;
    234             pr->cchar = pr->fmt + (p1 - fmtp);
     257            //Too early! xrealloc can move pr->fmt!
     258            //pr->cchar = pr->fmt + (p1 - fmtp);
    235259
    236260            /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
     
    239263             * we lose the " is a HEX number" part of fmt.
    240264             */
    241             for (p3 = p2; *p3 && *p3 != '%'; p3++);
    242             if (p3 > p2)
    243             {
     265            for (p3 = p2; *p3 && *p3 != '%'; p3++)
     266                continue;
     267            if (p3 > p2) {
    244268                savech = *p3;
    245269                *p3 = '\0';
    246                 pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1);
     270                pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt) + (p3-p2) + 1);
    247271                strcat(pr->fmt, p2);
    248272                *p3 = savech;
     
    250274            }
    251275
     276            pr->cchar = pr->fmt + (p1 - fmtp);
    252277            fmtp = p2;
    253278
     
    267292    /*
    268293     * if the format string interprets any data at all, and it's
    269      * not the same as the bb_dump_blocksize, and its last format unit
     294     * not the same as the blocksize, and its last format unit
    270295     * interprets any data at all, and has no iteration count,
    271296     * repeat it as necessary.
     
    274299     * gets output from the last iteration of the format unit.
    275300     */
    276     for (fu = fs->nextfu;; fu = fu->nextfu) {
    277         if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
    278             !(fu->flags & F_SETREP) && fu->bcnt)
    279             fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
     301    for (fu = fs->nextfu; fu; fu = fu->nextfu) {
     302        if (!fu->nextfu && fs->bcnt < dumper->blocksize
     303         && !(fu->flags & F_SETREP) && fu->bcnt
     304        ) {
     305            fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
     306        }
    280307        if (fu->reps > 1) {
    281308            for (pr = fu->nextpr;; pr = pr->nextpr)
     
    292319}
    293320
    294 static void do_skip(const char *fname, int statok)
     321static void do_skip(priv_dumper_t *dumper, const char *fname, int statok)
    295322{
    296323    struct stat sbuf;
    297324
    298325    if (statok) {
    299         if (fstat(STDIN_FILENO, &sbuf)) {
    300             bb_perror_msg_and_die("%s", fname);
    301         }
    302         if ((!(S_ISCHR(sbuf.st_mode) ||
    303                S_ISBLK(sbuf.st_mode) ||
    304                S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
    305             /* If bb_dump_size valid and bb_dump_skip >= size */
    306             bb_dump_skip -= sbuf.st_size;
    307             address += sbuf.st_size;
     326        xfstat(STDIN_FILENO, &sbuf, fname);
     327        if (!(S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode))
     328         && dumper->pub.dump_skip >= sbuf.st_size
     329        ) {
     330            /* If bb_dump_size valid and pub.dump_skip >= size */
     331            dumper->pub.dump_skip -= sbuf.st_size;
     332            dumper->address += sbuf.st_size;
    308333            return;
    309334        }
    310335    }
    311     if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
    312         bb_perror_msg_and_die("%s", fname);
    313     }
    314     savaddress = address += bb_dump_skip;
    315     bb_dump_skip = 0;
    316 }
    317 
    318 static int next(char **argv)
    319 {
    320     static smallint done;
    321 
     336    if (fseek(stdin, dumper->pub.dump_skip, SEEK_SET)) {
     337        bb_simple_perror_msg_and_die(fname);
     338    }
     339    dumper->address += dumper->pub.dump_skip;
     340    dumper->savaddress = dumper->address;
     341    dumper->pub.dump_skip = 0;
     342}
     343
     344static NOINLINE int next(priv_dumper_t *dumper)
     345{
    322346    int statok;
    323347
    324     if (argv) {
    325         _argv = argv;
    326         return 1;
    327     }
    328348    for (;;) {
    329         if (*_argv) {
    330             if (!(freopen(*_argv, "r", stdin))) {
    331                 bb_perror_msg("%s", *_argv);
    332                 exitval = 1;
    333                 ++_argv;
     349        if (*dumper->argv) {
     350            dumper->next__done = statok = 1;
     351            if (!(freopen(*dumper->argv, "r", stdin))) {
     352                bb_simple_perror_msg(*dumper->argv);
     353                dumper->exitval = 1;
     354                ++dumper->argv;
    334355                continue;
    335356            }
    336             done = statok = 1;
    337357        } else {
    338             if (done)
    339                 return 0;
    340             done = 1;
     358            if (dumper->next__done)
     359                return 0; /* no next file */
     360            dumper->next__done = 1;
    341361            statok = 0;
    342362        }
    343         if (bb_dump_skip)
    344             do_skip(statok ? *_argv : "stdin", statok);
    345         if (*_argv)
    346             ++_argv;
    347         if (!bb_dump_skip)
     363        if (dumper->pub.dump_skip)
     364            do_skip(dumper, statok ? *dumper->argv : "stdin", statok);
     365        if (*dumper->argv)
     366            ++dumper->argv;
     367        if (!dumper->pub.dump_skip)
    348368            return 1;
    349369    }
     
    351371}
    352372
    353 static unsigned char *get(void)
    354 {
    355     static smallint ateof = 1;
    356     static unsigned char *curp = NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
    357 
     373static unsigned char *get(priv_dumper_t *dumper)
     374{
    358375    int n;
    359376    int need, nread;
    360     unsigned char *tmpp;
    361 
    362     if (!curp) {
    363         address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
    364         curp = xmalloc(bb_dump_blocksize);
    365         savp = xmalloc(bb_dump_blocksize);
     377    int blocksize = dumper->blocksize;
     378
     379    if (!dumper->get__curp) {
     380        dumper->address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
     381        dumper->get__curp = xmalloc(blocksize);
     382        dumper->get__savp = xzalloc(blocksize); /* need to be initialized */
    366383    } else {
    367         tmpp = curp;
    368         curp = savp;
    369         savp = tmpp;
    370         address = savaddress += bb_dump_blocksize;
    371     }
    372     for (need = bb_dump_blocksize, nread = 0;;) {
     384        unsigned char *tmp = dumper->get__curp;
     385        dumper->get__curp = dumper->get__savp;
     386        dumper->get__savp = tmp;
     387        dumper->savaddress += blocksize;
     388        dumper->address = dumper->savaddress;
     389    }
     390    need = blocksize;
     391    nread = 0;
     392    while (1) {
    373393        /*
    374394         * if read the right number of bytes, or at EOF for one file,
     
    376396         * block and set the end flag.
    377397         */
    378         if (!bb_dump_length || (ateof && !next((char **) NULL))) {
    379             if (need == bb_dump_blocksize) {
     398        if (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) {
     399            if (need == blocksize) {
    380400                return NULL;
    381401            }
    382             if (bb_dump_vflag != ALL && !memcmp(curp, savp, nread)) {
    383                 if (bb_dump_vflag != DUP) {
     402            if (dumper->pub.dump_vflag != ALL && !memcmp(dumper->get__curp, dumper->get__savp, nread)) {
     403                if (dumper->pub.dump_vflag != DUP) {
    384404                    puts("*");
    385405                }
    386406                return NULL;
    387407            }
    388             memset((char *) curp + nread, 0, need);
    389             eaddress = address + nread;
    390             return curp;
    391         }
    392         n = fread((char *) curp + nread, sizeof(unsigned char),
    393                   bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
     408            memset(dumper->get__curp + nread, 0, need);
     409            dumper->eaddress = dumper->address + nread;
     410            return dumper->get__curp;
     411        }
     412        n = fread(dumper->get__curp + nread, sizeof(unsigned char),
     413                dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
    394414        if (!n) {
    395415            if (ferror(stdin)) {
    396                 bb_perror_msg("%s", _argv[-1]);
    397             }
    398             ateof = 1;
     416                bb_simple_perror_msg(dumper->argv[-1]);
     417            }
     418            dumper->get__ateof = 1;
    399419            continue;
    400420        }
    401         ateof = 0;
    402         if (bb_dump_length != -1) {
    403             bb_dump_length -= n;
     421        dumper->get__ateof = 0;
     422        if (dumper->pub.dump_length != -1) {
     423            dumper->pub.dump_length -= n;
    404424        }
    405425        need -= n;
    406426        if (!need) {
    407             if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
    408                 || memcmp(curp, savp, bb_dump_blocksize)) {
    409                 if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
    410                     bb_dump_vflag = WAIT;
    411                 }
    412                 return curp;
    413             }
    414             if (bb_dump_vflag == WAIT) {
     427            if (dumper->pub.dump_vflag == ALL || dumper->pub.dump_vflag == FIRST
     428             || memcmp(dumper->get__curp, dumper->get__savp, blocksize)
     429            ) {
     430                if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) {
     431                    dumper->pub.dump_vflag = WAIT;
     432                }
     433                return dumper->get__curp;
     434            }
     435            if (dumper->pub.dump_vflag == WAIT) {
    415436                puts("*");
    416437            }
    417             bb_dump_vflag = DUP;
    418             address = savaddress += bb_dump_blocksize;
    419             need = bb_dump_blocksize;
     438            dumper->pub.dump_vflag = DUP;
     439            dumper->savaddress += blocksize;
     440            dumper->address = dumper->savaddress;
     441            need = blocksize;
    420442            nread = 0;
    421443        } else {
     
    425447}
    426448
    427 static void bpad(PR * pr)
     449static void bpad(PR *pr)
    428450{
    429451    char *p1, *p2;
     
    435457    pr->flags = F_BPAD;
    436458    *pr->cchar = 's';
    437     for (p1 = pr->fmt; *p1 != '%'; ++p1);
     459    for (p1 = pr->fmt; *p1 != '%'; ++p1)
     460        continue;
    438461    for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
    439         if (pr->nospace) pr->nospace--;
    440     while ((*p2++ = *p1++) != 0);
     462        if (pr->nospace)
     463            pr->nospace--;
     464    while ((*p2++ = *p1++) != 0)
     465        continue;
    441466}
    442467
    443468static const char conv_str[] ALIGN1 =
    444469    "\0\\0\0"
    445     "\007\\a\0"             /* \a */
     470    "\007\\a\0"  /* \a */
    446471    "\b\\b\0"
    447472    "\f\\b\0"
     
    453478
    454479
    455 static void conv_c(PR * pr, unsigned char * p)
     480static void conv_c(PR *pr, unsigned char *p)
    456481{
    457482    const char *str = conv_str;
     
    466491    } while (*str);
    467492
    468     if (isprint(*p)) {
     493    if (isprint_asciionly(*p)) {
    469494        *pr->cchar = 'c';
    470         (void) printf(pr->fmt, *p);
     495        printf(pr->fmt, *p);
    471496    } else {
    472497        sprintf(buf, "%03o", (int) *p);
    473498        str = buf;
    474       strpr:
     499 strpr:
    475500        *pr->cchar = 's';
    476501        printf(pr->fmt, str);
     
    478503}
    479504
    480 static void conv_u(PR * pr, unsigned char * p)
     505static void conv_u(PR *pr, unsigned char *p)
    481506{
    482507    static const char list[] ALIGN1 =
     
    493518        *pr->cchar = 's';
    494519        printf(pr->fmt, "del");
    495     } else if (isprint(*p)) {
     520    } else if (*p < 0x7f) { /* isprint() */
    496521        *pr->cchar = 'c';
    497522        printf(pr->fmt, *p);
     
    502527}
    503528
    504 static void display(void)
    505 {
    506 /*  extern FU *endfu; */
     529static void display(priv_dumper_t* dumper)
     530{
    507531    FS *fs;
    508532    FU *fu;
    509533    PR *pr;
    510534    int cnt;
    511     unsigned char *bp;
    512 
     535    unsigned char *bp, *savebp;
    513536    off_t saveaddress;
    514     unsigned char savech = 0, *savebp;
    515 
    516     while ((bp = get()) != NULL) {
    517         for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
    518              fs = fs->nextfs, bp = savebp, address = saveaddress) {
     537    unsigned char savech = '\0';
     538
     539    while ((bp = get(dumper)) != NULL) {
     540        fs = dumper->pub.fshead;
     541        savebp = bp;
     542        saveaddress = dumper->address;
     543        for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) {
    519544            for (fu = fs->nextfu; fu; fu = fu->nextfu) {
    520545                if (fu->flags & F_IGNORE) {
     
    522547                }
    523548                for (cnt = fu->reps; cnt; --cnt) {
    524                     for (pr = fu->nextpr; pr; address += pr->bcnt,
    525                          bp += pr->bcnt, pr = pr->nextpr) {
    526                         if (eaddress && address >= eaddress &&
    527                             !(pr->flags & (F_TEXT | F_BPAD))) {
     549                    for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
     550                                bp += pr->bcnt, pr = pr->nextpr) {
     551                        if (dumper->eaddress && dumper->address >= dumper->eaddress
     552                         && !(pr->flags & (F_TEXT | F_BPAD))
     553                        ) {
    528554                            bpad(pr);
    529555                        }
     
    535561                        switch (pr->flags) {
    536562                        case F_ADDRESS:
    537                             printf(pr->fmt, (unsigned int) address);
     563                            printf(pr->fmt, (unsigned) dumper->address);
    538564                            break;
    539565                        case F_BPAD:
     
    546572                            printf(pr->fmt, *bp);
    547573                            break;
    548                         case F_DBL:{
     574                        case F_DBL: {
    549575                            double dval;
    550576                            float fval;
     
    552578                            switch (pr->bcnt) {
    553579                            case 4:
    554                                 memmove((char *) &fval, (char *) bp,
    555                                       sizeof(fval));
     580                                memcpy(&fval, bp, sizeof(fval));
    556581                                printf(pr->fmt, fval);
    557582                                break;
    558583                            case 8:
    559                                 memmove((char *) &dval, (char *) bp,
    560                                       sizeof(dval));
     584                                memcpy(&dval, bp, sizeof(dval));
    561585                                printf(pr->fmt, dval);
    562586                                break;
     
    564588                            break;
    565589                        }
    566                         case F_INT:{
     590                        case F_INT: {
    567591                            int ival;
    568592                            short sval;
     
    573597                                break;
    574598                            case 2:
    575                                 memmove((char *) &sval, (char *) bp,
    576                                       sizeof(sval));
     599                                memcpy(&sval, bp, sizeof(sval));
    577600                                printf(pr->fmt, (int) sval);
    578601                                break;
    579602                            case 4:
    580                                 memmove((char *) &ival, (char *) bp,
    581                                       sizeof(ival));
     603                                memcpy(&ival, bp, sizeof(ival));
    582604                                printf(pr->fmt, ival);
    583605                                break;
     
    586608                        }
    587609                        case F_P:
    588                             printf(pr->fmt, isprint(*bp) ? *bp : '.');
     610                            printf(pr->fmt, isprint_asciionly(*bp) ? *bp : '.');
    589611                            break;
    590612                        case F_STR:
     
    597619                            conv_u(pr, bp);
    598620                            break;
    599                         case F_UINT:{
    600                             unsigned int ival;
     621                        case F_UINT: {
     622                            unsigned ival;
    601623                            unsigned short sval;
    602624
    603625                            switch (pr->bcnt) {
    604626                            case 1:
    605                                 printf(pr->fmt, (unsigned int) * bp);
     627                                printf(pr->fmt, (unsigned) *bp);
    606628                                break;
    607629                            case 2:
    608                                 memmove((char *) &sval, (char *) bp,
    609                                       sizeof(sval));
    610                                 printf(pr->fmt, (unsigned int) sval);
     630                                memcpy(&sval, bp, sizeof(sval));
     631                                printf(pr->fmt, (unsigned) sval);
    611632                                break;
    612633                            case 4:
    613                                 memmove((char *) &ival, (char *) bp,
    614                                       sizeof(ival));
     634                                memcpy(&ival, bp, sizeof(ival));
    615635                                printf(pr->fmt, ival);
    616636                                break;
     
    627647        }
    628648    }
    629     if (endfu) {
     649    if (dumper->endfu) {
    630650        /*
    631          * if eaddress not set, error or file bb_dump_size was multiple of
    632          * bb_dump_blocksize, and no partial block ever found.
     651         * if eaddress not set, error or file size was multiple
     652         * of blocksize, and no partial block ever found.
    633653         */
    634         if (!eaddress) {
    635             if (!address) {
     654        if (!dumper->eaddress) {
     655            if (!dumper->address) {
    636656                return;
    637657            }
    638             eaddress = address;
    639         }
    640         for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
     658            dumper->eaddress = dumper->address;
     659        }
     660        for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) {
    641661            switch (pr->flags) {
    642662            case F_ADDRESS:
    643                 (void) printf(pr->fmt, (unsigned int) eaddress);
     663                printf(pr->fmt, (unsigned) dumper->eaddress);
    644664                break;
    645665            case F_TEXT:
    646                 (void) printf(pr->fmt);
     666                printf(pr->fmt);
    647667                break;
    648668            }
     
    651671}
    652672
    653 int bb_dump_dump(char **argv)
     673#define dumper ((priv_dumper_t*)pub_dumper)
     674int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv)
    654675{
    655676    FS *tfs;
     677    int blocksize;
    656678
    657679    /* figure out the data block bb_dump_size */
    658     for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
     680    blocksize = 0;
     681    tfs = dumper->pub.fshead;
     682    while (tfs) {
    659683        tfs->bcnt = bb_dump_size(tfs);
    660         if (bb_dump_blocksize < tfs->bcnt) {
    661             bb_dump_blocksize = tfs->bcnt;
    662         }
    663     }
     684        if (blocksize < tfs->bcnt) {
     685            blocksize = tfs->bcnt;
     686        }
     687        tfs = tfs->nextfs;
     688    }
     689    dumper->blocksize = blocksize;
     690
    664691    /* rewrite the rules, do syntax checking */
    665     for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
    666         rewrite(tfs);
    667     }
    668 
    669     next(argv);
    670     display();
    671 
    672     return exitval;
    673 }
    674 
    675 void bb_dump_add(const char *fmt)
     692    for (tfs = dumper->pub.fshead; tfs; tfs = tfs->nextfs) {
     693        rewrite(dumper, tfs);
     694    }
     695
     696    dumper->argv = argv;
     697    display(dumper);
     698
     699    return dumper->exitval;
     700}
     701
     702void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
    676703{
    677704    const char *p;
    678705    char *p1;
    679706    char *p2;
    680     static FS **nextfs;
    681707    FS *tfs;
    682     FU *tfu, **nextfu;
     708    FU *tfu, **nextfupp;
    683709    const char *savep;
    684710
    685711    /* start new linked list of format units */
    686712    tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
    687     if (!bb_dump_fshead) {
    688         bb_dump_fshead = tfs;
     713    if (!dumper->pub.fshead) {
     714        dumper->pub.fshead = tfs;
    689715    } else {
    690         *nextfs = tfs;
    691     }
    692     nextfs = &tfs->nextfs;
    693     nextfu = &tfs->nextfu;
     716        FS *fslast = dumper->pub.fshead;
     717        while (fslast->nextfs)
     718            fslast = fslast->nextfs;
     719        fslast->nextfs = tfs;
     720    }
     721    nextfupp = &tfs->nextfu;
    694722
    695723    /* take the format string and break it up into format units */
    696     for (p = fmt;;) {
    697         /* bb_dump_skip leading white space */
     724    p = fmt;
     725    for (;;) {
    698726        p = skip_whitespace(p);
    699727        if (!*p) {
     
    703731        /* allocate a new format unit and link it in */
    704732        /* NOSTRICT */
    705         /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
     733        /* DBU:[dave@cray.com] zalloc so that forward pointers start out NULL */
    706734        tfu = xzalloc(sizeof(FU));
    707         *nextfu = tfu;
    708         nextfu = &tfu->nextfu;
     735        *nextfupp = tfu;
     736        nextfupp = &tfu->nextfu;
    709737        tfu->reps = 1;
    710738
    711739        /* if leading digit, repetition count */
    712740        if (isdigit(*p)) {
    713             for (savep = p; isdigit(*p); ++p);
     741            for (savep = p; isdigit(*p); ++p)
     742                continue;
    714743            if (!isspace(*p) && *p != '/') {
    715744                bb_error_msg_and_die("bad format {%s}", fmt);
     
    718747            tfu->reps = atoi(savep);
    719748            tfu->flags = F_SETREP;
    720             /* bb_dump_skip trailing white space */
     749            /* skip trailing white space */
    721750            p = skip_whitespace(++p);
    722751        }
    723752
    724         /* bb_dump_skip slash and trailing white space */
     753        /* skip slash and trailing white space */
    725754        if (*p == '/') {
    726755            p = skip_whitespace(++p);
     
    731760// TODO: use bb_strtou
    732761            savep = p;
    733             do p++; while (isdigit(*p));
     762            while (isdigit(*++p))
     763                continue;
    734764            if (!isspace(*p)) {
    735765                bb_error_msg_and_die("bad format {%s}", fmt);
    736766            }
    737767            tfu->bcnt = atoi(savep);
    738             /* bb_dump_skip trailing white space */
     768            /* skip trailing white space */
    739769            p = skip_whitespace(++p);
    740770        }
     
    749779            }
    750780        }
    751         tfu->fmt = xmalloc(p - savep + 1);
    752         strncpy(tfu->fmt, savep, p - savep);
    753         tfu->fmt[p - savep] = '\0';
     781        tfu->fmt = xstrndup(savep, p - savep);
    754782/*      escape(tfu->fmt); */
    755783
  • branches/2.2.9/mindi-busybox/libbb/execable.c

    r1765 r2725  
    55 * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1414 * return 0 otherwise;
    1515 */
    16 int execable_file(const char *name)
     16int FAST_FUNC execable_file(const char *name)
    1717{
    1818    struct stat s;
     
    2020}
    2121
    22 /* search $PATH for an executable file;
     22/* search (*PATHp) for an executable file;
    2323 * return allocated string containing full path if found;
    24  * return NULL otherwise;
     24 *  PATHp points to the component after the one where it was found
     25 *  (or NULL),
     26 *  you may call find_execable again with this PATHp to continue
     27 *  (if it's not NULL).
     28 * return NULL otherwise; (PATHp is undefined)
     29 * in all cases (*PATHp) contents will be trashed (s/:/NUL/).
    2530 */
    26 char *find_execable(const char *filename)
     31char* FAST_FUNC find_execable(const char *filename, char **PATHp)
    2732{
    28     char *path, *p, *n;
     33    char *p, *n;
    2934
    30     p = path = xstrdup(getenv("PATH"));
     35    p = *PATHp;
    3136    while (p) {
    3237        n = strchr(p, ':');
     
    3641            p = concat_path_file(p, filename);
    3742            if (execable_file(p)) {
    38                 free(path);
     43                *PATHp = n;
    3944                return p;
    4045            }
     
    4247        }
    4348        p = n;
    44     }
    45     free(path);
    46     return NULL;
     49    } /* on loop exit p == NULL */
     50    return p;
    4751}
    4852
     
    5155 * return 0 otherwise;
    5256 */
    53 int exists_execable(const char *filename)
     57int FAST_FUNC exists_execable(const char *filename)
    5458{
    55     char *ret = find_execable(filename);
     59    char *path = xstrdup(getenv("PATH"));
     60    char *tmp = path;
     61    char *ret = find_execable(filename, &tmp);
     62    free(path);
    5663    if (ret) {
    5764        free(ret);
     
    6471/* just like the real execvp, but try to launch an applet named 'file' first
    6572 */
    66 int bb_execvp(const char *file, char *const argv[])
     73int FAST_FUNC bb_execvp(const char *file, char *const argv[])
    6774{
    68     return execvp(find_applet_by_name(file) ? bb_busybox_exec_path : file,
     75    return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file,
    6976                    argv);
    7077}
    7178#endif
     79
     80int FAST_FUNC BB_EXECVP_or_die(char **argv)
     81{
     82    BB_EXECVP(argv[0], argv);
     83    /* SUSv3-mandated exit codes */
     84    xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
     85    bb_perror_msg_and_die("can't execute '%s'", argv[0]);
     86}
  • branches/2.2.9/mindi-busybox/libbb/fclose_nonstdin.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1515#include "libbb.h"
    1616
    17 int fclose_if_not_stdin(FILE *f)
     17int FAST_FUNC fclose_if_not_stdin(FILE *f)
    1818{
    19     if (f != stdin) {
    20         return fclose(f);
    21     }
    22     return 0;
     19    /* Some more paranoid applets want ferror() check too */
     20    int r = ferror(f); /* NB: does NOT set errno! */
     21    if (r) errno = EIO; /* so we'll help it */
     22    if (f != stdin)
     23        return (r | fclose(f)); /* fclose does set errno on error */
     24    return r;
    2325}
  • branches/2.2.9/mindi-busybox/libbb/fflush_stdout_and_exit.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1414#include "libbb.h"
    1515
    16 void fflush_stdout_and_exit(int retval)
     16void FAST_FUNC fflush_stdout_and_exit(int retval)
    1717{
    1818    if (fflush(stdout))
  • branches/2.2.9/mindi-busybox/libbb/fgets_str.c

    r1765 r2725  
    66 * If you wrote this, please acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
    1111#include "libbb.h"
    1212
    13 /* Read up to (and including) TERMINATING_STRING from FILE and return it.
    14  * Return NULL on EOF.  */
    15 
    16 char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
     13static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off, size_t *maxsz_p)
    1714{
    1815    char *linebuf = NULL;
     
    2219    int idx = 0;
    2320    int ch;
     21    size_t maxsz = *maxsz_p;
    2422
    2523    while (1) {
    2624        ch = fgetc(file);
    2725        if (ch == EOF) {
    28             free(linebuf);
    29             return NULL;
     26            if (idx == 0)
     27                return linebuf; /* NULL */
     28            break;
    3029        }
    3130
    32         /* grow the line buffer as necessary */
    33         while (idx > linebufsz - 2) {
     31        if (idx >= linebufsz) {
    3432            linebufsz += 200;
    3533            linebuf = xrealloc(linebuf, linebufsz);
     34            if (idx >= maxsz) {
     35                linebuf[idx] = ch;
     36                idx++;
     37                break;
     38            }
    3639        }
    3740
     
    4144        /* Check for terminating string */
    4245        end_string_offset = idx - term_length;
    43         if (end_string_offset > 0
     46        if (end_string_offset >= 0
    4447         && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
    4548        ) {
    46             idx -= term_length;
     49            if (chop_off)
     50                idx -= term_length;
    4751            break;
    4852        }
    4953    }
     54    /* Grow/shrink *first*, then store NUL */
    5055    linebuf = xrealloc(linebuf, idx + 1);
    5156    linebuf[idx] = '\0';
     57    *maxsz_p = idx;
    5258    return linebuf;
    5359}
     60
     61/* Read up to TERMINATING_STRING from FILE and return it,
     62 * including terminating string.
     63 * Non-terminated string can be returned if EOF is reached.
     64 * Return NULL if EOF is reached immediately.  */
     65char* FAST_FUNC xmalloc_fgets_str(FILE *file, const char *terminating_string)
     66{
     67    size_t maxsz = INT_MAX - 4095;
     68    return xmalloc_fgets_internal(file, terminating_string, 0, &maxsz);
     69}
     70
     71char* FAST_FUNC xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p)
     72{
     73    size_t maxsz;
     74
     75    if (!maxsz_p) {
     76        maxsz = INT_MAX - 4095;
     77        maxsz_p = &maxsz;
     78    }
     79    return xmalloc_fgets_internal(file, terminating_string, 0, maxsz_p);
     80}
     81
     82char* FAST_FUNC xmalloc_fgetline_str(FILE *file, const char *terminating_string)
     83{
     84    size_t maxsz = INT_MAX - 4095;
     85    return xmalloc_fgets_internal(file, terminating_string, 1, &maxsz);
     86}
  • branches/2.2.9/mindi-busybox/libbb/find_mount_point.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1818 * filesystem.
    1919 */
    20 struct mntent *find_mount_point(const char *name, const char *table)
     20struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
    2121{
    2222    struct stat s;
    23     dev_t mountDevice;
    24     FILE *mountTable;
     23    FILE *mtab_fp;
    2524    struct mntent *mountEntry;
     25    dev_t devno_of_name;
     26    bool block_dev;
    2627
    2728    if (stat(name, &s) != 0)
    28         return 0;
     29        return NULL;
    2930
    30     if ((s.st_mode & S_IFMT) == S_IFBLK)
    31         mountDevice = s.st_rdev;
    32     else
    33         mountDevice = s.st_dev;
     31    devno_of_name = s.st_dev;
     32    block_dev = 0;
     33    if (S_ISBLK(s.st_mode)) {
     34        devno_of_name = s.st_rdev;
     35        block_dev = 1;
     36    }
    3437
     38    mtab_fp = setmntent(bb_path_mtab_file, "r");
     39    if (!mtab_fp)
     40        return NULL;
    3541
    36     mountTable = setmntent(table ? table : bb_path_mtab_file, "r");
    37     if (!mountTable)
    38         return 0;
     42    while ((mountEntry = getmntent(mtab_fp)) != NULL) {
     43        /* rootfs mount in Linux 2.6 exists always,
     44         * and it makes sense to always ignore it.
     45         * Otherwise people can't reference their "real" root! */
     46        if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
     47            continue;
    3948
    40     while ((mountEntry = getmntent(mountTable)) != 0) {
    4149        if (strcmp(name, mountEntry->mnt_dir) == 0
    4250         || strcmp(name, mountEntry->mnt_fsname) == 0
     
    4452            break;
    4553        }
    46         if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice)  /* Match the device. */
     54
     55        if (!(subdir_too || block_dev))
     56            continue;
     57
     58        /* Is device's dev_t == name's dev_t? */
     59        if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == devno_of_name)
    4760            break;
    48         if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice)  /* Match the directory's mount point. */
     61        /* Match the directory's mount point. */
     62        if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == devno_of_name)
    4963            break;
    5064    }
    51     endmntent(mountTable);
     65    endmntent(mtab_fp);
     66
    5267    return mountEntry;
    5368}
  • branches/2.2.9/mindi-busybox/libbb/find_pid_by_name.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    3939*/
    4040
    41 /* find_pid_by_name()
     41static int comm_match(procps_status_t *p, const char *procName)
     42{
     43    int argv1idx;
     44    const char *argv1;
     45
     46    if (strncmp(p->comm, procName, 15) != 0)
     47        return 0; /* comm does not match */
     48
     49    /* In Linux, if comm is 15 chars, it is truncated.
     50     * (or maybe the name was exactly 15 chars, but there is
     51     * no way to know that) */
     52    if (p->comm[14] == '\0')
     53        return 1; /* comm is not truncated - matches */
     54
     55    /* comm is truncated, but first 15 chars match.
     56     * This can be crazily_long_script_name.sh!
     57     * The telltale sign is basename(argv[1]) == procName */
     58
     59    if (!p->argv0)
     60        return 0;
     61
     62    argv1idx = strlen(p->argv0) + 1;
     63    if (argv1idx >= p->argv_len)
     64        return 0;
     65    argv1 = p->argv0 + argv1idx;
     66
     67    if (strcmp(bb_basename(argv1), procName) != 0)
     68        return 0;
     69
     70    return 1;
     71}
     72
     73/* This finds the pid of the specified process.
     74 * Currently, it's implemented by rummaging through
     75 * the proc filesystem.
    4276 *
    43  *  Modified by Vladimir Oleynik for use with libbb/procps.c
    44  *  This finds the pid of the specified process.
    45  *  Currently, it's implemented by rummaging through
    46  *  the proc filesystem.
     77 * Returns a list of all matching PIDs
     78 * It is the caller's duty to free the returned pidlist.
    4779 *
    48  *  Returns a list of all matching PIDs
    49  *  It is the caller's duty to free the returned pidlist.
     80 * Modified by Vladimir Oleynik for use with libbb/procps.c
    5081 */
    51 pid_t* find_pid_by_name(const char* procName)
     82pid_t* FAST_FUNC find_pid_by_name(const char *procName)
    5283{
    5384    pid_t* pidList;
     
    5586    procps_status_t* p = NULL;
    5687
    57     pidList = xmalloc(sizeof(*pidList));
    58     while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGV0))) {
    59         if (
    60         /* we require comm to match and to not be truncated */
    61         /* in Linux, if comm is 15 chars, it may be a truncated
    62          * name, so we don't allow that to match */
    63             (!p->comm[sizeof(p->comm)-2] && strcmp(p->comm, procName) == 0)
     88    pidList = xzalloc(sizeof(*pidList));
     89    while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) {
     90        if (comm_match(p, procName)
    6491        /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
    6592         || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
    66         /* TOOD: we can also try exe, do we want that? */
     93        /* or we require /proc/PID/exe link to match */
     94         || (p->exe && strcmp(bb_basename(p->exe), procName) == 0)
    6795        ) {
    68             pidList = xrealloc(pidList, sizeof(*pidList) * (i+2));
     96            pidList = xrealloc_vector(pidList, 2, i);
    6997            pidList[i++] = p->pid;
    7098        }
     
    75103}
    76104
    77 pid_t *pidlist_reverse(pid_t *pidList)
     105pid_t* FAST_FUNC pidlist_reverse(pid_t *pidList)
    78106{
    79107    int i = 0;
  • branches/2.2.9/mindi-busybox/libbb/find_root_device.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    6363}
    6464
    65 char *find_block_device(const char *path)
     65char* FAST_FUNC find_block_device(const char *path)
    6666{
    6767    struct arena a;
  • branches/2.2.9/mindi-busybox/libbb/full_write.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1515 * Returns the amount written, or -1 on an error.
    1616 */
    17 ssize_t full_write(int fd, const void *buf, size_t len)
     17ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
    1818{
    1919    ssize_t cc;
     
    2525        cc = safe_write(fd, buf, len);
    2626
    27         if (cc < 0)
    28             return cc;  /* write() returns -1 on failure. */
     27        if (cc < 0) {
     28            if (total) {
     29                /* we already wrote some! */
     30                /* user can do another write to know the error code */
     31                return total;
     32            }
     33            return cc;  /* write() returns -1 on failure. */
     34        }
    2935
    3036        total += cc;
  • branches/2.2.9/mindi-busybox/libbb/get_console.c

    r1765 r2725  
    66 * acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
    11 //#include <sys/ioctl.h>
    1211#include "libbb.h"
    13 
    1412
    1513/* From <linux/kd.h> */
    1614enum { KDGKBTYPE = 0x4B33 };  /* get keyboard type */
    17 
    1815
    1916static int open_a_console(const char *fnam)
     
    4037 * if someone else used X (which does a chown on /dev/console).
    4138 */
    42 
    43 int get_console_fd(void)
     39int FAST_FUNC get_console_fd_or_die(void)
    4440{
    4541    static const char *const console_names[] = {
     
    6864    }
    6965
    70     bb_error_msg("cannot get file descriptor referring to console");
    71     return fd;                      /* total failure */
     66    bb_error_msg_and_die("can't open console");
     67    /*return fd; - total failure */
    7268}
     69
     70/* From <linux/vt.h> */
     71enum {
     72    VT_ACTIVATE = 0x5606,   /* make vt active */
     73    VT_WAITACTIVE = 0x5607  /* wait for vt active */
     74};
     75
     76void FAST_FUNC console_make_active(int fd, const int vt_num)
     77{
     78    xioctl(fd, VT_ACTIVATE, (void *)(ptrdiff_t)vt_num);
     79    xioctl(fd, VT_WAITACTIVE, (void *)(ptrdiff_t)vt_num);
     80}
  • branches/2.2.9/mindi-busybox/libbb/get_last_path_component.c

    r1765 r2725  
    55 * Copyright (C) 2001  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
     11/*
     12 * "/"        -> "/"
     13 * "abc"      -> "abc"
     14 * "abc/def"  -> "def"
     15 * "abc/def/" -> ""
     16 */
     17char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
     18{
     19    char *slash = strrchr(path, '/');
    1120
    12 char *bb_get_last_path_component(char *path)
     21    if (!slash || (slash == path && !slash[1]))
     22        return (char*)path;
     23
     24    return slash + 1;
     25}
     26
     27/*
     28 * "/"        -> "/"
     29 * "abc"      -> "abc"
     30 * "abc/def"  -> "def"
     31 * "abc/def/" -> "def" !!
     32 */
     33char* FAST_FUNC bb_get_last_path_component_strip(char *path)
    1334{
    14     char *first = path;
    15     char *last;
     35    char *slash = last_char_is(path, '/');
    1636
    17     last = path - 1;
     37    if (slash)
     38        while (*slash == '/' && slash != path)
     39            *slash-- = '\0';
    1840
    19     while (*path) {
    20         if ((*path != '/') && (path > ++last)) {
    21             last = first = path;
    22         }
    23         ++path;
    24     }
    25 
    26     if (*first == '/') {
    27         last = first;
    28     }
    29     last[1] = '\0';
    30 
    31     return first;
     41    return bb_get_last_path_component_nostrip(path);
    3242}
  • branches/2.2.9/mindi-busybox/libbb/get_line_from_file.c

    r1765 r2725  
    77 * Copyright (C) 2001 Matt Krai
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 */
    1111
     
    1313
    1414/* This function reads an entire line from a text file, up to a newline
    15  * or NUL byte, inclusive.  It returns a malloc'ed char * which must be
    16  * stored and free'ed by the caller.  If end is NULL '\n' isn't considered
    17  * end of line.  If end isn't NULL, length of the chunk read is stored in it.
    18  * Return NULL if EOF/error */
    19 
    20 char *bb_get_chunk_from_file(FILE *file, int *end)
     15 * or NUL byte, inclusive.  It returns a malloc'ed char * which
     16 * must be free'ed by the caller.  If end is NULL '\n' isn't considered
     17 * end of line.  If end isn't NULL, length of the chunk is stored in it.
     18 * If lineno is not NULL, *lineno is incremented for each line,
     19 * and also trailing '\' is recognized as line continuation.
     20 *
     21 * Returns NULL if EOF/error. */
     22char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno)
    2123{
    2224    int ch;
     
    2830        /* grow the line buffer as necessary */
    2931        if (idx >= linebufsz) {
    30             linebufsz += 80;
     32            linebufsz += 256;
    3133            linebuf = xrealloc(linebuf, linebufsz);
    3234        }
    3335        linebuf[idx++] = (char) ch;
    34         if (!ch || (end && ch == '\n'))
     36        if (!ch)
    3537            break;
     38        if (end && ch == '\n') {
     39            if (lineno == NULL)
     40                break;
     41            (*lineno)++;
     42            if (idx < 2 || linebuf[idx-2] != '\\')
     43                break;
     44            idx -= 2;
     45        }
    3646    }
    3747    if (end)
     
    4454        //  return NULL;
    4555        //}
    46         linebuf = xrealloc(linebuf, idx+1);
     56        linebuf = xrealloc(linebuf, idx + 1);
    4757        linebuf[idx] = '\0';
    4858    }
     
    5060}
    5161
     62char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
     63{
     64    return bb_get_chunk_with_continuation(file, end, NULL);
     65}
     66
    5267/* Get line, including trailing \n if any */
    53 char *xmalloc_fgets(FILE *file)
     68char* FAST_FUNC xmalloc_fgets(FILE *file)
    5469{
    5570    int i;
     
    5772    return bb_get_chunk_from_file(file, &i);
    5873}
    59 
    6074/* Get line.  Remove trailing \n */
    61 char *xmalloc_getline(FILE *file)
     75char* FAST_FUNC xmalloc_fgetline(FILE *file)
    6276{
    6377    int i;
     
    6983    return c;
    7084}
     85
     86#if 0
     87/* GNUism getline() should be faster (not tested) than a loop with fgetc */
     88
     89/* Get line, including trailing \n if any */
     90char* FAST_FUNC xmalloc_fgets(FILE *file)
     91{
     92    char *res_buf = NULL;
     93    size_t res_sz;
     94
     95    if (getline(&res_buf, &res_sz, file) == -1) {
     96        free(res_buf); /* uclibc allocates a buffer even on EOF. WTF? */
     97        res_buf = NULL;
     98    }
     99//TODO: trimming to res_sz?
     100    return res_buf;
     101}
     102/* Get line.  Remove trailing \n */
     103char* FAST_FUNC xmalloc_fgetline(FILE *file)
     104{
     105    char *res_buf = NULL;
     106    size_t res_sz;
     107
     108    res_sz = getline(&res_buf, &res_sz, file);
     109
     110    if ((ssize_t)res_sz != -1) {
     111        if (res_buf[res_sz - 1] == '\n')
     112            res_buf[--res_sz] = '\0';
     113//TODO: trimming to res_sz?
     114    } else {
     115        free(res_buf); /* uclibc allocates a buffer even on EOF. WTF? */
     116        res_buf = NULL;
     117    }
     118    return res_buf;
     119}
     120
     121#endif
     122
     123#if 0
     124/* Faster routines (~twice as fast). +170 bytes. Unused as of 2008-07.
     125 *
     126 * NB: they stop at NUL byte too.
     127 * Performance is important here. Think "grep 50gigabyte_file"...
     128 * Ironically, grep can't use it because of NUL issue.
     129 * We sorely need C lib to provide fgets which reports size!
     130 *
     131 * Update:
     132 * Actually, uclibc and glibc have it. man getline. It's GNUism,
     133 *   but very useful one (if it's as fast as this code).
     134 * TODO:
     135 * - currently, sed and sort use bb_get_chunk_from_file and heavily
     136 *   depend on its "stop on \n or \0" behavior, and STILL they fail
     137 *   to handle all cases with embedded NULs correctly. So:
     138 * - audit sed and sort; convert them to getline FIRST.
     139 * - THEN ditch bb_get_chunk_from_file, replace it with getline.
     140 * - provide getline implementation for non-GNU systems.
     141 */
     142
     143static char* xmalloc_fgets_internal(FILE *file, int *sizep)
     144{
     145    int len;
     146    int idx = 0;
     147    char *linebuf = NULL;
     148
     149    while (1) {
     150        char *r;
     151
     152        linebuf = xrealloc(linebuf, idx + 0x100);
     153        r = fgets(&linebuf[idx], 0x100, file);
     154        if (!r) {
     155            /* need to terminate in case this is error
     156             * (EOF puts NUL itself) */
     157            linebuf[idx] = '\0';
     158            break;
     159        }
     160        /* stupid. fgets knows the len, it should report it somehow */
     161        len = strlen(&linebuf[idx]);
     162        idx += len;
     163        if (len != 0xff || linebuf[idx - 1] == '\n')
     164            break;
     165    }
     166    *sizep = idx;
     167    if (idx) {
     168        /* xrealloc(linebuf, idx + 1) is up to caller */
     169        return linebuf;
     170    }
     171    free(linebuf);
     172    return NULL;
     173}
     174
     175/* Get line, remove trailing \n */
     176char* FAST_FUNC xmalloc_fgetline_fast(FILE *file)
     177{
     178    int sz;
     179    char *r = xmalloc_fgets_internal(file, &sz);
     180    if (r && r[sz - 1] == '\n')
     181        r[--sz] = '\0';
     182    return r; /* not xrealloc(r, sz + 1)! */
     183}
     184
     185char* FAST_FUNC xmalloc_fgets(FILE *file)
     186{
     187    int sz;
     188    return xmalloc_fgets_internal(file, &sz);
     189}
     190
     191/* Get line, remove trailing \n */
     192char* FAST_FUNC xmalloc_fgetline(FILE *file)
     193{
     194    int sz;
     195    char *r = xmalloc_fgets_internal(file, &sz);
     196    if (!r)
     197        return r;
     198    if (r[sz - 1] == '\n')
     199        r[--sz] = '\0';
     200    return xrealloc(r, sz + 1);
     201}
     202#endif
  • branches/2.2.9/mindi-busybox/libbb/getopt32.c

    r1765 r2725  
    55 * Copyright (C) 2003-2005  Vladimir Oleynik  <dzo@simtreas.ru>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    3131        "r" will add 1    (bit 0)
    3232        "n" will add 2    (bit 1)
    33         "u  will add 4    (bit 2)
     33        "u" will add 4    (bit 2)
    3434        "g" will add 8    (bit 3)
    3535
     
    7373        Here we want env to process just the '-i', not the '-d'.
    7474
     75 "!"    Report bad option, missing required options,
     76        inconsistent options with all-ones return value (instead of abort).
     77
    7578const char *applet_long_options
    7679
     
    113116
    114117 "ww"   Adjacent double options have a counter associated which indicates
    115         the number of occurences of the option.
     118        the number of occurrences of the option.
    116119        For example the ps applet needs:
    117120        if w is given once, GNU ps sets the width to 132,
    118121        if w is given more than once, it is "unlimited"
    119122
    120         int w_counter = 0;
     123        int w_counter = 0; // must be initialized!
    121124        opt_complementary = "ww";
    122125        getopt32(argv, "w", &w_counter);
     
    138141        f = getopt32(argv, "vb:c", &my_b, &verbose_level);
    139142        if (f & 2)       // -c after -b unsets -b flag
    140                 while (my_b) { dosomething_with(my_b->data); my_b = my_b->link; }
     143                while (my_b) dosomething_with(llist_pop(&my_b));
    141144        if (my_b)        // but llist is stored if -b is specified
    142145                free_llist(my_b);
     
    145148Special characters:
    146149
    147  "-"    A dash as the first char in a opt_complementary group forces
    148         all arguments to be treated as options, even if they have
    149         no leading dashes. Next char in this case can't be a digit (0-9),
    150         use ':' or end of line. For example:
    151 
    152         opt_complementary = "-:w-x:x-w";
    153         getopt32(argv, "wx");
    154 
    155         Allows any arguments to be given without a dash (./program w x)
     150 "-"    A group consisting of just a dash forces all arguments
     151        to be treated as options, even if they have no leading dashes.
     152        Next char in this case can't be a digit (0-9), use ':' or end of line.
     153        Example:
     154
     155        opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work,
     156        getopt32(argv, "wx");            // but is less readable
     157
     158        This makes it possible to use options without a dash (./program w x)
    156159        as well as with a dash (./program -x).
     160
     161        NB: getopt32() will leak a small amount of memory if you use
     162        this option! Do not use it if there is a possibility of recursive
     163        getopt32() calls.
    157164
    158165 "--"   A double dash at the beginning of opt_complementary means the
     
    162169        tar xvf foo.tar
    163170
     171        NB: getopt32() will leak a small amount of memory if you use
     172        this option! Do not use it if there is a possibility of recursive
     173        getopt32() calls.
     174
    164175 "-N"   A dash as the first char in a opt_complementary group followed
    165176        by a single digit (0-9) means that at least N non-option
     
    175186
    176187 "V-"   An option with dash before colon or end-of-line results in
    177         bb_show_usage being called if this option is encountered.
     188        bb_show_usage() being called if this option is encountered.
    178189        This is typically used to implement "print verbose usage message
    179190        and exit" option.
    180191
    181  "-"    A dash between two options causes the second of the two
     192 "a-b"  A dash between two options causes the second of the two
    182193        to be unset (and ignored) if it is given on the command line.
    183194
     
    205216                printf("Detected odd -x usage\n");
    206217
    207  "--"  A double dash between two options, or between an option and a group
     218 "a--b" A double dash between two options, or between an option and a group
    208219        of options, means that they are mutually exclusive.  Unlike
    209220        the "-" case above, an error will be forced if the options
     
    221232        at most once.
    222233
    223  "::"   A double colon after a char in opt_complementary means that the
     234 "a+"   A plus after a char in opt_complementary means that the parameter
     235        for this option is a nonnegative integer. It will be processed
     236        with xatoi_positive() - allowed range is 0..INT_MAX.
     237
     238        int param;  // "unsigned param;" will also work
     239        opt_complementary = "p+";
     240        getopt32(argv, "p:", &param);
     241
     242 "a::"  A double colon after a char in opt_complementary means that the
    224243        option can occur multiple times. Each occurrence will be saved as
    225244        a llist_t element instead of char*.
     
    241260        user:x:500:500::/home/user:/bin/bash
    242261
    243  "?"    An "?" between an option and a group of options means that
     262 "a?b"  A "?" between an option and a group of options means that
    244263        at least one of them is required to occur if the first option
    245264        occurs in preceding command line arguments.
     
    248267
    249268        // Don't allow -n -r -rn -ug -rug -nug -rnug
    250         opt_complementary = "r?ug:n?ug:?u--g:g--u";
     269        opt_complementary = "r?ug:n?ug:u--g:g--u";
    251270        flags = getopt32(argv, "rnug");
    252271
     
    260279
    261280        // Don't allow -KS -SK, but -S or -K is required
    262         opt_complementary = "K:S:?K--S:S--K";
     281        opt_complementary = "K:S:K--S:S--K";
    263282        flags = getopt32(argv, "KS...);
    264283
     
    269288        a '-2' option then unset '-3', '-X' and '-a'; if there is
    270289        a '-2' and after it a '-x' then error out.
     290        But it's far too obfuscated. Use ':' to separate groups.
    271291*/
    272292
    273293/* Code here assumes that 'unsigned' is at least 32 bits wide */
    274294
     295const char *const bb_argv_dash[] = { "-", NULL };
     296
    275297const char *opt_complementary;
    276298
     299enum {
     300    PARAM_STRING,
     301    PARAM_LIST,
     302    PARAM_INT,
     303};
     304
    277305typedef struct {
    278     int opt;
    279     int list_flg;
     306    unsigned char opt_char;
     307    smallint param_type;
    280308    unsigned switch_on;
    281309    unsigned switch_off;
    282310    unsigned incongruously;
    283311    unsigned requires;
    284     void **optarg;               /* char **optarg or llist_t **optarg */
     312    void **optarg;  /* char**, llist_t** or int *. */
    285313    int *counter;
    286314} t_complementary;
    287315
    288316/* You can set applet_long_options for parse called long options */
    289 #if ENABLE_GETOPT_LONG
     317#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
    290318static const struct option bb_null_long_options[1] = {
    291319    { 0, 0, 0, 0 }
     
    296324uint32_t option_mask32;
    297325
    298 uint32_t
     326uint32_t FAST_FUNC
    299327getopt32(char **argv, const char *applet_opts, ...)
    300328{
     
    302330    unsigned flags = 0;
    303331    unsigned requires = 0;
    304     t_complementary complementary[33];
     332    t_complementary complementary[33]; /* last stays zero-filled */
     333    char first_char;
    305334    int c;
    306335    const unsigned char *s;
    307336    t_complementary *on_off;
    308337    va_list p;
    309 #if ENABLE_GETOPT_LONG
     338#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
    310339    const struct option *l_o;
    311340    struct option *long_options = (struct option *) &bb_null_long_options;
    312341#endif
    313342    unsigned trigger;
    314     char **pargv = NULL;
     343    char **pargv;
    315344    int min_arg = 0;
    316345    int max_arg = -1;
     
    319348#define ALL_ARGV_IS_OPTS        2
    320349#define FIRST_ARGV_IS_OPT       4
    321 #define FREE_FIRST_ARGV_IS_OPT  8
     350
    322351    int spec_flgs = 0;
    323352
    324     argc = 0;
     353    /* skip 0: some applets cheat: they do not actually HAVE argv[0] */
     354    argc = 1;
    325355    while (argv[argc])
    326356        argc++;
     
    331361    on_off = complementary;
    332362    memset(on_off, 0, sizeof(complementary));
     363
     364    /* skip bbox extension */
     365    first_char = applet_opts[0];
     366    if (first_char == '!')
     367        applet_opts++;
    333368
    334369    /* skip GNU extension */
     
    337372        s++;
    338373    while (*s) {
    339         if (c >= 32) break;
    340         on_off->opt = *s;
     374        if (c >= 32)
     375            break;
     376        on_off->opt_char = *s;
    341377        on_off->switch_on = (1 << c);
    342378        if (*++s == ':') {
    343379            on_off->optarg = va_arg(p, void **);
    344             while (*++s == ':') /* skip */;
     380            while (*++s == ':')
     381                continue;
    345382        }
    346383        on_off++;
     
    348385    }
    349386
    350 #if ENABLE_GETOPT_LONG
     387#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
    351388    if (applet_long_options) {
    352389        const char *optstr;
     
    375412            if (l_o->flag)
    376413                continue;
    377             for (on_off = complementary; on_off->opt != 0; on_off++)
    378                 if (on_off->opt == l_o->val)
     414            for (on_off = complementary; on_off->opt_char; on_off++)
     415                if (on_off->opt_char == l_o->val)
    379416                    goto next_long;
    380             if (c >= 32) break;
    381             on_off->opt = l_o->val;
     417            if (c >= 32)
     418                break;
     419            on_off->opt_char = l_o->val;
    382420            on_off->switch_on = (1 << c);
    383421            if (l_o->has_arg != no_argument)
     
    386424 next_long: ;
    387425        }
     426        /* Make it unnecessary to clear applet_long_options
     427         * by hand after each call to getopt32
     428         */
     429        applet_long_options = NULL;
    388430    }
    389 #endif /* ENABLE_GETOPT_LONG */
     431#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */
    390432    for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
    391433        t_complementary *pair;
     
    422464            continue;
    423465        }
    424         for (on_off = complementary; on_off->opt; on_off++)
    425             if (on_off->opt == *s)
     466        for (on_off = complementary; on_off->opt_char; on_off++)
     467            if (on_off->opt_char == *s)
    426468                break;
    427469        if (c == ':' && s[2] == ':') {
    428             on_off->list_flg++;
     470            on_off->param_type = PARAM_LIST;
     471            continue;
     472        }
     473        if (c == '+' && (s[2] == ':' || s[2] == '\0')) {
     474            on_off->param_type = PARAM_INT;
    429475            continue;
    430476        }
     
    444490        }
    445491        pair = on_off;
    446         pair_switch = &(pair->switch_on);
     492        pair_switch = &pair->switch_on;
    447493        for (s++; *s && *s != ':'; s++) {
    448494            if (*s == '?') {
    449                 pair_switch = &(pair->requires);
     495                pair_switch = &pair->requires;
    450496            } else if (*s == '-') {
    451                 if (pair_switch == &(pair->switch_off))
    452                     pair_switch = &(pair->incongruously);
     497                if (pair_switch == &pair->switch_off)
     498                    pair_switch = &pair->incongruously;
    453499                else
    454                     pair_switch = &(pair->switch_off);
     500                    pair_switch = &pair->switch_off;
    455501            } else {
    456                 for (on_off = complementary; on_off->opt; on_off++)
    457                     if (on_off->opt == *s) {
     502                for (on_off = complementary; on_off->opt_char; on_off++)
     503                    if (on_off->opt_char == *s) {
    458504                        *pair_switch |= on_off->switch_on;
    459505                        break;
     
    463509        s--;
    464510    }
     511    opt_complementary = NULL;
    465512    va_end(p);
    466513
    467     if (spec_flgs & FIRST_ARGV_IS_OPT) {
    468         if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
    469             argv[1] = xasprintf("-%s", argv[1]);
    470             if (ENABLE_FEATURE_CLEAN_UP)
    471                 spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
     514    if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) {
     515        pargv = argv + 1;
     516        while (*pargv) {
     517            if (pargv[0][0] != '-' && pargv[0][0] != '\0') {
     518                /* Can't use alloca: opts with params will
     519                 * return pointers to stack!
     520                 * NB: we leak these allocations... */
     521                char *pp = xmalloc(strlen(*pargv) + 2);
     522                *pp = '-';
     523                strcpy(pp + 1, *pargv);
     524                *pargv = pp;
     525            }
     526            if (!(spec_flgs & ALL_ARGV_IS_OPTS))
     527                break;
     528            pargv++;
    472529        }
    473530    }
    474531
    475     /* In case getopt32 was already called, reinit some state */
     532    /* In case getopt32 was already called:
     533     * reset the libc getopt() function, which keeps internal state.
     534     * run_nofork_applet_prime() does this, but we might end up here
     535     * also via gunzip_main() -> gzip_main(). Play safe.
     536     */
     537#ifdef __GLIBC__
     538    optind = 0;
     539#else /* BSD style */
    476540    optind = 1;
    477     /* optarg = NULL; opterr = 0; optopt = 0; ?? */
    478 
    479     /* Note: just "getopt() <= 0" will not work good for
     541    /* optreset = 1; */
     542#endif
     543    /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
     544
     545    pargv = NULL;
     546
     547    /* Note: just "getopt() <= 0" will not work well for
    480548     * "fake" short options, like this one:
    481549     * wget $'-\203' "Test: test" http://kernel.org/
    482550     * (supposed to act as --header, but doesn't) */
    483 #if ENABLE_GETOPT_LONG
     551#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
    484552    while ((c = getopt_long(argc, argv, applet_opts,
    485553            long_options, NULL)) != -1) {
     
    487555    while ((c = getopt(argc, argv, applet_opts)) != -1) {
    488556#endif
    489         c &= 0xff; /* fight libc's sign extends */
    490  loop_arg_is_opt:
    491         for (on_off = complementary; on_off->opt != c; on_off++) {
    492             /* c==0 if long opt have non NULL flag */
    493             if (on_off->opt == 0 && c != 0)
    494                 bb_show_usage();
     557        /* getopt prints "option requires an argument -- X"
     558         * and returns '?' if an option has no arg, but one is reqd */
     559        c &= 0xff; /* fight libc's sign extension */
     560        for (on_off = complementary; on_off->opt_char != c; on_off++) {
     561            /* c can be NUL if long opt has non-NULL ->flag,
     562             * but we construct long opts so that flag
     563             * is always NULL (see above) */
     564            if (on_off->opt_char == '\0' /* && c != '\0' */) {
     565                /* c is probably '?' - "bad option" */
     566                goto error;
     567            }
    495568        }
    496569        if (flags & on_off->incongruously)
    497             bb_show_usage();
     570            goto error;
    498571        trigger = on_off->switch_on & on_off->switch_off;
    499572        flags &= ~(on_off->switch_off ^ trigger);
     
    502575        if (on_off->counter)
    503576            (*(on_off->counter))++;
    504         if (on_off->list_flg) {
    505             llist_add_to_end((llist_t **)(on_off->optarg), optarg);
     577        if (on_off->param_type == PARAM_LIST) {
     578            if (optarg)
     579                llist_add_to_end((llist_t **)(on_off->optarg), optarg);
     580        } else if (on_off->param_type == PARAM_INT) {
     581            if (optarg)
     582//TODO: xatoi_positive indirectly pulls in printf machinery
     583                *(unsigned*)(on_off->optarg) = xatoi_positive(optarg);
    506584        } else if (on_off->optarg) {
    507             *(char **)(on_off->optarg) = optarg;
     585            if (optarg)
     586                *(char **)(on_off->optarg) = optarg;
    508587        }
    509588        if (pargv != NULL)
     
    511590    }
    512591
    513     if (spec_flgs & ALL_ARGV_IS_OPTS) {
    514         /* process argv is option, for example "ps" applet */
    515         if (pargv == NULL)
    516             pargv = argv + optind;
    517         while (*pargv) {
    518             c = **pargv;
    519             if (c == '\0') {
    520                 pargv++;
    521             } else {
    522                 (*pargv)++;
    523                 goto loop_arg_is_opt;
    524             }
    525         }
    526     }
    527 
    528 #if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP
    529     if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)
    530         free(argv[1]);
    531 #endif
    532592    /* check depending requires for given options */
    533     for (on_off = complementary; on_off->opt; on_off++) {
    534         if (on_off->requires && (flags & on_off->switch_on) &&
    535                     (flags & on_off->requires) == 0)
    536             bb_show_usage();
     593    for (on_off = complementary; on_off->opt_char; on_off++) {
     594        if (on_off->requires
     595         && (flags & on_off->switch_on)
     596         && (flags & on_off->requires) == 0
     597        ) {
     598            goto error;
     599        }
    537600    }
    538601    if (requires && (flags & requires) == 0)
    539         bb_show_usage();
     602        goto error;
    540603    argc -= optind;
    541604    if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
    542         bb_show_usage();
     605        goto error;
    543606
    544607    option_mask32 = flags;
    545608    return flags;
     609
     610 error:
     611    if (first_char != '!')
     612        bb_show_usage();
     613    return (int32_t)-1;
    546614}
  • branches/2.2.9/mindi-busybox/libbb/herror_msg.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
    12 void bb_herror_msg(const char *s, ...)
     11void FAST_FUNC bb_herror_msg(const char *s, ...)
    1312{
    1413    va_list p;
     
    1817    va_end(p);
    1918}
     19
     20void FAST_FUNC bb_herror_msg_and_die(const char *s, ...)
     21{
     22    va_list p;
     23
     24    va_start(p, s);
     25    bb_verror_msg(s, p, hstrerror(h_errno));
     26    va_end(p);
     27    xfunc_die();
     28}
  • branches/2.2.9/mindi-busybox/libbb/human_readable.c

    r1765 r2725  
    2525 *      Some code to omit the decimal point and tenths digit is sketched out
    2626 *      and "#if 0"'d below.
     27 *
     28 * Licensed under GPLv2, see file LICENSE in this source tree.
    2729 */
    2830
    2931#include "libbb.h"
    3032
    31 const char *make_human_readable_str(unsigned long long size,
     33const char* FAST_FUNC make_human_readable_str(unsigned long long val,
    3234    unsigned long block_size, unsigned long display_unit)
    3335{
    34     /* The code will adjust for additional (appended) units */
    35     static const char zero_and_units[] ALIGN1 = { '0', 0, 'k', 'M', 'G', 'T' };
    36     static const char fmt[] ALIGN1 = "%llu";
    37     static const char fmt_tenths[] ALIGN1 = "%llu.%d%c";
     36    static const char unit_chars[] ALIGN1 = {
     37        '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
     38    };
    3839
    39     static char str[21] ALIGN1;  /* Sufficient for 64 bit unsigned integers */
     40    static char *str;
    4041
    41     unsigned long long val;
    42     int frac;
     42    unsigned frac; /* 0..9 - the fractional digit */
    4343    const char *u;
    44     const char *f;
     44    const char *fmt;
    4545
    46     u = zero_and_units;
    47     f = fmt;
     46    if (val == 0)
     47        return "0";
     48
     49    fmt = "%llu";
     50    if (block_size > 1)
     51        val *= block_size;
    4852    frac = 0;
    49 
    50     val = size * block_size;
    51     if (val == 0) {
    52         return u;
    53     }
     53    u = unit_chars;
    5454
    5555    if (display_unit) {
    56         val += display_unit/2;  /* Deal with rounding */
    57         val /= display_unit;    /* Don't combine with the line above!!! */
     56        val += display_unit/2;  /* Deal with rounding */
     57        val /= display_unit;    /* Don't combine with the line above! */
     58        /* will just print it as ulonglong (below) */
    5859    } else {
    59         ++u;
    6060        while ((val >= 1024)
    61          && (u < zero_and_units + sizeof(zero_and_units) - 1)
     61         /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */
    6262        ) {
    63             f = fmt_tenths;
    64             ++u;
    65             frac = (((int)(val % 1024)) * 10 + 1024/2) / 1024;
     63            fmt = "%llu.%u%c";
     64            u++;
     65            frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024;
    6666            val /= 1024;
    6767        }
    68         if (frac >= 10) {       /* We need to round up here. */
     68        if (frac >= 10) { /* we need to round up here */
    6969            ++val;
    7070            frac = 0;
    7171        }
    72 #if 0
    73         /* Sample code to omit decimal point and tenths digit. */
    74         if (/* no_tenths */ 1) {
     72#if 1
     73        /* If block_size is 0, dont print fractional part */
     74        if (block_size == 0) {
    7575            if (frac >= 5) {
    7676                ++val;
    7777            }
    78             f = "%llu%*c" /* fmt_no_tenths */;
     78            fmt = "%llu%*c";
    7979            frac = 1;
    8080        }
     
    8282    }
    8383
    84     /* If f==fmt then 'frac' and 'u' are ignored. */
    85     snprintf(str, sizeof(str), f, val, frac, *u);
    86 
     84    if (!str) {
     85        /* sufficient for any width of val */
     86        str = xmalloc(sizeof(val)*3 + 2 + 3);
     87    }
     88    sprintf(str, fmt, val, frac, *u);
    8789    return str;
    8890}
     91
     92
     93/* vda's implementations of the similar idea */
     94
     95/* Convert unsigned long long value into compact 5-char representation.
     96 * String is not terminated (buf[5] is untouched) */
     97void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale)
     98{
     99    const char *fmt;
     100    char c;
     101    unsigned v, u, idx = 0;
     102
     103    if (ul > 99999) { // do not scale if 99999 or less
     104        ul *= 10;
     105        do {
     106            ul /= 1024;
     107            idx++;
     108        } while (ul >= 100000);
     109    }
     110    v = ul; // ullong divisions are expensive, avoid them
     111
     112    fmt = " 123456789";
     113    u = v / 10;
     114    v = v % 10;
     115    if (!idx) {
     116        // 99999 or less: use "12345" format
     117        // u is value/10, v is last digit
     118        c = buf[0] = " 123456789"[u/1000];
     119        if (c != ' ') fmt = "0123456789";
     120        c = buf[1] = fmt[u/100%10];
     121        if (c != ' ') fmt = "0123456789";
     122        c = buf[2] = fmt[u/10%10];
     123        if (c != ' ') fmt = "0123456789";
     124        buf[3] = fmt[u%10];
     125        buf[4] = "0123456789"[v];
     126    } else {
     127        // value has been scaled into 0..9999.9 range
     128        // u is value, v is 1/10ths (allows for 92.1M format)
     129        if (u >= 100) {
     130            // value is >= 100: use "1234M', " 123M" formats
     131            c = buf[0] = " 123456789"[u/1000];
     132            if (c != ' ') fmt = "0123456789";
     133            c = buf[1] = fmt[u/100%10];
     134            if (c != ' ') fmt = "0123456789";
     135            v = u % 10;
     136            u = u / 10;
     137            buf[2] = fmt[u%10];
     138        } else {
     139            // value is < 100: use "92.1M" format
     140            c = buf[0] = " 123456789"[u/10];
     141            if (c != ' ') fmt = "0123456789";
     142            buf[1] = fmt[u%10];
     143            buf[2] = '.';
     144        }
     145        buf[3] = "0123456789"[v];
     146        buf[4] = scale[idx]; /* typically scale = " kmgt..." */
     147    }
     148}
     149
     150/* Convert unsigned long long value into compact 4-char
     151 * representation. Examples: "1234", "1.2k", " 27M", "123T"
     152 * String is not terminated (buf[4] is untouched) */
     153void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale)
     154{
     155    const char *fmt;
     156    char c;
     157    unsigned v, u, idx = 0;
     158
     159    if (ul > 9999) { // do not scale if 9999 or less
     160        ul *= 10;
     161        do {
     162            ul /= 1024;
     163            idx++;
     164        } while (ul >= 10000);
     165    }
     166    v = ul; // ullong divisions are expensive, avoid them
     167
     168    fmt = " 123456789";
     169    u = v / 10;
     170    v = v % 10;
     171    if (!idx) {
     172        // 9999 or less: use "1234" format
     173        // u is value/10, v is last digit
     174        c = buf[0] = " 123456789"[u/100];
     175        if (c != ' ') fmt = "0123456789";
     176        c = buf[1] = fmt[u/10%10];
     177        if (c != ' ') fmt = "0123456789";
     178        buf[2] = fmt[u%10];
     179        buf[3] = "0123456789"[v];
     180    } else {
     181        // u is value, v is 1/10ths (allows for 9.2M format)
     182        if (u >= 10) {
     183            // value is >= 10: use "123M', " 12M" formats
     184            c = buf[0] = " 123456789"[u/100];
     185            if (c != ' ') fmt = "0123456789";
     186            v = u % 10;
     187            u = u / 10;
     188            buf[1] = fmt[u%10];
     189        } else {
     190            // value is < 10: use "9.2M" format
     191            buf[0] = "0123456789"[u];
     192            buf[1] = '.';
     193        }
     194        buf[2] = "0123456789"[v];
     195        buf[3] = scale[idx]; /* typically scale = " kmgt..." */
     196    }
     197}
  • branches/2.2.9/mindi-busybox/libbb/inet_common.c

    r1765 r2725  
    66 * Heavily modified by Manuel Novoa III       Mar 12, 2001
    77 *
    8  *
     8 * Licensed under GPLv2, see file LICENSE in this source tree.
    99 */
    1010
     
    1212#include "inet_common.h"
    1313
    14 int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
     14int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
    1515{
    1616    struct hostent *hp;
     
    2424
    2525    /* Default is special, meaning 0.0.0.0. */
    26     if (!strcmp(name, bb_str_default)) {
     26    if (strcmp(name, "default") == 0) {
    2727        s_in->sin_addr.s_addr = INADDR_ANY;
    2828        return 1;
     
    6464    res_init();
    6565    _res.options |= RES_DEBUG;
    66 #endif
    67 
    68 #ifdef DEBUG
    6966    bb_error_msg("gethostbyname(%s)", name);
    7067#endif
     
    8279 *          & 0x0fff: don't resolve
    8380 */
    84 char *INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask)
     81char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask)
    8582{
    8683    /* addr-to-name cache */
     
    9895    int host = 0;
    9996
    100     /* Grmpf. -FvK */
    10197    if (s_in->sin_family != AF_INET) {
    10298#ifdef DEBUG
     
    114110        if ((numeric & 0x0FFF) == 0) {
    115111            if (numeric & 0x8000)
    116                 return xstrdup(bb_str_default);
     112                return xstrdup("default");
    117113            return xstrdup("*");
    118114        }
     
    167163#if ENABLE_FEATURE_IPV6
    168164
    169 int INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
     165int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
    170166{
    171167    struct addrinfo req, *ai;
     
    191187
    192188
    193 char *INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
     189char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
    194190{
    195191    char name[128];
    196192    int s;
    197193
    198     /* Grmpf. -FvK */
    199194    if (sin6->sin6_family != AF_INET6) {
    200195#ifdef DEBUG
    201         bb_error_msg("rresolve: unsupport address family %d!",
     196        bb_error_msg("rresolve: unsupported address family %d!",
    202197                  sin6->sin6_family);
    203198#endif
     
    211206    if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
    212207        if (numeric & 0x8000)
    213             return xstrdup(bb_str_default);
     208            return xstrdup("default");
    214209        return xstrdup("*");
    215210    }
     
    224219}
    225220
    226 #endif                          /* CONFIG_FEATURE_IPV6 */
     221#endif  /* CONFIG_FEATURE_IPV6 */
  • branches/2.2.9/mindi-busybox/libbb/info_msg.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    10 #include <syslog.h>
    1110#include "libbb.h"
     11#if ENABLE_FEATURE_SYSLOG
     12# include <syslog.h>
     13#endif
    1214
    13 void bb_info_msg(const char *s, ...)
     15void FAST_FUNC bb_info_msg(const char *s, ...)
    1416{
     17#ifdef THIS_ONE_DOESNT_DO_SINGLE_WRITE
    1518    va_list p;
    1619    /* va_copy is used because it is not portable
     
    2427        fputs(msg_eol, stdout);
    2528    }
    26     if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG))
     29# if ENABLE_FEATURE_SYSLOG
     30    if (logmode & LOGMODE_SYSLOG)
    2731        vsyslog(LOG_INFO, s, p2);
     32# endif
    2833    va_end(p2);
    2934    va_end(p);
     35#else
     36    int used;
     37    char *msg;
     38    va_list p;
     39
     40    if (logmode == 0)
     41        return;
     42
     43    va_start(p, s);
     44    used = vasprintf(&msg, s, p);
     45    va_end(p);
     46    if (used < 0)
     47        return;
     48
     49# if ENABLE_FEATURE_SYSLOG
     50    if (logmode & LOGMODE_SYSLOG)
     51        syslog(LOG_INFO, "%s", msg);
     52# endif
     53    if (logmode & LOGMODE_STDIO) {
     54        fflush_all();
     55        /* used = strlen(msg); - must be true already */
     56        msg[used++] = '\n';
     57        full_write(STDOUT_FILENO, msg, used);
     58    }
     59
     60    free(msg);
     61#endif
    3062}
  • branches/2.2.9/mindi-busybox/libbb/inode_hash.c

    r1765 r2725  
    66 * If you wrote this, please acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
     
    1818} ino_dev_hashtable_bucket_t;
    1919
    20 #define HASH_SIZE   311     /* Should be prime */
    21 #define hash_inode(i)   ((i) % HASH_SIZE)
     20#define HASH_SIZE      311   /* Should be prime */
     21#define hash_inode(i)  ((i) % HASH_SIZE)
    2222
    2323/* array of [HASH_SIZE] elements */
     
    2828 * ino_dev_hashtable, else return NULL
    2929 */
    30 char *is_in_ino_dev_hashtable(const struct stat *statbuf)
     30char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf)
    3131{
    3232    ino_dev_hashtable_bucket_t *bucket;
     
    4848
    4949/* Add statbuf to statbuf hash table */
    50 void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
     50void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
    5151{
    5252    int i;
     
    6868}
    6969
    70 #if ENABLE_FEATURE_CLEAN_UP
     70#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP
    7171/* Clear statbuf hash table */
    72 void reset_ino_dev_hashtable(void)
     72void FAST_FUNC reset_ino_dev_hashtable(void)
    7373{
    7474    int i;
     
    8585    ino_dev_hashtable = NULL;
    8686}
    87 #else
    88 void reset_ino_dev_hashtable(void);
    8987#endif
  • branches/2.2.9/mindi-busybox/libbb/isdirectory.c

    r821 r2725  
    44 *
    55 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
    6  * Permission has been granted to redistribute this code under the GPL.
     6 * Permission has been granted to redistribute this code under GPL.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
     
    1313
    1414/*
    15  * Return TRUE if a fileName is a directory.
     15 * Return TRUE if fileName is a directory.
    1616 * Nonexistent files return FALSE.
    1717 */
    18 int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
     18int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf)
    1919{
    2020    int status;
     
    2222
    2323    if (statBuf == NULL) {
    24         /* set from auto stack buffer */
    25         statBuf = &astatBuf;
     24        /* use auto stack buffer */
     25        statBuf = &astatBuf;
    2626    }
    2727
     
    3131        status = lstat(fileName, statBuf);
    3232
    33     if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
    34         status = FALSE;
    35     }
    36     else status = TRUE;
     33    status = (status == 0 && S_ISDIR(statBuf->st_mode));
    3734
    3835    return status;
  • branches/2.2.9/mindi-busybox/libbb/kernel_version.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    10 #include <sys/utsname.h>        /* for uname(2) */
     10#include "libbb.h"
     11/* After libbb.h, since it needs sys/types.h on some systems */
     12#include <sys/utsname.h>  /* for uname(2) */
    1113
    12 #include "libbb.h"
    1314
    1415/* Returns current kernel version encoded as major*65536 + minor*256 + patch,
     
    1718 *     if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> }
    1819 */
    19 int get_linux_version_code(void)
     20int FAST_FUNC get_linux_version_code(void)
    2021{
    2122    struct utsname name;
     
    2425
    2526    if (uname(&name) == -1) {
    26         bb_perror_msg("cannot get system information");
     27        bb_perror_msg("can't get system information");
    2728        return 0;
    2829    }
  • branches/2.2.9/mindi-busybox/libbb/last_char_is.c

    r1765 r2725  
    55 * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1313 * Don't underrun the buffer if the string length is 0.
    1414 */
    15 char* last_char_is(const char *s, int c)
     15char* FAST_FUNC last_char_is(const char *s, int c)
    1616{
    1717    if (s && *s) {
  • branches/2.2.9/mindi-busybox/libbb/lineedit.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Termios command line History and Editing.
     3 * Command line editing.
    44 *
    55 * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
     
    1616
    1717/*
    18    Usage and known bugs:
    19    Terminal key codes are not extensive, and more will probably
    20    need to be added. This version was created on Debian GNU/Linux 2.x.
    21    Delete, Backspace, Home, End, and the arrow keys were tested
    22    to work in an Xterm and console. Ctrl-A also works as Home.
    23    Ctrl-E also works as End.
    24 
    25    Small bugs (simple effect):
    26    - not true viewing if terminal size (x*y symbols) less
    27      size (prompt + editor's line + 2 symbols)
    28    - not true viewing if length prompt less terminal width
     18 * Usage and known bugs:
     19 * Terminal key codes are not extensive, more needs to be added.
     20 * This version was created on Debian GNU/Linux 2.x.
     21 * Delete, Backspace, Home, End, and the arrow keys were tested
     22 * to work in an Xterm and console. Ctrl-A also works as Home.
     23 * Ctrl-E also works as End.
     24 *
     25 * The following readline-like commands are not implemented:
     26 * ESC-b -- Move back one word
     27 * ESC-f -- Move forward one word
     28 * ESC-d -- Delete forward one word
     29 * CTL-t -- Transpose two characters
     30 *
     31 * lineedit does not know that the terminal escape sequences do not
     32 * take up space on the screen. The redisplay code assumes, unless
     33 * told otherwise, that each character in the prompt is a printable
     34 * character that takes up one character position on the screen.
     35 * You need to tell lineedit that some sequences of characters
     36 * in the prompt take up no screen space. Compatibly with readline,
     37 * use the \[ escape to begin a sequence of non-printing characters,
     38 * and the \] escape to signal the end of such a sequence. Example:
     39 *
     40 * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
    2941 */
    30 
    3142#include "libbb.h"
    32 
    33 
    34 /* FIXME: obsolete CONFIG item? */
    35 #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
    36 
     43#include "unicode.h"
    3744
    3845#ifdef TEST
    39 
    40 #define ENABLE_FEATURE_EDITING 0
    41 #define ENABLE_FEATURE_TAB_COMPLETION 0
    42 #define ENABLE_FEATURE_USERNAME_COMPLETION 0
    43 #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
    44 #define ENABLE_FEATURE_CLEAN_UP 0
    45 
    46 #endif  /* TEST */
     46# define ENABLE_FEATURE_EDITING 0
     47# define ENABLE_FEATURE_TAB_COMPLETION 0
     48# define ENABLE_FEATURE_USERNAME_COMPLETION 0
     49#endif
    4750
    4851
     
    5053#if ENABLE_FEATURE_EDITING
    5154
    52 #if ENABLE_LOCALE_SUPPORT
    53 #define Isprint(c) isprint(c)
     55
     56#define ENABLE_USERNAME_OR_HOMEDIR \
     57    (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
     58#define IF_USERNAME_OR_HOMEDIR(...)
     59#if ENABLE_USERNAME_OR_HOMEDIR
     60# undef IF_USERNAME_OR_HOMEDIR
     61# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__
     62#endif
     63
     64
     65#undef CHAR_T
     66#if ENABLE_UNICODE_SUPPORT
     67# define BB_NUL ((wchar_t)0)
     68# define CHAR_T wchar_t
     69static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
     70# if ENABLE_FEATURE_EDITING_VI
     71static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); }
     72# endif
     73static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
     74# undef isspace
     75# undef isalnum
     76# undef ispunct
     77# undef isprint
     78# define isspace isspace_must_not_be_used
     79# define isalnum isalnum_must_not_be_used
     80# define ispunct ispunct_must_not_be_used
     81# define isprint isprint_must_not_be_used
    5482#else
    55 #define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
    56 #endif
    57 
    58 #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
    59 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
    60 
    61 enum { MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN };
    62 
    63 static line_input_t *state;
    64 
    65 static struct termios initial_settings, new_settings;
    66 
    67 static volatile unsigned cmdedit_termw = 80;        /* actual terminal width */
    68 
    69 static int cmdedit_x;           /* real x terminal position */
    70 static int cmdedit_y;           /* pseudoreal y terminal position */
    71 static int cmdedit_prmt_len;    /* length of prompt (without colors etc) */
    72 
    73 static unsigned cursor;
    74 static unsigned command_len;
    75 static char *command_ps;
    76 static const char *cmdedit_prompt;
    77 
     83# define BB_NUL '\0'
     84# define CHAR_T char
     85# define BB_isspace(c) isspace(c)
     86# define BB_isalnum(c) isalnum(c)
     87# define BB_ispunct(c) ispunct(c)
     88#endif
     89#if ENABLE_UNICODE_PRESERVE_BROKEN
     90# define unicode_mark_raw_byte(wc)   ((wc) | 0x20000000)
     91# define unicode_is_raw_byte(wc)     ((wc) & 0x20000000)
     92#else
     93# define unicode_is_raw_byte(wc)     0
     94#endif
     95
     96
     97#define ESC "\033"
     98
     99#define SEQ_CLEAR_TILL_END_OF_SCREEN  ESC"[J"
     100//#define SEQ_CLEAR_TILL_END_OF_LINE  ESC"[K"
     101
     102
     103enum {
     104    MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
     105                  ? CONFIG_FEATURE_EDITING_MAX_LEN
     106                  : 0x7ff0
     107};
     108
     109#if ENABLE_USERNAME_OR_HOMEDIR
     110static const char null_str[] ALIGN1 = "";
     111#endif
     112
     113/* We try to minimize both static and stack usage. */
     114struct lineedit_statics {
     115    line_input_t *state;
     116
     117    volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
     118    sighandler_t previous_SIGWINCH_handler;
     119
     120    unsigned cmdedit_x;        /* real x (col) terminal position */
     121    unsigned cmdedit_y;        /* pseudoreal y (row) terminal position */
     122    unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
     123
     124    unsigned cursor;
     125    int command_len; /* must be signed */
     126    /* signed maxsize: we want x in "if (x > S.maxsize)"
     127     * to _not_ be promoted to unsigned */
     128    int maxsize;
     129    CHAR_T *command_ps;
     130
     131    const char *cmdedit_prompt;
    78132#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
    79 static char *hostname_buf;
    80 static int num_ok_lines = 1;
    81 #endif
    82 
    83 #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
    84 static const char null_str[] = "";
    85 static char *user_buf;
    86 static char *home_pwd_buf = (char*)null_str;
    87 #endif
     133    int num_ok_lines; /* = 1; */
     134#endif
     135
     136#if ENABLE_USERNAME_OR_HOMEDIR
     137    char *user_buf;
     138    char *home_pwd_buf; /* = (char*)null_str; */
     139#endif
     140
     141#if ENABLE_FEATURE_TAB_COMPLETION
     142    char **matches;
     143    unsigned num_matches;
     144#endif
     145
     146#if ENABLE_FEATURE_EDITING_VI
     147# define DELBUFSIZ 128
     148    CHAR_T *delptr;
     149    smallint newdelflag;     /* whether delbuf should be reused yet */
     150    CHAR_T delbuf[DELBUFSIZ];  /* a place to store deleted characters */
     151#endif
     152#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
     153    smallint sent_ESC_br6n;
     154#endif
     155};
     156
     157/* See lineedit_ptr_hack.c */
     158extern struct lineedit_statics *const lineedit_ptr_to_statics;
     159
     160#define S (*lineedit_ptr_to_statics)
     161#define state            (S.state           )
     162#define cmdedit_termw    (S.cmdedit_termw   )
     163#define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
     164#define cmdedit_x        (S.cmdedit_x       )
     165#define cmdedit_y        (S.cmdedit_y       )
     166#define cmdedit_prmt_len (S.cmdedit_prmt_len)
     167#define cursor           (S.cursor          )
     168#define command_len      (S.command_len     )
     169#define command_ps       (S.command_ps      )
     170#define cmdedit_prompt   (S.cmdedit_prompt  )
     171#define num_ok_lines     (S.num_ok_lines    )
     172#define user_buf         (S.user_buf        )
     173#define home_pwd_buf     (S.home_pwd_buf    )
     174#define matches          (S.matches         )
     175#define num_matches      (S.num_matches     )
     176#define delptr           (S.delptr          )
     177#define newdelflag       (S.newdelflag      )
     178#define delbuf           (S.delbuf          )
     179
     180#define INIT_S() do { \
     181    (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
     182    barrier(); \
     183    cmdedit_termw = 80; \
     184    IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
     185    IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
     186} while (0)
     187static void deinit_S(void)
     188{
     189#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
     190    /* This one is allocated only if FANCY_PROMPT is on
     191     * (otherwise it points to verbatim prompt (NOT malloced)) */
     192    free((char*)cmdedit_prompt);
     193#endif
     194#if ENABLE_USERNAME_OR_HOMEDIR
     195    free(user_buf);
     196    if (home_pwd_buf != null_str)
     197        free(home_pwd_buf);
     198#endif
     199    free(lineedit_ptr_to_statics);
     200}
     201#define DEINIT_S() deinit_S()
     202
     203
     204#if ENABLE_UNICODE_SUPPORT
     205static size_t load_string(const char *src, int maxsize)
     206{
     207    ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
     208    if (len < 0)
     209        len = 0;
     210    command_ps[len] = BB_NUL;
     211    return len;
     212}
     213static unsigned save_string(char *dst, unsigned maxsize)
     214{
     215# if !ENABLE_UNICODE_PRESERVE_BROKEN
     216    ssize_t len = wcstombs(dst, command_ps, maxsize - 1);
     217    if (len < 0)
     218        len = 0;
     219    dst[len] = '\0';
     220    return len;
     221# else
     222    unsigned dstpos = 0;
     223    unsigned srcpos = 0;
     224
     225    maxsize--;
     226    while (dstpos < maxsize) {
     227        wchar_t wc;
     228        int n = srcpos;
     229
     230        /* Convert up to 1st invalid byte (or up to end) */
     231        while ((wc = command_ps[srcpos]) != BB_NUL
     232            && !unicode_is_raw_byte(wc)
     233        ) {
     234            srcpos++;
     235        }
     236        command_ps[srcpos] = BB_NUL;
     237        n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos);
     238        if (n < 0) /* should not happen */
     239            break;
     240        dstpos += n;
     241        if (wc == BB_NUL) /* usually is */
     242            break;
     243
     244        /* We do have invalid byte here! */
     245        command_ps[srcpos] = wc; /* restore it */
     246        srcpos++;
     247        if (dstpos == maxsize)
     248            break;
     249        dst[dstpos++] = (char) wc;
     250    }
     251    dst[dstpos] = '\0';
     252    return dstpos;
     253# endif
     254}
     255/* I thought just fputwc(c, stdout) would work. But no... */
     256static void BB_PUTCHAR(wchar_t c)
     257{
     258    char buf[MB_CUR_MAX + 1];
     259    mbstate_t mbst = { 0 };
     260    ssize_t len;
     261
     262    len = wcrtomb(buf, c, &mbst);
     263    if (len > 0) {
     264        buf[len] = '\0';
     265        fputs(buf, stdout);
     266    }
     267}
     268# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
     269static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc)
     270# else
     271static wchar_t adjust_width_and_validate_wc(wchar_t wc)
     272#  define adjust_width_and_validate_wc(width_adj, wc) \
     273    ((*(width_adj))++, adjust_width_and_validate_wc(wc))
     274# endif
     275{
     276    int w = 1;
     277
     278    if (unicode_status == UNICODE_ON) {
     279        if (wc > CONFIG_LAST_SUPPORTED_WCHAR) {
     280            /* note: also true for unicode_is_raw_byte(wc) */
     281            goto subst;
     282        }
     283        w = wcwidth(wc);
     284        if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0)
     285         || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
     286         || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
     287        ) {
     288 subst:
     289            w = 1;
     290            wc = CONFIG_SUBST_WCHAR;
     291        }
     292    }
     293
     294# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
     295    *width_adj += w;
     296#endif
     297    return wc;
     298}
     299#else /* !UNICODE */
     300static size_t load_string(const char *src, int maxsize)
     301{
     302    safe_strncpy(command_ps, src, maxsize);
     303    return strlen(command_ps);
     304}
     305# if ENABLE_FEATURE_TAB_COMPLETION
     306static void save_string(char *dst, unsigned maxsize)
     307{
     308    safe_strncpy(dst, command_ps, maxsize);
     309}
     310# endif
     311# define BB_PUTCHAR(c) bb_putchar(c)
     312/* Should never be called: */
     313int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
     314#endif
     315
    88316
    89317/* Put 'command_ps[cursor]', cursor++.
    90318 * Advance cursor on screen. If we reached right margin, scroll text up
    91319 * and remove terminal margin effect by printing 'next_char' */
    92 static void cmdedit_set_out_char(int next_char)
    93 {
    94     int c = (unsigned char)command_ps[cursor];
    95 
    96     if (c == '\0') {
     320#define HACK_FOR_WRONG_WIDTH 1
     321static void put_cur_glyph_and_inc_cursor(void)
     322{
     323    CHAR_T c = command_ps[cursor];
     324    unsigned width = 0;
     325    int ofs_to_right;
     326
     327    if (c == BB_NUL) {
    97328        /* erase character after end of input string */
    98329        c = ' ';
    99     }
    100 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
    101     /* Display non-printable characters in reverse */
    102     if (!Isprint(c)) {
    103         if (c >= 128)
    104             c -= 128;
    105         if (c < ' ')
    106             c += '@';
    107         if (c == 127)
    108             c = '?';
    109         printf("\033[7m%c\033[0m", c);
    110     } else
    111 #endif
    112     {
    113         if (initial_settings.c_lflag & ECHO)
    114             putchar(c);
    115     }
    116     if (++cmdedit_x >= cmdedit_termw) {
    117         /* terminal is scrolled down */
     330    } else {
     331        /* advance cursor only if we aren't at the end yet */
     332        cursor++;
     333        if (unicode_status == UNICODE_ON) {
     334            IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
     335            c = adjust_width_and_validate_wc(&cmdedit_x, c);
     336            IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
     337        } else {
     338            cmdedit_x++;
     339        }
     340    }
     341
     342    ofs_to_right = cmdedit_x - cmdedit_termw;
     343    if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
     344        /* c fits on this line */
     345        BB_PUTCHAR(c);
     346    }
     347
     348    if (ofs_to_right >= 0) {
     349        /* we go to the next line */
     350#if HACK_FOR_WRONG_WIDTH
     351        /* This works better if our idea of term width is wrong
     352         * and it is actually wider (often happens on serial lines).
     353         * Printing CR,LF *forces* cursor to next line.
     354         * OTOH if terminal width is correct AND terminal does NOT
     355         * have automargin (IOW: it is moving cursor to next line
     356         * by itself (which is wrong for VT-10x terminals)),
     357         * this will break things: there will be one extra empty line */
     358        puts("\r"); /* + implicit '\n' */
     359#else
     360        /* VT-10x terminals don't wrap cursor to next line when last char
     361         * on the line is printed - cursor stays "over" this char.
     362         * Need to print _next_ char too (first one to appear on next line)
     363         * to make cursor move down to next line.
     364         */
     365        /* Works ok only if cmdedit_termw is correct. */
     366        c = command_ps[cursor];
     367        if (c == BB_NUL)
     368            c = ' ';
     369        BB_PUTCHAR(c);
     370        bb_putchar('\b');
     371#endif
    118372        cmdedit_y++;
    119         cmdedit_x = 0;
    120         /* destroy "(auto)margin" */
    121         putchar(next_char);
    122         putchar('\b');
    123     }
    124 // Huh? What if command_ps[cursor] == '\0' (we are at the end already?)
    125     cursor++;
     373        if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
     374            width = 0;
     375        } else { /* ofs_to_right > 0 */
     376            /* wide char c didn't fit on prev line */
     377            BB_PUTCHAR(c);
     378        }
     379        cmdedit_x = width;
     380    }
    126381}
    127382
    128383/* Move to end of line (by printing all chars till the end) */
    129 static void input_end(void)
     384static void put_till_end_and_adv_cursor(void)
    130385{
    131386    while (cursor < command_len)
    132         cmdedit_set_out_char(' ');
     387        put_cur_glyph_and_inc_cursor();
    133388}
    134389
     
    136391static void goto_new_line(void)
    137392{
    138     input_end();
    139     if (cmdedit_x)
    140         putchar('\n');
    141 }
    142 
    143 
    144 static void out1str(const char *s)
    145 {
    146     if (s)
    147         fputs(s, stdout);
     393    put_till_end_and_adv_cursor();
     394    if (cmdedit_x != 0)
     395        bb_putchar('\n');
    148396}
    149397
    150398static void beep(void)
    151399{
    152     putchar('\007');
     400    bb_putchar('\007');
     401}
     402
     403static void put_prompt(void)
     404{
     405    unsigned w;
     406
     407    fputs(cmdedit_prompt, stdout);
     408    fflush_all();
     409    cursor = 0;
     410    w = cmdedit_termw; /* read volatile var once */
     411    cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
     412    cmdedit_x = cmdedit_prmt_len % w;
    153413}
    154414
     
    157417static void input_backward(unsigned num)
    158418{
    159     int count_y;
    160 
    161419    if (num > cursor)
    162420        num = cursor;
    163     if (!num)
     421    if (num == 0)
    164422        return;
    165423    cursor -= num;
     424
     425    if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS)
     426     && unicode_status == UNICODE_ON
     427    ) {
     428        /* correct NUM to be equal to _screen_ width */
     429        int n = num;
     430        num = 0;
     431        while (--n >= 0)
     432            adjust_width_and_validate_wc(&num, command_ps[cursor + n]);
     433        if (num == 0)
     434            return;
     435    }
    166436
    167437    if (cmdedit_x >= num) {
    168438        cmdedit_x -= num;
    169439        if (num <= 4) {
    170             printf("\b\b\b\b" + (4-num));
     440            /* This is longer by 5 bytes on x86.
     441             * Also gets miscompiled for ARM users
     442             * (busybox.net/bugs/view.php?id=2274).
     443             * printf(("\b\b\b\b" + 4) - num);
     444             * return;
     445             */
     446            do {
     447                bb_putchar('\b');
     448            } while (--num);
    171449            return;
    172450        }
    173         printf("\033[%uD", num);
     451        printf(ESC"[%uD", num);
    174452        return;
    175453    }
    176454
    177455    /* Need to go one or more lines up */
    178     num -= cmdedit_x;
    179     count_y = 1 + (num / cmdedit_termw);
    180     cmdedit_y -= count_y;
    181     cmdedit_x = cmdedit_termw * count_y - num;
    182     /* go to 1st column; go up; go to correct column */
    183     printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);
    184 }
    185 
    186 static void put_prompt(void)
    187 {
    188     out1str(cmdedit_prompt);
    189     cmdedit_x = cmdedit_prmt_len;
    190     cursor = 0;
    191 // Huh? what if cmdedit_prmt_len >= width?
    192     cmdedit_y = 0;                  /* new quasireal y */
     456    if (ENABLE_UNICODE_WIDE_WCHARS) {
     457        /* With wide chars, it is hard to "backtrack"
     458         * and reliably figure out where to put cursor.
     459         * Example (<> is a wide char; # is an ordinary char, _ cursor):
     460         * |prompt: <><> |
     461         * |<><><><><><> |
     462         * |_            |
     463         * and user presses left arrow. num = 1, cmdedit_x = 0,
     464         * We need to go up one line, and then - how do we know that
     465         * we need to go *10* positions to the right? Because
     466         * |prompt: <>#<>|
     467         * |<><><>#<><><>|
     468         * |_            |
     469         * in this situation we need to go *11* positions to the right.
     470         *
     471         * A simpler thing to do is to redraw everything from the start
     472         * up to new cursor position (which is already known):
     473         */
     474        unsigned sv_cursor;
     475        /* go to 1st column; go up to first line */
     476        printf("\r" ESC"[%uA", cmdedit_y);
     477        cmdedit_y = 0;
     478        sv_cursor = cursor;
     479        put_prompt(); /* sets cursor to 0 */
     480        while (cursor < sv_cursor)
     481            put_cur_glyph_and_inc_cursor();
     482    } else {
     483        int lines_up;
     484        unsigned width;
     485        /* num = chars to go back from the beginning of current line: */
     486        num -= cmdedit_x;
     487        width = cmdedit_termw; /* read volatile var once */
     488        /* num=1...w: one line up, w+1...2w: two, etc: */
     489        lines_up = 1 + (num - 1) / width;
     490        cmdedit_x = (width * cmdedit_y - num) % width;
     491        cmdedit_y -= lines_up;
     492        /* go to 1st column; go up */
     493        printf("\r" ESC"[%uA", lines_up);
     494        /* go to correct column.
     495         * xterm, konsole, Linux VT interpret 0 as 1 below! wow.
     496         * need to *make sure* we skip it if cmdedit_x == 0 */
     497        if (cmdedit_x)
     498            printf(ESC"[%uC", cmdedit_x);
     499    }
    193500}
    194501
     
    196503static void redraw(int y, int back_cursor)
    197504{
    198     if (y > 0)                              /* up to start y */
    199         printf("\033[%dA", y);
    200     putchar('\r');
     505    if (y > 0) /* up y lines */
     506        printf(ESC"[%uA", y);
     507    bb_putchar('\r');
    201508    put_prompt();
    202     input_end();                            /* rewrite */
    203     printf("\033[J");                       /* erase after cursor */
     509    put_till_end_and_adv_cursor();
     510    printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
    204511    input_backward(back_cursor);
    205512}
    206 
    207 #if ENABLE_FEATURE_EDITING_VI
    208 #define DELBUFSIZ 128
    209 static char *delbuf;  /* a (malloced) place to store deleted characters */
    210 static char *delp;
    211 static char newdelflag;      /* whether delbuf should be reused yet */
    212 #endif
    213513
    214514/* Delete the char in front of the cursor, optionally saving it
    215515 * for later putback */
     516#if !ENABLE_FEATURE_EDITING_VI
     517static void input_delete(void)
     518#define input_delete(save) input_delete()
     519#else
    216520static void input_delete(int save)
     521#endif
    217522{
    218523    int j = cursor;
    219524
    220     if (j == command_len)
     525    if (j == (int)command_len)
    221526        return;
    222527
     
    224529    if (save) {
    225530        if (newdelflag) {
    226             if (!delbuf)
    227                 delbuf = malloc(DELBUFSIZ);
    228             /* safe if malloc fails */
    229             delp = delbuf;
     531            delptr = delbuf;
    230532            newdelflag = 0;
    231533        }
    232         if (delbuf && (delp - delbuf < DELBUFSIZ))
    233             *delp++ = command_ps[j];
    234     }
    235 #endif
    236 
    237     strcpy(command_ps + j, command_ps + j + 1);
     534        if ((delptr - delbuf) < DELBUFSIZ)
     535            *delptr++ = command_ps[j];
     536    }
     537#endif
     538
     539    memmove(command_ps + j, command_ps + j + 1,
     540            /* (command_len + 1 [because of NUL]) - (j + 1)
     541             * simplified into (command_len - j) */
     542            (command_len - j) * sizeof(command_ps[0]));
    238543    command_len--;
    239     input_end();                    /* rewrite new line */
    240     cmdedit_set_out_char(' ');      /* erase char */
     544    put_till_end_and_adv_cursor();
     545    /* Last char is still visible, erase it (and more) */
     546    printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
    241547    input_backward(cursor - j);     /* back to old pos cursor */
    242548}
     
    246552{
    247553    int ocursor;
    248     int j = delp - delbuf;
     554    int j = delptr - delbuf;
    249555
    250556    if (j == 0)
     
    252558    ocursor = cursor;
    253559    /* open hole and then fill it */
    254     memmove(command_ps + cursor + j, command_ps + cursor, command_len - cursor + 1);
    255     strncpy(command_ps + cursor, delbuf, j);
     560    memmove(command_ps + cursor + j, command_ps + cursor,
     561            (command_len - cursor + 1) * sizeof(command_ps[0]));
     562    memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0]));
    256563    command_len += j;
    257     input_end();                    /* rewrite new line */
     564    put_till_end_and_adv_cursor();
    258565    input_backward(cursor - ocursor - j + 1); /* at end of new text */
    259566}
     
    273580{
    274581    if (cursor < command_len)
    275         cmdedit_set_out_char(command_ps[cursor + 1]);
    276 }
    277 
     582        put_cur_glyph_and_inc_cursor();
     583}
    278584
    279585#if ENABLE_FEATURE_TAB_COMPLETION
    280586
    281 static char **matches;
    282 static unsigned num_matches;
     587//FIXME:
     588//needs to be more clever: currently it thinks that "foo\ b<TAB>
     589//matches the file named "foo bar", which is untrue.
     590//Also, perhaps "foo b<TAB> needs to complete to "foo bar" <cursor>,
     591//not "foo bar <cursor>...
    283592
    284593static void free_tab_completion_data(void)
     
    294603static void add_match(char *matched)
    295604{
    296     int nm = num_matches;
    297     int nm1 = nm + 1;
    298 
    299     matches = xrealloc(matches, nm1 * sizeof(char *));
    300     matches[nm] = matched;
     605    matches = xrealloc_vector(matches, 4, num_matches);
     606    matches[num_matches] = matched;
    301607    num_matches++;
    302608}
    303609
    304 #if ENABLE_FEATURE_USERNAME_COMPLETION
    305 static void username_tab_completion(char *ud, char *with_shash_flg)
     610# if ENABLE_FEATURE_USERNAME_COMPLETION
     611/* Replace "~user/..." with "/homedir/...".
     612 * The parameter is malloced, free it or return it
     613 * unchanged if no user is matched.
     614 */
     615static char *username_path_completion(char *ud)
    306616{
    307617    struct passwd *entry;
    308     int userlen;
    309 
    310     ud++;                           /* ~user/... to user/... */
     618    char *tilde_name = ud;
     619    char *home = NULL;
     620
     621    ud++; /* skip ~ */
     622    if (*ud == '/') {       /* "~/..." */
     623        home = home_pwd_buf;
     624    } else {
     625        /* "~user/..." */
     626        ud = strchr(ud, '/');
     627        *ud = '\0';           /* "~user" */
     628        entry = getpwnam(tilde_name + 1);
     629        *ud = '/';            /* restore "~user/..." */
     630        if (entry)
     631            home = entry->pw_dir;
     632    }
     633    if (home) {
     634        ud = concat_path_file(home, ud);
     635        free(tilde_name);
     636        tilde_name = ud;
     637    }
     638    return tilde_name;
     639}
     640
     641/* ~use<tab> - find all users with this prefix.
     642 * Return the length of the prefix used for matching.
     643 */
     644static NOINLINE unsigned complete_username(const char *ud)
     645{
     646    /* Using _r function to avoid pulling in static buffers */
     647    char line_buff[256];
     648    struct passwd pwd;
     649    struct passwd *result;
     650    unsigned userlen;
     651
     652    ud++; /* skip ~ */
    311653    userlen = strlen(ud);
    312654
    313     if (with_shash_flg) {           /* "~/..." or "~user/..." */
    314         char *sav_ud = ud - 1;
    315         char *home = NULL;
    316         char *temp;
    317 
    318         if (*ud == '/') {       /* "~/..."     */
    319             home = home_pwd_buf;
    320         } else {
    321             /* "~user/..." */
    322             temp = strchr(ud, '/');
    323             *temp = 0;              /* ~user\0 */
    324             entry = getpwnam(ud);
    325             *temp = '/';            /* restore ~user/... */
    326             ud = temp;
    327             if (entry)
    328                 home = entry->pw_dir;
    329         }
    330         if (home) {
    331             if ((userlen + strlen(home) + 1) < MAX_LINELEN) {
    332                 char temp2[MAX_LINELEN];     /* argument size */
    333 
    334                 /* /home/user/... */
    335                 sprintf(temp2, "%s%s", home, ud);
    336                 strcpy(sav_ud, temp2);
    337             }
    338         }
    339     } else {
    340         /* "~[^/]*" */
    341         /* Using _r function to avoid pulling in static buffers */
    342         char line_buff[256];
    343         struct passwd pwd;
    344         struct passwd *result;
    345 
    346         setpwent();
    347         while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
    348             /* Null usernames should result in all users as possible completions. */
    349             if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
    350                 add_match(xasprintf("~%s/", pwd.pw_name));
    351             }
    352         }
    353         endpwent();
    354     }
    355 }
    356 #endif  /* FEATURE_COMMAND_USERNAME_COMPLETION */
     655    setpwent();
     656    while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
     657        /* Null usernames should result in all users as possible completions. */
     658        if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
     659            add_match(xasprintf("~%s/", pwd.pw_name));
     660        }
     661    }
     662    endpwent();
     663
     664    return 1 + userlen;
     665}
     666# endif  /* FEATURE_USERNAME_COMPLETION */
    357667
    358668enum {
     
    362672};
    363673
    364 static int path_parse(char ***p, int flags)
     674static int path_parse(char ***p)
    365675{
    366676    int npth;
     
    369679    char **res;
    370680
    371     /* if not setenv PATH variable, to search cur dir "." */
    372     if (flags != FIND_EXE_ONLY)
    373         return 1;
    374 
    375681    if (state->flags & WITH_PATH_LOOKUP)
    376682        pth = state->path_lookup;
    377683    else
    378684        pth = getenv("PATH");
    379     /* PATH=<empty> or PATH=:<empty> */
     685
     686    /* PATH="" or PATH=":"? */
    380687    if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
    381688        return 1;
     
    387694        if (!tmp)
    388695            break;
    389         if (*++tmp == '\0')
     696        tmp++;
     697        if (*tmp == '\0')
    390698            break;  /* :<empty> */
    391699        npth++;
    392700    }
    393701
    394     res = xmalloc(npth * sizeof(char*));
     702    *p = res = xmalloc(npth * sizeof(res[0]));
    395703    res[0] = tmp = xstrdup(pth);
    396704    npth = 1;
     
    404712        res[npth++] = tmp;
    405713    }
    406     *p = res;
    407714    return npth;
    408715}
    409716
    410 static void exe_n_cwd_tab_completion(char *command, int type)
    411 {
    412     DIR *dir;
    413     struct dirent *next;
    414     char dirbuf[MAX_LINELEN];
    415     struct stat st;
     717/* Complete command, directory or file name.
     718 * Return the length of the prefix used for matching.
     719 */
     720static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
     721{
    416722    char *path1[1];
    417723    char **paths = path1;
    418724    int npaths;
    419725    int i;
    420     char *found;
    421     char *pfind = strrchr(command, '/');
     726    unsigned pf_len;
     727    const char *pfind;
     728    char *dirbuf = NULL;
    422729
    423730    npaths = 1;
    424731    path1[0] = (char*)".";
    425732
    426     if (pfind == NULL) {
    427         /* no dir, if flags==EXE_ONLY - get paths, else "." */
    428         npaths = path_parse(&paths, type);
     733    pfind = strrchr(command, '/');
     734    if (!pfind) {
     735        if (type == FIND_EXE_ONLY)
     736            npaths = path_parse(&paths);
    429737        pfind = command;
    430738    } else {
    431         /* dirbuf = ".../.../.../" */
    432         safe_strncpy(dirbuf, command, (pfind - command) + 2);
    433 #if ENABLE_FEATURE_USERNAME_COMPLETION
    434         if (dirbuf[0] == '~')   /* ~/... or ~user/... */
    435             username_tab_completion(dirbuf, dirbuf);
    436 #endif
    437         paths[0] = dirbuf;
    438739        /* point to 'l' in "..../last_component" */
    439740        pfind++;
    440     }
     741        /* dirbuf = ".../.../.../" */
     742        dirbuf = xstrndup(command, pfind - command);
     743# if ENABLE_FEATURE_USERNAME_COMPLETION
     744        if (dirbuf[0] == '~')   /* ~/... or ~user/... */
     745            dirbuf = username_path_completion(dirbuf);
     746# endif
     747        path1[0] = dirbuf;
     748    }
     749    pf_len = strlen(pfind);
    441750
    442751    for (i = 0; i < npaths; i++) {
     752        DIR *dir;
     753        struct dirent *next;
     754        struct stat st;
     755        char *found;
     756
    443757        dir = opendir(paths[i]);
    444         if (!dir)                       /* Don't print an error */
    445             continue;
     758        if (!dir)
     759            continue; /* don't print an error */
    446760
    447761        while ((next = readdir(dir)) != NULL) {
    448             int len1;
    449             const char *str_found = next->d_name;
    450 
    451             /* matched? */
    452             if (strncmp(str_found, pfind, strlen(pfind)))
     762            unsigned len;
     763            const char *name_found = next->d_name;
     764
     765            /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
     766            if (!pfind[0] && DOT_OR_DOTDOT(name_found))
    453767                continue;
    454             /* not see .name without .match */
    455             if (*str_found == '.' && *pfind == 0) {
    456                 if (NOT_LONE_CHAR(paths[i], '/') || str_found[1])
    457                     continue;
    458                 str_found = ""; /* only "/" */
    459             }
    460             found = concat_path_file(paths[i], str_found);
    461             /* hmm, remover in progress? */
    462             if (stat(found, &st) < 0)
    463                 goto cont;
    464             /* find with dirs? */
    465             if (paths[i] != dirbuf)
    466                 strcpy(found, next->d_name);    /* only name */
    467 
    468             len1 = strlen(found);
    469             found = xrealloc(found, len1 + 2);
    470             found[len1] = '\0';
    471             found[len1+1] = '\0';
     768            /* match? */
     769            if (strncmp(name_found, pfind, pf_len) != 0)
     770                continue; /* no */
     771
     772            found = concat_path_file(paths[i], name_found);
     773            /* NB: stat() first so that we see is it a directory;
     774             * but if that fails, use lstat() so that
     775             * we still match dangling links */
     776            if (stat(found, &st) && lstat(found, &st))
     777                goto cont; /* hmm, remove in progress? */
     778
     779            /* Save only name */
     780            len = strlen(name_found);
     781            found = xrealloc(found, len + 2); /* +2: for slash and NUL */
     782            strcpy(found, name_found);
    472783
    473784            if (S_ISDIR(st.st_mode)) {
    474                 /* name is directory      */
    475                 if (found[len1-1] != '/') {
    476                     found[len1] = '/';
    477                 }
     785                /* name is a directory, add slash */
     786                found[len] = '/';
     787                found[len + 1] = '\0';
    478788            } else {
    479                 /* not put found file if search only dirs for cd */
     789                /* skip files if looking for dirs only (example: cd) */
    480790                if (type == FIND_DIR_ONLY)
    481791                    goto cont;
    482792            }
    483             /* Add it to the list */
     793            /* add it to the list */
    484794            add_match(found);
    485795            continue;
     
    488798        }
    489799        closedir(dir);
    490     }
     800    } /* for every path */
     801
    491802    if (paths != path1) {
    492         free(paths[0]);                 /* allocated memory only in first member */
     803        free(paths[0]); /* allocated memory is only in first member */
    493804        free(paths);
    494805    }
    495 }
    496 
     806    free(dirbuf);
     807
     808    return pf_len;
     809}
     810
     811/* build_match_prefix:
     812 * On entry, match_buf contains everything up to cursor at the moment <tab>
     813 * was pressed. This function looks at it, figures out what part of it
     814 * constitutes the command/file/directory prefix to use for completion,
     815 * and rewrites match_buf to contain only that part.
     816 */
     817#define dbg_bmp 0
     818/* Helpers: */
     819/* QUOT is used on elements of int_buf[], which are bytes,
     820 * not Unicode chars. Therefore it works correctly even in Unicode mode.
     821 */
    497822#define QUOT (UCHAR_MAX+1)
    498 
    499 #define collapse_pos(is, in) { \
    500     memmove(int_buf+(is), int_buf+(in), (MAX_LINELEN+1-(is)-(in))*sizeof(int)); \
    501     memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in))*sizeof(int)); }
    502 
    503 static int find_match(char *matchBuf, int *len_with_quotes)
     823static void remove_chunk(int16_t *int_buf, int beg, int end)
     824{
     825    /* beg must be <= end */
     826    if (beg == end)
     827        return;
     828
     829    while ((int_buf[beg] = int_buf[end]) != 0)
     830        beg++, end++;
     831
     832    if (dbg_bmp) {
     833        int i;
     834        for (i = 0; int_buf[i]; i++)
     835            bb_putchar((unsigned char)int_buf[i]);
     836        bb_putchar('\n');
     837    }
     838}
     839/* Caller ensures that match_buf points to a malloced buffer
     840 * big enough to hold strlen(match_buf)*2 + 2
     841 */
     842static NOINLINE int build_match_prefix(char *match_buf)
    504843{
    505844    int i, j;
    506845    int command_mode;
    507     int c, c2;
    508     int int_buf[MAX_LINELEN + 1];
    509     int pos_buf[MAX_LINELEN + 1];
    510 
    511     /* set to integer dimension characters and own positions */
    512     for (i = 0;; i++) {
    513         int_buf[i] = (unsigned char)matchBuf[i];
    514         if (int_buf[i] == 0) {
    515             pos_buf[i] = -1;        /* indicator end line */
    516             break;
    517         }
    518         pos_buf[i] = i;
    519     }
    520 
    521     /* mask \+symbol and convert '\t' to ' ' */
    522     for (i = j = 0; matchBuf[i]; i++, j++)
    523         if (matchBuf[i] == '\\') {
    524             collapse_pos(j, j + 1);
    525             int_buf[j] |= QUOT;
     846    int16_t *int_buf = (int16_t*)match_buf;
     847
     848    if (dbg_bmp) printf("\n%s\n", match_buf);
     849
     850    /* Copy in reverse order, since they overlap */
     851    i = strlen(match_buf);
     852    do {
     853        int_buf[i] = (unsigned char)match_buf[i];
     854        i--;
     855    } while (i >= 0);
     856
     857    /* Mark every \c as "quoted c" */
     858    for (i = 0; int_buf[i]; i++) {
     859        if (int_buf[i] == '\\') {
     860            remove_chunk(int_buf, i, i + 1);
     861            int_buf[i] |= QUOT;
     862        }
     863    }
     864    /* Quote-mark "chars" and 'chars', drop delimiters */
     865    {
     866        int in_quote = 0;
     867        i = 0;
     868        while (int_buf[i]) {
     869            int cur = int_buf[i];
     870            if (!cur)
     871                break;
     872            if (cur == '\'' || cur == '"') {
     873                if (!in_quote || (cur == in_quote)) {
     874                    in_quote ^= cur;
     875                    remove_chunk(int_buf, i, i + 1);
     876                    continue;
     877                }
     878            }
     879            if (in_quote)
     880                int_buf[i] = cur | QUOT;
    526881            i++;
    527 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
    528             if (matchBuf[i] == '\t')        /* algorithm equivalent */
    529                 int_buf[j] = ' ' | QUOT;
    530 #endif
    531         }
    532 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
    533         else if (matchBuf[i] == '\t')
    534             int_buf[j] = ' ';
    535 #endif
    536 
    537     /* mask "symbols" or 'symbols' */
    538     c2 = 0;
     882        }
     883    }
     884
     885    /* Remove everything up to command delimiters:
     886     * ';' ';;' '&' '|' '&&' '||',
     887     * but careful with '>&' '<&' '>|'
     888     */
    539889    for (i = 0; int_buf[i]; i++) {
    540         c = int_buf[i];
    541         if (c == '\'' || c == '"') {
    542             if (c2 == 0)
    543                 c2 = c;
    544             else {
    545                 if (c == c2)
    546                     c2 = 0;
    547                 else
    548                     int_buf[i] |= QUOT;
     890        int cur = int_buf[i];
     891        if (cur == ';' || cur == '&' || cur == '|') {
     892            int prev = i ? int_buf[i - 1] : 0;
     893            if (cur == '&' && (prev == '>' || prev == '<')) {
     894                continue;
     895            } else if (cur == '|' && prev == '>') {
     896                continue;
    549897            }
    550         } else if (c2 != 0 && c != '$')
    551             int_buf[i] |= QUOT;
    552     }
    553 
    554     /* skip commands with arguments if line has commands delimiters */
    555     /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
     898            remove_chunk(int_buf, 0, i + 1 + (cur == int_buf[i + 1]));
     899            i = -1;  /* back to square 1 */
     900        }
     901    }
     902    /* Remove all `cmd` */
    556903    for (i = 0; int_buf[i]; i++) {
    557         c = int_buf[i];
    558         c2 = int_buf[i + 1];
    559         j = i ? int_buf[i - 1] : -1;
    560         command_mode = 0;
    561         if (c == ';' || c == '&' || c == '|') {
    562             command_mode = 1 + (c == c2);
    563             if (c == '&') {
    564                 if (j == '>' || j == '<')
    565                     command_mode = 0;
    566             } else if (c == '|' && j == '>')
    567                 command_mode = 0;
    568         }
    569         if (command_mode) {
    570             collapse_pos(0, i + command_mode);
    571             i = -1;                         /* hack incremet */
    572         }
    573     }
    574     /* collapse `command...` */
    575     for (i = 0; int_buf[i]; i++)
    576904        if (int_buf[i] == '`') {
    577             for (j = i + 1; int_buf[j]; j++)
     905            for (j = i + 1; int_buf[j]; j++) {
    578906                if (int_buf[j] == '`') {
    579                     collapse_pos(i, j + 1);
    580                     j = 0;
    581                     break;
     907                    /* `cmd` should count as a word:
     908                     * `cmd` c<tab> should search for files c*,
     909                     * not commands c*. Therefore we don't drop
     910                     * `cmd` entirely, we replace it with single `.
     911                     */
     912                    remove_chunk(int_buf, i, j);
     913                    goto next;
    582914                }
    583             if (j) {
    584                 /* not found close ` - command mode, collapse all previous */
    585                 collapse_pos(0, i + 1);
    586                 break;
    587             } else
    588                 i--;                    /* hack incremet */
    589         }
    590 
    591     /* collapse (command...(command...)...) or {command...{command...}...} */
    592     c = 0;                                          /* "recursive" level */
    593     c2 = 0;
    594     for (i = 0; int_buf[i]; i++)
     915            }
     916            /* No closing ` - command mode, remove all up to ` */
     917            remove_chunk(int_buf, 0, i + 1);
     918            break;
     919 next: ;
     920        }
     921    }
     922
     923    /* Remove "cmd (" and "cmd {"
     924     * Example: "if { c<tab>"
     925     * In this example, c should be matched as command pfx.
     926     */
     927    for (i = 0; int_buf[i]; i++) {
    595928        if (int_buf[i] == '(' || int_buf[i] == '{') {
    596             if (int_buf[i] == '(')
    597                 c++;
    598             else
    599                 c2++;
    600             collapse_pos(0, i + 1);
    601             i = -1;                         /* hack incremet */
    602         }
    603     for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
    604         if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
    605             if (int_buf[i] == ')')
    606                 c--;
    607             else
    608                 c2--;
    609             collapse_pos(0, i + 1);
    610             i = -1;                         /* hack incremet */
    611         }
    612 
    613     /* skip first not quote space */
     929            remove_chunk(int_buf, 0, i + 1);
     930            i = -1;  /* back to square 1 */
     931        }
     932    }
     933
     934    /* Remove leading unquoted spaces */
    614935    for (i = 0; int_buf[i]; i++)
    615936        if (int_buf[i] != ' ')
    616937            break;
    617     if (i)
    618         collapse_pos(0, i);
    619 
    620     /* set find mode for completion */
     938    remove_chunk(int_buf, 0, i);
     939
     940    /* Determine completion mode */
    621941    command_mode = FIND_EXE_ONLY;
    622     for (i = 0; int_buf[i]; i++)
     942    for (i = 0; int_buf[i]; i++) {
    623943        if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
    624             if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
    625              && matchBuf[pos_buf[0]]=='c'
    626              && matchBuf[pos_buf[1]]=='d'
     944            if (int_buf[i] == ' '
     945             && command_mode == FIND_EXE_ONLY
     946             && (char)int_buf[0] == 'c'
     947             && (char)int_buf[1] == 'd'
     948             && i == 2 /* -> int_buf[2] == ' ' */
    627949            ) {
    628950                command_mode = FIND_DIR_ONLY;
     
    632954            }
    633955        }
    634     for (i = 0; int_buf[i]; i++)
    635         /* "strlen" */;
    636     /* find last word */
     956    }
     957    if (dbg_bmp) printf("command_mode(0:exe/1:dir/2:file):%d\n", command_mode);
     958
     959    /* Remove everything except last word */
     960    for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
     961        continue;
    637962    for (--i; i >= 0; i--) {
    638         c = int_buf[i];
    639         if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
    640             collapse_pos(0, i + 1);
    641             break;
    642         }
    643     }
    644     /* skip first not quoted '\'' or '"' */
    645     for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
    646         /*skip*/;
    647     /* collapse quote or unquote // or /~ */
    648     while ((int_buf[i] & ~QUOT) == '/'
    649      && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
    650     ) {
     963        int cur = int_buf[i];
     964        if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') {
     965            remove_chunk(int_buf, 0, i + 1);
     966            break;
     967        }
     968    }
     969
     970    /* Convert back to string of _chars_ */
     971    i = 0;
     972    while ((match_buf[i] = int_buf[i]) != '\0')
    651973        i++;
    652     }
    653 
    654     /* set only match and destroy quotes */
    655     j = 0;
    656     for (c = 0; pos_buf[i] >= 0; i++) {
    657         matchBuf[c++] = matchBuf[pos_buf[i]];
    658         j = pos_buf[i] + 1;
    659     }
    660     matchBuf[c] = 0;
    661     /* old lenght matchBuf with quotes symbols */
    662     *len_with_quotes = j ? j - pos_buf[0] : 0;
     974
     975    if (dbg_bmp) printf("final match_buf:'%s'\n", match_buf);
    663976
    664977    return command_mode;
     
    666979
    667980/*
    668  * display by column (original idea from ls applet,
    669  * very optimized by me :)
     981 * Display by column (original idea from ls applet,
     982 * very optimized by me [Vladimir] :)
    670983 */
    671984static void showfiles(void)
     
    677990    int l;
    678991
    679     /* find the longest file name- use that as the column width */
     992    /* find the longest file name - use that as the column width */
    680993    for (row = 0; row < nrows; row++) {
    681         l = strlen(matches[row]);
     994        l = unicode_strwidth(matches[row]);
    682995        if (column_width < l)
    683996            column_width = l;
     
    6991012        for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
    7001013            printf("%s%-*s", matches[n],
    701                 (int)(column_width - strlen(matches[n])), "");
    702         }
    703         printf("%s\n", matches[n]);
    704     }
    705 }
    706 
    707 static char *add_quote_for_spec_chars(char *found)
     1014                (int)(column_width - unicode_strwidth(matches[n])), ""
     1015            );
     1016        }
     1017        if (ENABLE_UNICODE_SUPPORT)
     1018            puts(printable_string(NULL, matches[n]));
     1019        else
     1020            puts(matches[n]);
     1021    }
     1022}
     1023
     1024static const char *is_special_char(char c)
     1025{
     1026    return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c);
     1027}
     1028
     1029static char *quote_special_chars(char *found)
    7081030{
    7091031    int l = 0;
    710     char *s = xmalloc((strlen(found) + 1) * 2);
     1032    char *s = xzalloc((strlen(found) + 1) * 2);
    7111033
    7121034    while (*found) {
    713         if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
     1035        if (is_special_char(*found))
    7141036            s[l++] = '\\';
    7151037        s[l++] = *found++;
    7161038    }
    717     s[l] = 0;
     1039    /* s[l] = '\0'; - already is */
    7181040    return s;
    7191041}
    7201042
    721 static int match_compare(const void *a, const void *b)
    722 {
    723     return strcmp(*(char**)a, *(char**)b);
    724 }
    725 
    7261043/* Do TAB completion */
    727 static void input_tab(int *lastWasTab)
    728 {
     1044static NOINLINE void input_tab(smallint *lastWasTab)
     1045{
     1046    char *chosen_match;
     1047    char *match_buf;
     1048    size_t len_found;
     1049    /* Length of string used for matching */
     1050    unsigned match_pfx_len = match_pfx_len;
     1051    int find_type;
     1052# if ENABLE_UNICODE_SUPPORT
     1053    /* cursor pos in command converted to multibyte form */
     1054    int cursor_mb;
     1055# endif
    7291056    if (!(state->flags & TAB_COMPLETION))
    7301057        return;
    7311058
    732     if (!*lastWasTab) {
    733         char *tmp, *tmp1;
    734         int len_found;
    735         char matchBuf[MAX_LINELEN];
    736         int find_type;
    737         int recalc_pos;
    738 
    739         *lastWasTab = TRUE;             /* flop trigger */
    740 
    741         /* Make a local copy of the string -- up
    742          * to the position of the cursor */
    743         tmp = strncpy(matchBuf, command_ps, cursor);
    744         tmp[cursor] = '\0';
    745 
    746         find_type = find_match(matchBuf, &recalc_pos);
    747 
    748         /* Free up any memory already allocated */
    749         free_tab_completion_data();
    750 
    751 #if ENABLE_FEATURE_USERNAME_COMPLETION
    752         /* If the word starts with `~' and there is no slash in the word,
    753          * then try completing this word as a username. */
    754         if (state->flags & USERNAME_COMPLETION)
    755             if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
    756                 username_tab_completion(matchBuf, NULL);
    757 #endif
    758         /* Try to match any executable in our path and everything
    759          * in the current working directory */
    760         if (!matches)
    761             exe_n_cwd_tab_completion(matchBuf, find_type);
    762         /* Sort, then remove any duplicates found */
    763         if (matches) {
    764             int i, n = 0;
    765             qsort(matches, num_matches, sizeof(char*), match_compare);
    766             for (i = 0; i < num_matches - 1; ++i) {
    767                 if (matches[i] && matches[i+1]) { /* paranoia */
    768                     if (strcmp(matches[i], matches[i+1]) == 0) {
    769                         free(matches[i]);
    770                         matches[i] = NULL; /* paranoia */
    771                     } else {
    772                         matches[n++] = matches[i];
    773                     }
    774                 }
    775             }
    776             matches[n] = matches[i];
    777             num_matches = n + 1;
    778         }
    779         /* Did we find exactly one match? */
    780         if (!matches || num_matches > 1) {
    781             beep();
    782             if (!matches)
    783                 return;         /* not found */
    784             /* find minimal match */
    785         // ash: yet another failure in trying to achieve "we don't die on OOM"
    786             tmp1 = xstrdup(matches[0]);
    787             for (tmp = tmp1; *tmp; tmp++)
    788                 for (len_found = 1; len_found < num_matches; len_found++)
    789                     if (matches[len_found][(tmp - tmp1)] != *tmp) {
    790                         *tmp = '\0';
    791                         break;
    792                     }
    793             if (*tmp1 == '\0') {        /* have unique */
    794                 free(tmp1);
    795                 return;
    796             }
    797             tmp = add_quote_for_spec_chars(tmp1);
    798             free(tmp1);
    799         } else {                        /* one match */
    800             tmp = add_quote_for_spec_chars(matches[0]);
    801             /* for next completion current found */
    802             *lastWasTab = FALSE;
    803 
    804             len_found = strlen(tmp);
    805             if (tmp[len_found-1] != '/') {
    806                 tmp[len_found] = ' ';
    807                 tmp[len_found+1] = '\0';
    808             }
    809         }
    810         len_found = strlen(tmp);
    811         /* have space to placed match? */
    812         if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) {
    813             /* before word for match   */
    814             command_ps[cursor - recalc_pos] = 0;
    815             /* save   tail line        */
    816             strcpy(matchBuf, command_ps + cursor);
    817             /* add    match            */
    818             strcat(command_ps, tmp);
    819             /* add    tail             */
    820             strcat(command_ps, matchBuf);
    821             /* back to begin word for match    */
    822             input_backward(recalc_pos);
    823             /* new pos                         */
    824             recalc_pos = cursor + len_found;
    825             /* new len                         */
    826             command_len = strlen(command_ps);
    827             /* write out the matched command   */
    828             redraw(cmdedit_y, command_len - recalc_pos);
    829         }
    830         free(tmp);
    831     } else {
    832         /* Ok -- the last char was a TAB.  Since they
    833          * just hit TAB again, print a list of all the
    834          * available choices... */
    835         if (matches && num_matches > 0) {
    836             int sav_cursor = cursor;        /* change goto_new_line() */
    837 
    838             /* Go to the next line */
     1059    if (*lastWasTab) {
     1060        /* The last char was a TAB too.
     1061         * Print a list of all the available choices.
     1062         */
     1063        if (num_matches > 0) {
     1064            /* cursor will be changed by goto_new_line() */
     1065            int sav_cursor = cursor;
    8391066            goto_new_line();
    8401067            showfiles();
    8411068            redraw(0, command_len - sav_cursor);
    8421069        }
    843     }
    844 }
    845 
    846 #else
    847 #define input_tab(a) ((void)0)
    848 #endif  /* FEATURE_COMMAND_TAB_COMPLETION */
     1070        return;
     1071    }
     1072
     1073    *lastWasTab = 1;
     1074    chosen_match = NULL;
     1075
     1076    /* Make a local copy of the string up to the position of the cursor.
     1077     * build_match_prefix will expand it into int16_t's, need to allocate
     1078     * twice as much as the string_len+1.
     1079     * (we then also (ab)use this extra space later - see (**))
     1080     */
     1081    match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
     1082# if !ENABLE_UNICODE_SUPPORT
     1083    save_string(match_buf, cursor + 1); /* +1 for NUL */
     1084# else
     1085    {
     1086        CHAR_T wc = command_ps[cursor];
     1087        command_ps[cursor] = BB_NUL;
     1088        save_string(match_buf, MAX_LINELEN);
     1089        command_ps[cursor] = wc;
     1090        cursor_mb = strlen(match_buf);
     1091    }
     1092# endif
     1093    find_type = build_match_prefix(match_buf);
     1094
     1095    /* Free up any memory already allocated */
     1096    free_tab_completion_data();
     1097
     1098# if ENABLE_FEATURE_USERNAME_COMPLETION
     1099    /* If the word starts with ~ and there is no slash in the word,
     1100     * then try completing this word as a username. */
     1101    if (state->flags & USERNAME_COMPLETION)
     1102        if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL)
     1103            match_pfx_len = complete_username(match_buf);
     1104# endif
     1105    /* If complete_username() did not match,
     1106     * try to match a command in $PATH, or a directory, or a file */
     1107    if (!matches)
     1108        match_pfx_len = complete_cmd_dir_file(match_buf, find_type);
     1109
     1110    /* Account for backslashes which will be inserted
     1111     * by quote_special_chars() later */
     1112    {
     1113        const char *e = match_buf + strlen(match_buf);
     1114        const char *s = e - match_pfx_len;
     1115        while (s < e)
     1116            if (is_special_char(*s++))
     1117                match_pfx_len++;
     1118    }
     1119
     1120    /* Remove duplicates */
     1121    if (matches) {
     1122        unsigned i, n = 0;
     1123        qsort_string_vector(matches, num_matches);
     1124        for (i = 0; i < num_matches - 1; ++i) {
     1125            //if (matches[i] && matches[i+1]) { /* paranoia */
     1126                if (strcmp(matches[i], matches[i+1]) == 0) {
     1127                    free(matches[i]);
     1128                    //matches[i] = NULL; /* paranoia */
     1129                } else {
     1130                    matches[n++] = matches[i];
     1131                }
     1132            //}
     1133        }
     1134        matches[n++] = matches[i];
     1135        num_matches = n;
     1136    }
     1137
     1138    /* Did we find exactly one match? */
     1139    if (num_matches != 1) { /* no */
     1140        char *cp;
     1141        beep();
     1142        if (!matches)
     1143            goto ret; /* no matches at all */
     1144        /* Find common prefix */
     1145        chosen_match = xstrdup(matches[0]);
     1146        for (cp = chosen_match; *cp; cp++) {
     1147            unsigned n;
     1148            for (n = 1; n < num_matches; n++) {
     1149                if (matches[n][cp - chosen_match] != *cp) {
     1150                    goto stop;
     1151                }
     1152            }
     1153        }
     1154 stop:
     1155        if (cp == chosen_match) { /* have unique prefix? */
     1156            goto ret; /* no */
     1157        }
     1158        *cp = '\0';
     1159        cp = quote_special_chars(chosen_match);
     1160        free(chosen_match);
     1161        chosen_match = cp;
     1162        len_found = strlen(chosen_match);
     1163    } else {                        /* exactly one match */
     1164        /* Next <tab> is not a double-tab */
     1165        *lastWasTab = 0;
     1166
     1167        chosen_match = quote_special_chars(matches[0]);
     1168        len_found = strlen(chosen_match);
     1169        if (chosen_match[len_found-1] != '/') {
     1170            chosen_match[len_found] = ' ';
     1171            chosen_match[++len_found] = '\0';
     1172        }
     1173    }
     1174
     1175# if !ENABLE_UNICODE_SUPPORT
     1176    /* Have space to place the match? */
     1177    /* The result consists of three parts with these lengths: */
     1178    /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */
     1179    /* it simplifies into: */
     1180    if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) {
     1181        int pos;
     1182        /* save tail */
     1183        strcpy(match_buf, &command_ps[cursor]);
     1184        /* add match and tail */
     1185        sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf);
     1186        command_len = strlen(command_ps);
     1187        /* new pos */
     1188        pos = cursor + len_found - match_pfx_len;
     1189        /* write out the matched command */
     1190        redraw(cmdedit_y, command_len - pos);
     1191    }
     1192# else
     1193    {
     1194        /* Use 2nd half of match_buf as scratch space - see (**) */
     1195        char *command = match_buf + MAX_LINELEN;
     1196        int len = save_string(command, MAX_LINELEN);
     1197        /* Have space to place the match? */
     1198        /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */
     1199        if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) {
     1200            int pos;
     1201            /* save tail */
     1202            strcpy(match_buf, &command[cursor_mb]);
     1203            /* where do we want to have cursor after all? */
     1204            strcpy(&command[cursor_mb], chosen_match + match_pfx_len);
     1205            len = load_string(command, S.maxsize);
     1206            /* add match and tail */
     1207            sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf);
     1208            command_len = load_string(command, S.maxsize);
     1209            /* write out the matched command */
     1210            /* paranoia: load_string can return 0 on conv error,
     1211             * prevent passing pos = (0 - 12) to redraw */
     1212            pos = command_len - len;
     1213            redraw(cmdedit_y, pos >= 0 ? pos : 0);
     1214        }
     1215    }
     1216# endif
     1217 ret:
     1218    free(chosen_match);
     1219    free(match_buf);
     1220}
     1221
     1222#endif  /* FEATURE_TAB_COMPLETION */
     1223
     1224
     1225line_input_t* FAST_FUNC new_line_input_t(int flags)
     1226{
     1227    line_input_t *n = xzalloc(sizeof(*n));
     1228    n->flags = flags;
     1229    return n;
     1230}
    8491231
    8501232
    8511233#if MAX_HISTORY > 0
    8521234
     1235static void save_command_ps_at_cur_history(void)
     1236{
     1237    if (command_ps[0] != BB_NUL) {
     1238        int cur = state->cur_history;
     1239        free(state->history[cur]);
     1240
     1241# if ENABLE_UNICODE_SUPPORT
     1242        {
     1243            char tbuf[MAX_LINELEN];
     1244            save_string(tbuf, sizeof(tbuf));
     1245            state->history[cur] = xstrdup(tbuf);
     1246        }
     1247# else
     1248        state->history[cur] = xstrdup(command_ps);
     1249# endif
     1250    }
     1251}
     1252
    8531253/* state->flags is already checked to be nonzero */
    854 static void get_previous_history(void)
    855 {
    856     if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) {
    857         free(state->history[state->cur_history]);
    858         state->history[state->cur_history] = xstrdup(command_ps);
    859     }
    860     state->cur_history--;
    861 }
    862 
    863 static int get_next_history(void)
    864 {
    865     if (state->flags & DO_HISTORY) {
    866         int ch = state->cur_history;
    867         if (ch < state->cnt_history) {
    868             get_previous_history(); /* save the current history line */
    869             state->cur_history = ch + 1;
    870             return state->cur_history;
    871         }
     1254static int get_previous_history(void)
     1255{
     1256    if ((state->flags & DO_HISTORY) && state->cur_history) {
     1257        save_command_ps_at_cur_history();
     1258        state->cur_history--;
     1259        return 1;
    8721260    }
    8731261    beep();
     
    8751263}
    8761264
    877 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
     1265static int get_next_history(void)
     1266{
     1267    if (state->flags & DO_HISTORY) {
     1268        if (state->cur_history < state->cnt_history) {
     1269            save_command_ps_at_cur_history(); /* save the current history line */
     1270            return ++state->cur_history;
     1271        }
     1272    }
     1273    beep();
     1274    return 0;
     1275}
     1276
     1277# if ENABLE_FEATURE_EDITING_SAVEHISTORY
     1278/* We try to ensure that concurrent additions to the history
     1279 * do not overwrite each other.
     1280 * Otherwise shell users get unhappy.
     1281 *
     1282 * History file is trimmed lazily, when it grows several times longer
     1283 * than configured MAX_HISTORY lines.
     1284 */
     1285
     1286static void free_line_input_t(line_input_t *n)
     1287{
     1288    int i = n->cnt_history;
     1289    while (i > 0)
     1290        free(n->history[--i]);
     1291    free(n);
     1292}
     1293
    8781294/* state->flags is already checked to be nonzero */
    879 static void load_history(const char *fromfile)
    880 {
     1295static void load_history(line_input_t *st_parm)
     1296{
     1297    char *temp_h[MAX_HISTORY];
     1298    char *line;
    8811299    FILE *fp;
    882     int hi;
    883 
    884     /* cleanup old */
    885     for (hi = state->cnt_history; hi > 0;) {
    886         hi--;
    887         free(state->history[hi]);
    888     }
    889 
    890     fp = fopen(fromfile, "r");
     1300    unsigned idx, i, line_len;
     1301
     1302    /* NB: do not trash old history if file can't be opened */
     1303
     1304    fp = fopen_for_read(st_parm->hist_file);
    8911305    if (fp) {
    892         for (hi = 0; hi < MAX_HISTORY;) {
    893             char *hl = xmalloc_getline(fp);
    894             int l;
    895 
    896             if (!hl)
    897                 break;
    898             l = strlen(hl);
    899             if (l >= MAX_LINELEN)
    900                 hl[MAX_LINELEN-1] = '\0';
    901             if (l == 0 || hl[0] == ' ') {
    902                 free(hl);
     1306        /* clean up old history */
     1307        for (idx = st_parm->cnt_history; idx > 0;) {
     1308            idx--;
     1309            free(st_parm->history[idx]);
     1310            st_parm->history[idx] = NULL;
     1311        }
     1312
     1313        /* fill temp_h[], retaining only last MAX_HISTORY lines */
     1314        memset(temp_h, 0, sizeof(temp_h));
     1315        st_parm->cnt_history_in_file = idx = 0;
     1316        while ((line = xmalloc_fgetline(fp)) != NULL) {
     1317            if (line[0] == '\0') {
     1318                free(line);
    9031319                continue;
    9041320            }
    905             state->history[hi++] = hl;
     1321            free(temp_h[idx]);
     1322            temp_h[idx] = line;
     1323            st_parm->cnt_history_in_file++;
     1324            idx++;
     1325            if (idx == MAX_HISTORY)
     1326                idx = 0;
    9061327        }
    9071328        fclose(fp);
    908     }
    909     state->cur_history = state->cnt_history = hi;
     1329
     1330        /* find first non-NULL temp_h[], if any */
     1331        if (st_parm->cnt_history_in_file) {
     1332            while (temp_h[idx] == NULL) {
     1333                idx++;
     1334                if (idx == MAX_HISTORY)
     1335                    idx = 0;
     1336            }
     1337        }
     1338
     1339        /* copy temp_h[] to st_parm->history[] */
     1340        for (i = 0; i < MAX_HISTORY;) {
     1341            line = temp_h[idx];
     1342            if (!line)
     1343                break;
     1344            idx++;
     1345            if (idx == MAX_HISTORY)
     1346                idx = 0;
     1347            line_len = strlen(line);
     1348            if (line_len >= MAX_LINELEN)
     1349                line[MAX_LINELEN-1] = '\0';
     1350            st_parm->history[i++] = line;
     1351        }
     1352        st_parm->cnt_history = i;
     1353    }
    9101354}
    9111355
    9121356/* state->flags is already checked to be nonzero */
    913 static void save_history(const char *tofile)
    914 {
    915     FILE *fp;
    916 
    917     fp = fopen(tofile, "w");
    918     if (fp) {
    919         int i;
    920 
    921         for (i = 0; i < state->cnt_history; i++) {
    922             fprintf(fp, "%s\n", state->history[i]);
    923         }
    924         fclose(fp);
    925     }
    926 }
    927 #else
    928 #define load_history(a) ((void)0)
    929 #define save_history(a) ((void)0)
    930 #endif /* FEATURE_COMMAND_SAVEHISTORY */
    931 
    932 static void remember_in_history(const char *str)
     1357static void save_history(char *str)
     1358{
     1359    int fd;
     1360    int len, len2;
     1361
     1362    fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
     1363    if (fd < 0)
     1364        return;
     1365    xlseek(fd, 0, SEEK_END); /* paranoia */
     1366    len = strlen(str);
     1367    str[len] = '\n'; /* we (try to) do atomic write */
     1368    len2 = full_write(fd, str, len + 1);
     1369    str[len] = '\0';
     1370    close(fd);
     1371    if (len2 != len + 1)
     1372        return; /* "wtf?" */
     1373
     1374    /* did we write so much that history file needs trimming? */
     1375    state->cnt_history_in_file++;
     1376    if (state->cnt_history_in_file > MAX_HISTORY * 4) {
     1377        char *new_name;
     1378        line_input_t *st_temp;
     1379
     1380        /* we may have concurrently written entries from others.
     1381         * load them */
     1382        st_temp = new_line_input_t(state->flags);
     1383        st_temp->hist_file = state->hist_file;
     1384        load_history(st_temp);
     1385
     1386        /* write out temp file and replace hist_file atomically */
     1387        new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
     1388        fd = open(state->hist_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
     1389        if (fd >= 0) {
     1390            FILE *fp;
     1391            int i;
     1392
     1393            fp = xfdopen_for_write(fd);
     1394            for (i = 0; i < st_temp->cnt_history; i++)
     1395                fprintf(fp, "%s\n", st_temp->history[i]);
     1396            fclose(fp);
     1397            if (rename(new_name, state->hist_file) == 0)
     1398                state->cnt_history_in_file = st_temp->cnt_history;
     1399        }
     1400        free(new_name);
     1401        free_line_input_t(st_temp);
     1402    }
     1403}
     1404# else
     1405#  define load_history(a) ((void)0)
     1406#  define save_history(a) ((void)0)
     1407# endif /* FEATURE_COMMAND_SAVEHISTORY */
     1408
     1409static void remember_in_history(char *str)
    9331410{
    9341411    int i;
     
    9361413    if (!(state->flags & DO_HISTORY))
    9371414        return;
    938 
     1415    if (str[0] == '\0')
     1416        return;
    9391417    i = state->cnt_history;
    940     free(state->history[MAX_HISTORY]);
    941     state->history[MAX_HISTORY] = NULL;
    942     /* After max history, remove the oldest command */
     1418    /* Don't save dupes */
     1419    if (i && strcmp(state->history[i-1], str) == 0)
     1420        return;
     1421
     1422    free(state->history[MAX_HISTORY]); /* redundant, paranoia */
     1423    state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */
     1424
     1425    /* If history[] is full, remove the oldest command */
     1426    /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */
    9431427    if (i >= MAX_HISTORY) {
    9441428        free(state->history[0]);
    9451429        for (i = 0; i < MAX_HISTORY-1; i++)
    9461430            state->history[i] = state->history[i+1];
    947     }
    948 // Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
    949 // (i.e. do not save dups?)
     1431        /* i == MAX_HISTORY-1 */
     1432    }
     1433    /* i <= MAX_HISTORY-1 */
    9501434    state->history[i++] = xstrdup(str);
     1435    /* i <= MAX_HISTORY */
    9511436    state->cur_history = i;
    9521437    state->cnt_history = i;
    953 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
     1438# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
    9541439    if ((state->flags & SAVE_HISTORY) && state->hist_file)
    955         save_history(state->hist_file);
    956 #endif
    957     USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
     1440        save_history(str);
     1441# endif
     1442    IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
    9581443}
    9591444
    9601445#else /* MAX_HISTORY == 0 */
    961 #define remember_in_history(a) ((void)0)
     1446# define remember_in_history(a) ((void)0)
    9621447#endif /* MAX_HISTORY */
    9631448
    9641449
     1450#if ENABLE_FEATURE_EDITING_VI
    9651451/*
    966  * This function is used to grab a character buffer
    967  * from the input file descriptor and allows you to
    968  * a string with full command editing (sort of like
    969  * a mini readline).
    970  *
    971  * The following standard commands are not implemented:
    972  * ESC-b -- Move back one word
    973  * ESC-f -- Move forward one word
    974  * ESC-d -- Delete back one word
    975  * ESC-h -- Delete forward one word
    976  * CTL-t -- Transpose two characters
    977  *
    978  * Minimalist vi-style command line editing available if configured.
    9791452 * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
    9801453 */
    981 
    982 #if ENABLE_FEATURE_EDITING_VI
    9831454static void
    984 vi_Word_motion(char *command, int eat)
    985 {
    986     while (cursor < command_len && !isspace(command[cursor]))
     1455vi_Word_motion(int eat)
     1456{
     1457    CHAR_T *command = command_ps;
     1458
     1459    while (cursor < command_len && !BB_isspace(command[cursor]))
    9871460        input_forward();
    988     if (eat) while (cursor < command_len && isspace(command[cursor]))
     1461    if (eat) while (cursor < command_len && BB_isspace(command[cursor]))
    9891462        input_forward();
    9901463}
    9911464
    9921465static void
    993 vi_word_motion(char *command, int eat)
    994 {
    995     if (isalnum(command[cursor]) || command[cursor] == '_') {
     1466vi_word_motion(int eat)
     1467{
     1468    CHAR_T *command = command_ps;
     1469
     1470    if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
    9961471        while (cursor < command_len
    997          && (isalnum(command[cursor+1]) || command[cursor+1] == '_'))
     1472         && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_')
     1473        ) {
    9981474            input_forward();
    999     } else if (ispunct(command[cursor])) {
    1000         while (cursor < command_len && ispunct(command[cursor+1]))
     1475        }
     1476    } else if (BB_ispunct(command[cursor])) {
     1477        while (cursor < command_len && BB_ispunct(command[cursor+1]))
    10011478            input_forward();
    10021479    }
     
    10051482        input_forward();
    10061483
    1007     if (eat && cursor < command_len && isspace(command[cursor]))
    1008         while (cursor < command_len && isspace(command[cursor]))
     1484    if (eat) {
     1485        while (cursor < command_len && BB_isspace(command[cursor]))
    10091486            input_forward();
     1487    }
    10101488}
    10111489
    10121490static void
    1013 vi_End_motion(char *command)
    1014 {
     1491vi_End_motion(void)
     1492{
     1493    CHAR_T *command = command_ps;
     1494
    10151495    input_forward();
    1016     while (cursor < command_len && isspace(command[cursor]))
     1496    while (cursor < command_len && BB_isspace(command[cursor]))
    10171497        input_forward();
    1018     while (cursor < command_len-1 && !isspace(command[cursor+1]))
     1498    while (cursor < command_len-1 && !BB_isspace(command[cursor+1]))
    10191499        input_forward();
    10201500}
    10211501
    10221502static void
    1023 vi_end_motion(char *command)
    1024 {
     1503vi_end_motion(void)
     1504{
     1505    CHAR_T *command = command_ps;
     1506
    10251507    if (cursor >= command_len-1)
    10261508        return;
    10271509    input_forward();
    1028     while (cursor < command_len-1 && isspace(command[cursor]))
     1510    while (cursor < command_len-1 && BB_isspace(command[cursor]))
    10291511        input_forward();
    10301512    if (cursor >= command_len-1)
    10311513        return;
    1032     if (isalnum(command[cursor]) || command[cursor] == '_') {
     1514    if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
    10331515        while (cursor < command_len-1
    1034          && (isalnum(command[cursor+1]) || command[cursor+1] == '_')
     1516         && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_')
    10351517        ) {
    10361518            input_forward();
    10371519        }
    1038     } else if (ispunct(command[cursor])) {
    1039         while (cursor < command_len-1 && ispunct(command[cursor+1]))
     1520    } else if (BB_ispunct(command[cursor])) {
     1521        while (cursor < command_len-1 && BB_ispunct(command[cursor+1]))
    10401522            input_forward();
    10411523    }
     
    10431525
    10441526static void
    1045 vi_Back_motion(char *command)
    1046 {
    1047     while (cursor > 0 && isspace(command[cursor-1]))
     1527vi_Back_motion(void)
     1528{
     1529    CHAR_T *command = command_ps;
     1530
     1531    while (cursor > 0 && BB_isspace(command[cursor-1]))
    10481532        input_backward(1);
    1049     while (cursor > 0 && !isspace(command[cursor-1]))
     1533    while (cursor > 0 && !BB_isspace(command[cursor-1]))
    10501534        input_backward(1);
    10511535}
    10521536
    10531537static void
    1054 vi_back_motion(char *command)
    1055 {
     1538vi_back_motion(void)
     1539{
     1540    CHAR_T *command = command_ps;
     1541
    10561542    if (cursor <= 0)
    10571543        return;
    10581544    input_backward(1);
    1059     while (cursor > 0 && isspace(command[cursor]))
     1545    while (cursor > 0 && BB_isspace(command[cursor]))
    10601546        input_backward(1);
    10611547    if (cursor <= 0)
    10621548        return;
    1063     if (isalnum(command[cursor]) || command[cursor] == '_') {
     1549    if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
    10641550        while (cursor > 0
    1065          && (isalnum(command[cursor-1]) || command[cursor-1] == '_')
     1551         && (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_')
    10661552        ) {
    10671553            input_backward(1);
    10681554        }
    1069     } else if (ispunct(command[cursor])) {
    1070         while (cursor > 0 && ispunct(command[cursor-1]))
     1555    } else if (BB_ispunct(command[cursor])) {
     1556        while (cursor > 0 && BB_ispunct(command[cursor-1]))
    10711557            input_backward(1);
    10721558    }
    10731559}
    10741560#endif
     1561
     1562/* Modelled after bash 4.0 behavior of Ctrl-<arrow> */
     1563static void ctrl_left(void)
     1564{
     1565    CHAR_T *command = command_ps;
     1566
     1567    while (1) {
     1568        CHAR_T c;
     1569
     1570        input_backward(1);
     1571        if (cursor == 0)
     1572            break;
     1573        c = command[cursor];
     1574        if (c != ' ' && !BB_ispunct(c)) {
     1575            /* we reached a "word" delimited by spaces/punct.
     1576             * go to its beginning */
     1577            while (1) {
     1578                c = command[cursor - 1];
     1579                if (c == ' ' || BB_ispunct(c))
     1580                    break;
     1581                input_backward(1);
     1582                if (cursor == 0)
     1583                    break;
     1584            }
     1585            break;
     1586        }
     1587    }
     1588}
     1589static void ctrl_right(void)
     1590{
     1591    CHAR_T *command = command_ps;
     1592
     1593    while (1) {
     1594        CHAR_T c;
     1595
     1596        c = command[cursor];
     1597        if (c == BB_NUL)
     1598            break;
     1599        if (c != ' ' && !BB_ispunct(c)) {
     1600            /* we reached a "word" delimited by spaces/punct.
     1601             * go to its end + 1 */
     1602            while (1) {
     1603                input_forward();
     1604                c = command[cursor];
     1605                if (c == BB_NUL || c == ' ' || BB_ispunct(c))
     1606                    break;
     1607            }
     1608            break;
     1609        }
     1610        input_forward();
     1611    }
     1612}
    10751613
    10761614
     
    10791617 */
    10801618
     1619#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
     1620static void ask_terminal(void)
     1621{
     1622    /* Ask terminal where is the cursor now.
     1623     * lineedit_read_key handles response and corrects
     1624     * our idea of current cursor position.
     1625     * Testcase: run "echo -n long_line_long_line_long_line",
     1626     * then type in a long, wrapping command and try to
     1627     * delete it using backspace key.
     1628     * Note: we print it _after_ prompt, because
     1629     * prompt may contain CR. Example: PS1='\[\r\n\]\w '
     1630     */
     1631    /* Problem: if there is buffered input on stdin,
     1632     * the response will be delivered later,
     1633     * possibly to an unsuspecting application.
     1634     * Testcase: "sleep 1; busybox ash" + press and hold [Enter].
     1635     * Result:
     1636     * ~/srcdevel/bbox/fix/busybox.t4 #
     1637     * ~/srcdevel/bbox/fix/busybox.t4 #
     1638     * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 #  <-- garbage
     1639     * ~/srcdevel/bbox/fix/busybox.t4 #
     1640     *
     1641     * Checking for input with poll only makes the race narrower,
     1642     * I still can trigger it. Strace:
     1643     *
     1644     * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33
     1645     * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout)  <-- no input exists
     1646     * write(1, "\33[6n", 4) = 4  <-- send the ESC sequence, quick!
     1647     * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}])
     1648     * read(0, "\n", 1)      = 1  <-- oh crap, user's input got in first
     1649     */
     1650    struct pollfd pfd;
     1651
     1652    pfd.fd = STDIN_FILENO;
     1653    pfd.events = POLLIN;
     1654    if (safe_poll(&pfd, 1, 0) == 0) {
     1655        S.sent_ESC_br6n = 1;
     1656        fputs(ESC"[6n", stdout);
     1657        fflush_all(); /* make terminal see it ASAP! */
     1658    }
     1659}
     1660#else
     1661#define ask_terminal() ((void)0)
     1662#endif
     1663
    10811664#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
    1082 static void parse_prompt(const char *prmt_ptr)
     1665static void parse_and_put_prompt(const char *prmt_ptr)
    10831666{
    10841667    cmdedit_prompt = prmt_ptr;
     
    10871670}
    10881671#else
    1089 static void parse_prompt(const char *prmt_ptr)
     1672static void parse_and_put_prompt(const char *prmt_ptr)
    10901673{
    10911674    int prmt_len = 0;
     
    10931676    char flg_not_length = '[';
    10941677    char *prmt_mem_ptr = xzalloc(1);
    1095     char *pwd_buf = xrealloc_getcwd_or_warn(NULL);
    1096     char buf2[PATH_MAX + 1];
    1097     char buf[2];
     1678    char *cwd_buf = xrealloc_getcwd_or_warn(NULL);
     1679    char cbuf[2];
    10981680    char c;
    10991681    char *pbuf;
     
    11011683    cmdedit_prmt_len = 0;
    11021684
    1103     if (!pwd_buf) {
    1104         pwd_buf = (char *)bb_msg_unknown;
    1105     }
     1685    if (!cwd_buf) {
     1686        cwd_buf = (char *)bb_msg_unknown;
     1687    }
     1688
     1689    cbuf[1] = '\0'; /* never changes */
    11061690
    11071691    while (*prmt_ptr) {
    1108         pbuf = buf;
    1109         pbuf[1] = 0;
     1692        char *free_me = NULL;
     1693
     1694        pbuf = cbuf;
    11101695        c = *prmt_ptr++;
    11111696        if (c == '\\') {
     
    11151700            c = bb_process_escape_sequence(&prmt_ptr);
    11161701            if (prmt_ptr == cp) {
    1117                 if (*cp == 0)
     1702                if (*cp == '\0')
    11181703                    break;
    11191704                c = *prmt_ptr++;
     1705
    11201706                switch (c) {
    1121 #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
     1707# if ENABLE_USERNAME_OR_HOMEDIR
    11221708                case 'u':
    11231709                    pbuf = user_buf ? user_buf : (char*)"";
    11241710                    break;
    1125 #endif
     1711# endif
    11261712                case 'h':
    1127                     pbuf = hostname_buf;
    1128                     if (!pbuf) {
    1129                         pbuf = xzalloc(256);
    1130                         if (gethostname(pbuf, 255) < 0) {
    1131                             strcpy(pbuf, "?");
    1132                         } else {
    1133                             char *s = strchr(pbuf, '.');
    1134                             if (s)
    1135                                 *s = '\0';
    1136                         }
    1137                         hostname_buf = pbuf;
    1138                     }
     1713                    pbuf = free_me = safe_gethostname();
     1714                    *strchrnul(pbuf, '.') = '\0';
    11391715                    break;
    11401716                case '$':
    11411717                    c = (geteuid() == 0 ? '#' : '$');
    11421718                    break;
    1143 #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
     1719# if ENABLE_USERNAME_OR_HOMEDIR
    11441720                case 'w':
    1145                     pbuf = pwd_buf;
     1721                    /* /home/user[/something] -> ~[/something] */
     1722                    pbuf = cwd_buf;
    11461723                    l = strlen(home_pwd_buf);
    11471724                    if (l != 0
    1148                      && strncmp(home_pwd_buf, pbuf, l) == 0
    1149                      && (pbuf[l]=='/' || pbuf[l]=='\0')
    1150                      && strlen(pwd_buf+l)<PATH_MAX
     1725                     && strncmp(home_pwd_buf, cwd_buf, l) == 0
     1726                     && (cwd_buf[l]=='/' || cwd_buf[l]=='\0')
     1727                     && strlen(cwd_buf + l) < PATH_MAX
    11511728                    ) {
    1152                         pbuf = buf2;
    1153                         *pbuf = '~';
    1154                         strcpy(pbuf+1, pwd_buf+l);
     1729                        pbuf = free_me = xasprintf("~%s", cwd_buf + l);
    11551730                    }
    11561731                    break;
    1157 #endif
     1732# endif
    11581733                case 'W':
    1159                     pbuf = pwd_buf;
     1734                    pbuf = cwd_buf;
    11601735                    cp = strrchr(pbuf, '/');
    11611736                    if (cp != NULL && cp != pbuf)
     
    11631738                    break;
    11641739                case '!':
    1165                     pbuf = buf2;
    1166                     snprintf(buf2, sizeof(buf2), "%d", num_ok_lines);
     1740                    pbuf = free_me = xasprintf("%d", num_ok_lines);
    11671741                    break;
    11681742                case 'e': case 'E':     /* \e \E = \033 */
    11691743                    c = '\033';
    11701744                    break;
    1171                 case 'x': case 'X':
     1745                case 'x': case 'X': {
     1746                    char buf2[4];
    11721747                    for (l = 0; l < 3;) {
    1173                         int h;
     1748                        unsigned h;
    11741749                        buf2[l++] = *prmt_ptr;
    1175                         buf2[l] = 0;
    1176                         h = strtol(buf2, &pbuf, 16);
     1750                        buf2[l] = '\0';
     1751                        h = strtoul(buf2, &pbuf, 16);
    11771752                        if (h > UCHAR_MAX || (pbuf - buf2) < l) {
    1178                             l--;
     1753                            buf2[--l] = '\0';
    11791754                            break;
    11801755                        }
    11811756                        prmt_ptr++;
    11821757                    }
    1183                     buf2[l] = 0;
    1184                     c = (char)strtol(buf2, NULL, 16);
     1758                    c = (char)strtoul(buf2, NULL, 16);
    11851759                    if (c == 0)
    11861760                        c = '?';
    1187                     pbuf = buf;
     1761                    pbuf = cbuf;
    11881762                    break;
     1763                }
    11891764                case '[': case ']':
    11901765                    if (c == flg_not_length) {
    1191                         flg_not_length = flg_not_length == '[' ? ']' : '[';
     1766                        flg_not_length = (flg_not_length == '[' ? ']' : '[');
    11921767                        continue;
    11931768                    }
    11941769                    break;
    1195                 }
    1196             }
    1197         }
    1198         if (pbuf == buf)
    1199             *pbuf = c;
     1770                } /* switch */
     1771            } /* if */
     1772        } /* if */
     1773        cbuf[0] = c;
    12001774        cur_prmt_len = strlen(pbuf);
    12011775        prmt_len += cur_prmt_len;
     
    12031777            cmdedit_prmt_len += cur_prmt_len;
    12041778        prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
    1205     }
    1206     if (pwd_buf != (char *)bb_msg_unknown)
    1207         free(pwd_buf);
     1779        free(free_me);
     1780    } /* while */
     1781
     1782    if (cwd_buf != (char *)bb_msg_unknown)
     1783        free(cwd_buf);
    12081784    cmdedit_prompt = prmt_mem_ptr;
    12091785    put_prompt();
    12101786}
    12111787#endif
    1212 
    1213 #define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
    1214 #define getTermSettings(fd, argp) tcgetattr(fd, argp);
    1215 
    1216 static sighandler_t previous_SIGWINCH_handler;
    12171788
    12181789static void cmdedit_setwidth(unsigned w, int redraw_flg)
     
    12241795        /* redraw */
    12251796        redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
    1226         fflush(stdout);
     1797        fflush_all();
    12271798    }
    12281799}
     
    12301801static void win_changed(int nsig)
    12311802{
    1232     int width;
     1803    int sv_errno = errno;
     1804    unsigned width;
    12331805    get_terminal_width_height(0, &width, NULL);
    12341806    cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
    12351807    if (nsig == SIGWINCH)
    12361808        signal(SIGWINCH, win_changed); /* rearm ourself */
    1237 }
    1238 
    1239 /*
    1240  * The emacs and vi modes share much of the code in the big
    1241  * command loop.  Commands entered when in vi's command mode (aka
    1242  * "escape mode") get an extra bit added to distinguish them --
    1243  * this keeps them from being self-inserted.  This clutters the
    1244  * big switch a bit, but keeps all the code in one place.
    1245  */
    1246 
    1247 #define vbit 0x100
     1809    errno = sv_errno;
     1810}
     1811
     1812static int lineedit_read_key(char *read_key_buffer)
     1813{
     1814    int64_t ic;
     1815    int timeout = -1;
     1816#if ENABLE_UNICODE_SUPPORT
     1817    char unicode_buf[MB_CUR_MAX + 1];
     1818    int unicode_idx = 0;
     1819#endif
     1820
     1821    while (1) {
     1822        /* Wait for input. TIMEOUT = -1 makes read_key wait even
     1823         * on nonblocking stdin, TIMEOUT = 50 makes sure we won't
     1824         * insist on full MB_CUR_MAX buffer to declare input like
     1825         * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls".
     1826         *
     1827         * Note: read_key sets errno to 0 on success.
     1828         */
     1829        ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
     1830        if (errno) {
     1831#if ENABLE_UNICODE_SUPPORT
     1832            if (errno == EAGAIN && unicode_idx != 0)
     1833                goto pushback;
     1834#endif
     1835            break;
     1836        }
     1837
     1838#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
     1839        if ((int32_t)ic == KEYCODE_CURSOR_POS
     1840         && S.sent_ESC_br6n
     1841        ) {
     1842            S.sent_ESC_br6n = 0;
     1843            if (cursor == 0) { /* otherwise it may be bogus */
     1844                int col = ((ic >> 32) & 0x7fff) - 1;
     1845                if (col > cmdedit_prmt_len) {
     1846                    cmdedit_x += (col - cmdedit_prmt_len);
     1847                    while (cmdedit_x >= cmdedit_termw) {
     1848                        cmdedit_x -= cmdedit_termw;
     1849                        cmdedit_y++;
     1850                    }
     1851                }
     1852            }
     1853            continue;
     1854        }
     1855#endif
     1856
     1857#if ENABLE_UNICODE_SUPPORT
     1858        if (unicode_status == UNICODE_ON) {
     1859            wchar_t wc;
     1860
     1861            if ((int32_t)ic < 0) /* KEYCODE_xxx */
     1862                break;
     1863            // TODO: imagine sequence like: 0xff,<left-arrow>: we are currently losing 0xff...
     1864
     1865            unicode_buf[unicode_idx++] = ic;
     1866            unicode_buf[unicode_idx] = '\0';
     1867            if (mbstowcs(&wc, unicode_buf, 1) != 1) {
     1868                /* Not (yet?) a valid unicode char */
     1869                if (unicode_idx < MB_CUR_MAX) {
     1870                    timeout = 50;
     1871                    continue;
     1872                }
     1873 pushback:
     1874                /* Invalid sequence. Save all "bad bytes" except first */
     1875                read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1);
     1876# if !ENABLE_UNICODE_PRESERVE_BROKEN
     1877                ic = CONFIG_SUBST_WCHAR;
     1878# else
     1879                ic = unicode_mark_raw_byte(unicode_buf[0]);
     1880# endif
     1881            } else {
     1882                /* Valid unicode char, return its code */
     1883                ic = wc;
     1884            }
     1885        }
     1886#endif
     1887        break;
     1888    }
     1889
     1890    return ic;
     1891}
     1892
     1893#if ENABLE_UNICODE_BIDI_SUPPORT
     1894static int isrtl_str(void)
     1895{
     1896    int idx = cursor;
     1897
     1898    while (idx < command_len && unicode_bidi_is_neutral_wchar(command_ps[idx]))
     1899        idx++;
     1900    return unicode_bidi_isrtl(command_ps[idx]);
     1901}
     1902#else
     1903# define isrtl_str() 0
     1904#endif
    12481905
    12491906/* leave out the "vi-mode"-only case labels if vi editing isn't
    12501907 * configured. */
    1251 #define vi_case(caselabel) USE_FEATURE_EDITING(case caselabel)
     1908#define vi_case(caselabel) IF_FEATURE_EDITING_VI(case caselabel)
    12521909
    12531910/* convert uppercase ascii to equivalent control char, for readability */
     
    12551912#define CTRL(a) ((a) & ~0x40)
    12561913
    1257 /* Returns:
    1258  * -1 on read errors or EOF, or on bare Ctrl-D.
    1259  * 0  on ctrl-C,
     1914/* maxsize must be >= 2.
     1915 * Returns:
     1916 * -1 on read errors or EOF, or on bare Ctrl-D,
     1917 * 0  on ctrl-C (the line entered is still returned in 'command'),
    12601918 * >0 length of input string, including terminating '\n'
    12611919 */
    1262 int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *st)
    1263 {
    1264     int lastWasTab = FALSE;
    1265     unsigned int ic;
    1266     unsigned char c;
     1920int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
     1921{
     1922    int len;
     1923#if ENABLE_FEATURE_TAB_COMPLETION
     1924    smallint lastWasTab = 0;
     1925#endif
    12671926    smallint break_out = 0;
    12681927#if ENABLE_FEATURE_EDITING_VI
    12691928    smallint vi_cmdmode = 0;
    1270     smalluint prevc;
    1271 #endif
     1929#endif
     1930    struct termios initial_settings;
     1931    struct termios new_settings;
     1932    char read_key_buffer[KEYCODE_BUFFER_SIZE];
     1933
     1934    INIT_S();
     1935
     1936    if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
     1937     || !(initial_settings.c_lflag & ECHO)
     1938    ) {
     1939        /* Happens when e.g. stty -echo was run before */
     1940        parse_and_put_prompt(prompt);
     1941        /* fflush_all(); - done by parse_and_put_prompt */
     1942        if (fgets(command, maxsize, stdin) == NULL)
     1943            len = -1; /* EOF or error */
     1944        else
     1945            len = strlen(command);
     1946        DEINIT_S();
     1947        return len;
     1948    }
     1949
     1950    init_unicode();
    12721951
    12731952// FIXME: audit & improve this
    12741953    if (maxsize > MAX_LINELEN)
    12751954        maxsize = MAX_LINELEN;
     1955    S.maxsize = maxsize;
    12761956
    12771957    /* With null flags, no other fields are ever used */
    12781958    state = st ? st : (line_input_t*) &const_int_0;
    1279 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
     1959#if MAX_HISTORY > 0
     1960# if ENABLE_FEATURE_EDITING_SAVEHISTORY
    12801961    if ((state->flags & SAVE_HISTORY) && state->hist_file)
    1281         load_history(state->hist_file);
     1962        if (state->cnt_history == 0)
     1963            load_history(state);
     1964# endif
     1965    if (state->flags & DO_HISTORY)
     1966        state->cur_history = state->cnt_history;
    12821967#endif
    12831968
     
    12851970    cmdedit_y = 0;  /* quasireal y, not true if line > xt*yt */
    12861971    command_len = 0;
     1972#if ENABLE_UNICODE_SUPPORT
     1973    command_ps = xzalloc(maxsize * sizeof(command_ps[0]));
     1974#else
    12871975    command_ps = command;
    12881976    command[0] = '\0';
    1289 
    1290     getTermSettings(0, (void *) &initial_settings);
    1291     memcpy(&new_settings, &initial_settings, sizeof(new_settings));
     1977#endif
     1978#define command command_must_not_be_used
     1979
     1980    new_settings = initial_settings;
    12921981    new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
    12931982    /* Turn off echoing and CTRL-C, so we can trap it */
     
    12981987    /* Turn off CTRL-C, so we can trap it */
    12991988#ifndef _POSIX_VDISABLE
    1300 #define _POSIX_VDISABLE '\0'
     1989# define _POSIX_VDISABLE '\0'
    13011990#endif
    13021991    new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
    1303     setTermSettings(0, (void *) &new_settings);
     1992    tcsetattr_stdin_TCSANOW(&new_settings);
    13041993
    13051994    /* Now initialize things */
    13061995    previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
    13071996    win_changed(0); /* do initial resizing */
    1308 #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
     1997#if ENABLE_USERNAME_OR_HOMEDIR
    13091998    {
    13101999        struct passwd *entry;
     
    13122001        entry = getpwuid(geteuid());
    13132002        if (entry) {
    1314             /* If we enter read_line_input for the Nth time,
    1315              * they may be already allocated! Need to free. */
    1316             free(user_buf);
    1317             if (home_pwd_buf != null_str)
    1318                 free(home_pwd_buf);
    13192003            user_buf = xstrdup(entry->pw_name);
    13202004            home_pwd_buf = xstrdup(entry->pw_dir);
    1321             /* They are not freed on exit (too small to bother) */
    1322         }
    1323     }
    1324 #endif
    1325     /* Print out the command prompt */
    1326     parse_prompt(prompt);
    1327 
     2005        }
     2006    }
     2007#endif
     2008
     2009#if 0
     2010    for (i = 0; i <= MAX_HISTORY; i++)
     2011        bb_error_msg("history[%d]:'%s'", i, state->history[i]);
     2012    bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history);
     2013#endif
     2014
     2015    /* Print out the command prompt, optionally ask where cursor is */
     2016    parse_and_put_prompt(prompt);
     2017    ask_terminal();
     2018
     2019    read_key_buffer[0] = 0;
    13282020    while (1) {
    1329         fflush(stdout);
    1330 
    1331         if (safe_read(0, &c, 1) < 1) {
    1332             /* if we can't read input then exit */
    1333             goto prepare_to_die;
    1334         }
    1335 
    1336         ic = c;
     2021        /*
     2022         * The emacs and vi modes share much of the code in the big
     2023         * command loop.  Commands entered when in vi's command mode
     2024         * (aka "escape mode") get an extra bit added to distinguish
     2025         * them - this keeps them from being self-inserted. This
     2026         * clutters the big switch a bit, but keeps all the code
     2027         * in one place.
     2028         */
     2029        enum {
     2030            VI_CMDMODE_BIT = 0x40000000,
     2031            /* 0x80000000 bit flags KEYCODE_xxx */
     2032        };
     2033        int32_t ic, ic_raw;
     2034
     2035        fflush_all();
     2036        ic = ic_raw = lineedit_read_key(read_key_buffer);
    13372037
    13382038#if ENABLE_FEATURE_EDITING_VI
    13392039        newdelflag = 1;
    1340         if (vi_cmdmode)
    1341             ic |= vbit;
    1342 #endif
     2040        if (vi_cmdmode) {
     2041            /* btw, since KEYCODE_xxx are all < 0, this doesn't
     2042             * change ic if it contains one of them: */
     2043            ic |= VI_CMDMODE_BIT;
     2044        }
     2045#endif
     2046
    13432047        switch (ic) {
    13442048        case '\n':
    13452049        case '\r':
    1346         vi_case('\n'|vbit:)
    1347         vi_case('\r'|vbit:)
     2050        vi_case('\n'|VI_CMDMODE_BIT:)
     2051        vi_case('\r'|VI_CMDMODE_BIT:)
    13482052            /* Enter */
    13492053            goto_new_line();
    13502054            break_out = 1;
    13512055            break;
    1352 #if ENABLE_FEATURE_EDITING_FANCY_KEYS
    13532056        case CTRL('A'):
    1354         vi_case('0'|vbit:)
     2057        vi_case('0'|VI_CMDMODE_BIT:)
    13552058            /* Control-a -- Beginning of line */
    13562059            input_backward(cursor);
    13572060            break;
    13582061        case CTRL('B'):
    1359         vi_case('h'|vbit:)
    1360         vi_case('\b'|vbit:)
    1361         vi_case('\x7f'|vbit:) /* DEL */
    1362             /* Control-b -- Move back one character */
    1363             input_backward(1);
    1364             break;
    1365 #endif
    1366         case CTRL('C'):
    1367         vi_case(CTRL('C')|vbit:)
    1368             /* Control-c -- stop gathering input */
    1369             goto_new_line();
    1370             command_len = 0;
    1371             break_out = -1; /* "do not append '\n'" */
    1372             break;
    1373         case CTRL('D'):
    1374             /* Control-d -- Delete one character, or exit
    1375              * if the len=0 and no chars to delete */
    1376             if (command_len == 0) {
    1377                 errno = 0;
    1378  prepare_to_die:
    1379                 /* to control stopped jobs */
    1380                 break_out = command_len = -1;
    1381                 break;
    1382             }
    1383             input_delete(0);
    1384             break;
    1385 
    1386 #if ENABLE_FEATURE_EDITING_FANCY_KEYS
     2062        vi_case('h'|VI_CMDMODE_BIT:)
     2063        vi_case('\b'|VI_CMDMODE_BIT:) /* ^H */
     2064        vi_case('\x7f'|VI_CMDMODE_BIT:) /* DEL */
     2065            input_backward(1); /* Move back one character */
     2066            break;
    13872067        case CTRL('E'):
    1388         vi_case('$'|vbit:)
     2068        vi_case('$'|VI_CMDMODE_BIT:)
    13892069            /* Control-e -- End of line */
    1390             input_end();
     2070            put_till_end_and_adv_cursor();
    13912071            break;
    13922072        case CTRL('F'):
    1393         vi_case('l'|vbit:)
    1394         vi_case(' '|vbit:)
    1395             /* Control-f -- Move forward one character */
    1396             input_forward();
    1397             break;
    1398 #endif
    1399 
    1400         case '\b':
     2073        vi_case('l'|VI_CMDMODE_BIT:)
     2074        vi_case(' '|VI_CMDMODE_BIT:)
     2075            input_forward(); /* Move forward one character */
     2076            break;
     2077        case '\b':   /* ^H */
    14012078        case '\x7f': /* DEL */
    1402             /* Control-h and DEL */
    1403             input_backspace();
    1404             break;
    1405 
     2079            if (!isrtl_str())
     2080                input_backspace();
     2081            else
     2082                input_delete(0);
     2083            break;
     2084        case KEYCODE_DELETE:
     2085            if (!isrtl_str())
     2086                input_delete(0);
     2087            else
     2088                input_backspace();
     2089            break;
     2090#if ENABLE_FEATURE_TAB_COMPLETION
    14062091        case '\t':
    14072092            input_tab(&lastWasTab);
    14082093            break;
    1409 
    1410 #if ENABLE_FEATURE_EDITING_FANCY_KEYS
     2094#endif
    14112095        case CTRL('K'):
    14122096            /* Control-k -- clear to end of line */
    1413             command[cursor] = 0;
     2097            command_ps[cursor] = BB_NUL;
    14142098            command_len = cursor;
    1415             printf("\033[J");
     2099            printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
    14162100            break;
    14172101        case CTRL('L'):
    1418         vi_case(CTRL('L')|vbit:)
     2102        vi_case(CTRL('L')|VI_CMDMODE_BIT:)
    14192103            /* Control-l -- clear screen */
    1420             printf("\033[H");
     2104            printf(ESC"[H"); /* cursor to top,left */
    14212105            redraw(0, command_len - cursor);
    14222106            break;
    1423 #endif
    1424 
    14252107#if MAX_HISTORY > 0
    14262108        case CTRL('N'):
    1427         vi_case(CTRL('N')|vbit:)
    1428         vi_case('j'|vbit:)
     2109        vi_case(CTRL('N')|VI_CMDMODE_BIT:)
     2110        vi_case('j'|VI_CMDMODE_BIT:)
    14292111            /* Control-n -- Get next command in history */
    14302112            if (get_next_history())
     
    14322114            break;
    14332115        case CTRL('P'):
    1434         vi_case(CTRL('P')|vbit:)
    1435         vi_case('k'|vbit:)
     2116        vi_case(CTRL('P')|VI_CMDMODE_BIT:)
     2117        vi_case('k'|VI_CMDMODE_BIT:)
    14362118            /* Control-p -- Get previous command from history */
    1437             if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
    1438                 get_previous_history();
     2119            if (get_previous_history())
    14392120                goto rewrite_line;
    1440             }
    1441             beep();
    1442             break;
    1443 #endif
    1444 
    1445 #if ENABLE_FEATURE_EDITING_FANCY_KEYS
     2121            break;
     2122#endif
    14462123        case CTRL('U'):
    1447         vi_case(CTRL('U')|vbit:)
     2124        vi_case(CTRL('U')|VI_CMDMODE_BIT:)
    14482125            /* Control-U -- Clear line before cursor */
    14492126            if (cursor) {
    1450                 strcpy(command, command + cursor);
    14512127                command_len -= cursor;
     2128                memmove(command_ps, command_ps + cursor,
     2129                    (command_len + 1) * sizeof(command_ps[0]));
    14522130                redraw(cmdedit_y, command_len);
    14532131            }
    14542132            break;
    1455 #endif
    14562133        case CTRL('W'):
    1457         vi_case(CTRL('W')|vbit:)
     2134        vi_case(CTRL('W')|VI_CMDMODE_BIT:)
    14582135            /* Control-W -- Remove the last word */
    1459             while (cursor > 0 && isspace(command[cursor-1]))
     2136            while (cursor > 0 && BB_isspace(command_ps[cursor-1]))
    14602137                input_backspace();
    1461             while (cursor > 0 && !isspace(command[cursor-1]))
     2138            while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
    14622139                input_backspace();
    14632140            break;
    14642141
    14652142#if ENABLE_FEATURE_EDITING_VI
    1466         case 'i'|vbit:
     2143        case 'i'|VI_CMDMODE_BIT:
    14672144            vi_cmdmode = 0;
    14682145            break;
    1469         case 'I'|vbit:
     2146        case 'I'|VI_CMDMODE_BIT:
    14702147            input_backward(cursor);
    14712148            vi_cmdmode = 0;
    14722149            break;
    1473         case 'a'|vbit:
     2150        case 'a'|VI_CMDMODE_BIT:
    14742151            input_forward();
    14752152            vi_cmdmode = 0;
    14762153            break;
    1477         case 'A'|vbit:
    1478             input_end();
     2154        case 'A'|VI_CMDMODE_BIT:
     2155            put_till_end_and_adv_cursor();
    14792156            vi_cmdmode = 0;
    14802157            break;
    1481         case 'x'|vbit:
     2158        case 'x'|VI_CMDMODE_BIT:
    14822159            input_delete(1);
    14832160            break;
    1484         case 'X'|vbit:
     2161        case 'X'|VI_CMDMODE_BIT:
    14852162            if (cursor > 0) {
    14862163                input_backward(1);
     
    14882165            }
    14892166            break;
    1490         case 'W'|vbit:
    1491             vi_Word_motion(command, 1);
    1492             break;
    1493         case 'w'|vbit:
    1494             vi_word_motion(command, 1);
    1495             break;
    1496         case 'E'|vbit:
    1497             vi_End_motion(command);
    1498             break;
    1499         case 'e'|vbit:
    1500             vi_end_motion(command);
    1501             break;
    1502         case 'B'|vbit:
    1503             vi_Back_motion(command);
    1504             break;
    1505         case 'b'|vbit:
    1506             vi_back_motion(command);
    1507             break;
    1508         case 'C'|vbit:
     2167        case 'W'|VI_CMDMODE_BIT:
     2168            vi_Word_motion(1);
     2169            break;
     2170        case 'w'|VI_CMDMODE_BIT:
     2171            vi_word_motion(1);
     2172            break;
     2173        case 'E'|VI_CMDMODE_BIT:
     2174            vi_End_motion();
     2175            break;
     2176        case 'e'|VI_CMDMODE_BIT:
     2177            vi_end_motion();
     2178            break;
     2179        case 'B'|VI_CMDMODE_BIT:
     2180            vi_Back_motion();
     2181            break;
     2182        case 'b'|VI_CMDMODE_BIT:
     2183            vi_back_motion();
     2184            break;
     2185        case 'C'|VI_CMDMODE_BIT:
    15092186            vi_cmdmode = 0;
    15102187            /* fall through */
    1511         case 'D'|vbit:
     2188        case 'D'|VI_CMDMODE_BIT:
    15122189            goto clear_to_eol;
    15132190
    1514         case 'c'|vbit:
     2191        case 'c'|VI_CMDMODE_BIT:
    15152192            vi_cmdmode = 0;
    15162193            /* fall through */
    1517         case 'd'|vbit: {
     2194        case 'd'|VI_CMDMODE_BIT: {
    15182195            int nc, sc;
    1519             sc = cursor;
    1520             prevc = ic;
    1521             if (safe_read(0, &c, 1) < 1)
    1522                 goto prepare_to_die;
    1523             if (c == (prevc & 0xff)) {
    1524                 /* "cc", "dd" */
     2196
     2197            ic = lineedit_read_key(read_key_buffer);
     2198            if (errno) /* error */
     2199                goto return_error_indicator;
     2200            if (ic == ic_raw) { /* "cc", "dd" */
    15252201                input_backward(cursor);
    15262202                goto clear_to_eol;
    15272203                break;
    15282204            }
    1529             switch (c) {
     2205
     2206            sc = cursor;
     2207            switch (ic) {
    15302208            case 'w':
    15312209            case 'W':
    15322210            case 'e':
    15332211            case 'E':
    1534                 switch (c) {
     2212                switch (ic) {
    15352213                case 'w':   /* "dw", "cw" */
    1536                     vi_word_motion(command, vi_cmdmode);
     2214                    vi_word_motion(vi_cmdmode);
    15372215                    break;
    15382216                case 'W':   /* 'dW', 'cW' */
    1539                     vi_Word_motion(command, vi_cmdmode);
     2217                    vi_Word_motion(vi_cmdmode);
    15402218                    break;
    15412219                case 'e':   /* 'de', 'ce' */
    1542                     vi_end_motion(command);
     2220                    vi_end_motion();
    15432221                    input_forward();
    15442222                    break;
    15452223                case 'E':   /* 'dE', 'cE' */
    1546                     vi_End_motion(command);
     2224                    vi_End_motion();
    15472225                    input_forward();
    15482226                    break;
     
    15552233            case 'b':  /* "db", "cb" */
    15562234            case 'B':  /* implemented as B */
    1557                 if (c == 'b')
    1558                     vi_back_motion(command);
     2235                if (ic == 'b')
     2236                    vi_back_motion();
    15592237                else
    1560                     vi_Back_motion(command);
     2238                    vi_Back_motion();
    15612239                while (sc-- > cursor)
    15622240                    input_delete(1);
     
    15662244                break;
    15672245            case '$':  /* "d$", "c$" */
    1568             clear_to_eol:
     2246 clear_to_eol:
    15692247                while (cursor < command_len)
    15702248                    input_delete(1);
     
    15732251            break;
    15742252        }
    1575         case 'p'|vbit:
     2253        case 'p'|VI_CMDMODE_BIT:
    15762254            input_forward();
    15772255            /* fallthrough */
    1578         case 'P'|vbit:
     2256        case 'P'|VI_CMDMODE_BIT:
    15792257            put();
    15802258            break;
    1581         case 'r'|vbit:
    1582             if (safe_read(0, &c, 1) < 1)
    1583                 goto prepare_to_die;
    1584             if (c == 0)
     2259        case 'r'|VI_CMDMODE_BIT:
     2260//FIXME: unicode case?
     2261            ic = lineedit_read_key(read_key_buffer);
     2262            if (errno) /* error */
     2263                goto return_error_indicator;
     2264            if (ic < ' ' || ic > 255) {
    15852265                beep();
    1586             else {
    1587                 *(command + cursor) = c;
    1588                 putchar(c);
    1589                 putchar('\b');
     2266            } else {
     2267                command_ps[cursor] = ic;
     2268                bb_putchar(ic);
     2269                bb_putchar('\b');
    15902270            }
    15912271            break;
    1592 #endif /* FEATURE_COMMAND_EDITING_VI */
    1593 
    15942272        case '\x1b': /* ESC */
    1595 
    1596 #if ENABLE_FEATURE_EDITING_VI
    15972273            if (state->flags & VI_MODE) {
    1598                 /* ESC: insert mode --> command mode */
     2274                /* insert mode --> command mode */
    15992275                vi_cmdmode = 1;
    16002276                input_backward(1);
     2277            }
     2278            break;
     2279#endif /* FEATURE_COMMAND_EDITING_VI */
     2280
     2281#if MAX_HISTORY > 0
     2282        case KEYCODE_UP:
     2283            if (get_previous_history())
     2284                goto rewrite_line;
     2285            beep();
     2286            break;
     2287        case KEYCODE_DOWN:
     2288            if (!get_next_history())
     2289                break;
     2290 rewrite_line:
     2291            /* Rewrite the line with the selected history item */
     2292            /* change command */
     2293            command_len = load_string(state->history[state->cur_history] ?
     2294                    state->history[state->cur_history] : "", maxsize);
     2295            /* redraw and go to eol (bol, in vi) */
     2296            redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
     2297            break;
     2298#endif
     2299        case KEYCODE_RIGHT:
     2300            input_forward();
     2301            break;
     2302        case KEYCODE_LEFT:
     2303            input_backward(1);
     2304            break;
     2305        case KEYCODE_CTRL_LEFT:
     2306            ctrl_left();
     2307            break;
     2308        case KEYCODE_CTRL_RIGHT:
     2309            ctrl_right();
     2310            break;
     2311        case KEYCODE_HOME:
     2312            input_backward(cursor);
     2313            break;
     2314        case KEYCODE_END:
     2315            put_till_end_and_adv_cursor();
     2316            break;
     2317
     2318        default:
     2319            if (initial_settings.c_cc[VINTR] != 0
     2320             && ic_raw == initial_settings.c_cc[VINTR]
     2321            ) {
     2322                /* Ctrl-C (usually) - stop gathering input */
     2323                goto_new_line();
     2324                command_len = 0;
     2325                break_out = -1; /* "do not append '\n'" */
    16012326                break;
    16022327            }
    1603 #endif
    1604             /* escape sequence follows */
    1605             if (safe_read(0, &c, 1) < 1)
    1606                 goto prepare_to_die;
    1607             /* different vt100 emulations */
    1608             if (c == '[' || c == 'O') {
    1609         vi_case('['|vbit:)
    1610         vi_case('O'|vbit:)
    1611                 if (safe_read(0, &c, 1) < 1)
    1612                     goto prepare_to_die;
    1613             }
    1614             if (c >= '1' && c <= '9') {
    1615                 unsigned char dummy;
    1616 
    1617                 if (safe_read(0, &dummy, 1) < 1)
    1618                     goto prepare_to_die;
    1619                 if (dummy != '~')
    1620                     c = '\0';
    1621             }
    1622 
    1623             switch (c) {
    1624 #if ENABLE_FEATURE_TAB_COMPLETION
    1625             case '\t':                      /* Alt-Tab */
    1626                 input_tab(&lastWasTab);
    1627                 break;
    1628 #endif
    1629 #if MAX_HISTORY > 0
    1630             case 'A':
    1631                 /* Up Arrow -- Get previous command from history */
    1632                 if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
    1633                     get_previous_history();
    1634                     goto rewrite_line;
     2328            if (initial_settings.c_cc[VEOF] != 0
     2329             && ic_raw == initial_settings.c_cc[VEOF]
     2330            ) {
     2331                /* Ctrl-D (usually) - delete one character,
     2332                 * or exit if len=0 and no chars to delete */
     2333                if (command_len == 0) {
     2334                    errno = 0;
     2335
     2336        case -1: /* error (e.g. EIO when tty is destroyed) */
     2337 IF_FEATURE_EDITING_VI(return_error_indicator:)
     2338                    break_out = command_len = -1;
     2339                    break;
    16352340                }
    1636                 beep();
    1637                 break;
    1638             case 'B':
    1639                 /* Down Arrow -- Get next command in history */
    1640                 if (!get_next_history())
    1641                     break;
    1642  rewrite_line:
    1643                 /* Rewrite the line with the selected history item */
    1644                 /* change command */
    1645                 command_len = strlen(strcpy(command, state->history[state->cur_history]));
    1646                 /* redraw and go to eol (bol, in vi */
    1647                 redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
    1648                 break;
    1649 #endif
    1650             case 'C':
    1651                 /* Right Arrow -- Move forward one character */
    1652                 input_forward();
    1653                 break;
    1654             case 'D':
    1655                 /* Left Arrow -- Move back one character */
    1656                 input_backward(1);
    1657                 break;
    1658             case '3':
    1659                 /* Delete */
    16602341                input_delete(0);
    16612342                break;
    1662             case '1': // vt100? linux vt? or what?
    1663             case '7': // vt100? linux vt? or what?
    1664             case 'H': /* xterm's <Home> */
    1665                 input_backward(cursor);
     2343            }
     2344//          /* Control-V -- force insert of next char */
     2345//          if (c == CTRL('V')) {
     2346//              if (safe_read(STDIN_FILENO, &c, 1) < 1)
     2347//                  goto return_error_indicator;
     2348//              if (c == 0) {
     2349//                  beep();
     2350//                  break;
     2351//              }
     2352//          }
     2353            if (ic < ' '
     2354             || (!ENABLE_UNICODE_SUPPORT && ic >= 256)
     2355             || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT)
     2356            ) {
     2357                /* If VI_CMDMODE_BIT is set, ic is >= 256
     2358                 * and vi mode ignores unexpected chars.
     2359                 * Otherwise, we are here if ic is a
     2360                 * control char or an unhandled ESC sequence,
     2361                 * which is also ignored.
     2362                 */
    16662363                break;
    1667             case '4': // vt100? linux vt? or what?
    1668             case '8': // vt100? linux vt? or what?
    1669             case 'F': /* xterm's <End> */
    1670                 input_end();
     2364            }
     2365            if ((int)command_len >= (maxsize - 2)) {
     2366                /* Not enough space for the char and EOL */
    16712367                break;
    1672             default:
    1673                 c = '\0';
    1674                 beep();
    16752368            }
    1676             break;
    1677 
    1678         default:        /* If it's regular input, do the normal thing */
    1679 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
    1680             /* Control-V -- Add non-printable symbol */
    1681             if (c == CTRL('V')) {
    1682                 if (safe_read(0, &c, 1) < 1)
    1683                     goto prepare_to_die;
    1684                 if (c == 0) {
    1685                     beep();
    1686                     break;
    1687                 }
    1688             } else
    1689 #endif
    1690 
    1691 #if ENABLE_FEATURE_EDITING_VI
    1692             if (vi_cmdmode)  /* Don't self-insert */
    1693                 break;
    1694 #endif
    1695             if (!Isprint(c)) /* Skip non-printable characters */
    1696                 break;
    1697 
    1698             if (command_len >= (maxsize - 2))        /* Need to leave space for enter */
    1699                 break;
    17002369
    17012370            command_len++;
    1702             if (cursor == (command_len - 1)) {      /* Append if at the end of the line */
    1703                 command[cursor] = c;
    1704                 command[cursor+1] = '\0';
    1705                 cmdedit_set_out_char(' ');
    1706             } else {                        /* Insert otherwise */
     2371            if (cursor == (command_len - 1)) {
     2372                /* We are at the end, append */
     2373                command_ps[cursor] = ic;
     2374                command_ps[cursor + 1] = BB_NUL;
     2375                put_cur_glyph_and_inc_cursor();
     2376                if (unicode_bidi_isrtl(ic))
     2377                    input_backward(1);
     2378            } else {
     2379                /* In the middle, insert */
    17072380                int sc = cursor;
    17082381
    1709                 memmove(command + sc + 1, command + sc, command_len - sc);
    1710                 command[sc] = c;
    1711                 sc++;
    1712                 /* rewrite from cursor */
    1713                 input_end();
     2382                memmove(command_ps + sc + 1, command_ps + sc,
     2383                    (command_len - sc) * sizeof(command_ps[0]));
     2384                command_ps[sc] = ic;
     2385                /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */
     2386                if (!isrtl_str())
     2387                    sc++; /* no */
     2388                put_till_end_and_adv_cursor();
    17142389                /* to prev x pos + 1 */
    17152390                input_backward(cursor - sc);
    17162391            }
    17172392            break;
    1718         }
    1719         if (break_out)                  /* Enter is the command terminator, no more input. */
    1720             break;
    1721 
    1722         if (c != '\t')
    1723             lastWasTab = FALSE;
    1724     }
     2393        } /* switch (ic) */
     2394
     2395        if (break_out)
     2396            break;
     2397
     2398#if ENABLE_FEATURE_TAB_COMPLETION
     2399        if (ic_raw != '\t')
     2400            lastWasTab = 0;
     2401#endif
     2402    } /* while (1) */
     2403
     2404#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
     2405    if (S.sent_ESC_br6n) {
     2406        /* "sleep 1; busybox ash" + hold [Enter] to trigger.
     2407         * We sent "ESC [ 6 n", but got '\n' first, and
     2408         * KEYCODE_CURSOR_POS response is now buffered from terminal.
     2409         * It's bad already and not much can be done with it
     2410         * (it _will_ be visible for the next process to read stdin),
     2411         * but without this delay it even shows up on the screen
     2412         * as garbage because we restore echo settings with tcsetattr
     2413         * before it comes in. UGLY!
     2414         */
     2415        usleep(20*1000);
     2416    }
     2417#endif
     2418
     2419/* End of bug-catching "command_must_not_be_used" trick */
     2420#undef command
     2421
     2422#if ENABLE_UNICODE_SUPPORT
     2423    command[0] = '\0';
     2424    if (command_len > 0)
     2425        command_len = save_string(command, maxsize - 1);
     2426    free(command_ps);
     2427#endif
    17252428
    17262429    if (command_len > 0)
     
    17322435    }
    17332436
    1734 #if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_TAB_COMPLETION
     2437#if ENABLE_FEATURE_TAB_COMPLETION
    17352438    free_tab_completion_data();
    17362439#endif
    17372440
    1738 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
    1739     free((char*)cmdedit_prompt);
    1740 #endif
    17412441    /* restore initial_settings */
    1742     setTermSettings(STDIN_FILENO, (void *) &initial_settings);
     2442    tcsetattr_stdin_TCSANOW(&initial_settings);
    17432443    /* restore SIGWINCH handler */
    17442444    signal(SIGWINCH, previous_SIGWINCH_handler);
    1745     fflush(stdout);
    1746     return command_len;
    1747 }
    1748 
    1749 line_input_t *new_line_input_t(int flags)
    1750 {
    1751     line_input_t *n = xzalloc(sizeof(*n));
    1752     n->flags = flags;
    1753     return n;
    1754 }
    1755 
    1756 #else
     2445    fflush_all();
     2446
     2447    len = command_len;
     2448    DEINIT_S();
     2449
     2450    return len; /* can't return command_len, DEINIT_S() destroys it */
     2451}
     2452
     2453#else  /* !FEATURE_EDITING */
    17572454
    17582455#undef read_line_input
    1759 int read_line_input(const char* prompt, char* command, int maxsize)
     2456int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize)
    17602457{
    17612458    fputs(prompt, stdout);
    1762     fflush(stdout);
     2459    fflush_all();
    17632460    fgets(command, maxsize, stdin);
    17642461    return strlen(command);
    17652462}
    17662463
    1767 #endif  /* FEATURE_COMMAND_EDITING */
     2464#endif  /* !FEATURE_EDITING */
    17682465
    17692466
     
    17902487#endif
    17912488
    1792 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
    1793     setlocale(LC_ALL, "");
    1794 #endif
    17952489    while (1) {
    17962490        int l;
     
    17982492        if (l <= 0 || buff[l-1] != '\n')
    17992493            break;
    1800         buff[l-1] = 0;
     2494        buff[l-1] = '\0';
    18012495        printf("*** read_line_input() returned line =%s=\n", buff);
    18022496    }
  • branches/2.2.9/mindi-busybox/libbb/llist.c

    r1765 r2725  
    55 * Copyright (C) 2003 Glenn McGrath
    66 * Copyright (C) 2005 Vladimir Oleynik
    7  * Copyright (C) 2005 Bernhard Fischer
     7 * Copyright (C) 2005 Bernhard Reutner-Fischer
    88 * Copyright (C) 2006 Rob Landley <rob@landley.net>
    99 *
    10  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1111 */
    1212
     
    1414
    1515/* Add data to the start of the linked list.  */
    16 void llist_add_to(llist_t **old_head, void *data)
     16void FAST_FUNC llist_add_to(llist_t **old_head, void *data)
    1717{
    1818    llist_t *new_head = xmalloc(sizeof(llist_t));
     
    2424
    2525/* Add data to the end of the linked list.  */
    26 void llist_add_to_end(llist_t **list_head, void *data)
     26void FAST_FUNC llist_add_to_end(llist_t **list_head, void *data)
    2727{
    28     llist_t *new_item = xmalloc(sizeof(llist_t));
    29 
    30     new_item->data = data;
    31     new_item->link = NULL;
    32 
    33     if (!*list_head)
    34         *list_head = new_item;
    35     else {
    36         llist_t *tail = *list_head;
    37 
    38         while (tail->link)
    39             tail = tail->link;
    40         tail->link = new_item;
    41     }
     28    while (*list_head)
     29        list_head = &(*list_head)->link;
     30    *list_head = xzalloc(sizeof(llist_t));
     31    (*list_head)->data = data;
     32    /*(*list_head)->link = NULL;*/
    4233}
    4334
    4435/* Remove first element from the list and return it */
    45 void *llist_pop(llist_t **head)
     36void* FAST_FUNC llist_pop(llist_t **head)
    4637{
    47     void *data, *next;
     38    void *data = NULL;
     39    llist_t *temp = *head;
    4840
    49     if (!*head)
    50         return NULL;
    51 
    52     data = (*head)->data;
    53     next = (*head)->link;
    54     free(*head);
    55     *head = next;
    56 
     41    if (temp) {
     42        data = temp->data;
     43        *head = temp->link;
     44        free(temp);
     45    }
    5746    return data;
    5847}
    5948
    6049/* Unlink arbitrary given element from the list */
    61 void llist_unlink(llist_t **head, llist_t *elm)
     50void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm)
    6251{
    63     llist_t *crt;
    64 
    65     if (!(elm && *head))
     52    if (!elm)
    6653        return;
    67 
    68     if (elm == *head) {
    69         *head = (*head)->link;
    70         return;
    71     }
    72 
    73     for (crt = *head; crt; crt = crt->link) {
    74         if (crt->link == elm) {
    75             crt->link = elm->link;
    76             return;
     54    while (*head) {
     55        if (*head == elm) {
     56            *head = (*head)->link;
     57            break;
    7758        }
     59        head = &(*head)->link;
    7860    }
    7961}
     
    8163/* Recursively free all elements in the linked list.  If freeit != NULL
    8264 * call it on each datum in the list */
    83 void llist_free(llist_t *elm, void (*freeit) (void *data))
     65void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data))
    8466{
    8567    while (elm) {
     
    9173}
    9274
    93 #ifdef UNUSED
    9475/* Reverse list order. */
    95 llist_t *llist_rev(llist_t *list)
     76llist_t* FAST_FUNC llist_rev(llist_t *list)
    9677{
    9778    llist_t *rev = NULL;
     
    10687    return rev;
    10788}
    108 #endif
     89
     90llist_t* FAST_FUNC llist_find_str(llist_t *list, const char *str)
     91{
     92    while (list) {
     93        if (strcmp(list->data, str) == 0)
     94            break;
     95        list = list->link;
     96    }
     97    return list;
     98}
  • branches/2.2.9/mindi-busybox/libbb/login.c

    r1765 r2725  
    77 * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru>
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 */
    1111
    12 #include <sys/param.h>  /* MAXHOSTNAMELEN */
     12#include "libbb.h"
     13/* After libbb.h, since it needs sys/types.h on some systems */
    1314#include <sys/utsname.h>
    14 #include "libbb.h"
    1515
    1616#define LOGIN " login: "
     
    1919static const char fmtstr_t[] ALIGN1 = "%H:%M:%S";
    2020
    21 void print_login_issue(const char *issue_file, const char *tty)
     21void FAST_FUNC print_login_issue(const char *issue_file, const char *tty)
    2222{
    23     FILE *fd;
     23    FILE *fp;
    2424    int c;
    2525    char buf[256+1];
     
    3131    uname(&uts);
    3232
    33     puts("\r"); /* start a new line */
     33    puts("\r");  /* start a new line */
    3434
    35     fd = fopen(issue_file, "r");
    36     if (!fd)
     35    fp = fopen_for_read(issue_file);
     36    if (!fp)
    3737        return;
    38     while ((c = fgetc(fd)) != EOF) {
     38    while ((c = fgetc(fp)) != EOF) {
    3939        outbuf = buf;
    4040        buf[0] = c;
     
    4545        }
    4646        if (c == '\\' || c == '%') {
    47             c = fgetc(fd);
     47            c = fgetc(fp);
    4848            switch (c) {
    4949            case 's':
     
    5151                break;
    5252            case 'n':
     53            case 'h':
    5354                outbuf = uts.nodename;
    5455                break;
     
    6263                outbuf = uts.machine;
    6364                break;
     65/* The field domainname of struct utsname is Linux specific. */
     66#if defined(__linux__)
    6467            case 'D':
    6568            case 'o':
    66                 c = getdomainname(buf, sizeof(buf) - 1);
    67                 buf[c >= 0 ? c : 0] = '\0';
     69                outbuf = uts.domainname;
    6870                break;
     71#endif
    6972            case 'd':
    7073                strftime(buf, sizeof(buf), fmtstr_d, localtime(&t));
     
    7275            case 't':
    7376                strftime(buf, sizeof(buf), fmtstr_t, localtime(&t));
    74                 break;
    75             case 'h':
    76                 gethostname(buf, sizeof(buf) - 1);
    77                 buf[sizeof(buf) - 1] = '\0';
    7877                break;
    7978            case 'l':
     
    8685        fputs(outbuf, stdout);
    8786    }
    88     fclose(fd);
    89     fflush(stdout);
     87    fclose(fp);
     88    fflush_all();
    9089}
    9190
    92 void print_login_prompt(void)
     91void FAST_FUNC print_login_prompt(void)
    9392{
    94     char buf[MAXHOSTNAMELEN+1];
     93    char *hostname = safe_gethostname();
    9594
    96     if (gethostname(buf, MAXHOSTNAMELEN) == 0)
    97         fputs(buf, stdout);
     95    fputs(hostname, stdout);
     96    fputs(LOGIN, stdout);
     97    fflush_all();
     98    free(hostname);
     99}
    98100
    99     fputs(LOGIN, stdout);
    100     fflush(stdout);
     101/* Clear dangerous stuff, set PATH */
     102static const char forbid[] ALIGN1 =
     103    "ENV" "\0"
     104    "BASH_ENV" "\0"
     105    "HOME" "\0"
     106    "IFS" "\0"
     107    "SHELL" "\0"
     108    "LD_LIBRARY_PATH" "\0"
     109    "LD_PRELOAD" "\0"
     110    "LD_TRACE_LOADED_OBJECTS" "\0"
     111    "LD_BIND_NOW" "\0"
     112    "LD_AOUT_LIBRARY_PATH" "\0"
     113    "LD_AOUT_PRELOAD" "\0"
     114    "LD_NOWARN" "\0"
     115    "LD_KEEPDIR" "\0";
     116
     117int FAST_FUNC sanitize_env_if_suid(void)
     118{
     119    const char *p;
     120
     121    if (getuid() == geteuid())
     122        return 0;
     123
     124    p = forbid;
     125    do {
     126        unsetenv(p);
     127        p += strlen(p) + 1;
     128    } while (*p);
     129    putenv((char*)bb_PATH_root_path);
     130
     131    return 1; /* we indeed were run by different user! */
    101132}
  • branches/2.2.9/mindi-busybox/libbb/loop.c

    r1765 r2725  
    66 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
    77 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
     10#include "libbb.h"
     11#include <linux/version.h>
    1012
    11 #include "libbb.h"
     13#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
    1214
    1315/* For 2.6, use the cleaned up header to get the 64 bit API. */
    14 #include <linux/version.h>
    15 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
    16 #include <linux/loop.h>
     16// Commented out per Rob's request
     17//# include "fix_u32.h" /* some old toolchains need __u64 for linux/loop.h */
     18# include <linux/loop.h>
    1719typedef struct loop_info64 bb_loop_info;
    18 #define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
    19 #define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
     20# define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
     21# define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
     22
     23#else
    2024
    2125/* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */
    22 #else
    23 /* Stuff stolen from linux/loop.h for 2.4 and earlier kernels*/
    24 #include <linux/posix_types.h>
    25 #define LO_NAME_SIZE        64
    26 #define LO_KEY_SIZE         32
    27 #define LOOP_SET_FD         0x4C00
    28 #define LOOP_CLR_FD         0x4C01
    29 #define BB_LOOP_SET_STATUS  0x4C02
    30 #define BB_LOOP_GET_STATUS  0x4C03
     26/* Stuff stolen from linux/loop.h for 2.4 and earlier kernels */
     27# include <linux/posix_types.h>
     28# define LO_NAME_SIZE        64
     29# define LO_KEY_SIZE         32
     30# define LOOP_SET_FD         0x4C00
     31# define LOOP_CLR_FD         0x4C01
     32# define BB_LOOP_SET_STATUS  0x4C02
     33# define BB_LOOP_GET_STATUS  0x4C03
    3134typedef struct {
    3235    int                lo_number;
     
    4548#endif
    4649
    47 char *query_loop(const char *device)
     50char* FAST_FUNC query_loop(const char *device)
    4851{
    4952    int fd;
    5053    bb_loop_info loopinfo;
    51     char *dev = 0;
     54    char *dev = NULL;
    5255
    5356    fd = open(device, O_RDONLY);
    54     if (fd < 0) return 0;
    55     if (!ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo))
    56         dev = xasprintf("%ld %s", (long) loopinfo.lo_offset,
    57                 (char *)loopinfo.lo_file_name);
    58     close(fd);
     57    if (fd >= 0) {
     58        if (ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo) == 0) {
     59            dev = xasprintf("%"OFF_FMT"u %s", (off_t) loopinfo.lo_offset,
     60                    (char *)loopinfo.lo_file_name);
     61        }
     62        close(fd);
     63    }
    5964
    6065    return dev;
    6166}
    6267
    63 
    64 int del_loop(const char *device)
     68int FAST_FUNC del_loop(const char *device)
    6569{
    6670    int fd, rc;
    6771
    6872    fd = open(device, O_RDONLY);
    69     if (fd < 0) return 1;
     73    if (fd < 0)
     74        return 1;
    7075    rc = ioctl(fd, LOOP_CLR_FD, 0);
    7176    close(fd);
     
    8085   file/offset if it finds one.
    8186 */
    82 int set_loop(char **device, const char *file, unsigned long long offset)
     87int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset)
    8388{
    8489    char dev[LOOP_NAMESIZE];
     
    99104
    100105    /* Find a loop device.  */
    101     try = *device ? : dev;
    102     for (i = 0; rc; i++) {
     106    try = *device ? *device : dev;
     107    /* 1048575 is a max possible minor number in Linux circa 2010 */
     108    for (i = 0; rc && i < 1048576; i++) {
    103109        sprintf(dev, LOOP_FORMAT, i);
    104110
    105         /* Ran out of block devices, return failure.  */
    106         if (stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
     111        IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;)
     112        if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) {
     113            if (ENABLE_FEATURE_MOUNT_LOOP_CREATE
     114             && errno == ENOENT
     115             && try == dev
     116            ) {
     117                /* Node doesn't exist, try to create it.  */
     118                if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0)
     119                    goto try_to_open;
     120            }
     121            /* Ran out of block devices, return failure.  */
    107122            rc = -ENOENT;
    108123            break;
    109124        }
     125 try_to_open:
    110126        /* Open the sucker and check its loopiness.  */
    111127        dfd = open(try, mode);
     
    125141            loopinfo.lo_offset = offset;
    126142            /* Associate free loop device with file.  */
    127             if (!ioctl(dfd, LOOP_SET_FD, ffd)) {
    128                 if (!ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo))
     143            if (ioctl(dfd, LOOP_SET_FD, ffd) == 0) {
     144                if (ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo) == 0)
    129145                    rc = 0;
    130146                else
     
    137153           without using losetup manually is problematic.)
    138154         */
    139         } else if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
    140         || offset != loopinfo.lo_offset) {
     155        } else
     156        if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
     157         || offset != loopinfo.lo_offset
     158        ) {
    141159            rc = -1;
    142160        }
     
    146164    }
    147165    close(ffd);
    148     if (!rc) {
     166    if (rc == 0) {
    149167        if (!*device)
    150168            *device = xstrdup(dev);
  • branches/2.2.9/mindi-busybox/libbb/make_directory.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    2727/* This function is used from NOFORK applets. It must not allocate anything */
    2828
    29 int bb_make_directory (char *path, long mode, int flags)
     29int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
    3030{
    31     mode_t mask;
     31    mode_t cur_mask;
     32    mode_t org_mask;
    3233    const char *fail_msg;
    33     char *s = path;
     34    char *s;
    3435    char c;
    3536    struct stat st;
    3637
    37     mask = umask(0);
    38     if (mode == -1) {
    39         umask(mask);
    40         mode = (S_IXUSR | S_IXGRP | S_IXOTH |
    41                 S_IWUSR | S_IWGRP | S_IWOTH |
    42                 S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
    43     } else {
    44         umask(mask & ~0300);
    45     }
     38    /* Happens on bb_make_directory(dirname("no_slashes"),...) */
     39    if (LONE_CHAR(path, '.'))
     40        return 0;
    4641
    47     do {
    48         c = 0;
     42    org_mask = cur_mask = (mode_t)-1L;
     43    s = path;
     44    while (1) {
     45        c = '\0';
    4946
    50         if (flags & FILEUTILS_RECUR) {  /* Get the parent. */
    51             /* Bypass leading non-'/'s and then subsequent '/'s. */
     47        if (flags & FILEUTILS_RECUR) {  /* Get the parent */
     48            /* Bypass leading non-'/'s and then subsequent '/'s */
    5249            while (*s) {
    5350                if (*s == '/') {
     
    5552                        ++s;
    5653                    } while (*s == '/');
    57                     c = *s;     /* Save the current char */
    58                     *s = 0;     /* and replace it with nul. */
     54                    c = *s; /* Save the current char */
     55                    *s = '\0'; /* and replace it with nul */
    5956                    break;
    6057                }
     
    6360        }
    6461
     62        if (c != '\0') {
     63            /* Intermediate dirs: must have wx for user */
     64            if (cur_mask == (mode_t)-1L) { /* wasn't done yet? */
     65                mode_t new_mask;
     66                org_mask = umask(0);
     67                cur_mask = 0;
     68                /* Clear u=wx in umask - this ensures
     69                 * they won't be cleared on mkdir */
     70                new_mask = (org_mask & ~(mode_t)0300);
     71                //bb_error_msg("org_mask:%o cur_mask:%o", org_mask, new_mask);
     72                if (new_mask != cur_mask) {
     73                    cur_mask = new_mask;
     74                    umask(new_mask);
     75                }
     76            }
     77        } else {
     78            /* Last component: uses original umask */
     79            //bb_error_msg("1 org_mask:%o", org_mask);
     80            if (org_mask != cur_mask) {
     81                cur_mask = org_mask;
     82                umask(org_mask);
     83            }
     84        }
     85
    6586        if (mkdir(path, 0777) < 0) {
    6687            /* If we failed for any other reason than the directory
    67              * already exists, output a diagnostic and return -1.*/
    68             if (errno != EEXIST
    69                 || !(flags & FILEUTILS_RECUR)
    70                 || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
     88             * already exists, output a diagnostic and return -1 */
     89            if ((errno != EEXIST && errno != EISDIR)
     90             || !(flags & FILEUTILS_RECUR)
     91             || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode))
     92            ) {
    7193                fail_msg = "create";
    72                 umask(mask);
    7394                break;
    7495            }
    7596            /* Since the directory exists, don't attempt to change
    7697             * permissions if it was the full target.  Note that
    77              * this is not an error conditon. */
     98             * this is not an error condition. */
    7899            if (!c) {
    79                 umask(mask);
    80                 return 0;
     100                goto ret0;
    81101            }
    82102        }
    83103
    84104        if (!c) {
    85             /* Done.  If necessary, updated perms on the newly
     105            /* Done.  If necessary, update perms on the newly
    86106             * created directory.  Failure to update here _is_
    87              * an error.*/
    88             umask(mask);
    89             if ((mode != -1) && (chmod(path, mode) < 0)){
     107             * an error. */
     108            if ((mode != -1) && (chmod(path, mode) < 0)) {
    90109                fail_msg = "set permissions of";
    91110                break;
    92111            }
    93             return 0;
     112            goto ret0;
    94113        }
    95114
    96         /* Remove any inserted nul from the path (recursive mode). */
     115        /* Remove any inserted nul from the path (recursive mode) */
    97116        *s = c;
     117    } /* while (1) */
    98118
    99     } while (1);
    100 
    101     bb_perror_msg("cannot %s directory '%s'", fail_msg, path);
    102     return -1;
     119    bb_perror_msg("can't %s directory '%s'", fail_msg, path);
     120    flags = -1;
     121    goto ret;
     122 ret0:
     123    flags = 0;
     124 ret:
     125    //bb_error_msg("2 org_mask:%o", org_mask);
     126    if (org_mask != cur_mask)
     127        umask(org_mask);
     128    return flags;
    103129}
  • branches/2.2.9/mindi-busybox/libbb/makedev.c

    r1765 r2725  
    22 * Utility routines.
    33 *
    4  * Copyright (C) 2006 Denis Vlasenko
     4 * Copyright (C) 2006 Denys Vlasenko
    55 *
    6  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2, see file LICENSE in this source tree.
    77 */
    88
    99/* We do not include libbb.h - #define makedev() is there! */
     10#include "platform.h"
    1011#include <features.h>
    1112#include <sys/sysmacros.h>
     
    1617
    1718/* suppress gcc "no previous prototype" warning */
    18 unsigned long long bb_makedev(unsigned int major, unsigned int minor);
    19 unsigned long long bb_makedev(unsigned int major, unsigned int minor)
     19unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor);
     20unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor)
    2021{
    2122    return makedev(major, minor);
  • branches/2.2.9/mindi-busybox/libbb/match_fstype.c

    r1765 r2725  
    66 *   mount -at ,noddy
    77 *
    8  * Returns 0 for a match, otherwise -1
     8 * Returns 1 for a match, otherwise 0
    99 *
    10  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1111 */
    1212
    1313#include "libbb.h"
    1414
    15 int match_fstype(const struct mntent *mt, const char *fstype)
     15int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
    1616{
    17     int no = 0;
     17    int match = 1;
    1818    int len;
    1919
    20     if (!mt)
    21         return -1;
     20    if (!t_fstype)
     21        return match;
    2222
    23     if (!fstype)
    24         return 0;
    25 
    26     if (fstype[0] == 'n' && fstype[1] == 'o') {
    27         no = -1;
    28         fstype += 2;
     23    if (t_fstype[0] == 'n' && t_fstype[1] == 'o') {
     24        match--;
     25        t_fstype += 2;
    2926    }
    3027
    3128    len = strlen(mt->mnt_type);
    32     while (fstype) {
    33         if (!strncmp(mt->mnt_type, fstype, len)
    34          && (!fstype[len] || fstype[len] == ',')
     29    while (1) {
     30        if (strncmp(mt->mnt_type, t_fstype, len) == 0
     31         && (t_fstype[len] == '\0' || t_fstype[len] == ',')
    3532        ) {
    36             return no;
     33            return match;
    3734        }
    38         fstype = strchr(fstype, ',');
    39         if (fstype)
    40             fstype++;
     35        t_fstype = strchr(t_fstype, ',');
     36        if (!t_fstype)
     37            break;
     38        t_fstype++;
    4139    }
    4240
    43     return -(no + 1);
     41    return !match;
    4442}
  • branches/2.2.9/mindi-busybox/libbb/messages.c

    r1765 r2725  
    33 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    66 */
    77
    88#include "libbb.h"
    99
     10/* allow default system PATH to be extended via CFLAGS */
     11#ifndef BB_ADDITIONAL_PATH
     12#define BB_ADDITIONAL_PATH ""
     13#endif
     14
     15/* allow version to be extended, via CFLAGS */
    1016#ifndef BB_EXTRA_VERSION
    11 #define BANNER "BusyBox v" BB_VER " (" BB_BT ")"
    12 #else
     17#define BB_EXTRA_VERSION BB_BT
     18#endif
     19
    1320#define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")"
    14 #endif
     21
    1522const char bb_banner[] ALIGN1 = BANNER;
     23
    1624
    1725const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted";
    1826const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'";
    19 const char bb_msg_write_error[] ALIGN1 = "write error";
    20 const char bb_msg_read_error[] ALIGN1 = "read error";
    2127const char bb_msg_unknown[] ALIGN1 = "(unknown)";
    2228const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket";
    23 const char bb_msg_perm_denied_are_you_root[] ALIGN1 = "permission denied. (are you root?)";
     29const char bb_msg_perm_denied_are_you_root[] ALIGN1 = "permission denied (are you root?)";
     30const char bb_msg_you_must_be_root[] ALIGN1 = "you must be root";
    2431const char bb_msg_requires_arg[] ALIGN1 = "%s requires an argument";
    2532const char bb_msg_invalid_arg[] ALIGN1 = "invalid argument '%s' to '%s'";
     
    2734const char bb_msg_standard_output[] ALIGN1 = "standard output";
    2835
    29 const char bb_str_default[] ALIGN1 = "default";
    3036const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
    3137
    32 const char bb_path_passwd_file[] ALIGN1 = "/etc/passwd";
    33 const char bb_path_shadow_file[] ALIGN1 = "/etc/shadow";
    34 const char bb_path_group_file[] ALIGN1 = "/etc/group";
    35 const char bb_path_gshadow_file[] ALIGN1 = "/etc/gshadow";
    36 const char bb_path_motd_file[] ALIGN1 = "/etc/motd";
    37 const char bb_dev_null[] ALIGN1 = "/dev/null";
    3838const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
    3939const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
    4040/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
    4141 * but I want to save a few bytes here. Check libbb.h before changing! */
    42 const char bb_PATH_root_path[] ALIGN1 = "PATH=/sbin:/usr/sbin:/bin:/usr/bin";
     42const char bb_PATH_root_path[] ALIGN1 =
     43    "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
    4344
    4445
    45 const int const_int_0;
    4646const int const_int_1 = 1;
     47/* explicitly = 0, otherwise gcc may make it a common variable
     48 * and it will end up in bss */
     49const int const_int_0 = 0;
    4750
    4851#include <utmp.h>
     
    5053const char bb_path_wtmp_file[] ALIGN1 =
    5154#if defined _PATH_WTMP
    52 _PATH_WTMP;
     55    _PATH_WTMP;
    5356#elif defined WTMP_FILE
    54 WTMP_FILE;
     57    WTMP_FILE;
    5558#else
    56 # error unknown path to wtmp file
     59#error unknown path to wtmp file
    5760#endif
    5861
    59 char bb_common_bufsiz1[COMMON_BUFSIZE];
    60 
    61 struct globals;
    62 /* Make it reside in R/W memory: */
    63 struct globals *const ptr_to_globals __attribute__ ((section (".data")));
     62/* We use it for "global" data via *(struct global*)&bb_common_bufsiz1.
     63 * Since gcc insists on aligning struct global's members, it would be a pity
     64 * (and an alignment fault on some CPUs) to mess it up. */
     65char bb_common_bufsiz1[COMMON_BUFSIZE] ALIGNED(sizeof(long long));
  • branches/2.2.9/mindi-busybox/libbb/mode_string.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    4949 * and 'B' types don't appear to be available on linux.  So I removed them. */
    5050static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???";
    51 /*                                  0123456789abcdef */
     51/***************************************** 0123456789abcdef */
    5252static const char mode_chars[7] ALIGN1 = "rwxSTst";
    5353
    54 const char *bb_mode_string(mode_t mode)
     54const char* FAST_FUNC bb_mode_string(mode_t mode)
    5555{
    5656    static char buf[12];
     
    8989 * and 'B' types don't appear to be available on linux.  So I removed them. */
    9090static const char type_chars[16] = "?pc?d?b?-?l?s???";
    91 /*                                  0123456789abcdef */
     91/********************************** 0123456789abcdef */
    9292static const char mode_chars[7] = "rwxSTst";
    9393
    94 const char *bb_mode_string(mode_t mode)
     94const char* FAST_FUNC bb_mode_string(mode_t mode)
    9595{
    9696    static char buf[12];
  • branches/2.2.9/mindi-busybox/libbb/mtab.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1212
    1313#if ENABLE_FEATURE_MTAB_SUPPORT
    14 void erase_mtab(const char *name)
     14void FAST_FUNC erase_mtab(const char *name)
    1515{
    16     struct mntent *entries = NULL;
    17     int i, count = 0;
     16    struct mntent *entries;
     17    int i, count;
    1818    FILE *mountTable;
    1919    struct mntent *m;
     
    2727    }
    2828
     29    entries = NULL;
     30    count = 0;
    2931    while ((m = getmntent(mountTable)) != 0) {
    30         i = count++;
    31         entries = xrealloc(entries, count * sizeof(entries[0]));
    32         entries[i].mnt_fsname = xstrdup(m->mnt_fsname);
    33         entries[i].mnt_dir = xstrdup(m->mnt_dir);
    34         entries[i].mnt_type = xstrdup(m->mnt_type);
    35         entries[i].mnt_opts = xstrdup(m->mnt_opts);
    36         entries[i].mnt_freq = m->mnt_freq;
    37         entries[i].mnt_passno = m->mnt_passno;
     32        entries = xrealloc_vector(entries, 3, count);
     33        entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
     34        entries[count].mnt_dir = xstrdup(m->mnt_dir);
     35        entries[count].mnt_type = xstrdup(m->mnt_type);
     36        entries[count].mnt_opts = xstrdup(m->mnt_opts);
     37        entries[count].mnt_freq = m->mnt_freq;
     38        entries[count].mnt_passno = m->mnt_passno;
     39        count++;
    3840    }
    3941    endmntent(mountTable);
    4042
     43//TODO: make update atomic
    4144    mountTable = setmntent(bb_path_mtab_file, "w");
    4245    if (mountTable) {
  • branches/2.2.9/mindi-busybox/libbb/obscure.c

    r1765 r2725  
    55 * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    4646static int string_checker_helper(const char *p1, const char *p2)
    4747{
     48    /* as sub-string */
     49    if (strcasestr(p2, p1) != NULL
     50    /* invert in case haystack is shorter than needle */
     51     || strcasestr(p1, p2) != NULL
    4852    /* as-is or capitalized */
    49     if (strcasecmp(p1, p2) == 0
    50     /* as sub-string */
    51     || strcasestr(p2, p1) != NULL
    52     /* invert in case haystack is shorter than needle */
    53     || strcasestr(p1, p2) != NULL)
     53    /* || strcasecmp(p1, p2) == 0 - 1st strcasestr should catch this too */
     54    ) {
    5455        return 1;
     56    }
    5557    return 0;
    5658}
     
    5860static int string_checker(const char *p1, const char *p2)
    5961{
    60     int size;
     62    int size, i;
    6163    /* check string */
    6264    int ret = string_checker_helper(p1, p2);
    63     /* Make our own copy */
     65    /* make our own copy */
    6466    char *p = xstrdup(p1);
     67
    6568    /* reverse string */
    66     size = strlen(p);
     69    i = size = strlen(p1);
     70    while (--i >= 0) {
     71        *p++ = p1[i];
     72    }
     73    p -= size; /* restore pointer */
    6774
    68     while (size--) {
    69         *p = p1[size];
    70         p++;
    71     }
    72     /* restore pointer */
    73     p -= strlen(p1);
    7475    /* check reversed string */
    7576    ret |= string_checker_helper(p, p2);
     77
    7678    /* clean up */
    77     memset(p, 0, strlen(p1));
     79    memset(p, 0, size);
    7880    free(p);
     81
    7982    return ret;
    8083}
    8184
    82 #define LOWERCASE          1
    83 #define UPPERCASE          2
    84 #define NUMBERS            4
    85 #define SPECIAL            8
     85#define CATEGORIES  4
     86
     87#define LOWERCASE   1
     88#define UPPERCASE   2
     89#define NUMBERS     4
     90#define SPECIAL     8
     91
     92#define LAST_CAT    8
    8693
    8794static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
    8895{
    89     int i;
    90     int c;
    91     int length;
    92     int mixed = 0;
    93     /* Add 2 for each type of characters to the minlen of password */
    94     int size = CONFIG_PASSWORD_MINLEN + 8;
     96    unsigned length;
     97    unsigned size;
     98    unsigned mixed;
     99    unsigned c;
     100    unsigned i;
    95101    const char *p;
    96     char hostname[255];
     102    char *hostname;
    97103
    98104    /* size */
     
    105111    }
    106112    /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
    107     if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) {
     113    if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) {
    108114        return "similar to gecos";
    109115    }
    110116    /* hostname as-is, as sub-string, reversed, capitalized, doubled */
    111     if (gethostname(hostname, 255) == 0) {
    112         hostname[254] = '\0';
    113         if (string_checker(new_p, hostname)) {
    114             return "similar to hostname";
    115         }
    116     }
     117    hostname = safe_gethostname();
     118    i = string_checker(new_p, hostname);
     119    free(hostname);
     120    if (i)
     121        return "similar to hostname";
    117122
    118123    /* Should / Must contain a mix of: */
     124    mixed = 0;
    119125    for (i = 0; i < length; i++) {
    120126        if (islower(new_p[i])) {        /* a-z */
     
    127133            mixed |= SPECIAL;
    128134        }
    129         /* More than 50% similar characters ? */
     135        /* Count i'th char */
    130136        c = 0;
    131137        p = new_p;
    132138        while (1) {
    133             if ((p = strchr(p, new_p[i])) == NULL) {
     139            p = strchr(p, new_p[i]);
     140            if (p == NULL) {
    134141                break;
    135142            }
    136143            c++;
    137             if (!++p) {
    138                 break; /* move past the matched char if possible */
     144            p++;
     145            if (!*p) {
     146                break;
    139147            }
    140148        }
    141 
    142         if (c >= (length / 2)) {
     149        /* More than 50% similar characters ? */
     150        if (c*2 >= length) {
    143151            return "too many similar characters";
    144152        }
    145153    }
    146     for (i=0; i<4; i++)
    147         if (mixed & (1<<i)) size -= 2;
     154
     155    size = CONFIG_PASSWORD_MINLEN + 2*CATEGORIES;
     156    for (i = 1; i <= LAST_CAT; i <<= 1)
     157        if (mixed & i)
     158            size -= 2;
    148159    if (length < size)
    149160        return "too weak";
    150161
    151     if (old_p && old_p[0] != '\0') {
     162    if (old_p && old_p[0]) {
    152163        /* check vs. old password */
    153164        if (string_checker(new_p, old_p)) {
     
    155166        }
    156167    }
     168
    157169    return NULL;
    158170}
    159171
    160 int obscure(const char *old, const char *newval, const struct passwd *pw)
     172int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw)
    161173{
    162174    const char *msg;
  • branches/2.2.9/mindi-busybox/libbb/parse_mode.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1616#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
    1717
    18 int bb_parse_mode(const char *s, mode_t *current_mode)
     18int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
    1919{
    2020    static const mode_t who_mask[] = {
     
    4141    char op;
    4242
    43     if (((unsigned int)(*s - '0')) < 8) {
     43    if ((unsigned char)(*s - '0') < 8) {
    4444        unsigned long tmp;
    4545        char *e;
     
    5858     * We treat an empty mode as no change to perms. */
    5959
    60     while (*s) {    /* Process clauses. */
    61         if (*s == ',') {    /* We allow empty clauses. */
     60    while (*s) {  /* Process clauses. */
     61        if (*s == ',') {  /* We allow empty clauses. */
    6262            ++s;
    6363            continue;
     
    7878        } while (*++p);
    7979
    80         do {    /* Process action list. */
     80        do {    /* Process action list. */
    8181            if ((*s != '+') && (*s != '-')) {
    8282                if (*s != '=') {
     
    9494
    9595            /* Check for permcopy. */
    96             p = who_chars + 1;  /* Skip 'a' entry. */
     96            p = who_chars + 1;  /* Skip 'a' entry. */
    9797            do {
    9898                if (*p == *s) {
     
    129129            } while (*++p);
    130130 GOT_ACTION:
    131             if (permlist) { /* The permlist was nonempty. */
     131            if (permlist) { /* The permlist was nonempty. */
    132132                mode_t tmp = wholist;
    133133                if (!wholist) {
  • branches/2.2.9/mindi-busybox/libbb/perror_msg.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
    12 void bb_perror_msg(const char *s, ...)
     11void FAST_FUNC bb_perror_msg(const char *s, ...)
    1312{
    1413    va_list p;
     
    1918    va_end(p);
    2019}
     20
     21void FAST_FUNC bb_perror_msg_and_die(const char *s, ...)
     22{
     23    va_list p;
     24
     25    va_start(p, s);
     26    /* Guard against "<error message>: Success" */
     27    bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
     28    va_end(p);
     29    xfunc_die();
     30}
     31
     32void FAST_FUNC bb_simple_perror_msg(const char *s)
     33{
     34    bb_perror_msg("%s", s);
     35}
     36
     37void FAST_FUNC bb_simple_perror_msg_and_die(const char *s)
     38{
     39    bb_perror_msg_and_die("%s", s);
     40}
  • branches/2.2.9/mindi-busybox/libbb/perror_nomsg.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1212 * instead of including libbb.h */
    1313//#include "libbb.h"
    14 extern void bb_perror_msg(const char *s, ...);
     14#include "platform.h"
     15extern void bb_perror_msg(const char *s, ...) FAST_FUNC;
    1516
    1617/* suppress gcc "no previous prototype" warning */
    17 void bb_perror_nomsg(void);
    18 void bb_perror_nomsg(void)
     18void FAST_FUNC bb_perror_nomsg(void);
     19void FAST_FUNC bb_perror_nomsg(void)
    1920{
    2021    bb_perror_msg(0);
  • branches/2.2.9/mindi-busybox/libbb/perror_nomsg_and_die.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1212 * instead of including libbb.h */
    1313//#include "libbb.h"
    14 extern void bb_perror_msg_and_die(const char *s, ...);
     14#include "platform.h"
     15extern void bb_perror_msg_and_die(const char *s, ...) FAST_FUNC;
    1516
    1617/* suppress gcc "no previous prototype" warning */
    17 void bb_perror_nomsg_and_die(void);
    18 void bb_perror_nomsg_and_die(void)
     18void FAST_FUNC bb_perror_nomsg_and_die(void);
     19void FAST_FUNC bb_perror_nomsg_and_die(void)
    1920{
    2021    bb_perror_msg_and_die(0);
  • branches/2.2.9/mindi-busybox/libbb/pidfile.c

    r1765 r2725  
    55 * Copyright (C) 2007 by Stephane Billiart <stephane.billiart@gmail.com>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1414smallint wrote_pidfile;
    1515
    16 void write_pidfile(const char *path)
     16void FAST_FUNC write_pidfile(const char *path)
    1717{
    1818    int pid_fd;
  • branches/2.2.9/mindi-busybox/libbb/process_escape_sequence.c

    r1765 r2725  
    66 * and Vladimir Oleynik <dzo@simtreas.ru>
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
     
    1717#define _tolower(X) ((X)|((char) 0x20))
    1818
    19 char bb_process_escape_sequence(const char **ptr)
     19char FAST_FUNC bb_process_escape_sequence(const char **ptr)
    2020{
    21     static const char charmap[] ALIGN1 = {
    22         'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
    23         '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
    24 
    25     const char *p;
    2621    const char *q;
    27     unsigned int num_digits;
    28     unsigned int r;
    29     unsigned int n;
    30     unsigned int d;
    31     unsigned int base;
     22    unsigned num_digits;
     23    unsigned n;
     24    unsigned base;
    3225
    3326    num_digits = n = 0;
     
    3528    q = *ptr;
    3629
    37 #ifdef WANT_HEX_ESCAPES
    38     if (*q == 'x') {
     30    if (WANT_HEX_ESCAPES && *q == 'x') {
    3931        ++q;
    4032        base = 16;
    4133        ++num_digits;
    4234    }
     35
     36    /* bash requires leading 0 in octal escapes:
     37     * \02 works, \2 does not (prints \ and 2).
     38     * We treat \2 as a valid octal escape sequence. */
     39    do {
     40        unsigned r;
     41#if !WANT_HEX_ESCAPES
     42        unsigned d = (unsigned char)(*q) - '0';
     43#else
     44        unsigned d = (unsigned char)_tolower(*q) - '0';
     45        if (d >= 10)
     46            d += ('0' - 'a' + 10);
    4347#endif
    44 
    45     do {
    46         d = (unsigned char)(*q) - '0';
    47 #ifdef WANT_HEX_ESCAPES
    48         if (d >= 10) {
    49             d = (unsigned char)(_tolower(*q)) - 'a' + 10;
    50         }
    51 #endif
    52 
    5348        if (d >= base) {
    54 #ifdef WANT_HEX_ESCAPES
    55             if ((base == 16) && (!--num_digits)) {
    56 /*              return '\\'; */
    57                 --q;
     49            if (WANT_HEX_ESCAPES && base == 16) {
     50                --num_digits;
     51                if (num_digits == 0) {
     52                    /* \x<bad_char>: return '\',
     53                     * leave ptr pointing to x */
     54                    return '\\';
     55                }
    5856            }
    59 #endif
    6057            break;
    6158        }
     
    7067    } while (++num_digits < 3);
    7168
    72     if (num_digits == 0) {  /* mnemonic escape sequence? */
    73         p = charmap;
     69    if (num_digits == 0) {
     70        /* Not octal or hex escape sequence.
     71         * Is it one-letter one? */
     72
     73        /* bash builtin "echo -e '\ec'" interprets \e as ESC,
     74         * but coreutils "/bin/echo -e '\ec'" does not.
     75         * Manpages tend to support coreutils way.
     76         * Update: coreutils added support for \e on 28 Oct 2009. */
     77        static const char charmap[] ALIGN1 = {
     78            'a',  'b', 'e', 'f',  'n',  'r',  't',  'v',  '\\', '\0',
     79            '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\',
     80        };
     81        const char *p = charmap;
    7482        do {
    7583            if (*p == *q) {
     
    7785                break;
    7886            }
    79         } while (*++p);
    80         n = *(p + (sizeof(charmap)/2));
     87        } while (*++p != '\0');
     88        /* p points to found escape char or NUL,
     89         * advance it and find what it translates to.
     90         * Note that \NUL and unrecognized sequence \z return '\'
     91         * and leave ptr pointing to NUL or z. */
     92        n = p[sizeof(charmap) / 2];
    8193    }
    8294
     
    8597    return (char) n;
    8698}
     99
     100char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src)
     101{
     102    while (1) {
     103        char c, c1;
     104        c = c1 = *src++;
     105        if (c1 == '\\')
     106            c1 = bb_process_escape_sequence(&src);
     107        *dst = c1;
     108        if (c == '\0')
     109            return dst;
     110        dst++;
     111    }
     112}
  • branches/2.2.9/mindi-busybox/libbb/procps.c

    r1765 r2725  
    77 * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 */
    1111
     
    1414
    1515typedef struct unsigned_to_name_map_t {
    16     unsigned id;
     16    long id;
    1717    char name[USERNAME_MAX_SIZE];
    1818} unsigned_to_name_map_t;
     
    3131    cp->size = 0;
    3232}
    33 void clear_username_cache(void)
     33void FAST_FUNC clear_username_cache(void)
    3434{
    3535    clear_cache(&username);
     
    4747            return i;
    4848    i = cp->size++;
    49     cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
     49    cp->cache = xrealloc_vector(cp->cache, 2, i);
    5050    cp->cache[i++].id = id;
    5151    return -i;
     
    5353#endif
    5454
    55 typedef char* ug_func(char *name, int bufsize, long uid);
    56 static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)
     55static char* get_cached(cache_t *cp, long id,
     56            char* FAST_FUNC x2x_utoa(long id))
    5757{
    5858    int i;
     
    6161            return cp->cache[i].name;
    6262    i = cp->size++;
    63     cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
     63    cp->cache = xrealloc_vector(cp->cache, 2, i);
    6464    cp->cache[i].id = id;
    6565    /* Never fails. Generates numeric string if name isn't found */
    66     fp(cp->cache[i].name, sizeof(cp->cache[i].name), id);
     66    safe_strncpy(cp->cache[i].name, x2x_utoa(id), sizeof(cp->cache[i].name));
    6767    return cp->cache[i].name;
    6868}
    69 const char* get_cached_username(uid_t uid)
    70 {
    71     return get_cached(&username, uid, bb_getpwuid);
    72 }
    73 const char* get_cached_groupname(gid_t gid)
    74 {
    75     return get_cached(&groupname, gid, bb_getgrgid);
     69const char* FAST_FUNC get_cached_username(uid_t uid)
     70{
     71    return get_cached(&username, uid, uid2uname_utoa);
     72}
     73const char* FAST_FUNC get_cached_groupname(gid_t gid)
     74{
     75    return get_cached(&groupname, gid, gid2group_utoa);
    7676}
    7777
     
    9494}
    9595
    96 procps_status_t *alloc_procps_scan(int flags)
    97 {
     96static procps_status_t* FAST_FUNC alloc_procps_scan(void)
     97{
     98    unsigned n = getpagesize();
    9899    procps_status_t* sp = xzalloc(sizeof(procps_status_t));
    99100    sp->dir = xopendir("/proc");
     101    while (1) {
     102        n >>= 1;
     103        if (!n) break;
     104        sp->shift_pages_to_bytes++;
     105    }
     106    sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
    100107    return sp;
    101108}
    102109
    103 void free_procps_scan(procps_status_t* sp)
     110void FAST_FUNC free_procps_scan(procps_status_t* sp)
    104111{
    105112    closedir(sp->dir);
     113#if ENABLE_FEATURE_SHOW_THREADS
     114    if (sp->task_dir)
     115        closedir(sp->task_dir);
     116#endif
    106117    free(sp->argv0);
    107     USE_SELINUX(free(sp->context);)
     118    free(sp->exe);
     119    IF_SELINUX(free(sp->context);)
    108120    free(sp);
    109121}
    110122
    111 #if ENABLE_FEATURE_FAST_TOP
     123#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
     124static unsigned long fast_strtoul_16(char **endptr)
     125{
     126    unsigned char c;
     127    char *str = *endptr;
     128    unsigned long n = 0;
     129
     130    while ((c = *str++) != ' ') {
     131        c = ((c|0x20) - '0');
     132        if (c > 9)
     133            // c = c + '0' - 'a' + 10:
     134            c = c - ('a' - '0' - 10);
     135        n = n*16 + c;
     136    }
     137    *endptr = str; /* We skip trailing space! */
     138    return n;
     139}
     140#endif
     141
     142#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
    112143/* We cut a lot of corners here for speed */
    113144static unsigned long fast_strtoul_10(char **endptr)
     
    123154    return n;
    124155}
     156
     157# if ENABLE_FEATURE_FAST_TOP
     158static long fast_strtol_10(char **endptr)
     159{
     160    if (**endptr != '-')
     161        return fast_strtoul_10(endptr);
     162
     163    (*endptr)++;
     164    return - (long)fast_strtoul_10(endptr);
     165}
     166# endif
     167
    125168static char *skip_fields(char *str, int count)
    126169{
     
    134177#endif
    135178
     179#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
     180int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
     181              void (*cb)(struct smaprec *, void *), void *data)
     182{
     183    FILE *file;
     184    struct smaprec currec;
     185    char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3];
     186    char buf[PROCPS_BUFSIZE];
     187#if !ENABLE_PMAP
     188    void (*cb)(struct smaprec *, void *) = NULL;
     189    void *data = NULL;
     190#endif
     191
     192    sprintf(filename, "/proc/%u/smaps", (int)pid);
     193
     194    file = fopen_for_read(filename);
     195    if (!file)
     196        return 1;
     197
     198    memset(&currec, 0, sizeof(currec));
     199    while (fgets(buf, PROCPS_BUFSIZE, file)) {
     200        // Each mapping datum has this form:
     201        // f7d29000-f7d39000 rw-s ADR M:m OFS FILE
     202        // Size:                nnn kB
     203        // Rss:                 nnn kB
     204        // .....
     205
     206        char *tp = buf, *p;
     207
     208#define SCAN(S, X) \
     209        if (strncmp(tp, S, sizeof(S)-1) == 0) {              \
     210            tp = skip_whitespace(tp + sizeof(S)-1);      \
     211            total->X += currec.X = fast_strtoul_10(&tp); \
     212            continue;                                    \
     213        }
     214        if (cb) {
     215            SCAN("Pss:"  , smap_pss     );
     216            SCAN("Swap:" , smap_swap    );
     217        }
     218        SCAN("Private_Dirty:", private_dirty);
     219        SCAN("Private_Clean:", private_clean);
     220        SCAN("Shared_Dirty:" , shared_dirty );
     221        SCAN("Shared_Clean:" , shared_clean );
     222#undef SCAN
     223        tp = strchr(buf, '-');
     224        if (tp) {
     225            // We reached next mapping - the line of this form:
     226            // f7d29000-f7d39000 rw-s ADR M:m OFS FILE
     227
     228            if (cb) {
     229                /* If we have a previous record, there's nothing more
     230                 * for it, call the callback and clear currec
     231                 */
     232                if (currec.smap_size)
     233                    cb(&currec, data);
     234                free(currec.smap_name);
     235            }
     236            memset(&currec, 0, sizeof(currec));
     237
     238            *tp = ' ';
     239            tp = buf;
     240            currec.smap_start = fast_strtoul_16(&tp);
     241            currec.smap_size = (fast_strtoul_16(&tp) - currec.smap_start) >> 10;
     242
     243            strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1);
     244
     245            // skipping "rw-s ADR M:m OFS "
     246            tp = skip_whitespace(skip_fields(tp, 4));
     247            // filter out /dev/something (something != zero)
     248            if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
     249                if (currec.smap_mode[1] == 'w') {
     250                    currec.mapped_rw = currec.smap_size;
     251                    total->mapped_rw += currec.smap_size;
     252                } else if (currec.smap_mode[1] == '-') {
     253                    currec.mapped_ro = currec.smap_size;
     254                    total->mapped_ro += currec.smap_size;
     255                }
     256            }
     257
     258            if (strcmp(tp, "[stack]\n") == 0)
     259                total->stack += currec.smap_size;
     260            if (cb) {
     261                p = skip_non_whitespace(tp);
     262                if (p == tp) {
     263                    currec.smap_name = xstrdup("  [ anon ]");
     264                } else {
     265                    *p = '\0';
     266                    currec.smap_name = xstrdup(tp);
     267                }
     268            }
     269            total->smap_size += currec.smap_size;
     270        }
     271    }
     272    fclose(file);
     273
     274    if (cb) {
     275        if (currec.smap_size)
     276            cb(&currec, data);
     277        free(currec.smap_name);
     278    }
     279
     280    return 0;
     281}
     282#endif
     283
    136284void BUG_comm_size(void);
    137 procps_status_t *procps_scan(procps_status_t* sp, int flags)
     285procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
    138286{
    139287    struct dirent *entry;
     
    147295
    148296    if (!sp)
    149         sp = alloc_procps_scan(flags);
     297        sp = alloc_procps_scan();
    150298
    151299    for (;;) {
     300#if ENABLE_FEATURE_SHOW_THREADS
     301        if ((flags & PSSCAN_TASKS) && sp->task_dir) {
     302            entry = readdir(sp->task_dir);
     303            if (entry)
     304                goto got_entry;
     305            closedir(sp->task_dir);
     306            sp->task_dir = NULL;
     307        }
     308#endif
    152309        entry = readdir(sp->dir);
    153310        if (entry == NULL) {
     
    155312            return NULL;
    156313        }
     314 IF_FEATURE_SHOW_THREADS(got_entry:)
    157315        pid = bb_strtou(entry->d_name, NULL, 10);
    158316        if (errno)
    159317            continue;
    160 
    161         /* After this point we have to break, not continue
    162          * ("continue" would mean that current /proc/NNN
    163          * is not a valid process info) */
     318#if ENABLE_FEATURE_SHOW_THREADS
     319        if ((flags & PSSCAN_TASKS) && !sp->task_dir) {
     320            /* We found another /proc/PID. Do not use it,
     321             * there will be /proc/PID/task/PID (same PID!),
     322             * so just go ahead and dive into /proc/PID/task. */
     323            char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3];
     324            sprintf(task_dir, "/proc/%u/task", pid);
     325            sp->task_dir = xopendir(task_dir);
     326            continue;
     327        }
     328#endif
     329
     330        /* After this point we can:
     331         * "break": stop parsing, return the data
     332         * "continue": try next /proc/XXX
     333         */
    164334
    165335        memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
    166336
    167337        sp->pid = pid;
    168         if (!(flags & ~PSSCAN_PID)) break;
     338        if (!(flags & ~PSSCAN_PID))
     339            break; /* we needed only pid, we got it */
    169340
    170341#if ENABLE_SELINUX
     
    175346#endif
    176347
    177         filename_tail = filename + sprintf(filename, "/proc/%d", pid);
     348        filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
    178349
    179350        if (flags & PSSCAN_UIDGID) {
    180351            if (stat(filename, &sb))
    181                 break;
    182             /* Need comment - is this effective or real UID/GID? */
     352                continue; /* process probably exited */
     353            /* Effective UID/GID, not real */
    183354            sp->uid = sb.st_uid;
    184355            sp->gid = sb.st_gid;
     
    191362            unsigned long vsz, rss;
    192363#endif
    193 
    194364            /* see proc(5) for some details on this */
    195             strcpy(filename_tail, "/stat");
     365            strcpy(filename_tail, "stat");
    196366            n = read_to_buf(filename, buf);
    197367            if (n < 0)
    198                 break;
     368                continue; /* process probably exited */
    199369            cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
    200370            /*if (!cp || cp[1] != ' ')
    201                 break;*/
     371                continue;*/
    202372            cp[0] = '\0';
    203373            if (sizeof(sp->comm) < 16)
     
    215385                "%*s %*s %*s "         /* cutime, cstime, priority */
    216386                "%ld "                 /* nice */
    217                 "%*s %*s %*s "         /* timeout, it_real_value, start_time */
     387                "%*s %*s "             /* timeout, it_real_value */
     388                "%lu "                 /* start_time */
    218389                "%lu "                 /* vsize */
    219390                "%lu "                 /* rss */
    220             /*  "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
    221             /*  "%u %u %u %u "         signal, blocked, sigignore, sigcatch */
    222             /*  "%lu %lu %lu"          wchan, nswap, cnswap */
     391# if ENABLE_FEATURE_TOP_SMP_PROCESS
     392                "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
     393                "%*s %*s %*s %*s "         /*signal, blocked, sigignore, sigcatch */
     394                "%*s %*s %*s %*s "         /*wchan, nswap, cnswap, exit_signal */
     395                "%d"                       /*cpu last seen on*/
     396# endif
    223397                ,
    224398                sp->state, &sp->ppid,
     
    226400                &sp->utime, &sp->stime,
    227401                &tasknice,
     402                &sp->start_time,
    228403                &vsz,
    229                 &rss);
    230             if (n != 10)
    231                 break;
    232             sp->vsz = vsz >> 10; /* vsize is in bytes and we want kb */
    233             sp->rss = rss >> 10;
     404                &rss
     405# if ENABLE_FEATURE_TOP_SMP_PROCESS
     406                , &sp->last_seen_on_cpu
     407# endif
     408                );
     409
     410            if (n < 11)
     411                continue; /* bogus data, get next /proc/XXX */
     412# if ENABLE_FEATURE_TOP_SMP_PROCESS
     413            if (n < 11+15)
     414                sp->last_seen_on_cpu = 0;
     415# endif
     416
     417            /* vsz is in bytes and we want kb */
     418            sp->vsz = vsz >> 10;
     419            /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
     420            sp->rss = rss << sp->shift_pages_to_kb;
    234421            sp->tty_major = (tty >> 8) & 0xfff;
    235422            sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
     
    249436            sp->stime = fast_strtoul_10(&cp);
    250437            cp = skip_fields(cp, 3); /* cutime, cstime, priority */
    251             tasknice = fast_strtoul_10(&cp);
    252             cp = skip_fields(cp, 3); /* timeout, it_real_value, start_time */
    253             sp->vsz = fast_strtoul_10(&cp) >> 10; /* vsize is in bytes and we want kb */
    254             sp->rss = fast_strtoul_10(&cp) >> 10;
     438            tasknice = fast_strtol_10(&cp);
     439            cp = skip_fields(cp, 2); /* timeout, it_real_value */
     440            sp->start_time = fast_strtoul_10(&cp);
     441            /* vsz is in bytes and we want kb */
     442            sp->vsz = fast_strtoul_10(&cp) >> 10;
     443            /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
     444            sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
     445# if ENABLE_FEATURE_TOP_SMP_PROCESS
     446            /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
     447            /* (4): signal, blocked, sigignore, sigcatch */
     448            /* (4): wchan, nswap, cnswap, exit_signal */
     449            cp = skip_fields(cp, 14);
     450//FIXME: is it safe to assume this field exists?
     451            sp->last_seen_on_cpu = fast_strtoul_10(&cp);
     452# endif
     453#endif /* FEATURE_FAST_TOP */
     454
     455#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
     456            sp->niceness = tasknice;
    255457#endif
    256458
     
    265467            else
    266468                sp->state[2] = ' ';
    267 
    268         }
    269 
     469        }
     470
     471#if ENABLE_FEATURE_TOPMEM
     472        if (flags & PSSCAN_SMAPS)
     473            procps_read_smaps(pid, &sp->smaps, NULL, NULL);
     474#endif /* TOPMEM */
     475#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
     476        if (flags & PSSCAN_RUIDGID) {
     477            FILE *file;
     478
     479            strcpy(filename_tail, "status");
     480            file = fopen_for_read(filename);
     481            if (file) {
     482                while (fgets(buf, sizeof(buf), file)) {
     483                    char *tp;
     484#define SCAN_TWO(str, name, statement) \
     485    if (strncmp(buf, str, sizeof(str)-1) == 0) { \
     486        tp = skip_whitespace(buf + sizeof(str)-1); \
     487        sscanf(tp, "%u", &sp->name); \
     488        statement; \
     489    }
     490                    SCAN_TWO("Uid:", ruid, continue);
     491                    SCAN_TWO("Gid:", rgid, break);
     492#undef SCAN_TWO
     493                }
     494                fclose(file);
     495            }
     496        }
     497#endif /* PS_ADDITIONAL_COLUMNS */
     498        if (flags & PSSCAN_EXE) {
     499            strcpy(filename_tail, "exe");
     500            free(sp->exe);
     501            sp->exe = xmalloc_readlink(filename);
     502        }
     503        /* Note: if /proc/PID/cmdline is empty,
     504         * code below "breaks". Therefore it must be
     505         * the last code to parse /proc/PID/xxx data
     506         * (we used to have /proc/PID/exe parsing after it
     507         * and were getting stale sp->exe).
     508         */
    270509#if 0 /* PSSCAN_CMD is not used */
    271510        if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
    272             if (sp->argv0) {
    273                 free(sp->argv0);
    274                 sp->argv0 = NULL;
    275             }
    276             if (sp->cmd) {
    277                 free(sp->cmd);
    278                 sp->cmd = NULL;
    279             }
    280             strcpy(filename_tail, "/cmdline");
     511            free(sp->argv0);
     512            sp->argv0 = NULL;
     513            free(sp->cmd);
     514            sp->cmd = NULL;
     515            strcpy(filename_tail, "cmdline");
    281516            /* TODO: to get rid of size limits, read into malloc buf,
    282517             * then realloc it down to real size. */
     
    296531        }
    297532#else
    298         if (flags & PSSCAN_ARGV0) {
    299             if (sp->argv0) {
    300                 free(sp->argv0);
    301                 sp->argv0 = NULL;
    302             }
    303             strcpy(filename_tail, "/cmdline");
     533        if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) {
     534            free(sp->argv0);
     535            sp->argv0 = NULL;
     536            strcpy(filename_tail, "cmdline");
    304537            n = read_to_buf(filename, buf);
    305538            if (n <= 0)
    306539                break;
    307             if (flags & PSSCAN_ARGV0)
     540            if (flags & PSSCAN_ARGVN) {
     541                sp->argv_len = n;
     542                sp->argv0 = xmalloc(n + 1);
     543                memcpy(sp->argv0, buf, n + 1);
     544                /* sp->argv0[n] = '\0'; - buf has it */
     545            } else {
     546                sp->argv_len = 0;
    308547                sp->argv0 = xstrdup(buf);
     548            }
    309549        }
    310550#endif
    311551        break;
    312     }
     552    } /* for (;;) */
     553
    313554    return sp;
    314555}
    315556
    316 void read_cmdline(char *buf, int col, unsigned pid, const char *comm)
    317 {
    318     ssize_t sz;
     557void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
     558{
     559    int sz;
    319560    char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
    320561
    321562    sprintf(filename, "/proc/%u/cmdline", pid);
    322     sz = open_read_close(filename, buf, col);
     563    sz = open_read_close(filename, buf, col - 1);
    323564    if (sz > 0) {
    324565        buf[sz] = '\0';
    325         while (--sz >= 0)
     566        while (--sz >= 0 && buf[sz] == '\0')
     567            continue;
     568        do {
    326569            if ((unsigned char)(buf[sz]) < ' ')
    327570                buf[sz] = ' ';
     571        } while (--sz >= 0);
    328572    } else {
    329573        snprintf(buf, col, "[%s]", comm);
  • branches/2.2.9/mindi-busybox/libbb/pw_encrypt.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Utility routine.
     3 * Utility routines.
    44 *
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    11 #include <crypt.h>
    1211
    13 char *pw_encrypt(const char *clear, const char *salt)
     12/* static const uint8_t ascii64[] =
     13 * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     14 */
     15
     16static int i64c(int i)
    1417{
    15     /* Was static char[BIGNUM]. Malloced thing works as well */
    16     static char *cipher;
     18    i &= 0x3f;
     19    if (i == 0)
     20        return '.';
     21    if (i == 1)
     22        return '/';
     23    if (i < 12)
     24        return ('0' - 2 + i);
     25    if (i < 38)
     26        return ('A' - 12 + i);
     27    return ('a' - 38 + i);
     28}
    1729
    18 #if 0 /* was CONFIG_FEATURE_SHA1_PASSWORDS, but there is no such thing??? */
    19     if (strncmp(salt, "$2$", 3) == 0) {
    20         return sha1_crypt(clear);
     30int FAST_FUNC crypt_make_salt(char *p, int cnt, int x)
     31{
     32    x += getpid() + time(NULL);
     33    do {
     34        /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
     35         * (low-order bit is not "random", etc...),
     36         * but for our purposes it is good enough */
     37        x = x*1664525 + 1013904223;
     38        /* BTW, Park and Miller's "minimal standard generator" is
     39         * x = x*16807 % ((2^31)-1)
     40         * It has no problem with visibly alternating lowest bit
     41         * but is also weak in cryptographic sense + needs div,
     42         * which needs more code (and slower) on many CPUs */
     43        *p++ = i64c(x >> 16);
     44        *p++ = i64c(x >> 22);
     45    } while (--cnt);
     46    *p = '\0';
     47    return x;
     48}
     49
     50#if ENABLE_USE_BB_CRYPT
     51
     52static char*
     53to64(char *s, unsigned v, int n)
     54{
     55    while (--n >= 0) {
     56        /* *s++ = ascii64[v & 0x3f]; */
     57        *s++ = i64c(v);
     58        v >>= 6;
    2159    }
     60    return s;
     61}
     62
     63/*
     64 * DES and MD5 crypt implementations are taken from uclibc.
     65 * They were modified to not use static buffers.
     66 */
     67
     68#include "pw_encrypt_des.c"
     69#include "pw_encrypt_md5.c"
     70#if ENABLE_USE_BB_CRYPT_SHA
     71#include "pw_encrypt_sha.c"
    2272#endif
    2373
    24     free(cipher);
    25     cipher = xstrdup(crypt(clear, salt));
    26     return cipher;
     74/* Other advanced crypt ids (TODO?): */
     75/* $2$ or $2a$: Blowfish */
     76
     77static struct const_des_ctx *des_cctx;
     78static struct des_ctx *des_ctx;
     79
     80/* my_crypt returns malloc'ed data */
     81static char *my_crypt(const char *key, const char *salt)
     82{
     83    /* MD5 or SHA? */
     84    if (salt[0] == '$' && salt[1] && salt[2] == '$') {
     85        if (salt[1] == '1')
     86            return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
     87#if ENABLE_USE_BB_CRYPT_SHA
     88        if (salt[1] == '5' || salt[1] == '6')
     89            return sha_crypt((char*)key, (char*)salt);
     90#endif
     91    }
     92
     93    if (!des_cctx)
     94        des_cctx = const_des_init();
     95    des_ctx = des_init(des_ctx, des_cctx);
     96    return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
    2797}
     98
     99/* So far nobody wants to have it public */
     100static void my_crypt_cleanup(void)
     101{
     102    free(des_cctx);
     103    free(des_ctx);
     104    des_cctx = NULL;
     105    des_ctx = NULL;
     106}
     107
     108char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
     109{
     110    char *encrypted;
     111
     112    encrypted = my_crypt(clear, salt);
     113
     114    if (cleanup)
     115        my_crypt_cleanup();
     116
     117    return encrypted;
     118}
     119
     120#else /* if !ENABLE_USE_BB_CRYPT */
     121
     122char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
     123{
     124    return xstrdup(crypt(clear, salt));
     125}
     126
     127#endif
  • branches/2.2.9/mindi-busybox/libbb/read.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
    12 ssize_t safe_read(int fd, void *buf, size_t count)
     11ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count)
    1312{
    1413    ssize_t n;
     
    2726 * A short read is returned on an end of file.
    2827 */
    29 ssize_t full_read(int fd, void *buf, size_t len)
     28ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len)
    3029{
    3130    ssize_t cc;
     
    3736        cc = safe_read(fd, buf, len);
    3837
    39         if (cc < 0)
    40             return cc;  /* read() returns -1 on failure. */
     38        if (cc < 0) {
     39            if (total) {
     40                /* we already have some! */
     41                /* user can do another read to know the error code */
     42                return total;
     43            }
     44            return cc; /* read() returns -1 on failure. */
     45        }
    4146        if (cc == 0)
    4247            break;
     
    4954}
    5055
    51 // Die with an error message if we can't read the entire buffer.
    52 void xread(int fd, void *buf, size_t count)
    53 {
    54     if (count) {
    55         ssize_t size = full_read(fd, buf, count);
    56         if (size != count)
    57             bb_error_msg_and_die("short read");
    58     }
    59 }
    60 
    61 // Die with an error message if we can't read one character.
    62 unsigned char xread_char(int fd)
    63 {
    64     char tmp;
    65     xread(fd, &tmp, 1);
    66     return tmp;
    67 }
    68 
    69 // Read one line a-la fgets. Works only on seekable streams
    70 char *reads(int fd, char *buffer, size_t size)
    71 {
    72     char *p;
    73 
    74     if (size < 2)
    75         return NULL;
    76     size = full_read(fd, buffer, size-1);
    77     if ((ssize_t)size <= 0)
    78         return NULL;
    79 
    80     buffer[size] = '\0';
    81     p = strchr(buffer, '\n');
    82     if (p) {
    83         off_t offset;
    84         *p++ = '\0';
    85         // avoid incorrect (unsigned) widening
    86         offset = (off_t)(p-buffer) - (off_t)size;
    87         // set fd position right after '\n'
    88         if (offset && lseek(fd, offset, SEEK_CUR) == (off_t)-1)
    89             return NULL;
    90     }
    91     return buffer;
    92 }
    93 
    94 // Read one line a-la fgets. Reads byte-by-byte.
    95 // Useful when it is important to not read ahead.
    96 char *xmalloc_reads(int fd, char *buf)
    97 {
    98     char *p;
    99     int sz = buf ? strlen(buf) : 0;
    100 
    101     goto jump_in;
    102     while (1) {
    103         if (p - buf == sz) {
    104  jump_in:
    105             buf = xrealloc(buf, sz + 128);
    106             p = buf + sz;
    107             sz += 128;
    108         }
    109         if (safe_read(fd, p, 1) != 1) { /* EOF/error */
    110             if (p == buf) {
    111                 /* we read nothing [and buf was NULL initially] */
    112                 free(buf);
    113                 return NULL;
    114             }
    115             break;
    116         }
    117         if (*p == '\n')
    118             break;
    119         p++;
    120     }
    121     *p++ = '\0';
    122     return xrealloc(buf, p - buf);
    123 }
    124 
    125 ssize_t read_close(int fd, void *buf, size_t size)
     56ssize_t FAST_FUNC read_close(int fd, void *buf, size_t size)
    12657{
    12758    /*int e;*/
     
    13364}
    13465
    135 ssize_t open_read_close(const char *filename, void *buf, size_t size)
     66ssize_t FAST_FUNC open_read_close(const char *filename, void *buf, size_t size)
    13667{
    13768    int fd = open(filename, O_RDONLY);
     
    14071    return read_close(fd, buf, size);
    14172}
    142 
    143 // Read (potentially big) files in one go. File size is estimated by
    144 // lseek to end.
    145 void *xmalloc_open_read_close(const char *filename, size_t *sizep)
    146 {
    147     char *buf;
    148     size_t size = sizep ? *sizep : INT_MAX;
    149     int fd;
    150     off_t len;
    151 
    152     fd = xopen(filename, O_RDONLY);
    153     /* /proc/N/stat files report len 0 here */
    154     /* In order to make such files readable, we add small const */
    155     len = xlseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */
    156     xlseek(fd, 0, SEEK_SET);
    157     if (len < size)
    158         size = len;
    159     buf = xmalloc(size + 1);
    160     size = read_close(fd, buf, size);
    161     if ((ssize_t)size < 0)
    162         bb_perror_msg_and_die("'%s'", filename);
    163     xrealloc(buf, size + 1);
    164     buf[size] = '\0';
    165     if (sizep)
    166         *sizep = size;
    167     return buf;
    168 }
  • branches/2.2.9/mindi-busybox/libbb/recursive_action.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    2323 */
    2424
    25 static int true_action(const char *fileName, struct stat *statbuf,
    26                         void* userData, int depth)
     25static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM,
     26        struct stat *statbuf UNUSED_PARAM,
     27        void* userData UNUSED_PARAM,
     28        int depth UNUSED_PARAM)
    2729{
    2830    return TRUE;
     
    3335 * (fileAction/dirAction will be called on each file).
    3436 *
    35  * if !depthFirst, dirAction return value of 0 (FALSE) or 2 (SKIP)
    36  * prevents recursion into that directory, instead
    37  * recursive_action() returns 0 (if FALSE) or 1 (if SKIP).
     37 * If !ACTION_RECURSE, dirAction is called on the directory and its
     38 * return value is returned from recursive_action(). No recursion.
    3839 *
    39  * followLinks=0/1 differs mainly in handling of links to dirs.
     40 * If ACTION_RECURSE, recursive_action() is called on each directory.
     41 * If any one of these calls returns 0, current recursive_action() returns 0.
     42 *
     43 * If ACTION_DEPTHFIRST, dirAction is called after recurse.
     44 * If it returns 0, the warning is printed and recursive_action() returns 0.
     45 *
     46 * If !ACTION_DEPTHFIRST, dirAction is called before we recurse.
     47 * Return value of 0 (FALSE) or 2 (SKIP) prevents recursion
     48 * into that directory, instead recursive_action() returns 0 (if FALSE)
     49 * or 1 (if SKIP)
     50 *
     51 * ACTION_FOLLOWLINKS mainly controls handling of links to dirs.
    4052 * 0: lstat(statbuf). Calls fileAction on link name even if points to dir.
    4153 * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
    4254 */
    4355
    44 int recursive_action(const char *fileName,
     56int FAST_FUNC recursive_action(const char *fileName,
    4557        unsigned flags,
    46         int (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
    47         int (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
     58        int FAST_FUNC (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
     59        int FAST_FUNC (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
    4860        void* userData,
    4961        unsigned depth)
    5062{
    5163    struct stat statbuf;
     64    unsigned follow;
    5265    int status;
    5366    DIR *dir;
     
    5770    if (!dirAction) dirAction = true_action;
    5871
    59     status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */
    60     if (!depth) status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
    61     status = ((flags & status) ? stat : lstat)(fileName, &statbuf);
     72    follow = ACTION_FOLLOWLINKS;
     73    if (depth == 0)
     74        follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
     75    follow &= flags;
     76    status = (follow ? stat : lstat)(fileName, &statbuf);
    6277    if (status < 0) {
    6378#ifdef DEBUG_RECURS_ACTION
    6479        bb_error_msg("status=%d flags=%x", status, flags);
    6580#endif
     81        if ((flags & ACTION_DANGLING_OK)
     82         && errno == ENOENT
     83         && lstat(fileName, &statbuf) == 0
     84        ) {
     85            /* Dangling link */
     86            return fileAction(fileName, &statbuf, userData, depth);
     87        }
    6688        goto done_nak_warn;
    6789    }
     
    104126        if (nextFile == NULL)
    105127            continue;
    106         /* now descend into it (NB: ACTION_RECURSE is set in flags) */
    107         if (!recursive_action(nextFile, flags, fileAction, dirAction, userData, depth+1))
     128        /* process every file (NB: ACTION_RECURSE is set in flags) */
     129        if (!recursive_action(nextFile, flags, fileAction, dirAction,
     130                        userData, depth + 1))
    108131            status = FALSE;
     132//      s = recursive_action(nextFile, flags, fileAction, dirAction,
     133//                      userData, depth + 1);
    109134        free(nextFile);
     135//#define RECURSE_RESULT_ABORT 3
     136//      if (s == RECURSE_RESULT_ABORT) {
     137//          closedir(dir);
     138//          return s;
     139//      }
     140//      if (s == FALSE)
     141//          status = FALSE;
    110142    }
    111143    closedir(dir);
     
    116148    }
    117149
    118     if (!status)
    119         return FALSE;
    120     return TRUE;
     150    return status;
    121151
    122152 done_nak_warn:
    123     bb_perror_msg("%s", fileName);
     153    if (!(flags & ACTION_QUIET))
     154        bb_simple_perror_msg(fileName);
    124155    return FALSE;
    125156}
  • branches/2.2.9/mindi-busybox/libbb/remove_file.c

    r1765 r2725  
    55 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1212/* Used from NOFORK applets. Must not allocate anything */
    1313
    14 int remove_file(const char *path, int flags)
     14int FAST_FUNC remove_file(const char *path, int flags)
    1515{
    1616    struct stat path_stat;
     
    1818    if (lstat(path, &path_stat) < 0) {
    1919        if (errno != ENOENT) {
    20             bb_perror_msg("cannot stat '%s'", path);
     20            bb_perror_msg("can't stat '%s'", path);
    2121            return -1;
    2222        }
    2323        if (!(flags & FILEUTILS_FORCE)) {
    24             bb_perror_msg("cannot remove '%s'", path);
     24            bb_perror_msg("can't remove '%s'", path);
    2525            return -1;
    2626        }
     
    6464
    6565        if (closedir(dp) < 0) {
    66             bb_perror_msg("cannot close '%s'", path);
     66            bb_perror_msg("can't close '%s'", path);
    6767            return -1;
    6868        }
     
    7575
    7676        if (rmdir(path) < 0) {
    77             bb_perror_msg("cannot remove '%s'", path);
     77            bb_perror_msg("can't remove '%s'", path);
    7878            return -1;
    7979        }
     
    8383
    8484    /* !ISDIR */
    85     if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0
    86             && !S_ISLNK(path_stat.st_mode) && isatty(0))
     85    if ((!(flags & FILEUTILS_FORCE)
     86         && access(path, W_OK) < 0
     87         && !S_ISLNK(path_stat.st_mode)
     88         && isatty(0))
    8789     || (flags & FILEUTILS_INTERACTIVE)
    8890    ) {
     
    9395
    9496    if (unlink(path) < 0) {
    95         bb_perror_msg("cannot remove '%s'", path);
     97        bb_perror_msg("can't remove '%s'", path);
    9698        return -1;
    9799    }
  • branches/2.2.9/mindi-busybox/libbb/run_shell.c

    r1765 r2725  
    3737static security_context_t current_sid;
    3838
    39 void
    40 renew_current_security_context(void)
     39void FAST_FUNC renew_current_security_context(void)
    4140{
    42     if (current_sid)
    43         freecon(current_sid);  /* Release old context  */
     41    freecon(current_sid);  /* Release old context  */
    4442    getcon(&current_sid);  /* update */
    4543}
    46 void
    47 set_current_security_context(security_context_t sid)
     44void FAST_FUNC set_current_security_context(security_context_t sid)
    4845{
    49     if (current_sid)
    50         freecon(current_sid);  /* Release old context  */
     46    freecon(current_sid);  /* Release old context  */
    5147    current_sid = sid;
    5248}
     
    5450#endif
    5551
    56 /* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
    57    If COMMAND is nonzero, pass it to the shell with the -c option.
    58    If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
    59    arguments.  */
    60 
    61 void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
     52/* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL.
     53 * If COMMAND is nonzero, pass it to the shell with the -c option.
     54 * If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
     55 * arguments.  */
     56void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
    6257{
    6358    const char **args;
    64     int argno = 1;
     59    int argno;
    6560    int additional_args_cnt = 0;
    6661
     
    7065    args = xmalloc(sizeof(char*) * (4 + additional_args_cnt));
    7166
    72     args[0] = bb_get_last_path_component(xstrdup(shell));
     67    if (!shell || !shell[0])
     68        shell = DEFAULT_SHELL;
    7369
     70    args[0] = bb_get_last_path_component_nostrip(shell);
    7471    if (loginshell)
    7572        args[0] = xasprintf("-%s", args[0]);
    76 
     73    argno = 1;
    7774    if (command) {
    7875        args[argno++] = "-c";
     
    8481    }
    8582    args[argno] = NULL;
     83
    8684#if ENABLE_SELINUX
    87     if (current_sid && !setexeccon(current_sid)) {
     85    if (current_sid)
     86        setexeccon(current_sid);
     87    if (ENABLE_FEATURE_CLEAN_UP)
    8888        freecon(current_sid);
    89         execve(shell, (char **) args, environ);
    90     } else
    9189#endif
    9290    execv(shell, (char **) args);
    93     bb_perror_msg_and_die("cannot run %s", shell);
     91    bb_perror_msg_and_die("can't execute '%s'", shell);
    9492}
  • branches/2.2.9/mindi-busybox/libbb/safe_strncpy.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1111
    1212/* Like strncpy but make sure the resulting string is always 0 terminated. */
    13 char * safe_strncpy(char *dst, const char *src, size_t size)
     13char* FAST_FUNC safe_strncpy(char *dst, const char *src, size_t size)
    1414{
    1515    if (!size) return dst;
     
    1717    return strncpy(dst, src, size);
    1818}
     19
     20/* Like strcpy but can copy overlapping strings. */
     21void FAST_FUNC overlapping_strcpy(char *dst, const char *src)
     22{
     23    /* Cheap optimization for dst == src case -
     24     * better to have it here than in many callers.
     25     */
     26    if (dst != src) {
     27        while ((*dst = *src) != '\0') {
     28            dst++;
     29            src++;
     30        }
     31    }
     32}
  • branches/2.2.9/mindi-busybox/libbb/safe_write.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 ssize_t safe_write(int fd, const void *buf, size_t count)
     12ssize_t FAST_FUNC safe_write(int fd, const void *buf, size_t count)
    1313{
    1414    ssize_t n;
  • branches/2.2.9/mindi-busybox/libbb/selinux_common.c

    r1765 r2725  
    44 *
    55 * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
     6 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    68 */
    79#include "libbb.h"
    810#include <selinux/context.h>
    911
    10 context_t set_security_context_component(security_context_t cur_context,
     12context_t FAST_FUNC set_security_context_component(security_context_t cur_context,
    1113                     char *user, char *role, char *type, char *range)
    1214{
     
    3032}
    3133
    32 void setfscreatecon_or_die(security_context_t scontext)
     34void FAST_FUNC setfscreatecon_or_die(security_context_t scontext)
    3335{
    3436    if (setfscreatecon(scontext) < 0) {
    3537        /* Can be NULL. All known printf implementations
    3638         * display "(null)", "<null>" etc */
    37         bb_perror_msg_and_die("cannot set default "
     39        bb_perror_msg_and_die("can't set default "
    3840                "file creation context to %s", scontext);
    3941    }
    4042}
     43
     44void FAST_FUNC selinux_preserve_fcontext(int fdesc)
     45{
     46    security_context_t context;
     47
     48    if (fgetfilecon(fdesc, &context) < 0) {
     49        if (errno == ENODATA || errno == ENOTSUP)
     50            return;
     51        bb_perror_msg_and_die("fgetfilecon failed");
     52    }
     53    setfscreatecon_or_die(context);
     54    freecon(context);
     55}
  • branches/2.2.9/mindi-busybox/libbb/setup_environment.c

    r1765 r2725  
    3131#include "libbb.h"
    3232
    33 void setup_environment(const char *shell, int loginshell, int changeenv, const struct passwd *pw)
     33void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw)
    3434{
    35     if (loginshell) {
     35    /* Change the current working directory to be the home directory
     36     * of the user */
     37    if (chdir(pw->pw_dir)) {
     38        xchdir((flags & SETUP_ENV_TO_TMP) ? "/tmp" : "/");
     39        bb_error_msg("can't chdir to home directory '%s'", pw->pw_dir);
     40    }
     41
     42    if (flags & SETUP_ENV_CLEARENV) {
    3643        const char *term;
    3744
    38         /* Change the current working directory to be the home directory
    39          * of the user.  It is a fatal error for this process to be unable
    40          * to change to that directory.  There is no "default" home
    41          * directory.
    42          * Some systems default to HOME=/
    43          */
    44         if (chdir(pw->pw_dir)) {
    45             xchdir("/");
    46             fputs("warning: cannot change to home directory\n", stderr);
    47         }
    48 
    49         /* Leave TERM unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
    50            Unset all other environment variables.  */
     45        /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
     46         * Unset all other environment variables.  */
    5147        term = getenv("TERM");
    5248        clearenv();
    5349        if (term)
    5450            xsetenv("TERM", term);
    55         xsetenv("HOME",    pw->pw_dir);
    56         xsetenv("SHELL",   shell);
    57         xsetenv("USER",    pw->pw_name);
    58         xsetenv("LOGNAME", pw->pw_name);
    59         xsetenv("PATH",   (pw->pw_uid ? bb_default_path : bb_default_root_path));
    60     }
    61     else if (changeenv) {
     51        xsetenv("PATH", (pw->pw_uid ? bb_default_path : bb_default_root_path));
     52        goto shortcut;
     53        // No, gcc (4.2.1) is not clever enougn to do it itself.
     54        //xsetenv("USER",    pw->pw_name);
     55        //xsetenv("LOGNAME", pw->pw_name);
     56        //xsetenv("HOME",    pw->pw_dir);
     57        //xsetenv("SHELL",   shell);
     58    } else if (flags & SETUP_ENV_CHANGEENV) {
    6259        /* Set HOME, SHELL, and if not becoming a super-user,
    63            USER and LOGNAME.  */
    64         xsetenv("HOME",  pw->pw_dir);
    65         xsetenv("SHELL", shell);
     60         * USER and LOGNAME.  */
    6661        if (pw->pw_uid) {
     62 shortcut:
    6763            xsetenv("USER",    pw->pw_name);
    6864            xsetenv("LOGNAME", pw->pw_name);
    6965        }
     66        xsetenv("HOME",    pw->pw_dir);
     67        xsetenv("SHELL",   shell);
    7068    }
    7169}
  • branches/2.2.9/mindi-busybox/libbb/simplify_path.c

    r1765 r2725  
    55 * Copyright (C) 2001  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
    12 char *bb_simplify_path(const char *path)
     11char* FAST_FUNC bb_simplify_abs_path_inplace(char *start)
    1312{
    14     char *s, *start, *p;
     13    char *s, *p;
    1514
    16     if (path[0] == '/')
    17         start = xstrdup(path);
    18     else {
    19         s = xrealloc_getcwd_or_warn(NULL);
    20         start = concat_path_file(s, path);
    21         free(s);
    22     }
    2315    p = s = start;
    24 
    2516    do {
    2617        if (*p == '/') {
    27             if (*s == '/') {    /* skip duplicate (or initial) slash */
     18            if (*s == '/') {  /* skip duplicate (or initial) slash */
    2819                continue;
    2920            }
    3021            if (*s == '.') {
    31                 if (s[1] == '/' || !s[1]) { /* remove extra '.' */
     22                if (s[1] == '/' || !s[1]) {  /* remove extra '.' */
    3223                    continue;
    3324                }
     
    3526                    ++s;
    3627                    if (p > start) {
    37                         while (*--p != '/') /* omit previous dir */
     28                        while (*--p != '/')  /* omit previous dir */
    3829                            continue;
    3930                    }
     
    4536    } while (*++s);
    4637
    47     if ((p == start) || (*p != '/')) {  /* not a trailing slash */
    48         ++p;                    /* so keep last character */
     38    if ((p == start) || (*p != '/')) {  /* not a trailing slash */
     39        ++p;  /* so keep last character */
    4940    }
    50     *p = 0;
     41    *p = '\0';
     42    return p;
     43}
    5144
    52     return start;
     45char* FAST_FUNC bb_simplify_path(const char *path)
     46{
     47    char *s, *p;
     48
     49    if (path[0] == '/')
     50        s = xstrdup(path);
     51    else {
     52        p = xrealloc_getcwd_or_warn(NULL);
     53        s = concat_path_file(p, path);
     54        free(p);
     55    }
     56
     57    bb_simplify_abs_path_inplace(s);
     58    return s;
    5359}
  • branches/2.2.9/mindi-busybox/libbb/skip_whitespace.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 char *skip_whitespace(const char *s)
     12char* FAST_FUNC skip_whitespace(const char *s)
    1313{
    14     /* NB: isspace('0') returns 0 */
    15     while (isspace(*s)) ++s;
     14    /* In POSIX/C locale (the only locale we care about: do we REALLY want
     15     * to allow Unicode whitespace in, say, .conf files? nuts!)
     16     * isspace is only these chars: "\t\n\v\f\r" and space.
     17     * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
     18     * Use that.
     19     */
     20    while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9))
     21        s++;
    1622
    1723    return (char *) s;
    1824}
    1925
    20 char *skip_non_whitespace(const char *s)
     26char* FAST_FUNC skip_non_whitespace(const char *s)
    2127{
    22     while (*s && !isspace(*s)) ++s;
     28    while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9))
     29        s++;
    2330
    2431    return (char *) s;
    2532}
     33
     34char* FAST_FUNC skip_dev_pfx(const char *tty_name)
     35{
     36    if (strncmp(tty_name, "/dev/", 5) == 0)
     37        tty_name += 5;
     38    return (char*)tty_name;
     39}
  • branches/2.2.9/mindi-busybox/libbb/speed_table.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    10 #include <termios.h>
    1110#include "libbb.h"
    1211
     
    3130    {B4800, 4800},
    3231    {B9600, 9600},
    33 #ifdef  B19200
     32#ifdef B19200
    3433    {B19200, 19200},
    3534#elif defined(EXTA)
    3635    {EXTA, 19200},
    3736#endif
    38 #ifdef  B38400
     37#ifdef B38400
    3938    {B38400, 38400/256 + 0x8000U},
    4039#elif defined(EXTB)
     
    5352    {B460800, 460800/256 + 0x8000U},
    5453#endif
     54#ifdef B921600
     55    {B921600, 921600/256 + 0x8000U},
     56#endif
    5557};
    5658
    5759enum { NUM_SPEEDS = ARRAY_SIZE(speeds) };
    5860
    59 unsigned int tty_baud_to_value(speed_t speed)
     61unsigned FAST_FUNC tty_baud_to_value(speed_t speed)
    6062{
    6163    int i = 0;
     
    7375}
    7476
    75 speed_t tty_value_to_baud(unsigned int value)
     77speed_t FAST_FUNC tty_value_to_baud(unsigned int value)
    7678{
    7779    int i = 0;
     
    9597    speed_t s;
    9698
    97     for (v = 0 ; v < 500000; v++) {
     99    for (v = 0 ; v < 1000000; v++) {
    98100        s = tty_value_to_baud(v);
    99101        if (s == (speed_t) -1) {
  • branches/2.2.9/mindi-busybox/libbb/str_tolower.c

    r1765 r2725  
    22/* Convert string str to lowercase, return str.
    33 *
    4  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     4 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    55 */
    66#include "libbb.h"
    7 char* str_tolower(char *str)
     7
     8char* FAST_FUNC str_tolower(char *str)
    89{
    910    char *c;
  • branches/2.2.9/mindi-busybox/libbb/time.c

    r1765 r2725  
    33 * Utility routines.
    44 *
    5  * Copyright (C) 2007 Denis Vlasenko
     5 * Copyright (C) 2007 Denys Vlasenko
    66 *
    7  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
     11void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
     12{
     13    char end = '\0';
     14    const char *last_colon = strrchr(date_str, ':');
     15
     16    if (last_colon != NULL) {
     17        /* Parse input and assign appropriately to ptm */
     18#if ENABLE_DESKTOP
     19        const char *endp;
     20#endif
     21
     22        /* HH:MM */
     23        if (sscanf(date_str, "%u:%u%c",
     24                    &ptm->tm_hour,
     25                    &ptm->tm_min,
     26                    &end) >= 2) {
     27            /* no adjustments needed */
     28        } else
     29        /* mm.dd-HH:MM */
     30        if (sscanf(date_str, "%u.%u-%u:%u%c",
     31                    &ptm->tm_mon, &ptm->tm_mday,
     32                    &ptm->tm_hour, &ptm->tm_min,
     33                    &end) >= 4) {
     34            /* Adjust month from 1-12 to 0-11 */
     35            ptm->tm_mon -= 1;
     36        } else
     37        /* yyyy.mm.dd-HH:MM */
     38        if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year,
     39                    &ptm->tm_mon, &ptm->tm_mday,
     40                    &ptm->tm_hour, &ptm->tm_min,
     41                    &end) >= 5) {
     42            ptm->tm_year -= 1900; /* Adjust years */
     43            ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
     44        } else
     45        /* yyyy-mm-dd HH:MM */
     46        if (sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year,
     47                    &ptm->tm_mon, &ptm->tm_mday,
     48                    &ptm->tm_hour, &ptm->tm_min,
     49                    &end) >= 5) {
     50            ptm->tm_year -= 1900; /* Adjust years */
     51            ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
     52        } else
     53#if ENABLE_DESKTOP  /* strptime is BIG: ~1k in uclibc, ~10k in glibc */
     54        /* month_name d HH:MM:SS YYYY. Supported by GNU date */
     55        if ((endp = strptime(date_str, "%b %d %T %Y", ptm)) != NULL
     56         && *endp == '\0'
     57        ) {
     58            return; /* don't fall through to end == ":" check */
     59        } else
     60#endif
     61//TODO: coreutils 6.9 also accepts "yyyy-mm-dd HH" (no minutes)
     62        {
     63            bb_error_msg_and_die(bb_msg_invalid_date, date_str);
     64        }
     65        if (end == ':') {
     66            /* xxx:SS */
     67            if (sscanf(last_colon + 1, "%u%c", &ptm->tm_sec, &end) == 1)
     68                end = '\0';
     69            /* else end != NUL and we error out */
     70        }
     71    } else if (date_str[0] == '@') {
     72        time_t t = bb_strtol(date_str + 1, NULL, 10);
     73        if (!errno) {
     74            struct tm *lt = localtime(&t);
     75            if (lt) {
     76                *ptm = *lt;
     77                return;
     78            }
     79        }
     80        end = '1';
     81    } else {
     82        /* Googled the following on an old date manpage:
     83         *
     84         * The canonical representation for setting the date/time is:
     85         * cc   Century (either 19 or 20)
     86         * yy   Year in abbreviated form (e.g. 89, 06)
     87         * mm   Numeric month, a number from 1 to 12
     88         * dd   Day, a number from 1 to 31
     89         * HH   Hour, a number from 0 to 23
     90         * MM   Minutes, a number from 0 to 59
     91         * .SS  Seconds, a number from 0 to 61 (with leap seconds)
     92         * Everything but the minutes is optional
     93         *
     94         * This coincides with the format of "touch -t TIME"
     95         */
     96        int len = strchrnul(date_str, '.') - date_str;
     97
     98        /* MM[.SS] */
     99        if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u""%2u%c" + 12,
     100                    &ptm->tm_min,
     101                    &end) >= 1) {
     102        } else
     103        /* HHMM[.SS] */
     104        if (len == 4 && sscanf(date_str, "%2u%2u%2u""%2u%2u%c" + 9,
     105                    &ptm->tm_hour,
     106                    &ptm->tm_min,
     107                    &end) >= 2) {
     108        } else
     109        /* ddHHMM[.SS] */
     110        if (len == 6 && sscanf(date_str, "%2u%2u""%2u%2u%2u%c" + 6,
     111                    &ptm->tm_mday,
     112                    &ptm->tm_hour,
     113                    &ptm->tm_min,
     114                    &end) >= 3) {
     115        } else
     116        /* mmddHHMM[.SS] */
     117        if (len == 8 && sscanf(date_str, "%2u""%2u%2u%2u%2u%c" + 3,
     118                    &ptm->tm_mon,
     119                    &ptm->tm_mday,
     120                    &ptm->tm_hour,
     121                    &ptm->tm_min,
     122                    &end) >= 4) {
     123            /* Adjust month from 1-12 to 0-11 */
     124            ptm->tm_mon -= 1;
     125        } else
     126        /* yymmddHHMM[.SS] */
     127        if (len == 10 && sscanf(date_str, "%2u%2u%2u%2u%2u%c",
     128                    &ptm->tm_year,
     129                    &ptm->tm_mon,
     130                    &ptm->tm_mday,
     131                    &ptm->tm_hour,
     132                    &ptm->tm_min,
     133                    &end) >= 5) {
     134            /* Adjust month from 1-12 to 0-11 */
     135            ptm->tm_mon -= 1;
     136        } else
     137        /* ccyymmddHHMM[.SS] */
     138        if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c",
     139                    &ptm->tm_year,
     140                    &ptm->tm_mon,
     141                    &ptm->tm_mday,
     142                    &ptm->tm_hour,
     143                    &ptm->tm_min,
     144                    &end) >= 5) {
     145            ptm->tm_year -= 1900; /* Adjust years */
     146            ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
     147        } else {
     148            bb_error_msg_and_die(bb_msg_invalid_date, date_str);
     149        }
     150        if (end == '.') {
     151            /* xxx.SS */
     152            if (sscanf(strchr(date_str, '.') + 1, "%u%c",
     153                    &ptm->tm_sec, &end) == 1)
     154                end = '\0';
     155            /* else end != NUL and we error out */
     156        }
     157    }
     158    if (end != '\0') {
     159        bb_error_msg_and_die(bb_msg_invalid_date, date_str);
     160    }
     161}
     162
     163time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm)
     164{
     165    time_t t = mktime(ptm);
     166    if (t == (time_t) -1L) {
     167        bb_error_msg_and_die(bb_msg_invalid_date, date_str);
     168    }
     169    return t;
     170}
     171
    12172#if ENABLE_MONOTONIC_SYSCALL
     173
    13174#include <sys/syscall.h>
     175/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
     176 * directly so this definition is safe. */
     177#ifndef CLOCK_MONOTONIC
     178#define CLOCK_MONOTONIC 1
     179#endif
    14180
    15181/* libc has incredibly messy way of doing this,
    16182 * typically requiring -lrt. We just skip all this mess */
    17 unsigned long long monotonic_us(void)
    18 {
    19     struct timespec ts;
    20     if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
     183static void get_mono(struct timespec *ts)
     184{
     185    if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
    21186        bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
     187}
     188unsigned long long FAST_FUNC monotonic_ns(void)
     189{
     190    struct timespec ts;
     191    get_mono(&ts);
     192    return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
     193}
     194unsigned long long FAST_FUNC monotonic_us(void)
     195{
     196    struct timespec ts;
     197    get_mono(&ts);
    22198    return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
    23199}
    24 unsigned monotonic_sec(void)
    25 {
    26     struct timespec ts;
    27     if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
    28         bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
     200unsigned long long FAST_FUNC monotonic_ms(void)
     201{
     202    struct timespec ts;
     203    get_mono(&ts);
     204    return ts.tv_sec * 1000ULL + ts.tv_nsec/1000000;
     205}
     206unsigned FAST_FUNC monotonic_sec(void)
     207{
     208    struct timespec ts;
     209    get_mono(&ts);
    29210    return ts.tv_sec;
    30211}
     212
    31213#else
    32 unsigned long long monotonic_us(void)
     214
     215unsigned long long FAST_FUNC monotonic_ns(void)
     216{
     217    struct timeval tv;
     218    gettimeofday(&tv, NULL);
     219    return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
     220}
     221unsigned long long FAST_FUNC monotonic_us(void)
    33222{
    34223    struct timeval tv;
     
    36225    return tv.tv_sec * 1000000ULL + tv.tv_usec;
    37226}
    38 
    39 unsigned monotonic_sec(void)
     227unsigned long long FAST_FUNC monotonic_ms(void)
     228{
     229    struct timeval tv;
     230    gettimeofday(&tv, NULL);
     231    return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
     232}
     233unsigned FAST_FUNC monotonic_sec(void)
    40234{
    41235    return time(NULL);
    42236}
    43 #endif
     237
     238#endif
  • branches/2.2.9/mindi-busybox/libbb/trim.c

    r1765 r2725  
    66 * If you wrote this, please acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
    1111#include "libbb.h"
    1212
    13 void trim(char *s)
     13void FAST_FUNC trim(char *s)
    1414{
    1515    size_t len = strlen(s);
    16     size_t lws;
    1716
    1817    /* trim trailing whitespace */
    19     while (len && isspace(s[len-1])) --len;
     18    while (len && isspace(s[len-1]))
     19        --len;
    2020
    2121    /* trim leading whitespace */
    2222    if (len) {
    23         lws = strspn(s, " \n\r\t\v");
    24         memmove(s, s + lws, len -= lws);
     23        char *nws = skip_whitespace(s);
     24        if ((nws - s) != 0) {
     25            len -= (nws - s);
     26            memmove(s, nws, len);
     27        }
    2528    }
    2629    s[len] = '\0';
  • branches/2.2.9/mindi-busybox/libbb/u_signal_names.c

    r1765 r2725  
    55 * Copyright 2006 Rob Landley <rob@landley.net>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 static const char signals[32][7] = {
     12/* Believe it or not, but some arches have more than 32 SIGs!
     13 * HPPA: SIGSTKFLT == 36. */
     14
     15static const char signals[][7] = {
    1316    // SUSv3 says kill must support these, and specifies the numerical values,
    1417    // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html
    15     // TODO: "[SIG]EXIT" shouldn't work for kill, right?
    1618    // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"},
    1719    // {6, "ABRT"}, {9, "KILL"}, {14, "ALRM"}, {15, "TERM"}
     
    2123    // {SIGCONT, "CONT"}, {SIGSTOP, "STOP"}, {SIGTSTP, "TSTP"}, {SIGTTIN, "TTIN"},
    2224    // {SIGTTOU, "TTOU"}
     25
    2326    [0] = "EXIT",
    2427#ifdef SIGHUP
     
    119122// Convert signal name to number.
    120123
    121 int get_signum(const char *name)
     124int FAST_FUNC get_signum(const char *name)
    122125{
    123     int i;
     126    unsigned i;
    124127
    125128    i = bb_strtou(name, NULL, 10);
     
    133136
    134137#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO))
    135     /* These are aliased to other names */
     138    /* SIGIO[T] are aliased to other names,
     139     * thus cannot be stored in the signals[] array.
     140     * Need special code to recognize them */
    136141    if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') {
    137142#ifdef SIGIO
     
    151156// Convert signal number to name
    152157
    153 const char *get_signame(int number)
     158const char* FAST_FUNC get_signame(int number)
    154159{
    155160    if ((unsigned)number < ARRAY_SIZE(signals)) {
     
    160165    return itoa(number);
    161166}
     167
     168
     169// Print the whole signal list
     170
     171void FAST_FUNC print_signames(void)
     172{
     173    unsigned signo;
     174
     175    for (signo = 1; signo < ARRAY_SIZE(signals); signo++) {
     176        const char *name = signals[signo];
     177        if (name[0])
     178            puts(name);
     179    }
     180}
  • branches/2.2.9/mindi-busybox/libbb/udp_io.c

    r1765 r2725  
    33 * Utility routines.
    44 *
    5  * Copyright (C) 2007 Denis Vlasenko
     5 * Copyright (C) 2007 Denys Vlasenko
    66 *
    7  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
     
    1413 * We don't check for errors here. Not supported == won't be used
    1514 */
    16 void
     15void FAST_FUNC
    1716socket_want_pktinfo(int fd)
    1817{
     
    2625
    2726
    28 #ifdef UNUSED
    29 ssize_t
     27ssize_t FAST_FUNC
    3028send_to_from(int fd, void *buf, size_t len, int flags,
    31         const struct sockaddr *from, const struct sockaddr *to,
     29        const struct sockaddr *to,
     30        const struct sockaddr *from,
    3231        socklen_t tolen)
    3332{
    3433#ifndef IP_PKTINFO
     34    (void)from; /* suppress "unused from" warning */
    3535    return sendto(fd, buf, len, flags, to, tolen);
    3636#else
    3737    struct iovec iov[1];
    3838    struct msghdr msg;
    39     char cbuf[sizeof(struct in_pktinfo)
    40 #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
    41         | sizeof(struct in6_pktinfo) /* (a|b) is poor man's max(a,b) */
    42 #endif
    43     ];
     39    union {
     40        char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
     41# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
     42        char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
     43# endif
     44    } u;
    4445    struct cmsghdr* cmsgptr;
    4546
    4647    if (from->sa_family != AF_INET
    47 #if ENABLE_FEATURE_IPV6
     48# if ENABLE_FEATURE_IPV6
    4849     && from->sa_family != AF_INET6
    49 #endif
     50# endif
    5051    ) {
    5152        /* ANY local address */
     
    5859    iov[0].iov_len = len;
    5960
    60     memset(cbuf, 0, sizeof(cbuf));
     61    memset(&u, 0, sizeof(u));
    6162
    6263    memset(&msg, 0, sizeof(msg));
     
    6566    msg.msg_iov = iov;
    6667    msg.msg_iovlen = 1;
    67     msg.msg_control = cbuf;
    68     msg.msg_controllen = sizeof(cbuf);
     68    msg.msg_control = &u;
     69    msg.msg_controllen = sizeof(u);
    6970    msg.msg_flags = flags;
    7071
     
    7677        cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
    7778        pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr));
    78         /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */
     79        /*pktptr->ipi_ifindex = 0; -- already done by memset(u...) */
     80        /* In general, CMSG_DATA() can be unaligned, but in this case
     81         * we know for sure it is sufficiently aligned:
     82         * CMSG_FIRSTHDR simply returns &u above,
     83         * and CMSG_DATA returns &u + size_t + int + int.
     84         * Thus direct assignment is ok:
     85         */
    7986        pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
    8087    }
    81 #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
     88# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
    8289    else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
    8390        struct in6_pktinfo *pktptr;
     
    8693        cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
    8794        pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
    88         /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */
     95        /* pktptr->ipi6_ifindex = 0; -- already done by memset(u...) */
    8996        pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr;
    9097    }
    91 #endif
     98# endif
     99    msg.msg_controllen = cmsgptr->cmsg_len;
     100
    92101    return sendmsg(fd, &msg, flags);
    93102#endif
    94103}
    95 #endif /* UNUSED */
    96104
    97105/* NB: this will never set port# in 'to'!
     
    99107 * Typical usage is to preinit 'to' with "default" value
    100108 * before calling recv_from_to(). */
    101 ssize_t
     109ssize_t FAST_FUNC
    102110recv_from_to(int fd, void *buf, size_t len, int flags,
    103111        struct sockaddr *from, struct sockaddr *to,
     
    105113{
    106114#ifndef IP_PKTINFO
     115    (void)to; /* suppress "unused to" warning */
    107116    return recvfrom(fd, buf, len, flags, from, &sa_size);
    108117#else
     
    111120    union {
    112121        char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
     122# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
    113123        char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
     124# endif
    114125    } u;
    115126    struct cmsghdr *cmsgptr;
    116127    struct msghdr msg;
    117     socklen_t recv_length;
     128    ssize_t recv_length;
    118129
    119130    iov[0].iov_base = buf;
     
    132143        return recv_length;
    133144
     145# define to4 ((struct sockaddr_in*)to)
     146# define to6 ((struct sockaddr_in6*)to)
    134147    /* Here we try to retrieve destination IP and memorize it */
    135148    for (cmsgptr = CMSG_FIRSTHDR(&msg);
     
    140153         && cmsgptr->cmsg_type == IP_PKTINFO
    141154        ) {
    142 #define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) )
     155            const int IPI_ADDR_OFF = offsetof(struct in_pktinfo, ipi_addr);
    143156            to->sa_family = AF_INET;
    144             ((struct sockaddr_in*)to)->sin_addr = pktinfo(cmsgptr)->ipi_addr;
    145             /* ((struct sockaddr_in*)to)->sin_port = 123; */
    146 #undef pktinfo
     157            /*# define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) )*/
     158            /*to4->sin_addr = pktinfo(cmsgptr)->ipi_addr; - may be unaligned */
     159            memcpy(&to4->sin_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI_ADDR_OFF, sizeof(to4->sin_addr));
     160            /*to4->sin_port = 123; - this data is not supplied by kernel */
    147161            break;
    148162        }
    149 #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
     163# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
    150164        if (cmsgptr->cmsg_level == IPPROTO_IPV6
    151165         && cmsgptr->cmsg_type == IPV6_PKTINFO
    152166        ) {
    153 #define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )
     167            const int IPI6_ADDR_OFF = offsetof(struct in6_pktinfo, ipi6_addr);
    154168            to->sa_family = AF_INET6;
    155             ((struct sockaddr_in6*)to)->sin6_addr = pktinfo(cmsgptr)->ipi6_addr;
    156             /* ((struct sockaddr_in6*)to)->sin6_port = 123; */
    157 #undef pktinfo
     169            /*#  define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )*/
     170            /*to6->sin6_addr = pktinfo(cmsgptr)->ipi6_addr; - may be unaligned */
     171            memcpy(&to6->sin6_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI6_ADDR_OFF, sizeof(to6->sin6_addr));
     172            /*to6->sin6_port = 123; */
    158173            break;
    159174        }
    160 #endif
     175# endif
    161176    }
    162177    return recv_length;
  • branches/2.2.9/mindi-busybox/libbb/update_passwd.c

    r1765 r2725  
    88 *
    99 * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org>
     10 *
     11 * Modified to be able to add or delete users, groups and users to/from groups
     12 * by Tito Ragusa <farmatito@tiscali.it>
     13 *
     14 * Licensed under GPLv2, see file LICENSE in this source tree.
    1015 */
    11 
    1216#include "libbb.h"
    1317
    14 int update_passwd(const char *filename, const char *username,
    15             const char *new_pw)
     18#if ENABLE_SELINUX
     19static void check_selinux_update_passwd(const char *username)
    1620{
     21    security_context_t context;
     22    char *seuser;
     23
     24    if (getuid() != (uid_t)0 || is_selinux_enabled() == 0)
     25        return;  /* No need to check */
     26
     27    if (getprevcon_raw(&context) < 0)
     28        bb_perror_msg_and_die("getprevcon failed");
     29    seuser = strtok(context, ":");
     30    if (!seuser)
     31        bb_error_msg_and_die("invalid context '%s'", context);
     32    if (strcmp(seuser, username) != 0) {
     33        if (checkPasswdAccess(PASSWD__PASSWD) != 0)
     34            bb_error_msg_and_die("SELinux: access denied");
     35    }
     36    if (ENABLE_FEATURE_CLEAN_UP)
     37        freecon(context);
     38}
     39#else
     40# define check_selinux_update_passwd(username) ((void)0)
     41#endif
     42
     43/*
     44 1) add a user: update_passwd(FILE, USER, REMAINING_PWLINE, NULL)
     45    only if CONFIG_ADDUSER=y and applet_name[0] == 'a' like in adduser
     46
     47 2) add a group: update_passwd(FILE, GROUP, REMAINING_GRLINE, NULL)
     48    only if CONFIG_ADDGROUP=y and applet_name[0] == 'a' like in addgroup
     49
     50 3) add a user to a group: update_passwd(FILE, GROUP, NULL, MEMBER)
     51    only if CONFIG_FEATURE_ADDUSER_TO_GROUP=y, applet_name[0] == 'a'
     52    like in addgroup and member != NULL
     53
     54 4) delete a user: update_passwd(FILE, USER, NULL, NULL)
     55
     56 5) delete a group: update_passwd(FILE, GROUP, NULL, NULL)
     57
     58 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER)
     59    only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL
     60
     61 7) change user's password: update_passwd(FILE, USER, NEW_PASSWD, NULL)
     62    only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd
     63    or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd
     64
     65 This function does not validate the arguments fed to it
     66 so the calling program should take care of that.
     67
     68 Returns number of lines changed, or -1 on error.
     69*/
     70int FAST_FUNC update_passwd(const char *filename,
     71        const char *name,
     72        const char *new_passwd,
     73        const char *member)
     74{
     75#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP)
     76#define member NULL
     77#endif
    1778    struct stat sb;
    1879    struct flock lock;
     
    2182    char *fnamesfx;
    2283    char *sfx_char;
     84    char *name_colon;
    2385    unsigned user_len;
    2486    int old_fd;
    2587    int new_fd;
    2688    int i;
    27     int cnt = 0;
     89    int changed_lines;
    2890    int ret = -1; /* failure */
     91    /* used as a bool: "are we modifying /etc/shadow?" */
     92#if ENABLE_FEATURE_SHADOWPASSWDS
     93    const char *shadow = strstr(filename, "shadow");
     94#else
     95# define shadow NULL
     96#endif
     97
     98    filename = xmalloc_follow_symlinks(filename);
     99    if (filename == NULL)
     100        return ret;
     101
     102    check_selinux_update_passwd(name);
    29103
    30104    /* New passwd file, "/etc/passwd+" for now */
    31105    fnamesfx = xasprintf("%s+", filename);
    32106    sfx_char = &fnamesfx[strlen(fnamesfx)-1];
    33     username = xasprintf("%s:", username);
    34     user_len = strlen(username);
    35 
    36     old_fp = fopen(filename, "r+");
    37     if (!old_fp)
     107    name_colon = xasprintf("%s:", name);
     108    user_len = strlen(name_colon);
     109
     110    if (shadow)
     111        old_fp = fopen(filename, "r+");
     112    else
     113        old_fp = fopen_or_warn(filename, "r+");
     114    if (!old_fp) {
     115        if (shadow)
     116            ret = 0; /* missing shadow is not an error */
    38117        goto free_mem;
     118    }
    39119    old_fd = fileno(old_fp);
     120
     121    selinux_preserve_fcontext(old_fd);
    40122
    41123    /* Try to create "/etc/passwd+". Wait if it exists. */
     
    48130        usleep(100000); /* 0.1 sec */
    49131    } while (--i);
    50     bb_perror_msg("cannot create '%s'", fnamesfx);
     132    bb_perror_msg("can't create '%s'", fnamesfx);
    51133    goto close_old_fp;
    52134
    53135 created:
    54     if (!fstat(old_fd, &sb)) {
     136    if (fstat(old_fd, &sb) == 0) {
    55137        fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
    56138        fchown(new_fd, sb.st_uid, sb.st_gid);
    57139    }
    58     new_fp = fdopen(new_fd, "w");
    59     if (!new_fp) {
    60         close(new_fd);
    61         goto unlink_new;
    62     }
     140    errno = 0;
     141    new_fp = xfdopen_for_write(new_fd);
    63142
    64143    /* Backup file is "/etc/passwd-" */
     
    68147    /* Create backup as a hardlink to current */
    69148    if (i || link(filename, fnamesfx))
    70         bb_perror_msg("warning: cannot create backup copy '%s'", fnamesfx);
     149        bb_perror_msg("warning: can't create backup copy '%s'",
     150                fnamesfx);
    71151    *sfx_char = '+';
    72152
     
    77157    lock.l_len = 0;
    78158    if (fcntl(old_fd, F_SETLK, &lock) < 0)
    79         bb_perror_msg("warning: cannot lock '%s'", filename);
     159        bb_perror_msg("warning: can't lock '%s'", filename);
    80160    lock.l_type = F_UNLCK;
    81161
    82162    /* Read current password file, write updated /etc/passwd+ */
     163    changed_lines = 0;
    83164    while (1) {
    84         char *line = xmalloc_fgets(old_fp);
    85         if (!line) break; /* EOF/error */
    86         if (strncmp(username, line, user_len) == 0) {
    87             /* we have a match with "username:"... */
    88             const char *cp = line + user_len;
    89             /* now cp -> old passwd, skip it: */
    90             cp = strchrnul(cp, ':');
    91             /* now cp -> ':' after old passwd or -> "" */
    92             fprintf(new_fp, "%s%s%s", username, new_pw, cp);
    93             cnt++;
     165        char *cp, *line;
     166
     167        line = xmalloc_fgetline(old_fp);
     168        if (!line) /* EOF/error */
     169            break;
     170        if (strncmp(name_colon, line, user_len) != 0) {
     171            fprintf(new_fp, "%s\n", line);
     172            goto next;
     173        }
     174
     175        /* We have a match with "name:"... */
     176        cp = line + user_len; /* move past name: */
     177
     178#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
     179        if (member) {
     180            /* It's actually /etc/group+, not /etc/passwd+ */
     181            if (ENABLE_FEATURE_ADDUSER_TO_GROUP
     182             && applet_name[0] == 'a'
     183            ) {
     184                /* Add user to group */
     185                fprintf(new_fp, "%s%s%s\n", line,
     186                    last_char_is(line, ':') ? "" : ",",
     187                    member);
     188                changed_lines++;
     189            } else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP
     190            /* && applet_name[0] == 'd' */
     191            ) {
     192                /* Delete user from group */
     193                char *tmp;
     194                const char *fmt = "%s";
     195
     196                /* find the start of the member list: last ':' */
     197                cp = strrchr(line, ':');
     198                /* cut it */
     199                *cp++ = '\0';
     200                /* write the cut line name:passwd:gid:
     201                 * or name:!:: */
     202                fprintf(new_fp, "%s:", line);
     203                /* parse the tokens of the member list */
     204                tmp = cp;
     205                while ((cp = strsep(&tmp, ",")) != NULL) {
     206                    if (strcmp(member, cp) != 0) {
     207                        fprintf(new_fp, fmt, cp);
     208                        fmt = ",%s";
     209                    } else {
     210                        /* found member, skip it */
     211                        changed_lines++;
     212                    }
     213                }
     214                fprintf(new_fp, "\n");
     215            }
    94216        } else
    95             fputs(line, new_fp);
     217#endif
     218        if ((ENABLE_PASSWD && applet_name[0] == 'p')
     219         || (ENABLE_CHPASSWD && applet_name[0] == 'c')
     220        ) {
     221            /* Change passwd */
     222            cp = strchrnul(cp, ':'); /* move past old passwd */
     223
     224            if (shadow && *cp == ':') {
     225                /* /etc/shadow's field 3 (passwd change date) needs updating */
     226                /* move past old change date */
     227                cp = strchrnul(cp + 1, ':');
     228                /* "name:" + "new_passwd" + ":" + "change date" + ":rest of line" */
     229                fprintf(new_fp, "%s%s:%u%s\n", name_colon, new_passwd,
     230                    (unsigned)(time(NULL)) / (24*60*60), cp);
     231            } else {
     232                /* "name:" + "new_passwd" + ":rest of line" */
     233                fprintf(new_fp, "%s%s%s\n", name_colon, new_passwd, cp);
     234            }
     235            changed_lines++;
     236        } /* else delete user or group: skip the line */
     237 next:
    96238        free(line);
    97239    }
     240
     241    if (changed_lines == 0) {
     242#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
     243        if (member) {
     244            if (ENABLE_ADDGROUP && applet_name[0] == 'a')
     245                bb_error_msg("can't find %s in %s", name, filename);
     246            if (ENABLE_DELGROUP && applet_name[0] == 'd')
     247                bb_error_msg("can't find %s in %s", member, filename);
     248        }
     249#endif
     250        if ((ENABLE_ADDUSER || ENABLE_ADDGROUP)
     251         && applet_name[0] == 'a' && !member
     252        ) {
     253            /* add user or group */
     254            fprintf(new_fp, "%s%s\n", name_colon, new_passwd);
     255            changed_lines++;
     256        }
     257    }
     258
    98259    fcntl(old_fd, F_SETLK, &lock);
    99260
    100261    /* We do want all of them to execute, thus | instead of || */
     262    errno = 0;
    101263    if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
    102264     || rename(fnamesfx, filename)
    103265    ) {
    104266        /* At least one of those failed */
     267        bb_perror_nomsg();
    105268        goto unlink_new;
    106269    }
    107     ret = cnt; /* whee, success! */
     270    /* Success: ret >= 0 */
     271    ret = changed_lines;
    108272
    109273 unlink_new:
    110     if (ret < 0) unlink(fnamesfx);
     274    if (ret < 0)
     275        unlink(fnamesfx);
    111276
    112277 close_old_fp:
     
    115280 free_mem:
    116281    free(fnamesfx);
    117     free((char*)username);
     282    free((char *)filename);
     283    free(name_colon);
    118284    return ret;
    119285}
  • branches/2.2.9/mindi-busybox/libbb/uuencode.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Copyright 2006 Rob Landley <rob@landley.net>
     3 * Copyright 2003, Glenn McGrath
     4 * Copyright 2006, Rob Landley <rob@landley.net>
     5 * Copyright 2010, Denys Vlasenko
    46 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    68 */
    79
     
    4042 * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
    4143 */
    42 void bb_uuencode(char *p, const void *src, int length, const char *tbl)
     44void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl)
    4345{
    4446    const unsigned char *s = src;
     
    7072    }
    7173}
     74
     75/*
     76 * Decode base64 encoded stream.
     77 * Can stop on EOF, specified char, or on uuencode-style "====" line:
     78 * flags argument controls it.
     79 */
     80void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
     81{
     82/* Note that EOF _can_ be passed as exit_char too */
     83#define exit_char    ((int)(signed char)flags)
     84#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
     85
     86    int term_count = 0;
     87
     88    while (1) {
     89        unsigned char translated[4];
     90        int count = 0;
     91
     92        /* Process one group of 4 chars */
     93        while (count < 4) {
     94            char *table_ptr;
     95            int ch;
     96
     97            /* Get next _valid_ character.
     98             * bb_uuenc_tbl_base64[] contains this string:
     99             *  0         1         2         3         4         5         6
     100             *  012345678901234567890123456789012345678901234567890123456789012345
     101             * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n"
     102             */
     103            do {
     104                ch = fgetc(src_stream);
     105                if (ch == exit_char && count == 0)
     106                    return;
     107                if (ch == EOF)
     108                    bb_error_msg_and_die("truncated base64 input");
     109                table_ptr = strchr(bb_uuenc_tbl_base64, ch);
     110//TODO: add BASE64_FLAG_foo to die on bad char?
     111//Note that then we may need to still allow '\r' (for mail processing)
     112            } while (!table_ptr);
     113
     114            /* Convert encoded character to decimal */
     115            ch = table_ptr - bb_uuenc_tbl_base64;
     116
     117            if (ch == 65 /* '\n' */) {
     118                /* Terminating "====" line? */
     119                if (uu_style_end && term_count == 4)
     120                    return; /* yes */
     121                term_count = 0;
     122                continue;
     123            }
     124            /* ch is 64 if char was '=', otherwise 0..63 */
     125            translated[count] = ch & 63; /* 64 -> 0 */
     126            if (ch == 64) {
     127                term_count++;
     128                break;
     129            }
     130            count++;
     131            term_count = 0;
     132        }
     133
     134        /* Merge 6 bit chars to 8 bit.
     135         * count can be < 4 when we decode the tail:
     136         * "eQ==" -> "y", not "y NUL NUL"
     137         */
     138        if (count > 1)
     139            fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
     140        if (count > 2)
     141            fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
     142        if (count > 3)
     143            fputc(translated[2] << 6 | translated[3], dst_stream);
     144    } /* while (1) */
     145}
  • branches/2.2.9/mindi-busybox/libbb/vdprintf.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1111
    1212#if defined(__GLIBC__) && __GLIBC__ < 2
    13 int vdprintf(int d, const char *format, va_list ap)
     13int FAST_FUNC vdprintf(int d, const char *format, va_list ap)
    1414{
    1515    char buf[BUF_SIZE];
  • branches/2.2.9/mindi-busybox/libbb/verror_msg.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    10 #include <syslog.h>
    119#include "libbb.h"
     10#if ENABLE_FEATURE_SYSLOG
     11# include <syslog.h>
     12#endif
    1213
    1314smallint logmode = LOGMODE_STDIO;
    1415const char *msg_eol = "\n";
    1516
    16 void bb_verror_msg(const char *s, va_list p, const char* strerr)
     17void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
    1718{
    18     char *msg;
     19    char *msg, *msg1;
    1920    int applet_len, strerr_len, msgeol_len, used;
    2021
     
    3738    strerr_len = strerr ? strlen(strerr) : 0;
    3839    msgeol_len = strlen(msg_eol);
     40    /* can't use xrealloc: it calls error_msg on failure,
     41     * that may result in a recursion */
    3942    /* +3 is for ": " before strerr and for terminating NUL */
    40     msg = xrealloc(msg, applet_len + used + strerr_len + msgeol_len + 3);
    41     /* TODO: maybe use writev instead of memmoving? Need full_writev? */
    42     memmove(msg + applet_len, msg, used);
    43     used += applet_len;
    44     strcpy(msg, applet_name);
    45     msg[applet_len - 2] = ':';
    46     msg[applet_len - 1] = ' ';
    47     if (strerr) {
    48         msg[used++] = ':';
    49         msg[used++] = ' ';
    50         strcpy(&msg[used], strerr);
    51         used += strerr_len;
     43    msg1 = realloc(msg, applet_len + used + strerr_len + msgeol_len + 3);
     44    if (!msg1) {
     45        msg[used++] = '\n'; /* overwrites NUL */
     46        applet_len = 0;
     47    } else {
     48        msg = msg1;
     49        /* TODO: maybe use writev instead of memmoving? Need full_writev? */
     50        memmove(msg + applet_len, msg, used);
     51        used += applet_len;
     52        strcpy(msg, applet_name);
     53        msg[applet_len - 2] = ':';
     54        msg[applet_len - 1] = ' ';
     55        if (strerr) {
     56            if (s[0]) { /* not perror_nomsg? */
     57                msg[used++] = ':';
     58                msg[used++] = ' ';
     59            }
     60            strcpy(&msg[used], strerr);
     61            used += strerr_len;
     62        }
     63        strcpy(&msg[used], msg_eol);
     64        used += msgeol_len;
    5265    }
    53     strcpy(&msg[used], msg_eol);
    5466
    5567    if (logmode & LOGMODE_STDIO) {
    56         fflush(stdout);
    57         full_write(2, msg, used + msgeol_len);
     68        fflush_all();
     69        full_write(STDERR_FILENO, msg, used);
    5870    }
     71#if ENABLE_FEATURE_SYSLOG
    5972    if (logmode & LOGMODE_SYSLOG) {
    6073        syslog(LOG_ERR, "%s", msg + applet_len);
    6174    }
     75#endif
    6276    free(msg);
    6377}
    6478
    65 
    6679#ifdef VERSION_WITH_WRITEV
    67 
    6880/* Code size is approximately the same, but currently it's the only user
    6981 * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */
    70 
    71 void bb_verror_msg(const char *s, va_list p, const char* strerr)
     82void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
    7283{
    7384    int strerr_len, msgeol_len;
     
    115126        /*iov[2].iov_base = msgc;*/
    116127        /*iov[2].iov_len = used;*/
    117         fflush(stdout);
    118         writev(2, iov, 3);
     128        fflush_all();
     129        writev(STDERR_FILENO, iov, 3);
    119130    }
     131# if ENABLE_FEATURE_SYSLOG
    120132    if (logmode & LOGMODE_SYSLOG) {
    121133        syslog(LOG_ERR, "%s", msgc);
    122134    }
     135# endif
    123136    free(msgc);
    124137}
    125138#endif
     139
     140
     141void FAST_FUNC bb_error_msg_and_die(const char *s, ...)
     142{
     143    va_list p;
     144
     145    va_start(p, s);
     146    bb_verror_msg(s, p, NULL);
     147    va_end(p);
     148    xfunc_die();
     149}
     150
     151void FAST_FUNC bb_error_msg(const char *s, ...)
     152{
     153    va_list p;
     154
     155    va_start(p, s);
     156    bb_verror_msg(s, p, NULL);
     157    va_end(p);
     158}
  • branches/2.2.9/mindi-busybox/libbb/vfork_daemon_rexec.c

    r1765 r2725  
    1313 * Modified for uClibc by Erik Andersen <andersee@debian.org>
    1414 *
    15  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     15 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1616 */
    1717
    18 #include <paths.h>
    19 #include "busybox.h" /* for struct bb_applet */
     18#include "busybox.h" /* uses applet tables */
    2019
    2120/* This does a fork/exec in one call, using vfork().  Returns PID of new child,
    2221 * -1 for failure.  Runs argv[0], searching path if that has no / in it. */
    23 pid_t spawn(char **argv)
     22pid_t FAST_FUNC spawn(char **argv)
    2423{
    2524    /* Compiler should not optimize stores here */
     
    2726    pid_t pid;
    2827
    29 // Ain't it a good place to fflush(NULL)?
     28    fflush_all();
    3029
    3130    /* Be nice to nommu machines. */
     
    4342         */
    4443        failed = errno;
     44        /* mount, for example, does not want the message */
     45        /*bb_perror_msg("can't execute '%s'", argv[0]);*/
    4546        _exit(111);
    4647    }
     
    5253     * If 111 - then it (most probably) failed to exec */
    5354    if (failed) {
     55        safe_waitpid(pid, NULL, 0); /* prevent zombie */
    5456        errno = failed;
    5557        return -1;
     
    5961
    6062/* Die with an error message if we can't spawn a child process. */
    61 pid_t xspawn(char **argv)
     63pid_t FAST_FUNC xspawn(char **argv)
    6264{
    6365    pid_t pid = spawn(argv);
    6466    if (pid < 0)
    65         bb_perror_msg_and_die("%s", *argv);
     67        bb_simple_perror_msg_and_die(*argv);
    6668    return pid;
    6769}
    6870
    69 // Wait for the specified child PID to exit, returning child's error return.
    70 int wait4pid(int pid)
    71 {
    72     int status;
    73 
    74     if (pid <= 0) {
    75         /*errno = ECHILD; -- wrong. */
    76         /* we expect errno to be already set from failed [v]fork/exec */
    77         return -1;
    78     }
    79     if (waitpid(pid, &status, 0) == -1)
    80         return -1;
    81     if (WIFEXITED(status))
    82         return WEXITSTATUS(status);
    83     if (WIFSIGNALED(status))
    84         return WTERMSIG(status) + 1000;
    85     return 0;
    86 }
    87 
    88 int wait_nohang(int *wstat)
    89 {
    90     return waitpid(-1, wstat, WNOHANG);
    91 }
    92 
    93 int wait_pid(int *wstat, int pid)
    94 {
    95     int r;
    96 
    97     do
    98         r = waitpid(pid, wstat, 0);
    99     while ((r == -1) && (errno == EINTR));
    100     return r;
    101 }
    102 
    10371#if ENABLE_FEATURE_PREFER_APPLETS
    104 void save_nofork_data(struct nofork_save_area *save)
     72void FAST_FUNC save_nofork_data(struct nofork_save_area *save)
    10573{
    10674    memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
    107     save->current_applet = current_applet;
     75    save->applet_name = applet_name;
    10876    save->xfunc_error_retval = xfunc_error_retval;
    10977    save->option_mask32 = option_mask32;
     
    11280}
    11381
    114 void restore_nofork_data(struct nofork_save_area *save)
     82void FAST_FUNC restore_nofork_data(struct nofork_save_area *save)
    11583{
    11684    memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
    117     current_applet = save->current_applet;
     85    applet_name = save->applet_name;
    11886    xfunc_error_retval = save->xfunc_error_retval;
    11987    option_mask32 = save->option_mask32;
    12088    die_sleep = save->die_sleep;
    121 
    122     applet_name = current_applet->name;
    123 }
    124 
    125 int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv)
     89}
     90
     91int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv)
    12692{
    12793    int rc, argc;
    12894
    129     current_applet = a;
    130     applet_name = a->name;
     95    applet_name = APPLET_NAME(applet_no);
     96
    13197    xfunc_error_retval = EXIT_FAILURE;
    132     /*option_mask32 = 0; - not needed */
    133     /* special flag for xfunc_die(). If xfunc will "die"
     98
     99    /* Special flag for xfunc_die(). If xfunc will "die"
    134100     * in NOFORK applet, xfunc_die() sees negative
    135101     * die_sleep and longjmp here instead. */
    136102    die_sleep = -1;
     103
     104    /* In case getopt() or getopt32() was already called:
     105     * reset the libc getopt() function, which keeps internal state.
     106     *
     107     * BSD-derived getopt() functions require that optind be set to 1 in
     108     * order to reset getopt() state.  This used to be generally accepted
     109     * way of resetting getopt().  However, glibc's getopt()
     110     * has additional getopt() state beyond optind, and requires that
     111     * optind be set to zero to reset its state.  So the unfortunate state of
     112     * affairs is that BSD-derived versions of getopt() misbehave if
     113     * optind is set to 0 in order to reset getopt(), and glibc's getopt()
     114     * will core dump if optind is set 1 in order to reset getopt().
     115     *
     116     * More modern versions of BSD require that optreset be set to 1 in
     117     * order to reset getopt().  Sigh.  Standards, anyone?
     118     */
     119#ifdef __GLIBC__
     120    optind = 0;
     121#else /* BSD style */
     122    optind = 1;
     123    /* optreset = 1; */
     124#endif
     125    /* optarg = NULL; opterr = 1; optopt = 63; - do we need this too? */
     126    /* (values above are what they initialized to in glibc and uclibc) */
     127    /* option_mask32 = 0; - not needed, no applet depends on it being 0 */
    137128
    138129    argc = 1;
     
    147138        memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
    148139        /* Finally we can call NOFORK applet's main() */
    149         rc = a->main(argc, tmp_argv);
     140        rc = applet_main[applet_no](argc, tmp_argv);
     141
     142    /* The whole reason behind nofork_save_area is that <applet>_main
     143     * may exit non-locally! For example, in hush Ctrl-Z tries
     144     * (modulo bugs) to dynamically create a child (backgrounded task)
     145     * if it detects that Ctrl-Z was pressed when a NOFORK was running.
     146     * Testcase: interactive "rm -i".
     147     * Don't fool yourself into thinking "and <applet>_main() returns
     148     * quickly here" and removing "useless" nofork_save_area code. */
     149
    150150    } else { /* xfunc died in NOFORK applet */
    151151        /* in case they meant to return 0... */
     
    154154    }
    155155
    156     /* Restoring globals */
     156    /* Restoring some globals */
    157157    restore_nofork_data(old);
    158     return rc;
    159 }
    160 
    161 int run_nofork_applet(const struct bb_applet *a, char **argv)
     158
     159    /* Other globals can be simply reset to defaults */
     160#ifdef __GLIBC__
     161    optind = 0;
     162#else /* BSD style */
     163    optind = 1;
     164#endif
     165
     166    return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
     167}
     168
     169int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
    162170{
    163171    struct nofork_save_area old;
     
    165173    /* Saving globals */
    166174    save_nofork_data(&old);
    167     return run_nofork_applet_prime(&old, a, argv);
     175    return run_nofork_applet_prime(&old, applet_no, argv);
    168176}
    169177#endif /* FEATURE_PREFER_APPLETS */
    170178
    171 int spawn_and_wait(char **argv)
     179int FAST_FUNC spawn_and_wait(char **argv)
    172180{
    173181    int rc;
    174182#if ENABLE_FEATURE_PREFER_APPLETS
    175     const struct bb_applet *a = find_applet_by_name(argv[0]);
    176 
    177     if (a && (a->nofork
     183    int a = find_applet_by_name(argv[0]);
     184
     185    if (a >= 0 && (APPLET_IS_NOFORK(a)
    178186#if BB_MMU
    179          || a->noexec /* NOEXEC trick needs fork() */
     187            || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
    180188#endif
    181189    )) {
    182190#if BB_MMU
    183         if (a->nofork)
     191        if (APPLET_IS_NOFORK(a))
    184192#endif
    185193        {
     
    194202        /* child */
    195203        xfunc_error_retval = EXIT_FAILURE;
    196         current_applet = a;
    197         run_current_applet_and_exit(argv);
     204        run_applet_no_and_exit(a, argv);
    198205#endif
    199206    }
     
    204211
    205212#if !BB_MMU
    206 void re_exec(char **argv)
     213void FAST_FUNC re_exec(char **argv)
    207214{
    208215    /* high-order bit of first char in argv[0] is a hidden
     
    210217    argv[0][0] |= 0x80;
    211218    execv(bb_busybox_exec_path, argv);
    212     bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
    213 }
    214 
    215 void forkexit_or_rexec(char **argv)
     219    bb_perror_msg_and_die("can't execute '%s'", bb_busybox_exec_path);
     220}
     221
     222pid_t FAST_FUNC fork_or_rexec(char **argv)
    216223{
    217224    pid_t pid;
    218225    /* Maybe we are already re-execed and come here again? */
    219226    if (re_execed)
    220         return;
    221 
    222     pid = vfork();
    223     if (pid < 0) /* wtf? */
    224         bb_perror_msg_and_die("vfork");
     227        return 0;
     228    pid = xvfork();
    225229    if (pid) /* parent */
    226         exit(0);
     230        return pid;
    227231    /* child - re-exec ourself */
    228232    re_exec(argv);
    229233}
    230 #else
    231 /* Dance around (void)...*/
    232 #undef forkexit_or_rexec
    233 void forkexit_or_rexec(void)
    234 {
    235     pid_t pid;
    236     pid = fork();
    237     if (pid < 0) /* wtf? */
    238         bb_perror_msg_and_die("fork");
    239     if (pid) /* parent */
    240         exit(0);
    241     /* child */
    242 }
    243 #define forkexit_or_rexec(argv) forkexit_or_rexec()
    244234#endif
    245235
    246236/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
    247237 * char **argv "vanishes" */
    248 void bb_daemonize_or_rexec(int flags, char **argv)
     238void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
    249239{
    250240    int fd;
     
    259249    }
    260250
    261     fd = xopen(bb_dev_null, O_RDWR);
     251    fd = open(bb_dev_null, O_RDWR);
     252    if (fd < 0) {
     253        /* NB: we can be called as bb_sanitize_stdio() from init
     254         * or mdev, and there /dev/null may legitimately not (yet) exist!
     255         * Do not use xopen above, but obtain _ANY_ open descriptor,
     256         * even bogus one as below. */
     257        fd = xopen("/", O_RDONLY); /* don't believe this can fail */
     258    }
    262259
    263260    while ((unsigned)fd < 2)
     
    265262
    266263    if (!(flags & DAEMON_ONLY_SANITIZE)) {
    267         forkexit_or_rexec(argv);
     264        if (fork_or_rexec(argv))
     265            exit(EXIT_SUCCESS); /* parent */
    268266        /* if daemonizing, make sure we detach from stdio & ctty */
    269267        setsid();
     
    280278}
    281279
    282 void bb_sanitize_stdio(void)
     280void FAST_FUNC bb_sanitize_stdio(void)
    283281{
    284282    bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
  • branches/2.2.9/mindi-busybox/libbb/warn_ignoring_args.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    109#include "libbb.h"
    1110
    12 void bb_warn_ignoring_args(int n)
     11#if ENABLE_DESKTOP
     12void FAST_FUNC bb_warn_ignoring_args(char *arg)
    1313{
    14     if (n) {
     14    if (arg) {
    1515        bb_error_msg("ignoring all arguments");
    1616    }
    1717}
     18#endif
  • branches/2.2.9/mindi-busybox/libbb/wfopen.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 FILE *fopen_or_warn(const char *path, const char *mode)
     12FILE* FAST_FUNC fopen_or_warn(const char *path, const char *mode)
    1313{
    1414    FILE *fp = fopen(path, mode);
    1515    if (!fp) {
    16         bb_perror_msg("%s", path);
    17         errno = 0;
     16        bb_simple_perror_msg(path);
     17        //errno = 0; /* why? */
    1818    }
    1919    return fp;
    2020}
     21
     22FILE* FAST_FUNC fopen_for_read(const char *path)
     23{
     24    return fopen(path, "r");
     25}
     26
     27FILE* FAST_FUNC xfopen_for_read(const char *path)
     28{
     29    return xfopen(path, "r");
     30}
     31
     32FILE* FAST_FUNC fopen_for_write(const char *path)
     33{
     34    return fopen(path, "w");
     35}
     36
     37FILE* FAST_FUNC xfopen_for_write(const char *path)
     38{
     39    return xfopen(path, "w");
     40}
     41
     42static FILE* xfdopen_helper(unsigned fd_and_rw_bit)
     43{
     44    FILE* fp = fdopen(fd_and_rw_bit >> 1, fd_and_rw_bit & 1 ? "w" : "r");
     45    if (!fp)
     46        bb_error_msg_and_die(bb_msg_memory_exhausted);
     47    return fp;
     48}
     49FILE* FAST_FUNC xfdopen_for_read(int fd)
     50{
     51    return xfdopen_helper(fd << 1);
     52}
     53FILE* FAST_FUNC xfdopen_for_write(int fd)
     54{
     55    return xfdopen_helper((fd << 1) + 1);
     56}
  • branches/2.2.9/mindi-busybox/libbb/wfopen_input.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    1111 * is a command line arg.  Since often that arg is '-' (meaning stdin),
    1212 * we avoid testing everywhere by consolidating things in this routine.
    13  *
    14  * Note: we also consider "" to mean stdin (for 'cmp' at least).
    1513 */
    1614
    1715#include "libbb.h"
    1816
    19 FILE *fopen_or_warn_stdin(const char *filename)
     17FILE* FAST_FUNC fopen_or_warn_stdin(const char *filename)
    2018{
    2119    FILE *fp = stdin;
    2220
    2321    if (filename != bb_msg_standard_input
    24      && filename[0]
    2522     && NOT_LONE_DASH(filename)
    2623    ) {
    2724        fp = fopen_or_warn(filename, "r");
    2825    }
    29 
    3026    return fp;
    3127}
     28
     29FILE* FAST_FUNC xfopen_stdin(const char *filename)
     30{
     31    FILE *fp = fopen_or_warn_stdin(filename);
     32    if (fp)
     33        return fp;
     34    xfunc_die();  /* We already output an error message. */
     35}
     36
     37int FAST_FUNC open_or_warn_stdin(const char *filename)
     38{
     39    int fd = STDIN_FILENO;
     40
     41    if (filename != bb_msg_standard_input
     42     && NOT_LONE_DASH(filename)
     43    ) {
     44        fd = open_or_warn(filename, O_RDONLY);
     45    }
     46
     47    return fd;
     48}
     49
     50int FAST_FUNC xopen_stdin(const char *filename)
     51{
     52    int fd = open_or_warn_stdin(filename);
     53    if (fd >= 0)
     54        return fd;
     55    xfunc_die();  /* We already output an error message. */
     56}
  • branches/2.2.9/mindi-busybox/libbb/xatonum.c

    r1765 r2725  
    55 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    99
     
    6060/* A few special cases */
    6161
    62 int xatoi_u(const char *numstr)
     62int FAST_FUNC xatoi_positive(const char *numstr)
    6363{
    6464    return xatou_range(numstr, 0, INT_MAX);
    6565}
    6666
    67 uint16_t xatou16(const char *numstr)
     67uint16_t FAST_FUNC xatou16(const char *numstr)
    6868{
    6969    return xatou_range(numstr, 0, 0xffff);
  • branches/2.2.9/mindi-busybox/libbb/xatonum_template.c

    r1765 r2725  
     1/*
     2 *
     3 * Licensed under GPLv2, see file LICENSE in this source tree.
     4 */
    15/*
    26You need to define the following (example):
     
    1317*/
    1418
    15 unsigned type xstrtou(_range_sfx)(const char *numstr, int base,
     19unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base,
    1620        unsigned type lower,
    1721        unsigned type upper,
     
    2226    char *e;
    2327
    24     /* Disallow '-' and any leading whitespace.  Speed isn't critical here
    25      * since we're parsing commandline args.  So make sure we get the
    26      * actual isspace function rather than a lnumstrer macro implementaion. */
    27     if (*numstr == '-' || *numstr == '+' || (isspace)(*numstr))
     28    /* Disallow '-' and any leading whitespace. */
     29    if (*numstr == '-' || *numstr == '+' || isspace(*numstr))
    2830        goto inval;
    2931
     
    4042        goto inval; /* error / no digits / illegal trailing chars */
    4143
    42     errno = old_errno;  /* Ok.  So restore errno. */
     44    errno = old_errno;  /* Ok.  So restore errno. */
    4345
    4446    /* Do optional suffix parsing.  Allow 'empty' suffix tables.
     
    7375}
    7476
    75 unsigned type xstrtou(_range)(const char *numstr, int base,
     77unsigned type FAST_FUNC xstrtou(_range)(const char *numstr, int base,
    7678        unsigned type lower,
    7779        unsigned type upper)
     
    8082}
    8183
    82 unsigned type xstrtou(_sfx)(const char *numstr, int base,
     84unsigned type FAST_FUNC xstrtou(_sfx)(const char *numstr, int base,
    8385        const struct suffix_mult *suffixes)
    8486{
     
    8688}
    8789
    88 unsigned type xstrtou()(const char *numstr, int base)
     90unsigned type FAST_FUNC xstrtou()(const char *numstr, int base)
    8991{
    9092    return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
    9193}
    9294
    93 unsigned type xatou(_range_sfx)(const char *numstr,
     95unsigned type FAST_FUNC xatou(_range_sfx)(const char *numstr,
    9496        unsigned type lower,
    9597        unsigned type upper,
     
    99101}
    100102
    101 unsigned type xatou(_range)(const char *numstr,
     103unsigned type FAST_FUNC xatou(_range)(const char *numstr,
    102104        unsigned type lower,
    103105        unsigned type upper)
     
    106108}
    107109
    108 unsigned type xatou(_sfx)(const char *numstr,
     110unsigned type FAST_FUNC xatou(_sfx)(const char *numstr,
    109111        const struct suffix_mult *suffixes)
    110112{
     
    112114}
    113115
    114 unsigned type xatou()(const char *numstr)
     116unsigned type FAST_FUNC xatou()(const char *numstr)
    115117{
    116118    return xatou(_sfx)(numstr, NULL);
     
    119121/* Signed ones */
    120122
    121 type xstrto(_range_sfx)(const char *numstr, int base,
     123type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
    122124        type lower,
    123125        type upper,
     
    128130    const char *p = numstr;
    129131
    130     if (p[0] == '-') {
     132    /* NB: if you'll decide to disallow '+':
     133     * at least renice applet needs to allow it */
     134    if (p[0] == '+' || p[0] == '-') {
    131135        ++p;
    132         ++u;    /* two's complement */
     136        if (p[0] == '-')
     137            ++u; /* = <type>_MIN (01111... + 1 == 10000...) */
    133138    }
    134139
     
    147152}
    148153
    149 type xstrto(_range)(const char *numstr, int base, type lower, type upper)
     154type FAST_FUNC xstrto(_range)(const char *numstr, int base, type lower, type upper)
    150155{
    151156    return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
    152157}
    153158
    154 type xato(_range_sfx)(const char *numstr,
     159type FAST_FUNC xstrto()(const char *numstr, int base)
     160{
     161    return xstrto(_range_sfx)(numstr, base, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
     162}
     163
     164type FAST_FUNC xato(_range_sfx)(const char *numstr,
    155165        type lower,
    156166        type upper,
     
    160170}
    161171
    162 type xato(_range)(const char *numstr, type lower, type upper)
     172type FAST_FUNC xato(_range)(const char *numstr, type lower, type upper)
    163173{
    164174    return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL);
    165175}
    166176
    167 type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
     177type FAST_FUNC xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
    168178{
    169179    return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes);
    170180}
    171181
    172 type xato()(const char *numstr)
     182type FAST_FUNC xato()(const char *numstr)
    173183{
    174184    return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
  • branches/2.2.9/mindi-busybox/libbb/xconnect.c

    r1765 r2725  
    55 * Connect to host at port using address resolution from getaddrinfo
    66 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    78 */
    89
     10#include <sys/types.h>
     11#include <sys/socket.h> /* netinet/in.h needs it */
    912#include <netinet/in.h>
     13#include <net/if.h>
     14#include <sys/un.h>
    1015#include "libbb.h"
    1116
    12 void setsockopt_reuseaddr(int fd)
     17void FAST_FUNC setsockopt_reuseaddr(int fd)
    1318{
    1419    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
    1520}
    16 int setsockopt_broadcast(int fd)
     21int FAST_FUNC setsockopt_broadcast(int fd)
    1722{
    1823    return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
    1924}
    2025
    21 void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
     26#ifdef SO_BINDTODEVICE
     27int FAST_FUNC setsockopt_bindtodevice(int fd, const char *iface)
     28{
     29    int r;
     30    struct ifreq ifr;
     31    strncpy_IFNAMSIZ(ifr.ifr_name, iface);
     32    /* NB: passing (iface, strlen(iface) + 1) does not work!
     33     * (maybe it works on _some_ kernels, but not on 2.6.26)
     34     * Actually, ifr_name is at offset 0, and in practice
     35     * just giving char[IFNAMSIZ] instead of struct ifreq works too.
     36     * But just in case it's not true on some obscure arch... */
     37    r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
     38    if (r)
     39        bb_perror_msg("can't bind to interface %s", iface);
     40    return r;
     41}
     42#else
     43int FAST_FUNC setsockopt_bindtodevice(int fd UNUSED_PARAM,
     44        const char *iface UNUSED_PARAM)
     45{
     46    bb_error_msg("SO_BINDTODEVICE is not supported on this system");
     47    return -1;
     48}
     49#endif
     50
     51static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen))
     52{
     53    len_and_sockaddr lsa;
     54    len_and_sockaddr *lsa_ptr;
     55
     56    lsa.len = LSA_SIZEOF_SA;
     57    if (get_name(fd, &lsa.u.sa, &lsa.len) != 0)
     58        return NULL;
     59
     60    lsa_ptr = xzalloc(LSA_LEN_SIZE + lsa.len);
     61    if (lsa.len > LSA_SIZEOF_SA) { /* rarely (if ever) happens */
     62        lsa_ptr->len = lsa.len;
     63        get_name(fd, &lsa_ptr->u.sa, &lsa_ptr->len);
     64    } else {
     65        memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len);
     66    }
     67    return lsa_ptr;
     68}
     69
     70len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd)
     71{
     72    return get_lsa(fd, getsockname);
     73}
     74
     75len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd)
     76{
     77    return get_lsa(fd, getpeername);
     78}
     79
     80void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
    2281{
    2382    if (connect(s, s_addr, addrlen) < 0) {
     
    2685        if (s_addr->sa_family == AF_INET)
    2786            bb_perror_msg_and_die("%s (%s)",
    28                 "cannot connect to remote host",
     87                "can't connect to remote host",
    2988                inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
    30         bb_perror_msg_and_die("cannot connect to remote host");
     89        bb_perror_msg_and_die("can't connect to remote host");
    3190    }
    3291}
     
    3493/* Return port number for a service.
    3594 * If "port" is a number use it as the port.
    36  * If "port" is a name it is looked up in /etc/services, if it isnt found return
    37  * default_port */
    38 unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
     95 * If "port" is a name it is looked up in /etc/services,
     96 * if it isnt found return default_port
     97 */
     98unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
    3999{
    40100    unsigned port_nr = default_port;
     
    58118
    59119
    60 /* "Old" networking API - only IPv4 */
    61 
    62 /*
    63 void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
    64 {
    65     struct hostent *he;
    66 
    67     memset(s_in, 0, sizeof(struct sockaddr_in));
    68     s_in->sin_family = AF_INET;
    69     he = xgethostbyname(host);
    70     memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
    71 }
    72 
    73 
    74 int xconnect_tcp_v4(struct sockaddr_in *s_addr)
    75 {
    76     int s = xsocket(AF_INET, SOCK_STREAM, 0);
    77     xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
    78     return s;
    79 }
    80 */
    81 
    82120/* "New" networking API */
    83121
    84122
    85 int get_nport(const struct sockaddr *sa)
     123int FAST_FUNC get_nport(const struct sockaddr *sa)
    86124{
    87125#if ENABLE_FEATURE_IPV6
     
    97135}
    98136
    99 void set_nport(len_and_sockaddr *lsa, unsigned port)
    100 {
    101 #if ENABLE_FEATURE_IPV6
    102     if (lsa->sa.sa_family == AF_INET6) {
    103         lsa->sin6.sin6_port = port;
     137void FAST_FUNC set_nport(len_and_sockaddr *lsa, unsigned port)
     138{
     139#if ENABLE_FEATURE_IPV6
     140    if (lsa->u.sa.sa_family == AF_INET6) {
     141        lsa->u.sin6.sin6_port = port;
    104142        return;
    105143    }
    106144#endif
    107     if (lsa->sa.sa_family == AF_INET) {
    108         lsa->sin.sin_port = port;
     145    if (lsa->u.sa.sa_family == AF_INET) {
     146        lsa->u.sin.sin_port = port;
    109147        return;
    110148    }
     
    120158static len_and_sockaddr* str2sockaddr(
    121159        const char *host, int port,
    122 USE_FEATURE_IPV6(sa_family_t af,)
     160IF_FEATURE_IPV6(sa_family_t af,)
    123161        int ai_flags)
    124162{
     163IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;)
    125164    int rc;
    126     len_and_sockaddr *r = NULL;
     165    len_and_sockaddr *r;
    127166    struct addrinfo *result = NULL;
     167    struct addrinfo *used_res;
    128168    const char *org_host = host; /* only for error msg */
    129169    const char *cp;
    130170    struct addrinfo hint;
    131171
     172    if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) {
     173        struct sockaddr_un *sun;
     174
     175        r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
     176        r->len = sizeof(struct sockaddr_un);
     177        r->u.sa.sa_family = AF_UNIX;
     178        sun = (struct sockaddr_un *)&r->u.sa;
     179        safe_strncpy(sun->sun_path, host + 6, sizeof(sun->sun_path));
     180        return r;
     181    }
     182
     183    r = NULL;
     184
    132185    /* Ugly parsing of host:addr */
    133186    if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
     187        /* Even uglier parsing of [xx]:nn */
    134188        host++;
    135189        cp = strchr(host, ']');
    136         if (!cp || cp[1] != ':') /* Malformed: must have [xx]:nn */
    137             bb_error_msg_and_die("bad address '%s'", org_host);
    138             //return r; /* return NULL */
     190        if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
     191            /* Malformed: must be [xx]:nn or [xx] */
     192            bb_error_msg("bad address '%s'", org_host);
     193            if (ai_flags & DIE_ON_ERROR)
     194                xfunc_die();
     195            return NULL;
     196        }
    139197    } else {
    140198        cp = strrchr(host, ':');
     
    144202        }
    145203    }
    146     if (cp) {
     204    if (cp) { /* points to ":" or "]:" */
    147205        int sz = cp - host + 1;
     206
    148207        host = safe_strncpy(alloca(sz), host, sz);
    149         if (ENABLE_FEATURE_IPV6 && *cp != ':')
     208        if (ENABLE_FEATURE_IPV6 && *cp != ':') {
    150209            cp++; /* skip ']' */
     210            if (*cp == '\0') /* [xx] without port */
     211                goto skip;
     212        }
    151213        cp++; /* skip ':' */
    152         port = xatou16(cp);
    153     }
     214        port = bb_strtou(cp, NULL, 10);
     215        if (errno || (unsigned)port > 0xffff) {
     216            bb_error_msg("bad port spec '%s'", org_host);
     217            if (ai_flags & DIE_ON_ERROR)
     218                xfunc_die();
     219            return NULL;
     220        }
     221 skip: ;
     222    }
     223
     224    /* Next two if blocks allow to skip getaddrinfo()
     225     * in case host name is a numeric IP(v6) address.
     226     * getaddrinfo() initializes DNS resolution machinery,
     227     * scans network config and such - tens of syscalls.
     228     */
     229    /* If we were not asked specifically for IPv6,
     230     * check whether this is a numeric IPv4 */
     231    IF_FEATURE_IPV6(if(af != AF_INET6)) {
     232        struct in_addr in4;
     233        if (inet_aton(host, &in4) != 0) {
     234            r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
     235            r->len = sizeof(struct sockaddr_in);
     236            r->u.sa.sa_family = AF_INET;
     237            r->u.sin.sin_addr = in4;
     238            goto set_port;
     239        }
     240    }
     241#if ENABLE_FEATURE_IPV6
     242    /* If we were not asked specifically for IPv4,
     243     * check whether this is a numeric IPv6 */
     244    if (af != AF_INET) {
     245        struct in6_addr in6;
     246        if (inet_pton(AF_INET6, host, &in6) > 0) {
     247            r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
     248            r->len = sizeof(struct sockaddr_in6);
     249            r->u.sa.sa_family = AF_INET6;
     250            r->u.sin6.sin6_addr = in6;
     251            goto set_port;
     252        }
     253    }
     254#endif
    154255
    155256    memset(&hint, 0 , sizeof(hint));
    156 #if !ENABLE_FEATURE_IPV6
    157     hint.ai_family = AF_INET; /* do not try to find IPv6 */
    158 #else
    159257    hint.ai_family = af;
    160 #endif
    161258    /* Needed. Or else we will get each address thrice (or more)
    162259     * for each possible socket type (tcp,udp,raw...): */
     
    170267        goto ret;
    171268    }
    172     r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen);
    173     r->len = result->ai_addrlen;
    174     memcpy(&r->sa, result->ai_addr, result->ai_addrlen);
     269    used_res = result;
     270#if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
     271    while (1) {
     272        if (used_res->ai_family == AF_INET)
     273            break;
     274        used_res = used_res->ai_next;
     275        if (!used_res) {
     276            used_res = result;
     277            break;
     278        }
     279    }
     280#endif
     281    r = xmalloc(LSA_LEN_SIZE + used_res->ai_addrlen);
     282    r->len = used_res->ai_addrlen;
     283    memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
     284
     285 set_port:
    175286    set_nport(r, htons(port));
    176287 ret:
     
    183294
    184295#if ENABLE_FEATURE_IPV6
    185 len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af)
     296len_and_sockaddr* FAST_FUNC host_and_af2sockaddr(const char *host, int port, sa_family_t af)
    186297{
    187298    return str2sockaddr(host, port, af, 0);
    188299}
    189300
    190 len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
     301len_and_sockaddr* FAST_FUNC xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
    191302{
    192303    return str2sockaddr(host, port, af, DIE_ON_ERROR);
     
    194305#endif
    195306
    196 len_and_sockaddr* host2sockaddr(const char *host, int port)
     307len_and_sockaddr* FAST_FUNC host2sockaddr(const char *host, int port)
    197308{
    198309    return str2sockaddr(host, port, AF_UNSPEC, 0);
    199310}
    200311
    201 len_and_sockaddr* xhost2sockaddr(const char *host, int port)
     312len_and_sockaddr* FAST_FUNC xhost2sockaddr(const char *host, int port)
    202313{
    203314    return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
    204315}
    205316
    206 len_and_sockaddr* xdotted2sockaddr(const char *host, int port)
     317len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port)
    207318{
    208319    return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
    209320}
    210321
    211 int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)
    212 {
    213     SKIP_FEATURE_IPV6(enum { family = AF_INET };)
     322#undef xsocket_type
     323int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type)
     324{
     325    IF_NOT_FEATURE_IPV6(enum { family = AF_INET };)
    214326    len_and_sockaddr *lsa;
    215327    int fd;
     
    234346    }
    235347#endif
    236     lsa = xzalloc(offsetof(len_and_sockaddr, sa) + len);
     348    lsa = xzalloc(LSA_LEN_SIZE + len);
    237349    lsa->len = len;
    238     lsa->sa.sa_family = family;
     350    lsa->u.sa.sa_family = family;
    239351    *lsap = lsa;
    240352    return fd;
    241353}
    242354
    243 int xsocket_stream(len_and_sockaddr **lsap)
    244 {
    245     return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
     355int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)
     356{
     357    return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
    246358}
    247359
     
    254366        lsa = xdotted2sockaddr(bindaddr, port);
    255367        /* user specified bind addr dictates family */
    256         fd = xsocket(lsa->sa.sa_family, sock_type, 0);
     368        fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
    257369    } else {
    258         fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);
     370        fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type);
    259371        set_nport(lsa, htons(port));
    260372    }
    261373    setsockopt_reuseaddr(fd);
    262     xbind(fd, &lsa->sa, lsa->len);
     374    xbind(fd, &lsa->u.sa, lsa->len);
    263375    free(lsa);
    264376    return fd;
    265377}
    266378
    267 int create_and_bind_stream_or_die(const char *bindaddr, int port)
     379int FAST_FUNC create_and_bind_stream_or_die(const char *bindaddr, int port)
    268380{
    269381    return create_and_bind_or_die(bindaddr, port, SOCK_STREAM);
    270382}
    271383
    272 int create_and_bind_dgram_or_die(const char *bindaddr, int port)
     384int FAST_FUNC create_and_bind_dgram_or_die(const char *bindaddr, int port)
    273385{
    274386    return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM);
     
    276388
    277389
    278 int create_and_connect_stream_or_die(const char *peer, int port)
     390int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port)
    279391{
    280392    int fd;
     
    282394
    283395    lsa = xhost2sockaddr(peer, port);
    284     fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
     396    fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
    285397    setsockopt_reuseaddr(fd);
    286     xconnect(fd, &lsa->sa, lsa->len);
     398    xconnect(fd, &lsa->u.sa, lsa->len);
    287399    free(lsa);
    288400    return fd;
    289401}
    290402
    291 int xconnect_stream(const len_and_sockaddr *lsa)
    292 {
    293     int fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
    294     xconnect(fd, &lsa->sa, lsa->len);
     403int FAST_FUNC xconnect_stream(const len_and_sockaddr *lsa)
     404{
     405    int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
     406    xconnect(fd, &lsa->u.sa, lsa->len);
    295407    return fd;
    296408}
     
    299411/* It doesn't hurt because we will add this bit anyway */
    300412#define IGNORE_PORT NI_NUMERICSERV
    301 static char* sockaddr2str(const struct sockaddr *sa, int flags)
     413static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags)
    302414{
    303415    char host[128];
     
    305417    int rc;
    306418    socklen_t salen;
     419
     420    if (ENABLE_FEATURE_UNIX_LOCAL && sa->sa_family == AF_UNIX) {
     421        struct sockaddr_un *sun = (struct sockaddr_un *)sa;
     422        return xasprintf("local:%.*s",
     423                (int) sizeof(sun->sun_path),
     424                sun->sun_path);
     425    }
    307426
    308427    salen = LSA_SIZEOF_SA;
     
    338457}
    339458
    340 char* xmalloc_sockaddr2host(const struct sockaddr *sa)
     459char* FAST_FUNC xmalloc_sockaddr2host(const struct sockaddr *sa)
    341460{
    342461    return sockaddr2str(sa, 0);
    343462}
    344463
    345 char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
     464char* FAST_FUNC xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
    346465{
    347466    return sockaddr2str(sa, IGNORE_PORT);
    348467}
    349468
    350 char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
     469char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
    351470{
    352471    return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
    353472}
    354 char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)
     473char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa)
    355474{
    356475    return sockaddr2str(sa, NI_NUMERICHOST);
    357476}
    358477
    359 char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
     478char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
    360479{
    361480    return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
  • branches/2.2.9/mindi-busybox/libbb/xfuncs.c

    r1765 r2725  
    55 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    66 * Copyright (C) 2006 Rob Landley
    7  * Copyright (C) 2006 Denis Vlasenko
     7 * Copyright (C) 2006 Denys Vlasenko
    88 *
    9  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2, see file LICENSE in this source tree.
    1010 */
    1111
     12/* We need to have separate xfuncs.c and xfuncs_printf.c because
     13 * with current linkers, even with section garbage collection,
     14 * if *.o module references any of XXXprintf functions, you pull in
     15 * entire printf machinery. Even if you do not use the function
     16 * which uses XXXprintf.
     17 *
     18 * xfuncs.c contains functions (not necessarily xfuncs)
     19 * which do not pull in printf, directly or indirectly.
     20 * xfunc_printf.c contains those which do.
     21 *
     22 * TODO: move xmalloc() and xatonum() here.
     23 */
     24
    1225#include "libbb.h"
    1326
    14 /* All the functions starting with "x" call bb_error_msg_and_die() if they
    15  * fail, so callers never need to check for errors.  If it returned, it
    16  * succeeded. */
    17 
    18 #ifndef DMALLOC
    19 /* dmalloc provides variants of these that do abort() on failure.
    20  * Since dmalloc's prototypes overwrite the impls here as they are
    21  * included after these prototypes in libbb.h, all is well.
     27/* Turn on nonblocking I/O on a fd */
     28int FAST_FUNC ndelay_on(int fd)
     29{
     30    return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
     31}
     32
     33int FAST_FUNC ndelay_off(int fd)
     34{
     35    return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
     36}
     37
     38int FAST_FUNC close_on_exec_on(int fd)
     39{
     40    return fcntl(fd, F_SETFD, FD_CLOEXEC);
     41}
     42
     43char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src)
     44{
     45#ifndef IFNAMSIZ
     46    enum { IFNAMSIZ = 16 };
     47#endif
     48    return strncpy(dst, src, IFNAMSIZ);
     49}
     50
     51
     52/* Convert unsigned integer to ascii, writing into supplied buffer.
     53 * A truncated result contains the first few digits of the result ala strncpy.
     54 * Returns a pointer past last generated digit, does _not_ store NUL.
    2255 */
    23 // Warn if we can't allocate size bytes of memory.
    24 void *malloc_or_warn(size_t size)
    25 {
    26     void *ptr = malloc(size);
    27     if (ptr == NULL && size != 0)
    28         bb_error_msg(bb_msg_memory_exhausted);
    29     return ptr;
    30 }
    31 
    32 // Die if we can't allocate size bytes of memory.
    33 void *xmalloc(size_t size)
    34 {
    35     void *ptr = malloc(size);
    36     if (ptr == NULL && size != 0)
    37         bb_error_msg_and_die(bb_msg_memory_exhausted);
    38     return ptr;
    39 }
    40 
    41 // Die if we can't resize previously allocated memory.  (This returns a pointer
    42 // to the new memory, which may or may not be the same as the old memory.
    43 // It'll copy the contents to a new chunk and free the old one if necessary.)
    44 void *xrealloc(void *ptr, size_t size)
    45 {
    46     ptr = realloc(ptr, size);
    47     if (ptr == NULL && size != 0)
    48         bb_error_msg_and_die(bb_msg_memory_exhausted);
    49     return ptr;
    50 }
    51 #endif /* DMALLOC */
    52 
    53 // Die if we can't allocate and zero size bytes of memory.
    54 void *xzalloc(size_t size)
    55 {
    56     void *ptr = xmalloc(size);
    57     memset(ptr, 0, size);
    58     return ptr;
    59 }
    60 
    61 // Die if we can't copy a string to freshly allocated memory.
    62 char * xstrdup(const char *s)
    63 {
    64     char *t;
    65 
    66     if (s == NULL)
    67         return NULL;
    68 
    69     t = strdup(s);
    70 
    71     if (t == NULL)
    72         bb_error_msg_and_die(bb_msg_memory_exhausted);
    73 
    74     return t;
    75 }
    76 
    77 // Die if we can't allocate n+1 bytes (space for the null terminator) and copy
    78 // the (possibly truncated to length n) string into it.
    79 char * xstrndup(const char *s, int n)
    80 {
    81     int m;
    82     char *t;
    83 
    84     if (ENABLE_DEBUG && s == NULL)
    85         bb_error_msg_and_die("xstrndup bug");
    86 
    87     /* We can just xmalloc(n+1) and strncpy into it, */
    88     /* but think about xstrndup("abc", 10000) wastage! */
    89     m = n;
    90     t = (char*) s;
    91     while (m) {
    92         if (!*t) break;
    93         m--;
    94         t++;
    95     }
    96     n -= m;
    97     t = xmalloc(n + 1);
    98     t[n] = '\0';
    99 
    100     return memcpy(t, s, n);
    101 }
    102 
    103 // Die if we can't open a file and return a FILE * to it.
    104 // Notice we haven't got xfread(), This is for use with fscanf() and friends.
    105 FILE *xfopen(const char *path, const char *mode)
    106 {
    107     FILE *fp = fopen(path, mode);
    108     if (fp == NULL)
    109         bb_perror_msg_and_die("can't open '%s'", path);
    110     return fp;
    111 }
    112 
    113 // Die if we can't open a file and return a fd.
    114 int xopen3(const char *pathname, int flags, int mode)
    115 {
    116     int ret;
    117 
    118     ret = open(pathname, flags, mode);
    119     if (ret < 0) {
    120         bb_perror_msg_and_die("can't open '%s'", pathname);
    121     }
    122     return ret;
    123 }
    124 
    125 // Die if we can't open an existing file and return a fd.
    126 int xopen(const char *pathname, int flags)
    127 {
    128     return xopen3(pathname, flags, 0666);
    129 }
    130 
    131 // Warn if we can't open a file and return a fd.
    132 int open3_or_warn(const char *pathname, int flags, int mode)
    133 {
    134     int ret;
    135 
    136     ret = open(pathname, flags, mode);
    137     if (ret < 0) {
    138         bb_perror_msg("can't open '%s'", pathname);
    139     }
    140     return ret;
    141 }
    142 
    143 // Warn if we can't open a file and return a fd.
    144 int open_or_warn(const char *pathname, int flags)
    145 {
    146     return open3_or_warn(pathname, flags, 0666);
    147 }
    148 
    149 void xpipe(int filedes[2])
    150 {
    151     if (pipe(filedes))
    152         bb_perror_msg_and_die("can't create pipe");
    153 }
    154 
    155 void xunlink(const char *pathname)
    156 {
    157     if (unlink(pathname))
    158         bb_perror_msg_and_die("can't remove file '%s'", pathname);
    159 }
    160 
    161 // Turn on nonblocking I/O on a fd
    162 int ndelay_on(int fd)
    163 {
    164     return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
    165 }
    166 
    167 int ndelay_off(int fd)
    168 {
    169     return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK);
    170 }
    171 
    172 void xdup2(int from, int to)
    173 {
    174     if (dup2(from, to) != to)
    175         bb_perror_msg_and_die("can't duplicate file descriptor");
    176 }
    177 
    178 // "Renumber" opened fd
    179 void xmove_fd(int from, int to)
    180 {
    181     if (from == to)
    182         return;
    183     xdup2(from, to);
    184     close(from);
    185 }
    186 
    187 // Die with an error message if we can't write the entire buffer.
    188 void xwrite(int fd, const void *buf, size_t count)
    189 {
    190     if (count) {
    191         ssize_t size = full_write(fd, buf, count);
    192         if (size != count)
    193             bb_error_msg_and_die("short write");
    194     }
    195 }
    196 
    197 // Die with an error message if we can't lseek to the right spot.
    198 off_t xlseek(int fd, off_t offset, int whence)
    199 {
    200     off_t off = lseek(fd, offset, whence);
    201     if (off == (off_t)-1) {
    202         if (whence == SEEK_SET)
    203             bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
    204         bb_perror_msg_and_die("lseek");
    205     }
    206     return off;
    207 }
    208 
    209 // Die with supplied filename if this FILE * has ferror set.
    210 void die_if_ferror(FILE *fp, const char *fn)
    211 {
    212     if (ferror(fp)) {
    213         /* ferror doesn't set useful errno */
    214         bb_error_msg_and_die("%s: I/O error", fn);
    215     }
    216 }
    217 
    218 // Die with an error message if stdout has ferror set.
    219 void die_if_ferror_stdout(void)
    220 {
    221     die_if_ferror(stdout, bb_msg_standard_output);
    222 }
    223 
    224 // Die with an error message if we have trouble flushing stdout.
    225 void xfflush_stdout(void)
    226 {
    227     if (fflush(stdout)) {
    228         bb_perror_msg_and_die(bb_msg_standard_output);
    229     }
    230 }
    231 
    232 void sig_block(int sig)
    233 {
    234     sigset_t ss;
    235     sigemptyset(&ss);
    236     sigaddset(&ss, sig);
    237     sigprocmask(SIG_BLOCK, &ss, NULL);
    238 }
    239 
    240 void sig_unblock(int sig)
    241 {
    242     sigset_t ss;
    243     sigemptyset(&ss);
    244     sigaddset(&ss, sig);
    245     sigprocmask(SIG_UNBLOCK, &ss, NULL);
    246 }
    247 
    248 #if 0
    249 void sig_blocknone(void)
    250 {
    251     sigset_t ss;
    252     sigemptyset(&ss);
    253     sigprocmask(SIG_SETMASK, &ss, NULL);
    254 }
    255 #endif
    256 
    257 void sig_catch(int sig, void (*f)(int))
    258 {
    259     struct sigaction sa;
    260     sa.sa_handler = f;
    261     sa.sa_flags = 0;
    262     sigemptyset(&sa.sa_mask);
    263     sigaction(sig, &sa, NULL);
    264 }
    265 
    266 void sig_pause(void)
    267 {
    268     sigset_t ss;
    269     sigemptyset(&ss);
    270     sigsuspend(&ss);
    271 }
    272 
    273 
    274 void xsetenv(const char *key, const char *value)
    275 {
    276     if (setenv(key, value, 1))
    277         bb_error_msg_and_die(bb_msg_memory_exhausted);
    278 }
    279 
    280 // Converts unsigned long long value into compact 4-char
    281 // representation. Examples: "1234", "1.2k", " 27M", "123T"
    282 // Fifth char is always '\0'
    283 void smart_ulltoa5(unsigned long long ul, char buf[5])
    284 {
    285     const char *fmt;
    286     char c;
    287     unsigned v,idx = 0;
    288     ul *= 10;
    289     if (ul > 9999*10) { // do not scale if 9999 or less
    290         while (ul >= 10000) {
    291             ul /= 1024;
    292             idx++;
    293         }
    294     }
    295     v = ul; // ullong divisions are expensive, avoid them
    296 
    297     fmt = " 123456789";
    298     if (!idx) {     // 9999 or less: use 1234 format
    299         c = buf[0] = " 123456789"[v/10000];
    300         if (c != ' ') fmt = "0123456789";
    301         c = buf[1] = fmt[v/1000%10];
    302         if (c != ' ') fmt = "0123456789";
    303         buf[2] = fmt[v/100%10];
    304         buf[3] = "0123456789"[v/10%10];
    305     } else {
    306         if (v >= 10*10) {   // scaled value is >=10: use 123M format
    307             c = buf[0] = " 123456789"[v/1000];
    308             if (c != ' ') fmt = "0123456789";
    309             buf[1] = fmt[v/100%10];
    310             buf[2] = "0123456789"[v/10%10];
    311         } else {    // scaled value is <10: use 1.2M format
    312             buf[0] = "0123456789"[v/10];
    313             buf[1] = '.';
    314             buf[2] = "0123456789"[v%10];
    315         }
    316         // see http://en.wikipedia.org/wiki/Tera
    317         buf[3] = " kMGTPEZY"[idx];
    318     }
    319     buf[4] = '\0';
    320 }
    321 
    322 // Convert unsigned integer to ascii, writing into supplied buffer.
    323 // A truncated result contains the first few digits of the result ala strncpy.
    324 // Returns a pointer past last generated digit, does _not_ store NUL.
    325 void BUG_sizeof_unsigned_not_4(void);
    326 char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
     56void BUG_sizeof(void);
     57char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen)
    32758{
    32859    unsigned i, out, res;
    329     if (sizeof(unsigned) != 4)
    330         BUG_sizeof_unsigned_not_4();
     60
    33161    if (buflen) {
    33262        out = 0;
    333         for (i = 1000000000; i; i /= 10) {
     63        if (sizeof(n) == 4)
     64        // 2^32-1 = 4294967295
     65            i = 1000000000;
     66#if UINT_MAX > 4294967295 /* prevents warning about "const too large" */
     67        else
     68        if (sizeof(n) == 8)
     69        // 2^64-1 = 18446744073709551615
     70            i = 10000000000000000000;
     71#endif
     72        else
     73            BUG_sizeof();
     74        for (; i; i /= 10) {
    33475            res = n / i;
     76            n = n % i;
    33577            if (res || out || i == 1) {
    336                 if (!--buflen) break;
     78                if (--buflen == 0)
     79                    break;
    33780                out++;
    338                 n -= res*i;
    33981                *buf++ = '0' + res;
    34082            }
     
    34486}
    34587
    346 // Convert signed integer to ascii, like utoa_to_buf()
    347 char *itoa_to_buf(int n, char *buf, unsigned buflen)
    348 {
    349     if (buflen && n<0) {
     88/* Convert signed integer to ascii, like utoa_to_buf() */
     89char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen)
     90{
     91    if (!buflen)
     92        return buf;
     93    if (n < 0) {
    35094        n = -n;
    35195        *buf++ = '-';
     
    358102// second time will overwrite previous results.
    359103//
    360 // The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes.
    361 // Int should always be 32 bits on any remotely Unix-like system, see
    362 // http://www.unix.org/whitepapers/64bit.html for the reasons why.
    363 
    364 static char local_buf[12];
    365 
    366 // Convert unsigned integer to ascii using a static buffer (returned).
    367 char *utoa(unsigned n)
    368 {
    369     *(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
     104// The largest 32 bit integer is -2 billion plus NUL, or 1+10+1=12 bytes.
     105// It so happens that sizeof(int) * 3 is enough for 32+ bit ints.
     106// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit)
     107
     108static char local_buf[sizeof(int) * 3];
     109
     110/* Convert unsigned integer to ascii using a static buffer (returned). */
     111char* FAST_FUNC utoa(unsigned n)
     112{
     113    *(utoa_to_buf(n, local_buf, sizeof(local_buf) - 1)) = '\0';
    370114
    371115    return local_buf;
    372116}
    373117
    374 // Convert signed integer to ascii using a static buffer (returned).
    375 char *itoa(int n)
    376 {
    377     *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
     118/* Convert signed integer to ascii using a static buffer (returned). */
     119char* FAST_FUNC itoa(int n)
     120{
     121    *(itoa_to_buf(n, local_buf, sizeof(local_buf) - 1)) = '\0';
    378122
    379123    return local_buf;
    380124}
    381125
    382 // Emit a string of hex representation of bytes
    383 char *bin2hex(char *p, const char *cp, int count)
     126/* Emit a string of hex representation of bytes */
     127char* FAST_FUNC bin2hex(char *p, const char *cp, int count)
    384128{
    385129    while (count) {
     
    393137}
    394138
    395 // Die with an error message if we can't set gid.  (Because resource limits may
    396 // limit this user to a given number of processes, and if that fills up the
    397 // setgid() will fail and we'll _still_be_root_, which is bad.)
    398 void xsetgid(gid_t gid)
    399 {
    400     if (setgid(gid)) bb_perror_msg_and_die("setgid");
    401 }
    402 
    403 // Die with an error message if we can't set uid.  (See xsetgid() for why.)
    404 void xsetuid(uid_t uid)
    405 {
    406     if (setuid(uid)) bb_perror_msg_and_die("setuid");
    407 }
    408 
    409 // Return how long the file at fd is, if there's any way to determine it.
    410 off_t fdlength(int fd)
     139/* Convert "[x]x[:][x]x[:][x]x[:][x]x" hex string to binary, no more than COUNT bytes */
     140char* FAST_FUNC hex2bin(char *dst, const char *str, int count)
     141{
     142    errno = EINVAL;
     143    while (*str && count) {
     144        uint8_t val;
     145        uint8_t c = *str++;
     146        if (isdigit(c))
     147            val = c - '0';
     148        else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
     149            val = (c|0x20) - ('a' - 10);
     150        else
     151            return NULL;
     152        val <<= 4;
     153        c = *str;
     154        if (isdigit(c))
     155            val |= c - '0';
     156        else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
     157            val |= (c|0x20) - ('a' - 10);
     158        else if (c == ':' || c == '\0')
     159            val >>= 4;
     160        else
     161            return NULL;
     162
     163        *dst++ = val;
     164        if (c != '\0')
     165            str++;
     166        if (*str == ':')
     167            str++;
     168        count--;
     169    }
     170    errno = (*str ? ERANGE : 0);
     171    return dst;
     172}
     173
     174/* Return how long the file at fd is, if there's any way to determine it. */
     175#ifdef UNUSED
     176off_t FAST_FUNC fdlength(int fd)
    411177{
    412178    off_t bottom = 0, top = 0, pos;
     
    446212    return pos + 1;
    447213}
    448 
    449 // Die with an error message if we can't malloc() enough space and do an
    450 // sprintf() into that space.
    451 char *xasprintf(const char *format, ...)
    452 {
    453     va_list p;
    454     int r;
    455     char *string_ptr;
    456 
    457 #if 1
    458     // GNU extension
    459     va_start(p, format);
    460     r = vasprintf(&string_ptr, format, p);
    461     va_end(p);
    462 #else
    463     // Bloat for systems that haven't got the GNU extension.
    464     va_start(p, format);
    465     r = vsnprintf(NULL, 0, format, p);
    466     va_end(p);
    467     string_ptr = xmalloc(r+1);
    468     va_start(p, format);
    469     r = vsnprintf(string_ptr, r+1, format, p);
    470     va_end(p);
    471214#endif
    472215
    473     if (r < 0) bb_error_msg_and_die(bb_msg_memory_exhausted);
    474     return string_ptr;
    475 }
    476 
    477 #if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */
    478 int fdprintf(int fd, const char *format, ...)
    479 {
    480     va_list p;
    481     int r;
    482     char *string_ptr;
    483 
    484 #if 1
    485     // GNU extension
    486     va_start(p, format);
    487     r = vasprintf(&string_ptr, format, p);
    488     va_end(p);
    489 #else
    490     // Bloat for systems that haven't got the GNU extension.
    491     va_start(p, format);
    492     r = vsnprintf(NULL, 0, format, p) + 1;
    493     va_end(p);
    494     string_ptr = malloc(r);
    495     if (string_ptr) {
    496         va_start(p, format);
    497         r = vsnprintf(string_ptr, r, format, p);
    498         va_end(p);
    499     }
    500 #endif
    501 
    502     if (r >= 0) {
    503         full_write(fd, string_ptr, r);
    504         free(string_ptr);
    505     }
    506     return r;
    507 }
    508 #endif
    509 
    510 // Die with an error message if we can't copy an entire FILE * to stdout, then
    511 // close that file.
    512 void xprint_and_close_file(FILE *file)
    513 {
    514     fflush(stdout);
    515     // copyfd outputs error messages for us.
    516     if (bb_copyfd_eof(fileno(file), 1) == -1)
    517         xfunc_die();
    518 
    519     fclose(file);
    520 }
    521 
    522 // Die if we can't chdir to a new path.
    523 void xchdir(const char *path)
    524 {
    525     if (chdir(path))
    526         bb_perror_msg_and_die("chdir(%s)", path);
    527 }
    528 
    529 // Print a warning message if opendir() fails, but don't die.
    530 DIR *warn_opendir(const char *path)
    531 {
    532     DIR *dp;
    533 
    534     dp = opendir(path);
    535     if (!dp)
    536         bb_perror_msg("can't open '%s'", path);
    537     return dp;
    538 }
    539 
    540 // Die with an error message if opendir() fails.
    541 DIR *xopendir(const char *path)
    542 {
    543     DIR *dp;
    544 
    545     dp = opendir(path);
    546     if (!dp)
    547         bb_perror_msg_and_die("can't open '%s'", path);
    548     return dp;
    549 }
    550 
    551 // Die with an error message if we can't open a new socket.
    552 int xsocket(int domain, int type, int protocol)
    553 {
    554     int r = socket(domain, type, protocol);
    555 
    556     if (r < 0) {
    557         /* Hijack vaguely related config option */
    558 #if ENABLE_VERBOSE_RESOLUTION_ERRORS
    559         const char *s = "INET";
    560         if (domain == AF_PACKET) s = "PACKET";
    561         if (domain == AF_NETLINK) s = "NETLINK";
    562 USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
    563         bb_perror_msg_and_die("socket(AF_%s)", s);
    564 #else
    565         bb_perror_msg_and_die("socket");
    566 #endif
    567     }
    568 
    569     return r;
    570 }
    571 
    572 // Die with an error message if we can't bind a socket to an address.
    573 void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
    574 {
    575     if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind");
    576 }
    577 
    578 // Die with an error message if we can't listen for connections on a socket.
    579 void xlisten(int s, int backlog)
    580 {
    581     if (listen(s, backlog)) bb_perror_msg_and_die("listen");
    582 }
    583 
    584 /* Die with an error message if sendto failed.
    585  * Return bytes sent otherwise  */
    586 ssize_t xsendto(int s, const  void *buf, size_t len, const struct sockaddr *to,
    587                 socklen_t tolen)
    588 {
    589     ssize_t ret = sendto(s, buf, len, 0, to, tolen);
    590     if (ret < 0) {
    591         if (ENABLE_FEATURE_CLEAN_UP)
    592             close(s);
    593         bb_perror_msg_and_die("sendto");
    594     }
    595     return ret;
    596 }
    597 
    598 // xstat() - a stat() which dies on failure with meaningful error message
    599 void xstat(const char *name, struct stat *stat_buf)
    600 {
    601     if (stat(name, stat_buf))
    602         bb_perror_msg_and_die("can't stat '%s'", name);
    603 }
    604 
    605 // selinux_or_die() - die if SELinux is disabled.
    606 void selinux_or_die(void)
    607 {
    608 #if ENABLE_SELINUX
    609     int rc = is_selinux_enabled();
    610     if (rc == 0) {
    611         bb_error_msg_and_die("SELinux is disabled");
    612     } else if (rc < 0) {
    613         bb_error_msg_and_die("is_selinux_enabled() failed");
    614     }
    615 #else
    616     bb_error_msg_and_die("SELinux support is disabled");
    617 #endif
     216int FAST_FUNC bb_putchar_stderr(char ch)
     217{
     218    return write(STDERR_FILENO, &ch, 1);
     219}
     220
     221ssize_t FAST_FUNC full_write1_str(const char *str)
     222{
     223    return full_write(STDOUT_FILENO, str, strlen(str));
     224}
     225
     226ssize_t FAST_FUNC full_write2_str(const char *str)
     227{
     228    return full_write(STDERR_FILENO, str, strlen(str));
     229}
     230
     231static int wh_helper(int value, int def_val, const char *env_name, int *err)
     232{
     233    if (value == 0) {
     234        char *s = getenv(env_name);
     235        if (s) {
     236            value = atoi(s);
     237            /* If LINES/COLUMNS are set, pretent that there is
     238             * no error getting w/h, this prevents some ugly
     239             * cursor tricks by our callers */
     240            *err = 0;
     241        }
     242    }
     243    if (value <= 1 || value >= 30000)
     244        value = def_val;
     245    return value;
    618246}
    619247
    620248/* It is perfectly ok to pass in a NULL for either width or for
    621249 * height, in which case that value will not be set.  */
    622 int get_terminal_width_height(int fd, int *width, int *height)
    623 {
    624     struct winsize win = { 0, 0, 0, 0 };
    625     int ret = ioctl(fd, TIOCGWINSZ, &win);
    626 
    627     if (height) {
    628         if (!win.ws_row) {
    629             char *s = getenv("LINES");
    630             if (s) win.ws_row = atoi(s);
    631         }
    632         if (win.ws_row <= 1 || win.ws_row >= 30000)
    633             win.ws_row = 24;
    634         *height = (int) win.ws_row;
    635     }
    636 
    637     if (width) {
    638         if (!win.ws_col) {
    639             char *s = getenv("COLUMNS");
    640             if (s) win.ws_col = atoi(s);
    641         }
    642         if (win.ws_col <= 1 || win.ws_col >= 30000)
    643             win.ws_col = 80;
    644         *width = (int) win.ws_col;
    645     }
    646 
    647     return ret;
    648 }
    649 
    650 void ioctl_or_perror_and_die(int fd, int request, void *argp, const char *fmt,...)
    651 {
    652     va_list p;
    653 
    654     if (ioctl(fd, request, argp) < 0) {
    655         va_start(p, fmt);
    656         bb_verror_msg(fmt, p, strerror(errno));
    657         /* xfunc_die can actually longjmp, so be nice */
    658         va_end(p);
    659         xfunc_die();
    660     }
    661 }
    662 
    663 int ioctl_or_perror(int fd, int request, void *argp, const char *fmt,...)
    664 {
    665     va_list p;
    666     int ret = ioctl(fd, request, argp);
    667 
    668     if (ret < 0) {
    669         va_start(p, fmt);
    670         bb_verror_msg(fmt, p, strerror(errno));
    671         va_end(p);
    672     }
    673     return ret;
    674 }
    675 
    676 #if ENABLE_IOCTL_HEX2STR_ERROR
    677 int bb_ioctl_or_warn(int fd, int request, void *argp, const char *ioctl_name)
    678 {
    679     int ret;
    680 
    681     ret = ioctl(fd, request, argp);
    682     if (ret < 0)
    683         bb_perror_msg("%s", ioctl_name);
    684     return ret;
    685 }
    686 void bb_xioctl(int fd, int request, void *argp, const char *ioctl_name)
    687 {
    688     if (ioctl(fd, request, argp) < 0)
    689         bb_perror_msg_and_die("%s", ioctl_name);
    690 }
    691 #else
    692 int bb_ioctl_or_warn(int fd, int request, void *argp)
    693 {
    694     int ret;
    695 
    696     ret = ioctl(fd, request, argp);
    697     if (ret < 0)
    698         bb_perror_msg("ioctl %#x failed", request);
    699     return ret;
    700 }
    701 void bb_xioctl(int fd, int request, void *argp)
    702 {
    703     if (ioctl(fd, request, argp) < 0)
    704         bb_perror_msg_and_die("ioctl %#x failed", request);
    705 }
    706 #endif
     250int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height)
     251{
     252    struct winsize win;
     253    int err;
     254
     255    win.ws_row = 0;
     256    win.ws_col = 0;
     257    /* I've seen ioctl returning 0, but row/col is (still?) 0.
     258     * We treat that as an error too.  */
     259    err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0;
     260    if (height)
     261        *height = wh_helper(win.ws_row, 24, "LINES", &err);
     262    if (width)
     263        *width = wh_helper(win.ws_col, 80, "COLUMNS", &err);
     264    return err;
     265}
     266
     267int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
     268{
     269    return tcsetattr(STDIN_FILENO, TCSANOW, tp);
     270}
     271
     272pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options)
     273{
     274    pid_t r;
     275
     276    do
     277        r = waitpid(pid, wstat, options);
     278    while ((r == -1) && (errno == EINTR));
     279    return r;
     280}
     281
     282pid_t FAST_FUNC wait_any_nohang(int *wstat)
     283{
     284    return safe_waitpid(-1, wstat, WNOHANG);
     285}
     286
     287// Wait for the specified child PID to exit, returning child's error return.
     288int FAST_FUNC wait4pid(pid_t pid)
     289{
     290    int status;
     291
     292    if (pid <= 0) {
     293        /*errno = ECHILD; -- wrong. */
     294        /* we expect errno to be already set from failed [v]fork/exec */
     295        return -1;
     296    }
     297    if (safe_waitpid(pid, &status, 0) == -1)
     298        return -1;
     299    if (WIFEXITED(status))
     300        return WEXITSTATUS(status);
     301    if (WIFSIGNALED(status))
     302        return WTERMSIG(status) + 0x180;
     303    return 0;
     304}
  • branches/2.2.9/mindi-busybox/libbb/xgetcwd.c

    r1765 r2725  
    66 *
    77 * Special function for busybox written by Vladimir Oleynik <dzo@simtreas.ru>
    8 */
     8 *
     9 * Licensed under GPLv2, see file LICENSE in this source tree.
     10 */
    911
    1012#include "libbb.h"
    11 
    12 /* Amount to increase buffer size by in each try. */
    13 #define PATH_INCR 32
    1413
    1514/* Return the current directory, newly allocated, arbitrarily long.
     
    1817*/
    1918
    20 char *
     19char* FAST_FUNC
    2120xrealloc_getcwd_or_warn(char *cwd)
    2221{
     22#define PATH_INCR 64
     23
    2324    char *ret;
    2425    unsigned path_max;
    2526
    26     path_max = (unsigned) PATH_MAX;
    27     path_max += 2;                /* The getcwd docs say to do this. */
     27    path_max = 128; /* 128 + 64 should be enough for 99% of cases */
    2828
    29     if (cwd == NULL)
    30         cwd = xmalloc(path_max);
    31 
    32     while ((ret = getcwd(cwd, path_max)) == NULL && errno == ERANGE) {
     29    while (1) {
    3330        path_max += PATH_INCR;
    3431        cwd = xrealloc(cwd, path_max);
     32        ret = getcwd(cwd, path_max);
     33        if (ret == NULL) {
     34            if (errno == ERANGE)
     35                continue;
     36            free(cwd);
     37            bb_perror_msg("getcwd");
     38            return NULL;
     39        }
     40        cwd = xrealloc(cwd, strlen(cwd) + 1);
     41        return cwd;
    3542    }
    36 
    37     if (ret == NULL) {
    38         free(cwd);
    39         bb_perror_msg("getcwd");
    40         return NULL;
    41     }
    42 
    43     return cwd;
    4443}
  • branches/2.2.9/mindi-busybox/libbb/xgethostbyname.c

    r1765 r2725  
    55 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    10 //#include <netdb.h>
    119#include "libbb.h"
    1210
    13 struct hostent *xgethostbyname(const char *name)
     11struct hostent* FAST_FUNC xgethostbyname(const char *name)
    1412{
    1513    struct hostent *retval = gethostbyname(name);
  • branches/2.2.9/mindi-busybox/libbb/xreadlink.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  *  xreadlink.c - safe implementation of readlink.
    4  *  Returns a NULL on failure...
     3 * xreadlink.c - safe implementation of readlink.
     4 * Returns a NULL on failure...
     5 *
     6 * Licensed under GPLv2, see file LICENSE in this source tree.
    57 */
    68
     
    911/*
    1012 * NOTE: This function returns a malloced char* that you will have to free
    11  * yourself. You have been warned.
     13 * yourself.
    1214 */
    13 char *xmalloc_readlink(const char *path)
     15char* FAST_FUNC xmalloc_readlink(const char *path)
    1416{
    1517    enum { GROWBY = 80 }; /* how large we will grow strings by */
     
    1921
    2022    do {
    21         buf = xrealloc(buf, bufsize += GROWBY);
     23        bufsize += GROWBY;
     24        buf = xrealloc(buf, bufsize);
    2225        readsize = readlink(path, buf, bufsize);
    2326        if (readsize == -1) {
     
    3235}
    3336
    34 char *xmalloc_readlink_or_warn(const char *path)
     37/*
     38 * This routine is not the same as realpath(), which
     39 * canonicalizes the given path completely. This routine only
     40 * follows trailing symlinks until a real file is reached and
     41 * returns its name. If the path ends in a dangling link or if
     42 * the target doesn't exist, the path is returned in any case.
     43 * Intermediate symlinks in the path are not expanded -- only
     44 * those at the tail.
     45 * A malloced char* is returned, which must be freed by the caller.
     46 */
     47char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
     48{
     49    char *buf;
     50    char *lpc;
     51    char *linkpath;
     52    int bufsize;
     53    int looping = MAXSYMLINKS + 1;
     54
     55    buf = xstrdup(path);
     56    goto jump_in;
     57
     58    while (1) {
     59        linkpath = xmalloc_readlink(buf);
     60        if (!linkpath) {
     61            /* not a symlink, or doesn't exist */
     62            if (errno == EINVAL || errno == ENOENT)
     63                return buf;
     64            goto free_buf_ret_null;
     65        }
     66
     67        if (!--looping) {
     68            free(linkpath);
     69 free_buf_ret_null:
     70            free(buf);
     71            return NULL;
     72        }
     73
     74        if (*linkpath != '/') {
     75            bufsize += strlen(linkpath);
     76            buf = xrealloc(buf, bufsize);
     77            lpc = bb_get_last_path_component_strip(buf);
     78            strcpy(lpc, linkpath);
     79            free(linkpath);
     80        } else {
     81            free(buf);
     82            buf = linkpath;
     83 jump_in:
     84            bufsize = strlen(buf) + 1;
     85        }
     86    }
     87}
     88
     89char* FAST_FUNC xmalloc_readlink_or_warn(const char *path)
    3590{
    3691    char *buf = xmalloc_readlink(path);
    3792    if (!buf) {
    3893        /* EINVAL => "file: Invalid argument" => puzzled user */
    39         bb_error_msg("%s: cannot read link (not a symlink?)", path);
     94        const char *errmsg = "not a symlink";
     95        int err = errno;
     96        if (err != EINVAL)
     97            errmsg = strerror(err);
     98        bb_error_msg("%s: cannot read link: %s", path, errmsg);
    4099    }
    41100    return buf;
    42101}
    43102
    44 /* UNUSED */
    45 #if 0
    46 char *xmalloc_realpath(const char *path)
     103char* FAST_FUNC xmalloc_realpath(const char *path)
    47104{
    48105#if defined(__GLIBC__) && !defined(__UCLIBC__)
    49106    /* glibc provides a non-standard extension */
     107    /* new: POSIX.1-2008 specifies this behavior as well */
    50108    return realpath(path, NULL);
    51109#else
    52110    char buf[PATH_MAX+1];
    53111
    54     /* on error returns NULL (xstrdup(NULL) ==NULL) */
     112    /* on error returns NULL (xstrdup(NULL) == NULL) */
    55113    return xstrdup(realpath(path, buf));
    56114#endif
    57115}
    58 #endif
  • branches/2.2.9/mindi-busybox/libbb/xregcomp.c

    r1765 r2725  
    66 * If you wrote this, please acknowledge your work.
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
     
    1212#include "xregex.h"
    1313
    14 char* regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags)
     14char* FAST_FUNC regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags)
    1515{
    1616    int ret = regcomp(preg, regex, cflags);
     
    2424}
    2525
    26 void xregcomp(regex_t *preg, const char *regex, int cflags)
     26void FAST_FUNC xregcomp(regex_t *preg, const char *regex, int cflags)
    2727{
    2828    char *errmsg = regcomp_or_errmsg(preg, regex, cflags);
    2929    if (errmsg) {
    30         bb_error_msg_and_die("xregcomp: %s", errmsg);
     30        bb_error_msg_and_die("bad regex '%s': %s", regex, errmsg);
    3131    }
    3232}
Note: See TracChangeset for help on using the changeset viewer.