motsognir109_logmore1.0.diff source

Home
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message

========================================================================
The following patch will turn an unchanged Motsognir v1.0.9 source tree
into a Motsognir v1.0.9+logmore1.0 source tree. 

Put this file into the source directory, chdir to the same directory,
then apply the patch with:

  patch -p1 < motsognir109+logmore1.0.diff

You don't need to trim any text: the patch program knows what to skip.


------------------------------------------------------------------------
Vvv====P:A:T:C:H===F:O:L:L:O:W:S====**====T:H:I:S===S:I:D:E===U:P=======
========================================================================
--- motsognir/NEWS_logmore	        (nonexistent)
+++ motsognir+logmore/NEWS_logmore	2018-08-14 10:24:17.355449379 +0200
@@ -0,0 +1,25 @@
+logmore1.0
+==========
+
+The logmore1.0 patch adds the following features to Motsognir v1.0.9:
+
++ New command line option '--log' allows user to specify either a log
+  file, or a syslog local facility number. This option is also available
+  as new configuration file directive 'log';
+
++ a directory specified on the command line is taken to be the
+  Gopher root;
+
++ standard options '--help', '--version'; plus '--license'.
+
+Motsognir v1.0.9+logmore1.0 was tested on the following systems:
+
++ Void Linux     (x86_64),  kernel 4.17.9_1 SMP PREEMPT,
+                            GNU libc 2.26,  gcc 7.3.0
++ CentOS Linux 7 (x86_64),  kernel 3.10.0   SMP,
+                            GNU libc 2.17,  gcc 4.8.5
+
+-- 
+Dario Niedermann <dario@darioniedermann.it>, 2018-08-14
+
+gopher://darioniedermann.it/  <>  https://www.darioniedermann.it/
========================================================================
--- motsognir/Makefile	2018-08-06 09:52:58.777357833 +0200
+++ motsognir+logmore/Makefile	2018-08-07 11:08:42.019332501 +0200
@@ -1,3 +1,6 @@
+# $Id: Makefile 19 2018-08-07 09:08:41Z ndr $
+
 CC ?= gcc
-CFLAGS += -Wall -Wextra -O3 -std=gnu89 -pedantic -Wformat-security
+CFLAGS += -Wall -Wextra -O3 -std=c99   -pedantic -Wformat-security  \
+					-D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -D_BSD_SOURCE
 
@@ -5,4 +8,4 @@
 
-motsognir: motsognir.o extmap.o
-	$(CC) motsognir.o extmap.o -o motsognir $(CFLAGS)
+motsognir: motsognir.o extmap.o cli.o log.o
+	$(CC) motsognir.o extmap.o cli.o log.o -o motsognir $(CFLAGS)
 
@@ -11,3 +14,3 @@
 
-motsognir.o: motsognir.c
+motsognir.o: motsognir.c motsognir.h extmap.h binary.h log.h
 	$(CC) -c motsognir.c -o motsognir.o $(CFLAGS)
@@ -17,2 +20,6 @@
 
+cli.o:	cli.c log.h motsognir.h
+
+log.o:	log.c log.h motsognir.h
+
 extmaptest: extmaptest.c extmap.o
