Merge branch 'master' into dev
This commit is contained in:
commit
f0b7b6fdf8
46
man/logger.1
46
man/logger.1
@ -33,11 +33,15 @@
|
||||
.Nd Send messages to system log, or a log file
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl chiknsv
|
||||
.Op Fl 46bchiknsv
|
||||
.Op Fl d Ar SD
|
||||
.Op Fl f Ar FILE
|
||||
.Op Fl h Ar HOST
|
||||
.Op Fl H Ar HOSTNAME
|
||||
.Op Fl I Ar PID
|
||||
.Op Fl m Ar MSGID
|
||||
.Op Fl p Ar PRIO
|
||||
.Op Fl P Ar PORT
|
||||
.Op Fl r Ar SIZE:NUM
|
||||
.Op Fl t Ar TAG
|
||||
.Op Fl u Ar SOCK
|
||||
@ -61,6 +65,16 @@ reads input from
|
||||
.Sh OPTIONS
|
||||
This program follows the usual UNIX command line syntax:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 4
|
||||
Force
|
||||
.Nm
|
||||
to use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Force
|
||||
.Nm
|
||||
to use IPv6 addresses only.
|
||||
.It Fl b
|
||||
Use RFC3164 (BSD) style format, default: RFC5424.
|
||||
.It Fl c
|
||||
Log to console
|
||||
.Ql ( LOG_CONS )
|
||||
@ -83,6 +97,25 @@ accepts
|
||||
.Fl f-
|
||||
as an alias for
|
||||
.Ar stdout .
|
||||
.It Fl H Ar hostname
|
||||
Set the hostname in the header of the message to specified value.
|
||||
If not specified, host part of
|
||||
.Xr gethostname 3
|
||||
will be used.
|
||||
.It Fl h Ar host
|
||||
Send the message to the remote system
|
||||
.Ar host
|
||||
instead of logging it locally.
|
||||
.It Fl I Ar PID
|
||||
Like
|
||||
.Fl i ,
|
||||
but uses
|
||||
.Ar PID .
|
||||
Useful when logging from shell scripts that send multiple messages.
|
||||
E.g., the following arguments might be a useful template:
|
||||
.Bd -literal -offset indent
|
||||
logger -t $(basename $0) -I $$
|
||||
.Ed
|
||||
.It Fl i
|
||||
Log the process id of the logger process with each line
|
||||
.Ql ( LOG_PID ) .
|
||||
@ -112,6 +145,17 @@ or sending remote in correctly formatted RFC5424 style.
|
||||
.It Fl n
|
||||
Open log file immediately
|
||||
.Ql ( LOG_NDELAY ) .
|
||||
.It Fl P Ar port
|
||||
Send the message to the specified
|
||||
.Ar port
|
||||
number on a remote system,
|
||||
which can be specified as a service name
|
||||
or as a decimal number.
|
||||
The default is
|
||||
.Dq Li syslog .
|
||||
If an unknown service name is used,
|
||||
.Nm
|
||||
prints a warning and falls back to port 514.
|
||||
.It Fl p Ar PRIO
|
||||
Priority, numeric or
|
||||
.Ar facility.severity
|
||||
|
100
src/logger.c
100
src/logger.c
@ -35,11 +35,14 @@
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define SYSLOG_NAMES
|
||||
#include "compat.h"
|
||||
@ -61,8 +64,8 @@ static int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
*/
|
||||
static int logrotate(char *file, int num, off_t sz)
|
||||
{
|
||||
int cnt;
|
||||
struct stat st;
|
||||
int cnt;
|
||||
|
||||
if (stat(file, &st))
|
||||
return 1;
|
||||
@ -122,6 +125,39 @@ static void log_kmsg(FILE *fp, char *ident, int pri, int opts, char *buf)
|
||||
fprintf(fp, "<%d>%s[%d]:%s\n", pri, ident, getpid(), buf);
|
||||
}
|
||||
|
||||
static int nslookup(const char *host, const char *svcname, int family, struct sockaddr *sa)
|
||||
{
|
||||
struct addrinfo hints, *ai, *result;
|
||||
int error;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = !host ? AI_PASSIVE : 0;
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
error = getaddrinfo(host, svcname, &hints, &result);
|
||||
if (error == EAI_SERVICE) {
|
||||
warnx("%s/udp: unknown service, trying syslog port 514", svcname);
|
||||
svcname = "514";
|
||||
error = getaddrinfo(host, svcname, &hints, &result);
|
||||
}
|
||||
if (error) {
|
||||
warnx("%s (%s:%s)", gai_strerror(error), host, svcname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (ai = result; ai; ai = ai->ai_next) {
|
||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
memcpy(sa, ai->ai_addr, ai->ai_addrlen);
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int checksz(FILE *fp, off_t sz)
|
||||
{
|
||||
struct stat st;
|
||||
@ -193,16 +229,23 @@ static int usage(int code)
|
||||
"\n"
|
||||
"Write MESSAGE (or line-by-line stdin) to syslog, or file (with logrotate).\n"
|
||||
"\n"
|
||||
" -4 Prefer IPv4 address when sending remote, see -h\n"
|
||||
" -6 Prefer IPv6 address when sending remote, see -h\n"
|
||||
" -b Use RFC3164 (BSD) style format, default: RFC5424\n"
|
||||
" -c Log to console (LOG_CONS) on failure\n"
|
||||
" -d SD Log SD as RFC5424 style 'structured data' in message\n"
|
||||
" -f FILE Log file to write messages to, instead of syslog daemon\n"
|
||||
" -h HOST Send (UDP) message to this remote syslog server (IP or DNS name)\n"
|
||||
" -H NAME Use NAME instead of system hostname in message header\n"
|
||||
" -i Log process ID of the logger process with each line (LOG_PID)\n"
|
||||
" -I PID Log process ID using PID, recommed using PID $$ for shell scripts\n"
|
||||
#ifdef __linux__
|
||||
" -k Log to kernel /dev/kmsg if /dev/log doesn't exist yet\n"
|
||||
#endif
|
||||
" -m MSGID Log message using this RFC5424 style MSGID\n"
|
||||
" -n Open log file immediately (LOG_NDELAY)\n"
|
||||
" -p PRIO Log message priority (numeric or facility.severity pair)\n"
|
||||
" -P PORT Use PORT (or named UDP service) for remote server, default: syslog\n"
|
||||
" -r S[:R] Enable log file rotation, default: 200 kB \e[4ms\e[0mize, 5 \e[4mr\e[0motations\n"
|
||||
" -s Log to stderr as well as the system log\n"
|
||||
" -t TAG Log using the specified tag (defaults to user name)\n"
|
||||
@ -220,21 +263,36 @@ static int usage(int code)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int c, num = 5;
|
||||
char *ident = NULL, *logfile = NULL;
|
||||
char *host = NULL, *sockpath = NULL;
|
||||
char *msgid = NULL, *sd = NULL;
|
||||
char *svcname = "syslog";
|
||||
off_t size = 200 * 1024;
|
||||
int facility = LOG_USER;
|
||||
int severity = LOG_INFO;
|
||||
int log_opts = 0;
|
||||
int rotate = 0;
|
||||
int family = AF_UNSPEC;
|
||||
struct sockaddr sa;
|
||||
int allow_kmsg = 0;
|
||||
off_t size = 200 * 1024;
|
||||
char *ident = NULL, *logfile = NULL;
|
||||
char *msgid = NULL, *sd = NULL;
|
||||
char *sockpath = NULL;
|
||||
char buf[512] = "";
|
||||
int log_opts = 0;
|
||||
FILE *fp = NULL;
|
||||
int c, num = 5;
|
||||
int rotate = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "?cd:f:ikm:np:r:st:u:v")) != EOF) {
|
||||
while ((c = getopt(argc, argv, "46?bcd:f:h:H:iI:km:np:P:r:st:u:v")) != EOF) {
|
||||
switch (c) {
|
||||
case '4':
|
||||
family = AF_INET;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
family = AF_INET6;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
log_opts |= LOG_RFC3154;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
log_opts |= LOG_CONS;
|
||||
break;
|
||||
@ -247,10 +305,23 @@ int main(int argc, char *argv[])
|
||||
logfile = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
host = optarg;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
strlcpy(log.log_hostname, optarg, sizeof(log.log_hostname));
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
log_opts |= LOG_PID;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
log_opts |= LOG_PID;
|
||||
log.log_pid = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
#ifdef __linux__
|
||||
allow_kmsg = 1;
|
||||
@ -272,6 +343,10 @@ int main(int argc, char *argv[])
|
||||
return usage(1);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
svcname = optarg;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
parse_rotation(optarg, &size, &num);
|
||||
if (size > 0 && num > 0)
|
||||
@ -351,6 +426,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
return fclose(fp);
|
||||
}
|
||||
} else if (host) {
|
||||
log.log_host = &sa;
|
||||
if (nslookup(host, svcname, family, &sa))
|
||||
return 1;
|
||||
log_opts |= LOG_NDELAY;
|
||||
}
|
||||
|
||||
openlog_r(ident, log_opts, facility, &log);
|
||||
|
147
src/syslog.c
147
src/syslog.c
@ -96,6 +96,20 @@ is_socket(int fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used on systems that don't have sa->sa_len
|
||||
*/
|
||||
#ifndef HAVE_SA_LEN
|
||||
static socklen_t sa_len(struct sockaddr *sa)
|
||||
{
|
||||
if (sa->sa_family == AF_INET6)
|
||||
return sizeof(struct sockaddr_in6);
|
||||
if (sa->sa_family == AF_INET)
|
||||
return sizeof(struct sockaddr_in);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* syslog, vsyslog --
|
||||
* print message on log file; output is intended for syslogd(8).
|
||||
@ -190,6 +204,8 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
{
|
||||
static const char BRCOSP[] = "]: ";
|
||||
static const char CRLF[] = "\r\n";
|
||||
struct sockaddr *sa = NULL;
|
||||
socklen_t len = 0;
|
||||
size_t cnt, prlen, tries;
|
||||
char ch, *p, *t;
|
||||
struct timeval tv;
|
||||
@ -225,6 +241,17 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
if ((pri & LOG_FACMASK) == 0)
|
||||
pri |= data->log_fac;
|
||||
|
||||
/* Get system time, wallclock, fall back to UNIX time */
|
||||
if (gettimeofday(&tv, NULL) == -1) {
|
||||
tv.tv_sec = time(NULL);
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
|
||||
/* strftime() implies tzset(), localtime_r() doesn't. */
|
||||
tzset();
|
||||
now = (time_t) tv.tv_sec;
|
||||
localtime_r(&now, &tmnow);
|
||||
|
||||
/* Build the message. */
|
||||
p = tbuf;
|
||||
tbuf_left = TBUF_LEN;
|
||||
@ -237,23 +264,59 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
tbuf_left -= prlen; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/* Default log format is RFC5424, continues below BSD format */
|
||||
if (data->log_stat & LOG_RFC3154) {
|
||||
if (!(data->log_stat & LOG_NLOG)) {
|
||||
prlen = snprintf(p, tbuf_left, "<%d>", pri);
|
||||
DEC();
|
||||
} else
|
||||
prlen = 0;
|
||||
|
||||
prlen = strftime(dbuf, sizeof(dbuf), "%b %d %T ", &tmnow);
|
||||
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
iov[iovcnt].iov_base = dbuf;
|
||||
iov[iovcnt].iov_len = strlen(dbuf);
|
||||
iovcnt++;
|
||||
}
|
||||
if (data->log_host) {
|
||||
memcpy(p, dbuf, prlen);
|
||||
DEC();
|
||||
}
|
||||
|
||||
if (data->log_hostname[0] == '\0' && gethostname(data->log_hostname,
|
||||
sizeof(data->log_hostname)) == -1) {
|
||||
/* can this really happen? */
|
||||
data->log_hostname[0] = '-';
|
||||
data->log_hostname[1] = '\0';
|
||||
}
|
||||
prlen = snprintf(p, tbuf_left, "%s ", data->log_hostname);
|
||||
DEC();
|
||||
|
||||
if (data->log_tag == NULL)
|
||||
data->log_tag = getprogname();
|
||||
prlen = snprintf(p, tbuf_left, "%s", data->log_tag);
|
||||
DEC();
|
||||
|
||||
if (data->log_stat & LOG_PID) {
|
||||
if (data->log_pid == -1)
|
||||
data->log_pid = getpid();
|
||||
prlen = snprintf(p, tbuf_left, "[%d]", data->log_pid);
|
||||
DEC();
|
||||
}
|
||||
strlcat(p, ":", tbuf_left);
|
||||
prlen = 1;
|
||||
DEC();
|
||||
goto output;
|
||||
}
|
||||
|
||||
if (!(data->log_stat & LOG_NLOG)) {
|
||||
prlen = snprintf(p, tbuf_left, "<%d>1 ", pri);
|
||||
DEC();
|
||||
} else
|
||||
prlen = 0;
|
||||
|
||||
if (gettimeofday(&tv, NULL) == -1) {
|
||||
tv.tv_sec = time(NULL);
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
|
||||
{
|
||||
/* strftime() implies tzset(), localtime_r() doesn't. */
|
||||
tzset();
|
||||
now = (time_t) tv.tv_sec;
|
||||
localtime_r(&now, &tmnow);
|
||||
|
||||
prlen = strftime(p, tbuf_left, "%FT%T", &tmnow);
|
||||
DEC();
|
||||
prlen = snprintf(p, tbuf_left, ".%06ld", (long)tv.tv_usec);
|
||||
@ -307,7 +370,9 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
DEC();
|
||||
|
||||
if (data->log_stat & LOG_PID) {
|
||||
prlen = snprintf(p, tbuf_left, "%d ", getpid());
|
||||
if (data->log_pid == -1)
|
||||
data->log_pid = getpid();
|
||||
prlen = snprintf(p, tbuf_left, "%d ", data->log_pid);
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
iov[iovcnt].iov_base = __UNCONST("[");
|
||||
iov[iovcnt].iov_len = 1;
|
||||
@ -343,6 +408,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
} else
|
||||
strlcat(fmt_cat, "-", FMT_LEN);
|
||||
|
||||
output:
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG))
|
||||
msgsdlen = strlen(fmt_cat) + 1;
|
||||
else
|
||||
@ -425,8 +491,17 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (data->log_host) {
|
||||
sa = data->log_host;
|
||||
#ifdef HAVE_SA_LEN
|
||||
len = sa->sa_len;
|
||||
#else
|
||||
len = sa_len(sa);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* If the send() failed, there are two likely scenarios:
|
||||
* If the send() fails, there are two likely scenarios:
|
||||
* 1) syslogd was restarted
|
||||
* 2) /dev/log is out of socket buffer space
|
||||
* We attempt to reconnect to /dev/log to take care of
|
||||
@ -434,7 +509,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
* to give syslogd a chance to empty its socket buffer.
|
||||
*/
|
||||
for (tries = 0; tries < MAXTRIES; tries++) {
|
||||
if (send(data->log_file, tbuf, cnt, 0) != -1)
|
||||
if (sendto(data->log_file, tbuf, cnt, 0, sa, len) != -1)
|
||||
break;
|
||||
if (errno != ENOBUFS) {
|
||||
disconnectlog_r(data);
|
||||
@ -487,7 +562,7 @@ disconnectlog_r(struct syslog_data *data)
|
||||
static void
|
||||
connectlog_r(struct syslog_data *data)
|
||||
{
|
||||
/* AF_UNIX address of local logger */
|
||||
struct sockaddr *sa = data->log_host;
|
||||
static struct sockaddr_un sun = {
|
||||
.sun_family = AF_LOCAL,
|
||||
#ifdef HAVE_SA_LEN
|
||||
@ -495,28 +570,48 @@ connectlog_r(struct syslog_data *data)
|
||||
#endif
|
||||
.sun_path = _PATH_LOG,
|
||||
};
|
||||
socklen_t len;
|
||||
int family;
|
||||
char *path;
|
||||
|
||||
path = getenv("SYSLOG_UNIX_PATH");
|
||||
if (!data->log_sockpath && path)
|
||||
data->log_sockpath = path;
|
||||
if (data->log_sockpath && !access(data->log_sockpath, W_OK))
|
||||
strlcpy(sun.sun_path, data->log_sockpath, sizeof(sun.sun_path));
|
||||
if (sa) {
|
||||
family = sa->sa_family;
|
||||
#ifdef HAVE_SA_LEN
|
||||
len = sa->sa_len;
|
||||
#else
|
||||
len = sa_len(sa);
|
||||
#endif
|
||||
} else {
|
||||
sa = (struct sockaddr *)&sun;
|
||||
family = AF_UNIX;
|
||||
#ifdef HAVE_SA_LEN
|
||||
len = sa->sa_len;
|
||||
#else
|
||||
len = sizeof(sun);
|
||||
#endif
|
||||
|
||||
path = getenv("SYSLOG_UNIX_PATH");
|
||||
if (!data->log_sockpath && path)
|
||||
data->log_sockpath = path;
|
||||
|
||||
if (data->log_sockpath && !access(data->log_sockpath, W_OK))
|
||||
strlcpy(sun.sun_path, data->log_sockpath, sizeof(sun.sun_path));
|
||||
}
|
||||
|
||||
if (data->log_file == -1 || fcntl(data->log_file, F_GETFL, 0) == -1) {
|
||||
data->log_file = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
data->log_file = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (data->log_file == -1)
|
||||
return;
|
||||
data->log_connected = 0;
|
||||
}
|
||||
|
||||
if (!data->log_connected) {
|
||||
if (!is_socket(data->log_file)) {
|
||||
data->log_connected = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (connect(data->log_file, (const struct sockaddr *)&sun,
|
||||
sizeof(sun)) == -1) {
|
||||
if (connect(data->log_file, sa, len) == -1) {
|
||||
(void)close(data->log_file);
|
||||
data->log_file = -1;
|
||||
} else
|
||||
@ -534,10 +629,12 @@ openlog_unlocked_r(const char *ident, int logstat, int logfac,
|
||||
if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
|
||||
data->log_fac = logfac;
|
||||
|
||||
if (data->log_stat & LOG_NDELAY) /* open immediately */
|
||||
if (data->log_stat & LOG_NDELAY) { /* open immediately */
|
||||
connectlog_r(data);
|
||||
|
||||
data->log_opened = 1;
|
||||
if (data->log_connected)
|
||||
data->log_opened = 1;
|
||||
} else
|
||||
data->log_opened = 1;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -190,6 +190,7 @@ CODE facilitynames[] = {
|
||||
#define LOG_PTRIM 0x040 /* trim tag and pid from messages to stderr */
|
||||
#define LOG_NLOG 0x080 /* don't write to the system log */
|
||||
#define LOG_STDOUT 0x100 /* like nlog, for debugging syslogp() API */
|
||||
#define LOG_RFC3154 0x200 /* Log to remote/ipc socket in old BSD format */
|
||||
|
||||
#ifndef __KERNEL__
|
||||
|
||||
@ -206,6 +207,8 @@ struct syslog_data {
|
||||
char log_hostname[256]; /* MAXHOSTNAMELEN */
|
||||
int log_fac;
|
||||
int log_mask;
|
||||
void *log_host; /* struct sockaddr* */
|
||||
int log_pid;
|
||||
};
|
||||
|
||||
#define SYSLOG_DATA_INIT { \
|
||||
@ -219,6 +222,8 @@ struct syslog_data {
|
||||
.log_hostname = { '\0' }, \
|
||||
.log_fac = LOG_USER, \
|
||||
.log_mask = 0xff, \
|
||||
.log_host = NULL, \
|
||||
.log_pid = -1, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -30,6 +30,7 @@ MSG=$MSG$MSG$MSG$MSG$MSG$MSG$MSG$MSG$MSG$MSG
|
||||
logger ${MSG}
|
||||
logger 1${MSG}
|
||||
logger 2${MSG}
|
||||
sleep 1
|
||||
|
||||
if [ -f "${LOG}.0" ] &&
|
||||
grep 'script 1' "${NOT1STAMP}" &&
|
||||
|
Loading…
Reference in New Issue
Block a user