diff --git a/lib/log_format.c b/lib/log_format.c
index 6c29f0a..82fa1eb 100644
--- a/lib/log_format.c
+++ b/lib/log_format.c
@@ -1,852 +1,853 @@
 /*
  * Copyright (C) 2011 Red Hat, Inc.
  *
  * All rights reserved.
  *
  * Author: Angus Salkeld <asalkeld@redhat.com>
  *
  * 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 <http://www.gnu.org/licenses/>.
  */
 #include "os_base.h"
 #include <ctype.h>
 
 #include <qb/qbdefs.h>
 #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}
 };
 
 struct syslog_names facilitynames[] = {
 	{"auth", LOG_AUTH},
 #if defined(LOG_AUTHPRIV)
 	{"authpriv", LOG_AUTHPRIV},
 #endif
 	{"cron", LOG_CRON},
 	{"daemon", LOG_DAEMON},
 #if defined(LOG_FTP)
 	{"ftp", LOG_FTP},
 #endif
 	{"kern", LOG_KERN},
 	{"lpr", LOG_LPR},
 	{"mail", LOG_MAIL},
 	{"news", LOG_NEWS},
 	{"syslog", LOG_SYSLOG},
 	{"user", LOG_USER},
 	{"uucp", LOG_UUCP},
 	{"local0", LOG_LOCAL0},
 	{"local1", LOG_LOCAL1},
 	{"local2", LOG_LOCAL2},
 	{"local3", LOG_LOCAL3},
 	{"local4", LOG_LOCAL4},
 	{"local5", LOG_LOCAL5},
 	{"local6", LOG_LOCAL6},
 	{"local7", LOG_LOCAL7},
 	{NULL, -1}
 };
 
 static const char log_month_name[][4] = {
 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 };
 
 static pthread_rwlock_t _formatlock;
 
 void
 qb_log_format_init(void)
 {
 	int32_t i;
 	struct qb_log_target *t;
 
 	i = pthread_rwlock_init(&_formatlock, NULL);
 	assert(i == 0);
 
 	for (i = 0; i < QB_LOG_TARGET_MAX; i++) {
 		t = qb_log_target_get(i);
 		t->format = strdup("[%p] %b");
 	}
 }
 
 void
 qb_log_format_fini(void)
 {
 	struct qb_log_target *t;
 	int32_t i;
 
 	pthread_rwlock_destroy(&_formatlock);
 
 	for (i = 0; i < QB_LOG_TARGET_MAX; i++) {
 		t = qb_log_target_get(i);
 		free(t->format);
 	}
 }
 
 void
 qb_log_format_set(int32_t target, const char *format)
 {
 	char modified_format[256];
 	struct qb_log_target *t = qb_log_target_get(target);
 
 	pthread_rwlock_wrlock(&_formatlock);
 
 	free(t->format);
 
 	if (format) {
 		qb_log_target_format_static(target, format, modified_format);
 		t->format = strdup(modified_format);
 	} else {
 		t->format = strdup("[%p] %b");
 	}
 	assert(t->format != NULL);
 
 	pthread_rwlock_unlock(&_formatlock);
 }
 
 /* Convert string "auth" to equivalent number "LOG_AUTH" etc. */
 int32_t
 qb_log_facility2int(const char *fname)
 {
 	int32_t i;
 
 	if (fname == NULL) {
 		return -EINVAL;
 	}
 
 	for (i = 0; facilitynames[i].c_name != NULL; i++) {
 		if (strcmp(fname, facilitynames[i].c_name) == 0) {
 			return facilitynames[i].c_val;
 		}
 	}
 	return -EINVAL;
 }
 
 /* Convert number "LOG_AUTH" to equivalent string "auth" etc. */
 const char *
 qb_log_facility2str(int32_t fnum)
 {
 	int32_t i;
 
 	for (i = 0; facilitynames[i].c_name != NULL; i++) {
 		if (facilitynames[i].c_val == fnum) {
 			return facilitynames[i].c_name;
 		}
 	}
 	return NULL;
 }
 
 const char *
 qb_log_priority2str(uint8_t priority)
 {
 	if (priority > LOG_TRACE) {
 		return prioritynames[LOG_TRACE].c_name;
 	}
 	return prioritynames[priority].c_name;
 }
 
 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, int ralign,
 	       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);
 	if (ralign) {
 		memset(dest, ' ', cutoff - len);
 		memcpy(dest + cutoff - len, src, len);
 	} else {
 		memcpy(dest, src, len);
 		memset(dest + len, ' ', cutoff - len);
 	}
 
 	dest[cutoff] = '\0';
 
 	return cutoff;
 }
 
 /*
  * This function will do static formatting (for things that don't
  * change on each log message).
  *
  * %P PID
  * %N name passed into qb_log_init
  * %H hostname
  *
  * any number between % and character specify field length to pad or chop
  */
 void
 qb_log_target_format_static(int32_t target, const char * format,
 			    char *output_buffer)
 {
 	char tmp_buf[255];
 	unsigned int format_buffer_idx = 0;
 	unsigned int output_buffer_idx = 0;
 	size_t cutoff;
 	uint32_t len;
 	int ralign;
 	int c;
 	struct qb_log_target *t = qb_log_target_get(target);
 
 	if (format == NULL) {
 		return;
 	}
 
 	while ((c = format[format_buffer_idx])) {
 		cutoff = 0;
 		ralign = QB_FALSE;
 		if (c != '%') {
 			output_buffer[output_buffer_idx++] = c;
 			format_buffer_idx++;
 		} else {
 			const char *p;
 			unsigned int percent_buffer_idx = format_buffer_idx;
 
 			format_buffer_idx += 1;
 			if (format[format_buffer_idx] == '-') {
 				ralign = QB_TRUE;
 				format_buffer_idx += 1;
 			}
 
 			if (isdigit(format[format_buffer_idx])) {
 				cutoff = atoi(&format[format_buffer_idx]);
 			}
 			while (isdigit(format[format_buffer_idx])) {
 				format_buffer_idx += 1;
 			}
 
 			switch (format[format_buffer_idx]) {
 			case 'P':
 				snprintf(tmp_buf, 30, "%d", getpid());
 				p = tmp_buf;
 				break;
 
 			case 'N':
 				p = t->name;
 				break;
 
 			case 'H':
-				if (gethostname(tmp_buf, 255) == 0) {
-					tmp_buf[254] = '\0';
+				if (gethostname(tmp_buf, sizeof(tmp_buf)) == 0) {
+					tmp_buf[sizeof(tmp_buf) - 1] = '\0';
 				} else {
-					(void)strlcpy(tmp_buf, "localhost", 255);
+					(void)strlcpy(tmp_buf, "localhost",
+						      sizeof(tmp_buf));
 				}
 				p = tmp_buf;
 				break;
 
 			default:
 				p = &format[percent_buffer_idx];
 				cutoff = (format_buffer_idx - percent_buffer_idx + 1);
 				ralign = QB_FALSE;
 				break;
 			}
 			len = _strcpy_cutoff(output_buffer + output_buffer_idx,
 					     p, cutoff, ralign,
 					     (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;
 		}
 	}
 
 	output_buffer[output_buffer_idx] = '\0';
 }
 
 /*
  * %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 tmp_buf[128];
 	struct tm tm_res;
 	unsigned int format_buffer_idx = 0;
 	unsigned int output_buffer_idx = 0;
 	size_t cutoff;
 	uint32_t len;
 	int ralign;
 	int c;
 	struct qb_log_target *t = qb_log_target_get(target);
 
 	pthread_rwlock_rdlock(&_formatlock);
 	if (t->format == NULL) {
 		pthread_rwlock_unlock(&_formatlock);
 		return;
 	}
 
 	while ((c = t->format[format_buffer_idx])) {
 		cutoff = 0;
 		ralign = QB_FALSE;
 		if (c != '%') {
 			output_buffer[output_buffer_idx++] = c;
 			format_buffer_idx++;
 		} else {
 			const char *p;
 
 			format_buffer_idx += 1;
 			if (t->format[format_buffer_idx] == '-') {
 				ralign = QB_TRUE;
 				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(tmp_buf, 30, "%d", cs->lineno);
 				p = tmp_buf;
 				break;
 
 			case 't':
 				(void)localtime_r(&current_time, &tm_res);
 				snprintf(tmp_buf, 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 = tmp_buf;
 				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, ralign,
 					     (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;
 		}
 	}
 	pthread_rwlock_unlock(&_formatlock);
 
 	if (output_buffer[output_buffer_idx - 1] == '\n') {
 		output_buffer[output_buffer_idx - 1] = '\0';
 	} else {
 		output_buffer[output_buffer_idx] = '\0';
 	}
 }
 
 
 /*
  * These wrappers around strl* functions just return the
  * number of characters written, not the number of characters
  * requested to be written.
  */
 static size_t
 my_strlcpy(char *dest, const char * src, size_t maxlen)
 {
 	size_t rc = strlcpy(dest, src, maxlen);
 	/* maxlen includes NUL, so -1 */
 	return QB_MIN(rc, maxlen-1);
 }
 
 static size_t
 my_strlcat(char *dest, const char * src, size_t maxlen)
 {
 	size_t rc = strlcat(dest, src, maxlen);
 	return QB_MIN(rc, maxlen-1);
 }
 
 size_t
 qb_vsnprintf_serialize(char *serialize, size_t max_len,
 		       const char *fmt, va_list ap)
 {
 	char *format;
 	char *p;
 	char *qb_xc;
 	int type_long = QB_FALSE;
 	int type_longlong = QB_FALSE;
         int sformat_length = 0;
         int sformat_precision = QB_FALSE;
 	uint32_t location = my_strlcpy(serialize, fmt, max_len) + 1;
 
 	/* Assume serialized output always wants extended information
 	 * (@todo: add variant of this function that takes argument for whether
 	 * to print extended information, and make this a macro with that
 	 * argument set to QB_TRUE, so callers can honor extended setting)
 	 */
 	if ((qb_xc = strchr(serialize, QB_XC)) != NULL) {
 		*qb_xc = *(qb_xc + 1)? '|' : '\0';
 	}
 
 	format = (char *)fmt;
 	for (;;) {
 		type_long = QB_FALSE;
 		type_longlong = QB_FALSE;
 		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 */
                     format++;
                     goto reprocess;
 		case '.': /* precision, ignore */
                     format++;
                     sformat_precision = QB_TRUE;
                     goto reprocess;
 		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 */
                         if (sformat_precision) {
                             sformat_length *= 10;
                             sformat_length += (format[0] - '0');
                         }
 			format++;
 			goto reprocess;
 		case '*': /* variable field width, save */ {
 			int arg_int = va_arg(ap, int);
 			if (location + sizeof (int) > max_len) {
 				return max_len;
 			}
 			memcpy(&serialize[location], &arg_int, sizeof (int));
 			location += sizeof(int);
 			format++;
 			goto reprocess;
 		}
 		case 'l':
 			format++;
 			type_long = QB_TRUE;
 			if (*format == 'l') {
 				type_long = QB_FALSE;
 				type_longlong = QB_TRUE;
 				format++;
 			}
 			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;
 
 				if (location + sizeof (long int) > max_len) {
 					return max_len;
 				}
 				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;
 
 				if (location + sizeof (long long int) > max_len) {
 					return max_len;
 				}
 				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;
 
 				if (location + sizeof (int) > max_len) {
 					return max_len;
 				}
 				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;
 
 			if (location + sizeof (double) > max_len) {
 				return max_len;
 			}
 			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;
 
 			if (location + sizeof (unsigned int) > max_len) {
 				return max_len;
 			}
 			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 *);
 			if (arg_string == NULL) {
 				location += my_strlcpy(&serialize[location],
 						   "(null)",
 						   QB_MIN(strlen("(null)") + 1,
 							  max_len - location));
 			} else if (sformat_length) {
 				location += my_strlcpy(&serialize[location],
 						   arg_string,
 						   QB_MIN(sformat_length + 1,
 						   (max_len - location)));
 			} else {
 				location += my_strlcpy(&serialize[location],
 						   arg_string,
 						   QB_MIN(strlen(arg_string) + 1,
 							  max_len - location));
 			}
 			location++;
 			break;
 			}
 		case 'p':
 			{
 			ptrdiff_t arg_pointer = va_arg(ap, ptrdiff_t);
 			if (location + sizeof (ptrdiff_t) > max_len) {
 				return max_len;
 			}
 			memcpy(&serialize[location], &arg_pointer, sizeof(ptrdiff_t));
 			location += sizeof(ptrdiff_t);
 			break;
 			}
 		case '%':
 			if (location + 1 > max_len) {
 				return max_len;
 			}
 			serialize[location++] = '%';
                         sformat_length = 0;
                         sformat_precision = QB_FALSE;
 			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 = QB_FALSE;
 	int type_longlong = QB_FALSE;
 	int len;
 
 	string[0] = '\0';
 	format = (char *)buf;
 	for (;;) {
 		type_long = QB_FALSE;
 		type_longlong = QB_FALSE;
 		p = strchrnul((const char *)format, '%');
 		if (*p == '\0') {
 			return my_strlcat(string, format, str_len) + 1;
 		}
 		/* copy from current to the next % */
 		len = p - format;
 		memcpy(&string[location], format, len);
 		location += len;
 		format = p;
 
 		/* 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;
 			memcpy(&arg_int, &buf[data_pos], sizeof(int));
 			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 = QB_TRUE;
 			if (*format == 'l') {
 				type_long = QB_FALSE;
 				type_longlong = QB_TRUE;
 			}
 			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';
 				memcpy(&arg_int, &buf[data_pos], sizeof(long int));
 				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';
 				memcpy(&arg_int, &buf[data_pos], sizeof(long long int));
 				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';
 				memcpy(&arg_int, &buf[data_pos], sizeof(int));
 				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';
 			memcpy(&arg_double, &buf[data_pos], sizeof(double));
 			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;
 			/* don't use len as there might be a len modifier */
 			data_pos += strlen(&buf[data_pos]) + 1;
 			format++;
 			break;
 			}
 		case 'p':
 			{
 			ptrdiff_t pt;
 			memcpy(&pt, &buf[data_pos],
 			       sizeof(ptrdiff_t));
 			fmt[fmt_pos++] = *format;
 			fmt[fmt_pos++] = '\0';
 			location += snprintf(&string[location],
 					     str_len - location,
 					     fmt, pt);
 			data_pos += sizeof(void*);
 			format++;
 			break;
 			}
 		case '%':
 			string[location++] = '%';
 			format++;
 			break;
 
 		}
 	}
 	return location;
 }
 