========================================================================
--- motsognir/cli.c	        (nonexistent)
+++ motsognir+logmore/cli.c	2018-08-06 08:53:02.747462626 +0200
@@ -0,0 +1,202 @@
+/*
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *  *  Motsognir - The mighty gopher server                               *
+ *  *  Copyright (C) 2008-2016 Mateusz Viste                              *
+ *  *  http://motsognir.sourceforge.net                                   *
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Some changes and additions: Copyright (C) 2018 Dario Niedermann
+ *  $Id: cli.c 18 2018-08-06 06:53:02Z ndr $
+ * ----------------------------------------------------------------------
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <err.h>
+#include <sysexits.h>
+#include <syslog.h>
+#include <libgen.h>
+#include <string.h>
+#include "log.h"
+#include "motsognir.h"
+
+#define FALSE  0
+#define TRUE   1
+
+/* declare the default config file location, if not already declared from CLI
+ * at compile-time - esp. useful for systems that store config files in other
+ * locations, like /usr/local/etc/ for FreeBSD... */
+#ifndef CONFIGFILE
+	#define CONFIGFILE "/etc/motsognir.conf"
+#endif
+
+
+static void print_version(void)
+{
+	printf("Motsognir v%s Copyright (C) Mateusz Viste et al. %s\n",
+					pVer, pDate);
+}
+
+
+static void print_usage(char *argv0)
+{
+	printf("Usage: %s [OPTIONS] [DIRECTORY]", basename(argv0));
+	printf("\n\
+Start the Motsognir Gopher server, with DIRECTORY as the Gopher root\n\n\
+Options:\n\
+  -c, --config=FILE         read server configuration from FILE\n\
+  -l, --log=FILE|0..7       log to FILE or syslog local facility #\n\
+  -V, --version             display version information and exit\n\
+  -L, --licence\n\
+      --license             display license and exit\n\
+  -h, --help                display this help text and exit\n\n\
+Command line arguments override configuration file directives.\n\
+Default Gopher root:        /var/gopher/\n\
+Default configuration file: /etc/motsognir.conf\n");
+}
+
+
+static void about(void) {
+	print_version();
+
+	printf("\n\
+This program is free software: you can redistribute it and/or modify it under\n\
+the terms of the GNU General Public License as published by the Free Software\n\
+Foundation, either version 3 of the License, or (at your option) any later\n\
+version.\n");
+
+	printf("\
+This program is distributed in the hope that it will be useful, but WITHOUT ANY\n\
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n\
+PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\n\
+Motsognir is a robust and reliable open-source gopher server for POSIX systems.\n\
+Motsognir is entirely written in ISO C99, without any external dependencies.\n\n");
+
+	printf("Homepage: %s\n", HOMEPAGE);
+}
+
+
+static int configLogging(char *dest, struct logParams *logConf)
+{
+	static char timesHere = 0;
+	int status = EXIT_SUCCESS;
+
+	if (++timesHere == 1) {   /* I'll only configure ONCE: from the cmd line
+															 if specified, from config file otherwise. */
+		if (dest[1] == '\0' && dest[0] <= '7' && dest[0] >= '0') {
+				/* destination is a syslog local facility number */
+			logConf->loggingType = TO_SYSLOG;
+				/* reduce the 1st -and last- char in dest to a 0 to 7 value, use
+					 it as an index to look up the facility value in the array */
+			logConf->facility = logConf->localFacility[dest[0]-'0'];
+		}
+		else {  /* option's arg is -arguably- a file name */
+			logConf->loggingType = TO_FILE;
+			logConf->fileName = dest;
+		}
+	}
+	else status = EX_DATAERR;
+
+	return status;
+}
+
+
+int parseCmdLine(char mode, int myArgc, char **myArgv,
+								 struct MotsognirConfig *confStruct)
+{
+	#define DONE_PARSING    -1         /* getopt_long() returns -1 when done */
+	static struct option long_options[] = {
+		{"config",  required_argument, NULL, 'c'},
+		{"help",    no_argument,       NULL, 'h'},
+		{"licence", no_argument,       NULL, 'L'},
+		{"license", no_argument,       NULL, 'L'},
+		{"log",     required_argument, NULL, 'l'},
+		{"version", no_argument,       NULL, 'V'},
+		{0,         0,                 0,     0 }
+	};
+	static struct logParams logConf;
+		/* since LOG_LOCALn symbols might (in theory) have any value, let's put
+			 them in order into an array, where we can refer to them by index   */
+	static int localFacilities[] = {  LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2,
+																		LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5,
+																		LOG_LOCAL6, LOG_LOCAL7  };
+	int c,  option_index,  this_option = 0,  status = EXIT_SUCCESS;
+
+	if (mode == FIRST_PASS) {   /* Do some one-time setup: */
+		confStruct->configfile  = CONFIGFILE;
+		logConf.loggingType     = TO_SYSLOG;
+		logConf.facility        = LOG_DAEMON;
+		logConf.fileName        = NULL;
+		logConf.localFacility   = localFacilities;
+	}
+
+	optind=1; while (status == EXIT_SUCCESS) {
+		this_option = optind ? optind : 1;
+		option_index = 0;
+
+		c = getopt_long(myArgc, myArgv, ":c:hLl:V", long_options, &option_index);
+		if (c == DONE_PARSING) break;
+
+		switch (c) {
+			case 'c':
+				confStruct->configfile  =  optarg;                              break;
+
+			case 'h':
+				print_usage(myArgv[0]); status = OK_EXIT_NOW;                   break;
+
+			case 'L':
+				about();                status = OK_EXIT_NOW;                   break;
+
+			case 'l':
+				if (configLogging(optarg, &logConf))
+						/* if configLogging is called >1 time, it'll error out */
+					if (mode != LAST_PASS)
+						warnx("further logging destination '%s' ignored", optarg);
+																																				break;
+			case 'V':
+				print_version();        status = OK_EXIT_NOW;                   break;
+
+			case '?':
+				warnx("unrecognized option '%s'", myArgv[this_option]);
+				print_usage(myArgv[0]); status = EX_USAGE;                      break;
+
+			case ':':
+				warnx("option '%s' requires an argument",
+								myArgv[this_option]);
+																status = EX_USAGE;                      break;
+
+			default:                  /* should never happen... */
+				warnx("internal error while parsing command line, char code 0%o", c);
+																status = EX_SOFTWARE;
+		}
+	}
+
+	/* init the logging functions, either with default values,
+		 or values from the command line: */
+	logme(INIT, NO_MSG, &logConf);
+
+	/* non-option args at the end of cmd line? */
+	if (mode == LAST_PASS)    /* only deal with them the last time I'm called */
+		for (c=0; optind < myArgc && c < 256; c++, optind++) {
+			if (!c)       /* the 1st will be our gopher root */
+				confStruct->gopherroot = myArgv[optind];
+			else
+				warnx("ignoring trailing argument: '%s'", myArgv[optind]);
+		}
+
+	return status; 
+}
========================================================================
--- motsognir/log.c	        (nonexistent)
+++ motsognir+logmore/log.c	2018-08-05 17:37:50.420143737 +0200
@@ -0,0 +1,151 @@
+/*
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *  *  Motsognir - The mighty gopher server                               *
+ *  *  Copyright (C) 2008-2016 Mateusz Viste                              *
+ *  *  http://motsognir.sourceforge.net                                   *
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Some changes and additions: Copyright (C) 2018 Dario Niedermann
+ *  $Id: log.c 15 2018-08-05 15:37:50Z ndr $
+ * ----------------------------------------------------------------------
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <err.h>
+#include <sysexits.h>
+#include <assert.h>
+#include "motsognir.h"
+#include "log.h"
+
+#define MAX_MSGLEN  2048  /* max bytes in a single log entry */
+
+struct logWritersParams {
+	int   level,
+				facility;
+	char  *fileName,
+				*prefix,
+				*msg;
+	FILE  *filePtr;
+};
+
+static int logToFile(struct logWritersParams *params)
+{
+	int status;
+
+	status = EXIT_SUCCESS;
+	if (params->filePtr == NULL)
+		if ((params->filePtr = fopen(params->fileName, "a")) == NULL)
+			return EX_CANTCREAT;
+	/* else... */
+	if (params->prefix != NULL)
+		if (fprintf(params->filePtr, "%s ", params->prefix) < 1)
+			status = EX_IOERR;
+
+	if ((fprintf(params->filePtr, "%s\n", params->msg) < 1)
+			 || fflush(params->filePtr))
+					status = EX_IOERR;
+
+	if (status == EX_IOERR) fclose(params->filePtr);
+	return status;
+}
+
+
+static int logToSyslog(struct logWritersParams *params)
+{ 
+	assert(params->level >= LOG_EMERG && params->level <= LOG_DEBUG);
+	assert((params->facility >= LOG_LOCAL0 && params->facility <= LOG_LOCAL7)
+																				 || params->facility == LOG_DAEMON);
+	syslog(params->level | params->facility,  "%s", params->msg);
+	return 0;
+}
+
+
+void logme(int level, const char *fmt, ...)
+{
+	va_list argPtr;           /* points to the list of unnamed args */
+	static  struct logWritersParams logWritersSettings;
+	static  char msg[MAX_MSGLEN],  whereToLog;
+	static  int (*writerFunc)() =  NULL;
+	struct  logParams             *logSettings;
+	int     msgLen;
+	char   *clientIP;
+
+	va_start(argPtr, fmt);    /* make argPtr point to 1st unnamed arg */
+
+	switch (level) {
+		case INIT:
+		/* If I'm called with pseudo-level INIT, I won't log a message: instead
+			 I'll regard 1st unnamed passed-in arg as a pointer to a logParams struct.
+			 Spares the need of being passed a config struct by every func calling me
+		*/
+			assert(fmt==NO_MSG);  /* or there must be collision with INIT's value */
+			logWritersSettings.msg  = msg;        /* never to be changed */
+			logSettings = va_arg(argPtr, struct logParams *);
+				/* mk our static copys of settings (passed-in struc may be destroyd) */
+			whereToLog = logSettings->loggingType;
+			assert(whereToLog==TO_FILE||whereToLog==TO_SYSLOG);
+			logWritersSettings.facility = logSettings->facility;
+				/* no need to alloc -- points to somewhere in argv[] if it came from
+					 a command line opt, or to a strdup'ed string if from config file: */
+			logWritersSettings.fileName = logSettings->fileName;
+			logWritersSettings.filePtr  = NULL;
+
+			/* pick function according to message destination -- file or syslog */
+			writerFunc = (whereToLog == TO_FILE) ? logToFile : logToSyslog;
+			break;
+
+		case SET_PREFIX:
+		/* This pseudo-level means I'll set the common prefix to log entries.
+			 The 1st unnamed passed-in arg must now be a connected client's IP,
+			 because I only get called this way when a new client connects.
+			 The 2nd unnamed arg points to a char array that will contain the prefix.
+		*/
+			assert(writerFunc != NULL);  /* I must've been previously INIT'ed */
+			clientIP = va_arg(argPtr, char *);
+			logWritersSettings.prefix = va_arg(argPtr, char *);
+			sprintf(logWritersSettings.prefix, fmt, clientIP);
+			if (whereToLog == TO_SYSLOG) {
+				/* set up the logging to log with PID and peer's IP address */
+				openlog(logWritersSettings.prefix, LOG_PID,
+								logWritersSettings.facility);
+			}
+			else
+				assert(whereToLog == TO_FILE);
+			break;
+
+		default:                       /* an actual syslog level */
+			assert(level >= LOG_EMERG && level <= LOG_DEBUG);
+			logWritersSettings.level = level;
+					/* turn fmt and any following args into a fixed string in msg: */
+			msgLen = vsnprintf(msg, MAX_MSGLEN, fmt, argPtr); 
+					/* write msg to log: */
+			while ((*writerFunc)(&logWritersSettings)) {
+					/* got error. From logToFile() 'cause logToSyslog() only returns 0 */
+				whereToLog = TO_SYSLOG;
+					/* facility must still be as initially,since we were loggin'to file*/
+				assert(logWritersSettings.facility == LOG_DAEMON);
+				writerFunc = logToSyslog;
+				LOG(ERR,"Could not write to log file '%s' -- reverting to syslog",
+									logWritersSettings.fileName);
+			}
+			if (msgLen >= MAX_MSGLEN)
+				LOG(WARNING,"previous log message was truncated");
+	}
+	va_end(argPtr);                  /* clean up va_ stuff */
+}
========================================================================
--- motsognir/log.h	        (nonexistent)
+++ motsognir+logmore/log.h	2018-08-05 17:37:50.423144093 +0200
@@ -0,0 +1,29 @@
+/*
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *  *  Motsognir - The mighty gopher server                               *
+ *  *  Copyright (C) 2008-2016 Mateusz Viste                              *
+ *  *  http://motsognir.sourceforge.net                                   *
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Some changes and additions: Copyright (C) 2018 Dario Niedermann
+ *  $Id: log.h 15 2018-08-05 15:37:50Z ndr $
+ * ----------------------------------------------------------------------
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ----------------------------------------------------------------------
+ */
+
+#define LOG(level, ...) logme(LOG_##level, __VA_ARGS__)
+#define NO_MSG          NULL
+
+void logme(int level, const char *fmt, ...);
========================================================================
--- motsognir/motsognir.c	2018-08-06 09:52:59.080393386 +0200
+++ motsognir+logmore/motsognir.c	2018-08-05 17:37:50.430144924 +0200
@@ -7,2 +7,4 @@
  *
