Commit Diff


commit - 677afbd3f873425bcc6f9a23be7efe3066aed70a
commit + d7802bb44a8562917b58bfc76f135ddf4fcbbe3b
blob - 740b34e95d2dc79932dd650941c50b3701f8dd6a
blob + a369acc66378987aa6ee2009bd5eeec86a9cab24
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,8 @@
+2020-12-02  Omar Polo  <op@omarpolo.com>
+
+	* gmid.c: logging reworked and daemonize.  The -l option was
+	removed: now it logs on syslog if -f (foreground) is not passed.
+
 2020-11-18  Omar Polo  <op@omarpolo.com>
 
 	* 1.3.2 tagged
blob - 91d9da971685ea3909deb27798254c548e2353a6
blob + fef69f753d561af468de6f9f41e2b41dc0757cbb
--- README.md
+++ README.md
@@ -6,11 +6,10 @@
 # SYNOPSIS
 
 **gmid**
-\[**-h**]
+\[**-fh**]
 \[**-c**&nbsp;*cert.pem*]
 \[**-d**&nbsp;*docs*]
 \[**-k**&nbsp;*key.pem*]
-\[**-l**&nbsp;*logfile*]
 \[**-p**&nbsp;*port*]
 \[**-x**&nbsp;*cgi-bin*]
 
@@ -64,6 +63,10 @@ The options are as follows:
 > By default is
 > *docs*.
 
+**-f**
+
+> stays and log in the foreground, do not daemonize the process.
+
 **-h**
 
 > Print the usage and exit.
@@ -73,10 +76,6 @@ The options are as follows:
 > The key for the certificate, by default is
 > *key.pem*.
 
-**-l** *logfile*
-
-> log to the given file instead of the standard error.
-
 **-p** *port*
 
 > The port to bind to, by default 1965.
@@ -217,5 +216,3 @@ since it's relative to the document root.
 *	it doesn't support virtual hosts: the host part of the request URL is
 	completely ignored.
 
-*	it doesn't fork in the background or anything like that.
-
blob - 069deea7d7fdb0a25c8c72d27b2f91d6ad79f113
blob + e294253eca4c8094a5c43ad34172a9bc1f374a7d
--- gmid.1
+++ gmid.1
@@ -20,11 +20,10 @@
 .Sh SYNOPSIS
 .Nm
 .Bk -words
-.Op Fl h
+.Op Fl fh
 .Op Fl c Ar cert.pem
 .Op Fl d Ar docs
 .Op Fl k Ar key.pem
-.Op Fl l Ar logfile
 .Op Fl p Ar port
 .Op Fl x Ar cgi-bin
 .Ek
@@ -73,13 +72,13 @@ The root directory to serve.
 won't serve any file that is outside that directory.
 By default is
 .Pa docs .
+.It Fl f
+stays and log in the foreground, do not daemonize the process.
 .It Fl h
 Print the usage and exit.
 .It Fl k Ar key.pem
 The key for the certificate, by default is
 .Pa key.pem .
-.It Fl l Ar logfile
-log to the given file instead of the standard error.
 .It Fl p Ar port
 The port to bind to, by default 1965.
 .It Fl x Ar dir
@@ -189,6 +188,4 @@ since it's relative to the document root.
 .It
 it doesn't support virtual hosts: the host part of the request URL is
 completely ignored.
-.It
-it doesn't fork in the background or anything like that.
 .El
blob - d75f9b3dccebe0281d83e43ac8644639db569e75
blob + e9f90f52efbc05a49a6f72e8e44ac120b02d9bdb
--- gmid.c
+++ gmid.c
@@ -30,6 +30,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <syslog.h>
 #include <tls.h>
 #include <unistd.h>
 
@@ -113,17 +114,39 @@ struct etm {			/* file extension to mime */
 	{NULL, NULL}
 };
 
-#define LOG(c, fmt, ...)						\
+#define LOG(priority, c, fmt, ...)					\
 	do {								\
 		char buf[INET_ADDRSTRLEN];				\
-		if (inet_ntop((c)->af, &(c)->addr, buf, sizeof(buf)) == NULL) \
-			err(1, "inet_ntop");				\
-		dprintf(logfd, "[%s] " fmt "\n", buf, __VA_ARGS__);	\
+		if (inet_ntop((c)->af, &(c)->addr,			\
+		    buf, sizeof(buf)) == NULL)				\
+			FATAL("inet_ntop: %s", strerror(errno));	\
+		if (foreground)						\
+			fprintf(stderr,					\
+			    "%s " fmt "\n", buf, __VA_ARGS__);		\
+		else							\
+			syslog((priority) | LOG_DAEMON,			\
+			    "%s " fmt, buf, __VA_ARGS__);		\
 	} while (0)
 
