busybox/libbb/verror_msg.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Utility routines.
   4 *
   5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
   6 *
   7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9#include "libbb.h"
  10#if ENABLE_FEATURE_SYSLOG
  11# include <syslog.h>
  12#endif
  13
  14#if ENABLE_FEATURE_SYSLOG
  15static smallint syslog_level = LOG_ERR;
  16#endif
  17smallint logmode = LOGMODE_STDIO;
  18const char *msg_eol = "\n";
  19
  20void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
  21{
  22        char *msg, *msg1;
  23        char stack_msg[80];
  24        int applet_len, strerr_len, msgeol_len, used;
  25
  26        if (!logmode)
  27                return;
  28
  29        if (!s) /* nomsg[_and_die] uses NULL fmt */
  30                s = ""; /* some libc don't like printf(NULL) */
  31
  32        applet_len = strlen(applet_name) + 2; /* "applet: " */
  33        strerr_len = strerr ? strlen(strerr) : 0;
  34        msgeol_len = strlen(msg_eol);
  35
  36        /* This costs ~90 bytes of code, but avoids costly
  37         * malloc()[in vasprintf]+realloc()+memmove()+free() in 99% of cases.
  38         * ~40% speedup.
  39         */
  40        if ((int)sizeof(stack_msg) - applet_len > 0) {
  41                va_list p2;
  42
  43                /* It is not portable to use va_list twice, need to va_copy it */
  44                va_copy(p2, p);
  45                used = vsnprintf(stack_msg + applet_len, (int)sizeof(stack_msg) - applet_len, s, p2);
  46                va_end(p2);
  47                msg = stack_msg;
  48                used += applet_len;
  49                if (used < (int)sizeof(stack_msg) - 3 - msgeol_len - strerr_len)
  50                        goto add_pfx_and_sfx;
  51        }
  52
  53        used = vasprintf(&msg, s, p);
  54        if (used < 0)
  55                return;
  56
  57        /* This is ugly and costs +60 bytes compared to multiple
  58         * fprintf's, but is guaranteed to do a single write.
  59         * This is needed for e.g. httpd logging, when multiple
  60         * children can produce log messages simultaneously. */
  61
  62        /* can't use xrealloc: it calls error_msg on failure,
  63         * that may result in a recursion */
  64        /* +3 is for ": " before strerr and for terminating NUL */
  65        msg1 = realloc(msg, applet_len + used + strerr_len + msgeol_len + 3);
  66        if (!msg1) {
  67                msg[used++] = '\n'; /* overwrites NUL */
  68                applet_len = 0;
  69        } else {
  70                msg = msg1;
  71                /* TODO: maybe use writev instead of memmoving? Need full_writev? */
  72                memmove(msg + applet_len, msg, used);
  73                used += applet_len;
  74 add_pfx_and_sfx:
  75                strcpy(msg, applet_name);
  76                msg[applet_len - 2] = ':';
  77                msg[applet_len - 1] = ' ';
  78                if (strerr) {
  79                        if (s[0]) { /* not perror_nomsg? */
  80                                msg[used++] = ':';
  81                                msg[used++] = ' ';
  82                        }
  83                        strcpy(&msg[used], strerr);
  84                        used += strerr_len;
  85                }
  86                strcpy(&msg[used], msg_eol);
  87                used += msgeol_len;
  88        }
  89
  90        if (logmode & LOGMODE_STDIO) {
  91                fflush_all();
  92                full_write(STDERR_FILENO, msg, used);
  93        }
  94#if ENABLE_FEATURE_SYSLOG
  95        if (logmode & LOGMODE_SYSLOG) {
  96                syslog(syslog_level, "%s", msg + applet_len);
  97        }
  98#endif
  99        if (msg != stack_msg)
 100                free(msg);
 101}
 102
 103#ifdef VERSION_WITH_WRITEV
 104/* Code size is approximately the same, but currently it's the only user
 105 * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */
 106void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
 107{
 108        int strerr_len, msgeol_len;
 109        struct iovec iov[3];
 110
 111#define used   (iov[2].iov_len)
 112#define msgv   (iov[2].iov_base)
 113#define msgc   ((char*)(iov[2].iov_base))
 114#define msgptr (&(iov[2].iov_base))
 115
 116        if (!logmode)
 117                return;
 118
 119        if (!s) /* nomsg[_and_die] uses NULL fmt */
 120                s = ""; /* some libc don't like printf(NULL) */
 121
 122        /* Prevent "derefing type-punned ptr will break aliasing rules" */
 123        used = vasprintf((char**)(void*)msgptr, s, p);
 124        if (used < 0)
 125                return;
 126
 127        /* This is ugly and costs +60 bytes compared to multiple
 128         * fprintf's, but is guaranteed to do a single write.
 129         * This is needed for e.g. httpd logging, when multiple
 130         * children can produce log messages simultaneously. */
 131
 132        strerr_len = strerr ? strlen(strerr) : 0;
 133        msgeol_len = strlen(msg_eol);
 134        /* +3 is for ": " before strerr and for terminating NUL */
 135        msgv = xrealloc(msgv, used + strerr_len + msgeol_len + 3);
 136        if (strerr) {
 137                msgc[used++] = ':';
 138                msgc[used++] = ' ';
 139                strcpy(msgc + used, strerr);
 140                used += strerr_len;
 141        }
 142        strcpy(msgc + used, msg_eol);
 143        used += msgeol_len;
 144
 145        if (logmode & LOGMODE_STDIO) {
 146                iov[0].iov_base = (char*)applet_name;
 147                iov[0].iov_len = strlen(applet_name);
 148                iov[1].iov_base = (char*)": ";
 149                iov[1].iov_len = 2;
 150                /*iov[2].iov_base = msgc;*/
 151                /*iov[2].iov_len = used;*/
 152                fflush_all();
 153                writev(STDERR_FILENO, iov, 3);
 154        }
 155# if ENABLE_FEATURE_SYSLOG
 156        if (logmode & LOGMODE_SYSLOG) {
 157                syslog(syslog_level, "%s", msgc);
 158        }
 159# endif
 160        free(msgc);
 161}
 162#endif
 163
 164
 165void FAST_FUNC bb_error_msg_and_die(const char *s, ...)
 166{
 167        va_list p;
 168
 169        va_start(p, s);
 170        bb_verror_msg(s, p, NULL);
 171        va_end(p);
 172        xfunc_die();
 173}
 174
 175void FAST_FUNC bb_error_msg(const char *s, ...)
 176{
 177        va_list p;
 178
 179        va_start(p, s);
 180        bb_verror_msg(s, p, NULL);
 181        va_end(p);
 182}
 183
 184#if ENABLE_FEATURE_SYSLOG_INFO
 185void FAST_FUNC bb_vinfo_msg(const char *s, va_list p)
 186{
 187        syslog_level = LOG_INFO;
 188        bb_verror_msg(s, p, NULL);
 189        syslog_level = LOG_ERR;
 190}
 191
 192void FAST_FUNC bb_info_msg(const char *s, ...)
 193{
 194        va_list p;
 195
 196        va_start(p, s);
 197        bb_vinfo_msg(s, p);
 198        va_end(p);
 199}
 200
 201void FAST_FUNC bb_simple_info_msg(const char *s)
 202{
 203        bb_info_msg("%s", s);
 204}
 205#endif
 206
 207void FAST_FUNC bb_simple_error_msg(const char *s)
 208{
 209        bb_error_msg("%s", s);
 210}
 211
 212void FAST_FUNC bb_simple_error_msg_and_die(const char *s)
 213{
 214        bb_error_msg_and_die("%s", s);
 215}
 216