+ *  Some changes and additions: Copyright (C) 2018 Dario Niedermann
+ *  $Id: motsognir.c 15 2018-08-05 15:37:50Z ndr $
  * ----------------------------------------------------------------------
@@ -29,3 +31,2 @@
 #include <pwd.h>
-#include <regex.h>   /* regcomp(), regexec()... */
 #include <signal.h>
@@ -48,47 +49,8 @@
 #include "extmap.h"
+#include "motsognir.h"
+#include "log.h"
 
-/* Constants */
-#define pVer "1.0.9"
-#define pDate "2008-2016"
-#define HOMEPAGE "http://motsognir.sourceforge.net"
-
-/* declare the default config file location, if not already declared from CLI
- * at compile-time - esp. useful for systems that store config files in other
- * locations, like /usr/local/etc/ for FreeBSD... */
-#ifndef CONFIGFILE
-  #define CONFIGFILE "/etc/motsognir.conf"
-#endif
-
-
-struct MotsognirConfig {
-  char *gopherroot;
-  char *userdir;
-  char **pubdirlist;
-  int gopherport;
-  char *gopherhostname;
-  char *defaultgophermap;
-  int verbosemode;
-  int capssupport;
-  char *capsservergeolocationstring;
-  char *capsserverarchitecture;
-  char *capsserverdescription;
-  char *capsserverdefaultencoding;
-  int cgisupport;
-  int phpsupport;
-  int subgophermaps;
-  int paranoidmode;
-  char *plugin;
-  regex_t *pluginfilter;
-  char *runasuser;
-  uid_t runasuser_uid;
-  gid_t runasuser_gid;
-  char *runasuser_home;
-  char *chroot;
-  char *httperrfile;
-  char *bind;
-  char *extmapfile;
-  struct extmap_t *extmap;
-  char securldelim;
-};
-
+/* implementation in 'cli.c': */
+int parseCmdLine(char mode, int argc, char **argv,
+								 struct MotsognirConfig *confStruct);
 
