diff options
author | 2012-06-22 14:19:14 -0700 | |
---|---|---|
committer | 2012-06-23 18:02:43 -0400 | |
commit | 40abb498ca4a24495fe34e133379382ce8c3eaca (patch) | |
tree | a8779b17558a4c96eb2d5c56e82cee4743d408aa /libsbutil | |
parent | use m4_flatten to make multiline lists easier to handle (diff) | |
download | sandbox-40abb498ca4a24495fe34e133379382ce8c3eaca.tar.gz sandbox-40abb498ca4a24495fe34e133379382ce8c3eaca.tar.bz2 sandbox-40abb498ca4a24495fe34e133379382ce8c3eaca.zip |
significantly overhaul output helpers
There are a few major points we want to hit here:
- have all output from libsandbox go through portage helpers when we are
in the portage environment so that output is properly logged
- convert SB_E{info,warn,error} to sb_e{info,warn,error} to match style
of other functions and cut down on confusion
- move all abort/output helpers to libsbutil so it can be used in all
source trees and not just by libsandbox
- migrate all abort points to the centralized sb_ebort helper
Unfortunately, it's not terribly easy to untangle these into separate
patches, but hopefully this shouldn't be too messy as much of it is
mechanical: move funcs between files, and change the name of funcs
that get called.
URL: http://bugs.gentoo.org/278761
Reported-by: Mounir Lamouri <volkmar@gentoo.org>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'libsbutil')
-rw-r--r-- | libsbutil/Makefile.am | 4 | ||||
-rw-r--r-- | libsbutil/sb_backtrace.c | 15 | ||||
-rw-r--r-- | libsbutil/sb_efuncs.c | 190 | ||||
-rw-r--r-- | libsbutil/sb_memory.c | 37 | ||||
-rw-r--r-- | libsbutil/sb_printf.c | 25 | ||||
-rw-r--r-- | libsbutil/sb_proc.c | 31 | ||||
-rw-r--r-- | libsbutil/sb_write_fd.c | 42 | ||||
-rw-r--r-- | libsbutil/sbutil.h | 39 |
8 files changed, 321 insertions, 62 deletions
diff --git a/libsbutil/Makefile.am b/libsbutil/Makefile.am index f1feca3..49a7d3b 100644 --- a/libsbutil/Makefile.am +++ b/libsbutil/Makefile.am @@ -20,11 +20,15 @@ libsbutil_la_SOURCES = \ get_tmp_dir.c \ is_env_on.c \ is_env_off.c \ + sb_backtrace.c \ + sb_efuncs.c \ sb_open.c \ sb_read.c \ sb_write.c \ + sb_write_fd.c \ sb_close.c \ sb_printf.c \ + sb_proc.c \ sb_memory.c \ include/rcscripts/rcutil.h \ include/rcscripts/util/str_list.h \ diff --git a/libsbutil/sb_backtrace.c b/libsbutil/sb_backtrace.c new file mode 100644 index 0000000..e3d1ed7 --- /dev/null +++ b/libsbutil/sb_backtrace.c @@ -0,0 +1,15 @@ +/* + * sb_backtrace.c + * + * Need to keep in a dedicated file so libsandbox can override. + * + * Copyright 1999-2012 Gentoo Foundation + * Licensed under the GPL-2 + */ + +#include "headers.h" +#include "sbutil.h" + +void __sb_dump_backtrace(void) +{ +} diff --git a/libsbutil/sb_efuncs.c b/libsbutil/sb_efuncs.c new file mode 100644 index 0000000..248c2bd --- /dev/null +++ b/libsbutil/sb_efuncs.c @@ -0,0 +1,190 @@ +/* + * sb_efuncs.c + * + * Helpers for doing pretty output. + * + * Copyright 1999-2012 Gentoo Foundation + * Licensed under the GPL-2 + */ + +#include "headers.h" +#include "sbutil.h" + +static bool nocolor, init_color = false; +void sb_efunc(const char *color, const char *hilight, const char *format, ...) +{ + save_errno(); + + int fd = STDERR_FILENO; + + if (!init_color) { + nocolor = is_env_on(ENV_NOCOLOR); + init_color = true; + } + + if (!nocolor) + sb_fdprintf(fd, "%s%s%s", color, hilight, COLOR_NORMAL); + else + sb_fdprintf(fd, "%s", hilight); + + va_list args; + va_start(args, format); + sb_vfdprintf(fd, format, args); + va_end(args); + + restore_errno(); +} + +const char *colors[] = { + "\033[0m", + "\033[32;01m", + "\033[33;01m", + "\033[31;01m", +}; +__attribute__((constructor)) +static void sbio_init(void) +{ + if (is_env_on(ENV_NOCOLOR)) + memset(colors, 0, sizeof(colors)); +} + +static bool try_portage_helpers = false; + +/* + * First try to use the helper programs from portage so that it can sanely + * log things itself, and so the output doesn't get consumed by something + * else #278761. If that fails, fall back to writing to /dev/tty. While + * this might annoy some people, using stderr will break tests that try to + * validate output #261957. + */ +static void sb_vefunc(const char *prog, const char *color, const char *format, va_list args) +{ + char shellcode[128]; + FILE *fp; + sighandler_t oldsig; + bool is_pipe = false; + + if (try_portage_helpers) { + /* If popen() fails, then writes to it will trigger SIGPIPE */ + /* XXX: convert this to sigaction */ + oldsig = signal(SIGPIPE, SIG_IGN); + + sprintf(shellcode, "xargs %s 2>/dev/null", prog); + fp = sbio_popen(shellcode, "we"); + is_pipe = true; + } else + fp = NULL; + + if (!fp) { + do_tty: + is_pipe = false; + int fd = sbio_open(sbio_fallback_path, O_WRONLY|O_CLOEXEC, 0); + if (fd >= 0) + fp = fdopen(fd, "ae"); + if (!fp) + fp = stderr; + } + + sb_fprintf(fp, " %s*%s ", color, COLOR_NORMAL); + sb_vfprintf(fp, format, args); + + if (is_pipe) { + int status = pclose(fp); + if (WEXITSTATUS(status)) + goto do_tty; + } else if (fp != stderr) + fclose(fp); + + if (try_portage_helpers) + signal(SIGPIPE, oldsig); +} + +void sb_einfo(const char *format, ...) +{ + va_list args; + va_start(args, format); + sb_vefunc("einfo", COLOR_GREEN, format, args); + va_end(args); +} + +void sb_debug_dyn(const char *format, ...) +{ + if (!is_env_on(ENV_SANDBOX_DEBUG)) + return; + + va_list args; + va_start(args, format); + sb_vefunc("einfo", COLOR_GREEN, format, args); + va_end(args); +} + +void sb_ewarn(const char *format, ...) +{ + va_list args; + va_start(args, format); + sb_vefunc("ewarn", COLOR_YELLOW, format, args); + va_end(args); +} + +void sb_eerror(const char *format, ...) +{ + va_list args; + va_start(args, format); + sb_vefunc("eerror", COLOR_RED, format, args); + va_end(args); +} + +void sb_eqawarn(const char *format, ...) +{ + va_list args; + va_start(args, format); + sb_vefunc("eqawarn", COLOR_YELLOW, format, args); + va_end(args); +} + +void sb_dump_backtrace(void) +{ +#ifdef HAVE_BACKTRACE + void *funcs[10]; + int num_funcs; + num_funcs = backtrace(funcs, ARRAY_SIZE(funcs)); + backtrace_symbols_fd(funcs, num_funcs, STDERR_FILENO); +#endif + __sb_dump_backtrace(); +} + +void __sb_ebort(const char *file, const char *func, size_t line_num, const char *format, ...) +{ + va_list args; + + sb_eerror("%s:%s():%zu: failure (%s):\n", file, func, line_num, strerror(errno)); + + va_start(args, format); + sb_vefunc("eerror", COLOR_RED, format, args); + va_end(args); + + sb_dump_backtrace(); + +#ifndef NDEBUG + if (is_env_on("SANDBOX_GDB")) { + sb_einfo("attempting to autolaunch gdb; please wait ...\n\n"); + pid_t crashed_pid = getpid(); + switch (fork()) { + case -1: break; + case 0: { + char pid[10]; + snprintf(pid, sizeof(pid), "%i", crashed_pid); + unsetenv(ENV_LD_PRELOAD); + /*sb_unwrapped_*/execlp("gdb", "gdb", "--quiet", "--pid", pid, "-ex", "bt full", NULL); + break; + } + default: { + int status; + wait(&status); + } + } + } +#endif + + abort(); +} diff --git a/libsbutil/sb_memory.c b/libsbutil/sb_memory.c index 40a4762..bdc054f 100644 --- a/libsbutil/sb_memory.c +++ b/libsbutil/sb_memory.c @@ -1,5 +1,5 @@ /* - * debug.c + * sb_memory.c * * Simle debugging/logging macro's and functions. * @@ -16,11 +16,8 @@ __xcalloc(size_t nmemb, size_t size, const char *file, const char *func, size_t { void *ret = calloc(nmemb, size); - if (ret == NULL) { - SB_EERROR("calloc()", " %s:%s():%zu: calloc(%zu, %zu) failed: %s\n", - file, func, line, nmemb, size, strerror(errno)); - abort(); - } + if (ret == NULL) + __sb_ebort(file, func, line, "calloc(%zu, %zu)\n", nmemb, size); return ret; } @@ -30,11 +27,8 @@ __xmalloc(size_t size, const char *file, const char *func, size_t line) { void *ret = malloc(size); - if (ret == NULL) { - SB_EERROR("malloc()", " %s:%s():%zu: malloc(%zu) failed: %s\n", - file, func, line, size, strerror(errno)); - abort(); - } + if (ret == NULL) + __sb_ebort(file, func, line, "malloc(%zu)\n", size); return ret; } @@ -50,11 +44,8 @@ __xrealloc(void *ptr, size_t size, const char *file, const char *func, size_t li { void *ret = realloc(ptr, size); - if (ret == NULL) { - SB_EERROR("realloc()", " %s:%s():%zu: realloc(%p, %zu) failed: %s\n", - file, func, line, ptr, size, strerror(errno)); - abort(); - } + if (ret == NULL) + __sb_ebort(file, func, line, "realloc(%p, %zu)\n", ptr, size); return ret; } @@ -64,11 +55,8 @@ __xstrdup(const char *str, const char *file, const char *func, size_t line) { char *ret = strdup(str); - if (ret == NULL) { - SB_EERROR("strdup()", " %s:%s():%zu: strdup(%p) failed: %s\n", - file, func, line, str, strerror(errno)); - abort(); - } + if (ret == NULL) + __sb_ebort(file, func, line, "strdup(%p)\n", str); return ret; } @@ -94,11 +82,8 @@ __xstrndup(const char *str, size_t size, const char *file, const char *func, siz { char *ret = strndup(str, size); - if (ret == NULL) { - SB_EERROR("strndup()", " %s:%s():%zu: strndup(%p, %zu) failed: %s\n", - file, func, line, str, size, strerror(errno)); - abort(); - } + if (ret == NULL) + __sb_ebort(file, func, line, "strndup(%p, %zu)\n", str, size); return ret; } diff --git a/libsbutil/sb_printf.c b/libsbutil/sb_printf.c index d3a27df..1ad9e23 100644 --- a/libsbutil/sb_printf.c +++ b/libsbutil/sb_printf.c @@ -187,28 +187,3 @@ void sb_printf(const char *format, ...) sb_vfdprintf(STDERR_FILENO, format, args); va_end(args); } - -static bool nocolor, init_color = false; -void sb_efunc(const char *color, const char *hilight, const char *format, ...) -{ - save_errno(); - - int fd = STDERR_FILENO; - - if (!init_color) { - nocolor = is_env_on(ENV_NOCOLOR); - init_color = true; - } - - if (!nocolor) - sb_fdprintf(fd, "%s%s%s", color, hilight, COLOR_NORMAL); - else - sb_fdprintf(fd, "%s", hilight); - - va_list args; - va_start(args, format); - sb_vfdprintf(fd, format, args); - va_end(args); - - restore_errno(); -} diff --git a/libsbutil/sb_proc.c b/libsbutil/sb_proc.c new file mode 100644 index 0000000..c583d95 --- /dev/null +++ b/libsbutil/sb_proc.c @@ -0,0 +1,31 @@ +/* + * funcs for poking around /proc + * + * Copyright 1999-2012 Gentoo Foundation + * Licensed under the GPL-2 + */ + +#include "headers.h" +#include "sbutil.h" + +const char sb_fd_dir[] = +#if defined(SANDBOX_PROC_SELF_FD) + "/proc/self/fd" +#elif defined(SANDBOX_DEV_FD) + "/dev/fd" +#else +# error "how do i access a proc's fd/ tree ?" +#endif +; + +const char *sb_get_cmdline(pid_t pid) +{ +#if !defined(SANDBOX_PROC_1_CMDLINE) && !defined(SANDBOX_PROC_SELF_CMDLINE) && !defined(SANDBOX_PROC_dd_CMDLINE) +# error "how do i access a proc's cmdline ?" +#endif + static char path[256]; + if (!pid) + pid = getpid(); + sprintf(path, "/proc/%i/cmdline", pid); + return path; +} diff --git a/libsbutil/sb_write_fd.c b/libsbutil/sb_write_fd.c new file mode 100644 index 0000000..f19d7de --- /dev/null +++ b/libsbutil/sb_write_fd.c @@ -0,0 +1,42 @@ +/* + * helper for sucking up a file and writing it to a fd. + * good for copying the contents of small status files + * into a log file. + * + * Copyright 1999-2012 Gentoo Foundation + * Licensed under the GPL-2 + */ + +#include "headers.h" +#include "sbutil.h" + +int sb_copy_file_to_fd(const char *file, int ofd) +{ + int ret = -1; + + int ifd = sb_open(file, O_RDONLY|O_CLOEXEC, 0); + if (ifd == -1) + return ret; + + size_t pagesz = getpagesize(); + char *buf = xmalloc(pagesz); + while (1) { + size_t len = sb_read(ifd, buf, pagesz); + if (len == -1) + goto error; + else if (!len) + break; + size_t i; + for (i = 0; i < len; ++i) + if (!buf[i]) + buf[i] = ' '; + if (sb_write(ofd, buf, len) != len) + goto error; + } + + ret = 0; + error: + sb_close(ifd); + free(buf); + return ret; +} diff --git a/libsbutil/sbutil.h b/libsbutil/sbutil.h index f45402e..f275514 100644 --- a/libsbutil/sbutil.h +++ b/libsbutil/sbutil.h @@ -42,8 +42,7 @@ #define ENV_SANDBOX_VERBOSE "SANDBOX_VERBOSE" #define ENV_SANDBOX_DEBUG "SANDBOX_DEBUG" -extern const char env_sandbox_testing[]; -#define ENV_SANDBOX_TESTING env_sandbox_testing +#define ENV_SANDBOX_TESTING "__SANDBOX_TESTING" #define ENV_SANDBOX_LIB "SANDBOX_LIB" #define ENV_SANDBOX_BASHRC "SANDBOX_BASHRC" @@ -67,15 +66,11 @@ extern const char env_sandbox_testing[]; #define SB_BUF_LEN 2048 -#define COLOR_NORMAL "\033[0m" -#define COLOR_GREEN "\033[32;01m" -#define COLOR_YELLOW "\033[33;01m" -#define COLOR_RED "\033[31;01m" - -/* Gentoo style e* printing macro's */ -#define SB_EINFO(_hilight, _args...) sb_efunc(COLOR_GREEN, _hilight, _args) -#define SB_EWARN(_hilight, _args...) sb_efunc(COLOR_YELLOW, _hilight, _args) -#define SB_EERROR(_hilight, _args...) sb_efunc(COLOR_RED, _hilight, _args) +extern const char *colors[]; +#define COLOR_NORMAL colors[0] +#define COLOR_GREEN colors[1] +#define COLOR_YELLOW colors[2] +#define COLOR_RED colors[3] char *get_sandbox_conf(void); char *get_sandbox_confd(char *path); @@ -87,19 +82,41 @@ int get_tmp_dir(char *path); bool is_env_on (const char *); bool is_env_off (const char *); +/* proc helpers */ +extern const char sb_fd_dir[]; +#define sb_get_fd_dir() sb_fd_dir +const char *sb_get_cmdline(pid_t pid); + /* libsandbox need to use a wrapper for open */ attribute_hidden extern int (*sbio_open)(const char *, int, mode_t); +attribute_hidden extern FILE *(*sbio_popen)(const char *, const char *); +extern const char sbio_fallback_path[]; /* Convenience functions to reliably open, read and write to a file */ int sb_open(const char *path, int flags, mode_t mode); size_t sb_read(int fd, void *buf, size_t count); size_t sb_write(int fd, const void *buf, size_t count); int sb_close(int fd); +int sb_copy_file_to_fd(const char *file, int ofd); /* Reliable output */ __printf(1, 2) void sb_printf(const char *format, ...); __printf(2, 3) void sb_fdprintf(int fd, const char *format, ...); __printf(2, 0) void sb_vfdprintf(int fd, const char *format, va_list args); __printf(3, 4) void sb_efunc(const char *color, const char *hilight, const char *format, ...); +__printf(1, 2) void sb_einfo(const char *format, ...); +__printf(1, 2) void sb_ewarn(const char *format, ...); +__printf(1, 2) void sb_eerror(const char *format, ...); +__printf(1, 2) void sb_eqawarn(const char *format, ...); +__printf(1, 2) void sb_debug_dyn(const char *format, ...); +__printf(4, 5) void __sb_ebort(const char *file, const char *func, size_t line_num, const char *format, ...) __noreturn; +#define sb_ebort(format, ...) __sb_ebort(__FILE__, __func__, __LINE__, format, ## __VA_ARGS__) +void sb_dump_backtrace(void); +void __sb_dump_backtrace(void); +#define sb_assert(cond) \ + do { \ + if (!(cond)) \ + sb_ebort("assertion failure !(%s)\n", #cond); \ + } while (0) #define sb_fprintf(fp, ...) sb_fdprintf(fileno(fp), __VA_ARGS__) #define sb_vfprintf(fp, ...) sb_vfdprintf(fileno(fp), __VA_ARGS__) |