1 /* Copyright 2008 Bernhard R. Fischer, Daniel Haslinger.
2  *
3  * This file is part of OnionCat.
4  *
5  * OnionCat is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * OnionCat is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with OnionCat. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*! @file
19  *  File contains logging functions.
20  *  @author Bernhard R. Fischer
21  *  @version 2008/10/1
22  */
23 
24 #include "ocat.h"
25 #include "ocat_netdesc.h"
26 
27 #define TIMESTRLEN 64
28 #define CBUFLEN 1024
29 
30 #ifndef LOG_PRI
31 #define LOG_PRI(p) ((p) & LOG_PRIMASK)
32 #endif
33 
34 static pthread_mutex_t log_mutex_ = PTHREAD_MUTEX_INITIALIZER;
35 static const char *flty_[8] = {"emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"};
36 //! FILE pointer to connect log
37 static FILE *clog_ = NULL;
38 
39 
40 /*! Open connect log.
41  *  The connect log contains logging entries regarding
42  *  incoming or outgoing connections.
43  *  @param dir Name of directory which should contain the log file
44  *  @return 0 if log was opened or -1 on failure.
45  */
open_connect_log(const char * dir)46 int open_connect_log(const char *dir)
47 {
48    char buf[CBUFLEN];
49 
50    if (clog_)
51       return 0;
52 
53    if (!dir)
54    {
55       log_debug("dir has NULL pointer");
56       return -1;
57    }
58 
59    strlcpy(buf, dir, CBUFLEN);
60    strlcat(buf, "/", CBUFLEN);
61    strlcat(buf, CNF(ocat_dir), CBUFLEN);
62 
63    log_debug("creating ocat log dir \"%s\"", buf);
64    if (mkdir(buf, S_IRWXU | S_IRGRP | S_IXGRP) && (errno != EEXIST))
65    {
66       log_msg(LOG_ERR, "could not create ocat directory \"%s\": \"%s\"", buf, strerror(errno));
67       return -1;
68    }
69 
70    strlcat(buf, "/", CBUFLEN);
71    strlcat(buf, NDESC(clog_file), CBUFLEN);
72 
73    log_debug("opening connect log \"%s\"", buf);
74    if (!(clog_ = fopen(buf, "a")))
75    {
76       log_msg(LOG_ERR, "could not open connect log \"%s\": \"%s\"", buf, strerror(errno));
77       return -1;
78    }
79    log_msg(LOG_NOTICE | LOG_FCONN, "connect log started");
80    return 0;
81 }
82 
83 
84 /*! Log a message to a file.
85  *  @param out Open FILE pointer
86  *  @param lf Logging priority (equal to syslog)
87  *  @param fmt Format string
88  *  @param ap Variable parameter list
89  */
vlog_msgf(FILE * out,int lf,const char * fmt,va_list ap)90 void vlog_msgf(FILE *out, int lf, const char *fmt, va_list ap)
91 {
92    struct timeval tv;
93    struct tm *tm;
94    time_t t;
95    char timestr[TIMESTRLEN] = "", timez[TIMESTRLEN] = "";
96    const OcatThread_t *th = get_thread();
97    OcatThread_t ths;
98    int level = LOG_PRI(lf);
99    char buf[SIZE_1K];
100 
101    if (CNF(debug_level) < level)
102       return;
103 
104    //t = time(NULL);
105    if (gettimeofday(&tv, NULL) == -1)
106       fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, strerror(errno)), exit(1);
107    t = tv.tv_sec;
108    if ((tm = localtime(&t)))
109    {
110       (void) strftime(timestr, TIMESTRLEN, "%a, %d %b %Y %H:%M:%S", tm);
111       (void) strftime(timez, TIMESTRLEN, "%z", tm);
112    }
113 
114    // if thread struct not in list
115    if (!th)
116    {
117       strlcpy(ths.name, "<NEW/DIE>", THREAD_NAME_LEN);
118       ths.id = -1;
119       th = &ths;
120    }
121 
122    (void) pthread_mutex_lock(&log_mutex_);
123    if (out)
124    {
125       fprintf(out, "%s.%03d %s [%d:%-*s:%6s] ", timestr, (int) (tv.tv_usec / 1000), timez, th->id, THREAD_NAME_LEN - 1, th->name, flty_[level]);
126       vfprintf(out, fmt, ap);
127       fprintf(out, "\n");
128    }
129    else
130    {
131       // log to syslog if no output stream is available
132       //vsyslog(level | LOG_DAEMON, fmt, ap);
133       vsnprintf(buf, SIZE_1K, fmt, ap);
134       syslog(level | LOG_DAEMON, "[%s] %s", th->name, buf);
135 
136    }
137    (void) pthread_mutex_unlock(&log_mutex_);
138 }
139 
140 
141 /*! Log a message. This function automatically determines
142  *  to which streams the message is logged.
143  *  @param lf Log priority.
144  *  @param fmt Format string.
145  *  @param ... arguments
146  */
log_msg(int lf,const char * fmt,...)147 void log_msg(int lf, const char *fmt, ...)
148 {
149    va_list ap;
150 
151    va_start(ap, fmt);
152    vlog_msgf(CNF(logf), lf, fmt, ap);
153    va_end(ap);
154    if (clog_ && (lf & LOG_FCONN))
155    {
156       va_start(ap, fmt);
157       vlog_msgf(clog_, lf, fmt, ap);
158       va_end(ap);
159       (void) fflush(clog_);
160    }
161    if (lf & LOG_FERR)
162    {
163       va_start(ap, fmt);
164       vfprintf(stderr, fmt, ap);
165       va_end(ap);
166       fprintf(stderr, "\n");
167    }
168 }
169 
170