@@ -157,3 +119,3 @@
   if (initgroups(config->runasuser, config->runasuser_gid) != 0 || setgid(config->runasuser_gid) != 0 || setuid(config->runasuser_uid) != 0) {
-    syslog(LOG_WARNING, "ERROR: Couldn't change to '%.32s' uid=%lu gid=%lu: %s", config->runasuser, (unsigned long)config->runasuser_uid, (unsigned long)config->runasuser_gid, strerror(errno));
+		LOG(WARNING,"ERROR: Couldn't change to '%.32s' uid=%lu gid=%lu: %s", config->runasuser, (unsigned long)config->runasuser_uid, (unsigned long)config->runasuser_gid, strerror(errno));
     return(-1);
@@ -162,3 +124,3 @@
   if (getuid() != config->runasuser_uid) {
-    syslog(LOG_WARNING, "ERROR: For some mysterious reasons Motsognir was unable to switch to user '%s'.", config->runasuser);
+		LOG(WARNING,"ERROR: For some mysterious reasons Motsognir was unable to switch to user '%s'.", config->runasuser);
     return(-1);
@@ -369,3 +331,3 @@
     if (dstlen + 4 >= dstmaxlen) {
-      syslog(LOG_WARNING, "WARNING: reached percent encoding length limit - aborting");
+			LOG(WARNING,"WARNING: reached percent encoding length limit - aborting");
       break; /* stop the work if we reached our limit */
@@ -450,3 +412,3 @@
       string[x] = 0;
-      syslog(LOG_WARNING, "ERROR: detected invalid percent encoding");
+			LOG(WARNING,"ERROR: detected invalid percent encoding");
       return(-1);
@@ -456,3 +418,3 @@
       string[x] = 0;
-      syslog(LOG_WARNING, "ERROR: detected a dangerous percent encoding (%%00)");
+			LOG(WARNING,"ERROR: detected a dangerous percent encoding (%%00)");
       return(-1);
@@ -464,3 +426,3 @@
       string[x - 2] = 0;
-      syslog(LOG_WARNING, "ERROR: detected an invalid percent encoding");
+			LOG(WARNING,"ERROR: detected an invalid percent encoding");
       return(-1);
@@ -516,23 +478,5 @@
 
-static void about(char *version, char *datestring, char *homepage) {
-  printf("Motsognir v%s Copyright (C) Mateusz Viste %s\n\n", version, datestring);
-  printf("This program is free software: you can redistribute it and/or modify it under\n"
-         "the terms of the GNU General Public License as published by the Free Software\n"
-         "Foundation, either version 3 of the License, or (at your option) any later\n"
-         "version.\n");
-  printf("This program is distributed in the hope that it will be useful, but WITHOUT ANY\n"
-         "WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n"
-         "PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\n");
-  printf("Motsognir is a robust and reliable open-source gopher server for POSIX systems.\n"
-         "Motsognir is entirely written in ANSI C, without any external dependencies.\n\n");
-  printf("Available command-line parameters:\n"
-         "  --config file.conf       use a configuration file in a custom location\n"
-         "\n");
-  printf("homepage: %s\n\n", homepage);
-}
-
-
 static void sendbackhttperror(int sock, struct MotsognirConfig *config) {
   char txtline[1024], portstr[16];
-  syslog(LOG_INFO, "HTTP request detected - a HTTP error message is returned");
+	LOG(INFO,"HTTP request detected - a HTTP error message is returned");
   sendline(sock, "HTTP/1.1 400 Bad request");
@@ -574,3 +518,3 @@
   char txtline[1024];
-  syslog(LOG_INFO, "GOPHER+ request detected - a gopher+ fake redirector is returned");
+	LOG(INFO,"GOPHER+ request detected - a gopher+ fake redirector is returned");
   sendline(sock, "+-1");
@@ -595,3 +539,3 @@
     if (res == NULL) {
-      syslog(LOG_ERR, "ERROR: OUT OF MEMORY ON LINE #%d", __LINE__);
+			LOG(ERR,"ERROR: OUT OF MEMORY ON LINE #%d", __LINE__);
       return(res);
@@ -618,3 +562,3 @@
 
-static int loadconfig(struct MotsognirConfig *config, char *configfile) {
+static int loadconfig(struct MotsognirConfig *config) {
   FILE *fd;
@@ -623,8 +567,6 @@
   int valuebuffpos = 0;
-  int bytebuff;
+	int bytebuff, priv_argc;
   int state = 0; /* 0=reading token, 1=reading value, 2=reading comment */
   struct passwd *pw;
-
-  /* zero out the config structure, just in case */
-  memset(config, 0, sizeof(*config));
+	char *priv_argv[3];
 
@@ -659,5 +601,5 @@
 
-  fd = fopen(configfile, "r");
+	fd = fopen(config->configfile, "r");
   if (fd == NULL) {
-    syslog(LOG_WARNING, "WARNING: Failed to open the configuration file at '%s'", configfile);
+		LOG(WARNING,"WARNING: Failed to open the configuration file at '%s'", config->configfile);
     return(-1);
@@ -729,5 +671,5 @@
           if (config->pluginfilter == NULL) {
-            syslog(LOG_ERR, "ERROR: Out of memory while trying to allocate regex space!");
+						LOG(ERR,"ERROR: Out of memory while trying to allocate regex space!");
           } else if (regcomp(config->pluginfilter, valuebuff, REG_EXTENDED | REG_NOSUB) != 0) {
-            syslog(LOG_ERR, "ERROR: Invalid PluginFilter regex!");
+						LOG(ERR,"ERROR: Invalid PluginFilter regex!");
             free(config->pluginfilter);
@@ -743,3 +685,3 @@
           config->httperrfile = readfiletomem(valuebuff);
-          if (config->httperrfile == NULL) syslog(LOG_WARNING, "WARNING: Failed to load custom http error file '%s'. Default content will be used instead.", valuebuff);
+					if (config->httperrfile == NULL) LOG(WARNING,"WARNING: Failed to load custom http error file '%s'. Default content will be used instead.", valuebuff);
         } else if (strcasecmp(tokenbuff, "ExtMapFile") == 0) {
@@ -748,2 +690,6 @@
           config->securldelim = atoi(valuebuff);
+				} else if (strcasecmp(tokenbuff, "log") == 0) {
+							/* simulate a '-l ARG' given on command line */
+						priv_argc=3; priv_argv[1]="-l"; priv_argv[2]=strdup(valuebuff);
+						parseCmdLine(FROM_FILE, priv_argc, priv_argv, config);
         }
@@ -765,3 +711,3 @@
   if (config->verbosemode < 0) {
-    syslog(LOG_ERR, "ERROR: Invalid verbose level found in the configuration file (%d)", config->verbosemode);
+		LOG(ERR,"ERROR: Invalid verbose level found in the configuration file (%d)", config->verbosemode);
     return(-1);
@@ -770,3 +716,3 @@
   if (config->gopherport < 1) {
-    syslog(LOG_ERR, "ERROR: Invalid gopher port found in the configuration file (%d)", config->gopherport);
+		LOG(ERR,"ERROR: Invalid gopher port found in the configuration file (%d)", config->gopherport);
     return(-1);
@@ -775,3 +721,3 @@
   if (config->gopherroot[0] == 0) {
-    syslog(LOG_ERR, "ERROR: Missing gopher root path in the configuration file. Please add a valid 'GopherRoot=' directive");
+		LOG(ERR,"ERROR: Missing gopher root path in the configuration file. Please add a valid 'GopherRoot=' directive");
     return(-1);
@@ -782,3 +728,3 @@
     if ((config->userdir[0] != '/') || (strstr(config->userdir, "%s") == NULL)) {
-      syslog(LOG_ERR, "ERROR: The UserDir configuration is invalid. It shall be an absolute path (start by '/') and contain the '%%s' placeholder.");
+			LOG(ERR,"ERROR: The UserDir configuration is invalid. It shall be an absolute path (start by '/') and contain the '%%s' placeholder.");
       return(-1);
@@ -788,3 +734,3 @@
   if (config->gopherhostname == NULL) {
-    syslog(LOG_WARNING, "WARNING: Missing gopher hostname in the configuration file. The local IP address will be used instead. Please add a valid 'GopherHostname=' directive.");
+		LOG(WARNING,"WARNING: Missing gopher hostname in the configuration file. The local IP address will be used instead. Please add a valid 'GopherHostname=' directive.");
   }
@@ -794,3 +740,3 @@
   if (config->extmap == NULL) {
-    syslog(LOG_ERR, "ERROR: failed to load the extension mapping file '%s'", config->extmapfile);
+		LOG(ERR,"ERROR: failed to load the extension mapping file '%s'", config->extmapfile);
     return(-1);
@@ -802,3 +748,3 @@
     if (pw == NULL) {
-      syslog(LOG_ERR, "ERROR: Could not map the username '%s' to a valid uid", config->runasuser);
+			LOG(ERR,"ERROR: Could not map the username '%s' to a valid uid", config->runasuser);
       return(-1);
@@ -849,3 +795,3 @@
   /* Retrieve server-side parameters */
-  syslog(LOG_INFO, "Got following server-side parameters: %s | %s", res[0], res[1]);
+	LOG(INFO,"Got following server-side parameters: %s | %s", res[0], res[1]);
   return(res); /* return the array with params */
@@ -893,3 +839,3 @@
     if ((timeoutStartTime != NULL) && (time(NULL) - *timeoutStartTime >= 10)) {
-      syslog(LOG_INFO, "Request takes too long to come. Connection aborted.");
+			LOG(INFO,"Request takes too long to come. Connection aborted.");
       return(-1);
@@ -931,3 +877,3 @@
   char linebuff[1024];
-  syslog(LOG_INFO, "The request is asking for a URL redirection - returned a html document redirecting to '%s'", rawurl);
+	LOG(INFO,"The request is asking for a URL redirection - returned a html document redirecting to '%s'", rawurl);
   sendline(sock, "<!DOCTYPE html>");
@@ -977,3 +923,3 @@
   if (dirptr == NULL) {
-    syslog(LOG_WARNING, "ERROR: Could not access directory '%s' (%s)", localfile, strerror(errno));
+		LOG(WARNING,"ERROR: Could not access directory '%s' (%s)", localfile, strerror(errno));
     sendline(sock, "3Error: could not access directory\tfake\tfake\t0");
@@ -985,3 +931,3 @@
   if (direntriescount < 0) {
-    syslog(LOG_WARNING, "ERROR: Failed to scan the directory '%s': %s", localfile, strerror(errno));
+		LOG(WARNING,"ERROR: Failed to scan the directory '%s': %s", localfile, strerror(errno));
     return;
@@ -989,3 +935,3 @@
 
-  syslog(LOG_INFO, "Found %d items in '%s'", direntriescount, localfile);
+	LOG(INFO,"Found %d items in '%s'", direntriescount, localfile);
 
@@ -1095,5 +1041,5 @@
   if ((srvsideparams[0] != NULL) || (srvsideparams[1] != NULL)) {
-    syslog(LOG_INFO, "running server-side app '%s' with queries '%s' + '%s'", localfile, srvsideparams[0], srvsideparams[1]);
+		LOG(INFO,"running server-side app '%s' with queries '%s' + '%s'", localfile, srvsideparams[0], srvsideparams[1]);
   } else {
-    syslog(LOG_INFO, "running server-side app '%s'", localfile);
+		LOG(INFO,"running server-side app '%s'", localfile);
   }
@@ -1127,3 +1073,3 @@
   if (cgifd == NULL) {
-    syslog(LOG_WARNING, "ERROR: failed to run the server-side app '%s'", localfile);
+		LOG(WARNING,"ERROR: failed to run the server-side app '%s'", localfile);
     return(0);
@@ -1147,3 +1093,3 @@
       if (explodegophermapline(tmpstring, &itemtype, itemdesc, itemselector, itemserver, &itemport) != 0) {
-        syslog(LOG_WARNING, "ERROR: dynamic gophermap processing aborted due to failure to interpret its output as being a gophermap line (%s)", localfile);
+				LOG(WARNING,"ERROR: dynamic gophermap processing aborted due to failure to interpret its output as being a gophermap line (%s)", localfile);
         break;
@@ -1166,5 +1112,5 @@
   if (res == -1) {
-    syslog(LOG_WARNING, "WARNING: call to server-side app '%s' failed (%s)", localfile, strerror(errno));
+		LOG(WARNING,"WARNING: call to server-side app '%s' failed (%s)", localfile, strerror(errno));
   } else if (WEXITSTATUS(res) != 0) {
-    syslog(LOG_WARNING, "WARNING: server-side app '%s' terminated with a non-zero exit code (%d)", localfile, WEXITSTATUS(res));
+		LOG(WARNING,"WARNING: server-side app '%s' terminated with a non-zero exit code (%d)", localfile, WEXITSTATUS(res));
   }
@@ -1194,6 +1140,6 @@
   if (gophermapfd == NULL) {
-    syslog(LOG_WARNING, "ERROR: Failed to open the gophermap at '%s' (%s)", gophermapfile, strerror(errno));
+		LOG(WARNING,"ERROR: Failed to open the gophermap at '%s' (%s)", gophermapfile, strerror(errno));
     return;
   }
-  syslog(LOG_INFO, "Response=\"Return gophermap. (%s)", gophermapfile);
+	LOG(INFO,"Response=\"Return gophermap. (%s)", gophermapfile);
 
@@ -1217,3 +1163,3 @@
         if (realscriptname == NULL) {
-          syslog(LOG_WARNING, "WARNING: Failed to resolve the path to '%s'", itemdesc);
+					LOG(WARNING,"WARNING: Failed to resolve the path to '%s'", itemdesc);
         } else {
@@ -1240,3 +1186,3 @@
   char gophermapfile[1024];
-  syslog(LOG_INFO, "The resource is a directory");
+	LOG(INFO,"The resource is a directory");
   if (lastcharofstring(localfile) != '/') strcat(localfile, "/");
@@ -1274,3 +1220,3 @@
     /* no gophermap found, simply list files & directories */
-    syslog(LOG_INFO, "No gophermap found. Listing directory content");
+		LOG(INFO,"No gophermap found. Listing directory content");
     outputdircontent(sock, config, localfile, directorytolist);
@@ -1297,3 +1243,3 @@
   if (sockmaster < 0) {
-    syslog(LOG_WARNING, "FATAL ERROR: socket could not be open (%s)", strerror(errno));
+		LOG(WARNING,"FATAL ERROR: socket could not be open (%s)", strerror(errno));
     return(-2);
@@ -1302,3 +1248,3 @@
   /* I set the socket to be reusable, to avoid having to wait for a longish time when the server is restarted */
-  if (setsockopt(sockmaster, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) syslog(LOG_WARNING, "WARNING: failed to set REUSEADDR on main socket");
+	if (setsockopt(sockmaster, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) LOG(WARNING,"WARNING: failed to set REUSEADDR on main socket");
 
@@ -1311,3 +1257,3 @@
     if (inet_pton(AF_INET6, config->bind, &(serv_addr.sin6_addr)) != 1) {
-      syslog(LOG_WARNING, "FATAL ERROR: failed to parse the IP address bind value. Please check your 'bind' configuration.");
+			LOG(WARNING,"FATAL ERROR: failed to parse the IP address bind value. Please check your 'bind' configuration.");
       return(-2);
@@ -1327,3 +1273,3 @@
   if (bind(sockmaster, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
-    syslog(LOG_WARNING, "FATAL ERROR: binding failed (%s)", strerror(errno));
+		LOG(WARNING,"FATAL ERROR: binding failed (%s)", strerror(errno));
     return(-2);
@@ -1341,3 +1287,3 @@
 
-  syslog(LOG_INFO, "motsognir v" pVer " process started");
+	LOG(INFO,"motsognir v" pVer " process started");
 
@@ -1352,3 +1298,3 @@
     close(sockmaster);
-    syslog(LOG_WARNING, "Failed to dameonize the motsognir process (%s)", strerror(errno));
+		LOG(WARNING,"Failed to dameonize the motsognir process (%s)", strerror(errno));
     return(-2);
@@ -1365,3 +1311,3 @@
   /* I want to be the pack master now (aka session leader) */
-  if (setsid() == -1) syslog(LOG_WARNING, "WARNING: setsid() failed (%s)", strerror(errno));
+	if (setsid() == -1) LOG(WARNING,"WARNING: setsid() failed (%s)", strerror(errno));
 
@@ -1371,3 +1317,3 @@
     if (chroot(config->chroot) != 0) {
-      syslog(LOG_WARNING, "Failed to chroot(): %s", strerror(errno));
+			LOG(WARNING,"Failed to chroot(): %s", strerror(errno));
       return(-2);
@@ -1377,3 +1323,3 @@
   /* set the working directory to the root directory */
-  if (chdir ("/") == -1) syslog(LOG_WARNING, "WARNING: failed to switch to / directory (%s)", strerror(errno));
+	if (chdir ("/") == -1) LOG(WARNING,"WARNING: failed to switch to / directory (%s)", strerror(errno));
 
@@ -1385,3 +1331,3 @@
     if (getuid() != 0) {
-      syslog(LOG_WARNING, "A 'RunAsUser' directive has been configured, but the process has not been launched under root account. The 'RunAsUser' directive is therefore ignored.");
+			LOG(WARNING,"A 'RunAsUser' directive has been configured, but the process has not been launched under root account. The 'RunAsUser' directive is therefore ignored.");
     } else { /* if I'm root, drop off privileges */
@@ -1390,3 +1336,3 @@
       } else {
-        syslog(LOG_WARNING, "Successfully dropped root privileges. Motsognir runs as user '%s' now.", config->runasuser);
+				LOG(WARNING,"Successfully dropped root privileges. Motsognir runs as user '%s' now.", config->runasuser);
       }
@@ -1399,3 +1345,3 @@
     if (sockslave < 0) {
-      syslog(LOG_WARNING, "FATAL ERROR: accepting connection failed (%s)", strerror(errno));
+			LOG(WARNING,"FATAL ERROR: accepting connection failed (%s)", strerror(errno));
       close(sockmaster);
@@ -1410,3 +1356,3 @@
       if (inet_ntop(cli_addr.sin6_family, &cli_addr.sin6_addr, clientipaddrstr, clientipaddrstr_maxlen) == NULL) {
-        syslog(LOG_WARNING, "Failed to fetch client's IP address: %s", strerror(errno));
+				LOG(WARNING,"Failed to fetch client's IP address: %s", strerror(errno));
         sprintf(clientipaddrstr, "UNKNOWN");
@@ -1416,3 +1362,3 @@
       if ((getsockname(sockslave, (struct sockaddr *) &serv_addr, &clilen) < 0) || (inet_ntop(serv_addr.sin6_family, &serv_addr.sin6_addr, serveripaddrstr, serveripaddrstr_maxlen) == NULL)) {
-        syslog(LOG_WARNING, "Failed to fetch server's IP address: %s", strerror(errno));
+				LOG(WARNING,"Failed to fetch server's IP address: %s", strerror(errno));
         sprintf(serveripaddrstr, "UNKNOWN");
@@ -1423,5 +1369,4 @@
       /* set logprefix to contain the client's address */
-      sprintf(logprefix, "motsognir [%s]", clientipaddrstr);
-      openlog(logprefix, LOG_PID, LOG_DAEMON); /* set up the logging to log with PID and peer's IP address */
-      syslog(LOG_INFO, "new connection to %s", serveripaddrstr);
+			logme(SET_PREFIX, "motsognir [%s]", clientipaddrstr, logprefix);
+			LOG(INFO,"new connection to %s", serveripaddrstr);
       /* if no gopher hostname was set, use the server's address */
@@ -1435,3 +1380,3 @@
     } else { /* error condition */
-      syslog(LOG_WARNING, "FATAL ERROR: fork() failed!");
+			LOG(WARNING,"FATAL ERROR: fork() failed!");
       close(sockslave);
@@ -1452,3 +1397,3 @@
   if (linebuff == NULL) {
-    syslog(LOG_WARNING, "ERROR: Out of memory while trying to allocate buffer for file");
+		LOG(WARNING,"ERROR: Out of memory while trying to allocate buffer for file");
     return;
@@ -1457,3 +1402,3 @@
   if (fd == NULL) { /* file could not be opened */
-    syslog(LOG_WARNING, "ERROR: File '%s' could not be opened", filename);
+		LOG(WARNING,"ERROR: File '%s' could not be opened", filename);
     free(linebuff);
@@ -1478,3 +1423,3 @@
   if (buff == NULL) {
-    syslog(LOG_WARNING, "ERROR: Out of memory while trying to allocate buffer for file");
+		LOG(WARNING,"ERROR: Out of memory while trying to allocate buffer for file");
     return;
@@ -1483,3 +1428,3 @@
   if (fd == NULL) { /* file could not be opened */
-    syslog(LOG_WARNING, "ERROR: File '%s' could not be opened", filename);
+		LOG(WARNING,"ERROR: File '%s' could not be opened", filename);
     free(buff);
@@ -1526,3 +1471,3 @@
   }
-  syslog(LOG_WARNING, "Evasion check: path '%s' (%s) seem to belong to neither '%s' nor any entry of the pubdir list", localfile, resolvedpath, gopherroot);
+	LOG(WARNING,"Evasion check: path '%s' (%s) seem to belong to neither '%s' nor any entry of the pubdir list", localfile, resolvedpath, gopherroot);
   return(1);
@@ -1618,3 +1563,3 @@
   if ((curdir == NULL) || (chdir(curdir) == -1)) {
-    syslog(LOG_WARNING, "WARNING: failed to switch current directory to %s (%s), original resource: %s", curdir, strerror(errno), s);
+		LOG(WARNING,"WARNING: failed to switch current directory to %s (%s), original resource: %s", curdir, strerror(errno), s);
     res = -1;
@@ -1642,4 +1587,3 @@
   char gophertype;
-  char *configfile = CONFIGFILE;
-  int sock;
+	int sock, status;
   struct MotsognirConfig config;
@@ -1647,17 +1591,11 @@
 
-  if (argc > 1) {
-    int x;
-    for (x = 1; x < argc; x++) {
-      if (strcmp(argv[x], "--config") == 0) {
-        x++;
-        if (x < argc) configfile = argv[x];
-      } else { /* unknown command line */
-        about(pVer, pDate, HOMEPAGE);
-        return(1);
-      }
-    }
-  }
+	/* zero out the config structure, just in case */
+	memset(&config, 0, sizeof(config));
+
+	if ((status = parseCmdLine(FIRST_PASS, argc, argv, &config)) != EXIT_SUCCESS)
+		return (status==OK_EXIT_NOW) ? EXIT_SUCCESS : status;
 
+	/* else... */
   /* load motsognir's configuration from file */
-  if (loadconfig(&config, configfile) != 0) {
+	if (loadconfig(&config) != 0) {
     puts("ERROR: A configuration error has been detected. Check the logs for details.");
@@ -1665,2 +1603,7 @@
   }
+		/* Again?! Yep... Command line args must override config file
+			 directives. But we also needed a 1st pass to possibly learn
+			 where the config file was... */
+	if ((status = parseCmdLine(LAST_PASS, argc, argv, &config)) != EXIT_SUCCESS)
+		return (status==OK_EXIT_NOW) ? EXIT_SUCCESS : status;
 
@@ -1676,3 +1619,3 @@
   if (sockreadline(sock, directorytolist, sizeof(directorytolist), &StartTime) < 0) {
-    syslog(LOG_WARNING, "Error during selector receiving phase. Connection aborted.");
+		LOG(WARNING,"Error during selector receiving phase. Connection aborted.");
     close(sock);
@@ -1680,3 +1623,3 @@
   }
-  syslog(LOG_INFO, "Query='%s'", directorytolist);
+	LOG(INFO,"Query='%s'", directorytolist);
   if (directorytolist[0] == 0) {   /* Empty request means "gimme the root listing" */
@@ -1698,3 +1641,3 @@
     if (res > 0) {
-      syslog(LOG_INFO, "Query handled by plugin (%s)", config.plugin);
+			LOG(INFO,"Query handled by plugin (%s)", config.plugin);
       drainsock(sock);  /* read whatever request the peer sent us, to drain the socket before closing it (otherwise the tcp stack would trigger a ugly RST) */
@@ -1742,3 +1685,3 @@
   if (percdecode(directorytolist) != 0) {
-    syslog(LOG_WARNING, "Percent decoding on request failed. Query aborted.");
+		LOG(WARNING,"Percent decoding on request failed. Query aborted.");
     return(0);
@@ -1749,3 +1692,3 @@
   if (securitycheckresult != NULL) {
-    syslog(LOG_INFO, "The gopher security module has detected a suspect condition. The query won't be processed. Reason: %s", securitycheckresult);
+		LOG(INFO,"The gopher security module has detected a suspect condition. The query won't be processed. Reason: %s", securitycheckresult);
     close(sock);
@@ -1761,6 +1704,6 @@
 
-  syslog(LOG_INFO, "Requested resource: %s / Local resource: %s", directorytolist, localfile);
+	LOG(INFO,"Requested resource: %s / Local resource: %s", directorytolist, localfile);
 
   if (checkforevasion(rootdir, config.pubdirlist, localfile) != 0) {
-    syslog(LOG_INFO, "Evasion attempt. Forbidden!");
+		LOG(INFO,"Evasion attempt. Forbidden!");
     sendline(sock, "iForbidden!\tfake\tfake\t0");
@@ -1772,3 +1715,3 @@
   if (is_it_a_directory(localfile) != 0) {
-    if (chdir(localfile) != 0) syslog(LOG_WARNING, "WARNING: failed to switch to directory '%s'", localfile);
+		if (chdir(localfile) != 0) LOG(WARNING,"WARNING: failed to switch to directory '%s'", localfile);
     outputdir(sock, &config, localfile, directorytolist, remoteclientaddr, srvsideparams);
@@ -1782,3 +1725,3 @@
   if (changedir(localfile) != 0) {
-    syslog(LOG_INFO, "ERROR: changedir() failure for '%s'", localfile);
+		LOG(INFO,"ERROR: changedir() failure for '%s'", localfile);
     sendline(sock, "iForbidden!\tfake\tfake\t0");
@@ -1790,3 +1733,3 @@
   if ((strcmp(directorytolist, "/caps.txt") == 0) && (config.capssupport != 0)) {  /* If asking for /caps.txt, return it. */
-    syslog(LOG_INFO, "Returned caps.txt data");
+		LOG(INFO,"Returned caps.txt data");
     printcapstxt(sock, &config, pVer);
@@ -1800,3 +1743,3 @@
   if ((fexist(localfile) == 0) || (islocalfileagophermap(localfile) != 0)) {
-    syslog(LOG_INFO, "FileExists check: the file doesn't exists");
+		LOG(INFO,"FileExists check: the file doesn't exists");
     sendline(sock, "3The selected resource doesn't exist!\tfake\tfake\t0");
@@ -1813,3 +1756,3 @@
       /* error while reading attributes */
-      syslog(LOG_INFO, "stat() failed: %s", strerror(errno));
+			LOG(INFO,"stat() failed: %s", strerror(errno));
       sendline(sock, "3Internal error\tfake\tfake\t0");
@@ -1821,3 +1764,3 @@
       /* not world-readable */
-      syslog(LOG_INFO, "Paranoid mode check failed: file is not world-readable");
+			LOG(INFO,"Paranoid mode check failed: file is not world-readable");
       sendline(sock, "3Permission denied\tfake\tfake\t0");
@@ -1845,3 +1788,3 @@
   /* we want a normal file's content */
-  syslog(LOG_INFO, "Returning file '%s'", localfile);
+	LOG(INFO,"Returning file '%s'", localfile);
   gophertype = DetectGopherType(localfile, config.extmap);
@@ -1860,3 +1803,3 @@
   close(sock);
-  syslog(LOG_INFO, "connection closed. duration: %us", (unsigned int)(time(NULL) - StartTime));
+	LOG(INFO,"connection closed. duration: %us", (unsigned int)(time(NULL) - StartTime));
   return(0);
========================================================================
--- motsognir/motsognir.h	        (nonexistent)
+++ motsognir+logmore/motsognir.h	2018-08-05 19:41:31.004474968 +0200
@@ -0,0 +1,83 @@
+/*
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *  *  Motsognir - The mighty gopher server                               *
+ *  *  Copyright (C) 2008-2016 Mateusz Viste                              *
+ *  *  http://motsognir.sourceforge.net                                   *
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Some changes and additions: Copyright (C) 2018 Dario Niedermann
+ *  $Id: motsognir.h 17 2018-08-05 17:41:30Z ndr $
+ * ----------------------------------------------------------------------
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ----------------------------------------------------------------------
+ */
+
+#include <regex.h>   /* regcomp(), regexec()... */
+
+/* Constants */
+#define pVer         "1.0.9+logmore1.0"
+#define pDate        "2008-2018"
+#define HOMEPAGE     "http://motsognir.sourceforge.net"
+#define OK_EXIT_NOW  -1
+
+	/* logging: */
+#define TO_SYSLOG     0
+#define TO_FILE       1
+#define INIT          65536  /* just needs to be a # not used in syslog.h */
+#define SET_PREFIX    65537  /* just needs to be a # not used in syslog.h */
+
+	/* parseCmdLine() operating modes: */
+#define FIRST_PASS    0
+#define FROM_FILE     1
+#define LAST_PASS     2
+
+struct MotsognirConfig {
+	char *gopherroot;
+	char *userdir;
+	char **pubdirlist;
+	int gopherport;
+	char *gopherhostname;
+	char *defaultgophermap;
+	int verbosemode;
+	int capssupport;
+	char *capsservergeolocationstring;
+	char *capsserverarchitecture;
+	char *capsserverdescription;
+	char *capsserverdefaultencoding;
+	int cgisupport;
+	int phpsupport;
+	int subgophermaps;
+	int paranoidmode;
+	char *plugin;
+	regex_t *pluginfilter;
+	char *runasuser;
+	uid_t runasuser_uid;
+	gid_t runasuser_gid;
+	char *runasuser_home;
+	char *chroot;
+	char *httperrfile;
+	char *bind;
+	char *extmapfile;
+	struct extmap_t *extmap;
+	char *configfile;
+	char securldelim;
+};
+
+struct  logParams {
+	char  loggingType;
+	int   facility;
+	char  *fileName;
+	int   *localFacility; /* upon struct creation, point me to an array of
+													 syslog facility values. Like in parseCmdLine() */
+};
==================================================END==OF==PATCH=*=*=***
-----BEGIN PGP SIGNATURE-----

iQIcBAEBAgAGBQJbcpi8AAoJEPJFaEEGrTgGxtgP/A4x/ff8d+WhbFL3EZeRvFSk
7sSdGObjo3NdhmJavYMcSB6EFuQ4rWH801LDlM5PeJeMJ6BNJlrfu4kQniSECoeK
GbLrA7osydjYd5EJfiUVx+UTtfF3OzIj9MyYW4MM4vaewuoXPTmS+M0f235rOuv3
ebo02yHI1f5sw6um9DfRf9lL9j2s4RAGdVjgawZSFa8ydOpHr9iiHKCtAKwZWsCY
2bv+LFbZT73asa3O7/REqmYlFkkGOdagSobdg6spAtPc8cEveAMJPOy3cHzAo08I
IDWshlYojynDfNBQ+SXMaxnqblFqegjOqv1ZX4LBz4p6KBcyjHD2e0njyk9CrCtN
LMS4WhVEfoFh5bpbbvv2PuEkXg9R4S5pdTXFPAarthNFQeSiqbc+yNQNhDmiwSFD
vmY9wjEayo03HFjp7b9xxJnzwGLmqfz5frJGXyWPEAfzdv332y+cXmCWsU9xb9FC
pMJLMvn5i3gRD4/fh8ppBqUsHrIbpCRj70+GQSxPSB4lPOuUbIonGafT3UZ5c7Xn
i7o2Kt56nhSDuiDLnEE1UqsaqkAirkI1j3nEBsEV+YyhaFLiV+DxMTqymY7CM29q
XjseWpdJx8FOxANlXBOVO+m15wntQknsdlWIqhNmKIWjY0W0HIMyE6z0eRNW9u+L
prIZZ5HQUndPIst9O/nA
=cu5F
-----END PGP SIGNATURE-----
“Logmore1.0 patch for Motsognir v1.0.9” is Copyright © Dario Niedermann — Released with no warranty under the terms of the GPLv3 license. Written and tested on Linux using GNU tools.
HomeNo Javascript iconValid HTML 4.01 StrictValid CSS!