commit - 677afbd3f873425bcc6f9a23be7efe3066aed70a
commit + d7802bb44a8562917b58bfc76f135ddf4fcbbe3b
blob - 740b34e95d2dc79932dd650941c50b3701f8dd6a
blob + a369acc66378987aa6ee2009bd5eeec86a9cab24
--- ChangeLog
+++ ChangeLog
+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
# SYNOPSIS
**gmid**
-\[**-h**]
+\[**-fh**]
\[**-c** *cert.pem*]
\[**-d** *docs*]
\[**-k** *key.pem*]
-\[**-l** *logfile*]
\[**-p** *port*]
\[**-x** *cgi-bin*]
> By default is
> *docs*.
+**-f**
+
+> stays and log in the foreground, do not daemonize the process.
+
**-h**
> Print the usage and exit.
> 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.
* 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
.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
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
.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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <tls.h>
#include <unistd.h>
{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);
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*);
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;
}
}
int
-check_path(const char *path, int *fd)
+check_path(struct client *c, const char *path, int *fd)
{
struct stat sb;
}
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;
}
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:
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))
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;
}
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);
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;
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;
}
query = adjust_path(path);
- LOG(client, "get %s%s%s", path,
+ LOGI(client, "GET %s%s%s", path,
query ? "?" : "",
query ? query : "");
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
}
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;
}
if ((fd = accept(sock, (struct sockaddr*)&addr, &len)) == -1) {
if (errno == EWOULDBLOCK)
return;
- err(1, "accept");
+ FATAL("accept: %s", strerror(errno));
}
mark_nonblock(fd);
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++) {
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
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;
dir = optarg;
break;
+ case 'f':
+ foreground = 1;
+ break;
+
case 'h':
usage(*argv);
return 0;
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;
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");