]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/logger.c
Merge branch 'logger-fix-local-timestamp' of https://github.com/rgerhards/util-linux
[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>
5ec85227 43#include <sys/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 52#include <getopt.h>
019b9702 53#include <pwd.h>
b363e86d 54
633493be 55#include "all-io.h"
b363e86d 56#include "c.h"
c05a80ca 57#include "closestream.h"
7eda085c 58#include "nls.h"
52a49e9a 59#include "pathnames.h"
b363e86d 60#include "strutils.h"
4b670c01 61#include "xalloc.h"
6dbe3af9
KZ
62
63#define SYSLOG_NAMES
64#include <syslog.h>
65
ebff016a 66#ifdef HAVE_LIBSYSTEMD
d77dc29e 67# include <systemd/sd-daemon.h>
4b670c01
SK
68# include <systemd/sd-journal.h>
69#endif
70
87ee2658
ST
71#ifdef HAVE_SYS_TIMEX_H
72# include <sys/timex.h>
73#endif
74
68265d07
SK
75enum {
76 TYPE_UDP = (1 << 1),
77 TYPE_TCP = (1 << 2),
78 ALL_TYPES = TYPE_UDP | TYPE_TCP
79};
80
d77dc29e
SK
81enum {
82 AF_UNIX_ERRORS_OFF = 0,
83 AF_UNIX_ERRORS_ON,
84 AF_UNIX_ERRORS_AUTO
85};
86
98920f80 87enum {
4b670c01 88 OPT_PRIO_PREFIX = CHAR_MAX + 1,
4de2e8a0
SK
89 OPT_JOURNALD,
90 OPT_RFC3164,
d77dc29e 91 OPT_RFC5424,
3f51c10b
SK
92 OPT_SOCKET_ERRORS,
93 OPT_ID
98920f80
DJ
94};
95
cfa77d26
SK
96struct logger_ctl {
97 int fd;
cfa77d26 98 int pri;
59c6ac0b 99 pid_t pid; /* zero when unwanted */
cfa77d26 100 char *tag;
c95d3209 101 char *unix_socket; /* -u <path> or default to _PATH_DEVLOG */
c68a1cb4
SK
102 char *server;
103 char *port;
104 int socket_type;
46ee14df 105 void (*syslogfp)(const struct logger_ctl *ctl, const char *msg);
4de2e8a0 106 unsigned int
d77dc29e
SK
107 unix_socket_errors:1, /* whether to report or not errors */
108 prio_prefix:1, /* read priority from intput */
109 stderr_printout:1, /* output message to stderr */
110 rfc5424_time:1, /* include time stamp */
111 rfc5424_tq:1, /* include time quality markup */
112 rfc5424_host:1; /* include hostname */
cfa77d26
SK
113};
114
d8b616c2 115static char *get_prio_prefix(char *msg, int *prio)
98920f80
DJ
116{
117 int p;
118 char *end = NULL;
119 int facility = *prio & LOG_FACMASK;
120
121 errno = 0;
122 p = strtoul(msg + 1, &end, 10);
123
124 if (errno || !end || end == msg + 1 || end[0] != '>')
125 return msg;
126
127 if (p & LOG_FACMASK)
128 facility = p & LOG_FACMASK;
129
130 *prio = facility | (p & LOG_PRIMASK);
131 return end + 1;
132}
133
46ee14df 134static int decode(const char *name, CODE *codetab)
82054b1d
DR
135{
136 register CODE *c;
137
4d7d1af6
SK
138 if (name == NULL || *name == '\0')
139 return -1;
140 if (isdigit(*name)) {
141 int num;
142 char *end = NULL;
143
144 num = strtol(name, &end, 10);
145 if (errno || name == end || (end && *end))
146 return -1;
147 for (c = codetab; c->c_name; c++)
148 if (num == c->c_val)
149 return num;
150 return -1;
151 }
82054b1d
DR
152 for (c = codetab; c->c_name; c++)
153 if (!strcasecmp(name, c->c_name))
154 return (c->c_val);
155
156 return -1;
157}
158
159static int pencode(char *s)
160{
2e0fd22d
SK
161 int facility, level;
162 char *separator;
163
164 separator = strchr(s, '.');
165 if (separator) {
166 *separator = '\0';
167 facility = decode(s, facilitynames);
168 if (facility < 0)
169 errx(EXIT_FAILURE, _("unknown facility name: %s"), s);
170 s = ++separator;
171 } else
172 facility = LOG_USER;
173 level = decode(s, prioritynames);
174 if (level < 0)
175 errx(EXIT_FAILURE, _("unknown priority name: %s"), s);
176 return ((level & LOG_PRIMASK) | (facility & LOG_FACMASK));
82054b1d
DR
177}
178
d77dc29e 179static int unix_socket(struct logger_ctl *ctl, const char *path, const int socket_type)
fe6999da 180{
68265d07 181 int fd, i;
fe6999da 182 static struct sockaddr_un s_addr; /* AF_UNIX address of local logger */
7eda085c 183
68265d07
SK
184 if (strlen(path) >= sizeof(s_addr.sun_path))
185 errx(EXIT_FAILURE, _("openlog %s: pathname too long"), path);
7eda085c 186
fe6999da 187 s_addr.sun_family = AF_UNIX;
68265d07
SK
188 strcpy(s_addr.sun_path, path);
189
190 for (i = 2; i; i--) {
191 int st = -1;
49999d6a 192
68265d07
SK
193 if (i == 2 && socket_type & TYPE_UDP)
194 st = SOCK_DGRAM;
195 if (i == 1 && socket_type & TYPE_TCP)
196 st = SOCK_STREAM;
197 if (st == -1 || (fd = socket(AF_UNIX, st, 0)) == -1)
198 continue;
fe6999da
SK
199 if (connect(fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {
200 close(fd);
68265d07 201 continue;
fe6999da 202 }
68265d07 203 break;
fe6999da 204 }
7eda085c 205
d77dc29e
SK
206 if (i == 0) {
207 if (ctl->unix_socket_errors)
208 err(EXIT_FAILURE, _("socket %s"), path);
209 else
210 /* See --socket-errors manual page entry for
211 * explanation of this strange exit. */
212 exit(EXIT_SUCCESS);
213 }
fe6999da 214 return fd;
7eda085c
KZ
215}
216
195c3603
KZ
217static int inet_socket(const char *servername, const char *port,
218 const int socket_type)
68265d07
SK
219{
220 int fd, errcode, i;
24f4db69 221 struct addrinfo hints, *res;
68265d07
SK
222 const char *p = port;
223
224 for (i = 2; i; i--) {
225 memset(&hints, 0, sizeof(hints));
226 if (i == 2 && socket_type & TYPE_UDP) {
227 hints.ai_socktype = SOCK_DGRAM;
228 if (port == NULL)
229 p = "syslog";
230 }
231 if (i == 1 && socket_type & TYPE_TCP) {
232 hints.ai_socktype = SOCK_STREAM;
233 if (port == NULL)
234 p = "syslog-conn";
235 }
236 if (hints.ai_socktype == 0)
237 continue;
238 hints.ai_family = AF_UNSPEC;
239 errcode = getaddrinfo(servername, p, &hints, &res);
240 if (errcode != 0)
4ce393f4 241 errx(EXIT_FAILURE, _("failed to resolve name %s port %s: %s"),
68265d07
SK
242 servername, p, gai_strerror(errcode));
243 if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
244 freeaddrinfo(res);
245 continue;
246 }
247 if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
248 freeaddrinfo(res);
249 close(fd);
250 continue;
251 }
24f4db69 252
68265d07
SK
253 freeaddrinfo(res);
254 break;
255 }
912d6b98 256
68265d07 257 if (i == 0)
4ce393f4 258 errx(EXIT_FAILURE, _("failed to connect to %s port %s"), servername, p);
49999d6a 259
912d6b98
WJE
260 return fd;
261}
68265d07 262
ebff016a 263#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
264static int journald_entry(FILE *fp)
265{
266 struct iovec *iovec;
267 char *buf = NULL;
268 ssize_t sz;
269 int n, lines, vectors = 8, ret;
270 size_t dummy = 0;
271
272 iovec = xmalloc(vectors * sizeof(struct iovec));
273 for (lines = 0; /* nothing */ ; lines++) {
274 buf = NULL;
275 sz = getline(&buf, &dummy, fp);
276 if (sz == -1)
277 break;
278 if (0 < sz && buf[sz - 1] == '\n') {
279 sz--;
280 buf[sz] = '\0';
281 }
282 if (lines == vectors) {
283 vectors *= 2;
047e2888
SK
284 if (IOV_MAX < vectors)
285 errx(EXIT_FAILURE, _("maximum input lines (%d) exceeded"), IOV_MAX);
4b670c01
SK
286 iovec = xrealloc(iovec, vectors * sizeof(struct iovec));
287 }
288 iovec[lines].iov_base = buf;
289 iovec[lines].iov_len = sz;
290 }
291 ret = sd_journal_sendv(iovec, lines);
292 for (n = 0; n < lines; n++)
293 free(iovec[n].iov_base);
294 free(iovec);
295 return ret;
296}
297#endif
298
46ee14df 299static char *xgetlogin(void)
019b9702
SK
300{
301 char *cp;
302 struct passwd *pw;
303
304 if (!(cp = getlogin()) || !*cp)
305 cp = (pw = getpwuid(geteuid()))? pw->pw_name : "<someone>";
306 return cp;
307}
308
3070ca77
RG
309
310/* this creates a timestamp based on current time according to the
311 * fine rules of RFC3164, most importantly it ensures in a portable
312 * way that the month day is correctly written (with a SP instead
313 * of a leading 0). The function uses a static buffer which is
314 * overwritten on the next call (just like ctime() does).
315 */
316static const char *
317rfc3164_current_time(void)
318{
319 static char time[32];
320 struct timeval tv;
321 struct tm *tm;
322 static char *monthnames[] = { "Jan", "Feb", "Mar", "Apr",
323 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
324
325 gettimeofday(&tv, NULL);
326 tm = localtime(&tv.tv_sec);
327 snprintf(time, sizeof(time),"%s %2d %2.2d:%2.2d:%2.2d",
328 monthnames[tm->tm_mon], tm->tm_mday,
329 tm->tm_hour, tm->tm_min, tm->tm_sec);
330 return time;
331}
332
46ee14df 333static void syslog_rfc3164(const struct logger_ctl *ctl, const char *msg)
195c3603 334{
3070ca77 335 char *buf, pid[30], *cp, *hostname, *dot;
d8b616c2 336 time_t now;
852feb72 337 int len;
d8b616c2 338
77c3bd5b 339 *pid = '\0';
cfa77d26 340 if (ctl->fd < 0)
c462a8ca 341 return;
59c6ac0b
KZ
342 if (ctl->pid)
343 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
852feb72
KZ
344
345 cp = ctl->tag ? ctl->tag : xgetlogin();
346
133bf77b
SK
347 hostname = xgethostname();
348 dot = strchr(hostname, '.');
349 if (dot)
350 *dot = '\0';
852feb72 351
852feb72 352 len = xasprintf(&buf, "<%d>%.15s %s %.200s%s: %.400s",
3070ca77 353 ctl->pri, rfc3164_current_time(), hostname, cp, pid, msg);
852feb72
KZ
354
355 if (write_all(ctl->fd, buf, len) < 0)
c462a8ca 356 warn(_("write failed"));
35d36197 357 if (ctl->stderr_printout)
4288f9f1 358 fprintf(stderr, "%s\n", buf);
852feb72
KZ
359
360 free(hostname);
361 free(buf);
7eda085c
KZ
362}
363
46ee14df 364static void syslog_rfc5424(const struct logger_ctl *ctl, const char *msg)
4de2e8a0 365{
852feb72 366 char *buf, *tag = NULL, *hostname = NULL;
77c3bd5b 367 char pid[32], time[64], timeq[80];
87ee2658 368#ifdef HAVE_SYS_TIMEX_H
4de2e8a0 369 struct ntptimeval ntptv;
87ee2658 370#endif
4de2e8a0
SK
371 struct timeval tv;
372 struct tm *tm;
852feb72 373 int len;
4de2e8a0 374
77c3bd5b 375 *pid = *time = *timeq = '\0';
4de2e8a0
SK
376 if (ctl->fd < 0)
377 return;
852feb72 378
4de2e8a0
SK
379 if (ctl->rfc5424_time) {
380 gettimeofday(&tv, NULL);
381 if ((tm = localtime(&tv.tv_sec)) != NULL) {
852feb72
KZ
382 char fmt[64];
383
2f267611
RG
384 const size_t i = strftime(fmt, sizeof(fmt),
385 " %Y-%m-%dT%H:%M:%S.%%06u%z ", tm);
386 /* patch TZ info to comply with RFC3339 (we left SP at end) */
387 fmt[i-1] = fmt[i-2];
388 fmt[i-2] = fmt[i-3];
389 fmt[i-3] = ':';
4de2e8a0
SK
390 snprintf(time, sizeof(time), fmt, tv.tv_usec);
391 } else
392 err(EXIT_FAILURE, _("localtime() failed"));
852feb72
KZ
393 }
394
4de2e8a0
SK
395 if (ctl->rfc5424_host) {
396 hostname = xgethostname();
397 /* Arbitrary looking 'if (var < strlen()) checks originate from
398 * RFC 5424 - 6 Syslog Message Format definition. */
399 if (255 < strlen(hostname))
400 errx(EXIT_FAILURE, _("hostname '%s' is too long"),
401 hostname);
852feb72
KZ
402 }
403
404 tag = ctl->tag ? ctl->tag : xgetlogin();
405
4de2e8a0
SK
406 if (48 < strlen(tag))
407 errx(EXIT_FAILURE, _("tag '%s' is too long"), tag);
852feb72 408
59c6ac0b
KZ
409 if (ctl->pid)
410 snprintf(pid, sizeof(pid), " %d", ctl->pid);
852feb72 411
4de2e8a0 412 if (ctl->rfc5424_tq) {
87ee2658 413#ifdef HAVE_SYS_TIMEX_H
4de2e8a0
SK
414 if (ntp_gettime(&ntptv) == TIME_OK)
415 snprintf(timeq, sizeof(timeq),
416 " [timeQuality tzKnown=\"1\" isSynced=\"1\" syncAccuracy=\"%ld\"]",
417 ntptv.maxerror);
418 else
87ee2658 419#endif
4de2e8a0
SK
420 snprintf(timeq, sizeof(timeq),
421 " [timeQuality tzKnown=\"1\" isSynced=\"0\"]");
852feb72
KZ
422 }
423
424 len = xasprintf(&buf, "<%d>1%s%s%s %s -%s%s %s", ctl->pri, time,
425 hostname ? " " : "",
426 hostname ? hostname : "",
427 tag, pid, timeq, msg);
428
429 if (write_all(ctl->fd, buf, len) < 0)
4de2e8a0 430 warn(_("write failed"));
852feb72 431
35d36197 432 if (ctl->stderr_printout)
4288f9f1 433 fprintf(stderr, "%s\n", buf);
852feb72
KZ
434
435 free(hostname);
4de2e8a0
SK
436 free(buf);
437}
438
439static void parse_rfc5424_flags(struct logger_ctl *ctl, char *optarg)
440{
441 char *in, *tok;
442
443 in = optarg;
444 while ((tok = strtok(in, ","))) {
445 in = NULL;
446 if (!strcmp(tok, "notime")) {
447 ctl->rfc5424_time = 0;
448 ctl->rfc5424_tq = 0;
449 } else if (!strcmp(tok, "notq"))
450 ctl->rfc5424_tq = 0;
451 else if (!strcmp(tok, "nohost"))
452 ctl->rfc5424_host = 0;
453 else
454 warnx(_("ignoring unknown option argument: %s"), tok);
455 }
456}
457
d77dc29e
SK
458static int parse_unix_socket_errors_flags(char *optarg)
459{
460 if (!strcmp(optarg, "off"))
461 return AF_UNIX_ERRORS_OFF;
462 if (!strcmp(optarg, "on"))
463 return AF_UNIX_ERRORS_ON;
464 if (!strcmp(optarg, "auto"))
465 return AF_UNIX_ERRORS_AUTO;
466 warnx(_("invalid argument: %s: using automatic errors"), optarg);
467 return AF_UNIX_ERRORS_AUTO;
468}
469
46ee14df 470static void syslog_local(const struct logger_ctl *ctl, const char *msg)
cfa77d26 471{
1d575033 472 char *buf, *tag;
3070ca77 473 char pid[32];
1d575033
SK
474 int len;
475
1d575033
SK
476 tag = ctl->tag ? ctl->tag : program_invocation_short_name;
477
59c6ac0b
KZ
478 if (ctl->pid)
479 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
1d575033
SK
480 else
481 pid[0] = '\0';
482
3070ca77
RG
483 len = xasprintf(&buf, "<%d>%s %s%s: %s", ctl->pri, rfc3164_current_time(),
484 tag, pid, msg);
1d575033
SK
485 if (write_all(ctl->fd, buf, len) < 0)
486 warn(_("write failed"));
35d36197 487 if (ctl->stderr_printout)
1d575033
SK
488 fprintf(stderr, "%s\n", buf);
489 free(buf);
cfa77d26
SK
490}
491
c68a1cb4
SK
492static void logger_open(struct logger_ctl *ctl)
493{
494 if (ctl->server) {
495 ctl->fd = inet_socket(ctl->server, ctl->port, ctl->socket_type);
4de2e8a0
SK
496 if (!ctl->syslogfp)
497 ctl->syslogfp = syslog_rfc5424;
c68a1cb4
SK
498 return;
499 }
7dc20804
RG
500 if (!ctl->unix_socket)
501 ctl->unix_socket = _PATH_DEVLOG;
502
503 ctl->fd = unix_socket(ctl, ctl->unix_socket, ctl->socket_type);
504 if (!ctl->syslogfp)
505 ctl->syslogfp = syslog_local;
c68a1cb4
SK
506}
507
46ee14df 508static void logger_command_line(const struct logger_ctl *ctl, char **argv)
c68a1cb4
SK
509{
510 char buf[4096];
511 char *p = buf;
512 const char *endp = buf + sizeof(buf) - 2;
513 size_t len;
514
515 while (*argv) {
516 len = strlen(*argv);
517 if (endp < p + len && p != buf) {
518 ctl->syslogfp(ctl, buf);
519 p = buf;
520 }
521 if (sizeof(buf) - 1 < len) {
522 ctl->syslogfp(ctl, *argv++);
523 continue;
524 }
525 if (p != buf)
526 *p++ = ' ';
527 memmove(p, *argv++, len);
528 *(p += len) = '\0';
529 }
530 if (p != buf)
531 ctl->syslogfp(ctl, buf);
532}
533
534static void logger_stdin(struct logger_ctl *ctl)
535{
536 char *msg;
537 int default_priority = ctl->pri;
538 char buf[1024];
539
540 while (fgets(buf, sizeof(buf), stdin) != NULL) {
541 int len = strlen(buf);
542
543 /* some glibc versions are buggy, they add an additional
544 * newline which is removed here. */
545 if (0 < len && buf[len - 1] == '\n')
546 buf[len - 1] = '\0';
547 msg = buf;
548 ctl->pri = default_priority;
549 if (ctl->prio_prefix && msg[0] == '<')
550 msg = get_prio_prefix(msg, &ctl->pri);
551 ctl->syslogfp(ctl, msg);
552 }
553}
554
46ee14df 555static void logger_close(const struct logger_ctl *ctl)
c68a1cb4 556{
1d575033
SK
557 if (close(ctl->fd) != 0)
558 err(EXIT_FAILURE, _("close failed"));
c68a1cb4
SK
559}
560
b363e86d
SK
561static void __attribute__ ((__noreturn__)) usage(FILE *out)
562{
925aa9e8 563 fputs(USAGE_HEADER, out);
4ce393f4 564 fprintf(out, _(" %s [options] [<message>]\n"), program_invocation_short_name);
2da49186 565
451dbcfa
BS
566 fputs(USAGE_SEPARATOR, out);
567 fputs(_("Enter messages into the system log.\n"), out);
568
925aa9e8 569 fputs(USAGE_OPTIONS, out);
3f51c10b
SK
570 fputs(_(" -i log the logger command's PID\n"), out);
571 fputs(_(" --id[=<id>] log the given <id>, or otherwise the PID\n"), out);
d0e875ff
KZ
572 fputs(_(" -f, --file <file> log the contents of this file\n"), out);
573 fputs(_(" -p, --priority <prio> mark given message with this priority\n"), out);
574 fputs(_(" --prio-prefix look for a prefix on every line read from stdin\n"), out);
575 fputs(_(" -s, --stderr output message to standard error as well\n"), out);
576 fputs(_(" -t, --tag <tag> mark every line with this tag\n"), out);
577 fputs(_(" -n, --server <name> write to this remote syslog server\n"), out);
578 fputs(_(" -P, --port <number> use this UDP port\n"), out);
579 fputs(_(" -T, --tcp use TCP only\n"), out);
580 fputs(_(" -d, --udp use UDP only\n"), out);
581 fputs(_(" --rfc3164 use the obsolete BSD syslog protocol\n"), out);
582 fputs(_(" --rfc5424[=<snip>] use the syslog protocol (the default);\n"
583 " <snip> can be notime, or notq, and/or nohost\n"), out);
584 fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out);
d77dc29e
SK
585 fputs(_(" --socket-errors[=<on|off|auto>]\n"
586 " print connection errors when using Unix sockets\n"), out);
ebff016a 587#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
588 fputs(_(" --journald[=<file>] write journald entry\n"), out);
589#endif
925aa9e8
KZ
590
591 fputs(USAGE_SEPARATOR, out);
592 fputs(USAGE_HELP, out);
593 fputs(USAGE_VERSION, out);
594 fprintf(out, USAGE_MAN_TAIL("logger(1)"));
b363e86d
SK
595
596 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
597}
598
6dbe3af9
KZ
599/*
600 * logger -- read and log utility
601 *
602 * Reads from an input and arranges to write the result on the system
603 * log.
604 */
195c3603
KZ
605int main(int argc, char **argv)
606{
cfa77d26
SK
607 struct logger_ctl ctl = {
608 .fd = -1,
59c6ac0b 609 .pid = 0,
cfa77d26 610 .pri = LOG_NOTICE,
c68a1cb4 611 .prio_prefix = 0,
cfa77d26 612 .tag = NULL,
c68a1cb4 613 .unix_socket = NULL,
d77dc29e 614 .unix_socket_errors = 0,
c68a1cb4
SK
615 .server = NULL,
616 .port = NULL,
4de2e8a0
SK
617 .socket_type = ALL_TYPES,
618 .rfc5424_time = 1,
619 .rfc5424_tq = 1,
620 .rfc5424_host = 1,
cfa77d26 621 };
c68a1cb4 622 int ch;
3d9f4b1d 623 int stdout_reopened = 0;
d77dc29e 624 int unix_socket_errors_mode = AF_UNIX_ERRORS_AUTO;
ebff016a 625#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
626 FILE *jfd = NULL;
627#endif
b363e86d 628 static const struct option longopts[] = {
3f51c10b 629 { "id", optional_argument, 0, OPT_ID },
b363e86d
SK
630 { "stderr", no_argument, 0, 's' },
631 { "file", required_argument, 0, 'f' },
632 { "priority", required_argument, 0, 'p' },
633 { "tag", required_argument, 0, 't' },
634 { "socket", required_argument, 0, 'u' },
d77dc29e 635 { "socket-errors", required_argument, 0, OPT_SOCKET_ERRORS },
b363e86d 636 { "udp", no_argument, 0, 'd' },
68265d07 637 { "tcp", no_argument, 0, 'T' },
b363e86d
SK
638 { "server", required_argument, 0, 'n' },
639 { "port", required_argument, 0, 'P' },
640 { "version", no_argument, 0, 'V' },
641 { "help", no_argument, 0, 'h' },
98920f80 642 { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX },
4de2e8a0
SK
643 { "rfc3164", no_argument, 0, OPT_RFC3164 },
644 { "rfc5424", optional_argument, 0, OPT_RFC5424 },
ebff016a 645#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
646 { "journald", optional_argument, 0, OPT_JOURNALD },
647#endif
b363e86d
SK
648 { NULL, 0, 0, 0 }
649 };
7eda085c
KZ
650
651 setlocale(LC_ALL, "");
652 bindtextdomain(PACKAGE, LOCALEDIR);
653 textdomain(PACKAGE);
c05a80ca 654 atexit(close_stdout);
6dbe3af9 655
3f51c10b 656 while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:Vh",
49999d6a 657 longopts, NULL)) != -1) {
98920f80 658 switch (ch) {
6dbe3af9 659 case 'f': /* file to log */
49999d6a 660 if (freopen(optarg, "r", stdin) == NULL)
3d9f4b1d
SK
661 err(EXIT_FAILURE, _("file %s"), optarg);
662 stdout_reopened = 1;
6dbe3af9
KZ
663 break;
664 case 'i': /* log process id also */
3f51c10b
SK
665 ctl.pid = getpid();
666 break;
667 case OPT_ID:
aab5b444 668 if (optarg) {
e598686d
KZ
669 const char *p = optarg;
670
671 if (*p == '=')
672 p++;
59c6ac0b
KZ
673 ctl.pid = strtoul_or_err(optarg, _("failed to parse id"));
674 } else
675 ctl.pid = getpid();
6dbe3af9
KZ
676 break;
677 case 'p': /* priority */
cfa77d26 678 ctl.pri = pencode(optarg);
6dbe3af9
KZ
679 break;
680 case 's': /* log to standard error */
35d36197 681 ctl.stderr_printout = 1;
6dbe3af9
KZ
682 break;
683 case 't': /* tag */
cfa77d26 684 ctl.tag = optarg;
6dbe3af9 685 break;
7eda085c 686 case 'u': /* unix socket */
c68a1cb4 687 ctl.unix_socket = optarg;
7eda085c 688 break;
66ee8158 689 case 'd':
c68a1cb4 690 ctl.socket_type = TYPE_UDP;
68265d07
SK
691 break;
692 case 'T':
c68a1cb4 693 ctl.socket_type = TYPE_TCP;
66ee8158 694 break;
68265d07 695 case 'n':
c68a1cb4 696 ctl.server = optarg;
912d6b98 697 break;
68265d07 698 case 'P':
c68a1cb4 699 ctl.port = optarg;
912d6b98 700 break;
b363e86d 701 case 'V':
e421313d 702 printf(UTIL_LINUX_VERSION);
b363e86d
SK
703 exit(EXIT_SUCCESS);
704 case 'h':
705 usage(stdout);
98920f80 706 case OPT_PRIO_PREFIX:
c68a1cb4 707 ctl.prio_prefix = 1;
98920f80 708 break;
4de2e8a0
SK
709 case OPT_RFC3164:
710 ctl.syslogfp = syslog_rfc3164;
711 break;
712 case OPT_RFC5424:
713 ctl.syslogfp = syslog_rfc5424;
714 if (optarg)
715 parse_rfc5424_flags(&ctl, optarg);
716 break;
ebff016a 717#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
718 case OPT_JOURNALD:
719 if (optarg) {
720 jfd = fopen(optarg, "r");
721 if (!jfd)
722 err(EXIT_FAILURE, _("cannot open %s"),
723 optarg);
724 } else
725 jfd = stdin;
726 break;
727#endif
d77dc29e
SK
728 case OPT_SOCKET_ERRORS:
729 unix_socket_errors_mode = parse_unix_socket_errors_flags(optarg);
730 break;
6dbe3af9
KZ
731 case '?':
732 default:
b363e86d 733 usage(stderr);
6dbe3af9 734 }
49999d6a 735 }
6dbe3af9
KZ
736 argc -= optind;
737 argv += optind;
3d9f4b1d
SK
738 if (stdout_reopened && argc)
739 warnx(_("--file <file> and <message> are mutually exclusive, message is ignored"));
ebff016a 740#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
741 if (jfd) {
742 int ret = journald_entry(jfd);
743 if (stdin != jfd)
744 fclose(jfd);
047e2888 745 if (ret)
54fefa07 746 errx(EXIT_FAILURE, _("journald entry could not be written"));
047e2888 747 return EXIT_SUCCESS;
4b670c01
SK
748 }
749#endif
d77dc29e
SK
750 switch (unix_socket_errors_mode) {
751 case AF_UNIX_ERRORS_OFF:
752 ctl.unix_socket_errors = 0;
753 break;
754 case AF_UNIX_ERRORS_ON:
755 ctl.unix_socket_errors = 1;
756 break;
757 case AF_UNIX_ERRORS_AUTO:
758#ifdef HAVE_LIBSYSTEMD
759 ctl.unix_socket_errors = sd_booted();
760#else
761 ctl.unix_socket_errors = 0;
762#endif
763 break;
764 default:
765 abort();
766 }
c68a1cb4
SK
767 logger_open(&ctl);
768 if (0 < argc)
769 logger_command_line(&ctl, argv);
7eda085c 770 else
c68a1cb4
SK
771 /* Note. --file <arg> reopens stdin making the below
772 * function to be used for file inputs. */
773 logger_stdin(&ctl);
774 logger_close(&ctl);
49999d6a 775 return EXIT_SUCCESS;
6dbe3af9 776}