1 /* Basic tests for syslog interfaces.
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <array_length.h>
22 #include <netinet/in.h>
23 #include <support/capture_subprocess.h>
24 #include <support/check.h>
25 #include <support/xstdio.h>
26 #include <support/xsocket.h>
27 #include <support/xunistd.h>
35 static const int facilities
[] =
59 static const int priorities
[] =
71 #define IDENT_LENGTH 64
72 #define MSG_LENGTH 1024
74 #define SYSLOG_MSG_BASE "syslog_message"
75 #define OPENLOG_IDENT "openlog_ident"
76 static char large_message
[MSG_LENGTH
];
82 char ident
[IDENT_LENGTH
];
88 call_vsyslog (int priority
, const char *format
, ...)
91 va_start (ap
, format
);
92 vsyslog (priority
, format
, ap
);
97 send_vsyslog (int options
)
99 for (size_t i
= 0; i
< array_length (facilities
); i
++)
101 for (size_t j
= 0; j
< array_length (priorities
); j
++)
103 int facility
= facilities
[i
];
104 int priority
= priorities
[j
];
105 call_vsyslog (facility
| priority
, "%s %d %d", SYSLOG_MSG_BASE
,
112 send_syslog (int options
)
114 for (size_t i
= 0; i
< array_length (facilities
); i
++)
116 for (size_t j
= 0; j
< array_length (priorities
); j
++)
118 int facility
= facilities
[i
];
119 int priority
= priorities
[j
];
120 syslog (facility
| priority
, "%s %d %d", SYSLOG_MSG_BASE
, facility
,
127 check_syslog_message (const struct msg_t
*msg
, int msgnum
, int options
,
130 if (msgnum
== array_length (facilities
) * array_length (priorities
) - 1)
133 int i
= msgnum
/ array_length (priorities
);
134 int j
= msgnum
% array_length (priorities
);
136 int expected_facility
= facilities
[i
];
137 /* With no preceding openlog, syslog default to LOG_USER. */
138 if (expected_facility
== LOG_KERN
)
139 expected_facility
= LOG_USER
;
140 int expected_priority
= priorities
[j
];
142 TEST_COMPARE (msg
->facility
, expected_facility
);
143 TEST_COMPARE (msg
->priority
, expected_priority
);
149 send_syslog_large (int options
)
151 int facility
= LOG_USER
;
152 int priority
= LOG_INFO
;
154 syslog (facility
| priority
, "%s %d %d", large_message
, facility
,
159 send_vsyslog_large (int options
)
161 int facility
= LOG_USER
;
162 int priority
= LOG_INFO
;
164 call_vsyslog (facility
| priority
, "%s %d %d", large_message
, facility
,
169 check_syslog_message_large (const struct msg_t
*msg
, int msgnum
, int options
,
172 TEST_COMPARE (msg
->facility
, LOG_USER
);
173 TEST_COMPARE (msg
->priority
, LOG_INFO
);
174 TEST_COMPARE_STRING (msg
->msg
, large_message
);
180 send_openlog (int options
)
182 /* Define a non-default IDENT and a not default facility. */
183 openlog (OPENLOG_IDENT
, options
, LOG_LOCAL0
);
184 for (size_t j
= 0; j
< array_length (priorities
); j
++)
186 int priority
= priorities
[j
];
187 syslog (priority
, "%s %d %d", SYSLOG_MSG_BASE
, LOG_LOCAL0
, priority
);
191 /* Back to the default IDENT with a non default facility. */
192 openlog (NULL
, 0, LOG_LOCAL6
);
193 for (size_t j
= 0; j
< array_length (priorities
); j
++)
195 int priority
= priorities
[j
];
196 syslog (LOG_LOCAL7
| priority
, "%s %d %d", SYSLOG_MSG_BASE
, LOG_LOCAL7
,
201 /* LOG_KERN does not change the internal default facility. */
202 openlog (NULL
, 0, LOG_KERN
);
203 for (size_t j
= 0; j
< array_length (priorities
); j
++)
205 int priority
= priorities
[j
];
206 syslog (priority
, "%s %d %d", SYSLOG_MSG_BASE
, LOG_KERN
, priority
);
212 send_openlog_large (int options
)
214 /* Define a non-default IDENT and a not default facility. */
215 openlog (OPENLOG_IDENT
, options
, LOG_LOCAL0
);
217 syslog (LOG_INFO
, "%s %d %d", large_message
, LOG_LOCAL0
, LOG_INFO
);
223 check_openlog_message (const struct msg_t
*msg
, int msgnum
,
224 int options
, pid_t pid
)
226 if (msgnum
== 3 * array_length (priorities
) - 1)
229 int expected_priority
= priorities
[msgnum
% array_length (priorities
)];
230 TEST_COMPARE (msg
->priority
, expected_priority
);
232 char expected_ident
[IDENT_LENGTH
];
233 snprintf (expected_ident
, sizeof (expected_ident
), "%s%s%.0d%s:",
235 options
& LOG_PID
? "[" : "",
236 options
& LOG_PID
? pid
: 0,
237 options
& LOG_PID
? "]" : "");
239 if (msgnum
< array_length (priorities
))
241 if (options
& LOG_PID
)
242 TEST_COMPARE (msg
->pid
, pid
);
243 TEST_COMPARE_STRING (msg
->ident
, expected_ident
);
244 TEST_COMPARE (msg
->facility
, LOG_LOCAL0
);
246 else if (msgnum
< 2 * array_length (priorities
))
247 TEST_COMPARE (msg
->facility
, LOG_LOCAL7
);
248 else if (msgnum
< 3 * array_length (priorities
))
249 TEST_COMPARE (msg
->facility
, LOG_KERN
);
255 check_openlog_message_large (const struct msg_t
*msg
, int msgnum
,
256 int options
, pid_t pid
)
258 char expected_ident
[IDENT_LENGTH
];
259 snprintf (expected_ident
, sizeof (expected_ident
), "%s%s%.0d%s:",
261 options
& LOG_PID
? "[" : "",
262 options
& LOG_PID
? pid
: 0,
263 options
& LOG_PID
? "]" : "");
265 TEST_COMPARE_STRING (msg
->ident
, expected_ident
);
266 TEST_COMPARE_STRING (msg
->msg
, large_message
);
267 TEST_COMPARE (msg
->priority
, LOG_INFO
);
268 TEST_COMPARE (msg
->facility
, LOG_LOCAL0
);
274 parse_syslog_msg (const char *msg
)
276 struct msg_t r
= { .pid
= -1 };
280 #define STRINPUT(size) XSTRINPUT(size)
281 #define XSTRINPUT(size) "%" # size "s"
283 /* The message in the form:
284 <179>Apr 8 14:51:19 tst-syslog: message 176 3 */
285 int n
= sscanf (msg
, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH
)
286 " " STRINPUT(MSG_LENGTH
) " %*d %*d",
287 &number
, &wsb
, &wsa
, r
.ident
, r
.msg
);
289 /* It should only one space between timestamp and message. */
290 TEST_COMPARE (wsa
- wsb
, 1);
292 r
.facility
= number
& LOG_FACMASK
;
293 r
.priority
= number
& LOG_PRIMASK
;
295 char *pid_start
= strchr (r
.ident
, '[');
296 if (pid_start
!= NULL
)
298 char *pid_end
= strchr (r
.ident
, ']');
300 r
.pid
= strtoul (pid_start
+ 1, NULL
, 10);
307 parse_syslog_console (const char *msg
)
313 /* The message in the form:
314 openlog_ident: syslog_message 128 0 */
315 int n
= sscanf (msg
, STRINPUT(IDENT_LENGTH
) " " STRINPUT(MSG_LENGTH
) " %d %d",
316 r
.ident
, r
.msg
, &facility
, &priority
);
319 r
.facility
= facility
;
320 r
.priority
= priority
;
326 check_syslog_udp (void (*syslog_send
)(int), int options
,
327 bool (*syslog_check
)(const struct msg_t
*, int, int,
330 struct sockaddr_un addr
=
332 .sun_family
= AF_UNIX
,
333 .sun_path
= _PATH_LOG
336 socklen_t addrlen
= sizeof (addr
);
337 int server_udp
= xsocket (AF_UNIX
, SOCK_DGRAM
| SOCK_CLOEXEC
, 0);
338 xbind (server_udp
, (struct sockaddr
*) &addr
, addrlen
);
340 pid_t sender_pid
= xfork ();
343 syslog_send (options
);
351 size_t l
= xrecvfrom (server_udp
, buf
, sizeof (buf
), 0,
352 (struct sockaddr
*) &addr
, &addrlen
);
355 struct msg_t msg
= parse_syslog_msg (buf
);
356 if (!syslog_check (&msg
, msgnum
++, options
, sender_pid
))
363 xwaitpid (sender_pid
, &status
, 0);
364 TEST_COMPARE (status
, 0);
370 check_syslog_tcp (void (*syslog_send
)(int), int options
,
371 bool (*syslog_check
)(const struct msg_t
*, int, int,
374 struct sockaddr_un addr
=
376 .sun_family
= AF_UNIX
,
377 .sun_path
= _PATH_LOG
379 socklen_t addrlen
= sizeof (addr
);
381 int server_tcp
= xsocket (AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
382 xbind (server_tcp
, (struct sockaddr
*) &addr
, addrlen
);
383 xlisten (server_tcp
, 5);
385 pid_t sender_pid
= xfork ();
388 syslog_send (options
);
392 int client_tcp
= xaccept (server_tcp
, NULL
, NULL
);
394 char buf
[2048], *rb
= buf
;
395 size_t rbl
= sizeof (buf
);
396 size_t prl
= 0; /* Track the size of the partial record. */
401 size_t rl
= xrecvfrom (client_tcp
, rb
, rbl
- prl
, 0, NULL
, NULL
);
405 /* Iterate over the buffer to find and check the record. */
410 /* With TCP each record ends with a '\0'. */
411 char *e
= memchr (b
, '\0', l
);
414 struct msg_t msg
= parse_syslog_msg (b
);
415 if (!syslog_check (&msg
, msgnum
++, options
, sender_pid
))
418 /* Advance to the next record. */
419 ptrdiff_t diff
= e
+ 1 - b
;
425 /* Move the partial record to the start of the buffer. */
438 xwaitpid (sender_pid
, &status
, 0);
439 TEST_COMPARE (status
, 0);
445 check_syslog_console_read (FILE *fp
)
449 while (fgets (buf
, sizeof (buf
), fp
) != NULL
)
451 struct msg_t msg
= parse_syslog_console (buf
);
452 TEST_COMPARE_STRING (msg
.ident
, OPENLOG_IDENT
":");
453 TEST_COMPARE (msg
.priority
, priorities
[msgnum
]);
454 TEST_COMPARE (msg
.facility
, LOG_LOCAL0
);
456 if (++msgnum
== array_length (priorities
))
462 check_syslog_console_read_large (FILE *fp
)
465 TEST_VERIFY (fgets (buf
, sizeof (buf
), fp
) != NULL
);
466 struct msg_t msg
= parse_syslog_console (buf
);
468 TEST_COMPARE_STRING (msg
.ident
, OPENLOG_IDENT
":");
469 TEST_COMPARE_STRING (msg
.msg
, large_message
);
470 TEST_COMPARE (msg
.priority
, LOG_INFO
);
471 TEST_COMPARE (msg
.facility
, LOG_LOCAL0
);
475 check_syslog_console (void (*syslog_send
)(int),
476 void (*syslog_check
)(FILE *fp
))
478 xmkfifo (_PATH_CONSOLE
, 0666);
480 pid_t sender_pid
= xfork ();
483 syslog_send (LOG_CONS
);
488 FILE *fp
= xfopen (_PATH_CONSOLE
, "r+");
494 xwaitpid (sender_pid
, &status
, 0);
495 TEST_COMPARE (status
, 0);
497 unlink (_PATH_CONSOLE
);
501 send_openlog_callback (void *clousure
)
503 int options
= *(int *) clousure
;
504 send_openlog (options
);
508 send_openlog_callback_large (void *clousure
)
510 int options
= *(int *) clousure
;
511 send_openlog_large (options
);
515 check_syslog_perror (bool large
)
517 struct support_capture_subprocess result
;
518 result
= support_capture_subprocess (large
519 ? send_openlog_callback_large
520 : send_openlog_callback
,
523 FILE *mfp
= fmemopen (result
.err
.buffer
, result
.err
.length
, "r");
525 FAIL_EXIT1 ("fmemopen: %m");
527 check_syslog_console_read_large (mfp
);
529 check_syslog_console_read (mfp
);
532 support_capture_subprocess_check (&result
, "tst-openlog-child", 0,
534 support_capture_subprocess_free (&result
);
540 /* Send every combination of facility/priority over UDP and TCP. */
541 check_syslog_udp (send_syslog
, 0, check_syslog_message
);
542 check_syslog_tcp (send_syslog
, 0, check_syslog_message
);
544 /* Also check vsyslog. */
545 check_syslog_udp (send_vsyslog
, 0, check_syslog_message
);
546 check_syslog_tcp (send_vsyslog
, 0, check_syslog_message
);
548 /* Run some openlog/syslog/closelog combinations. */
549 check_syslog_udp (send_openlog
, 0, check_openlog_message
);
550 check_syslog_tcp (send_openlog
, 0, check_openlog_message
);
552 /* Check the LOG_PID option. */
553 check_syslog_udp (send_openlog
, LOG_PID
, check_openlog_message
);
554 check_syslog_tcp (send_openlog
, LOG_PID
, check_openlog_message
);
556 /* Check the LOG_CONS option. */
557 check_syslog_console (send_openlog
, check_syslog_console_read
);
559 /* Check the LOG_PERROR option. */
560 check_syslog_perror (false);
562 /* Similar tests as before, but with a large message to trigger the
563 syslog path that uses dynamically allocated memory. */
564 memset (large_message
, 'a', sizeof large_message
- 1);
565 large_message
[sizeof large_message
- 1] = '\0';
567 check_syslog_udp (send_syslog_large
, 0, check_syslog_message_large
);
568 check_syslog_tcp (send_syslog_large
, 0, check_syslog_message_large
);
570 check_syslog_udp (send_vsyslog_large
, 0, check_syslog_message_large
);
571 check_syslog_tcp (send_vsyslog_large
, 0, check_syslog_message_large
);
573 check_syslog_udp (send_openlog_large
, 0, check_openlog_message_large
);
574 check_syslog_tcp (send_openlog_large
, 0, check_openlog_message_large
);
576 check_syslog_udp (send_openlog_large
, LOG_PID
, check_openlog_message_large
);
577 check_syslog_tcp (send_openlog_large
, LOG_PID
, check_openlog_message_large
);
579 check_syslog_console (send_openlog_large
, check_syslog_console_read_large
);
581 check_syslog_perror (true);
586 #include <support/test-driver.c>