Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * log.c - logging and debugging functions |
3 | | * |
4 | | * This file is part of the SSH Library |
5 | | * |
6 | | * Copyright (c) 2008-2013 by Aris Adamantiadis |
7 | | * |
8 | | * The SSH Library is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU Lesser General Public License as published by |
10 | | * the Free Software Foundation; either version 2.1 of the License, or (at your |
11 | | * option) any later version. |
12 | | * |
13 | | * The SSH Library is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
16 | | * License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with the SSH Library; see the file COPYING. If not, write to |
20 | | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
21 | | * MA 02111-1307, USA. |
22 | | */ |
23 | | |
24 | | #include "config.h" |
25 | | |
26 | | #include <stdio.h> |
27 | | #include <stdarg.h> |
28 | | #include <string.h> |
29 | | #ifdef HAVE_SYS_TIME_H |
30 | | #include <sys/time.h> |
31 | | #endif /* HAVE_SYS_TIME_H */ |
32 | | #ifdef HAVE_SYS_UTIME_H |
33 | | #include <sys/utime.h> |
34 | | #endif /* HAVE_SYS_UTIME_H */ |
35 | | #include <time.h> |
36 | | |
37 | | #include "libssh/priv.h" |
38 | | #include "libssh/misc.h" |
39 | | #include "libssh/session.h" |
40 | | |
41 | | #ifndef LOG_SIZE |
42 | | #define LOG_SIZE 1024 |
43 | | #endif |
44 | | |
45 | | static LIBSSH_THREAD int ssh_log_level; |
46 | | static LIBSSH_THREAD ssh_logging_callback ssh_log_cb; |
47 | | static LIBSSH_THREAD void *ssh_log_userdata = NULL; |
48 | | |
49 | | /** |
50 | | * @defgroup libssh_log The SSH logging functions |
51 | | * @ingroup libssh |
52 | | * |
53 | | * Logging functions for debugging and problem resolving. |
54 | | * |
55 | | * @{ |
56 | | */ |
57 | | |
58 | | static int current_timestring(int hires, char *buf, size_t len) |
59 | 0 | { |
60 | 0 | char tbuf[64]; |
61 | 0 | struct timeval tv; |
62 | 0 | struct tm tm, *tm_ptr = NULL; |
63 | 0 | time_t t; |
64 | |
|
65 | 0 | gettimeofday(&tv, NULL); |
66 | 0 | t = (time_t) tv.tv_sec; |
67 | |
|
68 | 0 | tm_ptr = localtime_r(&t, &tm); |
69 | 0 | if (tm_ptr == NULL) { |
70 | 0 | return -1; |
71 | 0 | } |
72 | | |
73 | 0 | if (hires) { |
74 | 0 | strftime(tbuf, sizeof(tbuf), "%Y/%m/%d %H:%M:%S", &tm); |
75 | 0 | snprintf(buf, len, "%s.%06ld", tbuf, (long)tv.tv_usec); |
76 | 0 | } else { |
77 | 0 | strftime(tbuf, sizeof(tbuf), "%Y/%m/%d %H:%M:%S", &tm); |
78 | 0 | snprintf(buf, len, "%s", tbuf); |
79 | 0 | } |
80 | |
|
81 | 0 | return 0; |
82 | 0 | } |
83 | | |
84 | | static void ssh_log_stderr(int verbosity, |
85 | | const char *function, |
86 | | const char *buffer) |
87 | 0 | { |
88 | 0 | char date[128] = {0}; |
89 | 0 | int rc; |
90 | |
|
91 | 0 | rc = current_timestring(1, date, sizeof(date)); |
92 | 0 | if (rc == 0) { |
93 | 0 | fprintf(stderr, "[%s, %d] %s:", date, verbosity, function); |
94 | 0 | } else { |
95 | 0 | fprintf(stderr, "[%d] %s", verbosity, function); |
96 | 0 | } |
97 | |
|
98 | 0 | fprintf(stderr, " %s\n", buffer); |
99 | 0 | } |
100 | | |
101 | | static void ssh_log_custom(ssh_logging_callback log_fn, |
102 | | int verbosity, |
103 | | const char *function, |
104 | | const char *buffer) |
105 | 0 | { |
106 | 0 | char buf[LOG_SIZE + 64]; |
107 | |
|
108 | 0 | snprintf(buf, sizeof(buf), "%s: %s", function, buffer); |
109 | 0 | log_fn(verbosity, function, buf, ssh_get_log_userdata()); |
110 | 0 | } |
111 | | |
112 | | void ssh_log_function(int verbosity, |
113 | | const char *function, |
114 | | const char *buffer) |
115 | 0 | { |
116 | 0 | ssh_logging_callback log_fn = ssh_get_log_callback(); |
117 | |
|
118 | 0 | if (log_fn) { |
119 | 0 | ssh_log_custom(log_fn, verbosity, function, buffer); |
120 | 0 | return; |
121 | 0 | } |
122 | | |
123 | 0 | ssh_log_stderr(verbosity, function, buffer); |
124 | 0 | } |
125 | | |
126 | | void ssh_vlog(int verbosity, |
127 | | const char *function, |
128 | | const char *format, |
129 | | va_list *va) |
130 | 0 | { |
131 | 0 | char buffer[LOG_SIZE]; |
132 | |
|
133 | 0 | vsnprintf(buffer, sizeof(buffer), format, *va); |
134 | 0 | ssh_log_function(verbosity, function, buffer); |
135 | 0 | } |
136 | | |
137 | | void _ssh_log(int verbosity, |
138 | | const char *function, |
139 | | const char *format, ...) |
140 | 0 | { |
141 | 0 | va_list va; |
142 | |
|
143 | 0 | if (verbosity <= ssh_get_log_level()) { |
144 | 0 | va_start(va, format); |
145 | 0 | ssh_vlog(verbosity, function, format, &va); |
146 | 0 | va_end(va); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | | /* LEGACY */ |
151 | | |
152 | | void ssh_log(ssh_session session, |
153 | | int verbosity, |
154 | | const char *format, ...) |
155 | 0 | { |
156 | 0 | va_list va; |
157 | |
|
158 | 0 | if (verbosity <= session->common.log_verbosity) { |
159 | 0 | va_start(va, format); |
160 | 0 | ssh_vlog(verbosity, "", format, &va); |
161 | 0 | va_end(va); |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | | /** @internal |
166 | | * @brief log a SSH event with a common pointer |
167 | | * @param common The SSH/bind session. |
168 | | * @param verbosity The verbosity of the event. |
169 | | * @param format The format string of the log entry. |
170 | | */ |
171 | | void ssh_log_common(struct ssh_common_struct *common, |
172 | | int verbosity, |
173 | | const char *function, |
174 | | const char *format, ...) |
175 | 0 | { |
176 | 0 | va_list va; |
177 | |
|
178 | 0 | if (verbosity <= common->log_verbosity) { |
179 | 0 | va_start(va, format); |
180 | 0 | ssh_vlog(verbosity, function, format, &va); |
181 | 0 | va_end(va); |
182 | 0 | } |
183 | 0 | } |
184 | | |
185 | | |
186 | | /* PUBLIC */ |
187 | | |
188 | | /** |
189 | | * @brief Set the log level of the library. |
190 | | * |
191 | | * @param[in] level The level to set. |
192 | | * |
193 | | * @return SSH_OK on success, SSH_ERROR on error. |
194 | | */ |
195 | 0 | int ssh_set_log_level(int level) { |
196 | 0 | if (level < 0) { |
197 | 0 | return SSH_ERROR; |
198 | 0 | } |
199 | | |
200 | 0 | ssh_log_level = level; |
201 | |
|
202 | 0 | return SSH_OK; |
203 | 0 | } |
204 | | |
205 | | /** |
206 | | * @brief Get the log level of the library. |
207 | | * |
208 | | * @return The value of the log level. |
209 | | */ |
210 | 0 | int ssh_get_log_level(void) { |
211 | 0 | return ssh_log_level; |
212 | 0 | } |
213 | | |
214 | 0 | int ssh_set_log_callback(ssh_logging_callback cb) { |
215 | 0 | if (cb == NULL) { |
216 | 0 | return SSH_ERROR; |
217 | 0 | } |
218 | | |
219 | 0 | ssh_log_cb = cb; |
220 | |
|
221 | 0 | return SSH_OK; |
222 | 0 | } |
223 | | |
224 | | void |
225 | | _ssh_reset_log_cb(void) |
226 | 0 | { |
227 | 0 | ssh_log_cb = NULL; |
228 | 0 | } |
229 | | |
230 | 0 | ssh_logging_callback ssh_get_log_callback(void) { |
231 | 0 | return ssh_log_cb; |
232 | 0 | } |
233 | | |
234 | | /** |
235 | | * @brief Get the userdata of the logging function. |
236 | | * |
237 | | * @return The userdata if set or NULL. |
238 | | */ |
239 | | void *ssh_get_log_userdata(void) |
240 | 0 | { |
241 | 0 | if (ssh_log_userdata == NULL) { |
242 | 0 | return NULL; |
243 | 0 | } |
244 | | |
245 | 0 | return ssh_log_userdata; |
246 | 0 | } |
247 | | |
248 | | /** |
249 | | * @brief Set the userdata for the logging function. |
250 | | * |
251 | | * @param[in] data The userdata to set. |
252 | | * |
253 | | * @return SSH_OK on success. |
254 | | */ |
255 | | int ssh_set_log_userdata(void *data) |
256 | 0 | { |
257 | 0 | ssh_log_userdata = data; |
258 | |
|
259 | 0 | return 0; |
260 | 0 | } |
261 | | |
262 | | /** @} */ |