From 7b9d199ec80aec60bfac5d956e483a5bfa868d3a Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Thu, 7 Nov 2013 17:23:08 +0100 Subject: [PATCH] make system calls safer/clean up headers wrap some libc functions that do system calls (terminal output) wrap read/write with syscall guard define real_read/write (next dynamic linker find for read/write) guard system calls in remaining code introduce native_internhal.h throw out some debug statements that break things clean up includes a bit declare board_init in native_internhal.h add -ldl to LINKFLAGS for cpu/syscalls --- boards/native/Makefile.include | 2 +- boards/native/drivers/native-uart0.c | 37 +++--- boards/native/include/board_internal.h | 2 + cpu/native/hwtimer_cpu.c | 6 +- cpu/native/include/cpu.h | 28 ++--- cpu/native/include/native_internal.h | 57 +++++++++ cpu/native/include/nativenet_internal.h | 2 +- cpu/native/irq_cpu.c | 74 +++++------- cpu/native/lpm_cpu.c | 11 +- cpu/native/native_cpu.c | 8 +- cpu/native/net/tap.c | 5 +- cpu/native/rtc/posix-rtc.c | 10 +- cpu/native/startup.c | 20 ++- cpu/native/syscalls.c | 154 ++++++++++++++++++++++++ 14 files changed, 314 insertions(+), 102 deletions(-) create mode 100644 cpu/native/include/native_internal.h create mode 100644 cpu/native/syscalls.c diff --git a/boards/native/Makefile.include b/boards/native/Makefile.include index 1a5b2e4d2d..ddd689541b 100644 --- a/boards/native/Makefile.include +++ b/boards/native/Makefile.include @@ -14,7 +14,7 @@ export OBJCOPY = $(PREFIX)objcopy FLASHER = lpc2k_pgm TERM = pyterm.py -LINKFLAGS += -m32 -gc +LINKFLAGS += -m32 -gc -ldl ifeq ($(strip $(PORT)),) export PORT = /dev/ttyUSB0 diff --git a/boards/native/drivers/native-uart0.c b/boards/native/drivers/native-uart0.c index b9d8b041d3..38720fd3c9 100644 --- a/boards/native/drivers/native-uart0.c +++ b/boards/native/drivers/native-uart0.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include @@ -13,21 +15,27 @@ #include "debug.h" #include "board_uart0.h" -int _native_uart_in; -int _native_uart_out; +#include "native_internal.h" + +static int _native_uart_in; fd_set _native_uart_rfds; -inline int uart0_puts(char *astring, int length) +int uart0_puts(char *astring, int length) { int nwritten, offset; nwritten = 0; offset = 0; - _native_in_syscall = 1; - - while ((length > 0) &&(nwritten = write(_native_uart_out, astring+offset, length-offset)) > 0) { + while ( + (length - offset > 0) && ( + (nwritten = write( + STDOUT_FILENO, + astring+offset, + length-offset) + ) > 0) + ) { offset += nwritten; } if (nwritten == -1) { @@ -38,8 +46,6 @@ inline int uart0_puts(char *astring, int length) errx(EXIT_FAILURE, "uart0_puts: Could not write to stdout. I don't know what to do now."); } - _native_in_syscall = 0; - return length; } @@ -53,8 +59,6 @@ void _native_handle_uart0_input() return; } DEBUG("_native_handle_uart0_input\n"); - _native_in_syscall = 0; - _native_in_isr = 1; nread = read(_native_uart_in, buf, sizeof(buf)); if (nread == -1) { @@ -66,33 +70,28 @@ void _native_handle_uart0_input() * with properly in #161 */ close(_native_uart_in); _native_uart_in = -1; - warnx("stdin closed"); + printf("stdin closed"); } for(int pos = 0; pos < nread; pos++) { uart0_handle_incoming(buf[pos]); } uart0_notify_thread(); - _native_in_isr = 0; thread_yield(); } int _native_set_uart_fds(void) { DEBUG("_native_set_uart_fds"); - FD_SET(_native_uart_in, &_native_rfds); + if (_native_uart_in != -1) { + FD_SET(_native_uart_in, &_native_rfds); + } return _native_uart_in; } void _native_init_uart0() { - _native_uart_out = STDOUT_FILENO; _native_uart_in = STDIN_FILENO; puts("RIOT native uart0 initialized."); } - -int putchar(int c) { - write(_native_uart_out, &c, 1); - return 0; -} diff --git a/boards/native/include/board_internal.h b/boards/native/include/board_internal.h index 368d5287de..8af1433e4c 100644 --- a/boards/native/include/board_internal.h +++ b/boards/native/include/board_internal.h @@ -4,3 +4,5 @@ void _native_handle_uart0_input(void); void _native_init_uart0(void); int _native_set_uart_fds(void); #endif + +void board_init(void); diff --git a/cpu/native/hwtimer_cpu.c b/cpu/native/hwtimer_cpu.c index 62767deac4..cfe8358804 100644 --- a/cpu/native/hwtimer_cpu.c +++ b/cpu/native/hwtimer_cpu.c @@ -31,12 +31,14 @@ #include #include #include + #include "hwtimer.h" #include "hwtimer_arch.h" #include "hwtimer_cpu.h" #include "cpu.h" #include "cpu-conf.h" +#include "native_internal.h" #define ENABLE_DEBUG (0) @@ -223,7 +225,7 @@ unsigned long hwtimer_arch_now(void) DEBUG("hwtimer_arch_now()\n"); - _native_in_syscall = 1; + _native_syscall_enter(); #ifdef __MACH__ clock_serv_t cclock; mach_timespec_t mts; @@ -239,7 +241,7 @@ unsigned long hwtimer_arch_now(void) } #endif - _native_in_syscall = 0; + _native_syscall_leave(); native_hwtimer_now = ts2ticks(&t) - time_null; diff --git a/cpu/native/include/cpu.h b/cpu/native/include/cpu.h index 9ff80eea0b..37a449c373 100644 --- a/cpu/native/include/cpu.h +++ b/cpu/native/include/cpu.h @@ -27,16 +27,22 @@ * http://sourceforge.net/p/predef/wiki/OperatingSystems/ */ #ifdef BSD // BSD = (FreeBSD, Darwin, ...) +#ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE -#elif defined(__linux__) -#define __USE_GNU -#endif #include -#ifdef BSD #undef _XOPEN_SOURCE -#elif defined(__linux__) -#undef __USE_GNU +#else +#include #endif +#elif defined(__linux__) +#ifndef _GNU_SOURCE +#define GNU_SOURCE +#include +#undef GNU_SOURCE +#else +#include +#endif +#endif // BSD/Linux #include "kernel_internal.h" #include "sched.h" @@ -62,15 +68,5 @@ int unregister_interrupt(int sig); /* this should be defined elsewhere */ void thread_yield(void); -extern void _native_sig_leave_tramp(void); -extern ucontext_t *_native_cur_ctx, *_native_isr_ctx; -extern volatile unsigned int _native_saved_eip; -extern volatile int _native_in_isr; -extern volatile int _native_in_syscall; -extern volatile int _native_sigpend; -#ifdef MODULE_UART0 -#include -extern fd_set _native_rfds; -#endif /** @} */ #endif //_CPU_H diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h new file mode 100644 index 0000000000..8eab3e609a --- /dev/null +++ b/cpu/native/include/native_internal.h @@ -0,0 +1,57 @@ +/** + * Native CPU internal declarations + */ + +/** + * @ingroup arch + * @defgroup native_cpu Native CPU + * @{ + * @author Ludwig Ortmann + */ + +#ifndef _NATIVE_INTERNAL_H +#define _NATIVE_INTERNAL_H + +//#include + +/** + * internal functions + */ +void native_cpu_init(void); +void native_interrupt_init(void); + +void native_irq_handler(); +extern void _native_sig_leave_tramp(void); + +void _native_syscall_leave(); +void _native_syscall_enter(); + +/** + * external functions regularly wrapped in native for direct use + */ +extern ssize_t (*real_read)(int fd, void *buf, size_t count); +extern ssize_t (*real_write)(int fd, const void *buf, size_t count); + +/** + * data structures + */ +extern volatile int native_interrupts_enabled; +extern volatile unsigned int _native_saved_eip; +extern int _sig_pipefd[2]; +extern volatile int _native_sigpend; +extern volatile int _native_in_isr; +extern volatile int _native_in_syscall; + +extern char __isr_stack[SIGSTKSZ]; +extern char __end_stack[SIGSTKSZ]; +extern ucontext_t native_isr_context; +extern ucontext_t end_context; +extern ucontext_t *_native_cur_ctx, *_native_isr_ctx; + +#ifdef MODULE_UART0 +#include +extern fd_set _native_rfds; +#endif + +/** @} */ +#endif /* _NATIVE_INTERNAL_H */ diff --git a/cpu/native/include/nativenet_internal.h b/cpu/native/include/nativenet_internal.h index 2c973aa010..ea7f4b0204 100644 --- a/cpu/native/include/nativenet_internal.h +++ b/cpu/native/include/nativenet_internal.h @@ -37,7 +37,7 @@ struct rx_buffer_s { char data[NATIVE_MAX_DATA_LENGTH]; }; -extern struct rx_buffer_s _nativenet_rx_buffer[]; +extern struct rx_buffer_s _nativenet_rx_buffer[RX_BUF_SIZE]; void _nativenet_handle_packet(radio_packet_t *packet); #endif /* NATIVENET_INTERNAL_H */ diff --git a/cpu/native/irq_cpu.c b/cpu/native/irq_cpu.c index b8168f6b91..b899534a3f 100644 --- a/cpu/native/irq_cpu.c +++ b/cpu/native/irq_cpu.c @@ -13,6 +13,7 @@ * @file * @author Ludwig Ortmann */ + #include #include #include @@ -39,24 +40,28 @@ #include "lpm.h" +#include "native_internal.h" + #define ENABLE_DEBUG (0) #include "debug.h" -volatile int native_interrupts_enabled; - -volatile int _native_sigpend; -volatile int _native_in_isr; -volatile int _native_in_syscall; -ucontext_t native_isr_context; -static sigset_t native_sig_set; -static char __isr_stack[SIGSTKSZ]; extern volatile tcb_t *active_thread; -volatile unsigned int _native_saved_eip; +volatile int native_interrupts_enabled; +volatile int _native_in_isr; +volatile int _native_in_syscall; + +static sigset_t native_sig_set; + +char __isr_stack[SIGSTKSZ]; +ucontext_t native_isr_context; ucontext_t *_native_cur_ctx, *_native_isr_ctx; + int *process_heap_address; -static int pipefd[2]; +volatile unsigned int _native_saved_eip; +volatile int _native_sigpend; +int _sig_pipefd[2]; struct int_handler_t { void (*func)(void); @@ -64,10 +69,6 @@ struct int_handler_t { static struct int_handler_t native_irq_handlers[255]; char sigalt_stk[SIGSTKSZ]; - -void native_irq_handler(); - - void print_thread_sigmask(ucontext_t *cp) { sigset_t *p = &cp->uc_sigmask; @@ -149,7 +150,7 @@ unsigned disableIRQ(void) unsigned int prev_state; sigset_t mask; - _native_in_syscall = 1; + _native_syscall_enter(); DEBUG("disableIRQ()\n"); if (_native_in_isr == 1) { @@ -179,7 +180,7 @@ unsigned disableIRQ(void) native_interrupts_enabled = 0; DEBUG("disableIRQ(): return\n"); - _native_in_syscall = 0; + _native_syscall_leave(); return prev_state; } @@ -191,7 +192,7 @@ unsigned enableIRQ(void) { unsigned int prev_state; - _native_in_syscall = 1; + _native_syscall_enter(); DEBUG("enableIRQ()\n"); if (_native_in_isr == 1) { @@ -204,21 +205,7 @@ unsigned enableIRQ(void) prev_state = native_interrupts_enabled; native_interrupts_enabled = 1; - - //print_sigmasks(); - //native_print_signals(); - if ((_native_sigpend > 0) && (_native_in_isr == 0)) { - _native_cur_ctx = (ucontext_t *)active_thread->sp; - DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n"); - _native_in_syscall = 0; - DEBUG("enableIRQ: calling swapcontext()\n"); - DEBUG("enableIRQ: _native_cur_ctx == %p, _native_isr_ctx == %p\n", _native_cur_ctx, _native_isr_ctx); - makecontext(&native_isr_context, native_irq_handler, 0); - swapcontext(_native_cur_ctx, _native_isr_ctx); - } - else { - _native_in_syscall = 0; - } + _native_syscall_leave(); DEBUG("enableIRQ(): return\n"); @@ -264,16 +251,14 @@ int _native_popsig(void) nleft = sizeof(int); i = 0; - _native_in_syscall = 1; - while ((nleft > 0) && ((nread = read(pipefd[0], ((uint8_t*)&sig) + i, nleft)) != -1)) { + while ((nleft > 0) && ((nread = real_read(_sig_pipefd[0], ((uint8_t*)&sig) + i, nleft)) != -1)) { i += nread; nleft -= nread; } if (nread == -1) { - err(1, "_native_popsig(): read()"); + err(1, "_native_popsig(): real_read()"); } - _native_in_syscall = 0; return sig; } @@ -318,13 +303,14 @@ void native_irq_handler() void native_isr_entry(int sig, siginfo_t *info, void *context) { (void) info; /* unused at the moment */ - DEBUG("\n\n\t\tnative_isr_entry\n\n"); + //printf("\n\033[33m\n\t\tnative_isr_entry(%i)\n\n\033[0m", sig); /* save the signal */ - if (write(pipefd[1], &sig, sizeof(int)) == -1) { - err(1, "native_isr_entry(): write()"); + if (real_write(_sig_pipefd[1], &sig, sizeof(int)) == -1) { + err(1, "native_isr_entry(): real_write()"); } _native_sigpend++; + //real_write(STDOUT_FILENO, "sigpend\n", 8); makecontext(&native_isr_context, native_irq_handler, 0); _native_cur_ctx = (ucontext_t *)active_thread->sp; @@ -332,7 +318,7 @@ void native_isr_entry(int sig, siginfo_t *info, void *context) /* XXX: Workaround safety check - whenever this happens it really * indicates a bug in disableIRQ */ if (native_interrupts_enabled == 0) { - warnx("interrupts are off, but I caught a signal."); + //printf("interrupts are off, but I caught a signal.\n"); return; } @@ -351,11 +337,12 @@ void native_isr_entry(int sig, siginfo_t *info, void *context) ((void*)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP])) > ((void*)process_heap_address) ) { - DEBUG("\n\033[36mEIP:\t%p\nHEAP:\t%p\nnot switching\n\n\033[0m", (void*)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP], (void*)process_heap_address); + //printf("\n\033[36mEIP:\t%p\nHEAP:\t%p\nnot switching\n\n\033[0m", (void*)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP], (void*)process_heap_address); } else { + _native_in_isr = 1; - DEBUG("\n\033[31mEIP:\t%p\nHEAP:\t%p\ngo switching\n\n\033[0m", (void*)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP], (void*)process_heap_address); + //printf("\n\033[31mEIP:\t%p\nHEAP:\t%p\ngo switching\n\n\033[0m", (void*)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP], (void*)process_heap_address); _native_saved_eip = ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]; ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP] = (unsigned int)&_native_sig_leave_tramp; } @@ -515,13 +502,14 @@ void native_interrupt_init(void) _native_in_syscall = 0; - if (pipe(pipefd) == -1) { + if (pipe(_sig_pipefd) == -1) { err(1, "native_interrupt_init(): pipe()"); } /* allow for ctrl+c to shut down gracefully */ register_interrupt(SIGINT, shutdown); + puts("RIOT native interrupts/signals initialized."); } /** @} */ diff --git a/cpu/native/lpm_cpu.c b/cpu/native/lpm_cpu.c index c85c9d7ad5..f8975831ad 100644 --- a/cpu/native/lpm_cpu.c +++ b/cpu/native/lpm_cpu.c @@ -28,6 +28,8 @@ #include "lpm.h" #include "debug.h" #include "cpu.h" + +#include "native_internal.h" #ifdef MODULE_UART0 #include "board_internal.h" #endif @@ -51,7 +53,10 @@ void _native_lpm_sleep() nfds = _native_set_uart_fds(); nfds++; + _native_in_syscall++; // no switching here nfds = select(nfds, &_native_rfds, NULL, NULL, NULL); + _native_in_syscall--; + DEBUG("_native_lpm_sleep: returned: %i\n", nfds); if (nfds != -1) { @@ -71,9 +76,8 @@ void _native_lpm_sleep() if (_native_sigpend > 0) { DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n"); - _native_in_syscall = 0; - _native_in_isr = 1; - swapcontext(_native_cur_ctx, _native_isr_ctx); + _native_in_syscall++; + _native_syscall_leave(); } } @@ -98,7 +102,6 @@ enum lpm_mode lpm_set(enum lpm_mode target) case LPM_IDLE: //DEBUG("lpm_set(): pause()\n"); - _native_in_syscall = 1; //pause(); _native_lpm_sleep(); break; diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index 561db15ee8..e26d62c063 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -42,12 +42,15 @@ #include "cpu.h" #include "cpu-conf.h" +#include "native_internal.h" + #define ENABLE_DEBUG (0) #include "debug.h" extern volatile tcb_t *active_thread; -static ucontext_t end_context; -static char __end_stack[SIGSTKSZ]; + +ucontext_t end_context; +char __end_stack[SIGSTKSZ]; #ifdef MODULE_UART0 fd_set _native_rfds; @@ -104,7 +107,6 @@ char *thread_stack_init(void (*task_func)(void), void *stack_start, int stacksiz void cpu_switch_context_exit(void) { ucontext_t *ctx; - extern int native_interrupts_enabled; DEBUG("XXX: cpu_switch_context_exit()\n"); if ((sched_context_switch_request == 1) || (active_thread == NULL)) { diff --git a/cpu/native/net/tap.c b/cpu/native/net/tap.c index 6292dd84b9..5d81f734ec 100644 --- a/cpu/native/net/tap.c +++ b/cpu/native/net/tap.c @@ -44,6 +44,7 @@ #include "tap.h" #include "nativenet.h" #include "nativenet_internal.h" +#include "native_internal.h" #define TAP_BUFFER_LENGTH (ETHER_MAX_LEN) int _native_marshall_ethernet(uint8_t *framebuf, radio_packet_t *packet); @@ -62,9 +63,7 @@ void _native_handle_tap_input(void) /* TODO: check whether this is an input or an output event TODO: refactor this into general io-signal multiplexer */ - _native_in_syscall = 1; - nread = read(_native_tap_fd, &frame, sizeof(union eth_frame)); - _native_in_syscall = 0; + nread = real_read(_native_tap_fd, &frame, sizeof(union eth_frame)); DEBUG("_native_handle_tap_input - read %d bytes\n", nread); if (nread > 0) { if (ntohs(frame.field.header.ether_type) == NATIVE_ETH_PROTO) { diff --git a/cpu/native/rtc/posix-rtc.c b/cpu/native/rtc/posix-rtc.c index f917d41018..cde2ecf201 100644 --- a/cpu/native/rtc/posix-rtc.c +++ b/cpu/native/rtc/posix-rtc.c @@ -26,6 +26,8 @@ #include "rtc.h" #include "cpu.h" +#include "native_internal.h" + static int native_rtc_enabled; void rtc_init(void) @@ -59,24 +61,24 @@ void rtc_get_localtime(struct tm *localt) time_t t; if (native_rtc_enabled == 1) { - _native_in_syscall++; + _native_syscall_enter(); t = time(NULL); if (localtime_r(&t, localt) == NULL) { err(1, "rtc_get_localtime: localtime_r"); } - _native_in_syscall--; + _native_syscall_leave(); } } time_t rtc_time(struct timeval *time) { if (native_rtc_enabled == 1) { - _native_in_syscall++; + _native_syscall_enter(); if (gettimeofday(time, NULL) == -1) { err(1, "rtc_time: gettimeofday"); } - _native_in_syscall--; + _native_syscall_leave(); } return time->tv_sec; } diff --git a/cpu/native/startup.c b/cpu/native/startup.c index befc8a8e89..d37b4b3f93 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -14,21 +14,29 @@ * @} */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#include +#else +#include +#endif + #include #include #include -#include -#include +#include "kernel_internal.h" +#include "cpu.h" + +#include "native_internal.h" #include "tap.h" -extern void board_init(void); -extern void native_cpu_init(void); -extern void native_interrupt_init(void); - __attribute__((constructor)) static void startup(int argc, char **argv) { + /* get system read/write */ + *(void **)(&real_read) = dlsym(RTLD_NEXT, "read"); + *(void **)(&real_write) = dlsym(RTLD_NEXT, "write"); #ifdef MODULE_NATIVENET if (argc < 2) { diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c new file mode 100644 index 0000000000..72efdcadcc --- /dev/null +++ b/cpu/native/syscalls.c @@ -0,0 +1,154 @@ +/** + * Native CPU syscall managing + * + * Wrap system calls and system call invoking library calls to make + * sure no context switches happen during a system call. + * + * Copyright (C) 2013 Ludwig Ortmann + * + * This file subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + * + * @ingroup native_cpu + * @{ + * @file + * @author Ludwig Ortmann + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "cpu.h" + +#include "native_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +extern volatile tcb_t *active_thread; + +ssize_t (*real_read)(int fd, void *buf, size_t count); +ssize_t (*real_write)(int fd, const void *buf, size_t count); + +void _native_syscall_enter() +{ + _native_in_syscall++; + DEBUG("> _native_in_syscall: %d\n", _native_in_syscall); +} + +void _native_syscall_leave() +{ + _native_in_syscall--; + DEBUG("< _native_in_syscall: %d\n", _native_in_syscall); + if ((_native_sigpend > 0) && (_native_in_isr == 0) && (_native_in_syscall == 0)) { + _native_in_isr = 1; + _native_cur_ctx = (ucontext_t *)active_thread->sp; + makecontext(&native_isr_context, native_irq_handler, 0); + swapcontext(_native_cur_ctx, &native_isr_context); + } +} + +ssize_t read(int fd, void *buf, size_t count) +{ + ssize_t r; + + _native_syscall_enter(); + r = real_read(fd, buf, count); + _native_syscall_leave(); + + return r; +} + +ssize_t write(int fd, const void *buf, size_t count) +{ + ssize_t r; + + _native_syscall_enter(); + //real_write(fd, "real_write: ", 12); + r = real_write(fd, buf, count); + _native_syscall_leave(); + + return r; +} + +int putchar(int c) { + write(STDOUT_FILENO, &c, 1); + return 0; +} + +int puts(const char *s) +{ + int r; + r = write(STDOUT_FILENO, (char*)s, strlen(s)); + putchar('\n'); + return r; +} + +char *make_message(const char *format, va_list argp) +{ + int n; + int size = 100; + char *message, *temp; + + if ((message = malloc(size)) == NULL) + return NULL; + + while (1) { + n = vsnprintf(message, size, format, argp); + if (n < 0) + return NULL; + if (n < size) + return message; + size = n + 1; + if ((temp = realloc(message, size)) == NULL) { + free(message); + return NULL; + } else { + message = temp; + } + } +} + +int printf(const char *format, ...) +{ + int r; + va_list argp; + char *m; + + va_start(argp, format); + if ((m = make_message(format, argp)) == NULL) { + err(EXIT_FAILURE, "malloc"); + } + r = write(STDOUT_FILENO, m, strlen(m)); + va_end(argp); + free(m); + + return r; +} + + +int vprintf(const char *format, va_list argp) +{ + int r; + char *m; + + if ((m = make_message(format, argp)) == NULL) { + err(EXIT_FAILURE, "malloc"); + } + r = write(STDOUT_FILENO, m, strlen(m)); + free(m); + + return r; +}