-const char *dir, *cgi;
-int dirfd, logfd;
+#define LOGE(c, fmt, ...) LOG(LOG_ERR,    c, fmt, __VA_ARGS__)
+#define LOGN(c, fmt, ...) LOG(LOG_NOTICE, c, fmt, __VA_ARGS__)
+#define LOGI(c, fmt, ...) LOG(LOG_INFO,   c, fmt, __VA_ARGS__)
+#define LOGD(c, fmt, ...) LOG(LOG_DEBUG,  c, fmt, __VA_ARGS__)
+
+#define FATAL(fmt, ...)							\
+	do {								\
+		if (foreground)						\
+			fprintf(stderr, fmt "\n", __VA_ARGS__);		\
+		else							\
+			syslog(LOG_DAEMON | LOG_CRIT,			\
+			    fmt, __VA_ARGS__);				\
+		exit(1);						\
+	} while (0)
+
+const char *dir, *cgi;
+int dirfd;
 int port;
+int foreground;
 int connected_clients;
 
 void		 siginfo_handler(int);
@@ -138,7 +161,7 @@ ssize_t		 filesize(int);
 int		 start_reply(struct pollfd*, struct client*, int, const char*);
 const char	*path_ext(const char*);
 const char	*mime(const char*);
-int		 check_path(const char*, int*);
+int		 check_path(struct client*, const char*, int*);
 int		 check_for_cgi(char *, char*, struct pollfd*, struct client*);
 int		 open_file(char*, char*, struct pollfd*, struct client*);
 int		 start_cgi(const char*, const char*, const char*, struct pollfd*, struct client*);
@@ -230,7 +253,7 @@ url_trim(struct client *c, char *url)
 	s[1] = '\0';
 
 	if (s[2] != '\0') {
-		LOG(c, "%s", "request longer than 1024 bytes\n");
+		LOGE(c, "%s", "request longer than 1024 bytes");
 		return 0;
 	}
 
@@ -342,7 +365,7 @@ mime(const char *path)
 }
 
 int
-check_path(const char *path, int *fd)
+check_path(struct client *c, const char *path, int *fd)
 {
 	struct stat sb;
 
@@ -353,7 +376,7 @@ check_path(const char *path, int *fd)
 	}
 
 	if (fstat(*fd, &sb) == -1) {
-		dprintf(logfd, "failed stat for %s\n", path);
+		LOGN(c, "failed stat for %s: %s", path, strerror(errno));
 		return FILE_MISSING;
 	}
 
