diff --git a/include/qb/qbdefs.h b/include/qb/qbdefs.h index 21d3627..25eb1bf 100644 --- a/include/qb/qbdefs.h +++ b/include/qb/qbdefs.h @@ -1,108 +1,112 @@ /* * Copyright (C) 2010 Red Hat, Inc. * * Author: Angus Salkeld * * libqb is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libqb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libqb. If not, see . */ #ifndef QB_DEFS_H_DEFINED #define QB_DEFS_H_DEFINED /* *INDENT-OFF* */ #ifdef __cplusplus extern "C" { #endif /* *INDENT-ON* */ /** * @file qbdefs.h * @author Angus Salkeld * * These are some convience macros and defines. */ /* * simple math macros */ #define QB_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define QB_ABS(i) (((i) < 0) ? -(i) : (i)) #define QB_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define QB_MIN(a, b) (((a) < (b)) ? (a) : (b)) /* * the usual boolean defines */ #define QB_FALSE 0 #define QB_TRUE (!QB_FALSE) /* * bit manipulation */ #define qb_bit_value(bit) (1 << (bit)) #define qb_bit_set(barray, bit) (barray |= qb_bit_value(bit)) #define qb_bit_clear(barray, bit) (barray &= ~(qb_bit_value(bit))) #define qb_bit_is_set(barray, bit) (barray & qb_bit_value(bit)) #define qb_bit_is_clear(barray, bit) (!(barray & qb_bit_value(bit))) /* * handy time based converters. */ #ifndef HZ #define HZ 100 /* 10ms */ #endif #define QB_TIME_MS_IN_SEC 1000ULL #define QB_TIME_US_IN_SEC 1000000ULL #define QB_TIME_NS_IN_SEC 1000000000ULL #define QB_TIME_US_IN_MSEC 1000ULL #define QB_TIME_NS_IN_MSEC 1000000ULL #define QB_TIME_NS_IN_USEC 1000ULL #if defined (__GNUC__) && defined (__STRICT_ANSI__) #undef inline #define inline __inline__ #undef typeof #define typeof __typeof__ #endif /* ANSI */ +#if defined (__GNUC__) && defined (__STRICT_ANSI__) +#define va_copy(_a, _b) *_a = *_b +#endif /* ANSI */ + #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) #define QB_GNUC_DEPRECATED \ __attribute__((__deprecated__)) #else #define QB_GNUC_DEPRECATED #endif /* __GNUC__ */ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define QB_GNUC_DEPRECATED_FOR(f) \ __attribute__((deprecated("Use " #f " instead"))) #else #define QB_GNUC_DEPRECATED_FOR(f) QB_GNUC_DEPRECATED #endif /* __GNUC__ */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) #define QB_GNUC_MAY_ALIAS __attribute__((may_alias)) #else #define QB_GNUC_MAY_ALIAS #endif /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* __cplusplus */ /* *INDENT-ON* */ #endif /* QB_DEFS_H_DEFINED */ diff --git a/lib/log_format.c b/lib/log_format.c index c370880..0cd07c7 100644 --- a/lib/log_format.c +++ b/lib/log_format.c @@ -1,536 +1,536 @@ /* * Copyright (C) 2011 Red Hat, Inc. * * All rights reserved. * * Author: Angus Salkeld * * libqb is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libqb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libqb. If not, see . */ #include "os_base.h" #include #include #include "log_int.h" static qb_log_tags_stringify_fn _user_tags_stringify_fn; /* * syslog prioritynames, facility names to value mapping * Some C libraries build this in to their headers, but it is non-portable * so logsys supplies its own version. */ struct syslog_names { const char *c_name; int32_t c_val; }; static struct syslog_names prioritynames[] = { {"emerg", LOG_EMERG}, {"alert", LOG_ALERT}, {"crit", LOG_CRIT}, {"error", LOG_ERR}, {"warning", LOG_WARNING}, {"notice", LOG_NOTICE}, {"info", LOG_INFO}, {"debug", LOG_DEBUG}, {"trace", LOG_TRACE}, {NULL, -1} }; static const char log_month_name[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; void qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn) { _user_tags_stringify_fn = fn; } static int _strcpy_cutoff(char *dest, const char *src, size_t cutoff, size_t buf_len) { size_t len = strlen(src); if (buf_len <= 1) { if (buf_len == 0) dest[0] = 0; return 0; } if (cutoff == 0) { cutoff = len; } cutoff = QB_MIN(cutoff, buf_len - 1); len = QB_MIN(len, cutoff); memcpy(dest, src, len); memset(dest + len, ' ', cutoff - len); dest[cutoff] = '\0'; return cutoff; } /* * %n FUNCTION NAME * %f FILENAME * %l FILELINE * %p PRIORITY * %t TIMESTAMP * %b BUFFER * %g SUBSYSTEM * * any number between % and character specify field length to pad or chop */ void qb_log_target_format(int32_t target, struct qb_log_callsite *cs, time_t current_time, const char *formatted_message, char *output_buffer) { char char_time[128]; struct tm tm_res; char line_no[30]; unsigned int format_buffer_idx = 0; unsigned int output_buffer_idx = 0; size_t cutoff; uint32_t len; int c; struct qb_log_target *t = qb_log_target_get(target); while ((c = t->format[format_buffer_idx])) { cutoff = 0; if (c != '%') { output_buffer[output_buffer_idx++] = c; format_buffer_idx++; } else { const char *p; format_buffer_idx += 1; if (isdigit(t->format[format_buffer_idx])) { cutoff = atoi(&t->format[format_buffer_idx]); } while (isdigit(t->format[format_buffer_idx])) { format_buffer_idx += 1; } switch (t->format[format_buffer_idx]) { case 'g': if (_user_tags_stringify_fn) { p = _user_tags_stringify_fn(cs->tags); } else { p = ""; } break; case 'n': p = cs->function; break; case 'f': #ifdef BUILDING_IN_PLACE p = cs->filename; #else p = strrchr(cs->filename, '/'); if (p == NULL) { p = cs->filename; } else { p++; /* move past the "/" */ } #endif /* BUILDING_IN_PLACE */ break; case 'l': snprintf(line_no, 30, "%d", cs->lineno); p = line_no; break; case 't': (void)localtime_r(¤t_time, &tm_res); snprintf(char_time, TIME_STRING_SIZE, "%s %02d %02d:%02d:%02d", log_month_name[tm_res.tm_mon], tm_res.tm_mday, tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec); p = char_time; break; case 'b': p = formatted_message; break; case 'p': if (cs->priority > LOG_TRACE) { p = prioritynames[LOG_TRACE].c_name; } else { p = prioritynames[cs->priority].c_name; } break; default: p = ""; break; } len = _strcpy_cutoff(output_buffer + output_buffer_idx, p, cutoff, (QB_LOG_MAX_LEN - output_buffer_idx)); output_buffer_idx += len; format_buffer_idx += 1; } if (output_buffer_idx >= QB_LOG_MAX_LEN - 1) { break; } } if (output_buffer[output_buffer_idx - 1] == '\n') { output_buffer[output_buffer_idx - 1] = '\0'; } else { output_buffer[output_buffer_idx] = '\0'; } } size_t qb_vsprintf_serialize(char *serialize, const char *fmt, va_list ap) { char *format; char *p; uint32_t location = 0; int type_long = 0; int type_longlong = 0; p = stpcpy(serialize, fmt); location = p - serialize + 1; format = (char *)fmt; for (;;) { type_long = 0; type_longlong = 0; p = strchrnul ((const char *)format, '%'); if (*p == '\0') { break; } format = p + 1; reprocess: switch (format[0]) { case '#': /* alternate form conversion, ignore */ case '-': /* left adjust, ignore */ case ' ': /* a space, ignore */ case '+': /* a sign should be used, ignore */ case '\'': /* group in thousands, ignore */ case 'I': /* glibc-ism locale alternative, ignore */ case '.': /* precision, ignore */ case '0': /* field width, ignore */ case '1': /* field width, ignore */ case '2': /* field width, ignore */ case '3': /* field width, ignore */ case '4': /* field width, ignore */ case '5': /* field width, ignore */ case '6': /* field width, ignore */ case '7': /* field width, ignore */ case '8': /* field width, ignore */ case '9': /* field width, ignore */ format++; goto reprocess; case '*': /* variable field width, save */ { int arg_int = va_arg(ap, int); memcpy(&serialize[location], &arg_int, sizeof (int)); location += sizeof(int); format++; goto reprocess; } case 'l': format++; type_long = 1; if (*format == 'l') { type_long = 0; type_longlong = 1; } goto reprocess; case 'd': /* int argument */ case 'i': /* int argument */ case 'o': /* unsigned int argument */ case 'u': case 'x': case 'X': if (type_long) { long int arg_int; arg_int = va_arg(ap, long int); memcpy (&serialize[location], &arg_int, sizeof (long int)); location += sizeof(long int); format++; break; } else if (type_longlong) { long long int arg_int; arg_int = va_arg(ap, long long int); memcpy (&serialize[location], &arg_int, sizeof (long long int)); location += sizeof(long long int); format++; break; } else { int arg_int; arg_int = va_arg(ap, int); memcpy (&serialize[location], &arg_int, sizeof (int)); location += sizeof(int); format++; break; } case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': { double arg_double; arg_double = va_arg(ap, double); memcpy (&serialize[location], &arg_double, sizeof (double)); location += sizeof(double); format++; break; } case 'c': { int arg_int; unsigned char arg_char; arg_int = va_arg(ap, unsigned int); arg_char = (unsigned char)arg_int; memcpy (&serialize[location], &arg_char, sizeof (unsigned char)); location += sizeof(unsigned char); break; } case 's': { char *arg_string; arg_string = va_arg(ap, char *); p = stpcpy(&serialize[location], arg_string); location += p - &serialize[location] + 1; break; } case 'p': { void *arg_pointer; arg_pointer = va_arg(ap, void *); memcpy (&serialize[location], &arg_pointer, sizeof (void *)); location += sizeof (arg_pointer); break; } case '%': serialize[location++] = '%'; break; } } return (location); } #define MINI_FORMAT_STR_LEN 20 size_t qb_vsnprintf_deserialize(char *string, size_t str_len, const char *buf) { char *p; char *format; char fmt[MINI_FORMAT_STR_LEN]; int fmt_pos; uint32_t location = 0; uint32_t data_pos = strlen(buf) + 1; int type_long = 0; int type_longlong = 0; int len; format = (char *)buf; for (;;) { type_long = 0; type_longlong = 0; p = strchrnul((const char *)format, '%'); if (*p == '\0') { p = stpcpy(&string[location], format); location += p - &string[location] + 1; break; } - // copy from current to the next % + /* copy from current to the next % */ len = p - format; strncpy(&string[location], format, len); location += len; format = p; - // start building up the format for snprintf + /* start building up the format for snprintf */ fmt_pos = 0; fmt[fmt_pos++] = *format; format++; reprocess: switch (format[0]) { case '#': /* alternate form conversion, ignore */ case '-': /* left adjust, ignore */ case ' ': /* a space, ignore */ case '+': /* a sign should be used, ignore */ case '\'': /* group in thousands, ignore */ case 'I': /* glibc-ism locale alternative, ignore */ case '.': /* precision, ignore */ case '0': /* field width, ignore */ case '1': /* field width, ignore */ case '2': /* field width, ignore */ case '3': /* field width, ignore */ case '4': /* field width, ignore */ case '5': /* field width, ignore */ case '6': /* field width, ignore */ case '7': /* field width, ignore */ case '8': /* field width, ignore */ case '9': /* field width, ignore */ fmt[fmt_pos++] = *format; format++; goto reprocess; case '*': { int *arg_int = (int *)&buf[data_pos]; data_pos += sizeof(int); fmt_pos += snprintf(&fmt[fmt_pos], MINI_FORMAT_STR_LEN - fmt_pos, "%d", *arg_int); format++; goto reprocess; } case 'l': fmt[fmt_pos++] = *format; format++; type_long = 1; if (*format == 'l') { type_long = 0; type_longlong = 1; } goto reprocess; case 'd': /* int argument */ case 'i': /* int argument */ case 'o': /* unsigned int argument */ case 'u': case 'x': case 'X': if (type_long) { long int *arg_int; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; arg_int = (long int *)&buf[data_pos]; location += snprintf(&string[location], str_len - location, fmt, *arg_int); data_pos += sizeof(long int); format++; break; } else if (type_longlong) { long long int *arg_int; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; arg_int = (long long int *)&buf[data_pos]; location += snprintf(&string[location], str_len - location, fmt, *arg_int); data_pos += sizeof(long long int); format++; break; } else { int *arg_int; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; arg_int = (int *)&buf[data_pos]; location += snprintf(&string[location], str_len - location, fmt, *arg_int); data_pos += sizeof(int); format++; break; } case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': { double *arg_double; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; arg_double = (double *)&buf[data_pos]; location += snprintf(&string[location], str_len - location, fmt, *arg_double); data_pos += sizeof(double); format++; break; } case 'c': { unsigned char *arg_char; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; arg_char = (unsigned char*)&buf[data_pos]; location += snprintf(&string[location], str_len - location, fmt, *arg_char); data_pos += sizeof(unsigned char); format++; break; } case 's': { fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; len = snprintf(&string[location], str_len - location, fmt, &buf[data_pos]); location += len; data_pos += len + 1; format++; break; } case 'p': { fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; location = snprintf(&string[location], str_len - location, fmt, &buf[data_pos]); data_pos += sizeof(void*); format++; break; } case '%': string[location++] = '%'; format++; break; } } return location; }