commit 00b0e16d70d9075c4363a2edaa16efe387d52ddd
Author: David Goulet <dgoulet(a)ev0ke.net>
Date: Sun Jun 2 16:18:51 2013 -0400
Reengineer logging and remove old show_msg
Signed-off-by: David Goulet <dgoulet(a)ev0ke.net>
---
src/common/config-file.c | 127 ++++++++++++++--------------
src/common/defaults.h | 9 ++
src/common/log.c | 211 ++++++++++++++++++++++++++++++++--------------
src/common/log.h | 94 +++++++++++++++++----
4 files changed, 299 insertions(+), 142 deletions(-)
diff --git a/src/common/config-file.c b/src/common/config-file.c
index ad7b683..47f6a09 100644
--- a/src/common/config-file.c
+++ b/src/common/config-file.c
@@ -58,9 +58,8 @@ static int check_server(struct config_server_entry *server)
static int handle_endpath(struct config_parsed *config, int lineno, int nowords) {
if (nowords != 1) {
- show_msg(MSGERR, "Badly formed path close statement on line "
- "%d in configuration file (should look like "
- "\"}\")\n", lineno);
+ ERR("Badly formed path close statement on line %d in configuration"
+ "file (should look like \"}\")\n", lineno);
} else {
currentcontext = &(config->default_server);
}
@@ -112,7 +111,7 @@ int make_config_network_entry(char *value, struct config_network_entry **ent) {
exit(1);
}
- show_msg(MSGDEBUG, "New network entry for %s going to 0x%08x\n", ip, *ent);
+ DBG("New network entry for %s going to 0x%08x\n", ip, *ent);
if (!start_port)
(*ent)->start_port = 0;
@@ -174,46 +173,46 @@ static int handle_reaches(int lineno, char *value) {
rc = make_config_network_entry(value, &ent);
switch(rc) {
case 1:
- show_msg(MSGERR, "Local network specification (%s) is not validly "
+ ERR("Local network specification (%s) is not validly "
"constructed in reach statement on line "
"%d in configuration "
"file\n", value, lineno);
return(0);
break;
case 2:
- show_msg(MSGERR, "IP in reach statement "
+ ERR("IP in reach statement "
"network specification (%s) is not valid on line "
"%d in configuration file\n", value, lineno);
return(0);
break;
case 3:
- show_msg(MSGERR, "SUBNET in reach statement "
+ ERR("SUBNET in reach statement "
"network specification (%s) is not valid on "
"line %d in configuration file\n", value,
lineno);
return(0);
break;
case 4:
- show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->local_ip));
- show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
+ ERR("IP (%s) & ", inet_ntoa(ent->local_ip));
+ ERR("SUBNET (%s) != IP on line %d in "
"configuration file, ignored\n",
inet_ntoa(ent->local_net), lineno);
return(0);
break;
case 5:
- show_msg(MSGERR, "Start port in reach statement "
+ ERR("Start port in reach statement "
"network specification (%s) is not valid on line "
"%d in configuration file\n", value, lineno);
return(0);
break;
case 6:
- show_msg(MSGERR, "End port in reach statement "
+ ERR("End port in reach statement "
"network specification (%s) is not valid on line "
"%d in configuration file\n", value, lineno);
return(0);
break;
case 7:
- show_msg(MSGERR, "End port in reach statement "
+ ERR("End port in reach statement "
"network specification (%s) is less than the start "
"port on line %d in configuration file\n", value,
lineno);
@@ -239,11 +238,11 @@ static int handle_server(struct config_parsed *config, int lineno, char *value)
currentcontext->address = strdup(ip);
else {
if (currentcontext == &(config->default_server))
- show_msg(MSGERR, "Only one default SOCKS server "
+ ERR("Only one default SOCKS server "
"may be specified at line %d in "
"configuration file\n", lineno);
else
- show_msg(MSGERR, "Only one SOCKS server may be specified "
+ ERR("Only one SOCKS server may be specified "
"per path on line %d in configuration "
"file. (Path begins on line %d)\n",
lineno, currentcontext->lineno);
@@ -256,11 +255,11 @@ static int handle_port(struct config_parsed *config, int lineno, char *value) {
if (currentcontext->port != 0) {
if (currentcontext == &(config->default_server))
- show_msg(MSGERR, "Server port may only be specified "
+ ERR("Server port may only be specified "
"once for default server, at line %d "
"in configuration file\n", lineno);
else
- show_msg(MSGERR, "Server port may only be specified "
+ ERR("Server port may only be specified "
"once per path on line %d in configuration "
"file. (Path begins on line %d)\n",
lineno, currentcontext->lineno);
@@ -269,7 +268,7 @@ static int handle_port(struct config_parsed *config, int lineno, char *value) {
currentcontext->port = (unsigned short int)
(strtol(value, (char **)NULL, 10));
if ((errno != 0) || (currentcontext->port == 0)) {
- show_msg(MSGERR, "Invalid server port number "
+ ERR("Invalid server port number "
"specified in configuration file "
"(%s) on line %d\n", value, lineno);
currentcontext->port = 0;
@@ -283,11 +282,11 @@ static int handle_username(struct config_parsed *config, int lineno, char *value
if (currentcontext->username != NULL) {
if (currentcontext == &(config->default_server))
- show_msg(MSGERR, "Default username may only be specified "
+ ERR("Default username may only be specified "
"once for default server, at line %d "
"in configuration file\n", lineno);
else
- show_msg(MSGERR, "Default username may only be specified "
+ ERR("Default username may only be specified "
"once per path on line %d in configuration "
"file. (Path begins on line %d)\n",
lineno, currentcontext->lineno);
@@ -302,11 +301,11 @@ static int handle_password(struct config_parsed *config, int lineno, char *value
if (currentcontext->password != NULL) {
if (currentcontext == &(config->default_server))
- show_msg(MSGERR, "Default password may only be specified "
+ ERR("Default password may only be specified "
"once for default server, at line %d "
"in configuration file\n", lineno);
else
- show_msg(MSGERR, "Default password may only be specified "
+ ERR("Default password may only be specified "
"once per path on line %d in configuration "
"file. (Path begins on line %d)\n",
lineno, currentcontext->lineno);
@@ -321,11 +320,11 @@ static int handle_type(struct config_parsed *config, int lineno, char *value) {
if (currentcontext->type != 0) {
if (currentcontext == &(config->default_server))
- show_msg(MSGERR, "Server type may only be specified "
+ ERR("Server type may only be specified "
"once for default server, at line %d "
"in configuration file\n", lineno);
else
- show_msg(MSGERR, "Server type may only be specified "
+ ERR("Server type may only be specified "
"once per path on line %d in configuration "
"file. (Path begins on line %d)\n",
lineno, currentcontext->lineno);
@@ -334,7 +333,7 @@ static int handle_type(struct config_parsed *config, int lineno, char *value) {
currentcontext->type = (int) strtol(value, (char **)NULL, 10);
if ((errno != 0) || (currentcontext->type == 0) ||
((currentcontext->type != 4) && (currentcontext->type != 5))) {
- show_msg(MSGERR, "Invalid server type (%s) "
+ ERR("Invalid server type (%s) "
"specified in configuration file "
"on line %d, only 4 or 5 may be "
"specified\n", value, lineno);
@@ -363,7 +362,7 @@ static int handle_tordns_enabled(struct config_parsed *config, int lineno,
{
int val = handle_flag(value);
if(val == -1) {
- show_msg(MSGERR, "Invalid value %s supplied for tordns_enabled at "
+ ERR("Invalid value %s supplied for tordns_enabled at "
"line %d in config file, IGNORED\n", value, lineno);
} else {
config->tordns_enabled = val;
@@ -377,15 +376,15 @@ static int handle_tordns_cache_size(struct config_parsed *config,
char *endptr;
long size = strtol(value, &endptr, 10);
if(*endptr != '\0') {
- show_msg(MSGERR, "Error parsing integer value for "
+ ERR("Error parsing integer value for "
"tordns_cache_size (%s), using default %d\n",
value, config->tordns_cache_size);
} else if(size < 128) {
- show_msg(MSGERR, "The value supplied for tordns_cache_size (%d) "
+ ERR("The value supplied for tordns_cache_size (%d) "
"is too small (<128), using default %d\n", size,
config->tordns_cache_size);
} else if(size > 4096) {
- show_msg(MSGERR, "The value supplied for tordns_cache_range (%d) "
+ ERR("The value supplied for tordns_cache_range (%d) "
"is too large (>4096), using default %d\n", size,
config->tordns_cache_size);
} else {
@@ -399,13 +398,13 @@ static int handle_path(struct config_parsed *config, int lineno, int nowords, ch
struct config_server_entry *newserver;
if ((nowords != 2) || (strcmp(words[1], "{"))) {
- show_msg(MSGERR, "Badly formed path open statement on line %d "
+ ERR("Badly formed path open statement on line %d "
"in configuration file (should look like "
"\"path {\")\n", lineno);
} else if (currentcontext != &(config->default_server)) {
/* You cannot nest path statements so check that */
/* the current context is default_server */
- show_msg(MSGERR, "Path statements cannot be nested on line %d "
+ ERR("Path statements cannot be nested on line %d "
"in configuration file\n", lineno);
} else {
/* Open up a new config_server_entry, put it on the list */
@@ -414,7 +413,7 @@ static int handle_path(struct config_parsed *config, int lineno, int nowords, ch
exit(-1);
/* Initialize the structure */
- show_msg(MSGDEBUG, "New server structure from line %d in configuration file going "
+ DBG("New server structure from line %d in configuration file going "
"to 0x%08x\n", lineno, newserver);
memset(newserver, 0x0, sizeof(*newserver));
newserver->next = config->paths;
@@ -431,7 +430,7 @@ static int handle_local(struct config_parsed *config, int lineno, const char *va
struct config_network_entry *ent;
if (currentcontext != &(config->default_server)) {
- show_msg(MSGERR, "Local networks cannot be specified in path "
+ ERR("Local networks cannot be specified in path "
"block at line %d in configuration file. "
"(Path block started at line %d)\n",
lineno, currentcontext->lineno);
@@ -441,34 +440,34 @@ static int handle_local(struct config_parsed *config, int lineno, const char *va
rc = make_config_network_entry((char *)value, &ent);
switch(rc) {
case 1:
- show_msg(MSGERR, "Local network specification (%s) is not validly "
+ ERR("Local network specification (%s) is not validly "
"constructed on line %d in configuration "
"file\n", value, lineno);
return(0);
break;
case 2:
- show_msg(MSGERR, "IP for local "
+ ERR("IP for local "
"network specification (%s) is not valid on line "
"%d in configuration file\n", value, lineno);
return(0);
break;
case 3:
- show_msg(MSGERR, "SUBNET for "
+ ERR("SUBNET for "
"local network specification (%s) is not valid on "
"line %d in configuration file\n", value,
lineno);
return(0);
break;
case 4:
- show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->local_ip));
- show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
+ ERR("IP (%s) & ", inet_ntoa(ent->local_ip));
+ ERR("SUBNET (%s) != IP on line %d in "
"configuration file, ignored\n",
inet_ntoa(ent->local_net), lineno);
return(0);
case 5:
case 6:
case 7:
- show_msg(MSGERR, "Port specification is invalid and "
+ ERR("Port specification is invalid and "
"not allowed in local network specification "
"(%s) on line %d in configuration file\n",
value, lineno);
@@ -477,7 +476,7 @@ static int handle_local(struct config_parsed *config, int lineno, const char *va
}
if (ent->start_port || ent->end_port) {
- show_msg(MSGERR, "Port specification is "
+ ERR("Port specification is "
"not allowed in local network specification "
"(%s) on line %d in configuration file\n",
value, lineno);
@@ -498,13 +497,13 @@ static int handle_tordns_deadpool_range(struct config_parsed *config, int lineno
struct config_network_entry *ent;
if (config->tordns_deadpool_range != NULL) {
- show_msg(MSGERR, "Only one 'deadpool' entry permitted, found a "
+ ERR("Only one 'deadpool' entry permitted, found a "
"second at line %d in configuration file.\n");
return(0);
}
if (currentcontext != &(config->default_server)) {
- show_msg(MSGERR, "Deadpool cannot be specified in path "
+ ERR("Deadpool cannot be specified in path "
"block at line %d in configuration file. "
"(Path block started at line %d)\n",
lineno, currentcontext->lineno);
@@ -516,34 +515,34 @@ static int handle_tordns_deadpool_range(struct config_parsed *config, int lineno
a generic whinge() function or something */
switch(rc) {
case 1:
- show_msg(MSGERR, "The deadpool specification (%s) is not validly "
+ ERR("The deadpool specification (%s) is not validly "
"constructed on line %d in configuration "
"file\n", value, lineno);
return(0);
break;
case 2:
- show_msg(MSGERR, "IP for deadpool "
+ ERR("IP for deadpool "
"network specification (%s) is not valid on line "
"%d in configuration file\n", value, lineno);
return(0);
break;
case 3:
- show_msg(MSGERR, "SUBNET for "
+ ERR("SUBNET for "
"deadpool network specification (%s) is not valid on "
"line %d in configuration file\n", value,
lineno);
return(0);
break;
case 4:
- show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->local_ip));
- show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
+ ERR("IP (%s) & ", inet_ntoa(ent->local_ip));
+ ERR("SUBNET (%s) != IP on line %d in "
"configuration file, ignored\n",
inet_ntoa(ent->local_net), lineno);
return(0);
case 5:
case 6:
case 7:
- show_msg(MSGERR, "Port specification is invalid and "
+ ERR("Port specification is invalid and "
"not allowed in deadpool specification "
"(%s) on line %d in configuration file\n",
value, lineno);
@@ -551,7 +550,7 @@ static int handle_tordns_deadpool_range(struct config_parsed *config, int lineno
break;
}
if (ent->start_port || ent->end_port) {
- show_msg(MSGERR, "Port specification is "
+ ERR("Port specification is "
"not allowed in deadpool specification "
"(%s) on line %d in configuration file\n",
value, lineno);
@@ -590,7 +589,7 @@ static int handle_line(struct config_parsed *config, char *line, int lineno)
} else {
/* Has to be a pair */
if ((nowords != 3) || (strcmp(words[1], "="))) {
- show_msg(MSGERR, "Malformed configuration pair "
+ ERR("Malformed configuration pair "
"on line %d in configuration "
"file, \"%s\"\n", lineno, savedline);
} else if (!strcmp(words[0], "reaches")) {
@@ -614,7 +613,7 @@ static int handle_line(struct config_parsed *config, char *line, int lineno)
} else if (!strcmp(words[0], "tordns_cache_size")) {
handle_tordns_cache_size(config, words[2]);
} else {
- show_msg(MSGERR, "Invalid pair type (%s) specified "
+ ERR("Invalid pair type (%s) specified "
"on line %d in configuration file, "
"\"%s\"\n", words[0], lineno,
savedline);
@@ -629,31 +628,31 @@ int is_local(struct config_parsed *config, struct in_addr *testip) {
struct config_network_entry *ent;
char buf[16];
inet_ntop(AF_INET, testip, buf, sizeof(buf));
- show_msg(MSGDEBUG, "checking if address: %s is local"
+ DBG("checking if address: %s is local"
"\n",
buf);
for (ent = (config->local_nets); ent != NULL; ent = ent -> next) {
inet_ntop(AF_INET, &ent->local_net, buf, sizeof(buf));
- show_msg(MSGDEBUG, "local_net addr: %s"
+ DBG("local_net addr: %s"
"\n",
buf);
inet_ntop(AF_INET, &ent->local_ip, buf, sizeof(buf));
- show_msg(MSGDEBUG, "local_ip addr: %s"
+ DBG("local_ip addr: %s"
"\n",
buf);
- show_msg(MSGDEBUG, "result testip->s_addr & ent->local_net.s_addr : %i"
+ DBG("result testip->s_addr & ent->local_net.s_addr : %i"
"\n",
testip->s_addr & ent->local_net.s_addr);
- show_msg(MSGDEBUG, "result ent->local_ip.s_addr & ent->local_net.s_addr : %i"
+ DBG("result ent->local_ip.s_addr & ent->local_net.s_addr : %i"
"\n",
ent->local_ip.s_addr & ent->local_net.s_addr);
- show_msg(MSGDEBUG, "result ent->local_ip.s_addr : %i"
+ DBG("result ent->local_ip.s_addr : %i"
"\n",
ent->local_ip.s_addr);
if ((testip->s_addr & ent->local_net.s_addr) ==
(ent->local_ip.s_addr & ent->local_net.s_addr)) {
- show_msg(MSGDEBUG, "address: %s is local"
+ DBG("address: %s is local"
"\n",
buf);
return(0);
@@ -661,7 +660,7 @@ int is_local(struct config_parsed *config, struct in_addr *testip) {
}
inet_ntop(AF_INET, testip, buf, sizeof(buf));
- show_msg(MSGDEBUG, "address: %s is not local"
+ DBG("address: %s is not local"
"\n",
buf);
return(1);
@@ -673,24 +672,24 @@ int pick_server(struct config_parsed *config, struct config_server_entry **ent,
struct config_network_entry *net;
char ipbuf[64];
- show_msg(MSGDEBUG, "Picking appropriate server for %s\n", inet_ntoa(*ip));
+ DBG("Picking appropriate server for %s\n", inet_ntoa(*ip));
*ent = (config->paths);
while (*ent != NULL) {
/* Go through all the servers looking for one */
/* with a path to this network */
- show_msg(MSGDEBUG, "Checking SOCKS server %s\n",
+ DBG("Checking SOCKS server %s\n",
((*ent)->address ? (*ent)->address : "(No Address)"));
net = (*ent)->reachnets;
while (net != NULL) {
strcpy(ipbuf, inet_ntoa(net->local_ip));
- show_msg(MSGDEBUG, "Server can reach %s/%s\n",
+ DBG("Server can reach %s/%s\n",
ipbuf, inet_ntoa(net->local_net));
if (((ip->s_addr & net->local_net.s_addr) ==
(net->local_ip.s_addr & net->local_net.s_addr)) &&
(!net->start_port ||
((net->start_port <= port) && (net->end_port >= port))))
{
- show_msg(MSGDEBUG, "This server can reach target\n");
+ DBG("This server can reach target\n");
/* Found the net, return */
return(0);
}
@@ -734,13 +733,13 @@ int config_file_read(const char *filename, struct config_parsed *config)
/* Insure null termination */
line[sizeof(line) - 1] = (char) 0;
filename = line;
- show_msg(MSGDEBUG, "Configuration file not provided by TORSOCKS_CONF_FILE "
+ DBG("Configuration file not provided by TORSOCKS_CONF_FILE "
"environment variable, attempting to use defaults in %s.\n", filename);
}
/* If there is no configuration file use reasonable defaults for Tor */
if ((conf = fopen(filename, "r")) == NULL) {
- show_msg(MSGERR, "Could not open socks configuration file "
+ ERR("Could not open socks configuration file "
"(%s) errno (%d), assuming sensible defaults for Tor.\n", filename, errno);
memset(&(config->default_server), 0x0, sizeof(config->default_server));
check_server(&(config->default_server));
diff --git a/src/common/defaults.h b/src/common/defaults.h
index c13db66..6e11e83 100644
--- a/src/common/defaults.h
+++ b/src/common/defaults.h
@@ -18,8 +18,17 @@
#ifndef TORSOCKS_DEFAULTS_H
#define TORSOCKS_DEFAULTS_H
+#include "log.h"
+
#define DEFAULT_TOR_PORT 9050
#define DEFAULT_TOR_ADDRESS "127.0.0.1"
#define DEFAULT_TOR_SOCKS 5
+/* Logging defaults. */
+#define DEFAULT_LOG_LEVEL_ENV "TORSOCKS_LOG_LEVEL"
+#define DEFAULT_LOG_TIME_ENV "TORSOCKS_LOG_TIME"
+#define DEFAULT_LOG_FILEPATH_ENV "TORSOCKS_LOG_FILE_PATH"
+#define DEFAULT_LOG_TIME_STATUS LOG_TIME_ADD
+#define DEFAULT_LOG_LEVEL MSGWARN
+
#endif /* TORSOCKS_DEFAULTS_H */
diff --git a/src/common/log.c b/src/common/log.c
index 29888c0..e415721 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,5 @@
/*
- * Copyright (C) 2000-2008 - Shaun Clowes <delius(a)progsoc.org>
- * 2008-2011 - Robert Hogan <robert(a)roberthogan.net>
- * 2013 - David Goulet <dgoulet(a)ev0ke.net>
+ * Copyright (C) 2013 - David Goulet <dgoulet(a)ev0ke.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License, version 2 only, as
@@ -17,91 +15,180 @@
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include "defaults.h"
+#include "macros.h"
-#include "log.h"
-
-/* Set logging options, the options are as follows: */
-/* level - This sets the logging threshold, messages with */
-/* a higher level (i.e lower importance) will not be */
-/* output. For example, if the threshold is set to */
-/* MSGWARN a call to log a message of level MSGDEBUG */
-/* would be ignored. This can be set to -1 to disable */
-/* messages entirely */
-/* filename - This is a filename to which the messages should */
-/* be logged instead of to standard error */
-/* timestamp - This indicates that messages should be prefixed */
-/* with timestamps (and the process id) */
-void set_log_options(int level, char *filename, int timestamp)
+static struct log_config {
+ FILE *fp;
+ char *filepath;
+ /* Add time or not to the log entry. */
+ enum log_time_status time_status;
+} logconfig;
+
+/*
+ * The default logging level is to only log error messages.
+ */
+int tsocks_loglevel = DEFAULT_LOG_LEVEL;
+
+/*
+ * Add a special formatted timestamp at the beginning of the given buffer.
+ *
+ * On success, return the number of bytes written else, return 0.
+ */
+static size_t add_time_to_log(char *buf, size_t len)
{
- loglevel = level;
- if (loglevel < MSGERR)
- loglevel = MSGNONE;
+ time_t now;
+ const struct tm *tm;
- if (filename) {
- strncpy(logfilename, filename, sizeof(logfilename));
- logfilename[sizeof(logfilename) - 1] = '\0';
- }
+ assert(buf);
- logstamp = timestamp;
+ /* Get time stamp. */
+ time(&now);
+ tm = localtime(&now);
+ return strftime(buf, len, "[%b %d %H:%M:%S] ", tm);
}
-void show_msg(int level, const char *fmt, ...)
+/*
+ * Log function taking a format and variable number of arguments fitting the
+ * given format.
+ */
+static void _log_write(char *buf, size_t len)
{
+ int ret;
+
+ assert(buf);
+ assert(logconfig.fp);
+
+ /* Make sure buffer is NULL terminated. */
+ buf[len - 1] = '\0';
+
+ ret = fprintf(logconfig.fp, "%s", buf);
+ if (ret < 0) {
+ fprintf(stderr, "[tsocks] logging failed. Stopping logging.\n");
+ log_destroy();
+ goto end;
+ }
+
+ /*
+ * On a write failure we stop the logging but a flush failure is not that
+ * critical.
+ */
+ (void) fflush(logconfig.fp);
+
+end:
+ return;
+}
+
+/*
+ * Log messages using the logconfig configuration.
+ */
+ATTR_HIDDEN
+void log_print(const char *fmt, ...)
+{
+ int ret;
+ size_t written = 0;
va_list ap;
- int saveerr;
- extern char *torsocks_progname;
- char timestring[20];
- time_t timestamp;
-
- if ((loglevel == MSGNONE) || (level > loglevel))
- return;
-
- if (!logfile) {
- if (logfilename[0]) {
- logfile = fopen(logfilename, "a");
- if (logfile == NULL) {
- logfile = stderr;
- show_msg(MSGERR, "Could not open log file, %s, %s\n",
- logfilename, strerror(errno));
- }
- } else
- logfile = stderr;
- }
+ /* This is a hard limit for the size of the line. */
+ char buf[4096];
- if (logstamp) {
- timestamp = time(NULL);
- strftime(timestring, sizeof(timestring), "%H:%M:%S",
- localtime(×tamp));
- fprintf(logfile, "%s ", timestring);
+ assert(fmt);
+
+ if (!logconfig.fp) {
+ goto end;
}
- fputs(torsocks_progname, logfile);
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
- if (logstamp) {
- fprintf(logfile, "(%d)", getpid());
+ if (logconfig.time_status == LOG_TIME_ADD) {
+ written = add_time_to_log(buf, sizeof(buf));
}
- fputs(": ", logfile);
+ ret = vsnprintf(buf + written, sizeof(buf) - written, fmt, ap);
+ if (ret < 0) {
+ perror("[tsocks] vsnprintf log");
+ goto error;
+ }
- va_start(ap, fmt);
+ _log_write(buf, sizeof(buf));
+
+error:
+ va_end(ap);
+end:
+ return;
+}
+
+/*
+ * Initialize logconfig.
+ *
+ * Return 0 on success or else a negative errno value.
+ */
+ATTR_HIDDEN
+int log_init(int level, const char *filepath, enum log_time_status t_status)
+{
+ int ret = 0;
- /* Save errno */
- saveerr = errno;
+ /* Reset logconfig. Useful if this is call multiple times. */
+ memset(&logconfig, 0, sizeof(logconfig));
- vfprintf(logfile, fmt, ap);
+ if (level < MSGNONE || level > MSGDEBUG) {
+ fprintf(stderr, "[tsocks] Unknown loglevel %d\n", level);
+ ret = -ENOENT;
+ goto error;
+ }
- fflush(logfile);
+ if (filepath) {
+ logconfig.fp = fopen(filepath, "a");
+ if (!logconfig.fp) {
+ fprintf(stderr, "[tsocks] Unable to open log file %s\n", filepath);
+ ret = -errno;
+ goto error;
+ }
+
+ logconfig.filepath = strdup(filepath);
+ if (!logconfig.filepath) {
+ perror("[tsocks] log init strdup");
+ ret = -errno;
+ fclose(logconfig.fp);
+ goto error;
+ }
+ } else {
+ /* The default output is stderr if no filepath is given. */
+ fileno(stderr);
+ if (errno != EBADF) {
+ logconfig.fp = stderr;
+ }
+ }
- errno = saveerr;
+ tsocks_loglevel = level;
+ logconfig.time_status = t_status;
- va_end(ap);
+error:
+ return ret;
}
+/*
+ * Cleanup the logconfig data structure.
+ */
+ATTR_HIDDEN
+void log_destroy(void)
+{
+ free(logconfig.filepath);
+ if (logconfig.fp) {
+ int ret;
+
+ ret = fclose(logconfig.fp);
+ if (ret) {
+ perror("[tsocks] fclose log destroy");
+ }
+ }
+}
diff --git a/src/common/log.h b/src/common/log.h
index fd141a0..a60618b 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -20,21 +20,83 @@
#ifndef TORSOCKS_LOG_H
#define TORSOCKS_LOG_H
-#define MSGNONE -1
-#define MSGERR 0
-#define MSGWARN 1
-#define MSGTEST 2
-#define MSGNOTICE 3
-#define MSGDEBUG 3
-
-int loglevel = MSGERR; /* The default logging level is to only log
- error messages */
-char logfilename[256]; /* Name of file to which log messages should
- be redirected */
-FILE *logfile; /* File to which messages should be logged */
-int logstamp; /* Timestamp (and pid stamp) messages */
-
-void set_log_options(int level, char *filename, int timestamp);
-void show_msg(int level, const char *fmt, ...);
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "compat.h"
+
+/* Stringify the expansion of a define */
+#define XSTR(d) STR(d)
+#define STR(s) #s
+
+#define MSGNONE 0x1
+#define MSGERR 0x2
+#define MSGWARN 0x3
+#define MSGNOTICE 0x4
+#define MSGDEBUG 0x5
+
+/*
+ * Used during logging initialization whether or not to add the time or
+ * suppress it from a log entry.
+ */
+enum log_time_status {
+ LOG_TIME_NONE = 0,
+ LOG_TIME_ADD = 1,
+};
+
+extern int tsocks_loglevel;
+
+void log_print(const char *fmt, ...);
+int log_init(int level, const char *filepath, enum log_time_status t_status);
+void log_destroy(void);
+
+#define __tsocks_print(level, fmt, args...) \
+ do { \
+ if (level != MSGNONE && level <= tsocks_loglevel) { \
+ log_print(fmt, ## args); \
+ } \
+ } while (0)
+
+#define _ERRMSG(msg, type, fmt, args...) __tsocks_print(type, msg \
+ " torsocks[%ld]: " fmt " (in %s() at " __FILE__ ":" XSTR(__LINE__) ")\n", \
+ (long) getpid(), ## args, __func__)
+
+#define MSG(fmt, args...) __tsocks_print(MSGNOTICE, fmt "\n", ## args)
+#define ERR(fmt, args...) _ERRMSG("ERROR", MSGERR, fmt, ## args)
+#define WARN(fmt, args...) _ERRMSG("Warning", MSGWARN, fmt, ## args)
+#define DBG(fmt, args...) _ERRMSG("DEBUG", MSGDEBUG, fmt, ## args)
+
+/*
+ * Local wrapper used by the PERROR() call below. Should NOT be used outside of
+ * this scope.
+ */
+#define _PERROR(fmt, args...) _ERRMSG("PERROR", MSGERR, fmt, ## args)
+
+#if !defined(__linux__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
+
+/*
+ * Version using XSI strerror_r.
+ */
+#define PERROR(call, args...) \
+ do { \
+ char buf[200]; \
+ strerror_r(errno, buf, sizeof(buf)); \
+ _PERROR(call ": %s", ## args, buf); \
+ } while(0);
+
+#else /* _POSIX_C_SOURCE */
+
+/*
+ * Version using GNU strerror_r, for linux with appropriate defines.
+ */
+#define PERROR(call, args...) \
+ do { \
+ char *buf; \
+ char tmp[200]; \
+ buf = strerror_r(errno, tmp, sizeof(tmp)); \
+ _PERROR(call ": %s", ## args, buf); \
+ } while(0);
+
+#endif /* _POSIX_C_SOURCE */
#endif /* TORSOCKS_LOG_H */