@@ -389,7 +412,7 @@ check_for_cgi(char *path, char *query, struct pollfd *
 			end--;
 		*end = '\0';
 
-		switch (check_path(path, &c->fd)) {
+		switch (check_path(c, path, &c->fd)) {
 		case FILE_EXECUTABLE:
 			return start_cgi(path, end+1, query, fds,c);
 		case FILE_MISSING:
@@ -421,7 +444,7 @@ open_file(char *path, char *query, struct pollfd *fds,
 		fpath[0] = '.';
 	strlcat(fpath, path, PATHBUF);
 
-	switch (check_path(fpath, &c->fd)) {
+	switch (check_path(c, fpath, &c->fd)) {
 	case FILE_EXECUTABLE:
 		/* +2 to skip the ./ */
 		if (cgi != NULL && starts_with(fpath+2, cgi))
@@ -431,7 +454,7 @@ open_file(char *path, char *query, struct pollfd *fds,
 
 	case FILE_EXISTS:
 		if ((c->len = filesize(c->fd)) == -1) {
-			LOG(c, "failed to get file size for %s", fpath);
+			LOGE(c, "failed to get file size for %s", fpath);
 			goodbye(fds, c);
 			return 0;
 		}
@@ -446,7 +469,7 @@ open_file(char *path, char *query, struct pollfd *fds,
 		return start_reply(fds, c, SUCCESS, mime(fpath));
 
 	case FILE_DIRECTORY:
-		LOG(c, "%s is a directory, trying %s/index.gmi", fpath, fpath);
+		LOGD(c, "%s is a directory, trying %s/index.gmi", fpath, fpath);
 		close(c->fd);
 		c->fd = -1;
 		send_dir(fpath, fds, c);
@@ -650,7 +673,7 @@ send_file(char *path, char *query, struct pollfd *fds,
 	while (len > 0) {
 		switch (ret = tls_write(c->ctx, c->i, len)) {
 		case -1:
-			LOG(c, "tls_write: %s", tls_error(c->ctx));
+			LOGE(c, "tls_write: %s", tls_error(c->ctx));
 			goodbye(fds, c);
 			return;
 
@@ -709,7 +732,7 @@ handle(struct pollfd *fds, struct client *client)
 		bzero(buf, GEMINI_URL_LEN);
 		switch (tls_read(client->ctx, buf, sizeof(buf)-1)) {
 		case -1:
-			LOG(client, "tls_read: %s", tls_error(client->ctx));
+			LOGE(client, "tls_read: %s", tls_error(client->ctx));
 			goodbye(fds, client);
 			return;
 
@@ -737,7 +760,7 @@ handle(struct pollfd *fds, struct client *client)
 		}
 
 		query = adjust_path(path);
-		LOG(client, "get %s%s%s", path,
+		LOGI(client, "GET %s%s%s", path,
 		    query ? "?" : "",
 		    query ? query : "");
 
@@ -781,9 +804,9 @@ mark_nonblock(int fd)
 	int flags;
 
 	if ((flags = fcntl(fd, F_GETFL)) == -1)
-		err(1, "fcntl(F_GETFL)");
+		FATAL("fcntl(F_GETFL): %s", strerror(errno));
 	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
-		err(1, "fcntl(F_SETFL)");
+		FATAL("fcntl(F_SETFL): %s", strerror(errno));
 }
 
 int
@@ -820,23 +843,23 @@ make_socket(int port, int family)
 	}
 
 	if ((sock = socket(family, SOCK_STREAM, 0)) == -1)
-		err(1, "socket");
+		FATAL("socket: %s", strerror(errno));
 
 	v = 1;
 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) == -1)
-		err(1, "setsockopt(SO_REUSEADDR)");
+		FATAL("setsockopt(SO_REUSEADDR): %s", strerror(errno));
 
 	v = 1;
 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v)) == -1)
-		err(1, "setsockopt(SO_REUSEPORT)");
+		FATAL("setsockopt(SO_REUSEPORT): %s", strerror(errno));
 
 	mark_nonblock(sock);
 
 	if (bind(sock, addr, len) == -1)
-		err(1, "bind");
+		FATAL("bind: %s", strerror(errno));
 
 	if (listen(sock, 16) == -1)
-		err(1, "listen");
+		FATAL("listen: %s", strerror(errno));
 
 	return sock;
 }
@@ -852,7 +875,7 @@ do_accept(int sock, struct tls *ctx, struct pollfd *fd
 	if ((fd = accept(sock, (struct sockaddr*)&addr, &len)) == -1) {
 		if (errno == EWOULDBLOCK)
 			return;
-		err(1, "accept");
+		FATAL("accept: %s", strerror(errno));
 	}
 
 	mark_nonblock(fd);
@@ -931,10 +954,11 @@ loop(struct tls *ctx, int sock)
 	for (;;) {
 		if ((todo = poll(fds, MAX_USERS, INFTIM)) == -1) {
 			if (errno == EINTR) {
-                                warnx("connected clients: %d", connected_clients);
+                                warnx("connected clients: %d",
+				    connected_clients);
 				continue;
 			}
-			err(1, "poll");
+			FATAL("poll: %s", strerror(errno));
 		}
 
 		for (i = 0; i < MAX_USERS; i++) {
@@ -944,7 +968,8 @@ loop(struct tls *ctx, int sock)
 				continue;
 
 			if (fds[i].revents & (POLLERR|POLLNVAL))
-				err(1, "bad fd %d", fds[i].fd);
+				FATAL("bad fd %d: %s", fds[i].fd,
+				    strerror(errno));
 
 			if (fds[i].revents & POLLHUP) {
 				/* fds[i] may be the fd of the stdin
@@ -995,11 +1020,11 @@ main(int argc, char **argv)
 	connected_clients = 0;
 
 	dir = "docs/";
-	logfd = 2;		/* stderr */
 	cgi = NULL;
 	port = 1965;
+	foreground = 0;
 
-	while ((ch = getopt(argc, argv, "c:d:hk:l:p:x:")) != -1) {
+	while ((ch = getopt(argc, argv, "c:d:fhk:p:x:")) != -1) {
 		switch (ch) {
 		case 'c':
 			cert = optarg;
@@ -1009,6 +1034,10 @@ main(int argc, char **argv)
 			dir = optarg;
 			break;
 
+		case 'f':
+			foreground = 1;
+			break;
+
 		case 'h':
 			usage(*argv);
 			return 0;
@@ -1017,13 +1046,6 @@ main(int argc, char **argv)
 			key = optarg;
 			break;
 
-		case 'l':
-			/* open log file or create it with 644 */
-			if ((logfd = open(optarg, O_WRONLY | O_CREAT | O_CLOEXEC,
-					S_IRUSR | S_IWUSR | S_IRGRP | S_IWOTH)) == -1)
-				err(1, "%s", optarg);
-			break;
-
 		case 'p': {
 			char *ep;
 			long lval;
@@ -1076,6 +1098,9 @@ main(int argc, char **argv)
 	if ((dirfd = open(dir, O_RDONLY | O_DIRECTORY)) == -1)
 		err(1, "open: %s", dir);
 
+	if (!foreground && daemon(0, 1) == -1)
+		exit(1);
+
 	if (cgi != NULL) {
 		if (unveil(dir, "rx") == -1)
 			err(1, "unveil");