commit d7802bb44a8562917b58bfc76f135ddf4fcbbe3b from: Omar Polo date: Wed Dec 02 20:18:01 2020 UTC logging reworked and daemonize by default The -l option was removed: now it logs on syslog if -f (foreground) is not passed. commit - 677afbd3f873425bcc6f9a23be7efe3066aed70a commit + d7802bb44a8562917b58bfc76f135ddf4fcbbe3b blob - 740b34e95d2dc79932dd650941c50b3701f8dd6a blob + a369acc66378987aa6ee2009bd5eeec86a9cab24 --- ChangeLog +++ ChangeLog @@ -1,3 +1,8 @@ +2020-12-02 Omar Polo + + * 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 * 1.3.2 tagged blob - 91d9da971685ea3909deb27798254c548e2353a6 blob + fef69f753d561af468de6f9f41e2b41dc0757cbb --- README.md +++ README.md @@ -6,11 +6,10 @@ # SYNOPSIS **gmid** -\[**-h**] +\[**-fh**] \[**-c** *cert.pem*] \[**-d** *docs*] \[**-k** *key.pem*] -\[**-l** *logfile*] \[**-p** *port*] \[**-x** *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 #include #include +#include #include #include @@ -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");