1    	/*
2    	 * Copyright (c) 2011-2015 Red Hat, Inc.
3    	 *
4    	 * All rights reserved.
5    	 *
6    	 * Author: Angus Salkeld <asalkeld@redhat.com>
7    	 *
8    	 * This file is part of libqb.
9    	 *
10   	 * libqb is free software: you can redistribute it and/or modify
11   	 * it under the terms of the GNU Lesser General Public License as published by
12   	 * the Free Software Foundation, either version 2.1 of the License, or
13   	 * (at your option) any later version.
14   	 *
15   	 * libqb is distributed in the hope that it will be useful,
16   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   	 * GNU Lesser General Public License for more details.
19   	 *
20   	 * You should have received a copy of the GNU Lesser General Public License
21   	 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
22   	 */
23   	
24   	#include "os_base.h"
25   	#include <pthread.h>
26   	
27   	#include "check_common.h"
28   	
29   	#include <qb/qbdefs.h>
30   	#include <qb/qbutil.h>
31   	#include <qb/qblog.h>
32   	
33   	#ifdef USE_JOURNAL
34   	#include <systemd/sd-journal.h>
35   	#endif
36   	
37   	#include "_syslog_override.h"
38   	
39   	extern size_t qb_vsnprintf_serialize(char *serialize, size_t max_len, const char *fmt, va_list ap);
40   	extern size_t qb_vsnprintf_deserialize(char *string, size_t strlen, const char *buf);
41   	
42   	
43   	static void
44   	format_this(char *out, const char *fmt, ...)
45   	{
46   		char buf[QB_LOG_MAX_LEN];
47   		va_list ap;
48   	
49   		va_start(ap, fmt);
50   		qb_vsnprintf_serialize(buf, QB_LOG_MAX_LEN, fmt, ap);
51   		qb_vsnprintf_deserialize(out, QB_LOG_MAX_LEN, buf);
52   		va_end(ap);
53   	}
54   	
55   	static void
56   	format_this_up_to(char *out, size_t max_len, const char *fmt, ...)
57   	{
58   		char buf[QB_LOG_MAX_LEN];
59   		va_list ap;
60   	
61   		va_start(ap, fmt);
62   		qb_vsnprintf_serialize(buf, max_len, fmt, ap);
63   		qb_vsnprintf_deserialize(out, QB_LOG_MAX_LEN, buf);
64   		va_end(ap);
65   	}
66   	
67   	START_TEST(test_va_serialize)
68   	{
69   		char buf[QB_LOG_MAX_LEN];
70   		char cmp_buf[QB_LOG_MAX_LEN];
71   	
72   		format_this(buf, "one line");
73   		ck_assert_str_eq(buf, "one line");
74   	
75   		format_this(buf, "p1:%p, p2:%p", format_this, buf);
76   		snprintf(cmp_buf, QB_LOG_MAX_LEN, "p1:%p, p2:%p", format_this, buf);
77   		ck_assert_str_eq(buf, cmp_buf);
78   	
79   		format_this(buf, "s1:%s, s2:%s", "Yes", "Never");
80   		ck_assert_str_eq(buf, "s1:Yes, s2:Never");
81   	
82   		format_this(buf, "s1:%s, s2:%s", "Yes", "Never");
83   		ck_assert_str_eq(buf, "s1:Yes, s2:Never");
84   	
85   		format_this(buf, "d1:%d, d2:%5i, d3:%04i", 23, 37, 84);
86   		ck_assert_str_eq(buf, "d1:23, d2:   37, d3:0084");
87   	
88   		format_this(buf, "f1:%.5f, f2:%.2f", 23.34109, 23.34109);
89   		ck_assert_str_eq(buf, "f1:23.34109, f2:23.34");
90   	
91   		format_this(buf, "%zd", (size_t)13140964);
92   		ck_assert_str_eq(buf, "13140964");
93   		format_this(buf, "%jd", (intmax_t)30627823);
94   		ck_assert_str_eq(buf, "30627823");
95   		format_this(buf, "%td", buf-cmp_buf);
96   		snprintf(cmp_buf, QB_LOG_MAX_LEN, "%td", buf-cmp_buf);
97   		ck_assert_str_eq(buf, cmp_buf);
98   	
99   		format_this(buf, ":%s:", "Hello, world!");
100  		ck_assert_str_eq(buf, ":Hello, world!:");
101  		format_this(buf, ":%15s:", "Hello, world!");
102  		ck_assert_str_eq(buf, ":  Hello, world!:");
103  		format_this(buf, ":%.10s:", "Hello, world!");
104  		ck_assert_str_eq(buf, ":Hello, wor:");
105  		format_this(buf, ":%-10s:", "Hello, world!");
106  		ck_assert_str_eq(buf, ":Hello, world!:");
107  		format_this(buf, ":%-15s:", "Hello, world!");
108  		ck_assert_str_eq(buf, ":Hello, world!  :");
109  		format_this(buf, ":%.15s:", "Hello, world!");
110  		ck_assert_str_eq(buf, ":Hello, world!:");
111  		format_this(buf, ":%15.10s:", "Hello, world!");
112  		ck_assert_str_eq(buf, ":     Hello, wor:");
113  		format_this(buf, ":%-15.10s:", "Hello, world!");
114  		ck_assert_str_eq(buf, ":Hello, wor     :");
115  	
116  		format_this(buf, ":%*d:", 8, 96);
117  		ck_assert_str_eq(buf, ":      96:");
118  	
119  		format_this_up_to(buf, 11, "123456789____");
120  		ck_assert_str_eq(buf, "123456789_");
121  	
122  		format_this(buf, "Client %s.%.9s wants to fence (%s) '%s' with device '%s'",
123  			    "bla", "foooooooooooooooooo",
124  			    "action", "target", "hoop");
125  	
126  		ck_assert_str_eq(buf,
127  				 "Client bla.foooooooo wants to fence (action) 'target' with device 'hoop'");
128  	
129  		format_this(buf, "Node %s now has process list: %.32x (was %.32x)",
130  			    "18builder", 2, 0);
131  		ck_assert_str_eq(buf, "Node 18builder now has process list: 00000000000000000000000000000002 (was 00000000000000000000000000000000)");
132  	
133  	
134  	}
135  	END_TEST
136  	
137  	START_TEST(test_log_stupid_inputs)
138  	{
139  		int32_t rc;
140  	
141  		/* shouldn't crash with out an init() */
142  		qb_log_fini();
143  	
144  		/* not init'ed */
145  		rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
146  				       QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
147  		ck_assert_int_eq(rc, -EINVAL);
148  	
149  		rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 2000);
150  		ck_assert_int_eq(rc, -EINVAL);
151  	
152  		qb_log(LOG_INFO, "not init'd");
153  	
154  		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
155  					    __LINE__, 0, "also not init'd");
156  	
157  		qb_log_init("test", LOG_USER, LOG_DEBUG);
158  	
159  		/* non-opened log file */
160  		rc = qb_log_filter_ctl(21, QB_LOG_FILTER_ADD,
161  				       QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
162  		ck_assert_int_eq(rc, -EBADF);
163  	
164  		rc = qb_log_ctl(21, QB_LOG_CONF_PRIORITY_BUMP, -1);
165  		ck_assert_int_eq(rc, -EBADF);
166  	
167  		/* target < 0 or >= 32 */
168  		rc = qb_log_filter_ctl(41, QB_LOG_FILTER_ADD,
169  				       QB_LOG_FILTER_FILE, "bla", LOG_TRACE);
170  		ck_assert_int_eq(rc, -EBADF);
171  	
172  		rc = qb_log_ctl(-1, QB_LOG_CONF_PRIORITY_BUMP, -1);
173  		ck_assert_int_eq(rc, -EBADF);
174  	
175  		/* crap values to filter_ctl() */
176  		rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
177  				       QB_LOG_FILTER_FILE, NULL, LOG_INFO);
178  		ck_assert_int_eq(rc, -EINVAL);
179  		rc = qb_log_filter_ctl(QB_LOG_SYSLOG, 56,
180  				       QB_LOG_FILTER_FILE, "boja", LOG_INFO);
181  		ck_assert_int_eq(rc, -EINVAL);
182  	
183  		/* crap values to ctl() */
184  		rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, -2000);
185  		ck_assert_int_eq(rc, -EINVAL);
186  		rc = qb_log_ctl(QB_LOG_BLACKBOX, 67, 2000);
187  		ck_assert_int_eq(rc, -EINVAL);
188  		rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_SIZE, 2000);
189  		ck_assert_int_eq(rc, -ENOSYS);
190  	
191  	}
192  	END_TEST
193  	
194  	static char test_buf[4097];
195  	static uint8_t test_priority;
196  	static int32_t num_msgs;
197  	static size_t last_length;
198  	
199  	/*
200  	 * to test that we get what we expect.
201  	 */
202  	static void
203  	_test_logger(int32_t t,
204  		     struct qb_log_callsite *cs,
205  		     struct timespec *timestamp, const char *msg)
206  	{
207  		test_buf[0] = '\0';
208  		qb_log_target_format(t, cs, timestamp, msg, test_buf);
209  		test_priority = cs->priority;
210  	
211  		num_msgs++;
212  	}
213  	
214  	static void
215  	_test_length_logger(int32_t t,
216  		     struct qb_log_callsite *cs,
217  		     struct timespec *timestamp, const char *msg)
218  	{
219  		strcpy(test_buf, msg);
220  		qb_log_target_format(t, cs, timestamp, msg, test_buf);
221  		test_priority = cs->priority;
222  	
223  		num_msgs++;
224  		last_length = strlen(msg);
225  	}
226  	
227  	static void log_also(void)
228  	{
229  		qb_log(LOG_INFO, "yes please");
230  	}
231  	
232  	static void log_and_this_too(void)
233  	{
234  		qb_log(LOG_INFO, "this too please");
235  	}
236  	
237  	static void log_it_please(void)
238  	{
239  		qb_enter();
240  		qb_log(LOG_TRACE, "A:%d B:%d C:%d", 1, 2, 3);
241  		qb_log(LOG_DEBUG, "A:%d B:%d C:%d", 1, 2, 3);
242  		errno = EEXIST;
243  		qb_perror(LOG_WARNING, "bogus error");
244  		errno = 0;
245  		qb_log(LOG_INFO, "A:%d B:%d C:%d", 1, 2, 3);
246  		qb_log(LOG_NOTICE, "A:%d B:%d C:%d", 1, 2, 3);
247  		qb_log(LOG_WARNING, "A:%d B:%d C:%d", 1, 2, 3);
248  		qb_log(LOG_ERR, "A:%d B:%d C:%d", 1, 2, 3);
249  		qb_leave();
250  	}
251  	
252  	
253  	static int32_t _cust_t = -1;
254  	static void
255  	m_filter(struct qb_log_callsite *cs)
256  	{
257  		if ((cs->priority >= LOG_ALERT &&
258  		     cs->priority <= LOG_INFO) ||
259  		    cs->tags > 0) {
260  			qb_bit_set(cs->targets, _cust_t);
261  		} else {
262  			qb_bit_clear(cs->targets, _cust_t);
263  		}
264  	}
265  	
266  	
267  	START_TEST(test_log_filter_fn)
268  	{
269  		int32_t rc;
270  	
271  		qb_log_init("test", LOG_USER, LOG_EMERG);
272  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
273  	
274  		_cust_t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
275  		_ck_assert_int(_cust_t, >, QB_LOG_BLACKBOX);
276  		rc = qb_log_ctl(_cust_t, QB_LOG_CONF_ENABLED, QB_TRUE);
277  		ck_assert_int_eq(rc, 0);
278  	
279  		/*
280  		 * test the custom filter function.
281  		 * make sure qb_log, and qb_log_from_external_source are filtered.
282  		 */
283  		qb_log_filter_fn_set(m_filter);
284  		num_msgs = 0;
285  	
286  		qb_log(LOG_NOTICE, "qb_log_filter_fn_set good");
287  		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
288  					    __LINE__, 0, "qb_log_filter_fn_set good");
289  		qb_log(LOG_TRACE, "qb_log_filter_fn_set bad");
290  		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_DEBUG,
291  					    __LINE__, 44, "qb_log_filter_fn_set woot");
292  		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_DEBUG,
293  					    __LINE__, 0, "qb_log_filter_fn_set bad");
294  	
295  		ck_assert_int_eq(num_msgs, 3);
296  	}
297  	END_TEST
298  	
299  	START_TEST(test_file_logging)
300  	{
301  		struct stat st;
302  		int rc, lf;
303  	
304  		unlink("test1.log");
305  		unlink("test2.log");
306  	
307  		qb_log_init("test", LOG_USER, LOG_DEBUG);
308  		lf = qb_log_file_open("test1.log");
309  		rc = qb_log_filter_ctl(lf, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE,
310  				       __FILE__, LOG_DEBUG);
(1) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
311  		ck_assert_int_eq(rc, 0);
312  		rc = qb_log_ctl(lf, QB_LOG_CONF_ENABLED, QB_TRUE);
(2) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
313  		ck_assert_int_eq(rc, 0);
314  	
315  		qb_log(LOG_INFO, "write to file 1");
316  		qb_log(LOG_INFO, "write to file 1 again");
317  	
318  		rc = stat("test1.log", &st);
(3) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
319  		ck_assert_int_eq(rc, 0);
(4) Event cond_true: Condition "_ck_x >= _ck_y", taking true branch.
320  		ck_assert_int_ge(st.st_size, 32);
321  	
322  		/* Test reopen with NULL arg */
323  		rc = qb_log_file_reopen(lf, NULL);
(5) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
324  		ck_assert_int_eq(rc, 0);
325  		qb_log(LOG_INFO, "write to file 1 and again");
326  		qb_log(LOG_INFO, "write to file 1 yet again");
(6) Event fs_check_call: Calling function "stat" to perform check on ""test1.log"".
Also see events: [toctou]
327  		rc = stat("test1.log", &st);
(7) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
328  		ck_assert_int_eq(rc, 0);
(8) Event cond_true: Condition "_ck_x >= _ck_y", taking true branch.
329  		ck_assert_int_ge(st.st_size, 64);
330  	
331  		/* Test reopen with new file */
332  		rc = qb_log_file_reopen(lf, "test2.log");
(9) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
333  		ck_assert_int_eq(rc, 0);
334  	
335  		qb_log(LOG_INFO, "write to file 2");
336  		qb_log(LOG_INFO, "write to file 2 again");
337  	
338  		rc = stat("test2.log", &st);
(10) Event cond_true: Condition "_ck_x == _ck_y", taking true branch.
339  		ck_assert_int_eq(rc, 0);
(11) Event cond_true: Condition "_ck_x >= _ck_y", taking true branch.
340  		ck_assert_int_ge(st.st_size, 32);
341  	
(12) Event toctou: Calling function "unlink" that uses ""test1.log"" after a check function. This can cause a time-of-check, time-of-use race condition.
Also see events: [fs_check_call]
342  		unlink("test1.log");
343  		unlink("test2.log");
344  	}
345  	END_TEST
346  	
347  	START_TEST(test_timestamps)
348  	{
349  		int32_t t;
350  		int32_t rc;
351  		int a,b,c,d;
352  	
353  		qb_log_init("test", LOG_USER, LOG_EMERG);
354  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
355  	
356  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
357  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
358  				       QB_LOG_FILTER_FILE, "*", LOG_INFO);
359  		ck_assert_int_eq(rc, 0);
360  	
361  		/* normal timestamp */
362  		qb_log_format_set(t, "%t %b");
363  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
364  		ck_assert_int_eq(rc, 0);
365  	
366  		qb_log(LOG_INFO, "The time now is (see left)");
367  		rc = sscanf(test_buf+7, "%d:%d:%d.%d", &a, &b, &c, &d);
368  		ck_assert_int_eq(rc, 3);
369  	
370  		/* millisecond timestamp */
371  		qb_log_format_set(t, "%T %b");
372  		qb_log(LOG_INFO, "The time now is precisely (see left)");
373  		rc = sscanf(test_buf+7, "%d:%d:%d.%d", &a, &b, &c, &d);
374  		ck_assert_int_eq(rc, 4);
375  	}
376  	END_TEST
377  	
378  	
379  	START_TEST(test_line_length)
380  	{
381  		int32_t t;
382  		int32_t rc;
383  		int i;
384  		char bigbuf[4097];
385  	
386  		qb_log_init("test", LOG_USER, LOG_EMERG);
387  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
388  	
389  		t = qb_log_custom_open(_test_length_logger, NULL, NULL, NULL);
390  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
391  				  QB_LOG_FILTER_FORMAT, "*", LOG_WARNING);
392  		ck_assert_int_eq(rc, 0);
393  		qb_log_format_set(t, "[%p] %b");
394  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
395  		ck_assert_int_eq(rc, 0);
396  		rc = qb_log_ctl(t, QB_LOG_CONF_MAX_LINE_LEN, 32);
397  		ck_assert_int_eq(rc, 0);
398  		rc = qb_log_ctl(t, QB_LOG_CONF_ELLIPSIS, QB_TRUE);
399  		ck_assert_int_eq(rc, 0);
400  	
401  		/* captures last log */
402  		memset(test_buf, 0, sizeof(test_buf));
403  		test_priority = 0;
404  		num_msgs = 0;
405  	
406  		qb_log(LOG_ERR, "Short message");
407  		qb_log(LOG_ERR, "This is a longer message 123456789012345678901234567890");
408  		qb_log(LOG_ERR, "Long message with parameters %d %s", 1234, "Oh yes it is");
409  	
410  		ck_assert_int_eq(num_msgs, 3);
411  		ck_assert_int_eq(last_length, 31);
412  	
413  		ck_assert_str_eq(test_buf+28, "...");
414  	
415  		rc = qb_log_ctl(t, QB_LOG_CONF_ELLIPSIS, QB_FALSE);
416  		ck_assert_int_eq(rc, 0);
417  	
418  		qb_log(LOG_ERR, "Long message with parameters %d %s", 1234, "Oh yes it is");
419  		ck_assert_str_ne(test_buf+28, "...");
420  	
421  		/* Long lines */
422  		num_msgs = 0;
423  		rc = qb_log_ctl(t, QB_LOG_CONF_MAX_LINE_LEN, 4096);
424  		ck_assert_int_eq(rc, 0);
425  	
426  		for (i=0; i<4096; i++) {
427  			bigbuf[i] = '0'+(i%10);
428  		}
429  		bigbuf[4096] = '\0';
430  		qb_log(LOG_ERR, "%s", bigbuf);
431  		ck_assert_int_eq(num_msgs, 1);
432  		ck_assert_int_eq(last_length, 4095);
433  	}
434  	END_TEST
435  	
436  	START_TEST(test_log_basic)
437  	{
438  		int32_t t;
439  		int32_t rc;
440  	
441  		qb_log_init("test", LOG_USER, LOG_EMERG);
442  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
443  	
444  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
445  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
446  				  QB_LOG_FILTER_FORMAT, "Angus", LOG_WARNING);
447  		ck_assert_int_eq(rc, 0);
448  		qb_log_format_set(t, "%b");
449  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
450  		ck_assert_int_eq(rc, 0);
451  	
452  		/* captures last log */
453  		memset(test_buf, 0, sizeof(test_buf));
454  		test_priority = 0;
455  		num_msgs = 0;
456  	
457  		/*
458  		 * test filtering by format
459  		 */
460  		qb_log(LOG_INFO, "Hello Angus, how are you?");
461  		qb_log(LOG_WARNING, "Hello Steven, how are you?");
462  		qb_log(LOG_ERR, "Hello Andrew, how are you?");
463  		qb_log(LOG_ERR, "Hello Angus, how are you?");
464  		qb_log(LOG_EMERG, "Hello Anna, how are you?");
465  		ck_assert_int_eq(test_priority, LOG_ERR);
466  		ck_assert_int_eq(num_msgs, 1);
467  		ck_assert_str_eq(test_buf, "Hello Angus, how are you?");
468  	
469  	
470  		/*
471  		 * test filtering by file regex
472  	 	 */
473  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
474  				  QB_LOG_FILTER_FORMAT, "*", LOG_TRACE);
475  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
476  				  QB_LOG_FILTER_FILE_REGEX, "^fakefile*", LOG_DEBUG);
477  	
478  		num_msgs = 0;
479  		qb_log_from_external_source(__func__, "fakefile_logging", "%s bla", LOG_INFO,
480  					    56, 0, "filename/lineno");
481  		qb_log_from_external_source(__func__, "do_not_log_fakefile_logging", "%s bla", LOG_INFO,
482  					    56, 0, "filename/lineno");
483  		ck_assert_int_eq(num_msgs, 1);
484  	
485  		/*
486  		 * test filtering by format regex
487  	 	 */
488  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
489  				  QB_LOG_FILTER_FORMAT, "*", LOG_TRACE);
490  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
491  				  QB_LOG_FILTER_FORMAT_REGEX, "^one", LOG_WARNING);
492  	
493  		num_msgs = 0;
494  		qb_log(LOG_INFO, "one two three");
495  		qb_log(LOG_ERR, "testing one two three");
496  		qb_log(LOG_WARNING, "one two three");
497  		qb_log(LOG_ERR, "one two three");
498  		qb_log(LOG_EMERG, "one two three");
499  		ck_assert_int_eq(num_msgs, 3);
500  	
501  		/*
502  		 * test filtering by function and regex
503  		 */
504  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
505  				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
506  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
507  				  QB_LOG_FILTER_FUNCTION_REGEX, "^log_.*please", LOG_WARNING);
508  	
509  		num_msgs = 0;
510  		qb_log(LOG_ERR, "try if you: log_it_please()");
511  		log_it_please();
512  		ck_assert_int_eq(num_msgs, 3);
513  	
514  		qb_log_filter_ctl(t, QB_LOG_FILTER_REMOVE,
515  				  QB_LOG_FILTER_FUNCTION_REGEX, "log_it_please", LOG_WARNING);
516  	
517  		/*
518  		 * test filtering by function
519  		 */
520  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
521  				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
522  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
523  				  QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
524  	
525  		num_msgs = 0;
526  		qb_log(LOG_ERR, "try if you: log_it_please()");
527  		log_it_please();
528  		ck_assert_int_eq(num_msgs, 3);
529  	
530  		qb_log_filter_ctl(t, QB_LOG_FILTER_REMOVE,
531  				  QB_LOG_FILTER_FUNCTION, "log_it_please", LOG_WARNING);
532  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
533  				  QB_LOG_FILTER_FUNCTION, __func__, LOG_DEBUG);
534  	
535  		num_msgs = 0;
536  		log_it_please();
537  		ck_assert_int_eq(num_msgs, 0);
538  		qb_log(LOG_DEBUG, "try if you: log_it_please()");
539  		ck_assert_int_eq(num_msgs, 1);
540  	
541  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
542  				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
543  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
544  				  QB_LOG_FILTER_FUNCTION,
545  				  "log_also,log_and_this_too",
546  				  LOG_DEBUG);
547  		num_msgs = 0;
548  		log_also();
549  		log_and_this_too();
550  		ck_assert_int_eq(num_msgs, 2);
551  	
552  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
553  				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
554  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
555  				  QB_LOG_FILTER_FILE, "fakefile.c,"__FILE__",otherfakefile", LOG_DEBUG);
556  		/*
557  		 * make sure we can pass in a null filename or function name.
558  		 */
559  		qb_log_from_external_source(__func__, NULL, "%s", LOG_INFO,
560  					    __LINE__, 0, "null filename");
561  		qb_log_from_external_source(NULL, __FILE__, "%s", LOG_INFO,
562  					    __LINE__, 0, "null function");
563  	
564  		/* check same file/lineno logs with different formats work
565  		 */
566  		num_msgs = 0;
567  		qb_log_from_external_source(__func__, __FILE__, "%s bla", LOG_INFO,
568  					    56, 0, "filename/lineno");
569  		ck_assert_int_eq(num_msgs, 1);
570  		ck_assert_str_eq(test_buf, "filename/lineno bla");
571  	
572  		num_msgs = 0;
573  		qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
574  					    56, 0, "same filename/lineno");
575  		ck_assert_int_eq(num_msgs, 1);
576  		ck_assert_str_eq(test_buf, "same filename/lineno");
577  	
578  		/* check filtering works on same file/lineno but different
579  		 * log level.
580  		 */
581  		qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
582  				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
583  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
584  				  QB_LOG_FILTER_FILE, __FILE__, LOG_INFO);
585  	
586  		num_msgs = 0;
587  		qb_log_from_external_source(__func__, __FILE__,
588  					    "same filename/lineno, this level %d",
589  					    LOG_INFO, 56, 0, LOG_INFO);
590  		ck_assert_int_eq(num_msgs, 1);
591  		ck_assert_str_eq(test_buf, "same filename/lineno, this level 6");
592  	
593  		num_msgs = 0;
594  		qb_log_from_external_source(__func__, __FILE__,
595  					    "same filename/lineno, this level %d",
596  					    LOG_DEBUG, 56, 0, LOG_DEBUG);
597  		ck_assert_int_eq(num_msgs, 0);
598  	}
599  	END_TEST
600  	
601  	static const char *_test_tags_stringify(uint32_t tags)
602  	{
603  		if (tags == 1) {
604  			return "ONE";
605  		} else if (tags == 8) {
606  			return "ATE";
607  		} else {
608  			return "ANY";
609  		}
610  	}
611  	
612  	START_TEST(test_log_format)
613  	{
614  		int32_t t;
615  		/* following size/length related equation holds in the context of use:
616  		   strlen(cmp_str) = strlen(host_str) + X; X ~ 20 < sizeof(host_str) */
617  		char host_str[256];
618  		char cmp_str[2 * sizeof(host_str)];
619  	
620  		qb_log_init("test", LOG_USER, LOG_DEBUG);
621  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
622  	
623  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
624  		qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
625  	
626  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
627  				  QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
628  		qb_log_format_set(t, "%p %f %b");
629  	
630  		qb_log(LOG_DEBUG, "Angus");
631  		ck_assert_str_eq(test_buf, "debug check_log.c Angus");
632  		qb_log(LOG_INFO, "Angus");
633  		ck_assert_str_eq(test_buf, "info check_log.c Angus");
634  		qb_log(LOG_NOTICE, "Angus");
635  		ck_assert_str_eq(test_buf, "notice check_log.c Angus");
636  		qb_log(LOG_WARNING, "Angus");
637  		ck_assert_str_eq(test_buf, "warning check_log.c Angus");
638  		qb_log(LOG_ERR, "Angus");
639  		ck_assert_str_eq(test_buf, "error check_log.c Angus");
640  		qb_log(LOG_CRIT, "Angus");
641  		ck_assert_str_eq(test_buf, "crit check_log.c Angus");
642  		qb_log(LOG_ALERT, "Angus");
643  		ck_assert_str_eq(test_buf, "alert check_log.c Angus");
644  		qb_log(LOG_EMERG, "Angus");
645  		ck_assert_str_eq(test_buf, "emerg check_log.c Angus");
646  	
647  		qb_log_tags_stringify_fn_set(_test_tags_stringify);
648  		qb_log_format_set(t, "%g %b");
649  	
650  		qb_logt(LOG_INFO, 0, "Angus");
651  		ck_assert_str_eq(test_buf, "ANY Angus");
652  		qb_logt(LOG_INFO, 1, "Angus");
653  		ck_assert_str_eq(test_buf, "ONE Angus");
654  		qb_logt(LOG_INFO, 5, "Angus");
655  		ck_assert_str_eq(test_buf, "ANY Angus");
656  		qb_logt(LOG_INFO, 8, "Angus");
657  		ck_assert_str_eq(test_buf, "ATE Angus");
658  	
659  		qb_log_format_set(t, "%-15f %b");
660  		qb_log(LOG_WARNING, "Andrew");
661  		ck_assert_str_eq(test_buf, "    check_log.c Andrew");
662  	
663  		qb_log_tags_stringify_fn_set(NULL);
664  	
665  		gethostname(host_str, sizeof(host_str));
666  		host_str[sizeof(host_str) - 1] = '\0';
667  	
668  		qb_log_format_set(t, "%P %H %N %b");
669  		qb_log(LOG_INFO, "Angus");
670  		snprintf(cmp_str, sizeof(cmp_str), "%d %s test Angus", getpid(),
671  			 host_str);
672  		ck_assert_str_eq(test_buf, cmp_str);
673  	
674  		qb_log_format_set(t, "%3N %H %P %b");
675  		qb_log(LOG_INFO, "Angus");
676  		snprintf(cmp_str, sizeof(cmp_str), "tes %s %d Angus", host_str,
677  			 getpid());
678  		ck_assert_str_eq(test_buf, cmp_str);
679  	}
680  	END_TEST
681  	
682  	START_TEST(test_log_enable)
683  	{
684  		int32_t t;
685  		int32_t state;
686  	
687  		qb_log_init("test", LOG_USER, LOG_DEBUG);
688  		state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
689  		ck_assert_int_eq(state, QB_LOG_STATE_ENABLED);
690  		state = qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0);
691  		ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
692  		state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
693  		ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
694  	
695  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
696  		state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
697  		ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
698  	
699  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
700  		qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
701  	
702  		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
703  				  QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
704  		qb_log_format_set(t, "%b");
705  	
706  		qb_log(LOG_DEBUG, "Hello");
707  		ck_assert_str_eq(test_buf, "Hello");
708  	
709  		num_msgs = 0;
710  		qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_FALSE);
711  		qb_log(LOG_DEBUG, "Goodbye");
712  		ck_assert_int_eq(num_msgs, 0);
713  		qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
714  		qb_log(LOG_DEBUG, "Hello again");
715  		ck_assert_int_eq(num_msgs, 1);
716  		ck_assert_str_eq(test_buf, "Hello again");
717  	}
718  	END_TEST
719  	
720  	#define ITERATIONS 100000
721  	static void *thr_send_logs_2(void *ctx)
722  	{
723  		int32_t i;
724  		printf("%s\n", __func__);
725  	
726  		for (i = 0; i < ITERATIONS; i++) {
727  			qb_log(LOG_INFO, "bla bla");
728  			qb_log(LOG_INFO, "blue blue");
729  			qb_log(LOG_INFO, "bra bra");
730  			qb_log(LOG_INFO, "bro bro");
731  			qb_log(LOG_INFO, "brown brown");
732  			qb_log(LOG_INFO, "booo booo");
733  			qb_log(LOG_INFO, "bogus bogus");
734  			qb_log(LOG_INFO, "bungu bungu");
735  		}
736  		return (NULL);
737  	}
738  	
739  	static void *thr_send_logs_1(void *ctx)
740  	{
741  		int32_t i;
742  	
743  		printf("%s\n", __func__);
744  		for (i = 0; i < ITERATIONS; i++) {
745  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
746  						    __LINE__, 0, "foo soup");
747  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
748  						    __LINE__, 0, "fungus soup");
749  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
750  						    __LINE__, 0, "fruity soup");
751  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
752  						    __LINE__, 0, "free soup");
753  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
754  						    __LINE__, 0, "frot soup");
755  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
756  						    __LINE__, 0, "fresh soup");
757  			qb_log_from_external_source(__func__, __FILE__, "%s", LOG_INFO,
758  						    __LINE__, 0, "fattening soup");
759  	
760  		}
761  		return (NULL);
762  	}
763  	
764  	#define THREADS 4
765  	START_TEST(test_log_threads)
766  	{
767  		pthread_t threads[THREADS];
768  		pthread_attr_t thread_attr[THREADS];
769  		int32_t i;
770  		int32_t rc;
771  		int32_t lf;
772  		void *retval;
773  	
774  		qb_log_init("test", LOG_USER, LOG_DEBUG);
775  		lf = qb_log_file_open("threads.log");
776  		rc = qb_log_filter_ctl(lf, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE,
777  						   __FILE__, LOG_DEBUG);
778  		ck_assert_int_eq(rc, 0);
779  		qb_log_format_set(lf, "[%p] [%l] %b");
780  		rc = qb_log_ctl(lf, QB_LOG_CONF_ENABLED, QB_TRUE);
781  		ck_assert_int_eq(rc, 0);
782  		rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
783  		ck_assert_int_eq(rc, 0);
784  	
785  		for (i = 0; i < THREADS/2; i++) {
786  			pthread_attr_init(&thread_attr[i]);
787  	
788  			pthread_attr_setdetachstate(&thread_attr[i],
789  						    PTHREAD_CREATE_JOINABLE);
790  			pthread_create(&threads[i], &thread_attr[i],
791  				       thr_send_logs_1, NULL);
792  		}
793  		for (i = THREADS/2; i < THREADS; i++) {
794  			pthread_attr_init(&thread_attr[i]);
795  	
796  			pthread_attr_setdetachstate(&thread_attr[i],
797  						    PTHREAD_CREATE_JOINABLE);
798  			pthread_create(&threads[i], &thread_attr[i],
799  				       thr_send_logs_2, NULL);
800  		}
801  		for (i = 0; i < THREADS; i++) {
802  			pthread_join(threads[i], &retval);
803  		}
804  	
805  	}
806  	END_TEST
807  	
808  	START_TEST(test_log_long_msg)
809  	{
810  		int lpc;
811  		int rc;
812  		int i, max = 1000;
813  		char *buffer = calloc(1, max);
814  	
815  		qb_log_init("test", LOG_USER, LOG_DEBUG);
816  		rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
817  		ck_assert_int_eq(rc, 0);
818  		rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024);
819  		ck_assert_int_eq(rc, 0);
820  		rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
821  		ck_assert_int_eq(rc, 0);
822  		rc = qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
823  				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
824  		ck_assert_int_eq(rc, 0);
825  	
826  		for (lpc = 500; lpc < max; lpc++) {
827  			lpc++;
828  			for(i = 0; i < max; i++) {
829  				buffer[i] = 'a' + (i % 10);
830  			}
831  			buffer[lpc%600] = 0;
832  			qb_log(LOG_INFO, "Message %d %d - %s", lpc, lpc%600, buffer);
833  		}
834  	
835  	        rc = qb_log_blackbox_write_to_file("blackbox.dump");
836  		ck_assert_int_gt(rc, 0);
837  	        rc = qb_log_blackbox_print_from_file("blackbox.dump");
838  		ck_assert_int_le(rc, 0);
839  		unlink("blackbox.dump");
840  		qb_log_fini();
841  	}
842  	END_TEST
843  	
844  	START_TEST(test_threaded_logging)
845  	{
846  		int32_t t;
847  		int32_t rc;
848  	
849  		qb_log_init("test", LOG_USER, LOG_EMERG);
850  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
851  	
852  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
853  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
854  				       QB_LOG_FILTER_FILE, "*", LOG_INFO);
855  		ck_assert_int_eq(rc, 0);
856  		qb_log_format_set(t, "%b");
857  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
858  		ck_assert_int_eq(rc, 0);
859  		rc = qb_log_ctl(t, QB_LOG_CONF_THREADED, QB_TRUE);
860  		ck_assert_int_eq(rc, 0);
861  		qb_log_thread_start();
862  	
863  		memset(test_buf, 0, sizeof(test_buf));
864  		test_priority = 0;
865  		num_msgs = 0;
866  	
867  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
868  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
869  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
870  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
871  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
872  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
873  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
874  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
875  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
876  		qb_log(LOG_INFO, "Yoda how old are you? - %d", __LINE__);
877  	
878  		qb_log_fini();
879  	
880  		ck_assert_int_eq(num_msgs, 10);
881  	}
882  	END_TEST
883  	
884  	#ifdef HAVE_PTHREAD_SETSCHEDPARAM
885  	START_TEST(test_threaded_logging_bad_sched_params)
886  	{
887  		int32_t t;
888  		int32_t rc;
889  	
890  		qb_log_init("test", LOG_USER, LOG_EMERG);
891  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
892  	
893  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
894  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
895  				       QB_LOG_FILTER_FILE, "*", LOG_INFO);
896  		ck_assert_int_eq(rc, 0);
897  		qb_log_format_set(t, "%b");
898  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
899  		ck_assert_int_eq(rc, 0);
900  		rc = qb_log_ctl(t, QB_LOG_CONF_THREADED, QB_TRUE);
901  		ck_assert_int_eq(rc, 0);
902  	
903  	#if defined(SCHED_RR)
904  	#define QB_SCHED SCHED_RR
905  	#elif defined(SCHED_FIFO)
906  	#define QB_SCHED SCHED_FIFO
907  	#else
908  	#define QB_SCHED (-1)
909  	#endif
910  		rc = qb_log_thread_priority_set(QB_SCHED, -1);
911  		ck_assert_int_eq(rc, 0);
912  	
913  		rc = qb_log_thread_start();
914  		ck_assert_int_ne(rc, 0);
915  		qb_log_fini();
916  	}
917  	END_TEST
918  	#endif
919  	
920  	START_TEST(test_extended_information)
921  	{
922  		int32_t t;
923  		int32_t rc;
924  		int extended;
925  	
926  		qb_log_init("test", LOG_USER, LOG_DEBUG);
927  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
928  	
929  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
930  		_ck_assert_int(t, >, QB_LOG_STDOUT);
931  		qb_log_format_set(t, "%b");
932  		rc = qb_log_filter_fn_set(NULL);
933  		ck_assert_int_eq(rc, 0);
934  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FILE,
935  				       "*", LOG_TRACE);
936  		ck_assert_int_eq(rc, 0);
937  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FORMAT,
938  				       "*", LOG_TRACE);
939  		ck_assert_int_eq(rc, 0);
940  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FORMAT,
941  				       "*", LOG_TRACE);
942  		ck_assert_int_eq(rc, 0);
943  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
944  		ck_assert_int_eq(rc, 0);
945  	
946  		for (extended = QB_FALSE; extended <= QB_TRUE; ++extended) {
947  			rc = qb_log_ctl(t, QB_LOG_CONF_EXTENDED, extended);
948  			ck_assert_int_eq(rc, 0);
949  	
950  			num_msgs = 0;
951  	
952  			memset(test_buf, 0, sizeof(test_buf));
953  			qb_log(LOG_ERR, "message with no extended information");
954  			ck_assert_str_eq(test_buf, "message with no extended information");
955  	
956  			memset(test_buf, 0, sizeof(test_buf));
957  			qb_log(LOG_ERR, "message with empty extended information "QB_XS);
958  			ck_assert_str_eq(test_buf, "message with empty extended information ");
959  	
960  			memset(test_buf, 0, sizeof(test_buf));
961  			qb_log(LOG_ERR, QB_XS" message with only extended information");
962  			ck_assert_str_eq(test_buf, extended?
963  					 "| message with only extended information" : "");
964  	
965  			memset(test_buf, 0, sizeof(test_buf));
966  			qb_log(LOG_ERR, "message with extended information "QB_XS" (namely this)");
967  			ck_assert_str_eq(test_buf, extended?
968  					 "message with extended information | (namely this)"
969  					 : "message with extended information ");
970  	
971  			ck_assert_int_eq(num_msgs, (extended? 4 : 3));
972  		}
973  		qb_log_fini();
974  	}
975  	END_TEST
976  	
977  	static const char *tagtest_stringify_tag(uint32_t tag)
978  	{
979  		static char buf[32];
980  		sprintf(buf, "%5" PRIu32, tag);
981  		return buf;
982  	}
983  	
984  	START_TEST(test_zero_tags)
985  	{
986  		int32_t rc;
987  		int32_t t;
988  	
989  		qb_log_init("test", LOG_USER, LOG_EMERG);
990  		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
991  	
992  		t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
993  		rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
994  				       QB_LOG_FILTER_FILE, "*", LOG_INFO);
995  		ck_assert_int_eq(rc, 0);
996  	
997  		qb_log_format_set(t, "[%g] %b");
998  		qb_log_tags_stringify_fn_set(tagtest_stringify_tag);
999  		rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
1000 		ck_assert_int_eq(rc, 0);
1001 	
1002 		qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
1003 				  QB_LOG_FILTER_FILE, "*", LOG_TRACE);
1004 	
1005 		qb_log_from_external_source("function", "filename", "%s: %d", LOG_DEBUG, 356, 2, "testlog", 2);
1006 		ck_assert_str_eq(test_buf, "[    2] testlog: 2");
1007 	
1008 		qb_log_from_external_source("function", "filename", "%s: %d", LOG_DEBUG, 356, 0, "testlog", 0);
1009 		ck_assert_str_eq(test_buf, "[    2] testlog: 0");
1010 	
1011 		qb_log_fini();
1012 	
1013 	
1014 	}
1015 	END_TEST
1016 	
1017 	#ifdef USE_JOURNAL
1018 	START_TEST(test_journal)
1019 	{
1020 		int rc;
1021 		const char *msg;
1022 		size_t len;
1023 		pid_t log_pid;
1024 		sd_journal *jnl;
1025 		int count = 0;
1026 		const char *msgid="f77379a8490b408bbe5f6940505a777b";
1027 	
1028 		qb_log_init("check_log", LOG_USER, LOG_DEBUG);
1029 		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
1030 		rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_USE_JOURNAL, 1);
1031 		ck_assert_int_eq(rc, 0);
1032 		qb_log2(msgid, LOG_ERR, "Test message 1 from libqb");
1033 	
1034 		qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
1035 		rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_USE_JOURNAL, 1);
1036 		ck_assert_int_eq(rc, -EINVAL);
1037 		sleep(1);
1038 	
1039 		/* Check it reached the journal */
1040 		rc = sd_journal_open(&jnl, 0);
1041 		ck_assert_int_eq(rc, 0);
1042 		rc = sd_journal_seek_tail(jnl);
1043 		ck_assert_int_eq(rc, 0);
1044 		SD_JOURNAL_FOREACH_BACKWARDS(jnl) {
1045 		    rc = sd_journal_get_data(jnl, "_PID", (const void **)&msg, &len);
1046 		    ck_assert_int_eq(rc, 0);
1047 		    sscanf(msg, "_PID=%d", &log_pid);
1048 		    fprintf(stderr, "PID message = '%s' - pid = %d (pid=%d, parent=%d)\n", msg, log_pid, getpid(), getppid());
1049 		    if (log_pid == getpid()) {
1050 		        rc = sd_journal_get_data(jnl, "MESSAGE", (const void **)&msg, &len);
1051 			ck_assert_int_eq(rc, 0);
1052 		        rc = sd_journal_get_data(jnl, "MESSAGE_ID", (const void **)&msg, &len);
1053 			ck_assert_int_eq(rc, 0);
1054 			ck_assert_str_eq(msg+11, msgid);
1055 			break;
1056 		    }
1057 		    if (++count > 20) {
1058 			    break;
1059 	            }
1060 	        }
1061 		sd_journal_close(jnl);
1062 		ck_assert_int_lt(count, 20);
1063 	}
1064 	END_TEST
1065 	#else
1066 	START_TEST(test_syslog)
1067 	{
1068 		int rc;
1069 	
1070 		qb_log_init("flip", LOG_USER, LOG_INFO);
1071 		qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
1072 	
1073 		qb_log(LOG_ERR, "first as flip");
1074 		ck_assert_int_eq(_syslog_opened, 1);
1075 		ck_assert_str_eq(_syslog_ident, "flip");
1076 	
1077 		qb_log_ctl2(QB_LOG_SYSLOG, QB_LOG_CONF_IDENT, QB_LOG_CTL2_S("flop"));
1078 		qb_log(LOG_ERR, "second as flop");
1079 		ck_assert_str_eq(_syslog_ident, "flop");
1080 	
1081 		/* This test only runs if USE_JOURNAL is undefined, so should always fail */
1082 		rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_USE_JOURNAL, 1);
1083 		ck_assert_int_eq(rc, -EOPNOTSUPP);
1084 	
1085 		qb_log_fini();
1086 	}
1087 	END_TEST
1088 	#endif
1089 	
1090 	static Suite *
1091 	log_suite(void)
1092 	{
1093 		TCase *tc;
1094 		Suite *s = suite_create("logging");
1095 	
1096 		add_tcase(s, tc, test_va_serialize, 0);
1097 		add_tcase(s, tc, test_log_stupid_inputs, 0);
1098 		add_tcase(s, tc, test_log_basic, 0);
1099 		add_tcase(s, tc, test_log_format, 0);
1100 		add_tcase(s, tc, test_log_enable, 0);
1101 		add_tcase(s, tc, test_log_threads, 360);
1102 		add_tcase(s, tc, test_log_long_msg, 0);
1103 		add_tcase(s, tc, test_log_filter_fn, 0);
1104 		add_tcase(s, tc, test_threaded_logging, 0);
1105 		add_tcase(s, tc, test_line_length, 0);
1106 		add_tcase(s, tc, test_file_logging, 0);
1107 	#ifdef HAVE_PTHREAD_SETSCHEDPARAM
1108 		add_tcase(s, tc, test_threaded_logging_bad_sched_params, 0);
1109 	#endif
1110 		add_tcase(s, tc, test_timestamps, 0);
1111 		add_tcase(s, tc, test_extended_information, 0);
1112 		add_tcase(s, tc, test_zero_tags, 0);
1113 	/*
1114 	 * You can still use syslog and journal in a normal application,
1115 	 * but the syslog_override code doesn't work when -lsystemd is present
1116 	 */
1117 	#ifdef USE_JOURNAL
1118 	        add_tcase(s, tc, test_journal, 0);
1119 	#else
1120 		add_tcase(s, tc, test_syslog, 0);
1121 	#endif
1122 	
1123 		return s;
1124 	}
1125 	
1126 	int32_t
1127 	main(void)
1128 	{
1129 		int32_t number_failed;
1130 	
1131 		Suite *s = log_suite();
1132 		SRunner *sr = srunner_create(s);
1133 	
1134 		srunner_run_all(sr, CK_VERBOSE);
1135 		number_failed = srunner_ntests_failed(sr);
1136 		srunner_free(sr);
1137 		return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
1138 	}
1139