From bdb1d45f90e41e00cdf84901df7e62d9b4e60579 Mon Sep 17 00:00:00 2001
From: Joachim Nilsson <troglobit@gmail.com>
Date: Fri, 25 Oct 2019 15:52:14 +0200
Subject: [PATCH] Refactor and drop '-n' option for rotation

The '-n' option is commonly used for remote servers, so let's
consolidate the log rotation under the '-r' flag instead, with
the same syntax as previously established in syslog.conf

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
---
 man/logger.1 | 52 +++++++++++++++++++++++++++++++++--------
 src/logger.c | 65 +++++++++++++++++++++++++++++++++-------------------
 2 files changed, 83 insertions(+), 34 deletions(-)

diff --git a/man/logger.1 b/man/logger.1
index 929f11e..11f55c1 100644
--- a/man/logger.1
+++ b/man/logger.1
@@ -34,11 +34,10 @@
 .Nm
 .Op Fl hsv
 .Op Fl f Ar FILE
-.Op Fl n Ar SIZE
 .Op Fl p Ar PRIO
-.Op Fl r Ar NUM
+.Op Fl r Ar SIZE:NUM
 .Op Fl t Ar TAG
-.Qq Ar message
+.Op Ar MESSAGE
 .Sh DESCRIPTIOMN
 .Nm
 can be used to send messages to the system log from a UNIX shell, or
@@ -47,27 +46,59 @@ script.
 This program follows the usual UNIX command line syntax:
 .Bl -tag -width Ds
 .It Fl f Ar FILE
-File to write log messages to, instead of syslog.
+Log file to write messages to, instead of syslog daemon.
 .It Fl h
 Show program help.
-.It Fl n Ar SIZE
-Number of bytes before rotating when logging to a file, default: 200 kB.
 .It Fl p Ar PRIO
-Priority, numeric or facility.level pair.
-.It Fl r Ar NUM
-Number of rotated files to keep when logging to a file, default: 5.
+Priority, numeric or
+.Ar facility.level
+pair.
+.It Fl r Ar SIZE:NUM
+Controls log file rotation.
+.Ar SIZE
+denotes number of bytes before rotating, default: 200 kB.
+.Ar NUM
+denotes number of rotated files to keep when logging to a file, default:
+5.
 .It Fl s
 Log to stderr as well as the system log.
 .It Fl t Ar TAG
 Log using the specified tag, default: username.
 .It Fl v
 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.
 .El
 .Sh EXAMPLES
 .Bd -unfilled -offset left
 logger -t dropbear -p auth.notice "Successful login for user 'admin' from 1.2.3.4"
 logger -t udhcpc -f /tmp/script.log "New lease 1.2.3.200 obtained for interface eth0"
 .Ed
+.Sh FILES
+.Bl -tag -width /var/run/log -compact
+.It Ar FILE
+If a log file is enabled, using
+.Fl f Ar FILE ,
+then this file is opened and written to by
+.Nm .
+With log file rotation,
+.Fl r Ar SIZE:NUM ,
+this means
+.Nm
+also creates
+.Pa FILE.1 FILE.2 FILE.3.gz
+etc.
+.It Pa /var/run/log
+Socket to connect to for communicating with
+.Xr syslogd 8 .
+In older implementations
+.Pa /dev/log
+was used.  This means this version of
+.Nm
+is not compatible with older releases, or other (local) syslog servers.
+.El
 .Sh SEE ALSO
 .Xr syslog 3
 .Xr syslogd 8
@@ -83,5 +114,6 @@ and be extended upon in the sysklogd project.
 .Sh STANDARDS
 The
 .Nm
-command is expected to be IEEE Std 1003.2 ("POSIX.2") compatible.
+command is expected to be IEEE Std 1003.2 ("POSIX.2") compatible, with
+extensions for RFC5424 and log file rotation.
 .Sh AVAILABILITY
diff --git a/src/logger.c b/src/logger.c
index 8e3344f..c59a0a5 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -39,6 +39,7 @@
 #include <syslog.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include "compat.h"
 
 static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
 
@@ -123,6 +124,19 @@ static int checksz(FILE *fp, off_t sz)
 	return 0;
 }
 
+static int logit(int level, char *buf, size_t len)
+{
+	if (buf[0]) {
+		syslog(level, "%s", buf);
+		return 0;
+	}
+
+	while ((fgets(buf, len, stdin)))
+		syslog(level, "%s", buf);
+
+	return 0;
+}
+
 static int flogit(char *logfile, int num, off_t sz, char *buf, size_t len)
 {
 	FILE *fp;
@@ -155,19 +169,6 @@ reopen:
 	return fclose(fp);
 }
 
-static int logit(int level, char *buf, size_t len)
-{
-	if (buf[0]) {
-		syslog(level, "%s", buf);
-		return 0;
-	}
-
-	while ((fgets(buf, len, stdin)))
-		syslog(level, "%s", buf);
-
-	return 0;
-}
-
 static int parse_prio(char *arg, int *f, int *l)
 {
 	char *ptr;
@@ -202,14 +203,14 @@ static int usage(int code)
 	       "\n"
 	       "Write MESSAGE (or stdin) to syslog, or file (with logrotate)\n"
 	       "\n"
-	       "  -?       This help text\n"
-	       "  -p PRIO  Priority (numeric or facility.level pair)\n"
+	       "  -p PRIO  Log message priority (numeric or facility.level 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"
-	       "  -f FILE  File to write log messages to, instead of syslog\n"
-	       "  -n SIZE  Number of bytes before rotating, default: 200 kB\n"
-	       "  -r NUM   Number of rotated files to keep, default: 5\n"
+	       "  -f FILE  Log file to write messages to, instead of syslog daemon\n"
+	       "  -r S:R   Log file rotation, default: 200 kB max \e[4ms\e[0mize, 5 \e[4mr\e[0motations\n"
+	       "\n"
+	       "  -?       This help text\n"
 	       "  -v       Show program version\n"
 	       "\n"
 	       "This version of logger is distributed as part of sysklogd.\n"
@@ -218,6 +219,26 @@ static int usage(int code)
 	return code;
 }
 
+static void parse_rotation(char *optarg, off_t *size, int *num)
+{
+	char buf[100];
+	char *c;
+	int sz = 0, cnt = 0;
+
+	strlcpy(buf, optarg, sizeof(buf));
+	c = strchr(buf, ':');
+	if (c) {
+		*c++ = 0;
+		cnt  = atoi(c);
+	}
+
+	sz = strtobytes(buf);
+	if (sz > 0)
+		*size = sz;
+	if (cnt)
+		*num = cnt;
+}
+
 int main(int argc, char *argv[])
 {
 	int c, rc, num = 5;
@@ -228,23 +249,19 @@ int main(int argc, char *argv[])
 	char *ident = NULL, *logfile = NULL;
 	char buf[512] = "";
 
-	while ((c = getopt(argc, argv, "?f:n:p:r:st:v")) != EOF) {
+	while ((c = getopt(argc, argv, "?f:p:r:st:v")) != EOF) {
 		switch (c) {
 		case 'f':
 			logfile = optarg;
 			break;
 
-		case 'n':
-			size = atoi(optarg);
-			break;
-
 		case 'p':
 			if (parse_prio(optarg, &facility, &level))
 				return usage(1);
 			break;
 
 		case 'r':
-			num = atoi(optarg);
+			parse_rotation(optarg, &size, &num);
 			break;
 
 		case 's':