benchtests: Add arc4random benchtest
[glibc.git] / misc / tst-syslog.c
blobe550d157967d2c57dfa57cd555582c81286996dc
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>
20 #include <fcntl.h>
21 #include <paths.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>
28 #include <stdarg.h>
29 #include <stdbool.h>
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <syslog.h>
33 #include <sys/un.h>
35 static const int facilities[] =
37 LOG_KERN,
38 LOG_USER,
39 LOG_MAIL,
40 LOG_DAEMON,
41 LOG_AUTH,
42 LOG_SYSLOG,
43 LOG_LPR,
44 LOG_NEWS,
45 LOG_UUCP,
46 LOG_CRON,
47 LOG_AUTHPRIV,
48 LOG_FTP,
49 LOG_LOCAL0,
50 LOG_LOCAL1,
51 LOG_LOCAL2,
52 LOG_LOCAL3,
53 LOG_LOCAL4,
54 LOG_LOCAL5,
55 LOG_LOCAL6,
56 LOG_LOCAL7,
59 static const int priorities[] =
61 LOG_EMERG,
62 LOG_ALERT,
63 LOG_CRIT,
64 LOG_ERR,
65 LOG_WARNING,
66 LOG_NOTICE,
67 LOG_INFO,
68 LOG_DEBUG
71 enum
73 ident_length = 64,
74 msg_length = 64
77 #define SYSLOG_MSG_BASE "syslog_message"
78 #define OPENLOG_IDENT "openlog_ident"
80 struct msg_t
82 int priority;
83 int facility;
84 char ident[ident_length];
85 char msg[msg_length];
86 pid_t pid;
89 static void
90 call_vsyslog (int priority, const char *format, ...)
92 va_list ap;
93 va_start (ap, format);
94 vsyslog (priority, format, ap);
95 va_end (ap);
98 static void
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,
108 facility, priority);
113 static void
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,
123 priority);
128 static bool
129 check_syslog_message (const struct msg_t *msg, int msgnum, int options,
130 pid_t pid)
132 if (msgnum == array_length (facilities) * array_length (priorities) - 1)
133 return false;
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);
147 return true;
150 static void
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);
160 closelog ();
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,
168 priority);
170 closelog ();
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);
179 closelog ();
182 static bool
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)
187 return false;
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:",
194 OPENLOG_IDENT,
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);
211 return true;
214 static struct msg_t
215 parse_syslog_msg (const char *msg)
217 struct msg_t r = { .pid = -1 };
218 int number;
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);
224 TEST_COMPARE (n, 3);
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, ']');
233 if (pid_end != NULL)
234 r.pid = strtoul (pid_start + 1, NULL, 10);
237 return r;
240 static struct msg_t
241 parse_syslog_console (const char *msg)
243 int priority;
244 int facility;
245 struct msg_t r;
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);
251 TEST_COMPARE (n, 4);
253 r.facility = facility;
254 r.priority = priority;
256 return r;
259 static void
260 check_syslog_udp (void (*syslog_send)(int), int options,
261 bool (*syslog_check)(const struct msg_t *, int, int,
262 pid_t))
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 ();
275 if (sender_pid == 0)
277 syslog_send (options);
278 _exit (0);
281 int msgnum = 0;
282 while (1)
284 char buf[512];
285 size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0,
286 (struct sockaddr *) &addr, &addrlen);
287 buf[l] = '\0';
289 struct msg_t msg = parse_syslog_msg (buf);
290 if (!syslog_check (&msg, msgnum++, options, sender_pid))
291 break;
294 xclose (server_udp);
296 int status;
297 xwaitpid (sender_pid, &status, 0);
298 TEST_COMPARE (status, 0);
300 unlink (_PATH_LOG);
303 static void
304 check_syslog_tcp (void (*syslog_send)(int), int options,
305 bool (*syslog_check)(const struct msg_t *, int, int,
306 pid_t))
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 ();
320 if (sender_pid == 0)
322 syslog_send (options);
323 _exit (0);
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. */
331 int msgnum = 0;
333 while (1)
335 size_t rl = xrecvfrom (client_tcp, rb, rbl - prl, 0, NULL, NULL);
336 if (rl == 0)
337 break;
339 /* Iterate over the buffer to find and check the record. */
340 size_t l = rl + prl;
341 char *b = buf;
342 while (1)
344 /* With TCP each record ends with a '\0'. */
345 char *e = memchr (b, '\0', l);
346 if (e != NULL)
348 struct msg_t msg = parse_syslog_msg (b);
349 if (!syslog_check (&msg, msgnum++, options, sender_pid))
350 break;
352 /* Advance to the next record. */
353 ptrdiff_t diff = e + 1 - b;
354 b += diff;
355 l -= diff;
357 else
359 /* Move the partial record to the start of the buffer. */
360 memmove (buf, b, l);
361 rb = buf + l;
362 prl = l;
363 break;
368 xclose (client_tcp);
369 xclose (server_tcp);
371 int status;
372 xwaitpid (sender_pid, &status, 0);
373 TEST_COMPARE (status, 0);
375 unlink (_PATH_LOG);
378 static void
379 check_syslog_console_read (FILE *fp)
381 char buf[512];
382 int msgnum = 0;
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))
391 break;
395 static void
396 check_syslog_console (void)
398 xmkfifo (_PATH_CONSOLE, 0666);
400 pid_t sender_pid = xfork ();
401 if (sender_pid == 0)
403 send_openlog (LOG_CONS);
404 _exit (0);
408 FILE *fp = xfopen (_PATH_CONSOLE, "r+");
409 check_syslog_console_read (fp);
410 xfclose (fp);
413 int status;
414 xwaitpid (sender_pid, &status, 0);
415 TEST_COMPARE (status, 0);
417 unlink (_PATH_CONSOLE);
420 static void
421 send_openlog_callback (void *clousure)
423 int options = *(int *) clousure;
424 send_openlog (options);
427 static void
428 check_syslog_perror (void)
430 struct support_capture_subprocess result;
431 result = support_capture_subprocess (send_openlog_callback,
432 &(int){LOG_PERROR});
434 FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r");
435 if (mfp == NULL)
436 FAIL_EXIT1 ("fmemopen: %m");
437 check_syslog_console_read (mfp);
438 xfclose (mfp);
440 support_capture_subprocess_check (&result, "tst-openlog-child", 0,
441 sc_allow_stderr);
442 support_capture_subprocess_free (&result);
445 static int
446 do_test (void)
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 ();
470 return 0;
473 #include <support/test-driver.c>