diff --git a/tests/check_log.c b/tests/check_log.c
index d7ac70b..8538620 100644
--- a/tests/check_log.c
+++ b/tests/check_log.c
@@ -1,859 +1,864 @@
 /*
  * Copyright (c) 2011-2015 Red Hat, Inc.
  *
  * All rights reserved.
  *
  * Author: Angus Salkeld <asalkeld@redhat.com>
  *
  * This file is part of libqb.
  *
  * 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 <http://www.gnu.org/licenses/>.
  */
 
 #include "os_base.h"
 #include <pthread.h>
 #include <check.h>
 
 #include <qb/qbdefs.h>
 #include <qb/qbutil.h>
 #include <qb/qblog.h>
 
 #ifdef HAVE_SYSLOG_TESTS
 #include "_syslog_override.h"
 #endif
 
 extern size_t qb_vsnprintf_serialize(char *serialize, size_t max_len, const char *fmt, va_list ap);
 extern size_t qb_vsnprintf_deserialize(char *string, size_t strlen, const char *buf);
 
 
 static void
 format_this(char *out, const char *fmt, ...)
 {
 	char buf[QB_LOG_MAX_LEN];
 	va_list ap;
 
 	va_start(ap, fmt);
 	qb_vsnprintf_serialize(buf, QB_LOG_MAX_LEN, fmt, ap);
 	qb_vsnprintf_deserialize(out, QB_LOG_MAX_LEN, buf);
 	va_end(ap);
 }
 
 static void
 format_this_up_to(char *out, size_t max_len, const char *fmt, ...)
 {
 	char buf[QB_LOG_MAX_LEN];
 	va_list ap;
 
 	va_start(ap, fmt);
 	qb_vsnprintf_serialize(buf, max_len, fmt, ap);
 	qb_vsnprintf_deserialize(out, QB_LOG_MAX_LEN, buf);
 	va_end(ap);
 }
 
 START_TEST(test_va_serialize)
 {
 	char buf[QB_LOG_MAX_LEN];
 	char cmp_buf[QB_LOG_MAX_LEN];
 
 	format_this(buf, "one line");
 	ck_assert_str_eq(buf, "one line");
 
 	format_this(buf, "p1:%p, p2:%p", format_this, buf);
 	snprintf(cmp_buf, QB_LOG_MAX_LEN, "p1:%p, p2:%p", format_this, buf);
 	ck_assert_str_eq(buf, cmp_buf);
 
 	format_this(buf, "s1:%s, s2:%s", "Yes", "Never");
 	ck_assert_str_eq(buf, "s1:Yes, s2:Never");
 
 	format_this(buf, "s1:%s, s2:%s", "Yes", "Never");
 	ck_assert_str_eq(buf, "s1:Yes, s2:Never");
 
 	format_this(buf, "d1:%d, d2:%5i, d3:%04i", 23, 37, 84);
 	ck_assert_str_eq(buf, "d1:23, d2:   37, d3:0084");
 
 	format_this(buf, "f1:%.5f, f2:%.2f", 23.34109, 23.34109);
 	ck_assert_str_eq(buf, "f1:23.34109, f2:23.34");
 
 	format_this(buf, ":%s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":Hello, world!:");
 	format_this(buf, ":%15s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":  Hello, world!:");
 	format_this(buf, ":%.10s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":Hello, wor:");
 	format_this(buf, ":%-10s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":Hello, world!:");
 	format_this(buf, ":%-15s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":Hello, world!  :");
 	format_this(buf, ":%.15s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":Hello, world!:");
 	format_this(buf, ":%15.10s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":     Hello, wor:");
 	format_this(buf, ":%-15.10s:", "Hello, world!");
 	ck_assert_str_eq(buf, ":Hello, wor     :");
 
 	format_this(buf, ":%*d:", 8, 96);
 	ck_assert_str_eq(buf, ":      96:");
 
 	format_this_up_to(buf, 11, "123456789____");
 	ck_assert_str_eq(buf, "123456789_");
 
 	format_this(buf, "Client %s.%.9s wants to fence (%s) '%s' with device '%s'",
 		    "bla", "foooooooooooooooooo",
 		    "action", "target", "hoop");
 
 	ck_assert_str_eq(buf,
 			 "Client bla.foooooooo wants to fence (action) 'target' with device 'hoop'");
 
 	format_this(buf, "Node %s now has process list: %.32x (was %.32x)",
 		    "18builder", 2, 0);
 	ck_assert_str_eq(buf, "Node 18builder now has process list: 00000000000000000000000000000002 (was 00000000000000000000000000000000)");
 
 
 }
 END_TEST
 
 START_TEST(test_log_stupid_inputs)
 {
 	int32_t rc;
 
 	/* shouldn't crash with out an init() */
 	qb_log_fini();
 
 	/* not init'ed */
 	rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
 			       QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
 	ck_assert_int_eq(rc, -EINVAL);
 
 	rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 2000);
 	ck_assert_int_eq(rc, -EINVAL);
 
 	qb_log(LOG_INFO, "not init'd");
 
 	qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 				    __LINE__, 0, "also not init'd");
 
 	qb_log_init("test", LOG_USER, LOG_DEBUG);
 
 	/* non-opened log file */
 	rc = qb_log_filter_ctl(21, QB_LOG_FILTER_ADD,
 			       QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
 	ck_assert_int_eq(rc, -EBADF);
 
 	rc = qb_log_ctl(21, QB_LOG_CONF_PRIORITY_BUMP, -1);
 	ck_assert_int_eq(rc, -EBADF);
 
 	/* target < 0 or >= 32 */
 	rc = qb_log_filter_ctl(41, QB_LOG_FILTER_ADD,
 			       QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
 	ck_assert_int_eq(rc, -EBADF);
 
 	rc = qb_log_ctl(-1, QB_LOG_CONF_PRIORITY_BUMP, -1);
 	ck_assert_int_eq(rc, -EBADF);
 
 	/* crap values to filter_ctl() */
 	rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
 			       QB_LOG_FILTER_FILE, NULL, LOG_INFO);
 	ck_assert_int_eq(rc, -EINVAL);
 	rc = qb_log_filter_ctl(QB_LOG_SYSLOG, 56,
 			       QB_LOG_FILTER_FILE, "boja", LOG_INFO);
 	ck_assert_int_eq(rc, -EINVAL);
 
 	/* crap values to ctl() */
 	rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, -2000);
 	ck_assert_int_eq(rc, -EINVAL);
 	rc = qb_log_ctl(QB_LOG_BLACKBOX, 67, 2000);
 	ck_assert_int_eq(rc, -EINVAL);
 	rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_SIZE, 2000);
 	ck_assert_int_eq(rc, -ENOSYS);
 
 }
 END_TEST
 
 static char test_buf[QB_LOG_MAX_LEN];
 static uint8_t test_priority;
 static int32_t num_msgs;
 
 /*
  * to test that we get what we expect.
  */
 static void
 _test_logger(int32_t t,
 	     struct qb_log_callsite *cs,
 	     time_t timestamp, const char *msg)
 {
 	test_buf[0] = '\0';
 	qb_log_target_format(t, cs, timestamp, msg, test_buf);
 	test_priority = cs->priority;
 
 	num_msgs++;
 }
 
 static void log_also(void)
 {
 	qb_log(LOG_INFO, "yes please");
 }
 
 static void log_and_this_too(void)
 {
 	qb_log(LOG_INFO, "this too please");
 }
 
 static void log_it_please(void)
 {
 	qb_enter();
 	qb_log(LOG_TRACE, "A:%d B:%d C:%d", 1, 2, 3);
 	qb_log(LOG_DEBUG, "A:%d B:%d C:%d", 1, 2, 3);
 	errno = EEXIST;
 	qb_perror(LOG_WARNING, "bogus error");
 	errno = 0;
 	qb_log(LOG_INFO, "A:%d B:%d C:%d", 1, 2, 3);
 	qb_log(LOG_NOTICE, "A:%d B:%d C:%d", 1, 2, 3);
 	qb_log(LOG_WARNING, "A:%d B:%d C:%d", 1, 2, 3);
 	qb_log(LOG_ERR, "A:%d B:%d C:%d", 1, 2, 3);
 	qb_leave();
 }
 
 
 static int32_t _cust_t = -1;
 static void
 m_filter(struct qb_log_callsite *cs)
 {
 	if ((cs->priority >= LOG_ALERT &&
 	     cs->priority <= LOG_INFO) ||
 	    cs->tags > 0) {
 		qb_bit_set(cs->targets, _cust_t);
 	} else {
 		qb_bit_clear(cs->targets, _cust_t);
 	}
 }
 
 
 START_TEST(test_log_filter_fn)
 {
 	int32_t rc;
 
 	qb_log_init("test", LOG_USER, LOG_EMERG);
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 
 	_cust_t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
 	_ck_assert_int(_cust_t, >, QB_LOG_BLACKBOX);
 	rc = qb_log_ctl(_cust_t, QB_LOG_CONF_ENABLED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 
 	/*
 	 * test the custom filter function.
 	 * make sure qb_log, and qb_log_from_external_source are filtered.
 	 */
 	qb_log_filter_fn_set(m_filter);
 	num_msgs = 0;
 
 	qb_log(LOG_NOTICE, "qb_log_filter_fn_set good");
 	qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 				    __LINE__, 0, "qb_log_filter_fn_set good");
 	qb_log(LOG_TRACE, "qb_log_filter_fn_set bad");
 	qb_log_from_external_source(__func__, __FILE__, "%s", LOG_DEBUG,
 				    __LINE__, 44, "qb_log_filter_fn_set woot");
 	qb_log_from_external_source(__func__, __FILE__, "%s", LOG_DEBUG,
 				    __LINE__, 0, "qb_log_filter_fn_set bad");
 
 	ck_assert_int_eq(num_msgs, 3);
 }
 END_TEST
 
 START_TEST(test_log_basic)
 {
 	int32_t t;
 	int32_t rc;
 
 	qb_log_init("test", LOG_USER, LOG_EMERG);
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 
 	t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
 	rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FORMAT, "Angus", LOG_WARNING);
 	ck_assert_int_eq(rc, 0);
 	qb_log_format_set(t, "%b");
 	rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 
 	/* captures last log */
 	memset(test_buf, 0, sizeof(test_buf));
 	test_priority = 0;
 	num_msgs = 0;
 
 	/*
 	 * test filtering by format
 	 */
 	qb_log(LOG_INFO, "Hello Angus, how are you?");
 	qb_log(LOG_WARNING, "Hello Steven, how are you?");
 	qb_log(LOG_ERR, "Hello Andrew, how are you?");
 	qb_log(LOG_ERR, "Hello Angus, how are you?");
 	qb_log(LOG_EMERG, "Hello Anna, how are you?");
 	ck_assert_int_eq(test_priority, LOG_ERR);
 	ck_assert_int_eq(num_msgs, 1);
 	ck_assert_str_eq(test_buf, "Hello Angus, how are you?");
 
 
 	/* 
 	 * test filtering by file regex
  	 */
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FORMAT, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FILE_REGEX, "^fakefile*", LOG_DEBUG);
 
 	num_msgs = 0;
 	qb_log_from_external_source(__func__, "fakefile_logging", "%s bla", LOG_INFO,
 				    56, 0, "filename/lineno");
 	qb_log_from_external_source(__func__, "do_not_log_fakefile_logging", "%s bla", LOG_INFO,
 				    56, 0, "filename/lineno");
 	ck_assert_int_eq(num_msgs, 1);
 
 	/* 
 	 * test filtering by format regex
  	 */
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FORMAT, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FORMAT_REGEX, "^one", LOG_WARNING);
 
 	num_msgs = 0;
 	qb_log(LOG_INFO, "one two three");
 	qb_log(LOG_ERR, "testing one two three");
 	qb_log(LOG_WARNING, "one two three");
 	qb_log(LOG_ERR, "one two three");
 	qb_log(LOG_EMERG, "one two three");
 	ck_assert_int_eq(num_msgs, 3);
 
 	/*
 	 * test filtering by function and regex
 	 */
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FUNCTION_REGEX, "^log_.*please", LOG_WARNING);
 
 	num_msgs = 0;
 	qb_log(LOG_ERR, "try if you: log_it_please()");
 	log_it_please();
 	ck_assert_int_eq(num_msgs, 3);
 
 	qb_log_filter_ctl(t, QB_LOG_FILTER_REMOVE,
 			  QB_LOG_FILTER_FUNCTION_REGEX, "log_it_please", LOG_WARNING);
 
 	/*
 	 * test filtering by function
 	 */
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
 
 	num_msgs = 0;
 	qb_log(LOG_ERR, "try if you: log_it_please()");
 	log_it_please();
 	ck_assert_int_eq(num_msgs, 3);
 
 	qb_log_filter_ctl(t, QB_LOG_FILTER_REMOVE,
 			  QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FUNCTION, __func__, LOG_DEBUG);
 
 	num_msgs = 0;
 	log_it_please();
 	ck_assert_int_eq(num_msgs, 0);
 	qb_log(LOG_DEBUG, "try if you: log_it_please()");
 	ck_assert_int_eq(num_msgs, 1);
 
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FUNCTION,
 			  "log_also,log_and_this_too",
 			  LOG_DEBUG);
 	num_msgs = 0;
 	log_also();
 	log_and_this_too();
 	ck_assert_int_eq(num_msgs, 2);
 
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FILE, "fakefile.c,"__FILE__",otherfakefile", LOG_DEBUG);
 	/*
 	 * make sure we can pass in a null filename or function name.
 	 */
 	qb_log_from_external_source(__func__, NULL, "%s", LOG_INFO,
 				    __LINE__, 0, "null filename");
 	qb_log_from_external_source(NULL, __FILE__, "%s", LOG_INFO,
 				    __LINE__, 0, "null function");
 
 	/* check same file/lineno logs with different formats work
 	 */
 	num_msgs = 0;
 	qb_log_from_external_source(__func__, __FILE__, "%s bla", LOG_INFO,
 				    56, 0, "filename/lineno");
 	ck_assert_int_eq(num_msgs, 1);
 	ck_assert_str_eq(test_buf, "filename/lineno bla");
 
 	num_msgs = 0;
 	qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 				    56, 0, "same filename/lineno");
 	ck_assert_int_eq(num_msgs, 1);
 	ck_assert_str_eq(test_buf, "same filename/lineno");
 
 	/* check filtering works on same file/lineno but different
 	 * log level.
 	 */
 	qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
 			  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FILE, __FILE__, LOG_INFO);
 
 	num_msgs = 0;
 	qb_log_from_external_source(__func__, __FILE__,
 				    "same filename/lineno, this level %d",
 				    LOG_INFO, 56, 0, LOG_INFO);
 	ck_assert_int_eq(num_msgs, 1);
 	ck_assert_str_eq(test_buf, "same filename/lineno, this level 6");
 
 	num_msgs = 0;
 	qb_log_from_external_source(__func__, __FILE__,
 				    "same filename/lineno, this level %d",
 				    LOG_DEBUG, 56, 0, LOG_DEBUG);
 	ck_assert_int_eq(num_msgs, 0);
 }
 END_TEST
 
 static const char *_test_tags_stringify(uint32_t tags)
 {
 	if (tags == 1) {
 		return "ONE";
 	} else if (tags == 8) {
 		return "ATE";
 	} else {
 		return "ANY";
 	}
 }
 
 START_TEST(test_log_format)
 {
 	int32_t t;
-	char cmp_str[256];
+	/* following size/length related equation holds in the context of use:
+	   strlen(cmp_str) = strlen(host_str) + X; X ~ 20 < sizeof(host_str) */
 	char host_str[256];
+	char cmp_str[2 * sizeof(host_str)];
 
 	qb_log_init("test", LOG_USER, LOG_DEBUG);
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 
 	t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
 	qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
 
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
 	qb_log_format_set(t, "%p %f %b");
 
 	qb_log(LOG_DEBUG, "Angus");
 	ck_assert_str_eq(test_buf, "debug check_log.c Angus");
 	qb_log(LOG_INFO, "Angus");
 	ck_assert_str_eq(test_buf, "info check_log.c Angus");
 	qb_log(LOG_NOTICE, "Angus");
 	ck_assert_str_eq(test_buf, "notice check_log.c Angus");
 	qb_log(LOG_WARNING, "Angus");
 	ck_assert_str_eq(test_buf, "warning check_log.c Angus");
 	qb_log(LOG_ERR, "Angus");
 	ck_assert_str_eq(test_buf, "error check_log.c Angus");
 	qb_log(LOG_CRIT, "Angus");
 	ck_assert_str_eq(test_buf, "crit check_log.c Angus");
 	qb_log(LOG_ALERT, "Angus");
 	ck_assert_str_eq(test_buf, "alert check_log.c Angus");
 	qb_log(LOG_EMERG, "Angus");
 	ck_assert_str_eq(test_buf, "emerg check_log.c Angus");
 
 	qb_log_tags_stringify_fn_set(_test_tags_stringify);
 	qb_log_format_set(t, "%g %b");
 
 	qb_logt(LOG_INFO, 0, "Angus");
 	ck_assert_str_eq(test_buf, "ANY Angus");
 	qb_logt(LOG_INFO, 1, "Angus");
 	ck_assert_str_eq(test_buf, "ONE Angus");
 	qb_logt(LOG_INFO, 5, "Angus");
 	ck_assert_str_eq(test_buf, "ANY Angus");
 	qb_logt(LOG_INFO, 8, "Angus");
 	ck_assert_str_eq(test_buf, "ATE Angus");
 
 	qb_log_format_set(t, "%-15f %b");
 	qb_log(LOG_WARNING, "Andrew");
 	ck_assert_str_eq(test_buf, "    check_log.c Andrew");
 
 	qb_log_tags_stringify_fn_set(NULL);
 
-	gethostname(host_str, 256);
+	gethostname(host_str, sizeof(host_str));
+	host_str[sizeof(host_str) - 1] = '\0';
 
 	qb_log_format_set(t, "%P %H %N %b");
 	qb_log(LOG_INFO, "Angus");
-	snprintf(cmp_str, 256, "%d %s test Angus", getpid(), host_str);
+	snprintf(cmp_str, sizeof(cmp_str), "%d %s test Angus", getpid(),
+		 host_str);
 	ck_assert_str_eq(test_buf, cmp_str);
 
 	qb_log_format_set(t, "%3N %H %P %b");
 	qb_log(LOG_INFO, "Angus");
-	snprintf(cmp_str, 256, "tes %s %d Angus", host_str, getpid());
+	snprintf(cmp_str, sizeof(cmp_str), "tes %s %d Angus", host_str,
+		 getpid());
 	ck_assert_str_eq(test_buf, cmp_str);
 }
 END_TEST
 
 START_TEST(test_log_enable)
 {
 	int32_t t;
 	int32_t state;
 
 	qb_log_init("test", LOG_USER, LOG_DEBUG);
 	state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
 	ck_assert_int_eq(state, QB_LOG_STATE_ENABLED);
 	state = qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0);
 	ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
 	state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
 	ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
 
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 	state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
 	ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
 
 	t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
 	qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
 
 	qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
 	qb_log_format_set(t, "%b");
 
 	qb_log(LOG_DEBUG, "Hello");
 	ck_assert_str_eq(test_buf, "Hello");
 
 	num_msgs = 0;
 	qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_FALSE);
 	qb_log(LOG_DEBUG, "Goodbye");
 	ck_assert_int_eq(num_msgs, 0);
 	qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
 	qb_log(LOG_DEBUG, "Hello again");
 	ck_assert_int_eq(num_msgs, 1);
 	ck_assert_str_eq(test_buf, "Hello again");
 }
 END_TEST
 
 #define ITERATIONS 100000
 static void *thr_send_logs_2(void *ctx)
 {
 	int32_t i;
 	printf("%s\n", __func__);
 
 	for (i = 0; i < ITERATIONS; i++) {
 		qb_log(LOG_INFO, "bla bla");
 		qb_log(LOG_INFO, "blue blue");
 		qb_log(LOG_INFO, "bra bra");
 		qb_log(LOG_INFO, "bro bro");
 		qb_log(LOG_INFO, "brown brown");
 		qb_log(LOG_INFO, "booo booo");
 		qb_log(LOG_INFO, "bogus bogus");
 		qb_log(LOG_INFO, "bungu bungu");
 	}
 	return (NULL);
 }
 
 static void *thr_send_logs_1(void *ctx)
 {
 	int32_t i;
 
 	printf("%s\n", __func__);
 	for (i = 0; i < ITERATIONS; i++) {
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "foo soup");
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "fungus soup");
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "fruity soup");
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "free soup");
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "frot soup");
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "fresh soup");
 		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
 					    __LINE__, 0, "fattening soup");
 
 	}
 	return (NULL);
 }
 
 #define THREADS 4
 START_TEST(test_log_threads)
 {
 	pthread_t threads[THREADS];
 	pthread_attr_t thread_attr[THREADS];
 	int32_t i;
 	int32_t rc;
 	int32_t lf;
 	void *retval;
 
 	qb_log_init("test", LOG_USER, LOG_DEBUG);
 	lf = qb_log_file_open("threads.log");
 	rc = qb_log_filter_ctl(lf, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE,
 					   __FILE__, LOG_DEBUG);
 	ck_assert_int_eq(rc, 0);
 	qb_log_format_set(lf, "[%p] [%l] %b");
 	rc = qb_log_ctl(lf, QB_LOG_CONF_ENABLED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 	ck_assert_int_eq(rc, 0);
 
 	for (i = 0; i < THREADS/2; i++) {
 		pthread_attr_init(&thread_attr[i]);
 
 		pthread_attr_setdetachstate(&thread_attr[i],
 					    PTHREAD_CREATE_JOINABLE);
 		pthread_create(&threads[i], &thread_attr[i],
 			       thr_send_logs_1, NULL);
 	}
 	for (i = THREADS/2; i < THREADS; i++) {
 		pthread_attr_init(&thread_attr[i]);
 
 		pthread_attr_setdetachstate(&thread_attr[i],
 					    PTHREAD_CREATE_JOINABLE);
 		pthread_create(&threads[i], &thread_attr[i],
 			       thr_send_logs_2, NULL);
 	}
 	for (i = 0; i < THREADS; i++) {
 		pthread_join(threads[i], &retval);
 	}
 
 }
 END_TEST
 
 START_TEST(test_log_long_msg)
 {
 	int lpc;
 	int rc;
 	int i, max = 1000;
 	char *buffer = calloc(1, max);
 
 	qb_log_init("test", LOG_USER, LOG_DEBUG);
 	rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
 			  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
 	ck_assert_int_eq(rc, 0);
 
 	for (lpc = 500; lpc < max; lpc++) {
 		lpc++;
 		for(i = 0; i < max; i++) {
 			buffer[i] = 'a' + (i % 10);
 		}
 		buffer[lpc%600] = 0;
 		qb_log(LOG_INFO, "Message %d %d - %s", lpc, lpc%600, buffer);
 	}
 
         qb_log_blackbox_write_to_file("blackbox.dump");
         qb_log_blackbox_print_from_file("blackbox.dump");
 	unlink("blackbox.dump");
 	qb_log_fini();
 }
 END_TEST
 
 START_TEST(test_threaded_logging)
 {
 	int32_t t;
 	int32_t rc;
 
 	qb_log_init("test", LOG_USER, LOG_EMERG);
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 
 	t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
 	rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
 			       QB_LOG_FILTER_FILE, "*", LOG_INFO);
 	ck_assert_int_eq(rc, 0);
 	qb_log_format_set(t, "%b");
 	rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_ctl(t, QB_LOG_CONF_THREADED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 	qb_log_thread_start();
 
 	memset(test_buf, 0, sizeof(test_buf));
 	test_priority = 0;
 	num_msgs = 0;
 
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 	qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
 
 	qb_log_fini();
 
 	ck_assert_int_eq(num_msgs, 10);
 }
 END_TEST
 
 START_TEST(test_extended_information)
 {
 	int32_t t;
 	int32_t rc;
 	int extended;
 
 	qb_log_init("test", LOG_USER, LOG_DEBUG);
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 
 	t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
 	_ck_assert_int(t, >, QB_LOG_STDOUT);
 	qb_log_format_set(t, "%b");
 	rc = qb_log_filter_fn_set(NULL);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FILE,
 			       "*", LOG_TRACE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FORMAT,
 			       "*", LOG_TRACE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FORMAT,
 			       "*", LOG_TRACE);
 	ck_assert_int_eq(rc, 0);
 	rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
 	ck_assert_int_eq(rc, 0);
 
 	for (extended = QB_FALSE; extended <= QB_TRUE; ++extended) {
 		rc = qb_log_ctl(t, QB_LOG_CONF_EXTENDED, extended);
 		ck_assert_int_eq(rc, 0);
 
 		num_msgs = 0;
 
 		memset(test_buf, 0, sizeof(test_buf));
 		qb_log(LOG_ERR, "message with no extended information");
 		ck_assert_str_eq(test_buf, "message with no extended information");
 
 		memset(test_buf, 0, sizeof(test_buf));
 		qb_log(LOG_ERR, "message with empty extended information "QB_XS);
 		ck_assert_str_eq(test_buf, "message with empty extended information ");
 
 		memset(test_buf, 0, sizeof(test_buf));
 		qb_log(LOG_ERR, QB_XS" message with only extended information");
 		ck_assert_str_eq(test_buf, extended?
 				 "| message with only extended information" : "");
 
 		memset(test_buf, 0, sizeof(test_buf));
 		qb_log(LOG_ERR, "message with extended information "QB_XS" (namely this)");
 		ck_assert_str_eq(test_buf, extended?
 				 "message with extended information | (namely this)"
 				 : "message with extended information ");
 
 		ck_assert_int_eq(num_msgs, (extended? 4 : 3));
 	}
 	qb_log_fini();
 }
 END_TEST
 
 #ifdef HAVE_SYSLOG_TESTS
 START_TEST(test_syslog)
 {
 	qb_log_init("flip", LOG_USER, LOG_INFO);
 	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
 
 	qb_log(LOG_ERR, "first as flip");
 	ck_assert_int_eq(_syslog_opened, 1);
 	ck_assert_str_eq(_syslog_ident, "flip");
 
 	qb_log_ctl2(QB_LOG_SYSLOG, QB_LOG_CONF_IDENT, QB_LOG_CTL2_S("flop"));
 	qb_log(LOG_ERR, "second as flop");
 	ck_assert_str_eq(_syslog_ident, "flop");
 
 	qb_log_fini();
 }
 END_TEST
 #endif
 
 static Suite *
 log_suite(void)
 {
 	TCase *tc;
 	Suite *s = suite_create("logging");
 
 	tc = tcase_create("va_serialize");
 	tcase_add_test(tc, test_va_serialize);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("limits");
 	tcase_add_test(tc, test_log_stupid_inputs);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("basic");
 	tcase_add_test(tc, test_log_basic);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("format");
 	tcase_add_test(tc, test_log_format);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("enable");
 	tcase_add_test(tc, test_log_enable);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("threads");
 	tcase_add_test(tc, test_log_threads);
 	tcase_set_timeout(tc, 360);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("long_msg");
 	tcase_add_test(tc, test_log_long_msg);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("filter_ft");
 	tcase_add_test(tc, test_log_filter_fn);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("threaded_logging");
 	tcase_add_test(tc, test_threaded_logging);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("extended_information");
 	tcase_add_test(tc, test_extended_information);
 	suite_add_tcase(s, tc);
 
 #ifdef HAVE_SYSLOG_TESTS
 	tc = tcase_create("syslog");
 	tcase_add_test(tc, test_syslog);
 	suite_add_tcase(s, tc);
 #endif
 
 	return s;
 }
 
 int32_t
 main(void)
 {
 	int32_t number_failed;
 
 	Suite *s = log_suite();
 	SRunner *sr = srunner_create(s);
 
 	srunner_run_all(sr, CK_VERBOSE);
 	number_failed = srunner_ntests_failed(sr);
 	srunner_free(sr);
 	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }