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