]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/logger.c
logger: ensure program writes everything to syslog file descriptor
[thirdparty/util-linux.git] / misc-utils / logger.c
CommitLineData
6dbe3af9
KZ
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
7eda085c 32 *
b50945d4 33 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c
KZ
34 * - added Native Language Support
35 * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
36 * - fixed strerr(errno) in gettext calls
6dbe3af9
KZ
37 */
38
6dbe3af9 39#include <errno.h>
047e2888 40#include <limits.h>
6dbe3af9
KZ
41#include <unistd.h>
42#include <stdlib.h>
7eda085c 43#include <time.h>
6dbe3af9
KZ
44#include <stdio.h>
45#include <ctype.h>
46#include <string.h>
7eda085c
KZ
47#include <sys/types.h>
48#include <sys/socket.h>
66ee8158 49#include <sys/un.h>
912d6b98
WJE
50#include <arpa/inet.h>
51#include <netdb.h>
b363e86d
SK
52#include <getopt.h>
53
633493be 54#include "all-io.h"
b363e86d 55#include "c.h"
c05a80ca 56#include "closestream.h"
7eda085c 57#include "nls.h"
b363e86d 58#include "strutils.h"
4b670c01 59#include "xalloc.h"
6dbe3af9
KZ
60
61#define SYSLOG_NAMES
62#include <syslog.h>
63
ebff016a 64#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
65# include <systemd/sd-journal.h>
66#endif
67
68265d07
SK
68enum {
69 TYPE_UDP = (1 << 1),
70 TYPE_TCP = (1 << 2),
71 ALL_TYPES = TYPE_UDP | TYPE_TCP
72};
73
98920f80 74enum {
4b670c01
SK
75 OPT_PRIO_PREFIX = CHAR_MAX + 1,
76 OPT_JOURNALD
98920f80
DJ
77};
78
79
80static char* get_prio_prefix(char *msg, int *prio)
81{
82 int p;
83 char *end = NULL;
84 int facility = *prio & LOG_FACMASK;
85
86 errno = 0;
87 p = strtoul(msg + 1, &end, 10);
88
89 if (errno || !end || end == msg + 1 || end[0] != '>')
90 return msg;
91
92 if (p & LOG_FACMASK)
93 facility = p & LOG_FACMASK;
94
95 *prio = facility | (p & LOG_PRIMASK);
96 return end + 1;
97}
98
82054b1d
DR
99static int decode(char *name, CODE *codetab)
100{
101 register CODE *c;
102
4d7d1af6
SK
103 if (name == NULL || *name == '\0')
104 return -1;
105 if (isdigit(*name)) {
106 int num;
107 char *end = NULL;
108
109 num = strtol(name, &end, 10);
110 if (errno || name == end || (end && *end))
111 return -1;
112 for (c = codetab; c->c_name; c++)
113 if (num == c->c_val)
114 return num;
115 return -1;
116 }
82054b1d
DR
117 for (c = codetab; c->c_name; c++)
118 if (!strcasecmp(name, c->c_name))
119 return (c->c_val);
120
121 return -1;
122}
123
124static int pencode(char *s)
125{
126 char *save;
127 int fac, lev;
128
129 for (save = s; *s && *s != '.'; ++s);
130 if (*s) {
131 *s = '\0';
132 fac = decode(save, facilitynames);
133 if (fac < 0)
09af3db4 134 errx(EXIT_FAILURE, _("unknown facility name: %s"), save);
82054b1d
DR
135 *s++ = '.';
136 }
137 else {
138 fac = LOG_USER;
139 s = save;
140 }
141 lev = decode(s, prioritynames);
142 if (lev < 0)
09af3db4 143 errx(EXIT_FAILURE, _("unknown priority name: %s"), save);
82054b1d
DR
144 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
145}
146
195c3603 147static int unix_socket(const char *path, const int socket_type)
fe6999da 148{
68265d07 149 int fd, i;
fe6999da 150 static struct sockaddr_un s_addr; /* AF_UNIX address of local logger */
7eda085c 151
68265d07
SK
152 if (strlen(path) >= sizeof(s_addr.sun_path))
153 errx(EXIT_FAILURE, _("openlog %s: pathname too long"), path);
7eda085c 154
fe6999da 155 s_addr.sun_family = AF_UNIX;
68265d07
SK
156 strcpy(s_addr.sun_path, path);
157
158 for (i = 2; i; i--) {
159 int st = -1;
49999d6a 160
68265d07
SK
161 if (i == 2 && socket_type & TYPE_UDP)
162 st = SOCK_DGRAM;
163 if (i == 1 && socket_type & TYPE_TCP)
164 st = SOCK_STREAM;
165 if (st == -1 || (fd = socket(AF_UNIX, st, 0)) == -1)
166 continue;
fe6999da
SK
167 if (connect(fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {
168 close(fd);
68265d07 169 continue;
fe6999da 170 }
68265d07 171 break;
fe6999da 172 }
7eda085c 173
68265d07
SK
174 if (i == 0)
175 err(EXIT_FAILURE, _("socket %s"), path);
176
fe6999da 177 return fd;
7eda085c
KZ
178}
179
195c3603
KZ
180static int inet_socket(const char *servername, const char *port,
181 const int socket_type)
68265d07
SK
182{
183 int fd, errcode, i;
24f4db69 184 struct addrinfo hints, *res;
68265d07
SK
185 const char *p = port;
186
187 for (i = 2; i; i--) {
188 memset(&hints, 0, sizeof(hints));
189 if (i == 2 && socket_type & TYPE_UDP) {
190 hints.ai_socktype = SOCK_DGRAM;
191 if (port == NULL)
192 p = "syslog";
193 }
194 if (i == 1 && socket_type & TYPE_TCP) {
195 hints.ai_socktype = SOCK_STREAM;
196 if (port == NULL)
197 p = "syslog-conn";
198 }
199 if (hints.ai_socktype == 0)
200 continue;
201 hints.ai_family = AF_UNSPEC;
202 errcode = getaddrinfo(servername, p, &hints, &res);
203 if (errcode != 0)
4ce393f4 204 errx(EXIT_FAILURE, _("failed to resolve name %s port %s: %s"),
68265d07
SK
205 servername, p, gai_strerror(errcode));
206 if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
207 freeaddrinfo(res);
208 continue;
209 }
210 if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
211 freeaddrinfo(res);
212 close(fd);
213 continue;
214 }
24f4db69 215
68265d07
SK
216 freeaddrinfo(res);
217 break;
218 }
912d6b98 219
68265d07 220 if (i == 0)
4ce393f4 221 errx(EXIT_FAILURE, _("failed to connect to %s port %s"), servername, p);
49999d6a 222
912d6b98
WJE
223 return fd;
224}
68265d07 225
ebff016a 226#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
227static int journald_entry(FILE *fp)
228{
229 struct iovec *iovec;
230 char *buf = NULL;
231 ssize_t sz;
232 int n, lines, vectors = 8, ret;
233 size_t dummy = 0;
234
235 iovec = xmalloc(vectors * sizeof(struct iovec));
236 for (lines = 0; /* nothing */ ; lines++) {
237 buf = NULL;
238 sz = getline(&buf, &dummy, fp);
239 if (sz == -1)
240 break;
241 if (0 < sz && buf[sz - 1] == '\n') {
242 sz--;
243 buf[sz] = '\0';
244 }
245 if (lines == vectors) {
246 vectors *= 2;
047e2888
SK
247 if (IOV_MAX < vectors)
248 errx(EXIT_FAILURE, _("maximum input lines (%d) exceeded"), IOV_MAX);
4b670c01
SK
249 iovec = xrealloc(iovec, vectors * sizeof(struct iovec));
250 }
251 iovec[lines].iov_base = buf;
252 iovec[lines].iov_len = sz;
253 }
254 ret = sd_journal_sendv(iovec, lines);
255 for (n = 0; n < lines; n++)
256 free(iovec[n].iov_base);
257 free(iovec);
258 return ret;
259}
260#endif
261
195c3603
KZ
262static void mysyslog(int fd, int logflags, int pri, char *tag, char *msg)
263{
7eda085c
KZ
264 char buf[1000], pid[30], *cp, *tp;
265 time_t now;
266
267 if (fd > -1) {
7eda085c 268 if (logflags & LOG_PID)
dd0d1654 269 snprintf (pid, sizeof(pid), "[%d]", getpid());
7eda085c
KZ
270 else
271 pid[0] = 0;
272 if (tag)
273 cp = tag;
274 else {
275 cp = getlogin();
276 if (!cp)
277 cp = "<someone>";
278 }
89dda678 279 time(&now);
7eda085c
KZ
280 tp = ctime(&now)+4;
281
dd0d1654 282 snprintf(buf, sizeof(buf), "<%d>%.15s %.200s%s: %.400s",
7eda085c
KZ
283 pri, tp, cp, pid, msg);
284
633493be
SK
285 if (write_all(fd, buf, strlen(buf)+1) < 0)
286 warn(_("write failed"));
7eda085c
KZ
287 }
288}
289
b363e86d
SK
290static void __attribute__ ((__noreturn__)) usage(FILE *out)
291{
925aa9e8 292 fputs(USAGE_HEADER, out);
4ce393f4 293 fprintf(out, _(" %s [options] [<message>]\n"), program_invocation_short_name);
2da49186 294
925aa9e8 295 fputs(USAGE_OPTIONS, out);
68265d07 296 fputs(_(" -T, --tcp use TCP only\n"), out);
925aa9e8
KZ
297 fputs(_(" -d, --udp use UDP only\n"), out);
298 fputs(_(" -i, --id log the process ID too\n"), out);
299 fputs(_(" -f, --file <file> log the contents of this file\n"), out);
300 fputs(_(" -n, --server <name> write to this remote syslog server\n"), out);
301 fputs(_(" -P, --port <number> use this UDP port\n"), out);
302 fputs(_(" -p, --priority <prio> mark given message with this priority\n"), out);
98920f80 303 fputs(_(" --prio-prefix look for a prefix on every line read from stdin\n"), out);
925aa9e8
KZ
304 fputs(_(" -s, --stderr output message to standard error as well\n"), out);
305 fputs(_(" -t, --tag <tag> mark every line with this tag\n"), out);
306 fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out);
ebff016a 307#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
308 fputs(_(" --journald[=<file>] write journald entry\n"), out);
309#endif
925aa9e8
KZ
310
311 fputs(USAGE_SEPARATOR, out);
312 fputs(USAGE_HELP, out);
313 fputs(USAGE_VERSION, out);
314 fprintf(out, USAGE_MAN_TAIL("logger(1)"));
b363e86d
SK
315
316 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
317}
318
6dbe3af9
KZ
319/*
320 * logger -- read and log utility
321 *
322 * Reads from an input and arranges to write the result on the system
323 * log.
324 */
195c3603
KZ
325int main(int argc, char **argv)
326{
98920f80 327 int ch, logflags, pri, prio_prefix;
6dbe3af9 328 char *tag, buf[1024];
7eda085c 329 char *usock = NULL;
68265d07
SK
330 char *server = NULL;
331 char *port = NULL;
332 int LogSock = -1, socket_type = ALL_TYPES;
ebff016a 333#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
334 FILE *jfd = NULL;
335#endif
b363e86d
SK
336 static const struct option longopts[] = {
337 { "id", no_argument, 0, 'i' },
338 { "stderr", no_argument, 0, 's' },
339 { "file", required_argument, 0, 'f' },
340 { "priority", required_argument, 0, 'p' },
341 { "tag", required_argument, 0, 't' },
342 { "socket", required_argument, 0, 'u' },
343 { "udp", no_argument, 0, 'd' },
68265d07 344 { "tcp", no_argument, 0, 'T' },
b363e86d
SK
345 { "server", required_argument, 0, 'n' },
346 { "port", required_argument, 0, 'P' },
347 { "version", no_argument, 0, 'V' },
348 { "help", no_argument, 0, 'h' },
98920f80 349 { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX },
ebff016a 350#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
351 { "journald", optional_argument, 0, OPT_JOURNALD },
352#endif
b363e86d
SK
353 { NULL, 0, 0, 0 }
354 };
7eda085c
KZ
355
356 setlocale(LC_ALL, "");
357 bindtextdomain(PACKAGE, LOCALEDIR);
358 textdomain(PACKAGE);
c05a80ca 359 atexit(close_stdout);
6dbe3af9
KZ
360
361 tag = NULL;
362 pri = LOG_NOTICE;
363 logflags = 0;
98920f80 364 prio_prefix = 0;
68265d07 365 while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:Vh",
49999d6a 366 longopts, NULL)) != -1) {
98920f80 367 switch (ch) {
6dbe3af9 368 case 'f': /* file to log */
49999d6a
SK
369 if (freopen(optarg, "r", stdin) == NULL)
370 err(EXIT_FAILURE, _("file %s"),
371 optarg);
6dbe3af9
KZ
372 break;
373 case 'i': /* log process id also */
374 logflags |= LOG_PID;
375 break;
376 case 'p': /* priority */
377 pri = pencode(optarg);
378 break;
379 case 's': /* log to standard error */
380 logflags |= LOG_PERROR;
381 break;
382 case 't': /* tag */
383 tag = optarg;
384 break;
7eda085c
KZ
385 case 'u': /* unix socket */
386 usock = optarg;
387 break;
66ee8158 388 case 'd':
68265d07
SK
389 socket_type = TYPE_UDP;
390 break;
391 case 'T':
392 socket_type = TYPE_TCP;
66ee8158 393 break;
68265d07
SK
394 case 'n':
395 server = optarg;
912d6b98 396 break;
68265d07
SK
397 case 'P':
398 port = optarg;
912d6b98 399 break;
b363e86d 400 case 'V':
e421313d 401 printf(UTIL_LINUX_VERSION);
b363e86d
SK
402 exit(EXIT_SUCCESS);
403 case 'h':
404 usage(stdout);
98920f80
DJ
405 case OPT_PRIO_PREFIX:
406 prio_prefix = 1;
407 break;
ebff016a 408#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
409 case OPT_JOURNALD:
410 if (optarg) {
411 jfd = fopen(optarg, "r");
412 if (!jfd)
413 err(EXIT_FAILURE, _("cannot open %s"),
414 optarg);
415 } else
416 jfd = stdin;
417 break;
418#endif
6dbe3af9
KZ
419 case '?':
420 default:
b363e86d 421 usage(stderr);
6dbe3af9 422 }
49999d6a 423 }
6dbe3af9
KZ
424 argc -= optind;
425 argv += optind;
426
427 /* setup for logging */
ebff016a 428#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
429 if (jfd) {
430 int ret = journald_entry(jfd);
431 if (stdin != jfd)
432 fclose(jfd);
047e2888
SK
433 if (ret)
434 errx(EXIT_FAILURE, "journald entry could not be wrote");
435 return EXIT_SUCCESS;
4b670c01
SK
436 }
437#endif
2885c533 438 if (server)
68265d07 439 LogSock = inet_socket(server, port, socket_type);
2885c533 440 else if (usock)
68265d07 441 LogSock = unix_socket(usock, socket_type);
2885c533
KZ
442 else
443 openlog(tag ? tag : getlogin(), logflags, 0);
7eda085c 444
6dbe3af9
KZ
445 /* log input line if appropriate */
446 if (argc > 0) {
447 register char *p, *endp;
dd49983a 448 size_t len;
6dbe3af9
KZ
449
450 for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
451 len = strlen(*argv);
452 if (p + len > endp && p > buf) {
68265d07 453 if (!usock && !server)
6dbe3af9 454 syslog(pri, "%s", buf);
7eda085c
KZ
455 else
456 mysyslog(LogSock, logflags, pri, tag, buf);
6dbe3af9
KZ
457 p = buf;
458 }
7eda085c 459 if (len > sizeof(buf) - 1) {
68265d07 460 if (!usock && !server)
6dbe3af9 461 syslog(pri, "%s", *argv++);
7eda085c
KZ
462 else
463 mysyslog(LogSock, logflags, pri, tag, *argv++);
464 } else {
6dbe3af9
KZ
465 if (p != buf)
466 *p++ = ' ';
c0f19ccf 467 memmove(p, *argv++, len);
6dbe3af9
KZ
468 *(p += len) = '\0';
469 }
470 }
7eda085c 471 if (p != buf) {
68265d07 472 if (!usock && !server)
6dbe3af9 473 syslog(pri, "%s", buf);
7eda085c
KZ
474 else
475 mysyslog(LogSock, logflags, pri, tag, buf);
476 }
49999d6a 477 } else {
98920f80
DJ
478 char *msg;
479 int default_priority = pri;
7eda085c 480 while (fgets(buf, sizeof(buf), stdin) != NULL) {
eb63b9b8
KZ
481 /* glibc is buggy and adds an additional newline,
482 so we have to remove it here until glibc is fixed */
483 int len = strlen(buf);
484
485 if (len > 0 && buf[len - 1] == '\n')
486 buf[len - 1] = '\0';
487
98920f80
DJ
488 msg = buf;
489 pri = default_priority;
490 if (prio_prefix && msg[0] == '<')
491 msg = get_prio_prefix(msg, &pri);
492
68265d07 493 if (!usock && !server)
98920f80 494 syslog(pri, "%s", msg);
7eda085c 495 else
98920f80 496 mysyslog(LogSock, logflags, pri, tag, msg);
7eda085c 497 }
49999d6a 498 }
68265d07 499 if (!usock && !server)
7eda085c
KZ
500 closelog();
501 else
502 close(LogSock);
49999d6a
SK
503
504 return EXIT_SUCCESS;
6dbe3af9 505}