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