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