]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/logger.c
lib/monotonic: fix compiler warnings
[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;
c68a1cb4
SK
101 char *unix_socket;
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
46ee14df 309static void syslog_rfc3164(const struct logger_ctl *ctl, const char *msg)
195c3603 310{
77c3bd5b 311 char *buf, pid[30], *cp, *tp, *hostname, *dot;
d8b616c2 312 time_t now;
852feb72 313 int len;
d8b616c2 314
77c3bd5b 315 *pid = '\0';
cfa77d26 316 if (ctl->fd < 0)
c462a8ca 317 return;
59c6ac0b
KZ
318 if (ctl->pid)
319 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
852feb72
KZ
320
321 cp = ctl->tag ? ctl->tag : xgetlogin();
322
133bf77b
SK
323 hostname = xgethostname();
324 dot = strchr(hostname, '.');
325 if (dot)
326 *dot = '\0';
852feb72 327
c462a8ca
SK
328 time(&now);
329 tp = ctime(&now) + 4;
852feb72
KZ
330
331 len = xasprintf(&buf, "<%d>%.15s %s %.200s%s: %.400s",
133bf77b 332 ctl->pri, tp, hostname, cp, pid, msg);
852feb72
KZ
333
334 if (write_all(ctl->fd, buf, len) < 0)
c462a8ca 335 warn(_("write failed"));
35d36197 336 if (ctl->stderr_printout)
4288f9f1 337 fprintf(stderr, "%s\n", buf);
852feb72
KZ
338
339 free(hostname);
340 free(buf);
7eda085c
KZ
341}
342
46ee14df 343static void syslog_rfc5424(const struct logger_ctl *ctl, const char *msg)
4de2e8a0 344{
852feb72 345 char *buf, *tag = NULL, *hostname = NULL;
77c3bd5b 346 char pid[32], time[64], timeq[80];
87ee2658 347#ifdef HAVE_SYS_TIMEX_H
4de2e8a0 348 struct ntptimeval ntptv;
87ee2658 349#endif
4de2e8a0
SK
350 struct timeval tv;
351 struct tm *tm;
852feb72 352 int len;
4de2e8a0 353
77c3bd5b 354 *pid = *time = *timeq = '\0';
4de2e8a0
SK
355 if (ctl->fd < 0)
356 return;
852feb72 357
4de2e8a0
SK
358 if (ctl->rfc5424_time) {
359 gettimeofday(&tv, NULL);
360 if ((tm = localtime(&tv.tv_sec)) != NULL) {
852feb72
KZ
361 char fmt[64];
362
2f267611
RG
363 const size_t i = strftime(fmt, sizeof(fmt),
364 " %Y-%m-%dT%H:%M:%S.%%06u%z ", tm);
365 /* patch TZ info to comply with RFC3339 (we left SP at end) */
366 fmt[i-1] = fmt[i-2];
367 fmt[i-2] = fmt[i-3];
368 fmt[i-3] = ':';
4de2e8a0
SK
369 snprintf(time, sizeof(time), fmt, tv.tv_usec);
370 } else
371 err(EXIT_FAILURE, _("localtime() failed"));
852feb72
KZ
372 }
373
4de2e8a0
SK
374 if (ctl->rfc5424_host) {
375 hostname = xgethostname();
376 /* Arbitrary looking 'if (var < strlen()) checks originate from
377 * RFC 5424 - 6 Syslog Message Format definition. */
378 if (255 < strlen(hostname))
379 errx(EXIT_FAILURE, _("hostname '%s' is too long"),
380 hostname);
852feb72
KZ
381 }
382
383 tag = ctl->tag ? ctl->tag : xgetlogin();
384
4de2e8a0
SK
385 if (48 < strlen(tag))
386 errx(EXIT_FAILURE, _("tag '%s' is too long"), tag);
852feb72 387
59c6ac0b
KZ
388 if (ctl->pid)
389 snprintf(pid, sizeof(pid), " %d", ctl->pid);
852feb72 390
4de2e8a0 391 if (ctl->rfc5424_tq) {
87ee2658 392#ifdef HAVE_SYS_TIMEX_H
4de2e8a0
SK
393 if (ntp_gettime(&ntptv) == TIME_OK)
394 snprintf(timeq, sizeof(timeq),
395 " [timeQuality tzKnown=\"1\" isSynced=\"1\" syncAccuracy=\"%ld\"]",
396 ntptv.maxerror);
397 else
87ee2658 398#endif
4de2e8a0
SK
399 snprintf(timeq, sizeof(timeq),
400 " [timeQuality tzKnown=\"1\" isSynced=\"0\"]");
852feb72
KZ
401 }
402
403 len = xasprintf(&buf, "<%d>1%s%s%s %s -%s%s %s", ctl->pri, time,
404 hostname ? " " : "",
405 hostname ? hostname : "",
406 tag, pid, timeq, msg);
407
408 if (write_all(ctl->fd, buf, len) < 0)
4de2e8a0 409 warn(_("write failed"));
852feb72 410
35d36197 411 if (ctl->stderr_printout)
4288f9f1 412 fprintf(stderr, "%s\n", buf);
852feb72
KZ
413
414 free(hostname);
4de2e8a0
SK
415 free(buf);
416}
417
418static void parse_rfc5424_flags(struct logger_ctl *ctl, char *optarg)
419{
420 char *in, *tok;
421
422 in = optarg;
423 while ((tok = strtok(in, ","))) {
424 in = NULL;
425 if (!strcmp(tok, "notime")) {
426 ctl->rfc5424_time = 0;
427 ctl->rfc5424_tq = 0;
428 } else if (!strcmp(tok, "notq"))
429 ctl->rfc5424_tq = 0;
430 else if (!strcmp(tok, "nohost"))
431 ctl->rfc5424_host = 0;
432 else
433 warnx(_("ignoring unknown option argument: %s"), tok);
434 }
435}
436
d77dc29e
SK
437static int parse_unix_socket_errors_flags(char *optarg)
438{
439 if (!strcmp(optarg, "off"))
440 return AF_UNIX_ERRORS_OFF;
441 if (!strcmp(optarg, "on"))
442 return AF_UNIX_ERRORS_ON;
443 if (!strcmp(optarg, "auto"))
444 return AF_UNIX_ERRORS_AUTO;
445 warnx(_("invalid argument: %s: using automatic errors"), optarg);
446 return AF_UNIX_ERRORS_AUTO;
447}
448
46ee14df 449static void syslog_local(const struct logger_ctl *ctl, const char *msg)
cfa77d26 450{
1d575033
SK
451 char *buf, *tag;
452 char time[32], pid[32];
453 struct timeval tv;
454 struct tm *tm;
1d575033
SK
455 int len;
456
457 gettimeofday(&tv, NULL);
458 tm = localtime(&tv.tv_sec);
459 strftime(time, sizeof(time), "%h %e %T", tm);
460
461 tag = ctl->tag ? ctl->tag : program_invocation_short_name;
462
59c6ac0b
KZ
463 if (ctl->pid)
464 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
1d575033
SK
465 else
466 pid[0] = '\0';
467
468 len = xasprintf(&buf, "<%d>%s %s%s: %s", ctl->pri, time, tag, pid, msg);
469 if (write_all(ctl->fd, buf, len) < 0)
470 warn(_("write failed"));
35d36197 471 if (ctl->stderr_printout)
1d575033
SK
472 fprintf(stderr, "%s\n", buf);
473 free(buf);
cfa77d26
SK
474}
475
c68a1cb4
SK
476static void logger_open(struct logger_ctl *ctl)
477{
478 if (ctl->server) {
479 ctl->fd = inet_socket(ctl->server, ctl->port, ctl->socket_type);
4de2e8a0
SK
480 if (!ctl->syslogfp)
481 ctl->syslogfp = syslog_rfc5424;
c68a1cb4
SK
482 return;
483 }
484 if (ctl->unix_socket) {
d77dc29e 485 ctl->fd = unix_socket(ctl, ctl->unix_socket, ctl->socket_type);
4de2e8a0
SK
486 if (!ctl->syslogfp)
487 ctl->syslogfp = syslog_rfc5424;
c68a1cb4
SK
488 return;
489 }
52a49e9a 490 ctl->fd = unix_socket(ctl, _PATH_DEVLOG, ctl->socket_type);
c68a1cb4
SK
491 ctl->syslogfp = syslog_local;
492}
493
46ee14df 494static void logger_command_line(const struct logger_ctl *ctl, char **argv)
c68a1cb4
SK
495{
496 char buf[4096];
497 char *p = buf;
498 const char *endp = buf + sizeof(buf) - 2;
499 size_t len;
500
501 while (*argv) {
502 len = strlen(*argv);
503 if (endp < p + len && p != buf) {
504 ctl->syslogfp(ctl, buf);
505 p = buf;
506 }
507 if (sizeof(buf) - 1 < len) {
508 ctl->syslogfp(ctl, *argv++);
509 continue;
510 }
511 if (p != buf)
512 *p++ = ' ';
513 memmove(p, *argv++, len);
514 *(p += len) = '\0';
515 }
516 if (p != buf)
517 ctl->syslogfp(ctl, buf);
518}
519
520static void logger_stdin(struct logger_ctl *ctl)
521{
522 char *msg;
523 int default_priority = ctl->pri;
524 char buf[1024];
525
526 while (fgets(buf, sizeof(buf), stdin) != NULL) {
527 int len = strlen(buf);
528
529 /* some glibc versions are buggy, they add an additional
530 * newline which is removed here. */
531 if (0 < len && buf[len - 1] == '\n')
532 buf[len - 1] = '\0';
533 msg = buf;
534 ctl->pri = default_priority;
535 if (ctl->prio_prefix && msg[0] == '<')
536 msg = get_prio_prefix(msg, &ctl->pri);
537 ctl->syslogfp(ctl, msg);
538 }
539}
540
46ee14df 541static void logger_close(const struct logger_ctl *ctl)
c68a1cb4 542{
1d575033
SK
543 if (close(ctl->fd) != 0)
544 err(EXIT_FAILURE, _("close failed"));
c68a1cb4
SK
545}
546
b363e86d
SK
547static void __attribute__ ((__noreturn__)) usage(FILE *out)
548{
925aa9e8 549 fputs(USAGE_HEADER, out);
4ce393f4 550 fprintf(out, _(" %s [options] [<message>]\n"), program_invocation_short_name);
2da49186 551
451dbcfa
BS
552 fputs(USAGE_SEPARATOR, out);
553 fputs(_("Enter messages into the system log.\n"), out);
554
925aa9e8 555 fputs(USAGE_OPTIONS, out);
3f51c10b
SK
556 fputs(_(" -i log the logger command's PID\n"), out);
557 fputs(_(" --id[=<id>] log the given <id>, or otherwise the PID\n"), out);
d0e875ff
KZ
558 fputs(_(" -f, --file <file> log the contents of this file\n"), out);
559 fputs(_(" -p, --priority <prio> mark given message with this priority\n"), out);
560 fputs(_(" --prio-prefix look for a prefix on every line read from stdin\n"), out);
561 fputs(_(" -s, --stderr output message to standard error as well\n"), out);
562 fputs(_(" -t, --tag <tag> mark every line with this tag\n"), out);
563 fputs(_(" -n, --server <name> write to this remote syslog server\n"), out);
564 fputs(_(" -P, --port <number> use this UDP port\n"), out);
565 fputs(_(" -T, --tcp use TCP only\n"), out);
566 fputs(_(" -d, --udp use UDP only\n"), out);
567 fputs(_(" --rfc3164 use the obsolete BSD syslog protocol\n"), out);
568 fputs(_(" --rfc5424[=<snip>] use the syslog protocol (the default);\n"
569 " <snip> can be notime, or notq, and/or nohost\n"), out);
570 fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out);
d77dc29e
SK
571 fputs(_(" --socket-errors[=<on|off|auto>]\n"
572 " print connection errors when using Unix sockets\n"), out);
ebff016a 573#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
574 fputs(_(" --journald[=<file>] write journald entry\n"), out);
575#endif
925aa9e8
KZ
576
577 fputs(USAGE_SEPARATOR, out);
578 fputs(USAGE_HELP, out);
579 fputs(USAGE_VERSION, out);
580 fprintf(out, USAGE_MAN_TAIL("logger(1)"));
b363e86d
SK
581
582 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
583}
584
6dbe3af9
KZ
585/*
586 * logger -- read and log utility
587 *
588 * Reads from an input and arranges to write the result on the system
589 * log.
590 */
195c3603
KZ
591int main(int argc, char **argv)
592{
cfa77d26
SK
593 struct logger_ctl ctl = {
594 .fd = -1,
59c6ac0b 595 .pid = 0,
cfa77d26 596 .pri = LOG_NOTICE,
c68a1cb4 597 .prio_prefix = 0,
cfa77d26 598 .tag = NULL,
c68a1cb4 599 .unix_socket = NULL,
d77dc29e 600 .unix_socket_errors = 0,
c68a1cb4
SK
601 .server = NULL,
602 .port = NULL,
4de2e8a0
SK
603 .socket_type = ALL_TYPES,
604 .rfc5424_time = 1,
605 .rfc5424_tq = 1,
606 .rfc5424_host = 1,
cfa77d26 607 };
c68a1cb4 608 int ch;
3d9f4b1d 609 int stdout_reopened = 0;
d77dc29e 610 int unix_socket_errors_mode = AF_UNIX_ERRORS_AUTO;
ebff016a 611#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
612 FILE *jfd = NULL;
613#endif
b363e86d 614 static const struct option longopts[] = {
3f51c10b 615 { "id", optional_argument, 0, OPT_ID },
b363e86d
SK
616 { "stderr", no_argument, 0, 's' },
617 { "file", required_argument, 0, 'f' },
618 { "priority", required_argument, 0, 'p' },
619 { "tag", required_argument, 0, 't' },
620 { "socket", required_argument, 0, 'u' },
d77dc29e 621 { "socket-errors", required_argument, 0, OPT_SOCKET_ERRORS },
b363e86d 622 { "udp", no_argument, 0, 'd' },
68265d07 623 { "tcp", no_argument, 0, 'T' },
b363e86d
SK
624 { "server", required_argument, 0, 'n' },
625 { "port", required_argument, 0, 'P' },
626 { "version", no_argument, 0, 'V' },
627 { "help", no_argument, 0, 'h' },
98920f80 628 { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX },
4de2e8a0
SK
629 { "rfc3164", no_argument, 0, OPT_RFC3164 },
630 { "rfc5424", optional_argument, 0, OPT_RFC5424 },
ebff016a 631#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
632 { "journald", optional_argument, 0, OPT_JOURNALD },
633#endif
b363e86d
SK
634 { NULL, 0, 0, 0 }
635 };
7eda085c
KZ
636
637 setlocale(LC_ALL, "");
638 bindtextdomain(PACKAGE, LOCALEDIR);
639 textdomain(PACKAGE);
c05a80ca 640 atexit(close_stdout);
6dbe3af9 641
3f51c10b 642 while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:Vh",
49999d6a 643 longopts, NULL)) != -1) {
98920f80 644 switch (ch) {
6dbe3af9 645 case 'f': /* file to log */
49999d6a 646 if (freopen(optarg, "r", stdin) == NULL)
3d9f4b1d
SK
647 err(EXIT_FAILURE, _("file %s"), optarg);
648 stdout_reopened = 1;
6dbe3af9
KZ
649 break;
650 case 'i': /* log process id also */
3f51c10b
SK
651 ctl.pid = getpid();
652 break;
653 case OPT_ID:
aab5b444 654 if (optarg) {
e598686d
KZ
655 const char *p = optarg;
656
657 if (*p == '=')
658 p++;
59c6ac0b
KZ
659 ctl.pid = strtoul_or_err(optarg, _("failed to parse id"));
660 } else
661 ctl.pid = getpid();
6dbe3af9
KZ
662 break;
663 case 'p': /* priority */
cfa77d26 664 ctl.pri = pencode(optarg);
6dbe3af9
KZ
665 break;
666 case 's': /* log to standard error */
35d36197 667 ctl.stderr_printout = 1;
6dbe3af9
KZ
668 break;
669 case 't': /* tag */
cfa77d26 670 ctl.tag = optarg;
6dbe3af9 671 break;
7eda085c 672 case 'u': /* unix socket */
c68a1cb4 673 ctl.unix_socket = optarg;
7eda085c 674 break;
66ee8158 675 case 'd':
c68a1cb4 676 ctl.socket_type = TYPE_UDP;
68265d07
SK
677 break;
678 case 'T':
c68a1cb4 679 ctl.socket_type = TYPE_TCP;
66ee8158 680 break;
68265d07 681 case 'n':
c68a1cb4 682 ctl.server = optarg;
912d6b98 683 break;
68265d07 684 case 'P':
c68a1cb4 685 ctl.port = optarg;
912d6b98 686 break;
b363e86d 687 case 'V':
e421313d 688 printf(UTIL_LINUX_VERSION);
b363e86d
SK
689 exit(EXIT_SUCCESS);
690 case 'h':
691 usage(stdout);
98920f80 692 case OPT_PRIO_PREFIX:
c68a1cb4 693 ctl.prio_prefix = 1;
98920f80 694 break;
4de2e8a0
SK
695 case OPT_RFC3164:
696 ctl.syslogfp = syslog_rfc3164;
697 break;
698 case OPT_RFC5424:
699 ctl.syslogfp = syslog_rfc5424;
700 if (optarg)
701 parse_rfc5424_flags(&ctl, optarg);
702 break;
ebff016a 703#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
704 case OPT_JOURNALD:
705 if (optarg) {
706 jfd = fopen(optarg, "r");
707 if (!jfd)
708 err(EXIT_FAILURE, _("cannot open %s"),
709 optarg);
710 } else
711 jfd = stdin;
712 break;
713#endif
d77dc29e
SK
714 case OPT_SOCKET_ERRORS:
715 unix_socket_errors_mode = parse_unix_socket_errors_flags(optarg);
716 break;
6dbe3af9
KZ
717 case '?':
718 default:
b363e86d 719 usage(stderr);
6dbe3af9 720 }
49999d6a 721 }
6dbe3af9
KZ
722 argc -= optind;
723 argv += optind;
3d9f4b1d
SK
724 if (stdout_reopened && argc)
725 warnx(_("--file <file> and <message> are mutually exclusive, message is ignored"));
ebff016a 726#ifdef HAVE_LIBSYSTEMD
4b670c01
SK
727 if (jfd) {
728 int ret = journald_entry(jfd);
729 if (stdin != jfd)
730 fclose(jfd);
047e2888 731 if (ret)
54fefa07 732 errx(EXIT_FAILURE, _("journald entry could not be written"));
047e2888 733 return EXIT_SUCCESS;
4b670c01
SK
734 }
735#endif
d77dc29e
SK
736 switch (unix_socket_errors_mode) {
737 case AF_UNIX_ERRORS_OFF:
738 ctl.unix_socket_errors = 0;
739 break;
740 case AF_UNIX_ERRORS_ON:
741 ctl.unix_socket_errors = 1;
742 break;
743 case AF_UNIX_ERRORS_AUTO:
744#ifdef HAVE_LIBSYSTEMD
745 ctl.unix_socket_errors = sd_booted();
746#else
747 ctl.unix_socket_errors = 0;
748#endif
749 break;
750 default:
751 abort();
752 }
c68a1cb4
SK
753 logger_open(&ctl);
754 if (0 < argc)
755 logger_command_line(&ctl, argv);
7eda085c 756 else
c68a1cb4
SK
757 /* Note. --file <arg> reopens stdin making the below
758 * function to be used for file inputs. */
759 logger_stdin(&ctl);
760 logger_close(&ctl);
49999d6a 761 return EXIT_SUCCESS;
6dbe3af9 762}