Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- 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 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 5 6 6 7 menu "Busybox Library Tuning" 8 9 7 10 8 11 config PASSWORD_MINLEN … … 14 17 15 18 config MD5_SIZE_VS_SPEED 16 int " MD5: Trade Bytes for Speed"19 int "MD5: Trade bytes for speed (0:fast, 3:slow)" 17 20 default 2 18 21 range 0 3 … … 29 32 config FEATURE_FAST_TOP 30 33 bool "Faster /proc scanning code (+100 bytes)" 31 default n34 default y 32 35 help 33 36 This option makes top (and ps) ~20% faster (or 20% less CPU hungry), … … 42 45 instead of IP/mask pairs in route command. 43 46 47 config 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 44 58 config FEATURE_EDITING 45 59 bool "Command line editing" 46 default n60 default y 47 61 help 48 62 Enable line editing (mainly for shell command line). … … 58 72 benefits from smaller stack usage. 59 73 60 config FEATURE_EDITING_FANCY_KEYS61 bool "Additional editing keys"62 default n63 depends on FEATURE_EDITING64 help65 Enable additonal editing keys (Ctrl-E, Ctrl-U etc).66 Arrow keys, Home/End/Delete and Ctrl-W work even without this option.67 68 74 config FEATURE_EDITING_VI 69 75 bool "vi-style line editing commands" … … 71 77 depends on FEATURE_EDITING 72 78 help 73 Enable vi-style line editing. 79 Enable vi-style line editing. In shells, this mode can be 74 80 turned on and off with "set -o vi" and "set +o vi". 75 81 … … 77 83 int "History size" 78 84 range 0 99999 79 default 1585 default 255 80 86 depends on FEATURE_EDITING 81 87 help … … 84 90 config FEATURE_EDITING_SAVEHISTORY 85 91 bool "History saving" 86 default n87 depends on ASH &&FEATURE_EDITING92 default y 93 depends on FEATURE_EDITING 88 94 help 89 Enable history saving in ash shell.95 Enable history saving in shells. 90 96 91 97 config FEATURE_TAB_COMPLETION 92 98 bool "Tab completion" 93 default n99 default y 94 100 depends on FEATURE_EDITING 95 101 help … … 105 111 config FEATURE_EDITING_FANCY_PROMPT 106 112 bool "Fancy shell prompts" 107 default n113 default y 108 114 depends on FEATURE_EDITING 109 115 help … … 111 117 \$ and escape codes. 112 118 119 config 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 131 config 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 141 config 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 155 config 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 113 165 config MONOTONIC_SYSCALL 114 166 bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" 115 default y 167 default n 168 depends on PLATFORM_LINUX 116 169 help 117 170 Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring … … 128 181 (e.g. VT_DISALLOCATE rather than 0x5608). If disabled this 129 182 saves about 1400 bytes. 183 184 config FEATURE_HWIB 185 bool "Support infiniband HW" 186 default y 187 help 188 Support for printing infiniband addresses in 189 network applets. 190 130 191 endmenu -
branches/2.2.9/mindi-busybox/libbb/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 4 5 # 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 8 libbb/appletlib.o: include/usage_compressed.h 6 9 7 10 lib-y:= 8 11 12 13 14 lib-y += appletlib.o 9 15 lib-y += ask_confirmation.o 10 16 lib-y += bb_askpass.o 11 17 lib-y += bb_basename.o 18 lib-y += bb_bswap_64.o 12 19 lib-y += bb_do_delay.o 13 20 lib-y += bb_pwd.o 21 lib-y += bb_qsort.o 22 #lib-y += bb_strtod.o 14 23 lib-y += bb_strtonum.o 15 24 lib-y += change_identity.o … … 26 35 lib-y += device_open.o 27 36 lib-y += dump.o 28 lib-y += error_msg.o29 lib-y += error_msg_and_die.o30 37 lib-y += execable.o 31 38 lib-y += fclose_nonstdin.o … … 39 46 lib-y += get_line_from_file.o 40 47 lib-y += getopt32.o 48 lib-y += getpty.o 49 lib-y += get_volsize.o 41 50 lib-y += herror_msg.o 42 lib-y += herror_msg_and_die.o43 51 lib-y += human_readable.o 44 52 lib-y += inet_common.o … … 48 56 lib-y += kernel_version.o 49 57 lib-y += last_char_is.o 50 lib-y += lineedit.o 58 lib-y += lineedit.o lineedit_ptr_hack.o 51 59 lib-y += llist.o 52 60 lib-y += login.o … … 54 62 lib-y += makedev.o 55 63 lib-y += match_fstype.o 56 lib-y += md5.o 64 lib-y += hash_md5_sha.o 65 # Alternative (disabled) MD5 implementation 66 #lib-y += hash_md5prime.o 57 67 lib-y += messages.o 58 68 lib-y += mode_string.o 59 lib-y += mtab_file.o60 69 lib-y += obscure.o 61 70 lib-y += parse_mode.o 71 lib-y += parse_config.o 62 72 lib-y += perror_msg.o 63 lib-y += perror_msg_and_die.o64 73 lib-y += perror_nomsg.o 65 74 lib-y += perror_nomsg_and_die.o 66 75 lib-y += pidfile.o 76 lib-y += platform.o 77 lib-y += printable.o 78 lib-y += printable_string.o 79 lib-y += print_flags.o 67 80 lib-y += process_escape_sequence.o 68 81 lib-y += procps.o 82 lib-y += progress.o 83 lib-y += ptr_to_globals.o 69 84 lib-y += read.o 85 lib-y += read_printf.o 86 lib-y += read_key.o 70 87 lib-y += recursive_action.o 71 88 lib-y += remove_file.o 72 lib-y += restricted_shell.o73 89 lib-y += run_shell.o 90 lib-y += safe_gethostname.o 91 lib-y += safe_poll.o 74 92 lib-y += safe_strncpy.o 75 93 lib-y += safe_write.o 76 94 lib-y += setup_environment.o 77 lib-y += s ha1.o95 lib-y += signals.o 78 96 lib-y += simplify_path.o 97 lib-y += single_argv.o 79 98 lib-y += skip_whitespace.o 80 99 lib-y += speed_table.o 81 100 lib-y += str_tolower.o 101 lib-y += strrstr.o 82 102 lib-y += time.o 83 103 lib-y += trim.o … … 91 111 lib-y += wfopen.o 92 112 lib-y += wfopen_input.o 113 lib-y += write.o 93 114 lib-y += xatonum.o 94 115 lib-y += xconnect.o 95 116 lib-y += xfuncs.o 117 lib-y += xfuncs_printf.o 118 lib-y += xfunc_die.o 96 119 lib-y += xgetcwd.o 97 120 lib-y += xgethostbyname.o 98 121 lib-y += xreadlink.o 122 lib-y += xrealloc_vector.o 99 123 100 # conditionally compiled objects: 124 lib-$(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) 128 lib-$(CONFIG_SELINUX) += selinux_common.o 129 lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o 130 lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o 131 lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 132 133 lib-$(CONFIG_LOSETUP) += loop.o 101 134 lib-$(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 136 lib-$(CONFIG_ADDGROUP) += update_passwd.o 137 lib-$(CONFIG_ADDUSER) += update_passwd.o 138 lib-$(CONFIG_DELGROUP) += update_passwd.o 139 lib-$(CONFIG_DELUSER) += update_passwd.o 140 141 lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o 142 lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o 143 lib-$(CONFIG_CRYPTPW) += pw_encrypt.o 107 144 lib-$(CONFIG_SULOGIN) += pw_encrypt.o 145 lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o 146 lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o 147 lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o 108 148 lib-$(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 112 150 lib-$(CONFIG_DF) += find_mount_point.o 113 151 lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o 114 lib-$(CONFIG_SELINUX) += selinux_common.o 152 lib-$(CONFIG_MKFS_EXT2) += find_mount_point.o 153 lib-$(CONFIG_MKFS_REISER) += find_mount_point.o 154 lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o 155 lib-$(CONFIG_MOUNT) += find_mount_point.o 156 157 lib-$(CONFIG_HWCLOCK) += rtc.o 158 lib-$(CONFIG_RTCWAKE) += rtc.o 159 160 lib-$(CONFIG_IOSTAT) += get_cpu_count.o 161 lib-$(CONFIG_MPSTAT) += get_cpu_count.o 162 lib-$(CONFIG_POWERTOP) += get_cpu_count.o 115 163 116 164 # We shouldn't build xregcomp.c if we don't need it - this ensures we don't … … 124 172 lib-$(CONFIG_MDEV) += xregcomp.o 125 173 lib-$(CONFIG_LESS) += xregcomp.o 174 lib-$(CONFIG_PGREP) += xregcomp.o 175 lib-$(CONFIG_PKILL) += xregcomp.o 126 176 lib-$(CONFIG_DEVFSD) += xregcomp.o 127 177 lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o -
branches/2.2.9/mindi-busybox/libbb/README
r821 r2725 9 9 Erik Andersen 10 10 <andersen@codepoet.org> 11 -
branches/2.2.9/mindi-busybox/libbb/ask_confirmation.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 11 11 * return 1. Otherwise return 0. 12 12 */ 13 14 13 #include "libbb.h" 15 14 16 int bb_ask_confirmation(void)15 int FAST_FUNC bb_ask_confirmation(void) 17 16 { 18 int retval = 0; 19 int first = 1; 17 char first = 0; 20 18 int c; 21 19 22 20 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; 30 23 } 31 24 } 32 25 33 return retval;26 return first == 'y'; 34 27 } -
branches/2.2.9/mindi-busybox/libbb/bb_askpass.c
r1765 r2725 6 6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 7 7 * 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. 9 9 */ 10 11 #include <termios.h>12 10 13 11 #include "libbb.h" 14 12 15 13 /* do nothing signal handler */ 16 static void askpass_timeout(int ATTRIBUTE_UNUSEDignore)14 static void askpass_timeout(int UNUSED_PARAM ignore) 17 15 { 18 16 } 19 17 20 char *bb_askpass(int timeout, const char * prompt) 18 char* FAST_FUNC bb_ask_stdin(const char *prompt) 19 { 20 return bb_ask(STDIN_FILENO, 0, prompt); 21 } 22 char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) 21 23 { 22 24 /* Was static char[BIGNUM] */ … … 26 28 char *ret; 27 29 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(); 30 55 31 56 if (!passwd) 32 57 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 } 65 74 } 66 75 … … 68 77 alarm(0); 69 78 } 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(); 74 83 return ret; 75 84 } -
branches/2.2.9/mindi-busybox/libbb/bb_basename.c
r1765 r2725 3 3 * Utility routines. 4 4 * 5 * Copyright (C) 2007 Den is Vlasenko5 * Copyright (C) 2007 Denys Vlasenko 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 12 const char *bb_basename(const char *name)12 const char* FAST_FUNC bb_basename(const char *name) 13 13 { 14 14 const char *cp = strrchr(name, '/'); -
branches/2.2.9/mindi-busybox/libbb/bb_do_delay.c
r1765 r2725 5 5 * Copyright (C) 2005 by Tito Ragusa <tito-wolit@tiscali.it> 6 6 * 7 * Licensed under the GPL v2, see the file LICENSE in this tarball.7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 12 void bb_do_delay(int seconds)12 void FAST_FUNC bb_do_delay(int seconds) 13 13 { 14 14 time_t start, now; 15 15 16 time(&start); 17 now = start; 18 while (difftime(now, start) < seconds) { 16 start = time(NULL); 17 do { 19 18 sleep(seconds); 20 time(&now);21 } 19 now = time(NULL); 20 } while ((now - start) < seconds); 22 21 } -
branches/2.2.9/mindi-busybox/libbb/bb_pwd.c
r1765 r2725 4 4 * 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it> 6 7 * 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. 8 9 */ 9 10 10 11 #include "libbb.h" 11 12 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 */ 13 17 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) 18 struct passwd* FAST_FUNC xgetpwnam(const char *name) 28 19 { 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; 39 24 } 40 25 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) 26 struct group* FAST_FUNC xgetgrnam(const char *name) 49 27 { 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; 64 32 } 65 33 66 /* returns a gid given a group name */ 67 long xgroup2gid(const char *name) 34 35 struct 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 43 struct 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 51 char* FAST_FUNC xuid2uname(uid_t uid) 52 { 53 struct passwd *pw = xgetpwuid(uid); 54 return pw->pw_name; 55 } 56 57 char* FAST_FUNC xgid2group(gid_t gid) 58 { 59 struct group *gr = xgetgrgid(gid); 60 return gr->gr_name; 61 } 62 63 char* FAST_FUNC uid2uname(uid_t uid) 64 { 65 struct passwd *pw = getpwuid(uid); 66 return (pw) ? pw->pw_name : NULL; 67 } 68 69 char* FAST_FUNC gid2group(gid_t gid) 70 { 71 struct group *gr = getgrgid(gid); 72 return (gr) ? gr->gr_name : NULL; 73 } 74 75 char* FAST_FUNC uid2uname_utoa(long uid) 76 { 77 char *name = uid2uname(uid); 78 return (name) ? name : utoa(uid); 79 } 80 81 char* FAST_FUNC gid2group_utoa(long gid) 82 { 83 char *name = gid2group(gid); 84 return (name) ? name : utoa(gid); 85 } 86 87 long FAST_FUNC xuname2uid(const char *name) 88 { 89 struct passwd *myuser; 90 91 myuser = xgetpwnam(name); 92 return myuser->pw_uid; 93 } 94 95 long FAST_FUNC xgroup2gid(const char *name) 68 96 { 69 97 struct group *mygroup; 70 98 71 mygroup = getgrnam(name); 72 if (mygroup == NULL) 73 bb_error_msg_and_die("unknown group name: %s", name); 74 99 mygroup = xgetgrnam(name); 75 100 return mygroup->gr_gid; 76 101 } 77 102 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 *)) 103 unsigned long FAST_FUNC get_ug_id(const char *s, 104 long FAST_FUNC (*xname2id)(const char *)) 92 105 { 93 106 unsigned long r; -
branches/2.2.9/mindi-busybox/libbb/bb_strtonum.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 11 11 12 12 /* On exit: errno = 0 only if there was non-empty, '\0' terminated value 13 * errno = EINVAL if value was not '\0' terminated, but other vise ok13 * errno = EINVAL if value was not '\0' terminated, but otherwise ok 14 14 * Return value is still valid, caller should just check whether end[0] 15 15 * is a valid terminating char for particular case. OTOH, if caller … … 19 19 * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok ) 20 20 * 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); 21 31 */ 22 32 … … 30 40 { 31 41 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();38 42 39 43 /* errno is already set to ERANGE by strtoXXX if value overflowed */ … … 49 53 50 54 51 unsigned long long bb_strtoull(const char *arg, char **endp, int base)55 unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base) 52 56 { 53 57 unsigned long long v; … … 64 68 } 65 69 66 long long bb_strtoll(const char *arg, char **endp, int base)70 long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base) 67 71 { 68 72 unsigned long long v; 69 73 char *endptr; 70 74 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 72 81 errno = 0; 73 82 v = strtoll(arg, &endptr, base); … … 76 85 77 86 #if ULONG_MAX != ULLONG_MAX 78 unsigned long bb_strtoul(const char *arg, char **endp, int base)87 unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base) 79 88 { 80 89 unsigned long v; … … 87 96 } 88 97 89 long bb_strtol(const char *arg, char **endp, int base)98 long FAST_FUNC bb_strtol(const char *arg, char **endp, int base) 90 99 { 91 100 long v; 92 101 char *endptr; 93 102 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 95 106 errno = 0; 96 107 v = strtol(arg, &endptr, base); … … 100 111 101 112 #if UINT_MAX != ULONG_MAX 102 unsigned bb_strtou(const char *arg, char **endp, int base)113 unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base) 103 114 { 104 115 unsigned long v; … … 112 123 } 113 124 114 int bb_strtoi(const char *arg, char **endp, int base)125 int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base) 115 126 { 116 127 long v; 117 128 char *endptr; 118 129 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 120 133 errno = 0; 121 134 v = strtol(arg, &endptr, base); … … 125 138 } 126 139 #endif 127 128 /* Floating point */129 130 #if 0131 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 31 31 #include "libbb.h" 32 32 33 34 33 /* Become the user and group(s) specified by PW. */ 35 const char *change_identity_e2str(const struct passwd *pw)34 void FAST_FUNC change_identity(const struct passwd *pw) 36 35 { 37 36 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 */ 40 39 xsetgid(pw->pw_gid); 41 40 xsetuid(pw->pw_uid); 42 return NULL;43 41 } 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 6 6 * If you wrote this, please acknowledge your work. 7 7 * 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. 9 9 */ 10 10 11 11 #include "libbb.h" 12 12 13 void chomp(char *s)13 void FAST_FUNC chomp(char *s) 14 14 { 15 15 char *lc = last_char_is(s, '\n'); -
branches/2.2.9/mindi-busybox/libbb/compare_string_array.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 4 */ 5 5 … … 8 8 /* returns the array index of the string */ 9 9 /* (index of first match is returned, or -1) */ 10 int index_in_str_array(const char *const string_array[], const char *key)10 int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key) 11 11 { 12 12 int i; … … 20 20 } 21 21 22 int index_in_strings(const char *strings, const char *key)22 int FAST_FUNC index_in_strings(const char *strings, const char *key) 23 23 { 24 24 int idx = 0; 25 25 26 while ( strings[0]) {26 while (*strings) { 27 27 if (strcmp(strings, key) == 0) { 28 28 return idx; … … 37 37 /* (index of first match is returned, or -1) */ 38 38 #ifdef UNUSED 39 int index_in_substr_array(const char *const string_array[], const char *key)39 int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key) 40 40 { 41 41 int i; … … 52 52 #endif 53 53 54 int index_in_substrings(const char *strings, const char *key)54 int FAST_FUNC index_in_substrings(const char *strings, const char *key) 55 55 { 56 int len = strlen(key); 56 int matched_idx = -1; 57 const int len = strlen(key); 57 58 58 59 if (len) { 59 60 int idx = 0; 60 while ( strings[0]) {61 while (*strings) { 61 62 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; 63 68 } 64 69 strings += strlen(strings) + 1; /* skip NUL */ … … 66 71 } 67 72 } 68 return -1;73 return matched_idx; 69 74 } 75 76 const 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. */ 87 smallint 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 6 6 * If you wrote this, please acknowledge your work. 7 7 * 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. 9 9 */ 10 10 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 */ 14 16 15 17 #include "libbb.h" 16 18 17 char *concat_path_file(const char *path, const char *filename)19 char* FAST_FUNC concat_path_file(const char *path, const char *filename) 18 20 { 19 21 char *lc; -
branches/2.2.9/mindi-busybox/libbb/concat_subpath_file.c
r1765 r2725 5 5 * Copyright (C) (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 6 6 * 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. 8 8 */ 9 9 … … 16 16 #include "libbb.h" 17 17 18 char *concat_subpath_file(const char *path, const char *f)18 char* FAST_FUNC concat_subpath_file(const char *path, const char *f) 19 19 { 20 20 if (f && DOT_OR_DOTDOT(f)) -
branches/2.2.9/mindi-busybox/libbb/copy_file.c
r1765 r2725 6 6 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp> 7 7 * 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. 10 9 */ 11 12 10 #include "libbb.h" 13 11 12 // FEATURE_NON_POSIX_CP: 13 // 14 14 // POSIX: if exists and -i, ask (w/o -i assume yes). 15 15 // Then open w/o EXCL (yes, not unlink!). 16 16 // If open still fails and -f, try unlink, then try open again. 17 17 // Result: a mess: 18 // If dest is a softlink, we overwrite softlink'sdestination!18 // If dest is a (sym)link, we overwrite link destination! 19 19 // (or fail, if it points to dir/nonexistent location/etc). 20 20 // This is strange, but POSIX-correct. 21 21 // 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 */ 30 26 static int ask_and_unlink(const char *dest, int flags) 31 27 { 32 #if DO_POSIX_CP 28 int e = errno; 29 30 #if !ENABLE_FEATURE_NON_POSIX_CP 33 31 if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) { 34 / / Either it exists, or the *path* doesnt exist35 bb_perror_msg("can not create '%s'", dest);32 /* Either it exists, or the *path* doesnt exist */ 33 bb_perror_msg("can't create '%s'", dest); 36 34 return -1; 37 35 } 38 36 #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? */ 43 45 if (flags & FILEUTILS_INTERACTIVE) { 44 46 // We would not do POSIX insanity. -i asks, … … 48 50 fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest); 49 51 if (!bb_ask_confirmation()) 50 return 0; / / not allowed to overwrite52 return 0; /* not allowed to overwrite */ 51 53 } 52 54 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) */ 57 68 } 58 69 … … 62 73 * (failures to preserve mode/owner/times are not reported in exit code) 63 74 */ 64 int copy_file(const char *source, const char *dest, int flags)75 int FAST_FUNC copy_file(const char *source, const char *dest, int flags) 65 76 { 66 77 /* This is a recursive function, try to minimize stack usage */ … … 72 83 signed char ovr; 73 84 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)) 75 87 76 88 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... */ 79 91 if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) 80 92 goto make_links; 81 bb_perror_msg("can not stat '%s'", source);93 bb_perror_msg("can't stat '%s'", source); 82 94 return -1; 83 95 } … … 85 97 if (lstat(dest, &dest_stat) < 0) { 86 98 if (errno != ENOENT) { 87 bb_perror_msg("can not stat '%s'", dest);99 bb_perror_msg("can't stat '%s'", dest); 88 100 return -1; 89 101 } … … 103 115 if (lgetfilecon(source, &con) >= 0) { 104 116 if (setfscreatecon(con) < 0) { 105 bb_perror_msg("can not set setfscreatecon %s", con);117 bb_perror_msg("can't set setfscreatecon %s", con); 106 118 freecon(con); 107 119 return -1; … … 110 122 setfscreatecon_or_die(NULL); 111 123 } else { 112 bb_perror_msg("can not lgetfilecon %s", source);124 bb_perror_msg("can't lgetfilecon %s", source); 113 125 return -1; 114 126 } … … 155 167 if (mkdir(dest, mode) < 0) { 156 168 umask(saved_umask); 157 bb_perror_msg("can not create directory '%s'", dest);169 bb_perror_msg("can't create directory '%s'", dest); 158 170 return -1; 159 171 } … … 161 173 /* need stat info for add_to_ino_dev_hashtable */ 162 174 if (lstat(dest, &dest_stat) < 0) { 163 bb_perror_msg("can not stat '%s'", dest);175 bb_perror_msg("can't stat '%s'", dest); 164 176 return -1; 165 177 } … … 183 195 continue; 184 196 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) 186 198 retval = -1; 187 199 free(new_source); … … 193 205 && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 194 206 ) { 195 bb_perror_msg("can not preserve %s of '%s'", "permissions", dest);207 bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); 196 208 /* retval = -1; - WRONG! copy *WAS* made */ 197 209 } … … 202 214 int (*lf)(const char *oldpath, const char *newpath); 203 215 make_links: 204 / /Hmm... maybe205 //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...) */ 207 219 lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; 208 220 if (lf(source, dest) < 0) { … … 211 223 return ovr; 212 224 if (lf(source, dest) < 0) { 213 bb_perror_msg("can not create link '%s'", dest);225 bb_perror_msg("can't create link '%s'", dest); 214 226 return -1; 215 227 } 216 228 } 217 229 /* _Not_ jumping to preserve_mode_ugid_time: 218 * hard/softlinks don't have those */230 * (sym)links don't have those */ 219 231 return 0; 220 232 } 221 233 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: */ 224 240 /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ 225 241 ) { 226 242 int src_fd; 227 243 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 } 228 250 229 251 if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { … … 236 258 return ovr; 237 259 if (link(link_target, dest) < 0) { 238 bb_perror_msg("can not create link '%s'", dest);260 bb_perror_msg("can't create link '%s'", dest); 239 261 return -1; 240 262 } … … 249 271 return -1; 250 272 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 } 263 284 if (dst_fd == -1) { 264 285 ovr = ask_and_unlink(dest, flags); … … 268 289 } 269 290 /* 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); 271 292 if (dst_fd < 0) { 272 293 close(src_fd); … … 276 297 277 298 #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)) 280 300 && is_selinux_enabled() > 0 281 301 ) { … … 297 317 if (bb_copyfd_eof(src_fd, dst_fd) == -1) 298 318 retval = -1; 299 /* Ok, writing side I can understand... */319 /* Careful with writing... */ 300 320 if (close(dst_fd) < 0) { 301 bb_perror_msg(" cannot close'%s'", dest);321 bb_perror_msg("error writing to '%s'", dest); 302 322 retval = -1; 303 323 } 304 324 /* ...but read size is already checked by bb_copyfd_eof */ 305 325 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; 306 330 goto preserve_mode_ugid_time; 307 331 } 332 dont_cat: 308 333 309 334 /* Source is a symlink or a special file */ … … 321 346 free(lpath); 322 347 if (r < 0) { 323 bb_perror_msg("can not create symlink '%s'", dest);348 bb_perror_msg("can't create symlink '%s'", dest); 324 349 return -1; 325 350 } 326 351 if (flags & FILEUTILS_PRESERVE_STATUS) 327 352 if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) 328 bb_perror_msg("can not preserve %s of '%s'", "ownership", dest);353 bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); 329 354 } 330 355 /* _Not_ jumping to preserve_mode_ugid_time: … … 336 361 ) { 337 362 if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { 338 bb_perror_msg("can not create '%s'", dest);363 bb_perror_msg("can't create '%s'", dest); 339 364 return -1; 340 365 } … … 350 375 /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */ 351 376 ) { 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; 356 381 /* BTW, utimes sets usec-precision time - just FYI */ 357 if (utime (dest, ×) < 0)358 bb_perror_msg("can not preserve %s of '%s'", "times", dest);382 if (utimes(dest, times) < 0) 383 bb_perror_msg("can't preserve %s of '%s'", "times", dest); 359 384 if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { 360 385 source_stat.st_mode &= ~(S_ISUID | S_ISGID); 361 bb_perror_msg("can not preserve %s of '%s'", "ownership", dest);386 bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); 362 387 } 363 388 if (chmod(dest, source_stat.st_mode) < 0) 364 bb_perror_msg("can not preserve %s of '%s'", "permissions", dest);389 bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); 365 390 } 366 391 -
branches/2.2.9/mindi-busybox/libbb/copyfd.c
r1765 r2725 5 5 * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 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 */ 19 16 static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) 20 17 { 21 18 int status = -1; 22 19 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 24 50 25 51 if (src_fd < 0) … … 27 53 28 54 if (!size) { 29 size = BUFSIZ;55 size = buffer_size; 30 56 status = 1; /* copy until eof */ 31 57 } … … 34 60 ssize_t rd; 35 61 36 rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ: size);62 rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size); 37 63 38 64 if (!rd) { /* eof - all done */ … … 48 74 ssize_t wr = full_write(dst_fd, buffer, rd); 49 75 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; 52 81 } 53 82 } … … 63 92 } 64 93 out: 94 95 #if CONFIG_FEATURE_COPYBUF_KB > 4 96 if (buffer_size != 4 * 1024) 97 munmap(buffer, buffer_size); 98 #endif 65 99 return status ? -1 : total; 66 100 } … … 68 102 69 103 #if 0 70 void complain_copyfd_and_die(off_t sz)104 void FAST_FUNC complain_copyfd_and_die(off_t sz) 71 105 { 72 106 if (sz != -1) … … 77 111 #endif 78 112 79 off_t bb_copyfd_size(int fd1, int fd2, off_t size)113 off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size) 80 114 { 81 115 if (size) { … … 85 119 } 86 120 87 void bb_copyfd_exact_size(int fd1, int fd2, off_t size)121 void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) 88 122 { 89 123 off_t sz = bb_copyfd_size(fd1, fd2, size); 90 if (sz == size)124 if (sz == (size >= 0 ? size : -size)) 91 125 return; 92 126 if (sz != -1) … … 96 130 } 97 131 98 off_t bb_copyfd_eof(int fd1, int fd2)132 off_t FAST_FUNC bb_copyfd_eof(int fd1, int fd2) 99 133 { 100 134 return bb_full_fd_action(fd1, fd2, 0); -
branches/2.2.9/mindi-busybox/libbb/correct_password.c
r1765 r2725 37 37 * NULL pw means "just fake it for login with bad username" */ 38 38 39 int correct_password(const struct passwd *pw)39 int FAST_FUNC correct_password(const struct passwd *pw) 40 40 { 41 41 char *unencrypted, *encrypted; 42 42 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 43 49 44 50 /* fake salt. crypt() can choke otherwise. */ … … 51 57 #if ENABLE_FEATURE_SHADOWPASSWDS 52 58 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; 58 64 } 59 65 #endif … … 63 69 64 70 fake_it: 65 unencrypted = bb_ask pass(0,"Password: ");71 unencrypted = bb_ask_stdin("Password: "); 66 72 if (!unencrypted) { 67 73 return 0; 68 74 } 69 encrypted = crypt(unencrypted, correct); 75 encrypted = pw_encrypt(unencrypted, correct, 1); 76 r = (strcmp(encrypted, correct) == 0); 77 free(encrypted); 70 78 memset(unencrypted, 0, strlen(unencrypted)); 71 return strcmp(encrypted, correct) == 0;79 return r; 72 80 } -
branches/2.2.9/mindi-busybox/libbb/crc32.c
r1765 r2725 13 13 * endian = 1: big-endian 14 14 * endian = 0: little-endian 15 * 16 * Licensed under GPLv2, see file LICENSE in this source tree. 15 17 */ 16 18 17 19 #include "libbb.h" 18 20 19 uint32_t *crc32_filltable(uint32_t *crc_table, int endian) 21 uint32_t *global_crc32_table; 22 23 uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) 20 24 { 21 25 uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; … … 39 43 return crc_table - 256; 40 44 } 45 46 uint32_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 57 uint32_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 3 3 * Utility routines. 4 4 * 5 * create raw socket for icmp (IPv6 version) protocol test permission5 * create raw socket for icmp (IPv6 version) protocol 6 6 * and drop root privileges if running setuid 7 7 * 8 * Licensed under GPLv2, see file LICENSE in this source tree. 8 9 */ 9 10 10 //#include <sys/types.h>11 //#include <netdb.h>12 //#include <sys/socket.h>13 11 #include "libbb.h" 14 12 15 13 #if ENABLE_FEATURE_IPV6 16 int create_icmp6_socket(void)14 int FAST_FUNC create_icmp6_socket(void) 17 15 { 16 int sock; 17 #if 0 18 18 struct protoent *proto; 19 int sock;20 21 19 proto = getprotobyname("ipv6-icmp"); 22 20 /* if getprotobyname failed, just silently force … … 24 22 sock = socket(AF_INET6, SOCK_RAW, 25 23 (proto ? proto->p_proto : IPPROTO_ICMPV6)); 24 #else 25 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 26 #endif 26 27 if (sock < 0) { 27 28 if (errno == EPERM) -
branches/2.2.9/mindi-busybox/libbb/create_icmp_socket.c
r1765 r2725 3 3 * Utility routines. 4 4 * 5 * create raw socket for icmp protocol test permission5 * create raw socket for icmp protocol 6 6 * and drop root privileges if running setuid 7 7 * 8 * Licensed under GPLv2, see file LICENSE in this source tree. 8 9 */ 9 10 10 //#include <sys/types.h>11 //#include <netdb.h>12 //#include <sys/socket.h>13 11 #include "libbb.h" 14 12 15 int create_icmp_socket(void)13 int FAST_FUNC create_icmp_socket(void) 16 14 { 15 int sock; 16 #if 0 17 17 struct protoent *proto; 18 int sock;19 20 18 proto = getprotobyname("icmp"); 21 19 /* if getprotobyname failed, just silently force … … 23 21 sock = socket(AF_INET, SOCK_RAW, 24 22 (proto ? proto->p_proto : 1)); /* 1 == ICMP */ 23 #else 24 sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */ 25 #endif 25 26 if (sock < 0) { 26 27 if (errno == EPERM) -
branches/2.2.9/mindi-busybox/libbb/default_error_retval.c
r1765 r2725 3 3 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 4 4 * 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. 6 6 */ 7 7 … … 16 16 #include "libbb.h" 17 17 18 int xfunc_error_retval = EXIT_FAILURE;18 uint8_t xfunc_error_retval = EXIT_FAILURE; -
branches/2.2.9/mindi-busybox/libbb/device_open.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 11 11 12 12 /* try to open up the specified device */ 13 int device_open(const char *device, int mode)13 int FAST_FUNC device_open(const char *device, int mode) 14 14 { 15 int m, f, fd = -1;15 int m, f, fd; 16 16 17 17 m = mode | O_NONBLOCK; … … 19 19 /* Retry up to 5 times */ 20 20 /* 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) 23 24 break; 25 } 24 26 if (fd < 0) 25 27 return fd; -
branches/2.2.9/mindi-busybox/libbb/dump.c
r1765 r2725 5 5 * 6 6 * Copyright (c) 1989 7 * 7 * The Regents of the University of California. All rights reserved. 8 8 * 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. 10 10 * 11 11 * Original copyright notice is retained at the end of this file. … … 15 15 #include "dump.h" 16 16 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 29 17 static const char index_str[] ALIGN1 = ".#-+ 0123456789"; 30 18 … … 34 22 static const char lcc[] ALIGN1 = "diouxX"; 35 23 36 int bb_dump_size(FS * fs) 24 25 typedef 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 43 dumper_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 53 static NOINLINE int bb_dump_size(FS *fs) 37 54 { 38 55 FU *fu; … … 52 69 continue; 53 70 /* 54 * bb_dump_skip any special chars -- save precision in71 * skip any special chars -- save precision in 55 72 * case it's a %s format. 56 73 */ … … 58 75 if (*fmt == '.' && isdigit(*++fmt)) { 59 76 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) { 63 82 if (*fmt == 's') { 64 83 bcnt += prec; … … 78 97 } 79 98 80 static void rewrite(FS *fs)99 static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) 81 100 { 82 101 enum { NOTOKAY, USEBCNT, USEPREC } sokay; … … 95 114 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 96 115 /* 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*/ 98 117 pr = xzalloc(sizeof(PR)); 99 118 if (!fu->nextpr) 100 119 fu->nextpr = pr; 101 120 /* ignore nextpr -- its unused inside the loop and is 102 * uninitialized 1st time thr u.121 * uninitialized 1st time through. 103 122 */ 104 123 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; 107 127 108 128 /* only text in the string */ … … 119 139 if (fu->bcnt) { 120 140 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; 123 144 } 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; 126 148 if (*p1 == '.' && isdigit(*++p1)) { 127 149 sokay = USEPREC; 128 150 prec = atoi(p1); 129 while (isdigit(*++p1)); 151 while (isdigit(*++p1)) 152 continue; 130 153 } else 131 154 sokay = NOTOKAY; 132 155 } 133 156 134 p2 = p1 + 1; 157 p2 = p1 + 1; /* set end pointer */ 135 158 136 159 /* … … 139 162 * pbb_dump_adding for end of data. 140 163 */ 141 142 164 if (*p1 == 'c') { 143 165 pr->flags = F_CHAR; 144 166 DO_BYTE_COUNT_1: 145 167 byte_count_str = "\001"; 146 168 DO_BYTE_COUNT: 147 169 if (fu->bcnt) { 148 170 do { … … 160 182 ++p2; 161 183 ++p1; 162 184 DO_INT_CONV: 163 185 { 164 186 const char *e; 165 if (!(e = strchr(lcc, *p1))) { 187 e = strchr(lcc, *p1); 188 if (!e) { 166 189 goto DO_BAD_CONV_CHAR; 167 190 } … … 186 209 } else if (sokay == USEPREC) { 187 210 pr->bcnt = prec; 188 } else { 211 } else { /* NOTOKAY */ 189 212 bb_error_msg_and_die("%%s requires a precision or a byte count"); 190 213 } … … 193 216 switch (p1[1]) { 194 217 case 'A': 195 endfu = fu;218 dumper->endfu = fu; 196 219 fu->flags |= F_IGNORE; 197 220 /* FALLTHROUGH */ … … 220 243 } 221 244 } else { 222 245 DO_BAD_CONV_CHAR: 223 246 bb_error_msg_and_die("bad conversion character %%%s", p1); 224 247 } … … 232 255 pr->fmt = xstrdup(fmtp); 233 256 *p2 = savech; 234 pr->cchar = pr->fmt + (p1 - fmtp); 257 //Too early! xrealloc can move pr->fmt! 258 //pr->cchar = pr->fmt + (p1 - fmtp); 235 259 236 260 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost. … … 239 263 * we lose the " is a HEX number" part of fmt. 240 264 */ 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) { 244 268 savech = *p3; 245 269 *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); 247 271 strcat(pr->fmt, p2); 248 272 *p3 = savech; … … 250 274 } 251 275 276 pr->cchar = pr->fmt + (p1 - fmtp); 252 277 fmtp = p2; 253 278 … … 267 292 /* 268 293 * if the format string interprets any data at all, and it's 269 * not the same as the b b_dump_blocksize, and its last format unit294 * not the same as the blocksize, and its last format unit 270 295 * interprets any data at all, and has no iteration count, 271 296 * repeat it as necessary. … … 274 299 * gets output from the last iteration of the format unit. 275 300 */ 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 } 280 307 if (fu->reps > 1) { 281 308 for (pr = fu->nextpr;; pr = pr->nextpr) … … 292 319 } 293 320 294 static void do_skip( const char *fname, int statok)321 static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) 295 322 { 296 323 struct stat sbuf; 297 324 298 325 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; 308 333 return; 309 334 } 310 335 } 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 344 static NOINLINE int next(priv_dumper_t *dumper) 345 { 322 346 int statok; 323 347 324 if (argv) {325 _argv = argv;326 return 1;327 }328 348 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; 334 355 continue; 335 356 } 336 done = statok = 1;337 357 } else { 338 if (d one)339 return 0; 340 d one = 1;358 if (dumper->next__done) 359 return 0; /* no next file */ 360 dumper->next__done = 1; 341 361 statok = 0; 342 362 } 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) 348 368 return 1; 349 369 } … … 351 371 } 352 372 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 373 static unsigned char *get(priv_dumper_t *dumper) 374 { 358 375 int n; 359 376 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 */ 366 383 } 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) { 373 393 /* 374 394 * if read the right number of bytes, or at EOF for one file, … … 376 396 * block and set the end flag. 377 397 */ 378 if (! bb_dump_length || (ateof && !next((char **) NULL))) {379 if (need == b b_dump_blocksize) {398 if (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) { 399 if (need == blocksize) { 380 400 return NULL; 381 401 } 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) { 384 404 puts("*"); 385 405 } 386 406 return NULL; 387 407 } 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); 394 414 if (!n) { 395 415 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; 399 419 continue; 400 420 } 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; 404 424 } 405 425 need -= n; 406 426 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) { 415 436 puts("*"); 416 437 } 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; 420 442 nread = 0; 421 443 } else { … … 425 447 } 426 448 427 static void bpad(PR * 449 static void bpad(PR *pr) 428 450 { 429 451 char *p1, *p2; … … 435 457 pr->flags = F_BPAD; 436 458 *pr->cchar = 's'; 437 for (p1 = pr->fmt; *p1 != '%'; ++p1); 459 for (p1 = pr->fmt; *p1 != '%'; ++p1) 460 continue; 438 461 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; 441 466 } 442 467 443 468 static const char conv_str[] ALIGN1 = 444 469 "\0\\0\0" 445 "\007\\a\0" 470 "\007\\a\0" /* \a */ 446 471 "\b\\b\0" 447 472 "\f\\b\0" … … 453 478 454 479 455 static void conv_c(PR * pr, unsigned char *p)480 static void conv_c(PR *pr, unsigned char *p) 456 481 { 457 482 const char *str = conv_str; … … 466 491 } while (*str); 467 492 468 if (isprint (*p)) {493 if (isprint_asciionly(*p)) { 469 494 *pr->cchar = 'c'; 470 (void)printf(pr->fmt, *p);495 printf(pr->fmt, *p); 471 496 } else { 472 497 sprintf(buf, "%03o", (int) *p); 473 498 str = buf; 474 499 strpr: 475 500 *pr->cchar = 's'; 476 501 printf(pr->fmt, str); … … 478 503 } 479 504 480 static void conv_u(PR * pr, unsigned char *p)505 static void conv_u(PR *pr, unsigned char *p) 481 506 { 482 507 static const char list[] ALIGN1 = … … 493 518 *pr->cchar = 's'; 494 519 printf(pr->fmt, "del"); 495 } else if ( isprint(*p)) {520 } else if (*p < 0x7f) { /* isprint() */ 496 521 *pr->cchar = 'c'; 497 522 printf(pr->fmt, *p); … … 502 527 } 503 528 504 static void display(void) 505 { 506 /* extern FU *endfu; */ 529 static void display(priv_dumper_t* dumper) 530 { 507 531 FS *fs; 508 532 FU *fu; 509 533 PR *pr; 510 534 int cnt; 511 unsigned char *bp; 512 535 unsigned char *bp, *savebp; 513 536 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) { 519 544 for (fu = fs->nextfu; fu; fu = fu->nextfu) { 520 545 if (fu->flags & F_IGNORE) { … … 522 547 } 523 548 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 ) { 528 554 bpad(pr); 529 555 } … … 535 561 switch (pr->flags) { 536 562 case F_ADDRESS: 537 printf(pr->fmt, (unsigned int)address);563 printf(pr->fmt, (unsigned) dumper->address); 538 564 break; 539 565 case F_BPAD: … … 546 572 printf(pr->fmt, *bp); 547 573 break; 548 case F_DBL: {574 case F_DBL: { 549 575 double dval; 550 576 float fval; … … 552 578 switch (pr->bcnt) { 553 579 case 4: 554 memmove((char *) &fval, (char *) bp, 555 sizeof(fval)); 580 memcpy(&fval, bp, sizeof(fval)); 556 581 printf(pr->fmt, fval); 557 582 break; 558 583 case 8: 559 memmove((char *) &dval, (char *) bp, 560 sizeof(dval)); 584 memcpy(&dval, bp, sizeof(dval)); 561 585 printf(pr->fmt, dval); 562 586 break; … … 564 588 break; 565 589 } 566 case F_INT: {590 case F_INT: { 567 591 int ival; 568 592 short sval; … … 573 597 break; 574 598 case 2: 575 memmove((char *) &sval, (char *) bp, 576 sizeof(sval)); 599 memcpy(&sval, bp, sizeof(sval)); 577 600 printf(pr->fmt, (int) sval); 578 601 break; 579 602 case 4: 580 memmove((char *) &ival, (char *) bp, 581 sizeof(ival)); 603 memcpy(&ival, bp, sizeof(ival)); 582 604 printf(pr->fmt, ival); 583 605 break; … … 586 608 } 587 609 case F_P: 588 printf(pr->fmt, isprint (*bp) ? *bp : '.');610 printf(pr->fmt, isprint_asciionly(*bp) ? *bp : '.'); 589 611 break; 590 612 case F_STR: … … 597 619 conv_u(pr, bp); 598 620 break; 599 case F_UINT: {600 unsigned i nt ival;621 case F_UINT: { 622 unsigned ival; 601 623 unsigned short sval; 602 624 603 625 switch (pr->bcnt) { 604 626 case 1: 605 printf(pr->fmt, (unsigned int) *bp);627 printf(pr->fmt, (unsigned) *bp); 606 628 break; 607 629 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); 611 632 break; 612 633 case 4: 613 memmove((char *) &ival, (char *) bp, 614 sizeof(ival)); 634 memcpy(&ival, bp, sizeof(ival)); 615 635 printf(pr->fmt, ival); 616 636 break; … … 627 647 } 628 648 } 629 if ( endfu) {649 if (dumper->endfu) { 630 650 /* 631 * if eaddress not set, error or file bb_dump_size was multiple of632 * 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. 633 653 */ 634 if (! eaddress) {635 if (! address) {654 if (!dumper->eaddress) { 655 if (!dumper->address) { 636 656 return; 637 657 } 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) { 641 661 switch (pr->flags) { 642 662 case F_ADDRESS: 643 (void) printf(pr->fmt, (unsigned int)eaddress);663 printf(pr->fmt, (unsigned) dumper->eaddress); 644 664 break; 645 665 case F_TEXT: 646 (void)printf(pr->fmt);666 printf(pr->fmt); 647 667 break; 648 668 } … … 651 671 } 652 672 653 int bb_dump_dump(char **argv) 673 #define dumper ((priv_dumper_t*)pub_dumper) 674 int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv) 654 675 { 655 676 FS *tfs; 677 int blocksize; 656 678 657 679 /* 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) { 659 683 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 664 691 /* 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 702 void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) 676 703 { 677 704 const char *p; 678 705 char *p1; 679 706 char *p2; 680 static FS **nextfs;681 707 FS *tfs; 682 FU *tfu, **nextfu ;708 FU *tfu, **nextfupp; 683 709 const char *savep; 684 710 685 711 /* start new linked list of format units */ 686 712 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; 689 715 } 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; 694 722 695 723 /* 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 (;;) { 698 726 p = skip_whitespace(p); 699 727 if (!*p) { … … 703 731 /* allocate a new format unit and link it in */ 704 732 /* 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 */ 706 734 tfu = xzalloc(sizeof(FU)); 707 *nextfu = tfu;708 nextfu = &tfu->nextfu;735 *nextfupp = tfu; 736 nextfupp = &tfu->nextfu; 709 737 tfu->reps = 1; 710 738 711 739 /* if leading digit, repetition count */ 712 740 if (isdigit(*p)) { 713 for (savep = p; isdigit(*p); ++p); 741 for (savep = p; isdigit(*p); ++p) 742 continue; 714 743 if (!isspace(*p) && *p != '/') { 715 744 bb_error_msg_and_die("bad format {%s}", fmt); … … 718 747 tfu->reps = atoi(savep); 719 748 tfu->flags = F_SETREP; 720 /* bb_dump_skip trailing white space */749 /* skip trailing white space */ 721 750 p = skip_whitespace(++p); 722 751 } 723 752 724 /* bb_dump_skip slash and trailing white space */753 /* skip slash and trailing white space */ 725 754 if (*p == '/') { 726 755 p = skip_whitespace(++p); … … 731 760 // TODO: use bb_strtou 732 761 savep = p; 733 do p++; while (isdigit(*p)); 762 while (isdigit(*++p)) 763 continue; 734 764 if (!isspace(*p)) { 735 765 bb_error_msg_and_die("bad format {%s}", fmt); 736 766 } 737 767 tfu->bcnt = atoi(savep); 738 /* bb_dump_skip trailing white space */768 /* skip trailing white space */ 739 769 p = skip_whitespace(++p); 740 770 } … … 749 779 } 750 780 } 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); 754 782 /* escape(tfu->fmt); */ 755 783 -
branches/2.2.9/mindi-busybox/libbb/execable.c
r1765 r2725 5 5 * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu> 6 6 * 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. 8 8 */ 9 9 … … 14 14 * return 0 otherwise; 15 15 */ 16 int execable_file(const char *name)16 int FAST_FUNC execable_file(const char *name) 17 17 { 18 18 struct stat s; … … 20 20 } 21 21 22 /* search $PATHfor an executable file;22 /* search (*PATHp) for an executable file; 23 23 * 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/). 25 30 */ 26 char *find_execable(const char *filename)31 char* FAST_FUNC find_execable(const char *filename, char **PATHp) 27 32 { 28 char *p ath, *p, *n;33 char *p, *n; 29 34 30 p = path = xstrdup(getenv("PATH"));35 p = *PATHp; 31 36 while (p) { 32 37 n = strchr(p, ':'); … … 36 41 p = concat_path_file(p, filename); 37 42 if (execable_file(p)) { 38 free(path);43 *PATHp = n; 39 44 return p; 40 45 } … … 42 47 } 43 48 p = n; 44 } 45 free(path); 46 return NULL; 49 } /* on loop exit p == NULL */ 50 return p; 47 51 } 48 52 … … 51 55 * return 0 otherwise; 52 56 */ 53 int exists_execable(const char *filename)57 int FAST_FUNC exists_execable(const char *filename) 54 58 { 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); 56 63 if (ret) { 57 64 free(ret); … … 64 71 /* just like the real execvp, but try to launch an applet named 'file' first 65 72 */ 66 int bb_execvp(const char *file, char *const argv[])73 int FAST_FUNC bb_execvp(const char *file, char *const argv[]) 67 74 { 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, 69 76 argv); 70 77 } 71 78 #endif 79 80 int 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 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 15 15 #include "libbb.h" 16 16 17 int fclose_if_not_stdin(FILE *f)17 int FAST_FUNC fclose_if_not_stdin(FILE *f) 18 18 { 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; 23 25 } -
branches/2.2.9/mindi-busybox/libbb/fflush_stdout_and_exit.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 14 14 #include "libbb.h" 15 15 16 void fflush_stdout_and_exit(int retval)16 void FAST_FUNC fflush_stdout_and_exit(int retval) 17 17 { 18 18 if (fflush(stdout)) -
branches/2.2.9/mindi-busybox/libbb/fgets_str.c
r1765 r2725 6 6 * If you wrote this, please acknowledge your work. 7 7 * 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. 9 9 */ 10 10 11 11 #include "libbb.h" 12 12 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) 13 static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off, size_t *maxsz_p) 17 14 { 18 15 char *linebuf = NULL; … … 22 19 int idx = 0; 23 20 int ch; 21 size_t maxsz = *maxsz_p; 24 22 25 23 while (1) { 26 24 ch = fgetc(file); 27 25 if (ch == EOF) { 28 free(linebuf); 29 return NULL; 26 if (idx == 0) 27 return linebuf; /* NULL */ 28 break; 30 29 } 31 30 32 /* grow the line buffer as necessary */ 33 while (idx > linebufsz - 2) { 31 if (idx >= linebufsz) { 34 32 linebufsz += 200; 35 33 linebuf = xrealloc(linebuf, linebufsz); 34 if (idx >= maxsz) { 35 linebuf[idx] = ch; 36 idx++; 37 break; 38 } 36 39 } 37 40 … … 41 44 /* Check for terminating string */ 42 45 end_string_offset = idx - term_length; 43 if (end_string_offset > 046 if (end_string_offset >= 0 44 47 && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0 45 48 ) { 46 idx -= term_length; 49 if (chop_off) 50 idx -= term_length; 47 51 break; 48 52 } 49 53 } 54 /* Grow/shrink *first*, then store NUL */ 50 55 linebuf = xrealloc(linebuf, idx + 1); 51 56 linebuf[idx] = '\0'; 57 *maxsz_p = idx; 52 58 return linebuf; 53 59 } 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. */ 65 char* 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 71 char* 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 82 char* 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 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 18 18 * filesystem. 19 19 */ 20 struct mntent *find_mount_point(const char *name, const char *table)20 struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) 21 21 { 22 22 struct stat s; 23 dev_t mountDevice; 24 FILE *mountTable; 23 FILE *mtab_fp; 25 24 struct mntent *mountEntry; 25 dev_t devno_of_name; 26 bool block_dev; 26 27 27 28 if (stat(name, &s) != 0) 28 return 0;29 return NULL; 29 30 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 } 34 37 38 mtab_fp = setmntent(bb_path_mtab_file, "r"); 39 if (!mtab_fp) 40 return NULL; 35 41 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; 39 48 40 while ((mountEntry = getmntent(mountTable)) != 0) {41 49 if (strcmp(name, mountEntry->mnt_dir) == 0 42 50 || strcmp(name, mountEntry->mnt_fsname) == 0 … … 44 52 break; 45 53 } 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) 47 60 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) 49 63 break; 50 64 } 51 endmntent(mountTable); 65 endmntent(mtab_fp); 66 52 67 return mountEntry; 53 68 } -
branches/2.2.9/mindi-busybox/libbb/find_pid_by_name.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 39 39 */ 40 40 41 /* find_pid_by_name() 41 static 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. 42 76 * 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. 47 79 * 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 50 81 */ 51 pid_t* find_pid_by_name(const char*procName)82 pid_t* FAST_FUNC find_pid_by_name(const char *procName) 52 83 { 53 84 pid_t* pidList; … … 55 86 procps_status_t* p = NULL; 56 87 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) 64 91 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ 65 92 || (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) 67 95 ) { 68 pidList = xrealloc (pidList, sizeof(*pidList) * (i+2));96 pidList = xrealloc_vector(pidList, 2, i); 69 97 pidList[i++] = p->pid; 70 98 } … … 75 103 } 76 104 77 pid_t *pidlist_reverse(pid_t *pidList)105 pid_t* FAST_FUNC pidlist_reverse(pid_t *pidList) 78 106 { 79 107 int i = 0; -
branches/2.2.9/mindi-busybox/libbb/find_root_device.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 63 63 } 64 64 65 char *find_block_device(const char *path)65 char* FAST_FUNC find_block_device(const char *path) 66 66 { 67 67 struct arena a; -
branches/2.2.9/mindi-busybox/libbb/full_write.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 15 15 * Returns the amount written, or -1 on an error. 16 16 */ 17 ssize_t full_write(int fd, const void *buf, size_t len)17 ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len) 18 18 { 19 19 ssize_t cc; … … 25 25 cc = safe_write(fd, buf, len); 26 26 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 } 29 35 30 36 total += cc; -
branches/2.2.9/mindi-busybox/libbb/get_console.c
r1765 r2725 6 6 * acknowledge your work. 7 7 * 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. 9 9 */ 10 10 11 //#include <sys/ioctl.h>12 11 #include "libbb.h" 13 14 12 15 13 /* From <linux/kd.h> */ 16 14 enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */ 17 18 15 19 16 static int open_a_console(const char *fnam) … … 40 37 * if someone else used X (which does a chown on /dev/console). 41 38 */ 42 43 int get_console_fd(void) 39 int FAST_FUNC get_console_fd_or_die(void) 44 40 { 45 41 static const char *const console_names[] = { … … 68 64 } 69 65 70 bb_error_msg ("cannot get file descriptor referring toconsole");71 return fd; /*total failure */66 bb_error_msg_and_die("can't open console"); 67 /*return fd; - total failure */ 72 68 } 69 70 /* From <linux/vt.h> */ 71 enum { 72 VT_ACTIVATE = 0x5606, /* make vt active */ 73 VT_WAITACTIVE = 0x5607 /* wait for vt active */ 74 }; 75 76 void 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 5 5 * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 /* 12 * "/" -> "/" 13 * "abc" -> "abc" 14 * "abc/def" -> "def" 15 * "abc/def/" -> "" 16 */ 17 char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path) 18 { 19 char *slash = strrchr(path, '/'); 11 20 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 */ 33 char* FAST_FUNC bb_get_last_path_component_strip(char *path) 13 34 { 14 char *first = path; 15 char *last; 35 char *slash = last_char_is(path, '/'); 16 36 17 last = path - 1; 37 if (slash) 38 while (*slash == '/' && slash != path) 39 *slash-- = '\0'; 18 40 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); 32 42 } -
branches/2.2.9/mindi-busybox/libbb/get_line_from_file.c
r1765 r2725 7 7 * Copyright (C) 2001 Matt Krai 8 8 * 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. 10 10 */ 11 11 … … 13 13 14 14 /* 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. */ 22 char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno) 21 23 { 22 24 int ch; … … 28 30 /* grow the line buffer as necessary */ 29 31 if (idx >= linebufsz) { 30 linebufsz += 80;32 linebufsz += 256; 31 33 linebuf = xrealloc(linebuf, linebufsz); 32 34 } 33 35 linebuf[idx++] = (char) ch; 34 if (!ch || (end && ch == '\n'))36 if (!ch) 35 37 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 } 36 46 } 37 47 if (end) … … 44 54 // return NULL; 45 55 //} 46 linebuf = xrealloc(linebuf, idx +1);56 linebuf = xrealloc(linebuf, idx + 1); 47 57 linebuf[idx] = '\0'; 48 58 } … … 50 60 } 51 61 62 char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) 63 { 64 return bb_get_chunk_with_continuation(file, end, NULL); 65 } 66 52 67 /* Get line, including trailing \n if any */ 53 char *xmalloc_fgets(FILE *file)68 char* FAST_FUNC xmalloc_fgets(FILE *file) 54 69 { 55 70 int i; … … 57 72 return bb_get_chunk_from_file(file, &i); 58 73 } 59 60 74 /* Get line. Remove trailing \n */ 61 char *xmalloc_getline(FILE *file)75 char* FAST_FUNC xmalloc_fgetline(FILE *file) 62 76 { 63 77 int i; … … 69 83 return c; 70 84 } 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 */ 90 char* 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 */ 103 char* 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 143 static 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 */ 176 char* 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 185 char* 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 */ 192 char* 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 5 5 * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru> 6 6 * 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. 8 8 */ 9 9 … … 31 31 "r" will add 1 (bit 0) 32 32 "n" will add 2 (bit 1) 33 "u 33 "u" will add 4 (bit 2) 34 34 "g" will add 8 (bit 3) 35 35 … … 73 73 Here we want env to process just the '-i', not the '-d'. 74 74 75 "!" Report bad option, missing required options, 76 inconsistent options with all-ones return value (instead of abort). 77 75 78 const char *applet_long_options 76 79 … … 113 116 114 117 "ww" Adjacent double options have a counter associated which indicates 115 the number of occur ences of the option.118 the number of occurrences of the option. 116 119 For example the ps applet needs: 117 120 if w is given once, GNU ps sets the width to 132, 118 121 if w is given more than once, it is "unlimited" 119 122 120 int w_counter = 0; 123 int w_counter = 0; // must be initialized! 121 124 opt_complementary = "ww"; 122 125 getopt32(argv, "w", &w_counter); … … 138 141 f = getopt32(argv, "vb:c", &my_b, &verbose_level); 139 142 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)); 141 144 if (my_b) // but llist is stored if -b is specified 142 145 free_llist(my_b); … … 145 148 Special characters: 146 149 147 "-" A dash as the first char in a opt_complementary group forces148 all arguments to be treated as options, even if they have149 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 givenwithout 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) 156 159 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. 157 164 158 165 "--" A double dash at the beginning of opt_complementary means the … … 162 169 tar xvf foo.tar 163 170 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 164 175 "-N" A dash as the first char in a opt_complementary group followed 165 176 by a single digit (0-9) means that at least N non-option … … 175 186 176 187 "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. 178 189 This is typically used to implement "print verbose usage message 179 190 and exit" option. 180 191 181 " -"A dash between two options causes the second of the two192 "a-b" A dash between two options causes the second of the two 182 193 to be unset (and ignored) if it is given on the command line. 183 194 … … 205 216 printf("Detected odd -x usage\n"); 206 217 207 " --"A double dash between two options, or between an option and a group218 "a--b" A double dash between two options, or between an option and a group 208 219 of options, means that they are mutually exclusive. Unlike 209 220 the "-" case above, an error will be forced if the options … … 221 232 at most once. 222 233 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:", ¶m); 241 242 "a::" A double colon after a char in opt_complementary means that the 224 243 option can occur multiple times. Each occurrence will be saved as 225 244 a llist_t element instead of char*. … … 241 260 user:x:500:500::/home/user:/bin/bash 242 261 243 " ?" An"?" between an option and a group of options means that262 "a?b" A "?" between an option and a group of options means that 244 263 at least one of them is required to occur if the first option 245 264 occurs in preceding command line arguments. … … 248 267 249 268 // 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"; 251 270 flags = getopt32(argv, "rnug"); 252 271 … … 260 279 261 280 // 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"; 263 282 flags = getopt32(argv, "KS...); 264 283 … … 269 288 a '-2' option then unset '-3', '-X' and '-a'; if there is 270 289 a '-2' and after it a '-x' then error out. 290 But it's far too obfuscated. Use ':' to separate groups. 271 291 */ 272 292 273 293 /* Code here assumes that 'unsigned' is at least 32 bits wide */ 274 294 295 const char *const bb_argv_dash[] = { "-", NULL }; 296 275 297 const char *opt_complementary; 276 298 299 enum { 300 PARAM_STRING, 301 PARAM_LIST, 302 PARAM_INT, 303 }; 304 277 305 typedef struct { 278 int opt;279 int list_flg;306 unsigned char opt_char; 307 smallint param_type; 280 308 unsigned switch_on; 281 309 unsigned switch_off; 282 310 unsigned incongruously; 283 311 unsigned requires; 284 void **optarg; /* char **optarg or llist_t **optarg*/312 void **optarg; /* char**, llist_t** or int *. */ 285 313 int *counter; 286 314 } t_complementary; 287 315 288 316 /* You can set applet_long_options for parse called long options */ 289 #if ENABLE_ GETOPT_LONG317 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 290 318 static const struct option bb_null_long_options[1] = { 291 319 { 0, 0, 0, 0 } … … 296 324 uint32_t option_mask32; 297 325 298 uint32_t 326 uint32_t FAST_FUNC 299 327 getopt32(char **argv, const char *applet_opts, ...) 300 328 { … … 302 330 unsigned flags = 0; 303 331 unsigned requires = 0; 304 t_complementary complementary[33]; 332 t_complementary complementary[33]; /* last stays zero-filled */ 333 char first_char; 305 334 int c; 306 335 const unsigned char *s; 307 336 t_complementary *on_off; 308 337 va_list p; 309 #if ENABLE_ GETOPT_LONG338 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 310 339 const struct option *l_o; 311 340 struct option *long_options = (struct option *) &bb_null_long_options; 312 341 #endif 313 342 unsigned trigger; 314 char **pargv = NULL;343 char **pargv; 315 344 int min_arg = 0; 316 345 int max_arg = -1; … … 319 348 #define ALL_ARGV_IS_OPTS 2 320 349 #define FIRST_ARGV_IS_OPT 4 321 #define FREE_FIRST_ARGV_IS_OPT 8 350 322 351 int spec_flgs = 0; 323 352 324 argc = 0; 353 /* skip 0: some applets cheat: they do not actually HAVE argv[0] */ 354 argc = 1; 325 355 while (argv[argc]) 326 356 argc++; … … 331 361 on_off = complementary; 332 362 memset(on_off, 0, sizeof(complementary)); 363 364 /* skip bbox extension */ 365 first_char = applet_opts[0]; 366 if (first_char == '!') 367 applet_opts++; 333 368 334 369 /* skip GNU extension */ … … 337 372 s++; 338 373 while (*s) { 339 if (c >= 32) break; 340 on_off->opt = *s; 374 if (c >= 32) 375 break; 376 on_off->opt_char = *s; 341 377 on_off->switch_on = (1 << c); 342 378 if (*++s == ':') { 343 379 on_off->optarg = va_arg(p, void **); 344 while (*++s == ':') /* skip */; 380 while (*++s == ':') 381 continue; 345 382 } 346 383 on_off++; … … 348 385 } 349 386 350 #if ENABLE_ GETOPT_LONG387 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 351 388 if (applet_long_options) { 352 389 const char *optstr; … … 375 412 if (l_o->flag) 376 413 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) 379 416 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; 382 420 on_off->switch_on = (1 << c); 383 421 if (l_o->has_arg != no_argument) … … 386 424 next_long: ; 387 425 } 426 /* Make it unnecessary to clear applet_long_options 427 * by hand after each call to getopt32 428 */ 429 applet_long_options = NULL; 388 430 } 389 #endif /* ENABLE_ GETOPT_LONG */431 #endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */ 390 432 for (s = (const unsigned char *)opt_complementary; s && *s; s++) { 391 433 t_complementary *pair; … … 422 464 continue; 423 465 } 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) 426 468 break; 427 469 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; 429 475 continue; 430 476 } … … 444 490 } 445 491 pair = on_off; 446 pair_switch = & (pair->switch_on);492 pair_switch = &pair->switch_on; 447 493 for (s++; *s && *s != ':'; s++) { 448 494 if (*s == '?') { 449 pair_switch = & (pair->requires);495 pair_switch = &pair->requires; 450 496 } 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; 453 499 else 454 pair_switch = & (pair->switch_off);500 pair_switch = &pair->switch_off; 455 501 } 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) { 458 504 *pair_switch |= on_off->switch_on; 459 505 break; … … 463 509 s--; 464 510 } 511 opt_complementary = NULL; 465 512 va_end(p); 466 513 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++; 472 529 } 473 530 } 474 531 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 */ 476 540 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 480 548 * "fake" short options, like this one: 481 549 * wget $'-\203' "Test: test" http://kernel.org/ 482 550 * (supposed to act as --header, but doesn't) */ 483 #if ENABLE_ GETOPT_LONG551 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 484 552 while ((c = getopt_long(argc, argv, applet_opts, 485 553 long_options, NULL)) != -1) { … … 487 555 while ((c = getopt(argc, argv, applet_opts)) != -1) { 488 556 #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 } 495 568 } 496 569 if (flags & on_off->incongruously) 497 bb_show_usage();570 goto error; 498 571 trigger = on_off->switch_on & on_off->switch_off; 499 572 flags &= ~(on_off->switch_off ^ trigger); … … 502 575 if (on_off->counter) 503 576 (*(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); 506 584 } else if (on_off->optarg) { 507 *(char **)(on_off->optarg) = optarg; 585 if (optarg) 586 *(char **)(on_off->optarg) = optarg; 508 587 } 509 588 if (pargv != NULL) … … 511 590 } 512 591 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_UP529 if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)530 free(argv[1]);531 #endif532 592 /* 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 } 537 600 } 538 601 if (requires && (flags & requires) == 0) 539 bb_show_usage();602 goto error; 540 603 argc -= optind; 541 604 if (argc < min_arg || (max_arg >= 0 && argc > max_arg)) 542 bb_show_usage();605 goto error; 543 606 544 607 option_mask32 = flags; 545 608 return flags; 609 610 error: 611 if (first_char != '!') 612 bb_show_usage(); 613 return (int32_t)-1; 546 614 } -
branches/2.2.9/mindi-busybox/libbb/herror_msg.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 12 void bb_herror_msg(const char *s, ...)11 void FAST_FUNC bb_herror_msg(const char *s, ...) 13 12 { 14 13 va_list p; … … 18 17 va_end(p); 19 18 } 19 20 void 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 25 25 * Some code to omit the decimal point and tenths digit is sketched out 26 26 * and "#if 0"'d below. 27 * 28 * Licensed under GPLv2, see file LICENSE in this source tree. 27 29 */ 28 30 29 31 #include "libbb.h" 30 32 31 const char *make_human_readable_str(unsigned long long size,33 const char* FAST_FUNC make_human_readable_str(unsigned long long val, 32 34 unsigned long block_size, unsigned long display_unit) 33 35 { 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 }; 38 39 39 static char str[21] ALIGN1; /* Sufficient for 64 bit unsigned integers */40 static char *str; 40 41 41 unsigned long long val; 42 int frac; 42 unsigned frac; /* 0..9 - the fractional digit */ 43 43 const char *u; 44 const char *f ;44 const char *fmt; 45 45 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; 48 52 frac = 0; 49 50 val = size * block_size; 51 if (val == 0) { 52 return u; 53 } 53 u = unit_chars; 54 54 55 55 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) */ 58 59 } else { 59 ++u;60 60 while ((val >= 1024) 61 && (u < zero_and_units + sizeof(zero_and_units) - 1)61 /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */ 62 62 ) { 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; 66 66 val /= 1024; 67 67 } 68 if (frac >= 10) { /* We need to round up here.*/68 if (frac >= 10) { /* we need to round up here */ 69 69 ++val; 70 70 frac = 0; 71 71 } 72 #if 073 /* 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) { 75 75 if (frac >= 5) { 76 76 ++val; 77 77 } 78 f = "%llu%*c" /* fmt_no_tenths */;78 fmt = "%llu%*c"; 79 79 frac = 1; 80 80 } … … 82 82 } 83 83 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); 87 89 return str; 88 90 } 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) */ 97 void 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) */ 153 void 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 6 6 * Heavily modified by Manuel Novoa III Mar 12, 2001 7 7 * 8 * 8 * Licensed under GPLv2, see file LICENSE in this source tree. 9 9 */ 10 10 … … 12 12 #include "inet_common.h" 13 13 14 int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)14 int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst) 15 15 { 16 16 struct hostent *hp; … … 24 24 25 25 /* Default is special, meaning 0.0.0.0. */ 26 if ( !strcmp(name, bb_str_default)) {26 if (strcmp(name, "default") == 0) { 27 27 s_in->sin_addr.s_addr = INADDR_ANY; 28 28 return 1; … … 64 64 res_init(); 65 65 _res.options |= RES_DEBUG; 66 #endif67 68 #ifdef DEBUG69 66 bb_error_msg("gethostbyname(%s)", name); 70 67 #endif … … 82 79 * & 0x0fff: don't resolve 83 80 */ 84 char *INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask)81 char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask) 85 82 { 86 83 /* addr-to-name cache */ … … 98 95 int host = 0; 99 96 100 /* Grmpf. -FvK */101 97 if (s_in->sin_family != AF_INET) { 102 98 #ifdef DEBUG … … 114 110 if ((numeric & 0x0FFF) == 0) { 115 111 if (numeric & 0x8000) 116 return xstrdup( bb_str_default);112 return xstrdup("default"); 117 113 return xstrdup("*"); 118 114 } … … 167 163 #if ENABLE_FEATURE_IPV6 168 164 169 int INET6_resolve(const char *name, struct sockaddr_in6 *sin6)165 int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6) 170 166 { 171 167 struct addrinfo req, *ai; … … 191 187 192 188 193 char *INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)189 char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) 194 190 { 195 191 char name[128]; 196 192 int s; 197 193 198 /* Grmpf. -FvK */199 194 if (sin6->sin6_family != AF_INET6) { 200 195 #ifdef DEBUG 201 bb_error_msg("rresolve: unsupport address family %d!",196 bb_error_msg("rresolve: unsupported address family %d!", 202 197 sin6->sin6_family); 203 198 #endif … … 211 206 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 212 207 if (numeric & 0x8000) 213 return xstrdup( bb_str_default);208 return xstrdup("default"); 214 209 return xstrdup("*"); 215 210 } … … 224 219 } 225 220 226 #endif 221 #endif /* CONFIG_FEATURE_IPV6 */ -
branches/2.2.9/mindi-busybox/libbb/info_msg.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 #include <syslog.h>11 10 #include "libbb.h" 11 #if ENABLE_FEATURE_SYSLOG 12 # include <syslog.h> 13 #endif 12 14 13 void bb_info_msg(const char *s, ...)15 void FAST_FUNC bb_info_msg(const char *s, ...) 14 16 { 17 #ifdef THIS_ONE_DOESNT_DO_SINGLE_WRITE 15 18 va_list p; 16 19 /* va_copy is used because it is not portable … … 24 27 fputs(msg_eol, stdout); 25 28 } 26 if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG)) 29 # if ENABLE_FEATURE_SYSLOG 30 if (logmode & LOGMODE_SYSLOG) 27 31 vsyslog(LOG_INFO, s, p2); 32 # endif 28 33 va_end(p2); 29 34 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 30 62 } -
branches/2.2.9/mindi-busybox/libbb/inode_hash.c
r1765 r2725 6 6 * If you wrote this, please acknowledge your work. 7 7 * 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. 9 9 */ 10 10 … … 18 18 } ino_dev_hashtable_bucket_t; 19 19 20 #define HASH_SIZE 311/* Should be prime */21 #define hash_inode(i) 20 #define HASH_SIZE 311 /* Should be prime */ 21 #define hash_inode(i) ((i) % HASH_SIZE) 22 22 23 23 /* array of [HASH_SIZE] elements */ … … 28 28 * ino_dev_hashtable, else return NULL 29 29 */ 30 char *is_in_ino_dev_hashtable(const struct stat *statbuf)30 char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf) 31 31 { 32 32 ino_dev_hashtable_bucket_t *bucket; … … 48 48 49 49 /* Add statbuf to statbuf hash table */ 50 void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)50 void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) 51 51 { 52 52 int i; … … 68 68 } 69 69 70 #if ENABLE_ FEATURE_CLEAN_UP70 #if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP 71 71 /* Clear statbuf hash table */ 72 void reset_ino_dev_hashtable(void)72 void FAST_FUNC reset_ino_dev_hashtable(void) 73 73 { 74 74 int i; … … 85 85 ino_dev_hashtable = NULL; 86 86 } 87 #else88 void reset_ino_dev_hashtable(void);89 87 #endif -
branches/2.2.9/mindi-busybox/libbb/isdirectory.c
r821 r2725 4 4 * 5 5 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 6 * Permission has been granted to redistribute this code under theGPL.6 * Permission has been granted to redistribute this code under GPL. 7 7 * 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. 9 9 */ 10 10 … … 13 13 14 14 /* 15 * Return TRUE if afileName is a directory.15 * Return TRUE if fileName is a directory. 16 16 * Nonexistent files return FALSE. 17 17 */ 18 int is_directory(const char *fileName, constint followLinks, struct stat *statBuf)18 int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf) 19 19 { 20 20 int status; … … 22 22 23 23 if (statBuf == NULL) { 24 /* set fromauto stack buffer */25 24 /* use auto stack buffer */ 25 statBuf = &astatBuf; 26 26 } 27 27 … … 31 31 status = lstat(fileName, statBuf); 32 32 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)); 37 34 38 35 return status; -
branches/2.2.9/mindi-busybox/libbb/kernel_version.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 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) */ 11 13 12 #include "libbb.h"13 14 14 15 /* Returns current kernel version encoded as major*65536 + minor*256 + patch, … … 17 18 * if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> } 18 19 */ 19 int get_linux_version_code(void)20 int FAST_FUNC get_linux_version_code(void) 20 21 { 21 22 struct utsname name; … … 24 25 25 26 if (uname(&name) == -1) { 26 bb_perror_msg("can not get system information");27 bb_perror_msg("can't get system information"); 27 28 return 0; 28 29 } -
branches/2.2.9/mindi-busybox/libbb/last_char_is.c
r1765 r2725 5 5 * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov> 6 6 * 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. 8 8 */ 9 9 … … 13 13 * Don't underrun the buffer if the string length is 0. 14 14 */ 15 char* last_char_is(const char *s, int c)15 char* FAST_FUNC last_char_is(const char *s, int c) 16 16 { 17 17 if (s && *s) { -
branches/2.2.9/mindi-busybox/libbb/lineedit.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * Termios command line History and Editing.3 * Command line editing. 4 4 * 5 5 * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. … … 16 16 17 17 /* 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\] ' 29 41 */ 30 31 42 #include "libbb.h" 32 33 34 /* FIXME: obsolete CONFIG item? */ 35 #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 36 43 #include "unicode.h" 37 44 38 45 #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 47 50 48 51 … … 50 53 #if ENABLE_FEATURE_EDITING 51 54 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 69 static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } 70 # if ENABLE_FEATURE_EDITING_VI 71 static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); } 72 # endif 73 static 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 54 82 #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 103 enum { 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 110 static const char null_str[] ALIGN1 = ""; 111 #endif 112 113 /* We try to minimize both static and stack usage. */ 114 struct 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; 78 132 #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 */ 158 extern 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) 187 static 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 205 static 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 } 213 static 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... */ 256 static 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 269 static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc) 270 # else 271 static 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 */ 300 static 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 306 static 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: */ 313 int adjust_width_and_validate_wc(unsigned *width_adj, int wc); 314 #endif 315 88 316 89 317 /* Put 'command_ps[cursor]', cursor++. 90 318 * Advance cursor on screen. If we reached right margin, scroll text up 91 319 * 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 321 static 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) { 97 328 /* erase character after end of input string */ 98 329 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 118 372 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 } 126 381 } 127 382 128 383 /* Move to end of line (by printing all chars till the end) */ 129 static void input_end(void)384 static void put_till_end_and_adv_cursor(void) 130 385 { 131 386 while (cursor < command_len) 132 cmdedit_set_out_char(' ');387 put_cur_glyph_and_inc_cursor(); 133 388 } 134 389 … … 136 391 static void goto_new_line(void) 137 392 { 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'); 148 396 } 149 397 150 398 static void beep(void) 151 399 { 152 putchar('\007'); 400 bb_putchar('\007'); 401 } 402 403 static 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; 153 413 } 154 414 … … 157 417 static void input_backward(unsigned num) 158 418 { 159 int count_y;160 161 419 if (num > cursor) 162 420 num = cursor; 163 if ( !num)421 if (num == 0) 164 422 return; 165 423 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 } 166 436 167 437 if (cmdedit_x >= num) { 168 438 cmdedit_x -= num; 169 439 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); 171 449 return; 172 450 } 173 printf( "\033[%uD", num);451 printf(ESC"[%uD", num); 174 452 return; 175 453 } 176 454 177 455 /* 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 } 193 500 } 194 501 … … 196 503 static void redraw(int y, int back_cursor) 197 504 { 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'); 201 508 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); 204 511 input_backward(back_cursor); 205 512 } 206 207 #if ENABLE_FEATURE_EDITING_VI208 #define DELBUFSIZ 128209 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 #endif213 513 214 514 /* Delete the char in front of the cursor, optionally saving it 215 515 * for later putback */ 516 #if !ENABLE_FEATURE_EDITING_VI 517 static void input_delete(void) 518 #define input_delete(save) input_delete() 519 #else 216 520 static void input_delete(int save) 521 #endif 217 522 { 218 523 int j = cursor; 219 524 220 if (j == command_len)525 if (j == (int)command_len) 221 526 return; 222 527 … … 224 529 if (save) { 225 530 if (newdelflag) { 226 if (!delbuf) 227 delbuf = malloc(DELBUFSIZ); 228 /* safe if malloc fails */ 229 delp = delbuf; 531 delptr = delbuf; 230 532 newdelflag = 0; 231 533 } 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])); 238 543 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); 241 547 input_backward(cursor - j); /* back to old pos cursor */ 242 548 } … … 246 552 { 247 553 int ocursor; 248 int j = delp - delbuf;554 int j = delptr - delbuf; 249 555 250 556 if (j == 0) … … 252 558 ocursor = cursor; 253 559 /* 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])); 256 563 command_len += j; 257 input_end(); /* rewrite new line */564 put_till_end_and_adv_cursor(); 258 565 input_backward(cursor - ocursor - j + 1); /* at end of new text */ 259 566 } … … 273 580 { 274 581 if (cursor < command_len) 275 cmdedit_set_out_char(command_ps[cursor + 1]); 276 } 277 582 put_cur_glyph_and_inc_cursor(); 583 } 278 584 279 585 #if ENABLE_FEATURE_TAB_COMPLETION 280 586 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>... 283 592 284 593 static void free_tab_completion_data(void) … … 294 603 static void add_match(char *matched) 295 604 { 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; 301 607 num_matches++; 302 608 } 303 609 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 */ 615 static char *username_path_completion(char *ud) 306 616 { 307 617 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 */ 644 static 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 ~ */ 311 653 userlen = strlen(ud); 312 654 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 */ 357 667 358 668 enum { … … 362 672 }; 363 673 364 static int path_parse(char ***p , int flags)674 static int path_parse(char ***p) 365 675 { 366 676 int npth; … … 369 679 char **res; 370 680 371 /* if not setenv PATH variable, to search cur dir "." */372 if (flags != FIND_EXE_ONLY)373 return 1;374 375 681 if (state->flags & WITH_PATH_LOOKUP) 376 682 pth = state->path_lookup; 377 683 else 378 684 pth = getenv("PATH"); 379 /* PATH=<empty> or PATH=:<empty> */ 685 686 /* PATH="" or PATH=":"? */ 380 687 if (!pth || !pth[0] || LONE_CHAR(pth, ':')) 381 688 return 1; … … 387 694 if (!tmp) 388 695 break; 389 if (*++tmp == '\0') 696 tmp++; 697 if (*tmp == '\0') 390 698 break; /* :<empty> */ 391 699 npth++; 392 700 } 393 701 394 res = xmalloc(npth * sizeof(char*));702 *p = res = xmalloc(npth * sizeof(res[0])); 395 703 res[0] = tmp = xstrdup(pth); 396 704 npth = 1; … … 404 712 res[npth++] = tmp; 405 713 } 406 *p = res;407 714 return npth; 408 715 } 409 716 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 */ 720 static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) 721 { 416 722 char *path1[1]; 417 723 char **paths = path1; 418 724 int npaths; 419 725 int i; 420 char *found; 421 char *pfind = strrchr(command, '/'); 726 unsigned pf_len; 727 const char *pfind; 728 char *dirbuf = NULL; 422 729 423 730 npaths = 1; 424 731 path1[0] = (char*)"."; 425 732 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); 429 737 pfind = command; 430 738 } else { 431 /* dirbuf = ".../.../.../" */432 safe_strncpy(dirbuf, command, (pfind - command) + 2);433 #if ENABLE_FEATURE_USERNAME_COMPLETION434 if (dirbuf[0] == '~') /* ~/... or ~user/... */435 username_tab_completion(dirbuf, dirbuf);436 #endif437 paths[0] = dirbuf;438 739 /* point to 'l' in "..../last_component" */ 439 740 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); 441 750 442 751 for (i = 0; i < npaths; i++) { 752 DIR *dir; 753 struct dirent *next; 754 struct stat st; 755 char *found; 756 443 757 dir = opendir(paths[i]); 444 if (!dir) /* Don't print an error */445 continue; 758 if (!dir) 759 continue; /* don't print an error */ 446 760 447 761 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)) 453 767 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); 472 783 473 784 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'; 478 788 } else { 479 /* not put found file if search only dirs for cd*/789 /* skip files if looking for dirs only (example: cd) */ 480 790 if (type == FIND_DIR_ONLY) 481 791 goto cont; 482 792 } 483 /* Add it to the list */793 /* add it to the list */ 484 794 add_match(found); 485 795 continue; … … 488 798 } 489 799 closedir(dir); 490 } 800 } /* for every path */ 801 491 802 if (paths != path1) { 492 free(paths[0]); /* allocated memoryonly in first member */803 free(paths[0]); /* allocated memory is only in first member */ 493 804 free(paths); 494 805 } 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 */ 497 822 #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) 823 static 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 */ 842 static NOINLINE int build_match_prefix(char *match_buf) 504 843 { 505 844 int i, j; 506 845 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; 526 881 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 */ 539 889 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; 549 897 } 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` */ 556 903 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++)576 904 if (int_buf[i] == '`') { 577 for (j = i + 1; int_buf[j]; j++) 905 for (j = i + 1; int_buf[j]; j++) { 578 906 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; 582 914 } 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++) { 595 928 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 */ 614 935 for (i = 0; int_buf[i]; i++) 615 936 if (int_buf[i] != ' ') 616 937 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 */ 621 941 command_mode = FIND_EXE_ONLY; 622 for (i = 0; int_buf[i]; i++) 942 for (i = 0; int_buf[i]; i++) { 623 943 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] == ' ' */ 627 949 ) { 628 950 command_mode = FIND_DIR_ONLY; … … 632 954 } 633 955 } 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; 637 962 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') 651 973 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); 663 976 664 977 return command_mode; … … 666 979 667 980 /* 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] :) 670 983 */ 671 984 static void showfiles(void) … … 677 990 int l; 678 991 679 /* find the longest file name -use that as the column width */992 /* find the longest file name - use that as the column width */ 680 993 for (row = 0; row < nrows; row++) { 681 l = strlen(matches[row]);994 l = unicode_strwidth(matches[row]); 682 995 if (column_width < l) 683 996 column_width = l; … … 699 1012 for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) { 700 1013 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 1024 static const char *is_special_char(char c) 1025 { 1026 return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c); 1027 } 1028 1029 static char *quote_special_chars(char *found) 708 1030 { 709 1031 int l = 0; 710 char *s = x malloc((strlen(found) + 1) * 2);1032 char *s = xzalloc((strlen(found) + 1) * 2); 711 1033 712 1034 while (*found) { 713 if ( strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>",*found))1035 if (is_special_char(*found)) 714 1036 s[l++] = '\\'; 715 1037 s[l++] = *found++; 716 1038 } 717 s[l] = 0;1039 /* s[l] = '\0'; - already is */ 718 1040 return s; 719 1041 } 720 1042 721 static int match_compare(const void *a, const void *b)722 {723 return strcmp(*(char**)a, *(char**)b);724 }725 726 1043 /* Do TAB completion */ 727 static void input_tab(int *lastWasTab) 728 { 1044 static 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 729 1056 if (!(state->flags & TAB_COMPLETION)) 730 1057 return; 731 1058 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; 839 1066 goto_new_line(); 840 1067 showfiles(); 841 1068 redraw(0, command_len - sav_cursor); 842 1069 } 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 1225 line_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 } 849 1231 850 1232 851 1233 #if MAX_HISTORY > 0 852 1234 1235 static 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 853 1253 /* 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 } 1254 static 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; 872 1260 } 873 1261 beep(); … … 875 1263 } 876 1264 877 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 1265 static 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 1286 static 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 878 1294 /* state->flags is already checked to be nonzero */ 879 static void load_history(const char *fromfile) 880 { 1295 static void load_history(line_input_t *st_parm) 1296 { 1297 char *temp_h[MAX_HISTORY]; 1298 char *line; 881 1299 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); 891 1305 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); 903 1319 continue; 904 1320 } 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; 906 1327 } 907 1328 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 } 910 1354 } 911 1355 912 1356 /* 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) 1357 static 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 1409 static void remember_in_history(char *str) 933 1410 { 934 1411 int i; … … 936 1413 if (!(state->flags & DO_HISTORY)) 937 1414 return; 938 1415 if (str[0] == '\0') 1416 return; 939 1417 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 > */ 943 1427 if (i >= MAX_HISTORY) { 944 1428 free(state->history[0]); 945 1429 for (i = 0; i < MAX_HISTORY-1; i++) 946 1430 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 */ 950 1434 state->history[i++] = xstrdup(str); 1435 /* i <= MAX_HISTORY */ 951 1436 state->cur_history = i; 952 1437 state->cnt_history = i; 953 # ifENABLE_FEATURE_EDITING_SAVEHISTORY1438 # if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 954 1439 if ((state->flags & SAVE_HISTORY) && state->hist_file) 955 save_history(st ate->hist_file);956 # endif957 USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)1440 save_history(str); 1441 # endif 1442 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) 958 1443 } 959 1444 960 1445 #else /* MAX_HISTORY == 0 */ 961 # define remember_in_history(a) ((void)0)1446 # define remember_in_history(a) ((void)0) 962 1447 #endif /* MAX_HISTORY */ 963 1448 964 1449 1450 #if ENABLE_FEATURE_EDITING_VI 965 1451 /* 966 * This function is used to grab a character buffer967 * from the input file descriptor and allows you to968 * a string with full command editing (sort of like969 * a mini readline).970 *971 * The following standard commands are not implemented:972 * ESC-b -- Move back one word973 * ESC-f -- Move forward one word974 * ESC-d -- Delete back one word975 * ESC-h -- Delete forward one word976 * CTL-t -- Transpose two characters977 *978 * Minimalist vi-style command line editing available if configured.979 1452 * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us> 980 1453 */ 981 982 #if ENABLE_FEATURE_EDITING_VI983 1454 static void 984 vi_Word_motion(char *command, int eat) 985 { 986 while (cursor < command_len && !isspace(command[cursor])) 1455 vi_Word_motion(int eat) 1456 { 1457 CHAR_T *command = command_ps; 1458 1459 while (cursor < command_len && !BB_isspace(command[cursor])) 987 1460 input_forward(); 988 if (eat) while (cursor < command_len && isspace(command[cursor]))1461 if (eat) while (cursor < command_len && BB_isspace(command[cursor])) 989 1462 input_forward(); 990 1463 } 991 1464 992 1465 static void 993 vi_word_motion(char *command, int eat) 994 { 995 if (isalnum(command[cursor]) || command[cursor] == '_') { 1466 vi_word_motion(int eat) 1467 { 1468 CHAR_T *command = command_ps; 1469 1470 if (BB_isalnum(command[cursor]) || command[cursor] == '_') { 996 1471 while (cursor < command_len 997 && (isalnum(command[cursor+1]) || command[cursor+1] == '_')) 1472 && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') 1473 ) { 998 1474 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])) 1001 1478 input_forward(); 1002 1479 } … … 1005 1482 input_forward(); 1006 1483 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])) 1009 1486 input_forward(); 1487 } 1010 1488 } 1011 1489 1012 1490 static void 1013 vi_End_motion(char *command) 1014 { 1491 vi_End_motion(void) 1492 { 1493 CHAR_T *command = command_ps; 1494 1015 1495 input_forward(); 1016 while (cursor < command_len && isspace(command[cursor]))1496 while (cursor < command_len && BB_isspace(command[cursor])) 1017 1497 input_forward(); 1018 while (cursor < command_len-1 && ! isspace(command[cursor+1]))1498 while (cursor < command_len-1 && !BB_isspace(command[cursor+1])) 1019 1499 input_forward(); 1020 1500 } 1021 1501 1022 1502 static void 1023 vi_end_motion(char *command) 1024 { 1503 vi_end_motion(void) 1504 { 1505 CHAR_T *command = command_ps; 1506 1025 1507 if (cursor >= command_len-1) 1026 1508 return; 1027 1509 input_forward(); 1028 while (cursor < command_len-1 && isspace(command[cursor]))1510 while (cursor < command_len-1 && BB_isspace(command[cursor])) 1029 1511 input_forward(); 1030 1512 if (cursor >= command_len-1) 1031 1513 return; 1032 if ( isalnum(command[cursor]) || command[cursor] == '_') {1514 if (BB_isalnum(command[cursor]) || command[cursor] == '_') { 1033 1515 while (cursor < command_len-1 1034 && ( isalnum(command[cursor+1]) || command[cursor+1] == '_')1516 && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') 1035 1517 ) { 1036 1518 input_forward(); 1037 1519 } 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])) 1040 1522 input_forward(); 1041 1523 } … … 1043 1525 1044 1526 static void 1045 vi_Back_motion(char *command) 1046 { 1047 while (cursor > 0 && isspace(command[cursor-1])) 1527 vi_Back_motion(void) 1528 { 1529 CHAR_T *command = command_ps; 1530 1531 while (cursor > 0 && BB_isspace(command[cursor-1])) 1048 1532 input_backward(1); 1049 while (cursor > 0 && ! isspace(command[cursor-1]))1533 while (cursor > 0 && !BB_isspace(command[cursor-1])) 1050 1534 input_backward(1); 1051 1535 } 1052 1536 1053 1537 static void 1054 vi_back_motion(char *command) 1055 { 1538 vi_back_motion(void) 1539 { 1540 CHAR_T *command = command_ps; 1541 1056 1542 if (cursor <= 0) 1057 1543 return; 1058 1544 input_backward(1); 1059 while (cursor > 0 && isspace(command[cursor]))1545 while (cursor > 0 && BB_isspace(command[cursor])) 1060 1546 input_backward(1); 1061 1547 if (cursor <= 0) 1062 1548 return; 1063 if ( isalnum(command[cursor]) || command[cursor] == '_') {1549 if (BB_isalnum(command[cursor]) || command[cursor] == '_') { 1064 1550 while (cursor > 0 1065 && ( isalnum(command[cursor-1]) || command[cursor-1] == '_')1551 && (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_') 1066 1552 ) { 1067 1553 input_backward(1); 1068 1554 } 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])) 1071 1557 input_backward(1); 1072 1558 } 1073 1559 } 1074 1560 #endif 1561 1562 /* Modelled after bash 4.0 behavior of Ctrl-<arrow> */ 1563 static 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 } 1589 static 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 } 1075 1613 1076 1614 … … 1079 1617 */ 1080 1618 1619 #if ENABLE_FEATURE_EDITING_ASK_TERMINAL 1620 static 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 1081 1664 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1082 static void parse_ prompt(const char *prmt_ptr)1665 static void parse_and_put_prompt(const char *prmt_ptr) 1083 1666 { 1084 1667 cmdedit_prompt = prmt_ptr; … … 1087 1670 } 1088 1671 #else 1089 static void parse_ prompt(const char *prmt_ptr)1672 static void parse_and_put_prompt(const char *prmt_ptr) 1090 1673 { 1091 1674 int prmt_len = 0; … … 1093 1676 char flg_not_length = '['; 1094 1677 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]; 1098 1680 char c; 1099 1681 char *pbuf; … … 1101 1683 cmdedit_prmt_len = 0; 1102 1684 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 */ 1106 1690 1107 1691 while (*prmt_ptr) { 1108 pbuf = buf; 1109 pbuf[1] = 0; 1692 char *free_me = NULL; 1693 1694 pbuf = cbuf; 1110 1695 c = *prmt_ptr++; 1111 1696 if (c == '\\') { … … 1115 1700 c = bb_process_escape_sequence(&prmt_ptr); 1116 1701 if (prmt_ptr == cp) { 1117 if (*cp == 0)1702 if (*cp == '\0') 1118 1703 break; 1119 1704 c = *prmt_ptr++; 1705 1120 1706 switch (c) { 1121 # if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR1707 # if ENABLE_USERNAME_OR_HOMEDIR 1122 1708 case 'u': 1123 1709 pbuf = user_buf ? user_buf : (char*)""; 1124 1710 break; 1125 # endif1711 # endif 1126 1712 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'; 1139 1715 break; 1140 1716 case '$': 1141 1717 c = (geteuid() == 0 ? '#' : '$'); 1142 1718 break; 1143 # if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR1719 # if ENABLE_USERNAME_OR_HOMEDIR 1144 1720 case 'w': 1145 pbuf = pwd_buf; 1721 /* /home/user[/something] -> ~[/something] */ 1722 pbuf = cwd_buf; 1146 1723 l = strlen(home_pwd_buf); 1147 1724 if (l != 0 1148 && strncmp(home_pwd_buf, pbuf, l) == 01149 && ( pbuf[l]=='/' || pbuf[l]=='\0')1150 && strlen( pwd_buf+l)<PATH_MAX1725 && strncmp(home_pwd_buf, cwd_buf, l) == 0 1726 && (cwd_buf[l]=='/' || cwd_buf[l]=='\0') 1727 && strlen(cwd_buf + l) < PATH_MAX 1151 1728 ) { 1152 pbuf = buf2; 1153 *pbuf = '~'; 1154 strcpy(pbuf+1, pwd_buf+l); 1729 pbuf = free_me = xasprintf("~%s", cwd_buf + l); 1155 1730 } 1156 1731 break; 1157 # endif1732 # endif 1158 1733 case 'W': 1159 pbuf = pwd_buf;1734 pbuf = cwd_buf; 1160 1735 cp = strrchr(pbuf, '/'); 1161 1736 if (cp != NULL && cp != pbuf) … … 1163 1738 break; 1164 1739 case '!': 1165 pbuf = buf2; 1166 snprintf(buf2, sizeof(buf2), "%d", num_ok_lines); 1740 pbuf = free_me = xasprintf("%d", num_ok_lines); 1167 1741 break; 1168 1742 case 'e': case 'E': /* \e \E = \033 */ 1169 1743 c = '\033'; 1170 1744 break; 1171 case 'x': case 'X': 1745 case 'x': case 'X': { 1746 char buf2[4]; 1172 1747 for (l = 0; l < 3;) { 1173 inth;1748 unsigned h; 1174 1749 buf2[l++] = *prmt_ptr; 1175 buf2[l] = 0;1176 h = strto l(buf2, &pbuf, 16);1750 buf2[l] = '\0'; 1751 h = strtoul(buf2, &pbuf, 16); 1177 1752 if (h > UCHAR_MAX || (pbuf - buf2) < l) { 1178 l--;1753 buf2[--l] = '\0'; 1179 1754 break; 1180 1755 } 1181 1756 prmt_ptr++; 1182 1757 } 1183 buf2[l] = 0; 1184 c = (char)strtol(buf2, NULL, 16); 1758 c = (char)strtoul(buf2, NULL, 16); 1185 1759 if (c == 0) 1186 1760 c = '?'; 1187 pbuf = buf;1761 pbuf = cbuf; 1188 1762 break; 1763 } 1189 1764 case '[': case ']': 1190 1765 if (c == flg_not_length) { 1191 flg_not_length = flg_not_length == '[' ? ']' : '[';1766 flg_not_length = (flg_not_length == '[' ? ']' : '['); 1192 1767 continue; 1193 1768 } 1194 1769 break; 1195 } 1196 } 1197 } 1198 if (pbuf == buf) 1199 *pbuf = c; 1770 } /* switch */ 1771 } /* if */ 1772 } /* if */ 1773 cbuf[0] = c; 1200 1774 cur_prmt_len = strlen(pbuf); 1201 1775 prmt_len += cur_prmt_len; … … 1203 1777 cmdedit_prmt_len += cur_prmt_len; 1204 1778 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); 1208 1784 cmdedit_prompt = prmt_mem_ptr; 1209 1785 put_prompt(); 1210 1786 } 1211 1787 #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;1217 1788 1218 1789 static void cmdedit_setwidth(unsigned w, int redraw_flg) … … 1224 1795 /* redraw */ 1225 1796 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); 1226 fflush (stdout);1797 fflush_all(); 1227 1798 } 1228 1799 } … … 1230 1801 static void win_changed(int nsig) 1231 1802 { 1232 int width; 1803 int sv_errno = errno; 1804 unsigned width; 1233 1805 get_terminal_width_height(0, &width, NULL); 1234 1806 cmdedit_setwidth(width, nsig /* - just a yes/no flag */); 1235 1807 if (nsig == SIGWINCH) 1236 1808 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 1812 static 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 1894 static 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 1248 1905 1249 1906 /* leave out the "vi-mode"-only case labels if vi editing isn't 1250 1907 * configured. */ 1251 #define vi_case(caselabel) USE_FEATURE_EDITING(case caselabel)1908 #define vi_case(caselabel) IF_FEATURE_EDITING_VI(case caselabel) 1252 1909 1253 1910 /* convert uppercase ascii to equivalent control char, for readability */ … … 1255 1912 #define CTRL(a) ((a) & ~0x40) 1256 1913 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'), 1260 1918 * >0 length of input string, including terminating '\n' 1261 1919 */ 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; 1920 int 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 1267 1926 smallint break_out = 0; 1268 1927 #if ENABLE_FEATURE_EDITING_VI 1269 1928 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(); 1272 1951 1273 1952 // FIXME: audit & improve this 1274 1953 if (maxsize > MAX_LINELEN) 1275 1954 maxsize = MAX_LINELEN; 1955 S.maxsize = maxsize; 1276 1956 1277 1957 /* With null flags, no other fields are ever used */ 1278 1958 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 1280 1961 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; 1282 1967 #endif 1283 1968 … … 1285 1970 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ 1286 1971 command_len = 0; 1972 #if ENABLE_UNICODE_SUPPORT 1973 command_ps = xzalloc(maxsize * sizeof(command_ps[0])); 1974 #else 1287 1975 command_ps = command; 1288 1976 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; 1292 1981 new_settings.c_lflag &= ~ICANON; /* unbuffered input */ 1293 1982 /* Turn off echoing and CTRL-C, so we can trap it */ … … 1298 1987 /* Turn off CTRL-C, so we can trap it */ 1299 1988 #ifndef _POSIX_VDISABLE 1300 # define _POSIX_VDISABLE '\0'1989 # define _POSIX_VDISABLE '\0' 1301 1990 #endif 1302 1991 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 1303 setTermSettings(0, (void *)&new_settings);1992 tcsetattr_stdin_TCSANOW(&new_settings); 1304 1993 1305 1994 /* Now initialize things */ 1306 1995 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); 1307 1996 win_changed(0); /* do initial resizing */ 1308 #if ENABLE_ FEATURE_GETUSERNAME_AND_HOMEDIR1997 #if ENABLE_USERNAME_OR_HOMEDIR 1309 1998 { 1310 1999 struct passwd *entry; … … 1312 2001 entry = getpwuid(geteuid()); 1313 2002 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);1319 2003 user_buf = xstrdup(entry->pw_name); 1320 2004 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; 1328 2020 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); 1337 2037 1338 2038 #if ENABLE_FEATURE_EDITING_VI 1339 2039 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 1343 2047 switch (ic) { 1344 2048 case '\n': 1345 2049 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:) 1348 2052 /* Enter */ 1349 2053 goto_new_line(); 1350 2054 break_out = 1; 1351 2055 break; 1352 #if ENABLE_FEATURE_EDITING_FANCY_KEYS1353 2056 case CTRL('A'): 1354 vi_case('0'| vbit:)2057 vi_case('0'|VI_CMDMODE_BIT:) 1355 2058 /* Control-a -- Beginning of line */ 1356 2059 input_backward(cursor); 1357 2060 break; 1358 2061 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; 1387 2067 case CTRL('E'): 1388 vi_case('$'| vbit:)2068 vi_case('$'|VI_CMDMODE_BIT:) 1389 2069 /* Control-e -- End of line */ 1390 input_end();2070 put_till_end_and_adv_cursor(); 1391 2071 break; 1392 2072 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 */ 1401 2078 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 1406 2091 case '\t': 1407 2092 input_tab(&lastWasTab); 1408 2093 break; 1409 1410 #if ENABLE_FEATURE_EDITING_FANCY_KEYS 2094 #endif 1411 2095 case CTRL('K'): 1412 2096 /* Control-k -- clear to end of line */ 1413 command [cursor] = 0;2097 command_ps[cursor] = BB_NUL; 1414 2098 command_len = cursor; 1415 printf( "\033[J");2099 printf(SEQ_CLEAR_TILL_END_OF_SCREEN); 1416 2100 break; 1417 2101 case CTRL('L'): 1418 vi_case(CTRL('L')| vbit:)2102 vi_case(CTRL('L')|VI_CMDMODE_BIT:) 1419 2103 /* Control-l -- clear screen */ 1420 printf( "\033[H");2104 printf(ESC"[H"); /* cursor to top,left */ 1421 2105 redraw(0, command_len - cursor); 1422 2106 break; 1423 #endif1424 1425 2107 #if MAX_HISTORY > 0 1426 2108 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:) 1429 2111 /* Control-n -- Get next command in history */ 1430 2112 if (get_next_history()) … … 1432 2114 break; 1433 2115 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:) 1436 2118 /* 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()) 1439 2120 goto rewrite_line; 1440 } 1441 beep(); 1442 break; 1443 #endif 1444 1445 #if ENABLE_FEATURE_EDITING_FANCY_KEYS 2121 break; 2122 #endif 1446 2123 case CTRL('U'): 1447 vi_case(CTRL('U')| vbit:)2124 vi_case(CTRL('U')|VI_CMDMODE_BIT:) 1448 2125 /* Control-U -- Clear line before cursor */ 1449 2126 if (cursor) { 1450 strcpy(command, command + cursor);1451 2127 command_len -= cursor; 2128 memmove(command_ps, command_ps + cursor, 2129 (command_len + 1) * sizeof(command_ps[0])); 1452 2130 redraw(cmdedit_y, command_len); 1453 2131 } 1454 2132 break; 1455 #endif1456 2133 case CTRL('W'): 1457 vi_case(CTRL('W')| vbit:)2134 vi_case(CTRL('W')|VI_CMDMODE_BIT:) 1458 2135 /* Control-W -- Remove the last word */ 1459 while (cursor > 0 && isspace(command[cursor-1]))2136 while (cursor > 0 && BB_isspace(command_ps[cursor-1])) 1460 2137 input_backspace(); 1461 while (cursor > 0 && ! isspace(command[cursor-1]))2138 while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) 1462 2139 input_backspace(); 1463 2140 break; 1464 2141 1465 2142 #if ENABLE_FEATURE_EDITING_VI 1466 case 'i'| vbit:2143 case 'i'|VI_CMDMODE_BIT: 1467 2144 vi_cmdmode = 0; 1468 2145 break; 1469 case 'I'| vbit:2146 case 'I'|VI_CMDMODE_BIT: 1470 2147 input_backward(cursor); 1471 2148 vi_cmdmode = 0; 1472 2149 break; 1473 case 'a'| vbit:2150 case 'a'|VI_CMDMODE_BIT: 1474 2151 input_forward(); 1475 2152 vi_cmdmode = 0; 1476 2153 break; 1477 case 'A'| vbit:1478 input_end();2154 case 'A'|VI_CMDMODE_BIT: 2155 put_till_end_and_adv_cursor(); 1479 2156 vi_cmdmode = 0; 1480 2157 break; 1481 case 'x'| vbit:2158 case 'x'|VI_CMDMODE_BIT: 1482 2159 input_delete(1); 1483 2160 break; 1484 case 'X'| vbit:2161 case 'X'|VI_CMDMODE_BIT: 1485 2162 if (cursor > 0) { 1486 2163 input_backward(1); … … 1488 2165 } 1489 2166 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: 1509 2186 vi_cmdmode = 0; 1510 2187 /* fall through */ 1511 case 'D'| vbit:2188 case 'D'|VI_CMDMODE_BIT: 1512 2189 goto clear_to_eol; 1513 2190 1514 case 'c'| vbit:2191 case 'c'|VI_CMDMODE_BIT: 1515 2192 vi_cmdmode = 0; 1516 2193 /* fall through */ 1517 case 'd'| vbit: {2194 case 'd'|VI_CMDMODE_BIT: { 1518 2195 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" */ 1525 2201 input_backward(cursor); 1526 2202 goto clear_to_eol; 1527 2203 break; 1528 2204 } 1529 switch (c) { 2205 2206 sc = cursor; 2207 switch (ic) { 1530 2208 case 'w': 1531 2209 case 'W': 1532 2210 case 'e': 1533 2211 case 'E': 1534 switch ( c) {2212 switch (ic) { 1535 2213 case 'w': /* "dw", "cw" */ 1536 vi_word_motion( command,vi_cmdmode);2214 vi_word_motion(vi_cmdmode); 1537 2215 break; 1538 2216 case 'W': /* 'dW', 'cW' */ 1539 vi_Word_motion( command,vi_cmdmode);2217 vi_Word_motion(vi_cmdmode); 1540 2218 break; 1541 2219 case 'e': /* 'de', 'ce' */ 1542 vi_end_motion( command);2220 vi_end_motion(); 1543 2221 input_forward(); 1544 2222 break; 1545 2223 case 'E': /* 'dE', 'cE' */ 1546 vi_End_motion( command);2224 vi_End_motion(); 1547 2225 input_forward(); 1548 2226 break; … … 1555 2233 case 'b': /* "db", "cb" */ 1556 2234 case 'B': /* implemented as B */ 1557 if ( c == 'b')1558 vi_back_motion( command);2235 if (ic == 'b') 2236 vi_back_motion(); 1559 2237 else 1560 vi_Back_motion( command);2238 vi_Back_motion(); 1561 2239 while (sc-- > cursor) 1562 2240 input_delete(1); … … 1566 2244 break; 1567 2245 case '$': /* "d$", "c$" */ 1568 2246 clear_to_eol: 1569 2247 while (cursor < command_len) 1570 2248 input_delete(1); … … 1573 2251 break; 1574 2252 } 1575 case 'p'| vbit:2253 case 'p'|VI_CMDMODE_BIT: 1576 2254 input_forward(); 1577 2255 /* fallthrough */ 1578 case 'P'| vbit:2256 case 'P'|VI_CMDMODE_BIT: 1579 2257 put(); 1580 2258 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) { 1585 2265 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'); 1590 2270 } 1591 2271 break; 1592 #endif /* FEATURE_COMMAND_EDITING_VI */1593 1594 2272 case '\x1b': /* ESC */ 1595 1596 #if ENABLE_FEATURE_EDITING_VI1597 2273 if (state->flags & VI_MODE) { 1598 /* ESC:insert mode --> command mode */2274 /* insert mode --> command mode */ 1599 2275 vi_cmdmode = 1; 1600 2276 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'" */ 1601 2326 break; 1602 2327 } 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; 1635 2340 } 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 #endif1650 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 */1660 2341 input_delete(0); 1661 2342 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 */ 1666 2363 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 */ 1671 2367 break; 1672 default:1673 c = '\0';1674 beep();1675 2368 } 1676 break;1677 1678 default: /* If it's regular input, do the normal thing */1679 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT1680 /* 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 } else1689 #endif1690 1691 #if ENABLE_FEATURE_EDITING_VI1692 if (vi_cmdmode) /* Don't self-insert */1693 break;1694 #endif1695 if (!Isprint(c)) /* Skip non-printable characters */1696 break;1697 1698 if (command_len >= (maxsize - 2)) /* Need to leave space for enter */1699 break;1700 2369 1701 2370 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 */ 1707 2380 int sc = cursor; 1708 2381 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(); 1714 2389 /* to prev x pos + 1 */ 1715 2390 input_backward(cursor - sc); 1716 2391 } 1717 2392 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 1725 2428 1726 2429 if (command_len > 0) … … 1732 2435 } 1733 2436 1734 #if ENABLE_FEATURE_ CLEAN_UP && ENABLE_FEATURE_TAB_COMPLETION2437 #if ENABLE_FEATURE_TAB_COMPLETION 1735 2438 free_tab_completion_data(); 1736 2439 #endif 1737 2440 1738 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT1739 free((char*)cmdedit_prompt);1740 #endif1741 2441 /* restore initial_settings */ 1742 setTermSettings(STDIN_FILENO, (void *)&initial_settings);2442 tcsetattr_stdin_TCSANOW(&initial_settings); 1743 2443 /* restore SIGWINCH handler */ 1744 2444 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 */ 1757 2454 1758 2455 #undef read_line_input 1759 int read_line_input(const char* prompt, char* command, int maxsize)2456 int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) 1760 2457 { 1761 2458 fputs(prompt, stdout); 1762 fflush (stdout);2459 fflush_all(); 1763 2460 fgets(command, maxsize, stdin); 1764 2461 return strlen(command); 1765 2462 } 1766 2463 1767 #endif /* FEATURE_COMMAND_EDITING */2464 #endif /* !FEATURE_EDITING */ 1768 2465 1769 2466 … … 1790 2487 #endif 1791 2488 1792 #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT1793 setlocale(LC_ALL, "");1794 #endif1795 2489 while (1) { 1796 2490 int l; … … 1798 2492 if (l <= 0 || buff[l-1] != '\n') 1799 2493 break; 1800 buff[l-1] = 0;2494 buff[l-1] = '\0'; 1801 2495 printf("*** read_line_input() returned line =%s=\n", buff); 1802 2496 } -
branches/2.2.9/mindi-busybox/libbb/llist.c
r1765 r2725 5 5 * Copyright (C) 2003 Glenn McGrath 6 6 * Copyright (C) 2005 Vladimir Oleynik 7 * Copyright (C) 2005 Bernhard Fischer7 * Copyright (C) 2005 Bernhard Reutner-Fischer 8 8 * Copyright (C) 2006 Rob Landley <rob@landley.net> 9 9 * 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. 11 11 */ 12 12 … … 14 14 15 15 /* Add data to the start of the linked list. */ 16 void llist_add_to(llist_t **old_head, void *data)16 void FAST_FUNC llist_add_to(llist_t **old_head, void *data) 17 17 { 18 18 llist_t *new_head = xmalloc(sizeof(llist_t)); … … 24 24 25 25 /* Add data to the end of the linked list. */ 26 void llist_add_to_end(llist_t **list_head, void *data)26 void FAST_FUNC llist_add_to_end(llist_t **list_head, void *data) 27 27 { 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;*/ 42 33 } 43 34 44 35 /* Remove first element from the list and return it */ 45 void *llist_pop(llist_t **head)36 void* FAST_FUNC llist_pop(llist_t **head) 46 37 { 47 void *data, *next; 38 void *data = NULL; 39 llist_t *temp = *head; 48 40 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 } 57 46 return data; 58 47 } 59 48 60 49 /* Unlink arbitrary given element from the list */ 61 void llist_unlink(llist_t **head, llist_t *elm)50 void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm) 62 51 { 63 llist_t *crt; 64 65 if (!(elm && *head)) 52 if (!elm) 66 53 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; 77 58 } 59 head = &(*head)->link; 78 60 } 79 61 } … … 81 63 /* Recursively free all elements in the linked list. If freeit != NULL 82 64 * call it on each datum in the list */ 83 void llist_free(llist_t *elm, void (*freeit) (void *data))65 void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data)) 84 66 { 85 67 while (elm) { … … 91 73 } 92 74 93 #ifdef UNUSED94 75 /* Reverse list order. */ 95 llist_t *llist_rev(llist_t *list)76 llist_t* FAST_FUNC llist_rev(llist_t *list) 96 77 { 97 78 llist_t *rev = NULL; … … 106 87 return rev; 107 88 } 108 #endif 89 90 llist_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 7 7 * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru> 8 8 * 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. 10 10 */ 11 11 12 #include <sys/param.h> /* MAXHOSTNAMELEN */ 12 #include "libbb.h" 13 /* After libbb.h, since it needs sys/types.h on some systems */ 13 14 #include <sys/utsname.h> 14 #include "libbb.h"15 15 16 16 #define LOGIN " login: " … … 19 19 static const char fmtstr_t[] ALIGN1 = "%H:%M:%S"; 20 20 21 void print_login_issue(const char *issue_file, const char *tty)21 void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) 22 22 { 23 FILE *f d;23 FILE *fp; 24 24 int c; 25 25 char buf[256+1]; … … 31 31 uname(&uts); 32 32 33 puts("\r"); 33 puts("\r"); /* start a new line */ 34 34 35 f d = fopen(issue_file, "r");36 if (!f d)35 fp = fopen_for_read(issue_file); 36 if (!fp) 37 37 return; 38 while ((c = fgetc(f d)) != EOF) {38 while ((c = fgetc(fp)) != EOF) { 39 39 outbuf = buf; 40 40 buf[0] = c; … … 45 45 } 46 46 if (c == '\\' || c == '%') { 47 c = fgetc(f d);47 c = fgetc(fp); 48 48 switch (c) { 49 49 case 's': … … 51 51 break; 52 52 case 'n': 53 case 'h': 53 54 outbuf = uts.nodename; 54 55 break; … … 62 63 outbuf = uts.machine; 63 64 break; 65 /* The field domainname of struct utsname is Linux specific. */ 66 #if defined(__linux__) 64 67 case 'D': 65 68 case 'o': 66 c = getdomainname(buf, sizeof(buf) - 1); 67 buf[c >= 0 ? c : 0] = '\0'; 69 outbuf = uts.domainname; 68 70 break; 71 #endif 69 72 case 'd': 70 73 strftime(buf, sizeof(buf), fmtstr_d, localtime(&t)); … … 72 75 case 't': 73 76 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';78 77 break; 79 78 case 'l': … … 86 85 fputs(outbuf, stdout); 87 86 } 88 fclose(f d);89 fflush (stdout);87 fclose(fp); 88 fflush_all(); 90 89 } 91 90 92 void print_login_prompt(void)91 void FAST_FUNC print_login_prompt(void) 93 92 { 94 char buf[MAXHOSTNAMELEN+1];93 char *hostname = safe_gethostname(); 95 94 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 } 98 100 99 fputs(LOGIN, stdout); 100 fflush(stdout); 101 /* Clear dangerous stuff, set PATH */ 102 static 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 117 int 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! */ 101 132 } -
branches/2.2.9/mindi-busybox/libbb/loop.c
r1765 r2725 6 6 * Copyright (C) 2005 by Rob Landley <rob@landley.net> 7 7 * 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. 9 9 */ 10 #include "libbb.h" 11 #include <linux/version.h> 10 12 11 #i nclude "libbb.h"13 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) 12 14 13 15 /* 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> 17 19 typedef 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 20 24 21 25 /* 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 31 34 typedef struct { 32 35 int lo_number; … … 45 48 #endif 46 49 47 char *query_loop(const char *device)50 char* FAST_FUNC query_loop(const char *device) 48 51 { 49 52 int fd; 50 53 bb_loop_info loopinfo; 51 char *dev = 0;54 char *dev = NULL; 52 55 53 56 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 } 59 64 60 65 return dev; 61 66 } 62 67 63 64 int del_loop(const char *device) 68 int FAST_FUNC del_loop(const char *device) 65 69 { 66 70 int fd, rc; 67 71 68 72 fd = open(device, O_RDONLY); 69 if (fd < 0) return 1; 73 if (fd < 0) 74 return 1; 70 75 rc = ioctl(fd, LOOP_CLR_FD, 0); 71 76 close(fd); … … 80 85 file/offset if it finds one. 81 86 */ 82 int set_loop(char **device, const char *file, unsigned long long offset)87 int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset) 83 88 { 84 89 char dev[LOOP_NAMESIZE]; … … 99 104 100 105 /* 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++) { 103 109 sprintf(dev, LOOP_FORMAT, i); 104 110 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. */ 107 122 rc = -ENOENT; 108 123 break; 109 124 } 125 try_to_open: 110 126 /* Open the sucker and check its loopiness. */ 111 127 dfd = open(try, mode); … … 125 141 loopinfo.lo_offset = offset; 126 142 /* 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) 129 145 rc = 0; 130 146 else … … 137 153 without using losetup manually is problematic.) 138 154 */ 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 ) { 141 159 rc = -1; 142 160 } … … 146 164 } 147 165 close(ffd); 148 if ( !rc) {166 if (rc == 0) { 149 167 if (!*device) 150 168 *device = xstrdup(dev); -
branches/2.2.9/mindi-busybox/libbb/make_directory.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 27 27 /* This function is used from NOFORK applets. It must not allocate anything */ 28 28 29 int bb_make_directory(char *path, long mode, int flags)29 int FAST_FUNC bb_make_directory(char *path, long mode, int flags) 30 30 { 31 mode_t mask; 31 mode_t cur_mask; 32 mode_t org_mask; 32 33 const char *fail_msg; 33 char *s = path;34 char *s; 34 35 char c; 35 36 struct stat st; 36 37 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; 46 41 47 do { 48 c = 0; 42 org_mask = cur_mask = (mode_t)-1L; 43 s = path; 44 while (1) { 45 c = '\0'; 49 46 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 */ 52 49 while (*s) { 53 50 if (*s == '/') { … … 55 52 ++s; 56 53 } while (*s == '/'); 57 c = *s; 58 *s = 0; /* and replace it with nul.*/54 c = *s; /* Save the current char */ 55 *s = '\0'; /* and replace it with nul */ 59 56 break; 60 57 } … … 63 60 } 64 61 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 65 86 if (mkdir(path, 0777) < 0) { 66 87 /* 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 ) { 71 93 fail_msg = "create"; 72 umask(mask);73 94 break; 74 95 } 75 96 /* Since the directory exists, don't attempt to change 76 97 * permissions if it was the full target. Note that 77 * this is not an error condit on. */98 * this is not an error condition. */ 78 99 if (!c) { 79 umask(mask); 80 return 0; 100 goto ret0; 81 101 } 82 102 } 83 103 84 104 if (!c) { 85 /* Done. If necessary, update dperms on the newly105 /* Done. If necessary, update perms on the newly 86 106 * 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)) { 90 109 fail_msg = "set permissions of"; 91 110 break; 92 111 } 93 return0;112 goto ret0; 94 113 } 95 114 96 /* Remove any inserted nul from the path (recursive mode) .*/115 /* Remove any inserted nul from the path (recursive mode) */ 97 116 *s = c; 117 } /* while (1) */ 98 118 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; 103 129 } -
branches/2.2.9/mindi-busybox/libbb/makedev.c
r1765 r2725 2 2 * Utility routines. 3 3 * 4 * Copyright (C) 2006 Den is Vlasenko4 * Copyright (C) 2006 Denys Vlasenko 5 5 * 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. 7 7 */ 8 8 9 9 /* We do not include libbb.h - #define makedev() is there! */ 10 #include "platform.h" 10 11 #include <features.h> 11 12 #include <sys/sysmacros.h> … … 16 17 17 18 /* 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)19 unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor); 20 unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor) 20 21 { 21 22 return makedev(major, minor); -
branches/2.2.9/mindi-busybox/libbb/match_fstype.c
r1765 r2725 6 6 * mount -at ,noddy 7 7 * 8 * Returns 0 for a match, otherwise -18 * Returns 1 for a match, otherwise 0 9 9 * 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. 11 11 */ 12 12 13 13 #include "libbb.h" 14 14 15 int match_fstype(const struct mntent *mt, const char *fstype)15 int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) 16 16 { 17 int no = 0;17 int match = 1; 18 18 int len; 19 19 20 if (! mt)21 return -1;20 if (!t_fstype) 21 return match; 22 22 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; 29 26 } 30 27 31 28 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] == ',') 35 32 ) { 36 return no;33 return match; 37 34 } 38 fstype = strchr(fstype, ','); 39 if (fstype) 40 fstype++; 35 t_fstype = strchr(t_fstype, ','); 36 if (!t_fstype) 37 break; 38 t_fstype++; 41 39 } 42 40 43 return -(no + 1);41 return !match; 44 42 } -
branches/2.2.9/mindi-busybox/libbb/messages.c
r1765 r2725 3 3 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 4 4 * 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. 6 6 */ 7 7 8 8 #include "libbb.h" 9 9 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 */ 10 16 #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 13 20 #define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")" 14 #endif 21 15 22 const char bb_banner[] ALIGN1 = BANNER; 23 16 24 17 25 const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted"; 18 26 const 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";21 27 const char bb_msg_unknown[] ALIGN1 = "(unknown)"; 22 28 const 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?)"; 29 const char bb_msg_perm_denied_are_you_root[] ALIGN1 = "permission denied (are you root?)"; 30 const char bb_msg_you_must_be_root[] ALIGN1 = "you must be root"; 24 31 const char bb_msg_requires_arg[] ALIGN1 = "%s requires an argument"; 25 32 const char bb_msg_invalid_arg[] ALIGN1 = "invalid argument '%s' to '%s'"; … … 27 34 const char bb_msg_standard_output[] ALIGN1 = "standard output"; 28 35 29 const char bb_str_default[] ALIGN1 = "default";30 36 const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; 31 37 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";38 38 const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; 39 39 const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 40 40 /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 41 41 * 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"; 42 const char bb_PATH_root_path[] ALIGN1 = 43 "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH; 43 44 44 45 45 const int const_int_0;46 46 const int const_int_1 = 1; 47 /* explicitly = 0, otherwise gcc may make it a common variable 48 * and it will end up in bss */ 49 const int const_int_0 = 0; 47 50 48 51 #include <utmp.h> … … 50 53 const char bb_path_wtmp_file[] ALIGN1 = 51 54 #if defined _PATH_WTMP 52 _PATH_WTMP;55 _PATH_WTMP; 53 56 #elif defined WTMP_FILE 54 WTMP_FILE;57 WTMP_FILE; 55 58 #else 56 # 59 #error unknown path to wtmp file 57 60 #endif 58 61 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. */ 65 char bb_common_bufsiz1[COMMON_BUFSIZE] ALIGNED(sizeof(long long)); -
branches/2.2.9/mindi-busybox/libbb/mode_string.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 49 49 * and 'B' types don't appear to be available on linux. So I removed them. */ 50 50 static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???"; 51 /* 51 /***************************************** 0123456789abcdef */ 52 52 static const char mode_chars[7] ALIGN1 = "rwxSTst"; 53 53 54 const char *bb_mode_string(mode_t mode)54 const char* FAST_FUNC bb_mode_string(mode_t mode) 55 55 { 56 56 static char buf[12]; … … 89 89 * and 'B' types don't appear to be available on linux. So I removed them. */ 90 90 static const char type_chars[16] = "?pc?d?b?-?l?s???"; 91 /* 91 /********************************** 0123456789abcdef */ 92 92 static const char mode_chars[7] = "rwxSTst"; 93 93 94 const char *bb_mode_string(mode_t mode)94 const char* FAST_FUNC bb_mode_string(mode_t mode) 95 95 { 96 96 static char buf[12]; -
branches/2.2.9/mindi-busybox/libbb/mtab.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 12 12 13 13 #if ENABLE_FEATURE_MTAB_SUPPORT 14 void erase_mtab(const char *name)14 void FAST_FUNC erase_mtab(const char *name) 15 15 { 16 struct mntent *entries = NULL;17 int i, count = 0;16 struct mntent *entries; 17 int i, count; 18 18 FILE *mountTable; 19 19 struct mntent *m; … … 27 27 } 28 28 29 entries = NULL; 30 count = 0; 29 31 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++; 38 40 } 39 41 endmntent(mountTable); 40 42 43 //TODO: make update atomic 41 44 mountTable = setmntent(bb_path_mtab_file, "w"); 42 45 if (mountTable) { -
branches/2.2.9/mindi-busybox/libbb/obscure.c
r1765 r2725 5 5 * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it> 6 6 * 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. 8 8 */ 9 9 … … 46 46 static int string_checker_helper(const char *p1, const char *p2) 47 47 { 48 /* as sub-string */ 49 if (strcasestr(p2, p1) != NULL 50 /* invert in case haystack is shorter than needle */ 51 || strcasestr(p1, p2) != NULL 48 52 /* 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 ) { 54 55 return 1; 56 } 55 57 return 0; 56 58 } … … 58 60 static int string_checker(const char *p1, const char *p2) 59 61 { 60 int size ;62 int size, i; 61 63 /* check string */ 62 64 int ret = string_checker_helper(p1, p2); 63 /* Make our own copy */65 /* make our own copy */ 64 66 char *p = xstrdup(p1); 67 65 68 /* 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 */ 67 74 68 while (size--) {69 *p = p1[size];70 p++;71 }72 /* restore pointer */73 p -= strlen(p1);74 75 /* check reversed string */ 75 76 ret |= string_checker_helper(p, p2); 77 76 78 /* clean up */ 77 memset(p, 0, s trlen(p1));79 memset(p, 0, size); 78 80 free(p); 81 79 82 return ret; 80 83 } 81 84 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 86 93 87 94 static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw) 88 95 { 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; 95 101 const char *p; 96 char hostname[255];102 char *hostname; 97 103 98 104 /* size */ … … 105 111 } 106 112 /* 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)) { 108 114 return "similar to gecos"; 109 115 } 110 116 /* 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"; 117 122 118 123 /* Should / Must contain a mix of: */ 124 mixed = 0; 119 125 for (i = 0; i < length; i++) { 120 126 if (islower(new_p[i])) { /* a-z */ … … 127 133 mixed |= SPECIAL; 128 134 } 129 /* More than 50% similar characters ?*/135 /* Count i'th char */ 130 136 c = 0; 131 137 p = new_p; 132 138 while (1) { 133 if ((p = strchr(p, new_p[i])) == NULL) { 139 p = strchr(p, new_p[i]); 140 if (p == NULL) { 134 141 break; 135 142 } 136 143 c++; 137 if (!++p) { 138 break; /* move past the matched char if possible */ 144 p++; 145 if (!*p) { 146 break; 139 147 } 140 148 } 141 142 if (c >= (length / 2)) {149 /* More than 50% similar characters ? */ 150 if (c*2 >= length) { 143 151 return "too many similar characters"; 144 152 } 145 153 } 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; 148 159 if (length < size) 149 160 return "too weak"; 150 161 151 if (old_p && old_p[0] != '\0') {162 if (old_p && old_p[0]) { 152 163 /* check vs. old password */ 153 164 if (string_checker(new_p, old_p)) { … … 155 166 } 156 167 } 168 157 169 return NULL; 158 170 } 159 171 160 int obscure(const char *old, const char *newval, const struct passwd *pw)172 int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw) 161 173 { 162 174 const char *msg; -
branches/2.2.9/mindi-busybox/libbb/parse_mode.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 16 16 #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) 17 17 18 int bb_parse_mode(const char *s, mode_t *current_mode)18 int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) 19 19 { 20 20 static const mode_t who_mask[] = { … … 41 41 char op; 42 42 43 if (( (unsigned int)(*s - '0')) < 8) {43 if ((unsigned char)(*s - '0') < 8) { 44 44 unsigned long tmp; 45 45 char *e; … … 58 58 * We treat an empty mode as no change to perms. */ 59 59 60 while (*s) { 61 if (*s == ',') { 60 while (*s) { /* Process clauses. */ 61 if (*s == ',') { /* We allow empty clauses. */ 62 62 ++s; 63 63 continue; … … 78 78 } while (*++p); 79 79 80 do { 80 do { /* Process action list. */ 81 81 if ((*s != '+') && (*s != '-')) { 82 82 if (*s != '=') { … … 94 94 95 95 /* Check for permcopy. */ 96 p = who_chars + 1; 96 p = who_chars + 1; /* Skip 'a' entry. */ 97 97 do { 98 98 if (*p == *s) { … … 129 129 } while (*++p); 130 130 GOT_ACTION: 131 if (permlist) { 131 if (permlist) { /* The permlist was nonempty. */ 132 132 mode_t tmp = wholist; 133 133 if (!wholist) { -
branches/2.2.9/mindi-busybox/libbb/perror_msg.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 12 void bb_perror_msg(const char *s, ...)11 void FAST_FUNC bb_perror_msg(const char *s, ...) 13 12 { 14 13 va_list p; … … 19 18 va_end(p); 20 19 } 20 21 void 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 32 void FAST_FUNC bb_simple_perror_msg(const char *s) 33 { 34 bb_perror_msg("%s", s); 35 } 36 37 void 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 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 12 12 * instead of including libbb.h */ 13 13 //#include "libbb.h" 14 extern void bb_perror_msg(const char *s, ...); 14 #include "platform.h" 15 extern void bb_perror_msg(const char *s, ...) FAST_FUNC; 15 16 16 17 /* suppress gcc "no previous prototype" warning */ 17 void bb_perror_nomsg(void);18 void bb_perror_nomsg(void)18 void FAST_FUNC bb_perror_nomsg(void); 19 void FAST_FUNC bb_perror_nomsg(void) 19 20 { 20 21 bb_perror_msg(0); -
branches/2.2.9/mindi-busybox/libbb/perror_nomsg_and_die.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 12 12 * instead of including libbb.h */ 13 13 //#include "libbb.h" 14 extern void bb_perror_msg_and_die(const char *s, ...); 14 #include "platform.h" 15 extern void bb_perror_msg_and_die(const char *s, ...) FAST_FUNC; 15 16 16 17 /* suppress gcc "no previous prototype" warning */ 17 void bb_perror_nomsg_and_die(void);18 void bb_perror_nomsg_and_die(void)18 void FAST_FUNC bb_perror_nomsg_and_die(void); 19 void FAST_FUNC bb_perror_nomsg_and_die(void) 19 20 { 20 21 bb_perror_msg_and_die(0); -
branches/2.2.9/mindi-busybox/libbb/pidfile.c
r1765 r2725 5 5 * Copyright (C) 2007 by Stephane Billiart <stephane.billiart@gmail.com> 6 6 * 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. 8 8 */ 9 9 … … 14 14 smallint wrote_pidfile; 15 15 16 void write_pidfile(const char *path)16 void FAST_FUNC write_pidfile(const char *path) 17 17 { 18 18 int pid_fd; -
branches/2.2.9/mindi-busybox/libbb/process_escape_sequence.c
r1765 r2725 6 6 * and Vladimir Oleynik <dzo@simtreas.ru> 7 7 * 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. 9 9 */ 10 10 … … 17 17 #define _tolower(X) ((X)|((char) 0x20)) 18 18 19 char bb_process_escape_sequence(const char **ptr)19 char FAST_FUNC bb_process_escape_sequence(const char **ptr) 20 20 { 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;26 21 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; 32 25 33 26 num_digits = n = 0; … … 35 28 q = *ptr; 36 29 37 #ifdef WANT_HEX_ESCAPES 38 if (*q == 'x') { 30 if (WANT_HEX_ESCAPES && *q == 'x') { 39 31 ++q; 40 32 base = 16; 41 33 ++num_digits; 42 34 } 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); 43 47 #endif 44 45 do {46 d = (unsigned char)(*q) - '0';47 #ifdef WANT_HEX_ESCAPES48 if (d >= 10) {49 d = (unsigned char)(_tolower(*q)) - 'a' + 10;50 }51 #endif52 53 48 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 } 58 56 } 59 #endif60 57 break; 61 58 } … … 70 67 } while (++num_digits < 3); 71 68 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; 74 82 do { 75 83 if (*p == *q) { … … 77 85 break; 78 86 } 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]; 81 93 } 82 94 … … 85 97 return (char) n; 86 98 } 99 100 char* 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 7 7 * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp> 8 8 * 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. 10 10 */ 11 11 … … 14 14 15 15 typedef struct unsigned_to_name_map_t { 16 unsignedid;16 long id; 17 17 char name[USERNAME_MAX_SIZE]; 18 18 } unsigned_to_name_map_t; … … 31 31 cp->size = 0; 32 32 } 33 void clear_username_cache(void)33 void FAST_FUNC clear_username_cache(void) 34 34 { 35 35 clear_cache(&username); … … 47 47 return i; 48 48 i = cp->size++; 49 cp->cache = xrealloc (cp->cache, cp->size * sizeof(*cp->cache));49 cp->cache = xrealloc_vector(cp->cache, 2, i); 50 50 cp->cache[i++].id = id; 51 51 return -i; … … 53 53 #endif 54 54 55 typedef char* ug_func(char *name, int bufsize, long uid); 56 static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)55 static char* get_cached(cache_t *cp, long id, 56 char* FAST_FUNC x2x_utoa(long id)) 57 57 { 58 58 int i; … … 61 61 return cp->cache[i].name; 62 62 i = cp->size++; 63 cp->cache = xrealloc (cp->cache, cp->size * sizeof(*cp->cache));63 cp->cache = xrealloc_vector(cp->cache, 2, i); 64 64 cp->cache[i].id = id; 65 65 /* 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)); 67 67 return cp->cache[i].name; 68 68 } 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);69 const char* FAST_FUNC get_cached_username(uid_t uid) 70 { 71 return get_cached(&username, uid, uid2uname_utoa); 72 } 73 const char* FAST_FUNC get_cached_groupname(gid_t gid) 74 { 75 return get_cached(&groupname, gid, gid2group_utoa); 76 76 } 77 77 … … 94 94 } 95 95 96 procps_status_t *alloc_procps_scan(int flags) 97 { 96 static procps_status_t* FAST_FUNC alloc_procps_scan(void) 97 { 98 unsigned n = getpagesize(); 98 99 procps_status_t* sp = xzalloc(sizeof(procps_status_t)); 99 100 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; 100 107 return sp; 101 108 } 102 109 103 void free_procps_scan(procps_status_t* sp)110 void FAST_FUNC free_procps_scan(procps_status_t* sp) 104 111 { 105 112 closedir(sp->dir); 113 #if ENABLE_FEATURE_SHOW_THREADS 114 if (sp->task_dir) 115 closedir(sp->task_dir); 116 #endif 106 117 free(sp->argv0); 107 USE_SELINUX(free(sp->context);) 118 free(sp->exe); 119 IF_SELINUX(free(sp->context);) 108 120 free(sp); 109 121 } 110 122 111 #if ENABLE_FEATURE_FAST_TOP 123 #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 124 static 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 112 143 /* We cut a lot of corners here for speed */ 113 144 static unsigned long fast_strtoul_10(char **endptr) … … 123 154 return n; 124 155 } 156 157 # if ENABLE_FEATURE_FAST_TOP 158 static 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 125 168 static char *skip_fields(char *str, int count) 126 169 { … … 134 177 #endif 135 178 179 #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 180 int 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 136 284 void BUG_comm_size(void); 137 procps_status_t *procps_scan(procps_status_t* sp, int flags)285 procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) 138 286 { 139 287 struct dirent *entry; … … 147 295 148 296 if (!sp) 149 sp = alloc_procps_scan( flags);297 sp = alloc_procps_scan(); 150 298 151 299 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 152 309 entry = readdir(sp->dir); 153 310 if (entry == NULL) { … … 155 312 return NULL; 156 313 } 314 IF_FEATURE_SHOW_THREADS(got_entry:) 157 315 pid = bb_strtou(entry->d_name, NULL, 10); 158 316 if (errno) 159 317 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 */ 164 334 165 335 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz)); 166 336 167 337 sp->pid = pid; 168 if (!(flags & ~PSSCAN_PID)) break; 338 if (!(flags & ~PSSCAN_PID)) 339 break; /* we needed only pid, we got it */ 169 340 170 341 #if ENABLE_SELINUX … … 175 346 #endif 176 347 177 filename_tail = filename + sprintf(filename, "/proc/% d", pid);348 filename_tail = filename + sprintf(filename, "/proc/%u/", pid); 178 349 179 350 if (flags & PSSCAN_UIDGID) { 180 351 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 */ 183 354 sp->uid = sb.st_uid; 184 355 sp->gid = sb.st_gid; … … 191 362 unsigned long vsz, rss; 192 363 #endif 193 194 364 /* see proc(5) for some details on this */ 195 strcpy(filename_tail, " /stat");365 strcpy(filename_tail, "stat"); 196 366 n = read_to_buf(filename, buf); 197 367 if (n < 0) 198 break;368 continue; /* process probably exited */ 199 369 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ 200 370 /*if (!cp || cp[1] != ' ') 201 break;*/371 continue;*/ 202 372 cp[0] = '\0'; 203 373 if (sizeof(sp->comm) < 16) … … 215 385 "%*s %*s %*s " /* cutime, cstime, priority */ 216 386 "%ld " /* nice */ 217 "%*s %*s %*s " /* timeout, it_real_value, start_time */ 387 "%*s %*s " /* timeout, it_real_value */ 388 "%lu " /* start_time */ 218 389 "%lu " /* vsize */ 219 390 "%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 223 397 , 224 398 sp->state, &sp->ppid, … … 226 400 &sp->utime, &sp->stime, 227 401 &tasknice, 402 &sp->start_time, 228 403 &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; 234 421 sp->tty_major = (tty >> 8) & 0xfff; 235 422 sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00); … … 249 436 sp->stime = fast_strtoul_10(&cp); 250 437 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; 255 457 #endif 256 458 … … 265 467 else 266 468 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 */ 270 509 #if 0 /* PSSCAN_CMD is not used */ 271 510 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"); 281 516 /* TODO: to get rid of size limits, read into malloc buf, 282 517 * then realloc it down to real size. */ … … 296 531 } 297 532 #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"); 304 537 n = read_to_buf(filename, buf); 305 538 if (n <= 0) 306 539 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; 308 547 sp->argv0 = xstrdup(buf); 548 } 309 549 } 310 550 #endif 311 551 break; 312 } 552 } /* for (;;) */ 553 313 554 return sp; 314 555 } 315 556 316 void read_cmdline(char *buf, int col, unsigned pid, const char *comm)317 { 318 ssize_t sz;557 void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) 558 { 559 int sz; 319 560 char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; 320 561 321 562 sprintf(filename, "/proc/%u/cmdline", pid); 322 sz = open_read_close(filename, buf, col );563 sz = open_read_close(filename, buf, col - 1); 323 564 if (sz > 0) { 324 565 buf[sz] = '\0'; 325 while (--sz >= 0) 566 while (--sz >= 0 && buf[sz] == '\0') 567 continue; 568 do { 326 569 if ((unsigned char)(buf[sz]) < ' ') 327 570 buf[sz] = ' '; 571 } while (--sz >= 0); 328 572 } else { 329 573 snprintf(buf, col, "[%s]", comm); -
branches/2.2.9/mindi-busybox/libbb/pw_encrypt.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * Utility routine .3 * Utility routines. 4 4 * 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 #include <crypt.h>12 11 13 char *pw_encrypt(const char *clear, const char *salt) 12 /* static const uint8_t ascii64[] = 13 * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 14 */ 15 16 static int i64c(int i) 14 17 { 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 } 17 29 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); 30 int 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 52 static char* 53 to64(char *s, unsigned v, int n) 54 { 55 while (--n >= 0) { 56 /* *s++ = ascii64[v & 0x3f]; */ 57 *s++ = i64c(v); 58 v >>= 6; 21 59 } 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" 22 72 #endif 23 73 24 free(cipher); 25 cipher = xstrdup(crypt(clear, salt)); 26 return cipher; 74 /* Other advanced crypt ids (TODO?): */ 75 /* $2$ or $2a$: Blowfish */ 76 77 static struct const_des_ctx *des_cctx; 78 static struct des_ctx *des_ctx; 79 80 /* my_crypt returns malloc'ed data */ 81 static 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); 27 97 } 98 99 /* So far nobody wants to have it public */ 100 static void my_crypt_cleanup(void) 101 { 102 free(des_cctx); 103 free(des_ctx); 104 des_cctx = NULL; 105 des_ctx = NULL; 106 } 107 108 char* 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 122 char* 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 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 12 ssize_t safe_read(int fd, void *buf, size_t count)11 ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) 13 12 { 14 13 ssize_t n; … … 27 26 * A short read is returned on an end of file. 28 27 */ 29 ssize_t full_read(int fd, void *buf, size_t len)28 ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len) 30 29 { 31 30 ssize_t cc; … … 37 36 cc = safe_read(fd, buf, len); 38 37 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 } 41 46 if (cc == 0) 42 47 break; … … 49 54 } 50 55 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) 56 ssize_t FAST_FUNC read_close(int fd, void *buf, size_t size) 126 57 { 127 58 /*int e;*/ … … 133 64 } 134 65 135 ssize_t open_read_close(const char *filename, void *buf, size_t size)66 ssize_t FAST_FUNC open_read_close(const char *filename, void *buf, size_t size) 136 67 { 137 68 int fd = open(filename, O_RDONLY); … … 140 71 return read_close(fd, buf, size); 141 72 } 142 143 // Read (potentially big) files in one go. File size is estimated by144 // 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 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 23 23 */ 24 24 25 static int true_action(const char *fileName, struct stat *statbuf, 26 void* userData, int depth) 25 static 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) 27 29 { 28 30 return TRUE; … … 33 35 * (fileAction/dirAction will be called on each file). 34 36 * 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. 38 39 * 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. 40 52 * 0: lstat(statbuf). Calls fileAction on link name even if points to dir. 41 53 * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. 42 54 */ 43 55 44 int recursive_action(const char *fileName,56 int FAST_FUNC recursive_action(const char *fileName, 45 57 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), 48 60 void* userData, 49 61 unsigned depth) 50 62 { 51 63 struct stat statbuf; 64 unsigned follow; 52 65 int status; 53 66 DIR *dir; … … 57 70 if (!dirAction) dirAction = true_action; 58 71 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); 62 77 if (status < 0) { 63 78 #ifdef DEBUG_RECURS_ACTION 64 79 bb_error_msg("status=%d flags=%x", status, flags); 65 80 #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 } 66 88 goto done_nak_warn; 67 89 } … … 104 126 if (nextFile == NULL) 105 127 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)) 108 131 status = FALSE; 132 // s = recursive_action(nextFile, flags, fileAction, dirAction, 133 // userData, depth + 1); 109 134 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; 110 142 } 111 143 closedir(dir); … … 116 148 } 117 149 118 if (!status) 119 return FALSE; 120 return TRUE; 150 return status; 121 151 122 152 done_nak_warn: 123 bb_perror_msg("%s", fileName); 153 if (!(flags & ACTION_QUIET)) 154 bb_simple_perror_msg(fileName); 124 155 return FALSE; 125 156 } -
branches/2.2.9/mindi-busybox/libbb/remove_file.c
r1765 r2725 5 5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu> 6 6 * 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. 8 8 */ 9 9 … … 12 12 /* Used from NOFORK applets. Must not allocate anything */ 13 13 14 int remove_file(const char *path, int flags)14 int FAST_FUNC remove_file(const char *path, int flags) 15 15 { 16 16 struct stat path_stat; … … 18 18 if (lstat(path, &path_stat) < 0) { 19 19 if (errno != ENOENT) { 20 bb_perror_msg("can not stat '%s'", path);20 bb_perror_msg("can't stat '%s'", path); 21 21 return -1; 22 22 } 23 23 if (!(flags & FILEUTILS_FORCE)) { 24 bb_perror_msg("can not remove '%s'", path);24 bb_perror_msg("can't remove '%s'", path); 25 25 return -1; 26 26 } … … 64 64 65 65 if (closedir(dp) < 0) { 66 bb_perror_msg("can not close '%s'", path);66 bb_perror_msg("can't close '%s'", path); 67 67 return -1; 68 68 } … … 75 75 76 76 if (rmdir(path) < 0) { 77 bb_perror_msg("can not remove '%s'", path);77 bb_perror_msg("can't remove '%s'", path); 78 78 return -1; 79 79 } … … 83 83 84 84 /* !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)) 87 89 || (flags & FILEUTILS_INTERACTIVE) 88 90 ) { … … 93 95 94 96 if (unlink(path) < 0) { 95 bb_perror_msg("can not remove '%s'", path);97 bb_perror_msg("can't remove '%s'", path); 96 98 return -1; 97 99 } -
branches/2.2.9/mindi-busybox/libbb/run_shell.c
r1765 r2725 37 37 static security_context_t current_sid; 38 38 39 void 40 renew_current_security_context(void) 39 void FAST_FUNC renew_current_security_context(void) 41 40 { 42 if (current_sid) 43 freecon(current_sid); /* Release old context */ 41 freecon(current_sid); /* Release old context */ 44 42 getcon(¤t_sid); /* update */ 45 43 } 46 void 47 set_current_security_context(security_context_t sid) 44 void FAST_FUNC set_current_security_context(security_context_t sid) 48 45 { 49 if (current_sid) 50 freecon(current_sid); /* Release old context */ 46 freecon(current_sid); /* Release old context */ 51 47 current_sid = sid; 52 48 } … … 54 50 #endif 55 51 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. */ 56 void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) 62 57 { 63 58 const char **args; 64 int argno = 1;59 int argno; 65 60 int additional_args_cnt = 0; 66 61 … … 70 65 args = xmalloc(sizeof(char*) * (4 + additional_args_cnt)); 71 66 72 args[0] = bb_get_last_path_component(xstrdup(shell)); 67 if (!shell || !shell[0]) 68 shell = DEFAULT_SHELL; 73 69 70 args[0] = bb_get_last_path_component_nostrip(shell); 74 71 if (loginshell) 75 72 args[0] = xasprintf("-%s", args[0]); 76 73 argno = 1; 77 74 if (command) { 78 75 args[argno++] = "-c"; … … 84 81 } 85 82 args[argno] = NULL; 83 86 84 #if ENABLE_SELINUX 87 if (current_sid && !setexeccon(current_sid)) { 85 if (current_sid) 86 setexeccon(current_sid); 87 if (ENABLE_FEATURE_CLEAN_UP) 88 88 freecon(current_sid); 89 execve(shell, (char **) args, environ);90 } else91 89 #endif 92 90 execv(shell, (char **) args); 93 bb_perror_msg_and_die("can not run %s", shell);91 bb_perror_msg_and_die("can't execute '%s'", shell); 94 92 } -
branches/2.2.9/mindi-busybox/libbb/safe_strncpy.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 11 11 12 12 /* Like strncpy but make sure the resulting string is always 0 terminated. */ 13 char *safe_strncpy(char *dst, const char *src, size_t size)13 char* FAST_FUNC safe_strncpy(char *dst, const char *src, size_t size) 14 14 { 15 15 if (!size) return dst; … … 17 17 return strncpy(dst, src, size); 18 18 } 19 20 /* Like strcpy but can copy overlapping strings. */ 21 void 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 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 12 ssize_t safe_write(int fd, const void *buf, size_t count)12 ssize_t FAST_FUNC safe_write(int fd, const void *buf, size_t count) 13 13 { 14 14 ssize_t n; -
branches/2.2.9/mindi-busybox/libbb/selinux_common.c
r1765 r2725 4 4 * 5 5 * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp> 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 6 8 */ 7 9 #include "libbb.h" 8 10 #include <selinux/context.h> 9 11 10 context_t set_security_context_component(security_context_t cur_context,12 context_t FAST_FUNC set_security_context_component(security_context_t cur_context, 11 13 char *user, char *role, char *type, char *range) 12 14 { … … 30 32 } 31 33 32 void setfscreatecon_or_die(security_context_t scontext)34 void FAST_FUNC setfscreatecon_or_die(security_context_t scontext) 33 35 { 34 36 if (setfscreatecon(scontext) < 0) { 35 37 /* Can be NULL. All known printf implementations 36 38 * display "(null)", "<null>" etc */ 37 bb_perror_msg_and_die("can not set default "39 bb_perror_msg_and_die("can't set default " 38 40 "file creation context to %s", scontext); 39 41 } 40 42 } 43 44 void 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 31 31 #include "libbb.h" 32 32 33 void setup_environment(const char *shell, int loginshell, int changeenv, const struct passwd *pw)33 void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw) 34 34 { 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) { 36 43 const char *term; 37 44 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. */ 51 47 term = getenv("TERM"); 52 48 clearenv(); 53 49 if (term) 54 50 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) { 62 59 /* 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. */ 66 61 if (pw->pw_uid) { 62 shortcut: 67 63 xsetenv("USER", pw->pw_name); 68 64 xsetenv("LOGNAME", pw->pw_name); 69 65 } 66 xsetenv("HOME", pw->pw_dir); 67 xsetenv("SHELL", shell); 70 68 } 71 69 } -
branches/2.2.9/mindi-busybox/libbb/simplify_path.c
r1765 r2725 5 5 * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 12 char *bb_simplify_path(const char *path)11 char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) 13 12 { 14 char *s, * start, *p;13 char *s, *p; 15 14 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 }23 15 p = s = start; 24 25 16 do { 26 17 if (*p == '/') { 27 if (*s == '/') { 18 if (*s == '/') { /* skip duplicate (or initial) slash */ 28 19 continue; 29 20 } 30 21 if (*s == '.') { 31 if (s[1] == '/' || !s[1]) { 22 if (s[1] == '/' || !s[1]) { /* remove extra '.' */ 32 23 continue; 33 24 } … … 35 26 ++s; 36 27 if (p > start) { 37 while (*--p != '/') 28 while (*--p != '/') /* omit previous dir */ 38 29 continue; 39 30 } … … 45 36 } while (*++s); 46 37 47 if ((p == start) || (*p != '/')) { 48 ++p; 38 if ((p == start) || (*p != '/')) { /* not a trailing slash */ 39 ++p; /* so keep last character */ 49 40 } 50 *p = 0; 41 *p = '\0'; 42 return p; 43 } 51 44 52 return start; 45 char* 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; 53 59 } -
branches/2.2.9/mindi-busybox/libbb/skip_whitespace.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 12 char *skip_whitespace(const char *s)12 char* FAST_FUNC skip_whitespace(const char *s) 13 13 { 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++; 16 22 17 23 return (char *) s; 18 24 } 19 25 20 char *skip_non_whitespace(const char *s)26 char* FAST_FUNC skip_non_whitespace(const char *s) 21 27 { 22 while (*s && !isspace(*s)) ++s; 28 while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9)) 29 s++; 23 30 24 31 return (char *) s; 25 32 } 33 34 char* 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 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 #include <termios.h>11 10 #include "libbb.h" 12 11 … … 31 30 {B4800, 4800}, 32 31 {B9600, 9600}, 33 #ifdef 32 #ifdef B19200 34 33 {B19200, 19200}, 35 34 #elif defined(EXTA) 36 35 {EXTA, 19200}, 37 36 #endif 38 #ifdef 37 #ifdef B38400 39 38 {B38400, 38400/256 + 0x8000U}, 40 39 #elif defined(EXTB) … … 53 52 {B460800, 460800/256 + 0x8000U}, 54 53 #endif 54 #ifdef B921600 55 {B921600, 921600/256 + 0x8000U}, 56 #endif 55 57 }; 56 58 57 59 enum { NUM_SPEEDS = ARRAY_SIZE(speeds) }; 58 60 59 unsigned inttty_baud_to_value(speed_t speed)61 unsigned FAST_FUNC tty_baud_to_value(speed_t speed) 60 62 { 61 63 int i = 0; … … 73 75 } 74 76 75 speed_t tty_value_to_baud(unsigned int value)77 speed_t FAST_FUNC tty_value_to_baud(unsigned int value) 76 78 { 77 79 int i = 0; … … 95 97 speed_t s; 96 98 97 for (v = 0 ; v < 500000; v++) {99 for (v = 0 ; v < 1000000; v++) { 98 100 s = tty_value_to_baud(v); 99 101 if (s == (speed_t) -1) { -
branches/2.2.9/mindi-busybox/libbb/str_tolower.c
r1765 r2725 2 2 /* Convert string str to lowercase, return str. 3 3 * 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. 5 5 */ 6 6 #include "libbb.h" 7 char* str_tolower(char *str) 7 8 char* FAST_FUNC str_tolower(char *str) 8 9 { 9 10 char *c; -
branches/2.2.9/mindi-busybox/libbb/time.c
r1765 r2725 3 3 * Utility routines. 4 4 * 5 * Copyright (C) 2007 Den is Vlasenko5 * Copyright (C) 2007 Denys Vlasenko 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 11 void 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 163 time_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 12 172 #if ENABLE_MONOTONIC_SYSCALL 173 13 174 #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 14 180 15 181 /* libc has incredibly messy way of doing this, 16 182 * 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)) 183 static void get_mono(struct timespec *ts) 184 { 185 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts)) 21 186 bb_error_msg_and_die("clock_gettime(MONOTONIC) failed"); 187 } 188 unsigned 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 } 194 unsigned long long FAST_FUNC monotonic_us(void) 195 { 196 struct timespec ts; 197 get_mono(&ts); 22 198 return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000; 23 199 } 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"); 200 unsigned 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 } 206 unsigned FAST_FUNC monotonic_sec(void) 207 { 208 struct timespec ts; 209 get_mono(&ts); 29 210 return ts.tv_sec; 30 211 } 212 31 213 #else 32 unsigned long long monotonic_us(void) 214 215 unsigned 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 } 221 unsigned long long FAST_FUNC monotonic_us(void) 33 222 { 34 223 struct timeval tv; … … 36 225 return tv.tv_sec * 1000000ULL + tv.tv_usec; 37 226 } 38 39 unsigned monotonic_sec(void) 227 unsigned 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 } 233 unsigned FAST_FUNC monotonic_sec(void) 40 234 { 41 235 return time(NULL); 42 236 } 43 #endif 237 238 #endif -
branches/2.2.9/mindi-busybox/libbb/trim.c
r1765 r2725 6 6 * If you wrote this, please acknowledge your work. 7 7 * 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. 9 9 */ 10 10 11 11 #include "libbb.h" 12 12 13 void trim(char *s)13 void FAST_FUNC trim(char *s) 14 14 { 15 15 size_t len = strlen(s); 16 size_t lws;17 16 18 17 /* trim trailing whitespace */ 19 while (len && isspace(s[len-1])) --len; 18 while (len && isspace(s[len-1])) 19 --len; 20 20 21 21 /* trim leading whitespace */ 22 22 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 } 25 28 } 26 29 s[len] = '\0'; -
branches/2.2.9/mindi-busybox/libbb/u_signal_names.c
r1765 r2725 5 5 * Copyright 2006 Rob Landley <rob@landley.net> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 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 15 static const char signals[][7] = { 13 16 // SUSv3 says kill must support these, and specifies the numerical values, 14 17 // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html 15 // TODO: "[SIG]EXIT" shouldn't work for kill, right?16 18 // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"}, 17 19 // {6, "ABRT"}, {9, "KILL"}, {14, "ALRM"}, {15, "TERM"} … … 21 23 // {SIGCONT, "CONT"}, {SIGSTOP, "STOP"}, {SIGTSTP, "TSTP"}, {SIGTTIN, "TTIN"}, 22 24 // {SIGTTOU, "TTOU"} 25 23 26 [0] = "EXIT", 24 27 #ifdef SIGHUP … … 119 122 // Convert signal name to number. 120 123 121 int get_signum(const char *name)124 int FAST_FUNC get_signum(const char *name) 122 125 { 123 inti;126 unsigned i; 124 127 125 128 i = bb_strtou(name, NULL, 10); … … 133 136 134 137 #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 */ 136 141 if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') { 137 142 #ifdef SIGIO … … 151 156 // Convert signal number to name 152 157 153 const char *get_signame(int number)158 const char* FAST_FUNC get_signame(int number) 154 159 { 155 160 if ((unsigned)number < ARRAY_SIZE(signals)) { … … 160 165 return itoa(number); 161 166 } 167 168 169 // Print the whole signal list 170 171 void 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 3 3 * Utility routines. 4 4 * 5 * Copyright (C) 2007 Den is Vlasenko5 * Copyright (C) 2007 Denys Vlasenko 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 … … 14 13 * We don't check for errors here. Not supported == won't be used 15 14 */ 16 void 15 void FAST_FUNC 17 16 socket_want_pktinfo(int fd) 18 17 { … … 26 25 27 26 28 #ifdef UNUSED 29 ssize_t 27 ssize_t FAST_FUNC 30 28 send_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, 32 31 socklen_t tolen) 33 32 { 34 33 #ifndef IP_PKTINFO 34 (void)from; /* suppress "unused from" warning */ 35 35 return sendto(fd, buf, len, flags, to, tolen); 36 36 #else 37 37 struct iovec iov[1]; 38 38 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; 44 45 struct cmsghdr* cmsgptr; 45 46 46 47 if (from->sa_family != AF_INET 47 # if ENABLE_FEATURE_IPV648 # if ENABLE_FEATURE_IPV6 48 49 && from->sa_family != AF_INET6 49 # endif50 # endif 50 51 ) { 51 52 /* ANY local address */ … … 58 59 iov[0].iov_len = len; 59 60 60 memset( cbuf, 0, sizeof(cbuf));61 memset(&u, 0, sizeof(u)); 61 62 62 63 memset(&msg, 0, sizeof(msg)); … … 65 66 msg.msg_iov = iov; 66 67 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); 69 70 msg.msg_flags = flags; 70 71 … … 76 77 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 77 78 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 */ 79 86 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; 80 87 } 81 # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)88 # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) 82 89 else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { 83 90 struct in6_pktinfo *pktptr; … … 86 93 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 87 94 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...) */ 89 96 pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr; 90 97 } 91 #endif 98 # endif 99 msg.msg_controllen = cmsgptr->cmsg_len; 100 92 101 return sendmsg(fd, &msg, flags); 93 102 #endif 94 103 } 95 #endif /* UNUSED */96 104 97 105 /* NB: this will never set port# in 'to'! … … 99 107 * Typical usage is to preinit 'to' with "default" value 100 108 * before calling recv_from_to(). */ 101 ssize_t 109 ssize_t FAST_FUNC 102 110 recv_from_to(int fd, void *buf, size_t len, int flags, 103 111 struct sockaddr *from, struct sockaddr *to, … … 105 113 { 106 114 #ifndef IP_PKTINFO 115 (void)to; /* suppress "unused to" warning */ 107 116 return recvfrom(fd, buf, len, flags, from, &sa_size); 108 117 #else … … 111 120 union { 112 121 char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; 122 # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) 113 123 char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 124 # endif 114 125 } u; 115 126 struct cmsghdr *cmsgptr; 116 127 struct msghdr msg; 117 s ocklen_t recv_length;128 ssize_t recv_length; 118 129 119 130 iov[0].iov_base = buf; … … 132 143 return recv_length; 133 144 145 # define to4 ((struct sockaddr_in*)to) 146 # define to6 ((struct sockaddr_in6*)to) 134 147 /* Here we try to retrieve destination IP and memorize it */ 135 148 for (cmsgptr = CMSG_FIRSTHDR(&msg); … … 140 153 && cmsgptr->cmsg_type == IP_PKTINFO 141 154 ) { 142 #define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) ) 155 const int IPI_ADDR_OFF = offsetof(struct in_pktinfo, ipi_addr); 143 156 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 */ 147 161 break; 148 162 } 149 # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)163 # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) 150 164 if (cmsgptr->cmsg_level == IPPROTO_IPV6 151 165 && cmsgptr->cmsg_type == IPV6_PKTINFO 152 166 ) { 153 #define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) ) 167 const int IPI6_ADDR_OFF = offsetof(struct in6_pktinfo, ipi6_addr); 154 168 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; */ 158 173 break; 159 174 } 160 # endif175 # endif 161 176 } 162 177 return recv_length; -
branches/2.2.9/mindi-busybox/libbb/update_passwd.c
r1765 r2725 8 8 * 9 9 * 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. 10 15 */ 11 12 16 #include "libbb.h" 13 17 14 int update_passwd(const char *filename, const char *username, 15 const char *new_pw)18 #if ENABLE_SELINUX 19 static void check_selinux_update_passwd(const char *username) 16 20 { 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 */ 70 int 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 17 78 struct stat sb; 18 79 struct flock lock; … … 21 82 char *fnamesfx; 22 83 char *sfx_char; 84 char *name_colon; 23 85 unsigned user_len; 24 86 int old_fd; 25 87 int new_fd; 26 88 int i; 27 int c nt = 0;89 int changed_lines; 28 90 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); 29 103 30 104 /* New passwd file, "/etc/passwd+" for now */ 31 105 fnamesfx = xasprintf("%s+", filename); 32 106 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 */ 38 117 goto free_mem; 118 } 39 119 old_fd = fileno(old_fp); 120 121 selinux_preserve_fcontext(old_fd); 40 122 41 123 /* Try to create "/etc/passwd+". Wait if it exists. */ … … 48 130 usleep(100000); /* 0.1 sec */ 49 131 } while (--i); 50 bb_perror_msg("can not create '%s'", fnamesfx);132 bb_perror_msg("can't create '%s'", fnamesfx); 51 133 goto close_old_fp; 52 134 53 135 created: 54 if ( !fstat(old_fd, &sb)) {136 if (fstat(old_fd, &sb) == 0) { 55 137 fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ 56 138 fchown(new_fd, sb.st_uid, sb.st_gid); 57 139 } 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); 63 142 64 143 /* Backup file is "/etc/passwd-" */ … … 68 147 /* Create backup as a hardlink to current */ 69 148 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); 71 151 *sfx_char = '+'; 72 152 … … 77 157 lock.l_len = 0; 78 158 if (fcntl(old_fd, F_SETLK, &lock) < 0) 79 bb_perror_msg("warning: can not lock '%s'", filename);159 bb_perror_msg("warning: can't lock '%s'", filename); 80 160 lock.l_type = F_UNLCK; 81 161 82 162 /* Read current password file, write updated /etc/passwd+ */ 163 changed_lines = 0; 83 164 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 } 94 216 } 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: 96 238 free(line); 97 239 } 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 98 259 fcntl(old_fd, F_SETLK, &lock); 99 260 100 261 /* We do want all of them to execute, thus | instead of || */ 262 errno = 0; 101 263 if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp)) 102 264 || rename(fnamesfx, filename) 103 265 ) { 104 266 /* At least one of those failed */ 267 bb_perror_nomsg(); 105 268 goto unlink_new; 106 269 } 107 ret = cnt; /* whee, success! */ 270 /* Success: ret >= 0 */ 271 ret = changed_lines; 108 272 109 273 unlink_new: 110 if (ret < 0) unlink(fnamesfx); 274 if (ret < 0) 275 unlink(fnamesfx); 111 276 112 277 close_old_fp: … … 115 280 free_mem: 116 281 free(fnamesfx); 117 free((char*)username); 282 free((char *)filename); 283 free(name_colon); 118 284 return ret; 119 285 } -
branches/2.2.9/mindi-busybox/libbb/uuencode.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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 4 6 * 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. 6 8 */ 7 9 … … 40 42 * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3)) 41 43 */ 42 void bb_uuencode(char *p, const void *src, int length, const char *tbl)44 void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl) 43 45 { 44 46 const unsigned char *s = src; … … 70 72 } 71 73 } 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 */ 80 void 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 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 11 11 12 12 #if defined(__GLIBC__) && __GLIBC__ < 2 13 int vdprintf(int d, const char *format, va_list ap)13 int FAST_FUNC vdprintf(int d, const char *format, va_list ap) 14 14 { 15 15 char buf[BUF_SIZE]; -
branches/2.2.9/mindi-busybox/libbb/verror_msg.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 10 #include <syslog.h>11 9 #include "libbb.h" 10 #if ENABLE_FEATURE_SYSLOG 11 # include <syslog.h> 12 #endif 12 13 13 14 smallint logmode = LOGMODE_STDIO; 14 15 const char *msg_eol = "\n"; 15 16 16 void bb_verror_msg(const char *s, va_list p, const char* strerr)17 void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) 17 18 { 18 char *msg ;19 char *msg, *msg1; 19 20 int applet_len, strerr_len, msgeol_len, used; 20 21 … … 37 38 strerr_len = strerr ? strlen(strerr) : 0; 38 39 msgeol_len = strlen(msg_eol); 40 /* can't use xrealloc: it calls error_msg on failure, 41 * that may result in a recursion */ 39 42 /* +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; 52 65 } 53 strcpy(&msg[used], msg_eol);54 66 55 67 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); 58 70 } 71 #if ENABLE_FEATURE_SYSLOG 59 72 if (logmode & LOGMODE_SYSLOG) { 60 73 syslog(LOG_ERR, "%s", msg + applet_len); 61 74 } 75 #endif 62 76 free(msg); 63 77 } 64 78 65 66 79 #ifdef VERSION_WITH_WRITEV 67 68 80 /* Code size is approximately the same, but currently it's the only user 69 81 * 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) 82 void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) 72 83 { 73 84 int strerr_len, msgeol_len; … … 115 126 /*iov[2].iov_base = msgc;*/ 116 127 /*iov[2].iov_len = used;*/ 117 fflush (stdout);118 writev( 2, iov, 3);128 fflush_all(); 129 writev(STDERR_FILENO, iov, 3); 119 130 } 131 # if ENABLE_FEATURE_SYSLOG 120 132 if (logmode & LOGMODE_SYSLOG) { 121 133 syslog(LOG_ERR, "%s", msgc); 122 134 } 135 # endif 123 136 free(msgc); 124 137 } 125 138 #endif 139 140 141 void 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 151 void 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 13 13 * Modified for uClibc by Erik Andersen <andersee@debian.org> 14 14 * 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. 16 16 */ 17 17 18 #include <paths.h> 19 #include "busybox.h" /* for struct bb_applet */ 18 #include "busybox.h" /* uses applet tables */ 20 19 21 20 /* This does a fork/exec in one call, using vfork(). Returns PID of new child, 22 21 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 23 pid_t spawn(char **argv)22 pid_t FAST_FUNC spawn(char **argv) 24 23 { 25 24 /* Compiler should not optimize stores here */ … … 27 26 pid_t pid; 28 27 29 // Ain't it a good place to fflush(NULL)? 28 fflush_all(); 30 29 31 30 /* Be nice to nommu machines. */ … … 43 42 */ 44 43 failed = errno; 44 /* mount, for example, does not want the message */ 45 /*bb_perror_msg("can't execute '%s'", argv[0]);*/ 45 46 _exit(111); 46 47 } … … 52 53 * If 111 - then it (most probably) failed to exec */ 53 54 if (failed) { 55 safe_waitpid(pid, NULL, 0); /* prevent zombie */ 54 56 errno = failed; 55 57 return -1; … … 59 61 60 62 /* Die with an error message if we can't spawn a child process. */ 61 pid_t xspawn(char **argv)63 pid_t FAST_FUNC xspawn(char **argv) 62 64 { 63 65 pid_t pid = spawn(argv); 64 66 if (pid < 0) 65 bb_ perror_msg_and_die("%s",*argv);67 bb_simple_perror_msg_and_die(*argv); 66 68 return pid; 67 69 } 68 70 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 do98 r = waitpid(pid, wstat, 0);99 while ((r == -1) && (errno == EINTR));100 return r;101 }102 103 71 #if ENABLE_FEATURE_PREFER_APPLETS 104 void save_nofork_data(struct nofork_save_area *save)72 void FAST_FUNC save_nofork_data(struct nofork_save_area *save) 105 73 { 106 74 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); 107 save-> current_applet = current_applet;75 save->applet_name = applet_name; 108 76 save->xfunc_error_retval = xfunc_error_retval; 109 77 save->option_mask32 = option_mask32; … … 112 80 } 113 81 114 void restore_nofork_data(struct nofork_save_area *save)82 void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) 115 83 { 116 84 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); 117 current_applet = save->current_applet;85 applet_name = save->applet_name; 118 86 xfunc_error_retval = save->xfunc_error_retval; 119 87 option_mask32 = save->option_mask32; 120 88 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 91 int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) 126 92 { 127 93 int rc, argc; 128 94 129 current_applet = a;130 applet_name = a->name; 95 applet_name = APPLET_NAME(applet_no); 96 131 97 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" 134 100 * in NOFORK applet, xfunc_die() sees negative 135 101 * die_sleep and longjmp here instead. */ 136 102 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 */ 137 128 138 129 argc = 1; … … 147 138 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); 148 139 /* 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 150 150 } else { /* xfunc died in NOFORK applet */ 151 151 /* in case they meant to return 0... */ … … 154 154 } 155 155 156 /* Restoring globals */156 /* Restoring some globals */ 157 157 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 169 int FAST_FUNC run_nofork_applet(int applet_no, char **argv) 162 170 { 163 171 struct nofork_save_area old; … … 165 173 /* Saving globals */ 166 174 save_nofork_data(&old); 167 return run_nofork_applet_prime(&old, a , argv);175 return run_nofork_applet_prime(&old, applet_no, argv); 168 176 } 169 177 #endif /* FEATURE_PREFER_APPLETS */ 170 178 171 int spawn_and_wait(char **argv)179 int FAST_FUNC spawn_and_wait(char **argv) 172 180 { 173 181 int rc; 174 182 #if ENABLE_FEATURE_PREFER_APPLETS 175 const struct bb_applet *a = find_applet_by_name(argv[0]);176 177 if (a && (a->nofork183 int a = find_applet_by_name(argv[0]); 184 185 if (a >= 0 && (APPLET_IS_NOFORK(a) 178 186 #if BB_MMU 179 || a->noexec/* NOEXEC trick needs fork() */187 || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ 180 188 #endif 181 189 )) { 182 190 #if BB_MMU 183 if ( a->nofork)191 if (APPLET_IS_NOFORK(a)) 184 192 #endif 185 193 { … … 194 202 /* child */ 195 203 xfunc_error_retval = EXIT_FAILURE; 196 current_applet = a; 197 run_current_applet_and_exit(argv); 204 run_applet_no_and_exit(a, argv); 198 205 #endif 199 206 } … … 204 211 205 212 #if !BB_MMU 206 void re_exec(char **argv)213 void FAST_FUNC re_exec(char **argv) 207 214 { 208 215 /* high-order bit of first char in argv[0] is a hidden … … 210 217 argv[0][0] |= 0x80; 211 218 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 222 pid_t FAST_FUNC fork_or_rexec(char **argv) 216 223 { 217 224 pid_t pid; 218 225 /* Maybe we are already re-execed and come here again? */ 219 226 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(); 225 229 if (pid) /* parent */ 226 exit(0);230 return pid; 227 231 /* child - re-exec ourself */ 228 232 re_exec(argv); 229 233 } 230 #else231 /* Dance around (void)...*/232 #undef forkexit_or_rexec233 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()244 234 #endif 245 235 246 236 /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - 247 237 * char **argv "vanishes" */ 248 void bb_daemonize_or_rexec(int flags, char **argv)238 void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) 249 239 { 250 240 int fd; … … 259 249 } 260 250 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 } 262 259 263 260 while ((unsigned)fd < 2) … … 265 262 266 263 if (!(flags & DAEMON_ONLY_SANITIZE)) { 267 forkexit_or_rexec(argv); 264 if (fork_or_rexec(argv)) 265 exit(EXIT_SUCCESS); /* parent */ 268 266 /* if daemonizing, make sure we detach from stdio & ctty */ 269 267 setsid(); … … 280 278 } 281 279 282 void bb_sanitize_stdio(void)280 void FAST_FUNC bb_sanitize_stdio(void) 283 281 { 284 282 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL); -
branches/2.2.9/mindi-busybox/libbb/warn_ignoring_args.c
r1765 r2725 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 10 9 #include "libbb.h" 11 10 12 void bb_warn_ignoring_args(int n) 11 #if ENABLE_DESKTOP 12 void FAST_FUNC bb_warn_ignoring_args(char *arg) 13 13 { 14 if ( n) {14 if (arg) { 15 15 bb_error_msg("ignoring all arguments"); 16 16 } 17 17 } 18 #endif -
branches/2.2.9/mindi-busybox/libbb/wfopen.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 12 FILE *fopen_or_warn(const char *path, const char *mode)12 FILE* FAST_FUNC fopen_or_warn(const char *path, const char *mode) 13 13 { 14 14 FILE *fp = fopen(path, mode); 15 15 if (!fp) { 16 bb_ perror_msg("%s",path);17 errno = 0;16 bb_simple_perror_msg(path); 17 //errno = 0; /* why? */ 18 18 } 19 19 return fp; 20 20 } 21 22 FILE* FAST_FUNC fopen_for_read(const char *path) 23 { 24 return fopen(path, "r"); 25 } 26 27 FILE* FAST_FUNC xfopen_for_read(const char *path) 28 { 29 return xfopen(path, "r"); 30 } 31 32 FILE* FAST_FUNC fopen_for_write(const char *path) 33 { 34 return fopen(path, "w"); 35 } 36 37 FILE* FAST_FUNC xfopen_for_write(const char *path) 38 { 39 return xfopen(path, "w"); 40 } 41 42 static 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 } 49 FILE* FAST_FUNC xfdopen_for_read(int fd) 50 { 51 return xfdopen_helper(fd << 1); 52 } 53 FILE* 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 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 11 11 * is a command line arg. Since often that arg is '-' (meaning stdin), 12 12 * we avoid testing everywhere by consolidating things in this routine. 13 *14 * Note: we also consider "" to mean stdin (for 'cmp' at least).15 13 */ 16 14 17 15 #include "libbb.h" 18 16 19 FILE *fopen_or_warn_stdin(const char *filename)17 FILE* FAST_FUNC fopen_or_warn_stdin(const char *filename) 20 18 { 21 19 FILE *fp = stdin; 22 20 23 21 if (filename != bb_msg_standard_input 24 && filename[0]25 22 && NOT_LONE_DASH(filename) 26 23 ) { 27 24 fp = fopen_or_warn(filename, "r"); 28 25 } 29 30 26 return fp; 31 27 } 28 29 FILE* 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 37 int 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 50 int 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 5 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 7 * Licensed under GPLv2, see file LICENSE in this tarball for details.7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 8 */ 9 9 … … 60 60 /* A few special cases */ 61 61 62 int xatoi_u(const char *numstr)62 int FAST_FUNC xatoi_positive(const char *numstr) 63 63 { 64 64 return xatou_range(numstr, 0, INT_MAX); 65 65 } 66 66 67 uint16_t xatou16(const char *numstr)67 uint16_t FAST_FUNC xatou16(const char *numstr) 68 68 { 69 69 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 */ 1 5 /* 2 6 You need to define the following (example): … … 13 17 */ 14 18 15 unsigned type xstrtou(_range_sfx)(const char *numstr, int base,19 unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base, 16 20 unsigned type lower, 17 21 unsigned type upper, … … 22 26 char *e; 23 27 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)) 28 30 goto inval; 29 31 … … 40 42 goto inval; /* error / no digits / illegal trailing chars */ 41 43 42 errno = old_errno; 44 errno = old_errno; /* Ok. So restore errno. */ 43 45 44 46 /* Do optional suffix parsing. Allow 'empty' suffix tables. … … 73 75 } 74 76 75 unsigned type xstrtou(_range)(const char *numstr, int base,77 unsigned type FAST_FUNC xstrtou(_range)(const char *numstr, int base, 76 78 unsigned type lower, 77 79 unsigned type upper) … … 80 82 } 81 83 82 unsigned type xstrtou(_sfx)(const char *numstr, int base,84 unsigned type FAST_FUNC xstrtou(_sfx)(const char *numstr, int base, 83 85 const struct suffix_mult *suffixes) 84 86 { … … 86 88 } 87 89 88 unsigned type xstrtou()(const char *numstr, int base)90 unsigned type FAST_FUNC xstrtou()(const char *numstr, int base) 89 91 { 90 92 return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL); 91 93 } 92 94 93 unsigned type xatou(_range_sfx)(const char *numstr,95 unsigned type FAST_FUNC xatou(_range_sfx)(const char *numstr, 94 96 unsigned type lower, 95 97 unsigned type upper, … … 99 101 } 100 102 101 unsigned type xatou(_range)(const char *numstr,103 unsigned type FAST_FUNC xatou(_range)(const char *numstr, 102 104 unsigned type lower, 103 105 unsigned type upper) … … 106 108 } 107 109 108 unsigned type xatou(_sfx)(const char *numstr,110 unsigned type FAST_FUNC xatou(_sfx)(const char *numstr, 109 111 const struct suffix_mult *suffixes) 110 112 { … … 112 114 } 113 115 114 unsigned type xatou()(const char *numstr)116 unsigned type FAST_FUNC xatou()(const char *numstr) 115 117 { 116 118 return xatou(_sfx)(numstr, NULL); … … 119 121 /* Signed ones */ 120 122 121 type xstrto(_range_sfx)(const char *numstr, int base,123 type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base, 122 124 type lower, 123 125 type upper, … … 128 130 const char *p = numstr; 129 131 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] == '-') { 131 135 ++p; 132 ++u; /* two's complement */ 136 if (p[0] == '-') 137 ++u; /* = <type>_MIN (01111... + 1 == 10000...) */ 133 138 } 134 139 … … 147 152 } 148 153 149 type xstrto(_range)(const char *numstr, int base, type lower, type upper)154 type FAST_FUNC xstrto(_range)(const char *numstr, int base, type lower, type upper) 150 155 { 151 156 return xstrto(_range_sfx)(numstr, base, lower, upper, NULL); 152 157 } 153 158 154 type xato(_range_sfx)(const char *numstr, 159 type 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 164 type FAST_FUNC xato(_range_sfx)(const char *numstr, 155 165 type lower, 156 166 type upper, … … 160 170 } 161 171 162 type xato(_range)(const char *numstr, type lower, type upper)172 type FAST_FUNC xato(_range)(const char *numstr, type lower, type upper) 163 173 { 164 174 return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL); 165 175 } 166 176 167 type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)177 type FAST_FUNC xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes) 168 178 { 169 179 return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes); 170 180 } 171 181 172 type xato()(const char *numstr)182 type FAST_FUNC xato()(const char *numstr) 173 183 { 174 184 return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL); -
branches/2.2.9/mindi-busybox/libbb/xconnect.c
r1765 r2725 5 5 * Connect to host at port using address resolution from getaddrinfo 6 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 7 8 */ 8 9 10 #include <sys/types.h> 11 #include <sys/socket.h> /* netinet/in.h needs it */ 9 12 #include <netinet/in.h> 13 #include <net/if.h> 14 #include <sys/un.h> 10 15 #include "libbb.h" 11 16 12 void setsockopt_reuseaddr(int fd)17 void FAST_FUNC setsockopt_reuseaddr(int fd) 13 18 { 14 19 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)); 15 20 } 16 int setsockopt_broadcast(int fd)21 int FAST_FUNC setsockopt_broadcast(int fd) 17 22 { 18 23 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1)); 19 24 } 20 25 21 void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 26 #ifdef SO_BINDTODEVICE 27 int 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 43 int 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 51 static 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 70 len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd) 71 { 72 return get_lsa(fd, getsockname); 73 } 74 75 len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd) 76 { 77 return get_lsa(fd, getpeername); 78 } 79 80 void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 22 81 { 23 82 if (connect(s, s_addr, addrlen) < 0) { … … 26 85 if (s_addr->sa_family == AF_INET) 27 86 bb_perror_msg_and_die("%s (%s)", 28 "can not connect to remote host",87 "can't connect to remote host", 29 88 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); 30 bb_perror_msg_and_die("can not connect to remote host");89 bb_perror_msg_and_die("can't connect to remote host"); 31 90 } 32 91 } … … 34 93 /* Return port number for a service. 35 94 * 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 */ 98 unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port) 39 99 { 40 100 unsigned port_nr = default_port; … … 58 118 59 119 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 82 120 /* "New" networking API */ 83 121 84 122 85 int get_nport(const struct sockaddr *sa)123 int FAST_FUNC get_nport(const struct sockaddr *sa) 86 124 { 87 125 #if ENABLE_FEATURE_IPV6 … … 97 135 } 98 136 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;137 void 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; 104 142 return; 105 143 } 106 144 #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; 109 147 return; 110 148 } … … 120 158 static len_and_sockaddr* str2sockaddr( 121 159 const char *host, int port, 122 USE_FEATURE_IPV6(sa_family_t af,)160 IF_FEATURE_IPV6(sa_family_t af,) 123 161 int ai_flags) 124 162 { 163 IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) 125 164 int rc; 126 len_and_sockaddr *r = NULL;165 len_and_sockaddr *r; 127 166 struct addrinfo *result = NULL; 167 struct addrinfo *used_res; 128 168 const char *org_host = host; /* only for error msg */ 129 169 const char *cp; 130 170 struct addrinfo hint; 131 171 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 132 185 /* Ugly parsing of host:addr */ 133 186 if (ENABLE_FEATURE_IPV6 && host[0] == '[') { 187 /* Even uglier parsing of [xx]:nn */ 134 188 host++; 135 189 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 } 139 197 } else { 140 198 cp = strrchr(host, ':'); … … 144 202 } 145 203 } 146 if (cp) { 204 if (cp) { /* points to ":" or "]:" */ 147 205 int sz = cp - host + 1; 206 148 207 host = safe_strncpy(alloca(sz), host, sz); 149 if (ENABLE_FEATURE_IPV6 && *cp != ':') 208 if (ENABLE_FEATURE_IPV6 && *cp != ':') { 150 209 cp++; /* skip ']' */ 210 if (*cp == '\0') /* [xx] without port */ 211 goto skip; 212 } 151 213 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 154 255 155 256 memset(&hint, 0 , sizeof(hint)); 156 #if !ENABLE_FEATURE_IPV6157 hint.ai_family = AF_INET; /* do not try to find IPv6 */158 #else159 257 hint.ai_family = af; 160 #endif161 258 /* Needed. Or else we will get each address thrice (or more) 162 259 * for each possible socket type (tcp,udp,raw...): */ … … 170 267 goto ret; 171 268 } 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: 175 286 set_nport(r, htons(port)); 176 287 ret: … … 183 294 184 295 #if ENABLE_FEATURE_IPV6 185 len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af)296 len_and_sockaddr* FAST_FUNC host_and_af2sockaddr(const char *host, int port, sa_family_t af) 186 297 { 187 298 return str2sockaddr(host, port, af, 0); 188 299 } 189 300 190 len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)301 len_and_sockaddr* FAST_FUNC xhost_and_af2sockaddr(const char *host, int port, sa_family_t af) 191 302 { 192 303 return str2sockaddr(host, port, af, DIE_ON_ERROR); … … 194 305 #endif 195 306 196 len_and_sockaddr* host2sockaddr(const char *host, int port)307 len_and_sockaddr* FAST_FUNC host2sockaddr(const char *host, int port) 197 308 { 198 309 return str2sockaddr(host, port, AF_UNSPEC, 0); 199 310 } 200 311 201 len_and_sockaddr* xhost2sockaddr(const char *host, int port)312 len_and_sockaddr* FAST_FUNC xhost2sockaddr(const char *host, int port) 202 313 { 203 314 return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR); 204 315 } 205 316 206 len_and_sockaddr* xdotted2sockaddr(const char *host, int port)317 len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port) 207 318 { 208 319 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); 209 320 } 210 321 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 323 int 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 };) 214 326 len_and_sockaddr *lsa; 215 327 int fd; … … 234 346 } 235 347 #endif 236 lsa = xzalloc( offsetof(len_and_sockaddr, sa)+ len);348 lsa = xzalloc(LSA_LEN_SIZE + len); 237 349 lsa->len = len; 238 lsa-> sa.sa_family = family;350 lsa->u.sa.sa_family = family; 239 351 *lsap = lsa; 240 352 return fd; 241 353 } 242 354 243 int xsocket_stream(len_and_sockaddr **lsap)244 { 245 return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);355 int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) 356 { 357 return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); 246 358 } 247 359 … … 254 366 lsa = xdotted2sockaddr(bindaddr, port); 255 367 /* 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); 257 369 } 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); 259 371 set_nport(lsa, htons(port)); 260 372 } 261 373 setsockopt_reuseaddr(fd); 262 xbind(fd, &lsa-> sa, lsa->len);374 xbind(fd, &lsa->u.sa, lsa->len); 263 375 free(lsa); 264 376 return fd; 265 377 } 266 378 267 int create_and_bind_stream_or_die(const char *bindaddr, int port)379 int FAST_FUNC create_and_bind_stream_or_die(const char *bindaddr, int port) 268 380 { 269 381 return create_and_bind_or_die(bindaddr, port, SOCK_STREAM); 270 382 } 271 383 272 int create_and_bind_dgram_or_die(const char *bindaddr, int port)384 int FAST_FUNC create_and_bind_dgram_or_die(const char *bindaddr, int port) 273 385 { 274 386 return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM); … … 276 388 277 389 278 int create_and_connect_stream_or_die(const char *peer, int port)390 int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port) 279 391 { 280 392 int fd; … … 282 394 283 395 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); 285 397 setsockopt_reuseaddr(fd); 286 xconnect(fd, &lsa-> sa, lsa->len);398 xconnect(fd, &lsa->u.sa, lsa->len); 287 399 free(lsa); 288 400 return fd; 289 401 } 290 402 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);403 int 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); 295 407 return fd; 296 408 } … … 299 411 /* It doesn't hurt because we will add this bit anyway */ 300 412 #define IGNORE_PORT NI_NUMERICSERV 301 static char* sockaddr2str(const struct sockaddr *sa, int flags)413 static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags) 302 414 { 303 415 char host[128]; … … 305 417 int rc; 306 418 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 } 307 426 308 427 salen = LSA_SIZEOF_SA; … … 338 457 } 339 458 340 char* xmalloc_sockaddr2host(const struct sockaddr *sa)459 char* FAST_FUNC xmalloc_sockaddr2host(const struct sockaddr *sa) 341 460 { 342 461 return sockaddr2str(sa, 0); 343 462 } 344 463 345 char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa)464 char* FAST_FUNC xmalloc_sockaddr2host_noport(const struct sockaddr *sa) 346 465 { 347 466 return sockaddr2str(sa, IGNORE_PORT); 348 467 } 349 468 350 char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)469 char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) 351 470 { 352 471 return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT); 353 472 } 354 char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)473 char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa) 355 474 { 356 475 return sockaddr2str(sa, NI_NUMERICHOST); 357 476 } 358 477 359 char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)478 char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) 360 479 { 361 480 return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT); -
branches/2.2.9/mindi-busybox/libbb/xfuncs.c
r1765 r2725 5 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 6 * Copyright (C) 2006 Rob Landley 7 * Copyright (C) 2006 Den is Vlasenko7 * Copyright (C) 2006 Denys Vlasenko 8 8 * 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. 10 10 */ 11 11 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 12 25 #include "libbb.h" 13 26 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 */ 28 int FAST_FUNC ndelay_on(int fd) 29 { 30 return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); 31 } 32 33 int FAST_FUNC ndelay_off(int fd) 34 { 35 return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); 36 } 37 38 int FAST_FUNC close_on_exec_on(int fd) 39 { 40 return fcntl(fd, F_SETFD, FD_CLOEXEC); 41 } 42 43 char* 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. 22 55 */ 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) 56 void BUG_sizeof(void); 57 char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen) 327 58 { 328 59 unsigned i, out, res; 329 if (sizeof(unsigned) != 4) 330 BUG_sizeof_unsigned_not_4(); 60 331 61 if (buflen) { 332 62 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) { 334 75 res = n / i; 76 n = n % i; 335 77 if (res || out || i == 1) { 336 if (!--buflen) break; 78 if (--buflen == 0) 79 break; 337 80 out++; 338 n -= res*i;339 81 *buf++ = '0' + res; 340 82 } … … 344 86 } 345 87 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() */ 89 char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen) 90 { 91 if (!buflen) 92 return buf; 93 if (n < 0) { 350 94 n = -n; 351 95 *buf++ = '-'; … … 358 102 // second time will overwrite previous results. 359 103 // 360 // The largest 32 bit integer is -2 billion plus null terminator, or12 bytes.361 // I nt should always be 32 bits on any remotely Unix-like system, see362 // 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 108 static char local_buf[sizeof(int) * 3]; 109 110 /* Convert unsigned integer to ascii using a static buffer (returned). */ 111 char* FAST_FUNC utoa(unsigned n) 112 { 113 *(utoa_to_buf(n, local_buf, sizeof(local_buf) - 1)) = '\0'; 370 114 371 115 return local_buf; 372 116 } 373 117 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). */ 119 char* FAST_FUNC itoa(int n) 120 { 121 *(itoa_to_buf(n, local_buf, sizeof(local_buf) - 1)) = '\0'; 378 122 379 123 return local_buf; 380 124 } 381 125 382 / / Emit a string of hex representation of bytes383 char *bin2hex(char *p, const char *cp, int count)126 /* Emit a string of hex representation of bytes */ 127 char* FAST_FUNC bin2hex(char *p, const char *cp, int count) 384 128 { 385 129 while (count) { … … 393 137 } 394 138 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 */ 140 char* 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 176 off_t FAST_FUNC fdlength(int fd) 411 177 { 412 178 off_t bottom = 0, top = 0, pos; … … 446 212 return pos + 1; 447 213 } 448 449 // Die with an error message if we can't malloc() enough space and do an450 // 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 1458 // GNU extension459 va_start(p, format);460 r = vasprintf(&string_ptr, format, p);461 va_end(p);462 #else463 // 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);471 214 #endif 472 215 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 216 int FAST_FUNC bb_putchar_stderr(char ch) 217 { 218 return write(STDERR_FILENO, &ch, 1); 219 } 220 221 ssize_t FAST_FUNC full_write1_str(const char *str) 222 { 223 return full_write(STDOUT_FILENO, str, strlen(str)); 224 } 225 226 ssize_t FAST_FUNC full_write2_str(const char *str) 227 { 228 return full_write(STDERR_FILENO, str, strlen(str)); 229 } 230 231 static 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; 618 246 } 619 247 620 248 /* It is perfectly ok to pass in a NULL for either width or for 621 249 * 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 250 int 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 267 int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) 268 { 269 return tcsetattr(STDIN_FILENO, TCSANOW, tp); 270 } 271 272 pid_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 282 pid_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. 288 int 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 6 6 * 7 7 * 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 */ 9 11 10 12 #include "libbb.h" 11 12 /* Amount to increase buffer size by in each try. */13 #define PATH_INCR 3214 13 15 14 /* Return the current directory, newly allocated, arbitrarily long. … … 18 17 */ 19 18 20 char *19 char* FAST_FUNC 21 20 xrealloc_getcwd_or_warn(char *cwd) 22 21 { 22 #define PATH_INCR 64 23 23 24 char *ret; 24 25 unsigned path_max; 25 26 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 */ 28 28 29 if (cwd == NULL) 30 cwd = xmalloc(path_max); 31 32 while ((ret = getcwd(cwd, path_max)) == NULL && errno == ERANGE) { 29 while (1) { 33 30 path_max += PATH_INCR; 34 31 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; 35 42 } 36 37 if (ret == NULL) {38 free(cwd);39 bb_perror_msg("getcwd");40 return NULL;41 }42 43 return cwd;44 43 } -
branches/2.2.9/mindi-busybox/libbb/xgethostbyname.c
r1765 r2725 5 5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>. 6 6 * 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. 8 8 */ 9 10 //#include <netdb.h>11 9 #include "libbb.h" 12 10 13 struct hostent *xgethostbyname(const char *name)11 struct hostent* FAST_FUNC xgethostbyname(const char *name) 14 12 { 15 13 struct hostent *retval = gethostbyname(name); -
branches/2.2.9/mindi-busybox/libbb/xreadlink.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 5 7 */ 6 8 … … 9 11 /* 10 12 * NOTE: This function returns a malloced char* that you will have to free 11 * yourself. You have been warned.13 * yourself. 12 14 */ 13 char *xmalloc_readlink(const char *path)15 char* FAST_FUNC xmalloc_readlink(const char *path) 14 16 { 15 17 enum { GROWBY = 80 }; /* how large we will grow strings by */ … … 19 21 20 22 do { 21 buf = xrealloc(buf, bufsize += GROWBY); 23 bufsize += GROWBY; 24 buf = xrealloc(buf, bufsize); 22 25 readsize = readlink(path, buf, bufsize); 23 26 if (readsize == -1) { … … 32 35 } 33 36 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 */ 47 char* 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 89 char* FAST_FUNC xmalloc_readlink_or_warn(const char *path) 35 90 { 36 91 char *buf = xmalloc_readlink(path); 37 92 if (!buf) { 38 93 /* 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); 40 99 } 41 100 return buf; 42 101 } 43 102 44 /* UNUSED */ 45 #if 0 46 char *xmalloc_realpath(const char *path) 103 char* FAST_FUNC xmalloc_realpath(const char *path) 47 104 { 48 105 #if defined(__GLIBC__) && !defined(__UCLIBC__) 49 106 /* glibc provides a non-standard extension */ 107 /* new: POSIX.1-2008 specifies this behavior as well */ 50 108 return realpath(path, NULL); 51 109 #else 52 110 char buf[PATH_MAX+1]; 53 111 54 /* on error returns NULL (xstrdup(NULL) == NULL) */112 /* on error returns NULL (xstrdup(NULL) == NULL) */ 55 113 return xstrdup(realpath(path, buf)); 56 114 #endif 57 115 } 58 #endif -
branches/2.2.9/mindi-busybox/libbb/xregcomp.c
r1765 r2725 6 6 * If you wrote this, please acknowledge your work. 7 7 * 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. 9 9 */ 10 10 … … 12 12 #include "xregex.h" 13 13 14 char* regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags)14 char* FAST_FUNC regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags) 15 15 { 16 16 int ret = regcomp(preg, regex, cflags); … … 24 24 } 25 25 26 void xregcomp(regex_t *preg, const char *regex, int cflags)26 void FAST_FUNC xregcomp(regex_t *preg, const char *regex, int cflags) 27 27 { 28 28 char *errmsg = regcomp_or_errmsg(preg, regex, cflags); 29 29 if (errmsg) { 30 bb_error_msg_and_die(" xregcomp: %s", errmsg);30 bb_error_msg_and_die("bad regex '%s': %s", regex, errmsg); 31 31 } 32 32 }
Note:
See TracChangeset
for help on using the changeset viewer.