]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/logger.c
Merge branch 'help' of https://github.com/rudimeier/util-linux
[thirdparty/util-linux.git] / misc-utils / logger.c
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.
32 *
33 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
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
37 */
38
39 #include <errno.h>
40 #include <limits.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <sys/time.h>
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <string.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <sys/un.h>
50 #include <arpa/inet.h>
51 #include <netdb.h>
52 #include <getopt.h>
53 #include <pwd.h>
54 #include <signal.h>
55 #include <sys/uio.h>
56
57 #include "all-io.h"
58 #include "c.h"
59 #include "closestream.h"
60 #include "nls.h"
61 #include "pathnames.h"
62 #include "strutils.h"
63 #include "xalloc.h"
64 #include "strv.h"
65 #include "list.h"
66
67 #define SYSLOG_NAMES
68 #include <syslog.h>
69
70 #ifdef HAVE_LIBSYSTEMD
71 # include <systemd/sd-daemon.h>
72 # include <systemd/sd-journal.h>
73 #endif
74
75 #ifdef HAVE_SYS_TIMEX_H
76 # include <sys/timex.h>
77 #endif
78
79 enum {
80 TYPE_UDP = (1 << 1),
81 TYPE_TCP = (1 << 2),
82 ALL_TYPES = TYPE_UDP | TYPE_TCP
83 };
84
85 enum {
86 AF_UNIX_ERRORS_OFF = 0,
87 AF_UNIX_ERRORS_ON,
88 AF_UNIX_ERRORS_AUTO
89 };
90
91 enum {
92 OPT_PRIO_PREFIX = CHAR_MAX + 1,
93 OPT_JOURNALD,
94 OPT_RFC3164,
95 OPT_RFC5424,
96 OPT_SOCKET_ERRORS,
97 OPT_MSGID,
98 OPT_NOACT,
99 OPT_ID,
100 OPT_STRUCTURED_DATA_ID,
101 OPT_STRUCTURED_DATA_PARAM,
102 OPT_OCTET_COUNT
103 };
104
105 /* rfc5424 structured data */
106 struct structured_data {
107 char *id; /* SD-ID */
108 char **params; /* array with SD-PARAMs */
109
110 struct list_head sds;
111 };
112
113 struct logger_ctl {
114 int fd;
115 int pri;
116 pid_t pid; /* zero when unwanted */
117 char *hdr; /* the syslog header (based on protocol) */
118 char const *tag;
119 char *msgid;
120 char *unix_socket; /* -u <path> or default to _PATH_DEVLOG */
121 char *server;
122 char *port;
123 int socket_type;
124 size_t max_message_size;
125 struct list_head user_sds; /* user defined rfc5424 structured data */
126 struct list_head reserved_sds; /* standard rfc5424 structured data */
127
128 void (*syslogfp)(struct logger_ctl *ctl);
129
130 unsigned int
131 unix_socket_errors:1, /* whether to report or not errors */
132 noact:1, /* do not write to sockets */
133 prio_prefix:1, /* read priority from input */
134 stderr_printout:1, /* output message to stderr */
135 rfc5424_time:1, /* include time stamp */
136 rfc5424_tq:1, /* include time quality markup */
137 rfc5424_host:1, /* include hostname */
138 skip_empty_lines:1, /* do not send empty lines when processing files */
139 octet_count:1; /* use RFC6587 octet counting */
140 };
141
142 /*
143 * For tests we want to be able to control datetime outputs
144 */
145 #ifdef TEST_LOGGER
146 static inline int logger_gettimeofday(struct timeval *tv, struct timezone *tz)
147 {
148 char *str = getenv("LOGGER_TEST_TIMEOFDAY");
149 uintmax_t sec, usec;
150
151 if (str && sscanf(str, "%ju.%ju", &sec, &usec) == 2) {
152 tv->tv_sec = sec;
153 tv->tv_usec = usec;
154 return tv->tv_sec >= 0 && tv->tv_usec >= 0 ? 0 : -EINVAL;
155 }
156
157 return gettimeofday(tv, tz);
158 }
159
160 static inline char *logger_xgethostname(void)
161 {
162 char *str = getenv("LOGGER_TEST_HOSTNAME");
163 return str ? xstrdup(str) : xgethostname();
164 }
165
166 static inline pid_t logger_getpid(void)
167 {
168 char *str = getenv("LOGGER_TEST_GETPID");
169 unsigned int pid;
170
171 if (str && sscanf(str, "%u", &pid) == 1)
172 return pid;
173 return getpid();
174 }
175
176
177 #undef HAVE_NTP_GETTIME /* force to default non-NTP */
178
179 #else /* !TEST_LOGGER */
180 # define logger_gettimeofday(x, y) gettimeofday(x, y)
181 # define logger_xgethostname xgethostname
182 # define logger_getpid getpid
183 #endif
184
185
186 static int decode(const char *name, const CODE *codetab)
187 {
188 register const CODE *c;
189
190 if (name == NULL || *name == '\0')
191 return -1;
192 if (isdigit(*name)) {
193 int num;
194 char *end = NULL;
195
196 errno = 0;
197 num = strtol(name, &end, 10);
198 if (errno || name == end || (end && *end))
199 return -1;
200 for (c = codetab; c->c_name; c++)
201 if (num == c->c_val)
202 return num;
203 return -1;
204 }
205 for (c = codetab; c->c_name; c++)
206 if (!strcasecmp(name, c->c_name))
207 return (c->c_val);
208
209 return -1;
210 }
211
212 static int pencode(char *s)
213 {
214 int facility, level;
215 char *separator;
216
217 separator = strchr(s, '.');
218 if (separator) {
219 *separator = '\0';
220 facility = decode(s, facilitynames);
221 if (facility < 0)
222 errx(EXIT_FAILURE, _("unknown facility name: %s"), s);
223 s = ++separator;
224 } else
225 facility = LOG_USER;
226 level = decode(s, prioritynames);
227 if (level < 0)
228 errx(EXIT_FAILURE, _("unknown priority name: %s"), s);
229 if (facility == LOG_KERN)
230 facility = LOG_USER; /* kern is forbidden */
231 return ((level & LOG_PRIMASK) | (facility & LOG_FACMASK));
232 }
233
234 static int unix_socket(struct logger_ctl *ctl, const char *path, int *socket_type)
235 {
236 int fd, i, type = -1;
237 static struct sockaddr_un s_addr; /* AF_UNIX address of local logger */
238
239 if (strlen(path) >= sizeof(s_addr.sun_path))
240 errx(EXIT_FAILURE, _("openlog %s: pathname too long"), path);
241
242 s_addr.sun_family = AF_UNIX;
243 strcpy(s_addr.sun_path, path);
244
245 for (i = 2; i; i--) {
246 int st = -1;
247
248 if (i == 2 && *socket_type & TYPE_UDP) {
249 st = SOCK_DGRAM;
250 type = TYPE_UDP;
251 }
252 if (i == 1 && *socket_type & TYPE_TCP) {
253 st = SOCK_STREAM;
254 type = TYPE_TCP;
255 }
256 if (st == -1 || (fd = socket(AF_UNIX, st, 0)) == -1)
257 continue;
258 if (connect(fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {
259 close(fd);
260 continue;
261 }
262 break;
263 }
264
265 if (i == 0) {
266 if (ctl->unix_socket_errors)
267 err(EXIT_FAILURE, _("socket %s"), path);
268
269 /* openlog(3) compatibility, socket errors are
270 * not reported, but ignored silently */
271 ctl->noact = 1;
272 return -1;
273 }
274
275 /* replace ALL_TYPES with the real TYPE_* */
276 if (type > 0 && type != *socket_type)
277 *socket_type = type;
278 return fd;
279 }
280
281 static int inet_socket(const char *servername, const char *port, int *socket_type)
282 {
283 int fd, errcode, i, type = -1;
284 struct addrinfo hints, *res;
285 const char *p = port;
286
287 for (i = 2; i; i--) {
288 memset(&hints, 0, sizeof(hints));
289 if (i == 2 && *socket_type & TYPE_UDP) {
290 hints.ai_socktype = SOCK_DGRAM;
291 type = TYPE_UDP;
292 if (port == NULL)
293 p = "syslog";
294 }
295 if (i == 1 && *socket_type & TYPE_TCP) {
296 hints.ai_socktype = SOCK_STREAM;
297 type = TYPE_TCP;
298 if (port == NULL)
299 p = "syslog-conn";
300 }
301 if (hints.ai_socktype == 0)
302 continue;
303 hints.ai_family = AF_UNSPEC;
304 errcode = getaddrinfo(servername, p, &hints, &res);
305 if (errcode != 0)
306 errx(EXIT_FAILURE, _("failed to resolve name %s port %s: %s"),
307 servername, p, gai_strerror(errcode));
308 if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
309 freeaddrinfo(res);
310 continue;
311 }
312 if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
313 freeaddrinfo(res);
314 close(fd);
315 continue;
316 }
317
318 freeaddrinfo(res);
319 break;
320 }
321
322 if (i == 0)
323 errx(EXIT_FAILURE, _("failed to connect to %s port %s"), servername, p);
324
325 /* replace ALL_TYPES with the real TYPE_* */
326 if (type > 0 && type != *socket_type)
327 *socket_type = type;
328 return fd;
329 }
330
331 #ifdef HAVE_LIBSYSTEMD
332 static int journald_entry(struct logger_ctl *ctl, FILE *fp)
333 {
334 struct iovec *iovec;
335 char *buf = NULL;
336 ssize_t sz;
337 int n, lines, vectors = 8, ret = 0;
338 size_t dummy = 0;
339
340 iovec = xmalloc(vectors * sizeof(struct iovec));
341 for (lines = 0; /* nothing */ ; lines++) {
342 buf = NULL;
343 sz = getline(&buf, &dummy, fp);
344 if (sz == -1 ||
345 (sz = rtrim_whitespace((unsigned char *) buf)) == 0) {
346 free(buf);
347 break;
348 }
349 if (lines == vectors) {
350 vectors *= 2;
351 if (IOV_MAX < vectors)
352 errx(EXIT_FAILURE, _("maximum input lines (%d) exceeded"), IOV_MAX);
353 iovec = xrealloc(iovec, vectors * sizeof(struct iovec));
354 }
355 iovec[lines].iov_base = buf;
356 iovec[lines].iov_len = sz;
357 }
358
359 if (!ctl->noact)
360 ret = sd_journal_sendv(iovec, lines);
361 if (ctl->stderr_printout) {
362 for (n = 0; n < lines; n++)
363 fprintf(stderr, "%s\n", (char *) iovec[n].iov_base);
364 }
365 for (n = 0; n < lines; n++)
366 free(iovec[n].iov_base);
367 free(iovec);
368 return ret;
369 }
370 #endif
371
372 static char const *xgetlogin(void)
373 {
374 char const *cp;
375 struct passwd *pw;
376
377 if (!(cp = getlogin()) || !*cp)
378 cp = (pw = getpwuid(geteuid()))? pw->pw_name : "<someone>";
379 return cp;
380 }
381
382 /* this creates a timestamp based on current time according to the
383 * fine rules of RFC3164, most importantly it ensures in a portable
384 * way that the month day is correctly written (with a SP instead
385 * of a leading 0). The function uses a static buffer which is
386 * overwritten on the next call (just like ctime() does).
387 */
388 static char const *rfc3164_current_time(void)
389 {
390 static char time[32];
391 struct timeval tv;
392 struct tm *tm;
393 static char const * const monthnames[] = {
394 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
395 "Sep", "Oct", "Nov", "Dec"
396 };
397
398 logger_gettimeofday(&tv, NULL);
399 tm = localtime(&tv.tv_sec);
400 snprintf(time, sizeof(time),"%s %2d %2.2d:%2.2d:%2.2d",
401 monthnames[tm->tm_mon], tm->tm_mday,
402 tm->tm_hour, tm->tm_min, tm->tm_sec);
403 return time;
404 }
405
406 #define next_iovec(ary, idx) __extension__ ({ \
407 assert(ARRAY_SIZE(ary) > (size_t)idx); \
408 assert(idx >= 0); \
409 &ary[idx++]; \
410 })
411
412 #define iovec_add_string(ary, idx, str, len) \
413 do { \
414 struct iovec *v = next_iovec(ary, idx); \
415 v->iov_base = (void *) str; \
416 v->iov_len = len ? len : strlen(str); \
417 } while (0)
418
419 #define iovec_memcmp(ary, idx, str, len) \
420 memcmp((ary)[(idx) - 1].iov_base, str, len)
421
422 /* writes generated buffer to desired destination. For TCP syslog,
423 * we use RFC6587 octet-stuffing (unless octet-counting is selected).
424 * This is not great, but doing full blown RFC5425 (TLS) looks like
425 * it is too much for the logger utility. If octet-counting is
426 * selected, we use that.
427 */
428 static void write_output(const struct logger_ctl *ctl, const char *const msg)
429 {
430 struct iovec iov[4];
431 int iovlen = 0;
432 char *octet = NULL;
433
434 /* 1) octen count */
435 if (ctl->octet_count) {
436 size_t len = xasprintf(&octet, "%zu ", strlen(ctl->hdr) + strlen(msg));
437 iovec_add_string(iov, iovlen, octet, len);
438 }
439
440 /* 2) header */
441 iovec_add_string(iov, iovlen, ctl->hdr, 0);
442
443 /* 3) message */
444 iovec_add_string(iov, iovlen, msg, 0);
445
446 if (!ctl->noact) {
447 struct msghdr message = { 0 };
448 #ifdef SCM_CREDENTIALS
449 struct cmsghdr *cmhp;
450 struct ucred *cred;
451 union {
452 struct cmsghdr cmh;
453 char control[CMSG_SPACE(sizeof(struct ucred))];
454 } cbuf;
455 #endif
456
457 /* 4) add extra \n to make sure message is terminated */
458 if ((ctl->socket_type == TYPE_TCP) && !ctl->octet_count)
459 iovec_add_string(iov, iovlen, "\n", 1);
460
461 message.msg_iov = iov;
462 message.msg_iovlen = iovlen;
463
464 #ifdef SCM_CREDENTIALS
465 /* syslog/journald may follow local socket credentials rather
466 * than in the message PID. If we use --id as root than we can
467 * force kernel to accept another valid PID than the real logger(1)
468 * PID.
469 */
470 if (ctl->pid && !ctl->server && ctl->pid != getpid()
471 && geteuid() == 0 && kill(ctl->pid, 0) == 0) {
472
473 message.msg_control = cbuf.control;
474 message.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
475
476 cmhp = CMSG_FIRSTHDR(&message);
477 cmhp->cmsg_len = CMSG_LEN(sizeof(struct ucred));
478 cmhp->cmsg_level = SOL_SOCKET;
479 cmhp->cmsg_type = SCM_CREDENTIALS;
480 cred = (struct ucred *) CMSG_DATA(cmhp);
481
482 cred->pid = ctl->pid;
483 }
484 #endif
485
486 if (sendmsg(ctl->fd, &message, 0) < 0)
487 warn(_("send message failed"));
488 }
489
490 if (ctl->stderr_printout) {
491 /* make sure it's terminated for stderr */
492 if (iovec_memcmp(iov, iovlen, "\n", 1) != 0)
493 iovec_add_string(iov, iovlen, "\n", 1);
494
495 ignore_result( writev(STDERR_FILENO, iov, iovlen) );
496 }
497
498 free(octet);
499 }
500
501 #define NILVALUE "-"
502 static void syslog_rfc3164_header(struct logger_ctl *const ctl)
503 {
504 char pid[30], *hostname;
505
506 *pid = '\0';
507 if (ctl->fd < 0)
508 return;
509 if (ctl->pid)
510 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
511
512 if ((hostname = logger_xgethostname())) {
513 char *dot = strchr(hostname, '.');
514 if (dot)
515 *dot = '\0';
516 } else
517 hostname = xstrdup(NILVALUE);
518
519 xasprintf(&ctl->hdr, "<%d>%.15s %s %.200s%s: ",
520 ctl->pri, rfc3164_current_time(), hostname, ctl->tag, pid);
521
522 free(hostname);
523 }
524
525 static inline struct list_head *get_user_structured_data(struct logger_ctl *ctl)
526 {
527 return &ctl->user_sds;
528 }
529
530 static inline struct list_head *get_reserved_structured_data(struct logger_ctl *ctl)
531 {
532 return &ctl->reserved_sds;
533 }
534
535 static int has_structured_data_id(struct list_head *ls, const char *id)
536 {
537 struct list_head *p;
538
539 if (!ls || list_empty(ls))
540 return 0;
541
542 list_for_each(p, ls) {
543 struct structured_data *sd = list_entry(p, struct structured_data, sds);
544 if (sd->id && strcmp(sd->id, id) == 0)
545 return 1;
546 }
547
548 return 0;
549 }
550
551 static void add_structured_data_id(struct list_head *ls, const char *id)
552 {
553 struct structured_data *sd;
554
555 assert(id);
556
557 if (has_structured_data_id(ls, id))
558 errx(EXIT_FAILURE, _("structured data ID '%s' is not unique"), id);
559
560 sd = xcalloc(1, sizeof(*sd));
561 INIT_LIST_HEAD(&sd->sds);
562 sd->id = xstrdup(id);
563
564 list_add_tail(&sd->sds, ls);
565 }
566
567 static void add_structured_data_param(struct list_head *ls, const char *param)
568 {
569 struct structured_data *sd;
570
571 if (list_empty(ls))
572 errx(EXIT_FAILURE, _("--sd-id was not specified for --sd-param %s"), param);
573
574 assert(param);
575
576 sd = list_last_entry(ls, struct structured_data, sds);
577
578 if (strv_extend(&sd->params, param))
579 err_oom();
580 }
581
582 static void add_structured_data_paramf(struct list_head *ls, const char *fmt, ...)
583 {
584 struct structured_data *sd;
585 va_list ap;
586 int x;
587
588 assert(!list_empty(ls));
589 assert(fmt);
590
591 sd = list_last_entry(ls, struct structured_data, sds);
592 va_start(ap, fmt);
593 x = strv_extendv(&sd->params, fmt, ap);
594 va_end(ap);
595
596 if (x)
597 err_oom();
598 }
599
600 static char *strdup_structured_data(struct structured_data *sd)
601 {
602 char *res, *tmp;
603
604 if (strv_isempty(sd->params))
605 return NULL;
606
607 xasprintf(&res, "[%s %s]", sd->id,
608 (tmp = strv_join(sd->params, " ")));
609 free(tmp);
610 return res;
611 }
612
613 static char *strdup_structured_data_list(struct list_head *ls)
614 {
615 struct list_head *p;
616 char *res = NULL;
617
618 list_for_each(p, ls) {
619 struct structured_data *sd = list_entry(p, struct structured_data, sds);
620 char *one = strdup_structured_data(sd);
621 char *tmp = res;
622
623 if (!one)
624 continue;
625 res = strappend(tmp, one);
626 free(tmp);
627 free(one);
628 }
629
630 return res;
631 }
632
633 static char *get_structured_data_string(struct logger_ctl *ctl)
634 {
635 char *sys = NULL, *usr = NULL, *res;
636
637 if (!list_empty(&ctl->reserved_sds))
638 sys = strdup_structured_data_list(&ctl->reserved_sds);
639 if (!list_empty(&ctl->user_sds))
640 usr = strdup_structured_data_list(&ctl->user_sds);
641
642 if (sys && usr) {
643 res = strappend(sys, usr);
644 free(sys);
645 free(usr);
646 } else
647 res = sys ? sys : usr;
648
649 return res;
650 }
651
652 static int valid_structured_data_param(const char *str)
653 {
654 char *eq = strchr(str, '='),
655 *qm1 = strchr(str, '"'),
656 *qm2 = qm1 ? strchr(qm1 + 1, '"') : NULL;
657
658 if (!eq || !qm1 || !qm2) /* something is missing */
659 return 0;
660
661 /* foo="bar" */
662 return eq > str && eq < qm1 && eq + 1 == qm1 && qm1 < qm2 && *(qm2 + 1) == '\0';
663 }
664
665 /* SD-ID format:
666 * name@<private enterprise number>, e.g., "ourSDID@32473"
667 */
668 static int valid_structured_data_id(const char *str)
669 {
670 char *at = strchr(str, '@');
671 const char *p;
672
673 /* standardized IDs without @<digits> */
674 if (!at && (strcmp(str, "timeQuality") == 0 ||
675 strcmp(str, "origin") == 0 ||
676 strcmp(str, "meta") == 0))
677 return 1;
678
679 if (!at || at == str || !*(at + 1))
680 return 0;
681
682 /* <digits> or <digits>.<digits>[...] */
683 for (p = at + 1; p && *p; p++) {
684 const char *end;
685
686 if (isdigit_strend(p, &end))
687 break; /* only digits in the string */
688
689 if (end == NULL || end == p ||
690 *end != '.' || *(end + 1) == '\0')
691 return 0;
692 p = end;
693 }
694
695 /* check for forbidden chars in the <name> */
696 for (p = str; p < at; p++) {
697 if (*p == '[' || *p == '=' || *p == '"' || *p == '@')
698 return 0;
699 if (isblank((unsigned char) *p) || iscntrl((unsigned char) *p))
700 return 0;
701 }
702 return 1;
703 }
704
705
706 /* Some field mappings may be controversial, thus I give the reason
707 * why this specific mapping was used:
708 * APP-NAME <-- tag
709 * Some may argue that "logger" is a better fit, but we think
710 * this is better inline of what other implementations do. In
711 * rsyslog, for example, the TAG value is populated from APP-NAME.
712 * PROCID <-- pid
713 * This is a relatively straightforward interpretation from
714 * RFC5424, sect. 6.2.6.
715 * MSGID <-- msgid (from --msgid)
716 * One may argue that the string "logger" would be better suited
717 * here so that a receiver can identify the sender process.
718 * However, this does not sound like a good match to RFC5424,
719 * sect. 6.2.7.
720 * Note that appendix A.1 of RFC5424 does not provide clear guidance
721 * of how these fields should be used. This is the case because the
722 * IETF working group couldn't arrive at a clear agreement when we
723 * specified RFC5424. The rest of the field mappings should be
724 * pretty clear from RFC5424. -- Rainer Gerhards, 2015-03-10
725 */
726 static void syslog_rfc5424_header(struct logger_ctl *const ctl)
727 {
728 char *time;
729 char *hostname;
730 char const *app_name = ctl->tag;
731 char *procid;
732 char *const msgid = xstrdup(ctl->msgid ? ctl->msgid : NILVALUE);
733 char *structured = NULL;
734 struct list_head *sd;
735
736 if (ctl->fd < 0)
737 return;
738
739 if (ctl->rfc5424_time) {
740 struct timeval tv;
741 struct tm *tm;
742
743 logger_gettimeofday(&tv, NULL);
744 if ((tm = localtime(&tv.tv_sec)) != NULL) {
745 char fmt[64];
746 const size_t i = strftime(fmt, sizeof(fmt),
747 "%Y-%m-%dT%H:%M:%S.%%06u%z ", tm);
748 /* patch TZ info to comply with RFC3339 (we left SP at end) */
749 fmt[i - 1] = fmt[i - 2];
750 fmt[i - 2] = fmt[i - 3];
751 fmt[i - 3] = ':';
752 xasprintf(&time, fmt, tv.tv_usec);
753 } else
754 err(EXIT_FAILURE, _("localtime() failed"));
755 } else
756 time = xstrdup(NILVALUE);
757
758 if (ctl->rfc5424_host) {
759 if (!(hostname = logger_xgethostname()))
760 hostname = xstrdup(NILVALUE);
761 /* Arbitrary looking 'if (var < strlen()) checks originate from
762 * RFC 5424 - 6 Syslog Message Format definition. */
763 if (255 < strlen(hostname))
764 errx(EXIT_FAILURE, _("hostname '%s' is too long"),
765 hostname);
766 } else
767 hostname = xstrdup(NILVALUE);
768
769 if (48 < strlen(ctl->tag))
770 errx(EXIT_FAILURE, _("tag '%s' is too long"), ctl->tag);
771
772 if (ctl->pid)
773 xasprintf(&procid, "%d", ctl->pid);
774 else
775 procid = xstrdup(NILVALUE);
776
777 sd = get_reserved_structured_data(ctl);
778
779 /* time quality structured data (maybe overwritten by --sd-id timeQuality) */
780 if (ctl->rfc5424_tq && !has_structured_data_id(sd, "timeQuality")) {
781
782 add_structured_data_id(sd, "timeQuality");
783 add_structured_data_param(sd, "tzKnown=\"1\"");
784
785 #ifdef HAVE_NTP_GETTIME
786 struct ntptimeval ntptv;
787
788 if (ntp_gettime(&ntptv) == TIME_OK) {
789 add_structured_data_param(sd, "isSynced=\"1\"");
790 add_structured_data_paramf(sd, "syncAccuracy=\"%ld\"", ntptv.maxerror);
791 } else
792 #endif
793 add_structured_data_paramf(sd, "isSynced=\"0\"");
794 }
795
796 /* convert all structured data to string */
797 structured = get_structured_data_string(ctl);
798 if (!structured)
799 structured = xstrdup(NILVALUE);
800
801 xasprintf(&ctl->hdr, "<%d>1 %s %s %s %s %s %s ",
802 ctl->pri,
803 time,
804 hostname,
805 app_name,
806 procid,
807 msgid,
808 structured);
809
810 free(time);
811 free(hostname);
812 /* app_name points to ctl->tag, do NOT free! */
813 free(procid);
814 free(msgid);
815 free(structured);
816 }
817
818 static void parse_rfc5424_flags(struct logger_ctl *ctl, char *s)
819 {
820 char *in, *tok;
821
822 in = s;
823 while ((tok = strtok(in, ","))) {
824 in = NULL;
825 if (!strcmp(tok, "notime")) {
826 ctl->rfc5424_time = 0;
827 ctl->rfc5424_tq = 0;
828 } else if (!strcmp(tok, "notq"))
829 ctl->rfc5424_tq = 0;
830 else if (!strcmp(tok, "nohost"))
831 ctl->rfc5424_host = 0;
832 else
833 warnx(_("ignoring unknown option argument: %s"), tok);
834 }
835 }
836
837 static int parse_unix_socket_errors_flags(char *s)
838 {
839 if (!strcmp(s, "off"))
840 return AF_UNIX_ERRORS_OFF;
841 if (!strcmp(s, "on"))
842 return AF_UNIX_ERRORS_ON;
843 if (!strcmp(s, "auto"))
844 return AF_UNIX_ERRORS_AUTO;
845 warnx(_("invalid argument: %s: using automatic errors"), s);
846 return AF_UNIX_ERRORS_AUTO;
847 }
848
849 static void syslog_local_header(struct logger_ctl *const ctl)
850 {
851 char pid[32];
852
853 if (ctl->pid)
854 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
855 else
856 pid[0] = '\0';
857
858 xasprintf(&ctl->hdr, "<%d>%s %s%s: ", ctl->pri, rfc3164_current_time(),
859 ctl->tag, pid);
860 }
861
862 static void generate_syslog_header(struct logger_ctl *const ctl)
863 {
864 free(ctl->hdr);
865 ctl->syslogfp(ctl);
866 }
867
868 static void logger_open(struct logger_ctl *ctl)
869 {
870 if (ctl->server) {
871 ctl->fd = inet_socket(ctl->server, ctl->port, &ctl->socket_type);
872 if (!ctl->syslogfp)
873 ctl->syslogfp = syslog_rfc5424_header;
874 } else {
875 if (!ctl->unix_socket)
876 ctl->unix_socket = _PATH_DEVLOG;
877
878 ctl->fd = unix_socket(ctl, ctl->unix_socket, &ctl->socket_type);
879 if (!ctl->syslogfp)
880 ctl->syslogfp = syslog_local_header;
881 }
882 if (!ctl->tag)
883 ctl->tag = xgetlogin();
884 generate_syslog_header(ctl);
885 }
886
887 static void logger_command_line(const struct logger_ctl *ctl, char **argv)
888 {
889 /* note: we never re-generate the syslog header here, even if we
890 * generate multiple messages. If so, we think it is the right thing
891 * to do to report them with the same timestamp, as the user actually
892 * intended to send a single message.
893 */
894 char *const buf = xmalloc(ctl->max_message_size + 1);
895 char *p = buf;
896 const char *endp = buf + ctl->max_message_size - 1;
897 size_t len;
898
899 while (*argv) {
900 len = strlen(*argv);
901 if (endp < p + len && p != buf) {
902 write_output(ctl, buf);
903 p = buf;
904 }
905 if (ctl->max_message_size < len) {
906 (*argv)[ctl->max_message_size] = '\0'; /* truncate */
907 write_output(ctl, *argv++);
908 continue;
909 }
910 if (p != buf)
911 *p++ = ' ';
912 memmove(p, *argv++, len);
913 *(p += len) = '\0';
914 }
915 if (p != buf)
916 write_output(ctl, buf);
917 free(buf);
918 }
919
920 static void logger_stdin(struct logger_ctl *ctl)
921 {
922 /* note: we re-generate the syslog header for each log message to
923 * update header timestamps and to reflect possible priority changes.
924 * The initial header is generated by logger_open().
925 */
926 int has_header = 1;
927 int default_priority = ctl->pri;
928 int last_pri = default_priority;
929 size_t max_usrmsg_size = ctl->max_message_size - strlen(ctl->hdr);
930 char *const buf = xmalloc(max_usrmsg_size + 2 + 2);
931 int pri;
932 int c;
933 size_t i;
934
935 c = getchar();
936 while (c != EOF) {
937 i = 0;
938 if (ctl->prio_prefix && c == '<') {
939 pri = 0;
940 buf[i++] = c;
941 while (isdigit(c = getchar()) && pri <= 191) {
942 buf[i++] = c;
943 pri = pri * 10 + c - '0';
944 }
945 if (c != EOF && c != '\n')
946 buf[i++] = c;
947 if (c == '>' && 0 <= pri && pri <= 191) {
948 /* valid RFC PRI values */
949 i = 0;
950 if (pri < 8) /* kern facility is forbidden */
951 pri |= 8;
952 ctl->pri = pri;
953 } else
954 ctl->pri = default_priority;
955
956 if (ctl->pri != last_pri) {
957 has_header = 0;
958 max_usrmsg_size =
959 ctl->max_message_size - strlen(ctl->hdr);
960 last_pri = ctl->pri;
961 }
962 if (c != EOF && c != '\n')
963 c = getchar();
964 }
965
966 while (c != EOF && c != '\n' && i < max_usrmsg_size) {
967 buf[i++] = c;
968 c = getchar();
969 }
970 buf[i] = '\0';
971
972 if (i > 0 || !ctl->skip_empty_lines) {
973 if (!has_header)
974 generate_syslog_header(ctl);
975 write_output(ctl, buf);
976 has_header = 0;
977 }
978
979 if (c == '\n') /* discard line terminator */
980 c = getchar();
981 }
982 }
983
984 static void logger_close(const struct logger_ctl *ctl)
985 {
986 if (ctl->fd != -1 && close(ctl->fd) != 0)
987 err(EXIT_FAILURE, _("close failed"));
988 free(ctl->hdr);
989 }
990
991 static void __attribute__((__noreturn__)) usage(void)
992 {
993 FILE *out = stdout;
994 fputs(USAGE_HEADER, out);
995 fprintf(out, _(" %s [options] [<message>]\n"), program_invocation_short_name);
996
997 fputs(USAGE_SEPARATOR, out);
998 fputs(_("Enter messages into the system log.\n"), out);
999
1000 fputs(USAGE_OPTIONS, out);
1001 fputs(_(" -i log the logger command's PID\n"), out);
1002 fputs(_(" --id[=<id>] log the given <id>, or otherwise the PID\n"), out);
1003 fputs(_(" -f, --file <file> log the contents of this file\n"), out);
1004 fputs(_(" -e, --skip-empty do not log empty lines when processing files\n"), out);
1005 fputs(_(" --no-act do everything except the write the log\n"), out);
1006 fputs(_(" -p, --priority <prio> mark given message with this priority\n"), out);
1007 fputs(_(" --octet-count use rfc6587 octet counting\n"), out);
1008 fputs(_(" --prio-prefix look for a prefix on every line read from stdin\n"), out);
1009 fputs(_(" -s, --stderr output message to standard error as well\n"), out);
1010 fputs(_(" -S, --size <size> maximum size for a single message\n"), out);
1011 fputs(_(" -t, --tag <tag> mark every line with this tag\n"), out);
1012 fputs(_(" -n, --server <name> write to this remote syslog server\n"), out);
1013 fputs(_(" -P, --port <port> use this port for UDP or TCP connection\n"), out);
1014 fputs(_(" -T, --tcp use TCP only\n"), out);
1015 fputs(_(" -d, --udp use UDP only\n"), out);
1016 fputs(_(" --rfc3164 use the obsolete BSD syslog protocol\n"), out);
1017 fputs(_(" --rfc5424[=<snip>] use the syslog protocol (the default for remote);\n"
1018 " <snip> can be notime, or notq, and/or nohost\n"), out);
1019 fputs(_(" --sd-id <id> rfc5424 structured data ID\n"), out);
1020 fputs(_(" --sd-param <data> rfc5424 structured data name=value\n"), out);
1021 fputs(_(" --msgid <msgid> set rfc5424 message id field\n"), out);
1022 fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out);
1023 fputs(_(" --socket-errors[=<on|off|auto>]\n"
1024 " print connection errors when using Unix sockets\n"), out);
1025 #ifdef HAVE_LIBSYSTEMD
1026 fputs(_(" --journald[=<file>] write journald entry\n"), out);
1027 #endif
1028
1029 fputs(USAGE_SEPARATOR, out);
1030 printf(USAGE_HELP_OPTIONS(26));
1031 printf(USAGE_MAN_TAIL("logger(1)"));
1032
1033 exit(EXIT_SUCCESS);
1034 }
1035
1036 /*
1037 * logger -- read and log utility
1038 *
1039 * Reads from an input and arranges to write the result on the system
1040 * log.
1041 */
1042 int main(int argc, char **argv)
1043 {
1044 struct logger_ctl ctl = {
1045 .fd = -1,
1046 .pid = 0,
1047 .pri = LOG_USER | LOG_NOTICE,
1048 .prio_prefix = 0,
1049 .tag = NULL,
1050 .unix_socket = NULL,
1051 .unix_socket_errors = 0,
1052 .server = NULL,
1053 .port = NULL,
1054 .hdr = NULL,
1055 .msgid = NULL,
1056 .socket_type = ALL_TYPES,
1057 .max_message_size = 1024,
1058 .rfc5424_time = 1,
1059 .rfc5424_tq = 1,
1060 .rfc5424_host = 1,
1061 .skip_empty_lines = 0
1062 };
1063 int ch;
1064 int stdout_reopened = 0;
1065 int unix_socket_errors_mode = AF_UNIX_ERRORS_AUTO;
1066 #ifdef HAVE_LIBSYSTEMD
1067 FILE *jfd = NULL;
1068 #endif
1069 static const struct option longopts[] = {
1070 { "id", optional_argument, 0, OPT_ID },
1071 { "stderr", no_argument, 0, 's' },
1072 { "file", required_argument, 0, 'f' },
1073 { "no-act", no_argument, 0, OPT_NOACT, },
1074 { "priority", required_argument, 0, 'p' },
1075 { "tag", required_argument, 0, 't' },
1076 { "socket", required_argument, 0, 'u' },
1077 { "socket-errors", required_argument, 0, OPT_SOCKET_ERRORS },
1078 { "udp", no_argument, 0, 'd' },
1079 { "tcp", no_argument, 0, 'T' },
1080 { "server", required_argument, 0, 'n' },
1081 { "port", required_argument, 0, 'P' },
1082 { "version", no_argument, 0, 'V' },
1083 { "help", no_argument, 0, 'h' },
1084 { "octet-count", no_argument, 0, OPT_OCTET_COUNT },
1085 { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX },
1086 { "rfc3164", no_argument, 0, OPT_RFC3164 },
1087 { "rfc5424", optional_argument, 0, OPT_RFC5424 },
1088 { "size", required_argument, 0, 'S' },
1089 { "msgid", required_argument, 0, OPT_MSGID },
1090 { "skip-empty", no_argument, 0, 'e' },
1091 { "sd-id", required_argument, 0, OPT_STRUCTURED_DATA_ID },
1092 { "sd-param", required_argument, 0, OPT_STRUCTURED_DATA_PARAM },
1093 #ifdef HAVE_LIBSYSTEMD
1094 { "journald", optional_argument, 0, OPT_JOURNALD },
1095 #endif
1096 { NULL, 0, 0, 0 }
1097 };
1098
1099 setlocale(LC_ALL, "");
1100 bindtextdomain(PACKAGE, LOCALEDIR);
1101 textdomain(PACKAGE);
1102 atexit(close_stdout);
1103
1104 INIT_LIST_HEAD(&ctl.user_sds);
1105 INIT_LIST_HEAD(&ctl.reserved_sds);
1106
1107 while ((ch = getopt_long(argc, argv, "ef:ip:S:st:u:dTn:P:Vh",
1108 longopts, NULL)) != -1) {
1109 switch (ch) {
1110 case 'f': /* file to log */
1111 if (freopen(optarg, "r", stdin) == NULL)
1112 err(EXIT_FAILURE, _("file %s"), optarg);
1113 stdout_reopened = 1;
1114 break;
1115 case 'e':
1116 ctl.skip_empty_lines = 1;
1117 break;
1118 case 'i': /* log process id also */
1119 ctl.pid = logger_getpid();
1120 break;
1121 case OPT_ID:
1122 if (optarg) {
1123 const char *p = optarg;
1124
1125 if (*p == '=')
1126 p++;
1127 ctl.pid = strtoul_or_err(optarg, _("failed to parse id"));
1128 } else
1129 ctl.pid = logger_getpid();
1130 break;
1131 case 'p': /* priority */
1132 ctl.pri = pencode(optarg);
1133 break;
1134 case 's': /* log to standard error */
1135 ctl.stderr_printout = 1;
1136 break;
1137 case 't': /* tag */
1138 ctl.tag = optarg;
1139 break;
1140 case 'u': /* unix socket */
1141 ctl.unix_socket = optarg;
1142 break;
1143 case 'S': /* max message size */
1144 ctl.max_message_size = strtosize_or_err(optarg,
1145 _("failed to parse message size"));
1146 break;
1147 case 'd':
1148 ctl.socket_type = TYPE_UDP;
1149 break;
1150 case 'T':
1151 ctl.socket_type = TYPE_TCP;
1152 break;
1153 case 'n':
1154 ctl.server = optarg;
1155 break;
1156 case 'P':
1157 ctl.port = optarg;
1158 break;
1159 case 'V':
1160 printf(UTIL_LINUX_VERSION);
1161 exit(EXIT_SUCCESS);
1162 case 'h':
1163 usage();
1164 case OPT_OCTET_COUNT:
1165 ctl.octet_count = 1;
1166 break;
1167 case OPT_PRIO_PREFIX:
1168 ctl.prio_prefix = 1;
1169 break;
1170 case OPT_RFC3164:
1171 ctl.syslogfp = syslog_rfc3164_header;
1172 break;
1173 case OPT_RFC5424:
1174 ctl.syslogfp = syslog_rfc5424_header;
1175 if (optarg)
1176 parse_rfc5424_flags(&ctl, optarg);
1177 break;
1178 case OPT_MSGID:
1179 if (strchr(optarg, ' '))
1180 errx(EXIT_FAILURE, _("--msgid cannot contain space"));
1181 ctl.msgid = optarg;
1182 break;
1183 #ifdef HAVE_LIBSYSTEMD
1184 case OPT_JOURNALD:
1185 if (optarg) {
1186 jfd = fopen(optarg, "r");
1187 if (!jfd)
1188 err(EXIT_FAILURE, _("cannot open %s"),
1189 optarg);
1190 } else
1191 jfd = stdin;
1192 break;
1193 #endif
1194 case OPT_SOCKET_ERRORS:
1195 unix_socket_errors_mode = parse_unix_socket_errors_flags(optarg);
1196 break;
1197 case OPT_NOACT:
1198 ctl.noact = 1;
1199 break;
1200 case OPT_STRUCTURED_DATA_ID:
1201 if (!valid_structured_data_id(optarg))
1202 errx(EXIT_FAILURE, _("invalid structured data ID: '%s'"), optarg);
1203 add_structured_data_id(get_user_structured_data(&ctl), optarg);
1204 break;
1205 case OPT_STRUCTURED_DATA_PARAM:
1206 if (!valid_structured_data_param(optarg))
1207 errx(EXIT_FAILURE, _("invalid structured data parameter: '%s'"), optarg);
1208 add_structured_data_param(get_user_structured_data(&ctl), optarg);
1209 break;
1210 default:
1211 errtryhelp(EXIT_FAILURE);
1212 }
1213 }
1214 argc -= optind;
1215 argv += optind;
1216 if (stdout_reopened && argc)
1217 warnx(_("--file <file> and <message> are mutually exclusive, message is ignored"));
1218 #ifdef HAVE_LIBSYSTEMD
1219 if (jfd) {
1220 int ret = journald_entry(&ctl, jfd);
1221 if (stdin != jfd)
1222 fclose(jfd);
1223 if (ret)
1224 errx(EXIT_FAILURE, _("journald entry could not be written"));
1225 return EXIT_SUCCESS;
1226 }
1227 #endif
1228
1229 /* user overwrites build-in SD-ELEMENT */
1230 if (has_structured_data_id(get_user_structured_data(&ctl), "timeQuality"))
1231 ctl.rfc5424_tq = 0;
1232
1233 switch (unix_socket_errors_mode) {
1234 case AF_UNIX_ERRORS_OFF:
1235 ctl.unix_socket_errors = 0;
1236 break;
1237 case AF_UNIX_ERRORS_ON:
1238 ctl.unix_socket_errors = 1;
1239 break;
1240 case AF_UNIX_ERRORS_AUTO:
1241 ctl.unix_socket_errors = ctl.noact || ctl.stderr_printout;
1242 #ifdef HAVE_LIBSYSTEMD
1243 ctl.unix_socket_errors |= !!sd_booted();
1244 #endif
1245 break;
1246 default:
1247 abort();
1248 }
1249 logger_open(&ctl);
1250 if (0 < argc)
1251 logger_command_line(&ctl, argv);
1252 else
1253 /* Note. --file <arg> reopens stdin making the below
1254 * function to be used for file inputs. */
1255 logger_stdin(&ctl);
1256 logger_close(&ctl);
1257 return EXIT_SUCCESS;
1258 }