1 /* Basic tests for syslog interfaces.
2 Copyright (C) 2022 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
[] =
77 #define SYSLOG_MSG_BASE "syslog_message"
78 #define OPENLOG_IDENT "openlog_ident"
84 char ident
[ident_length
];
90 call_vsyslog (int priority
, const char *format
, ...)
93 va_start (ap
, format
);
94 vsyslog (priority
, format
, ap
);
99 send_vsyslog (int options
)
101 for (size_t i
= 0; i
< array_length (facilities
); i
++)
103 for (size_t j
= 0; j
< array_length (priorities
); j
++)
105 int facility
= facilities
[i
];
106 int priority
= priorities
[j
];
107 call_vsyslog (facility
| priority
, "%s %d %d", SYSLOG_MSG_BASE
,
114 send_syslog (int options
)
116 for (size_t i
= 0; i
< array_length (facilities
); i
++)
118 for (size_t j
= 0; j
< array_length (priorities
); j
++)
120 int facility
= facilities
[i
];
121 int priority
= priorities
[j
];
122 syslog (facility
| priority
, "%s %d %d", SYSLOG_MSG_BASE
, facility
,
129 check_syslog_message (const struct msg_t
*msg
, int msgnum
, int options
,
132 if (msgnum
== array_length (facilities
) * array_length (priorities
) - 1)
135 int i
= msgnum
/ array_length (priorities
);
136 int j
= msgnum
% array_length (priorities
);
138 int expected_facility
= facilities
[i
];
139 /* With no preceding openlog, syslog default to LOG_USER. */
140 if (expected_facility
== LOG_KERN
)
141 expected_facility
= LOG_USER
;
142 int expected_priority
= priorities
[j
];
144 TEST_COMPARE (msg
->facility
, expected_facility
);
145 TEST_COMPARE (msg
->priority
, expected_priority
);
151 send_openlog (int options
)
153 /* Define a non-default IDENT and a not default facility. */
154 openlog (OPENLOG_IDENT
, options
, LOG_LOCAL0
);
155 for (size_t j
= 0; j
< array_length (priorities
); j
++)
157 int priority
= priorities
[j
];
158 syslog (priority
, "%s %d %d", SYSLOG_MSG_BASE
, LOG_LOCAL0
, priority
);
162 /* Back to the default IDENT with a non default facility. */
163 openlog (NULL
, 0, LOG_LOCAL6
);
164 for (size_t j
= 0; j
< array_length (priorities
); j
++)
166 int priority
= priorities
[j
];
167 syslog (LOG_LOCAL7
| priority
, "%s %d %d", SYSLOG_MSG_BASE
, LOG_LOCAL7
,
172 /* LOG_KERN does not change the internal default facility. */
173 openlog (NULL
, 0, LOG_KERN
);
174 for (size_t j
= 0; j
< array_length (priorities
); j
++)
176 int priority
= priorities
[j
];
177 syslog (priority
, "%s %d %d", SYSLOG_MSG_BASE
, LOG_KERN
, priority
);
183 check_openlog_message (const struct msg_t
*msg
, int msgnum
,
184 int options
, pid_t pid
)
186 if (msgnum
== 3 * array_length (priorities
) - 1)
189 int expected_priority
= priorities
[msgnum
% array_length (priorities
)];
190 TEST_COMPARE (msg
->priority
, expected_priority
);
192 char expected_ident
[ident_length
];
193 snprintf (expected_ident
, sizeof (expected_ident
), "%s%s%.0d%s:",
195 options
& LOG_PID
? "[" : "",
196 options
& LOG_PID
? pid
: 0,
197 options
& LOG_PID
? "]" : "");
199 if (msgnum
< array_length (priorities
))
201 if (options
& LOG_PID
)
202 TEST_COMPARE (msg
->pid
, pid
);
203 TEST_COMPARE_STRING (msg
->ident
, expected_ident
);
204 TEST_COMPARE (msg
->facility
, LOG_LOCAL0
);
206 else if (msgnum
< 2 * array_length (priorities
))
207 TEST_COMPARE (msg
->facility
, LOG_LOCAL7
);
208 else if (msgnum
< 3 * array_length (priorities
))
209 TEST_COMPARE (msg
->facility
, LOG_KERN
);
215 parse_syslog_msg (const char *msg
)
217 struct msg_t r
= { .pid
= -1 };
220 /* The message in the form:
221 <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */
222 int n
= sscanf (msg
, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d",
223 &number
, r
.ident
, r
.msg
);
226 r
.facility
= number
& LOG_FACMASK
;
227 r
.priority
= number
& LOG_PRIMASK
;
229 char *pid_start
= strchr (r
.ident
, '[');
230 if (pid_start
!= NULL
)
232 char *pid_end
= strchr (r
.ident
, ']');
234 r
.pid
= strtoul (pid_start
+ 1, NULL
, 10);
241 parse_syslog_console (const char *msg
)
247 /* The message in the form:
248 openlog_ident: syslog_message 128 0 */
249 int n
= sscanf (msg
, "%32s %64s %d %d",
250 r
.ident
, r
.msg
, &facility
, &priority
);
253 r
.facility
= facility
;
254 r
.priority
= priority
;
260 check_syslog_udp (void (*syslog_send
)(int), int options
,
261 bool (*syslog_check
)(const struct msg_t
*, int, int,
264 struct sockaddr_un addr
=
266 .sun_family
= AF_UNIX
,
267 .sun_path
= _PATH_LOG
270 socklen_t addrlen
= sizeof (addr
);
271 int server_udp
= xsocket (AF_UNIX
, SOCK_DGRAM
| SOCK_CLOEXEC
, 0);
272 xbind (server_udp
, (struct sockaddr
*) &addr
, addrlen
);
274 pid_t sender_pid
= xfork ();
277 syslog_send (options
);
285 size_t l
= xrecvfrom (server_udp
, buf
, sizeof (buf
), 0,
286 (struct sockaddr
*) &addr
, &addrlen
);
289 struct msg_t msg
= parse_syslog_msg (buf
);
290 if (!syslog_check (&msg
, msgnum
++, options
, sender_pid
))
297 xwaitpid (sender_pid
, &status
, 0);
298 TEST_COMPARE (status
, 0);
304 check_syslog_tcp (void (*syslog_send
)(int), int options
,
305 bool (*syslog_check
)(const struct msg_t
*, int, int,
308 struct sockaddr_un addr
=
310 .sun_family
= AF_UNIX
,
311 .sun_path
= _PATH_LOG
313 socklen_t addrlen
= sizeof (addr
);
315 int server_tcp
= xsocket (AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
316 xbind (server_tcp
, (struct sockaddr
*) &addr
, addrlen
);
317 xlisten (server_tcp
, 5);
319 pid_t sender_pid
= xfork ();
322 syslog_send (options
);
326 int client_tcp
= xaccept (server_tcp
, NULL
, NULL
);
328 char buf
[512], *rb
= buf
;
329 size_t rbl
= sizeof (buf
);
330 size_t prl
= 0; /* Track the size of the partial record. */
335 size_t rl
= xrecvfrom (client_tcp
, rb
, rbl
- prl
, 0, NULL
, NULL
);
339 /* Iterate over the buffer to find and check the record. */
344 /* With TCP each record ends with a '\0'. */
345 char *e
= memchr (b
, '\0', l
);
348 struct msg_t msg
= parse_syslog_msg (b
);
349 if (!syslog_check (&msg
, msgnum
++, options
, sender_pid
))
352 /* Advance to the next record. */
353 ptrdiff_t diff
= e
+ 1 - b
;
359 /* Move the partial record to the start of the buffer. */
372 xwaitpid (sender_pid
, &status
, 0);
373 TEST_COMPARE (status
, 0);
379 check_syslog_console_read (FILE *fp
)
383 while (fgets (buf
, sizeof (buf
), fp
) != NULL
)
385 struct msg_t msg
= parse_syslog_console (buf
);
386 TEST_COMPARE_STRING (msg
.ident
, OPENLOG_IDENT
":");
387 TEST_COMPARE (msg
.priority
, priorities
[msgnum
]);
388 TEST_COMPARE (msg
.facility
, LOG_LOCAL0
);
390 if (++msgnum
== array_length (priorities
))
396 check_syslog_console (void)
398 xmkfifo (_PATH_CONSOLE
, 0666);
400 pid_t sender_pid
= xfork ();
403 send_openlog (LOG_CONS
);
408 FILE *fp
= xfopen (_PATH_CONSOLE
, "r+");
409 check_syslog_console_read (fp
);
414 xwaitpid (sender_pid
, &status
, 0);
415 TEST_COMPARE (status
, 0);
417 unlink (_PATH_CONSOLE
);
421 send_openlog_callback (void *clousure
)
423 int options
= *(int *) clousure
;
424 send_openlog (options
);
428 check_syslog_perror (void)
430 struct support_capture_subprocess result
;
431 result
= support_capture_subprocess (send_openlog_callback
,
434 FILE *mfp
= fmemopen (result
.err
.buffer
, result
.err
.length
, "r");
436 FAIL_EXIT1 ("fmemopen: %m");
437 check_syslog_console_read (mfp
);
440 support_capture_subprocess_check (&result
, "tst-openlog-child", 0,
442 support_capture_subprocess_free (&result
);
448 /* Send every combination of facility/priority over UDP and TCP. */
449 check_syslog_udp (send_syslog
, 0, check_syslog_message
);
450 check_syslog_tcp (send_syslog
, 0, check_syslog_message
);
452 /* Also check vsyslog. */
453 check_syslog_udp (send_vsyslog
, 0, check_syslog_message
);
454 check_syslog_tcp (send_vsyslog
, 0, check_syslog_message
);
456 /* Run some openlog/syslog/closelog combinations. */
457 check_syslog_udp (send_openlog
, 0, check_openlog_message
);
458 check_syslog_tcp (send_openlog
, 0, check_openlog_message
);
460 /* Check the LOG_PID option. */
461 check_syslog_udp (send_openlog
, LOG_PID
, check_openlog_message
);
462 check_syslog_tcp (send_openlog
, LOG_PID
, check_openlog_message
);
464 /* Check the LOG_CONS option. */
465 check_syslog_console ();
467 /* Check the LOG_PERROR option. */
468 check_syslog_perror ();
473 #include <support/test-driver.c>