X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=libbb%2Fxfuncs.c;h=23f27516f633c2178f2b00b24e13aec5c9c2d357;hb=cfc212cdfff27c6a7b9d9743f87c4da70f97558c;hp=e47b01dc1dc5e8c7f3ee9d7bc1d731c533f95f10;hpb=db67a20595be279e7db9f5f8e27bd94534efb8d4;p=oweals%2Fbusybox.git diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index e47b01dc1..23f27516f 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Rob Landley * Copyright (C) 2006 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* We need to have separate xfuncs.c and xfuncs_printf.c because @@ -25,19 +25,25 @@ #include "libbb.h" /* Turn on nonblocking I/O on a fd */ -int FAST_FUNC ndelay_on(int fd) +void FAST_FUNC ndelay_on(int fd) { - return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + if (flags & O_NONBLOCK) + return; + fcntl(fd, F_SETFL, flags | O_NONBLOCK); } -int FAST_FUNC ndelay_off(int fd) +void FAST_FUNC ndelay_off(int fd) { - return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + if (!(flags & O_NONBLOCK)) + return; + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } -int FAST_FUNC close_on_exec_on(int fd) +void FAST_FUNC close_on_exec_on(int fd) { - return fcntl(fd, F_SETFD, FD_CLOEXEC); + fcntl(fd, F_SETFD, FD_CLOEXEC); } char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) @@ -49,23 +55,35 @@ char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) } -// Convert unsigned integer to ascii, writing into supplied buffer. -// A truncated result contains the first few digits of the result ala strncpy. -// Returns a pointer past last generated digit, does _not_ store NUL. -void BUG_sizeof_unsigned_not_4(void); +/* Convert unsigned integer to ascii, writing into supplied buffer. + * A truncated result contains the first few digits of the result ala strncpy. + * Returns a pointer past last generated digit, does _not_ store NUL. + */ +void BUG_sizeof(void); char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen) { unsigned i, out, res; - if (sizeof(unsigned) != 4) - BUG_sizeof_unsigned_not_4(); + if (buflen) { out = 0; - for (i = 1000000000; i; i /= 10) { + if (sizeof(n) == 4) + // 2^32-1 = 4294967295 + i = 1000000000; +#if UINT_MAX > 4294967295 /* prevents warning about "const too large" */ + else + if (sizeof(n) == 8) + // 2^64-1 = 18446744073709551615 + i = 10000000000000000000; +#endif + else + BUG_sizeof(); + for (; i; i /= 10) { res = n / i; + n = n % i; if (res || out || i == 1) { - if (!--buflen) break; + if (--buflen == 0) + break; out++; - n -= res*i; *buf++ = '0' + res; } } @@ -76,7 +94,9 @@ char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen) /* Convert signed integer to ascii, like utoa_to_buf() */ char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen) { - if (buflen && n < 0) { + if (!buflen) + return buf; + if (n < 0) { n = -n; *buf++ = '-'; buflen--; @@ -87,16 +107,16 @@ char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen) // The following two functions use a static buffer, so calling either one a // second time will overwrite previous results. // -// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes. -// It so happens that sizeof(int) * 3 is enough for 32+ bits. +// The largest 32 bit integer is -2 billion plus NUL, or 1+10+1=12 bytes. +// It so happens that sizeof(int) * 3 is enough for 32+ bit ints. // (sizeof(int) * 3 + 2 is correct for any width, even 8-bit) static char local_buf[sizeof(int) * 3]; -// Convert unsigned integer to ascii using a static buffer (returned). +/* Convert unsigned integer to ascii using a static buffer (returned). */ char* FAST_FUNC utoa(unsigned n) { - *(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; + *(utoa_to_buf(n, local_buf, sizeof(local_buf) - 1)) = '\0'; return local_buf; } @@ -104,7 +124,7 @@ char* FAST_FUNC utoa(unsigned n) /* Convert signed integer to ascii using a static buffer (returned). */ char* FAST_FUNC itoa(int n) { - *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; + *(itoa_to_buf(n, local_buf, sizeof(local_buf) - 1)) = '\0'; return local_buf; } @@ -122,6 +142,41 @@ char* FAST_FUNC bin2hex(char *p, const char *cp, int count) return p; } +/* Convert "[x]x[:][x]x[:][x]x[:][x]x" hex string to binary, no more than COUNT bytes */ +char* FAST_FUNC hex2bin(char *dst, const char *str, int count) +{ + errno = EINVAL; + while (*str && count) { + uint8_t val; + uint8_t c = *str++; + if (isdigit(c)) + val = c - '0'; + else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') + val = (c|0x20) - ('a' - 10); + else + return NULL; + val <<= 4; + c = *str; + if (isdigit(c)) + val |= c - '0'; + else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') + val |= (c|0x20) - ('a' - 10); + else if (c == ':' || c == '\0') + val >>= 4; + else + return NULL; + + *dst++ = val; + if (c != '\0') + str++; + if (*str == ':') + str++; + count--; + } + errno = (*str ? ERANGE : 0); + return dst; +} + /* Return how long the file at fd is, if there's any way to determine it. */ #ifdef UNUSED off_t FAST_FUNC fdlength(int fd) @@ -164,45 +219,55 @@ off_t FAST_FUNC fdlength(int fd) } #endif -char* FAST_FUNC xmalloc_ttyname(int fd) +int FAST_FUNC bb_putchar_stderr(char ch) { - char *buf = xzalloc(128); - int r = ttyname_r(fd, buf, 127); - if (r) { - free(buf); - buf = NULL; - } - return buf; + return write(STDERR_FILENO, &ch, 1); } -/* It is perfectly ok to pass in a NULL for either width or for - * height, in which case that value will not be set. */ -int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) +ssize_t FAST_FUNC full_write1_str(const char *str) { - struct winsize win = { 0, 0, 0, 0 }; - int ret = ioctl(fd, TIOCGWINSZ, &win); + return full_write(STDOUT_FILENO, str, strlen(str)); +} - if (height) { - if (!win.ws_row) { - char *s = getenv("LINES"); - if (s) win.ws_row = atoi(s); - } - if (win.ws_row <= 1 || win.ws_row >= 30000) - win.ws_row = 24; - *height = (int) win.ws_row; - } +ssize_t FAST_FUNC full_write2_str(const char *str) +{ + return full_write(STDERR_FILENO, str, strlen(str)); +} - if (width) { - if (!win.ws_col) { - char *s = getenv("COLUMNS"); - if (s) win.ws_col = atoi(s); +static int wh_helper(int value, int def_val, const char *env_name, int *err) +{ + if (value == 0) { + char *s = getenv(env_name); + if (s) { + value = atoi(s); + /* If LINES/COLUMNS are set, pretend that there is + * no error getting w/h, this prevents some ugly + * cursor tricks by our callers */ + *err = 0; } - if (win.ws_col <= 1 || win.ws_col >= 30000) - win.ws_col = 80; - *width = (int) win.ws_col; } + if (value <= 1 || value >= 30000) + value = def_val; + return value; +} - return ret; +/* It is perfectly ok to pass in a NULL for either width or for + * height, in which case that value will not be set. */ +int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) +{ + struct winsize win; + int err; + + win.ws_row = 0; + win.ws_col = 0; + /* I've seen ioctl returning 0, but row/col is (still?) 0. + * We treat that as an error too. */ + err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0; + if (height) + *height = wh_helper(win.ws_row, 24, "LINES", &err); + if (width) + *width = wh_helper(win.ws_col, 80, "COLUMNS", &err); + return err; } int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) @@ -210,65 +275,36 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) return tcsetattr(STDIN_FILENO, TCSANOW, tp); } -void FAST_FUNC generate_uuid(uint8_t *buf) +pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) { - /* http://www.ietf.org/rfc/rfc4122.txt - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | time_low | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | time_mid | time_hi_and_version | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |clk_seq_and_variant | node (0-1) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | node (2-5) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * IOW, uuid has this layout: - * uint32_t time_low (big endian) - * uint16_t time_mid (big endian) - * uint16_t time_hi_and_version (big endian) - * version is a 4-bit field: - * 1 Time-based - * 2 DCE Security, with embedded POSIX UIDs - * 3 Name-based (MD5) - * 4 Randomly generated - * 5 Name-based (SHA-1) - * uint16_t clk_seq_and_variant (big endian) - * variant is a 3-bit field: - * 0xx Reserved, NCS backward compatibility - * 10x The variant specified in rfc4122 - * 110 Reserved, Microsoft backward compatibility - * 111 Reserved for future definition - * uint8_t node[6] - * - * For version 4, these bits are set/cleared: - * time_hi_and_version & 0x0fff | 0x4000 - * clk_seq_and_variant & 0x3fff | 0x8000 - */ - pid_t pid; - int i; - - i = open("/dev/urandom", O_RDONLY); - if (i >= 0) { - read(i, buf, 16); - close(i); - } - /* Paranoia. /dev/urandom may be missing. - * rand() is guaranteed to generate at least [0, 2^15) range, - * but lowest bits in some libc are not so "random". */ - srand(monotonic_us()); - pid = getpid(); - while (1) { - for (i = 0; i < 16; i++) - buf[i] ^= rand() >> 5; - if (pid == 0) - break; - srand(pid); - pid = 0; - } + pid_t r; - /* version = 4 */ - buf[4 + 2 ] = (buf[4 + 2 ] & 0x0f) | 0x40; - /* variant = 10x */ - buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80; + do + r = waitpid(pid, wstat, options); + while ((r == -1) && (errno == EINTR)); + return r; +} + +pid_t FAST_FUNC wait_any_nohang(int *wstat) +{ + return safe_waitpid(-1, wstat, WNOHANG); +} + +// Wait for the specified child PID to exit, returning child's error return. +int FAST_FUNC wait4pid(pid_t pid) +{ + int status; + + if (pid <= 0) { + /*errno = ECHILD; -- wrong. */ + /* we expect errno to be already set from failed [v]fork/exec */ + return -1; + } + if (safe_waitpid(pid, &status, 0) == -1) + return -1; + if (WIFEXITED(status)) + return WEXITSTATUS(status); + if (WIFSIGNALED(status)) + return WTERMSIG(status) + 0x180; + return 0; }