diff options
-rw-r--r-- | libbb/Kbuild | 1 | ||||
-rw-r--r-- | libbb/getopt32.c | 1 | ||||
-rw-r--r-- | libbb/xfuncs.c | 531 |
3 files changed, 26 insertions, 507 deletions
diff --git a/libbb/Kbuild b/libbb/Kbuild index 11ae10d..3a68efc 100644 --- a/libbb/Kbuild +++ b/libbb/Kbuild @@ -101,6 +101,7 @@ lib-y += wfopen_input.o lib-y += xatonum.o lib-y += xconnect.o lib-y += xfuncs.o +lib-y += xfuncs_printf.o lib-y += xfunc_die.o lib-y += xgetcwd.o lib-y += xgethostbyname.o diff --git a/libbb/getopt32.c b/libbb/getopt32.c index c0d8856..cd89032 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -560,6 +560,7 @@ getopt32(char **argv, const char *applet_opts, ...) llist_add_to_end((llist_t **)(on_off->optarg), optarg); } else if (on_off->param_type == PARAM_INT) { if (optarg) +//TODO: xatoi_u indirectly pulls in printf machinery *(unsigned*)(on_off->optarg) = xatoi_u(optarg); } else if (on_off->optarg) { if (optarg) diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 1250639..5298ee5 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -9,252 +9,38 @@ * Licensed under GPL version 2, see file LICENSE in this tarball for details. */ -#include "libbb.h" - -/* All the functions starting with "x" call bb_error_msg_and_die() if they - * fail, so callers never need to check for errors. If it returned, it - * succeeded. */ - -#ifndef DMALLOC -/* dmalloc provides variants of these that do abort() on failure. - * Since dmalloc's prototypes overwrite the impls here as they are - * included after these prototypes in libbb.h, all is well. +/* We need to have separate xfuncs.c and xfuncs_printf.c because + * with current linkers, even with section garbage collection, + * if *.o module references any of XXXprintf functions, you pull in + * entire printf machinery. Even if you do not use the function + * which uses XXXprintf. + * + * xfuncs.c contains functions (not necessarily xfuncs) + * which do not pull in printf, directly or indirectly. + * xfunc_printf.c contains those which do. + * + * TODO: move xmalloc() and xatonum() here. */ -// Warn if we can't allocate size bytes of memory. -void *malloc_or_warn(size_t size) -{ - void *ptr = malloc(size); - if (ptr == NULL && size != 0) - bb_error_msg(bb_msg_memory_exhausted); - return ptr; -} - -// Die if we can't allocate size bytes of memory. -void *xmalloc(size_t size) -{ - void *ptr = malloc(size); - if (ptr == NULL && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); - return ptr; -} - -// Die if we can't resize previously allocated memory. (This returns a pointer -// to the new memory, which may or may not be the same as the old memory. -// It'll copy the contents to a new chunk and free the old one if necessary.) -void *xrealloc(void *ptr, size_t size) -{ - ptr = realloc(ptr, size); - if (ptr == NULL && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); - return ptr; -} -#endif /* DMALLOC */ - -// Die if we can't allocate and zero size bytes of memory. -void *xzalloc(size_t size) -{ - void *ptr = xmalloc(size); - memset(ptr, 0, size); - return ptr; -} - -// Die if we can't copy a string to freshly allocated memory. -char * xstrdup(const char *s) -{ - char *t; - - if (s == NULL) - return NULL; - - t = strdup(s); - - if (t == NULL) - bb_error_msg_and_die(bb_msg_memory_exhausted); - - return t; -} - -// Die if we can't allocate n+1 bytes (space for the null terminator) and copy -// the (possibly truncated to length n) string into it. -char *xstrndup(const char *s, int n) -{ - int m; - char *t; - - if (ENABLE_DEBUG && s == NULL) - bb_error_msg_and_die("xstrndup bug"); - - /* We can just xmalloc(n+1) and strncpy into it, */ - /* but think about xstrndup("abc", 10000) wastage! */ - m = n; - t = (char*) s; - while (m) { - if (!*t) break; - m--; - t++; - } - n -= m; - t = xmalloc(n + 1); - t[n] = '\0'; - - return memcpy(t, s, n); -} - -// Die if we can't open a file and return a FILE * to it. -// Notice we haven't got xfread(), This is for use with fscanf() and friends. -FILE *xfopen(const char *path, const char *mode) -{ - FILE *fp = fopen(path, mode); - if (fp == NULL) - bb_perror_msg_and_die("can't open '%s'", path); - return fp; -} - -// Die if we can't open a file and return a fd. -int xopen3(const char *pathname, int flags, int mode) -{ - int ret; - - ret = open(pathname, flags, mode); - if (ret < 0) { - bb_perror_msg_and_die("can't open '%s'", pathname); - } - return ret; -} - -// Die if we can't open an existing file and return a fd. -int xopen(const char *pathname, int flags) -{ - return xopen3(pathname, flags, 0666); -} - -// Warn if we can't open a file and return a fd. -int open3_or_warn(const char *pathname, int flags, int mode) -{ - int ret; - - ret = open(pathname, flags, mode); - if (ret < 0) { - bb_perror_msg("can't open '%s'", pathname); - } - return ret; -} - -// Warn if we can't open a file and return a fd. -int open_or_warn(const char *pathname, int flags) -{ - return open3_or_warn(pathname, flags, 0666); -} - -void xunlink(const char *pathname) -{ - if (unlink(pathname)) - bb_perror_msg_and_die("can't remove file '%s'", pathname); -} - -void xrename(const char *oldpath, const char *newpath) -{ - if (rename(oldpath, newpath)) - bb_perror_msg_and_die("can't move '%s' to '%s'", oldpath, newpath); -} - -int rename_or_warn(const char *oldpath, const char *newpath) -{ - int n = rename(oldpath, newpath); - if (n) - bb_perror_msg("can't move '%s' to '%s'", oldpath, newpath); - return n; -} -void xpipe(int filedes[2]) -{ - if (pipe(filedes)) - bb_perror_msg_and_die("can't create pipe"); -} +#include "libbb.h" -// Turn on nonblocking I/O on a fd +/* Turn on nonblocking I/O on a fd */ int ndelay_on(int fd) { return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); } -int close_on_exec_on(int fd) -{ - return fcntl(fd, F_SETFD, FD_CLOEXEC); -} - int ndelay_off(int fd) { return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK); } -void xdup2(int from, int to) -{ - if (dup2(from, to) != to) - bb_perror_msg_and_die("can't duplicate file descriptor"); -} - -// "Renumber" opened fd -void xmove_fd(int from, int to) -{ - if (from == to) - return; - xdup2(from, to); - close(from); -} - -// Die with an error message if we can't write the entire buffer. -void xwrite(int fd, const void *buf, size_t count) -{ - if (count) { - ssize_t size = full_write(fd, buf, count); - if (size != count) - bb_error_msg_and_die("short write"); - } -} - -// Die with an error message if we can't lseek to the right spot. -off_t xlseek(int fd, off_t offset, int whence) -{ - off_t off = lseek(fd, offset, whence); - if (off == (off_t)-1) { - if (whence == SEEK_SET) - bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset); - bb_perror_msg_and_die("lseek"); - } - return off; -} - -// Die with supplied filename if this FILE * has ferror set. -void die_if_ferror(FILE *fp, const char *fn) -{ - if (ferror(fp)) { - /* ferror doesn't set useful errno */ - bb_error_msg_and_die("%s: I/O error", fn); - } -} - -// Die with an error message if stdout has ferror set. -void die_if_ferror_stdout(void) -{ - die_if_ferror(stdout, bb_msg_standard_output); -} - -// Die with an error message if we have trouble flushing stdout. -void xfflush_stdout(void) -{ - if (fflush(stdout)) { - bb_perror_msg_and_die(bb_msg_standard_output); - } -} - -void xsetenv(const char *key, const char *value) +int close_on_exec_on(int fd) { - if (setenv(key, value, 1)) - bb_error_msg_and_die(bb_msg_memory_exhausted); + return fcntl(fd, F_SETFD, FD_CLOEXEC); } -/* Converts unsigned long long value into compact 4-char +/* Convert unsigned long long value into compact 4-char * representation. Examples: "1234", "1.2k", " 27M", "123T" * String is not terminated (buf[4] is untouched) */ void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) @@ -303,7 +89,7 @@ void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) } } -/* Converts unsigned long long value into compact 5-char representation. +/* Convert unsigned long long value into compact 5-char representation. * String is not terminated (buf[5] is untouched) */ void smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) { @@ -383,7 +169,7 @@ char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) return buf; } -// Convert signed integer to ascii, like utoa_to_buf() +/* Convert signed integer to ascii, like utoa_to_buf() */ char *itoa_to_buf(int n, char *buf, unsigned buflen) { if (buflen && n<0) { @@ -398,10 +184,10 @@ char *itoa_to_buf(int n, char *buf, unsigned buflen) // second time will overwrite previous results. // // The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes. -// Int should always be 32 bits on any remotely Unix-like system, see -// http://www.unix.org/whitepapers/64bit.html for the reasons why. +// It so happens that sizeof(int) * 3 is enough for 32+ bits. +// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit) -static char local_buf[12]; +static char local_buf[sizeof(int) * 3]; // Convert unsigned integer to ascii using a static buffer (returned). char *utoa(unsigned n) @@ -411,7 +197,7 @@ char *utoa(unsigned n) return local_buf; } -// Convert signed integer to ascii using a static buffer (returned). +/* Convert signed integer to ascii using a static buffer (returned). */ char *itoa(int n) { *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; @@ -419,7 +205,7 @@ char *itoa(int n) return local_buf; } -// Emit a string of hex representation of bytes +/* Emit a string of hex representation of bytes */ char *bin2hex(char *p, const char *cp, int count) { while (count) { @@ -432,21 +218,7 @@ char *bin2hex(char *p, const char *cp, int count) return p; } -// Die with an error message if we can't set gid. (Because resource limits may -// limit this user to a given number of processes, and if that fills up the -// setgid() will fail and we'll _still_be_root_, which is bad.) -void xsetgid(gid_t gid) -{ - if (setgid(gid)) bb_perror_msg_and_die("setgid"); -} - -// Die with an error message if we can't set uid. (See xsetgid() for why.) -void xsetuid(uid_t uid) -{ - if (setuid(uid)) bb_perror_msg_and_die("setuid"); -} - -// Return how long the file at fd is, if there's any way to determine it. +/* Return how long the file at fd is, if there's any way to determine it. */ #ifdef UNUSED off_t fdlength(int fd) { @@ -488,192 +260,6 @@ off_t fdlength(int fd) } #endif -int bb_putchar(int ch) -{ - /* time.c needs putc(ch, stdout), not putchar(ch). - * it does "stdout = stderr;", but then glibc's putchar() - * doesn't work as expected. bad glibc, bad */ - return putc(ch, stdout); -} - -// Die with an error message if we can't malloc() enough space and do an -// sprintf() into that space. -char *xasprintf(const char *format, ...) -{ - va_list p; - int r; - char *string_ptr; - -#if 1 - // GNU extension - va_start(p, format); - r = vasprintf(&string_ptr, format, p); - va_end(p); -#else - // Bloat for systems that haven't got the GNU extension. - va_start(p, format); - r = vsnprintf(NULL, 0, format, p); - va_end(p); - string_ptr = xmalloc(r+1); - va_start(p, format); - r = vsnprintf(string_ptr, r+1, format, p); - va_end(p); -#endif - - if (r < 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); - return string_ptr; -} - -#if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */ -int fdprintf(int fd, const char *format, ...) -{ - va_list p; - int r; - char *string_ptr; - -#if 1 - // GNU extension - va_start(p, format); - r = vasprintf(&string_ptr, format, p); - va_end(p); -#else - // Bloat for systems that haven't got the GNU extension. - va_start(p, format); - r = vsnprintf(NULL, 0, format, p) + 1; - va_end(p); - string_ptr = malloc(r); - if (string_ptr) { - va_start(p, format); - r = vsnprintf(string_ptr, r, format, p); - va_end(p); - } -#endif - - if (r >= 0) { - full_write(fd, string_ptr, r); - free(string_ptr); - } - return r; -} -#endif - -// Die with an error message if we can't copy an entire FILE * to stdout, then -// close that file. -void xprint_and_close_file(FILE *file) -{ - fflush(stdout); - // copyfd outputs error messages for us. - if (bb_copyfd_eof(fileno(file), 1) == -1) - xfunc_die(); - - fclose(file); -} - -// Die if we can't chdir to a new path. -void xchdir(const char *path) -{ - if (chdir(path)) - bb_perror_msg_and_die("chdir(%s)", path); -} - -void xchroot(const char *path) -{ - if (chroot(path)) - bb_perror_msg_and_die("can't change root directory to %s", path); -} - -// Print a warning message if opendir() fails, but don't die. -DIR *warn_opendir(const char *path) -{ - DIR *dp; - - dp = opendir(path); - if (!dp) - bb_perror_msg("can't open '%s'", path); - return dp; -} - -// Die with an error message if opendir() fails. -DIR *xopendir(const char *path) -{ - DIR *dp; - - dp = opendir(path); - if (!dp) - bb_perror_msg_and_die("can't open '%s'", path); - return dp; -} - -// Die with an error message if we can't open a new socket. -int xsocket(int domain, int type, int protocol) -{ - int r = socket(domain, type, protocol); - - if (r < 0) { - /* Hijack vaguely related config option */ -#if ENABLE_VERBOSE_RESOLUTION_ERRORS - const char *s = "INET"; - if (domain == AF_PACKET) s = "PACKET"; - if (domain == AF_NETLINK) s = "NETLINK"; -USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";) - bb_perror_msg_and_die("socket(AF_%s)", s); -#else - bb_perror_msg_and_die("socket"); -#endif - } - - return r; -} - -// Die with an error message if we can't bind a socket to an address. -void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) -{ - if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind"); -} - -// Die with an error message if we can't listen for connections on a socket. -void xlisten(int s, int backlog) -{ - if (listen(s, backlog)) bb_perror_msg_and_die("listen"); -} - -/* Die with an error message if sendto failed. - * Return bytes sent otherwise */ -ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, - socklen_t tolen) -{ - ssize_t ret = sendto(s, buf, len, 0, to, tolen); - if (ret < 0) { - if (ENABLE_FEATURE_CLEAN_UP) - close(s); - bb_perror_msg_and_die("sendto"); - } - return ret; -} - -// xstat() - a stat() which dies on failure with meaningful error message -void xstat(const char *name, struct stat *stat_buf) -{ - if (stat(name, stat_buf)) - bb_perror_msg_and_die("can't stat '%s'", name); -} - -// selinux_or_die() - die if SELinux is disabled. -void selinux_or_die(void) -{ -#if ENABLE_SELINUX - int rc = is_selinux_enabled(); - if (rc == 0) { - bb_error_msg_and_die("SELinux is disabled"); - } else if (rc < 0) { - bb_error_msg_and_die("is_selinux_enabled() failed"); - } -#else - bb_error_msg_and_die("SELinux support is disabled"); -#endif -} - /* 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 get_terminal_width_height(int fd, int *width, int *height) @@ -703,72 +289,3 @@ int get_terminal_width_height(int fd, int *width, int *height) return ret; } - -int ioctl_or_perror_and_die(int fd, int request, void *argp, const char *fmt,...) -{ - int ret; - va_list p; - - ret = ioctl(fd, request, argp); - if (ret < 0) { - va_start(p, fmt); - bb_verror_msg(fmt, p, strerror(errno)); - /* xfunc_die can actually longjmp, so be nice */ - va_end(p); - xfunc_die(); - } - return ret; -} - -int ioctl_or_perror(int fd, int request, void *argp, const char *fmt,...) -{ - va_list p; - int ret = ioctl(fd, request, argp); - - if (ret < 0) { - va_start(p, fmt); - bb_verror_msg(fmt, p, strerror(errno)); - va_end(p); - } - return ret; -} - -#if ENABLE_IOCTL_HEX2STR_ERROR -int bb_ioctl_or_warn(int fd, int request, void *argp, const char *ioctl_name) -{ - int ret; - - ret = ioctl(fd, request, argp); - if (ret < 0) - bb_simple_perror_msg(ioctl_name); - return ret; -} -int bb_xioctl(int fd, int request, void *argp, const char *ioctl_name) -{ - int ret; - - ret = ioctl(fd, request, argp); - if (ret < 0) - bb_simple_perror_msg_and_die(ioctl_name); - return ret; -} -#else -int bb_ioctl_or_warn(int fd, int request, void *argp) -{ - int ret; - - ret = ioctl(fd, request, argp); - if (ret < 0) - bb_perror_msg("ioctl %#x failed", request); - return ret; -} -int bb_xioctl(int fd, int request, void *argp) -{ - int ret; - - ret = ioctl(fd, request, argp); - if (ret < 0) - bb_perror_msg_and_die("ioctl %#x failed", request); - return ret; -} -#endif |