summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bounce.c27
-rw-r--r--bounce.h3
-rw-r--r--pounce.110
-rw-r--r--ring.c78
4 files changed, 117 insertions, 1 deletions
diff --git a/bounce.c b/bounce.c
index 65789ab..4e7458c 100644
--- a/bounce.c
+++ b/bounce.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sysexits.h>
 #include <tls.h>
 #include <unistd.h>
@@ -88,11 +89,20 @@ static char *sensitive(char *arg) {
 	return value;
 }
 
+static FILE *saveFile;
+static void exitSave(void) {
+	int error = ringSave(saveFile);
+	if (error) warn("fwrite");
+	error = fclose(saveFile);
+	if (error) warn("fclose");
+}
+
 int main(int argc, char *argv[]) {
 	const char *localHost = "localhost";
 	const char *localPort = "6697";
 	char certPath[PATH_MAX] = "";
 	char privPath[PATH_MAX] = "";
+	const char *save = NULL;
 
 	bool insecure = false;
 	const char *host = NULL;
@@ -107,7 +117,8 @@ int main(int argc, char *argv[]) {
 	const char *quit = "connection reset by purr";
 
 	int opt;
-	while (0 < (opt = getopt(argc, argv, "!A:C:H:K:NP:Q:W:a:h:j:n:p:r:u:vw:"))) {
+	const char *opts = "!A:C:H:K:NP:Q:W:a:f:h:j:n:p:r:u:vw:";
+	while (0 < (opt = getopt(argc, argv, opts))) {
 		switch (opt) {
 			break; case '!': insecure = true;
 			break; case 'A': away = optarg;
@@ -119,6 +130,7 @@ int main(int argc, char *argv[]) {
 			break; case 'Q': quit = optarg;
 			break; case 'W': clientPass = sensitive(optarg);
 			break; case 'a': auth = sensitive(optarg);
+			break; case 'f': save = optarg;
 			break; case 'h': host = optarg;
 			break; case 'j': join = optarg;
 			break; case 'n': nick = optarg;
@@ -146,6 +158,19 @@ int main(int argc, char *argv[]) {
 	if (!user) user = nick;
 	if (!real) real = nick;
 
+	if (save) {
+		umask(0066);
+		saveFile = fopen(save, "a+");
+		if (!saveFile) err(EX_CANTCREAT, "%s", save);
+
+		rewind(saveFile);
+		ringLoad(saveFile);
+
+		int error = ftruncate(fileno(saveFile), 0);
+		if (error) err(EX_IOERR, "ftruncate");
+		atexit(exitSave);
+	}
+
 	listenConfig(certPath, privPath);
 
 	int bind[8];
diff --git a/bounce.h b/bounce.h
index 9221185..6e9ddbd 100644
--- a/bounce.h
+++ b/bounce.h
@@ -15,6 +15,7 @@
  */
 
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
@@ -64,6 +65,8 @@ size_t ringDiff(size_t consumer);
 const char *ringPeek(time_t *time, size_t consumer);
 const char *ringConsume(time_t *time, size_t consumer);
 void ringInfo(void);
+int ringSave(FILE *file);
+void ringLoad(FILE *file);
 
 void listenConfig(const char *cert, const char *priv);
 size_t listenBind(int fds[], size_t cap, const char *host, const char *port);
diff --git a/pounce.1 b/pounce.1
index 41555ed..632ca3e 100644
--- a/pounce.1
+++ b/pounce.1
@@ -17,6 +17,7 @@
 .Op Fl Q Ar quit
 .Op Fl W Ar pass
 .Op Fl a Ar auth
+.Op Fl f Ar file
 .Op Fl h Ar host
 .Op Fl j Ar chan
 .Op Fl n Ar nick
@@ -108,6 +109,15 @@ Set
 to the first line read from
 .Ar file .
 .
+.It Fl f Ar file
+Load the contents of the ring buffer from
+.Ar file
+if it exists.
+The file is then truncated.
+On shutdown,
+save the contents of the ring buffer to
+.Ar file .
+.
 .It Fl h Ar host
 Connect to
 .Ar host .
diff --git a/ring.c b/ring.c
index 49fdd9b..474a6e4 100644
--- a/ring.c
+++ b/ring.c
@@ -103,3 +103,81 @@ void ringInfo(void) {
 		);
 	}
 }
+
+static const size_t FileVersion = 0x0165636E756F70;
+
+static int writeSize(FILE *file, size_t value) {
+	return (fwrite(&value, sizeof(value), 1, file) ? 0 : -1);
+}
+static int writeTime(FILE *file, time_t time) {
+	return (fwrite(&time, sizeof(time), 1, file) ? 0 : -1);
+}
+static int writeString(FILE *file, const char *str) {
+	return (fwrite(str, strlen(str) + 1, 1, file) ? 0 : -1);
+}
+
+int ringSave(FILE *file) {
+	if (writeSize(file, FileVersion)) return -1;
+	if (writeSize(file, producer)) return -1;
+	if (writeSize(file, consumers.len)) return -1;
+	for (size_t i = 0; i < consumers.len; ++i) {
+		if (writeString(file, consumers.ptr[i].name)) return -1;
+		if (writeSize(file, consumers.ptr[i].pos)) return -1;
+	}
+	for (size_t i = 0; i < RingLen; ++i) {
+		if (writeTime(file, ring.times[i])) return -1;
+	}
+	for (size_t i = 0; i < RingLen; ++i) {
+		if (!ring.lines[i]) break;
+		if (writeString(file, ring.lines[i])) return -1;
+	}
+	return 0;
+}
+
+static void readSize(FILE *file, size_t *value) {
+	fread(value, sizeof(*value), 1, file);
+	if (ferror(file)) err(EX_IOERR, "fread");
+	if (feof(file)) err(EX_DATAERR, "unexpected eof");
+}
+static void readTime(FILE *file, time_t *time) {
+	fread(time, sizeof(*time), 1, file);
+	if (ferror(file)) err(EX_IOERR, "fread");
+	if (feof(file)) err(EX_DATAERR, "unexpected eof");
+}
+static void readString(FILE *file, char **buf, size_t *cap) {
+	ssize_t len = getdelim(buf, cap, '\0', file);
+	if (len < 0 && !feof(file)) err(EX_IOERR, "getdelim");
+}
+
+void ringLoad(FILE *file) {
+	size_t version;
+	fread(&version, sizeof(version), 1, file);
+	if (ferror(file)) err(EX_IOERR, "fread");
+	if (feof(file)) return;
+
+	if (version != FileVersion) errx(EX_DATAERR, "unknown file version");
+	readSize(file, &producer);
+
+	char *buf = NULL;
+	size_t cap = 0;
+
+	size_t len;
+	readSize(file, &len);
+	for (size_t i = 0; i < len; ++i) {
+		readString(file, &buf, &cap);
+		size_t consumer = ringConsumer(buf);
+		readSize(file, &consumers.ptr[consumer].pos);
+	}
+
+	for (size_t i = 0; i < RingLen; ++i) {
+		readTime(file, &ring.times[i]);
+	}
+	for (size_t i = 0; i < RingLen; ++i) {
+		readString(file, &buf, &cap);
+		if (feof(file)) break;
+		ring.lines[i] = strdup(buf);
+		if (!ring.lines[i]) err(EX_OSERR, "strdup");
+	}
+
+	free(buf);
+}
ting each commit based on whether or not stdout points to a regular file (in maybe_flush_or_die()). Which means that when writing directly to the webserver, Git flushes stdout for us, but when we redirect stdout to the cache it points to a regular file so Git no longer flushes the output for us. The patch is still correct, but perhaps the full explanation is interesting! Reported-by: Konstantin Ryabitsev <mricon@kernel.org> 2014-06-28ui-log: ignore unhandled argumentsJohn Keeping If you search for a bogus range string here: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/log/ Using something like "range" and "qwerty123456", it returns an "Internal Server Error" and the following in the logs: > [Tue Jun 10 17:45:32 2014] [error] [client 172.21.1.6] fatal: > ambiguous argument 'qwerty123456': unknown revision or path not in the > working tree., referer: > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ > [Tue Jun 10 17:45:32 2014] [error] [client 172.21.1.6] Use '--' to > separate paths from revisions, like this:, referer: > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ > [Tue Jun 10 17:45:32 2014] [error] [client 172.21.1.6] 'git <command> > [<revision>...] -- [<file>...]', referer: > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ > [Tue Jun 10 17:45:32 2014] [error] [client 172.21.1.6] Premature end > of script headers: cgit, referer: > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ The cache will kick in, so if you search for the same string again, it'll show an empty range, so you have to change the bogus strings each time. This is because we just pass the arguments straight to Git's revision parsing machinery which die()s if it cannot parse an argument, printing the above to stderr and exiting. The patch below makes it a bit friendlier by just ignoring unhandled arguments, but I can't see an easy way to report errors when we can't parse revision arguments without losing the flexibility of supporting all of the revision specifiers supported by Git. Reported-by: Konstantin Ryabitsev <mricon@kernel.org> 2014-06-28git: update for git 2.0Christian Hesse prefixcmp() and suffixcmp() have been remove, functionality is now provided by starts_with() and ends_with(). Retrurn values have been changed, so instead of just renaming we have to fix logic. Everything else looks just fine. 2014-04-17remove trailing whitespaces from source filesChristian Hesse 2014-04-12git: update to 1.9.2Christian Hesse Everything works just bumping the version in Makefile and commit hash in submodule. No code changes required. 2014-04-05Fix cgit_parse_url when a repo url is contained in another repo urlJulian Maurice For example, if I have two repos (remove-suffix is enabled): /foo /foo/bar http://cgit/foo/bar/ is interpreted as "repository 'foo', command 'bar'" instead of "repository 'foo/bar'" 2014-03-20Makefile: use more reliable git tarball mirrorJason A. Donenfeld 2014-03-20git: update to 1.9.1Christian Hesse