Add a maximum file size parameter

Sometimes there are a few noisy machines generating 100GB+ per day,
filling up the disk and preventing logrotate from cleaning things up.
Manual intervention is required and several hours or days of logs are
lost - depending on how timely the humans respond.

Having a fixed limit of 1GB or some other reasonable value ensures we
lose logs from the noisy machines, but not from the well-behaving ones
due to full disk.

Signed-off-by: Joern Engel <joern@logfs.org>
diff --git a/cancd.c b/cancd.c
index cfcfec1..ebd8bdd 100644
--- a/cancd.c
+++ b/cancd.c
@@ -81,6 +81,12 @@
  */
 static uint16_t log_port = 7075;
 
+/*
+ * Maximum file size to generate - to prevent noisy machine from
+ * filling the disk
+ */
+static uint64_t size_limit = UINT64_MAX;
+
 /* Socket we are using */
 static int sock_fd;
 
@@ -423,7 +429,8 @@
 
 static void do_output(char *buf, int len, struct sockaddr_in *addr, socklen_t socklen)
 {
-	int fd;
+	int fd, err;
+	struct stat stat;
 	const char *name;
 	struct source_ip *sip = get_source_ip(addr);
 
@@ -432,12 +439,16 @@
 		return;
 
 	fd = open(name, O_WRONLY | O_APPEND | O_CREAT, 0644);
-	if (fd < 0)
+	if (fd < 0) {
 		syslog(LOG_ERR, "Unable to open \"%s\": %s", name, strerror(errno));
-	else {
-		write_formatted(fd, sip, buf, len);
-		close(fd);
+		return;
 	}
+	err = fstat(fd, &stat);
+	if (err || stat.st_size > size_limit)
+		goto out;
+	write_formatted(fd, sip, buf, len);
+out:
+	close(fd);
 }
 
 static int set_blocking(int blocking)
@@ -613,6 +624,7 @@
 extern int opterr;
 static int parse_options(int argc, char *argv[])
 {
+	char **garbage = NULL;
 	int c;
 
 	opterr = 0;
@@ -655,6 +667,13 @@
 				print_usage(-EINVAL);
 			}
 			break;
+		case 's':
+			size_limit = strtoull(optarg, garbage, 0);
+			if (garbage) {
+				fprintf(stderr, PROGNAME ": Invalid size limit: \"%s\"\n", optarg);
+				print_usage(-EINVAL);
+			}
+			break;
 		case 'D':
 			daemonize = 0;
 			break;