Support for logging to a file/stdout using syslog API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
parent
ee2d0ce106
commit
176ba2d095
27
man/logger.1
27
man/logger.1
@ -40,18 +40,29 @@
|
||||
.Op Ar MESSAGE
|
||||
.Sh DESCRIPTIOMN
|
||||
.Nm
|
||||
can be used to send messages to the system log from a UNIX shell, or
|
||||
script.
|
||||
can be used to log messages to the system log daemon from a UNIX shell,
|
||||
or script. Optionally a stand-alone log file can be used, which is the
|
||||
automatically log rotated. Without a
|
||||
.Ar MESSAGE
|
||||
argument
|
||||
.Nm
|
||||
reads input from
|
||||
.Ar stdin .
|
||||
.Sh OPTIONS
|
||||
This program follows the usual UNIX command line syntax:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl f Ar FILE
|
||||
Log file to write messages to, instead of syslog daemon.
|
||||
.Nm
|
||||
accepts
|
||||
.Fl f-
|
||||
as an alias for
|
||||
.Ar stdout .
|
||||
.It Fl h
|
||||
Show program help.
|
||||
.It Fl p Ar PRIO
|
||||
Priority, numeric or
|
||||
.Ar facility.level
|
||||
.Ar facility.severity
|
||||
pair.
|
||||
.It Fl r Ar SIZE:NUM
|
||||
Controls log file rotation.
|
||||
@ -69,7 +80,15 @@ Show program version.
|
||||
.It Ar MESSAGE
|
||||
Log message to write. Remember to use single/double qoutes if calling
|
||||
.Nm
|
||||
from a shell prompt due to expansion the shell does.
|
||||
from a shell prompt due to expansion the shell does. If no message is
|
||||
given
|
||||
.Nm
|
||||
will read from
|
||||
.Ar stdin
|
||||
until EOF. In this mode every new row (newline separated) is converted
|
||||
into an independent
|
||||
.Xr syslog 3
|
||||
call.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Bd -unfilled -offset left
|
||||
|
118
src/logger.c
118
src/logger.c
@ -29,7 +29,9 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
@ -42,7 +44,7 @@
|
||||
#include "compat.h"
|
||||
|
||||
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
|
||||
|
||||
static struct syslog_data log = SYSLOG_DATA_INIT;
|
||||
|
||||
static int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
@ -113,6 +115,7 @@ static int checksz(FILE *fp, off_t sz)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
fsync(fileno(fp));
|
||||
if (sz <= 0)
|
||||
return 0;
|
||||
|
||||
@ -124,49 +127,20 @@ static int checksz(FILE *fp, off_t sz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int logit(int level, char *buf, size_t len)
|
||||
char *chomp(char *str)
|
||||
{
|
||||
if (buf[0]) {
|
||||
syslog(level, "%s", buf);
|
||||
return 0;
|
||||
char *p;
|
||||
|
||||
if (!str || strlen(str) < 1) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((fgets(buf, len, stdin)))
|
||||
syslog(level, "%s", buf);
|
||||
p = str + strlen(str) - 1;
|
||||
while (p >= str && *p == '\n')
|
||||
*p-- = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flogit(char *logfile, int num, off_t sz, char *buf, size_t len)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
reopen:
|
||||
fp = fopen(logfile, "a");
|
||||
if (!fp) {
|
||||
syslog(LOG_ERR | LOG_PERROR, "Failed opening %s: %s", logfile, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (buf[0]) {
|
||||
fprintf(fp, "%s\n", buf);
|
||||
fsync(fileno(fp));
|
||||
if (checksz(fp, sz))
|
||||
return logrotate(logfile, num, sz);
|
||||
} else {
|
||||
while ((fgets(buf, len, stdin))) {
|
||||
fputs(buf, fp);
|
||||
fsync(fileno(fp));
|
||||
|
||||
if (checksz(fp, sz)) {
|
||||
logrotate(logfile, num, sz);
|
||||
buf[0] = 0;
|
||||
goto reopen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fclose(fp);
|
||||
return str;
|
||||
}
|
||||
|
||||
static int parse_prio(char *arg, int *f, int *l)
|
||||
@ -178,21 +152,23 @@ static int parse_prio(char *arg, int *f, int *l)
|
||||
*ptr++ = 0;
|
||||
|
||||
for (int i = 0; facilitynames[i].c_name; i++) {
|
||||
if (!strcmp(facilitynames[i].c_name, arg)) {
|
||||
if (strcmp(facilitynames[i].c_name, arg))
|
||||
continue;
|
||||
|
||||
*f = facilitynames[i].c_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
arg = ptr;
|
||||
}
|
||||
|
||||
for (int i = 0; prioritynames[i].c_name; i++) {
|
||||
if (!strcmp(prioritynames[i].c_name, arg)) {
|
||||
if (strcmp(prioritynames[i].c_name, arg))
|
||||
continue;
|
||||
|
||||
*l = prioritynames[i].c_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -203,7 +179,7 @@ static int usage(int code)
|
||||
"\n"
|
||||
"Write MESSAGE (or stdin) to syslog, or file (with logrotate)\n"
|
||||
"\n"
|
||||
" -p PRIO Log message priority (numeric or facility.level pair)\n"
|
||||
" -p PRIO Log message priority (numeric or facility.severity pair)\n"
|
||||
" -t TAG Log using the specified tag (defaults to user name)\n"
|
||||
" -s Log to stderr as well as the system log\n"
|
||||
"\n"
|
||||
@ -221,10 +197,12 @@ static int usage(int code)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c, rc, num = 5;
|
||||
FILE *fp;
|
||||
int c, num = 5;
|
||||
int facility = LOG_USER;
|
||||
int level = LOG_INFO;
|
||||
int log_opts = LOG_NOWAIT;
|
||||
int severity = LOG_INFO;
|
||||
int log_opts = LOG_NDELAY | LOG_PID;
|
||||
int rotate = 0;
|
||||
off_t size = 200 * 1024;
|
||||
char *ident = NULL, *logfile = NULL;
|
||||
char buf[512] = "";
|
||||
@ -236,7 +214,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (parse_prio(optarg, &facility, &level))
|
||||
if (parse_prio(optarg, &facility, &severity))
|
||||
return usage(1);
|
||||
break;
|
||||
|
||||
@ -276,14 +254,34 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
openlog(ident, log_opts, facility);
|
||||
|
||||
if (logfile)
|
||||
rc = flogit(logfile, num, size, buf, sizeof(buf));
|
||||
else
|
||||
rc = logit(level, buf, sizeof(buf));
|
||||
|
||||
closelog();
|
||||
|
||||
return rc;
|
||||
if (logfile) {
|
||||
if (strcmp(logfile, "-")) {
|
||||
log_opts |= LOG_NLOG;
|
||||
fp = fopen(logfile, "a");
|
||||
if (!fp)
|
||||
err(1, "Failed opening %s for writing: %m", logfile);
|
||||
rotate = 1;
|
||||
} else {
|
||||
log_opts |= LOG_STDOUT;
|
||||
fp = stdout;
|
||||
}
|
||||
|
||||
log.log_file = fileno(fp);
|
||||
}
|
||||
|
||||
openlog_r(ident, log_opts, facility, &log);
|
||||
|
||||
if (!buf[0]) {
|
||||
while ((fgets(buf, sizeof(buf), stdin)))
|
||||
syslog_r(severity, &log, "%s", chomp(buf));
|
||||
} else
|
||||
syslog_r(severity, &log, "%s", buf);
|
||||
|
||||
closelog_r(&log);
|
||||
|
||||
if (rotate && checksz(fp, size))
|
||||
logrotate(logfile, num, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
76
src/syslog.c
76
src/syslog.c
@ -40,6 +40,7 @@ __RCSID("$NetBSD: syslog.c,v 1.55 2015/10/26 11:44:30 roy Exp $");
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
@ -71,7 +72,8 @@ static mutex_t syslog_mutex = MUTEX_INITIALIZER;
|
||||
* wrapper to catch GLIBC syslog(), which provides this for security measures
|
||||
* Note: we only enter here if user includes GLIBC syslog.h
|
||||
*/
|
||||
void __syslog_chk(int pri, int flag __attribute__((unused)), const char *fmt, ...)
|
||||
void
|
||||
__syslog_chk(int pri, int flag __attribute__((unused)), const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@ -80,6 +82,20 @@ void __syslog_chk(int pri, int flag __attribute__((unused)), const char *fmt, ..
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to determine file/socket type of log_file
|
||||
*/
|
||||
static int
|
||||
is_socket(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st) || !S_ISSOCK(st.st_mode))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* syslog, vsyslog --
|
||||
* print message on log file; output is intended for syslogd(8).
|
||||
@ -186,8 +202,10 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN], fmt_cat[FMT_LEN] = "";
|
||||
size_t tbuf_left, fmt_left, msgsdlen;
|
||||
char *fmt = fmt_cat;
|
||||
struct iovec iov[7]; /* prog + [ + pid + ]: + fmt + crlf */
|
||||
int opened, iovcnt;
|
||||
char dbuf[30];
|
||||
struct iovec iov[8]; /* date/time + prog + [ + pid + ]: + fmt + crlf */
|
||||
int iovcnt = 0;
|
||||
int opened;
|
||||
|
||||
#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
|
||||
/* Check for invalid bits. */
|
||||
@ -219,8 +237,11 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
tbuf_left -= prlen; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
if (!(data->log_stat & LOG_NLOG)) {
|
||||
prlen = snprintf(p, tbuf_left, "<%d>1 ", pri);
|
||||
DEC();
|
||||
} else
|
||||
prlen = 0;
|
||||
|
||||
if (gettimeofday(&tv, NULL) != -1) {
|
||||
/* strftime() implies tzset(), localtime_r() doesn't. */
|
||||
@ -241,6 +262,13 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
p[prlen-2] = ':';
|
||||
prlen += 1;
|
||||
}
|
||||
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
strftime(dbuf, sizeof(dbuf), "%b %d %Y %T ", &tmnow);
|
||||
iov[iovcnt].iov_base = dbuf;
|
||||
iov[iovcnt].iov_len = strlen(dbuf);
|
||||
iovcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (data == &sdata)
|
||||
@ -266,8 +294,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
if (data == &sdata)
|
||||
mutex_unlock(&syslog_mutex);
|
||||
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
|
||||
iovcnt = 0;
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
iov[iovcnt].iov_base = p;
|
||||
iov[iovcnt].iov_len = prlen - 1;
|
||||
iovcnt++;
|
||||
@ -276,7 +303,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
|
||||
if (data->log_stat & LOG_PID) {
|
||||
prlen = snprintf(p, tbuf_left, "%d ", getpid());
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
iov[iovcnt].iov_base = __UNCONST("[");
|
||||
iov[iovcnt].iov_len = 1;
|
||||
iovcnt++;
|
||||
@ -289,7 +316,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
}
|
||||
} else {
|
||||
prlen = snprintf(p, tbuf_left, "- ");
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
iov[iovcnt].iov_base = __UNCONST(BRCOSP + 1);
|
||||
iov[iovcnt].iov_len = 2;
|
||||
iovcnt++;
|
||||
@ -311,7 +338,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
} else
|
||||
strlcat(fmt_cat, "-", FMT_LEN);
|
||||
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS))
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG))
|
||||
msgsdlen = strlen(fmt_cat) + 1;
|
||||
else
|
||||
msgsdlen = 0; /* XXX: GCC */
|
||||
@ -354,8 +381,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
*t = '\0';
|
||||
|
||||
prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
|
||||
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
|
||||
if (data->log_stat & (LOG_PERROR|LOG_CONS|LOG_NLOG)) {
|
||||
iov[iovcnt].iov_base = p + msgsdlen;
|
||||
iov[iovcnt].iov_len = prlen - msgsdlen;
|
||||
iovcnt++;
|
||||
@ -379,6 +405,21 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
openlog_unlocked_r(data->log_tag, data->log_stat, 0, data);
|
||||
connectlog_r(data);
|
||||
|
||||
/* Don't write to system log, instead use fd in log_file */
|
||||
if (data->log_stat & LOG_NLOG) {
|
||||
iov[iovcnt].iov_base = __UNCONST(CRLF + 1);
|
||||
iov[iovcnt].iov_len = 1;
|
||||
(void)writev(data->log_file, iov, iovcnt + 1);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Log to stdout, usually for debugging syslogp() API */
|
||||
if (data->log_stat & LOG_STDOUT) {
|
||||
strlcat(tbuf, "\n", sizeof(tbuf));
|
||||
write(data->log_file, tbuf, strlen(tbuf));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the send() failed, there are two likely scenarios:
|
||||
* 1) syslogd was restarted
|
||||
@ -411,6 +452,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
|
||||
(void)close(fd);
|
||||
}
|
||||
|
||||
done:
|
||||
if (data == &sdata)
|
||||
mutex_unlock(&syslog_mutex);
|
||||
|
||||
@ -450,15 +492,19 @@ connectlog_r(struct syslog_data *data)
|
||||
};
|
||||
|
||||
if (data->log_file == -1 || fcntl(data->log_file, F_GETFL, 0) == -1) {
|
||||
if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
|
||||
0)) == -1)
|
||||
data->log_file = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (data->log_file == -1)
|
||||
return;
|
||||
data->log_connected = 0;
|
||||
}
|
||||
if (!data->log_connected) {
|
||||
if (connect(data->log_file,
|
||||
(const struct sockaddr *)(const void *)&sun,
|
||||
(socklen_t)sizeof(sun)) == -1) {
|
||||
if (!is_socket(data->log_file)) {
|
||||
data->log_connected = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (connect(data->log_file, (const struct sockaddr *)&sun,
|
||||
sizeof(sun)) == -1) {
|
||||
(void)close(data->log_file);
|
||||
data->log_file = -1;
|
||||
} else
|
||||
|
Loading…
Reference in New Issue
Block a user