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