pcsc-lite 1.9.9
debuglog.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2002
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2002-2011
7 * Ludovic Rousseau <ludovic.rousseau@free.fr>
8 *
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions
11are met:
12
131. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
152. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
183. The name of the author may not be used to endorse or promote products
19 derived from this software without specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
38#include "config.h"
39#ifdef HAVE_SYSLOG_H
40#include <syslog.h>
41#endif
42#include <unistd.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <stdarg.h>
47#include <assert.h>
48#include <sys/types.h>
49#include <sys/time.h>
50#include <time.h>
51#include <pthread.h>
52
53#include "pcsclite.h"
54#include "misc.h"
55#include "debuglog.h"
56#include "sys_generic.h"
57
58#ifdef NO_LOG
59
60void log_msg(const int priority, const char *fmt, ...)
61{
62 (void)priority;
63 (void)fmt;
64}
65
66void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
67 const int len)
68{
69 (void)priority;
70 (void)msg;
71 (void)buffer;
72 (void)len;
73}
74
75void DebugLogSetLogType(const int dbgtype)
76{
77 (void)dbgtype;
78}
79
80void DebugLogSetLevel(const int level)
81{
82 (void)level;
83}
84
85INTERNAL void DebugLogSetCategory(const int dbginfo)
86{
87 (void)dbginfo;
88}
89
90INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
91 const int len)
92{
93 (void)category;
94 (void)buffer;
95 (void)len;
96}
97
98#else
99
103#define DEBUG_BUF_SIZE 2048
104
105static char LogMsgType = DEBUGLOG_NO_DEBUG;
106static char LogCategory = DEBUG_CATEGORY_NOTHING;
107
109static char LogLevel = PCSC_LOG_ERROR;
110
111static signed char LogDoColor = 0;
113static void log_line(const int priority, const char *DebugBuffer,
114 unsigned int rv);
115
116/*
117 * log a message with the RV value returned by the daemon
118 */
119void log_msg_rv(const int priority, unsigned int rv, const char *fmt, ...)
120{
121 char DebugBuffer[DEBUG_BUF_SIZE];
122 va_list argptr;
123
124 if ((priority < LogLevel) /* log priority lower than threshold? */
125 || (DEBUGLOG_NO_DEBUG == LogMsgType))
126 return;
127
128 va_start(argptr, fmt);
129 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
130 va_end(argptr);
131
132 log_line(priority, DebugBuffer, rv);
133}
134
135void log_msg(const int priority, const char *fmt, ...)
136{
137 char DebugBuffer[DEBUG_BUF_SIZE];
138 va_list argptr;
139
140 if ((priority < LogLevel) /* log priority lower than threshold? */
141 || (DEBUGLOG_NO_DEBUG == LogMsgType))
142 return;
143
144 va_start(argptr, fmt);
145 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
146 va_end(argptr);
147
148 log_line(priority, DebugBuffer, -1);
149} /* log_msg */
150
151/* convert from integer rv value to a string value
152 * SCARD_S_SUCCESS -> "SCARD_S_SUCCESS"
153 */
154const char * rv2text(unsigned int rv)
155{
156 const char *rv_text = NULL;
157 static __thread char strError[30];
158
159#define CASE(x) \
160 case x: \
161 rv_text = "rv=" #x; \
162 break
163
164 if (rv != (unsigned int)-1)
165 {
166 switch (rv)
167 {
168 CASE(SCARD_S_SUCCESS);
169 CASE(SCARD_E_CANCELLED);
174 CASE(SCARD_E_NO_MEMORY);
175 CASE(SCARD_E_NO_SERVICE);
181 CASE(SCARD_E_TIMEOUT);
184 CASE(SCARD_F_COMM_ERROR);
187 CASE(SCARD_W_RESET_CARD);
191
192 default:
193 (void)snprintf(strError, sizeof(strError)-1,
194 "Unknown error: 0x%08X", rv);
195 rv_text = strError;
196 }
197 }
198
199 return rv_text;
200}
201
202static void log_line(const int priority, const char *DebugBuffer,
203 unsigned int rv)
204{
205 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
206 syslog(LOG_INFO, "%s", DebugBuffer);
207 else
208 {
209 static struct timeval last_time = { 0, 0 };
210 struct timeval new_time = { 0, 0 };
211 struct timeval tmp;
212 int delta;
213 pthread_t thread_id;
214 const char *rv_text = NULL;
215
216 gettimeofday(&new_time, NULL);
217 if (0 == last_time.tv_sec)
218 last_time = new_time;
219
220 tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
221 tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
222 if (tmp.tv_usec < 0)
223 {
224 tmp.tv_sec--;
225 tmp.tv_usec += 1000000;
226 }
227 if (tmp.tv_sec < 100)
228 delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
229 else
230 delta = 99999999;
231
232 last_time = new_time;
233
234 thread_id = pthread_self();
235
236 rv_text = rv2text(rv);
237
238 if (LogDoColor)
239 {
240 const char *color_pfx = "", *color_sfx = "\33[0m";
241 const char *time_pfx = "\33[36m", *time_sfx = color_sfx;
242
243 switch (priority)
244 {
245 case PCSC_LOG_CRITICAL:
246 color_pfx = "\33[01;31m"; /* bright + Red */
247 break;
248
249 case PCSC_LOG_ERROR:
250 color_pfx = "\33[35m"; /* Magenta */
251 break;
252
253 case PCSC_LOG_INFO:
254 color_pfx = "\33[34m"; /* Blue */
255 break;
256
257 case PCSC_LOG_DEBUG:
258 color_pfx = ""; /* normal (black) */
259 color_sfx = "";
260 break;
261 }
262
263#ifdef __APPLE__
264#define THREAD_FORMAT "%p"
265#else
266#define THREAD_FORMAT "%lu"
267#endif
268 if (rv_text)
269 {
270 const char * rv_pfx = "", * rv_sfx = "";
271 if (rv != SCARD_S_SUCCESS)
272 {
273 rv_pfx = "\33[31m"; /* Red */
274 rv_sfx = "\33[0m";
275 }
276
277 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s, %s%s%s\n",
278 time_pfx, delta, time_sfx, thread_id,
279 color_pfx, DebugBuffer, color_sfx,
280 rv_pfx, rv_text, rv_sfx);
281 }
282 else
283 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s\n",
284 time_pfx, delta, time_sfx, thread_id,
285 color_pfx, DebugBuffer, color_sfx);
286 }
287 else
288 {
289 if (rv_text)
290 printf("%.8d %s, %s\n", delta, DebugBuffer, rv_text);
291 else
292 printf("%.8d %s\n", delta, DebugBuffer);
293 }
294 fflush(stdout);
295 }
296} /* log_line */
297
298static void log_xxd_always(const int priority, const char *msg,
299 const unsigned char *buffer, const int len)
300{
301 char DebugBuffer[len*3 + strlen(msg) +1];
302 int i;
303 char *c;
304
305 /* DebugBuffer is always big enough for msg */
306 strcpy(DebugBuffer, msg);
307 c = DebugBuffer + strlen(DebugBuffer);
308
309 for (i = 0; (i < len); ++i)
310 {
311 /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
312 snprintf(c, 4, "%02X ", buffer[i]);
313 c += 3;
314 }
315
316 log_line(priority, DebugBuffer, -1);
317} /* log_xxd_always */
318
319void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
320 const int len)
321{
322 if ((priority < LogLevel) /* log priority lower than threshold? */
323 || (DEBUGLOG_NO_DEBUG == LogMsgType))
324 return;
325
326 /* len is an error value? */
327 if (len < 0)
328 return;
329
330 log_xxd_always(priority, msg, buffer, len);
331} /* log_xxd */
332
333void DebugLogSetLogType(const int dbgtype)
334{
335 switch (dbgtype)
336 {
337 case DEBUGLOG_NO_DEBUG:
338 case DEBUGLOG_SYSLOG_DEBUG:
339 case DEBUGLOG_STDOUT_DEBUG:
340 case DEBUGLOG_STDOUT_COLOR_DEBUG:
341 LogMsgType = dbgtype;
342 break;
343 default:
344 Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
345 dbgtype);
346 LogMsgType = DEBUGLOG_STDOUT_DEBUG;
347 }
348
349 /* log to stdout and stdout is a tty? */
350 if ((DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
351 || (DEBUGLOG_STDOUT_COLOR_DEBUG == LogMsgType))
352 {
353 char *term;
354
355 term = getenv("TERM");
356 if (term)
357 {
358 const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
359 unsigned int i;
360
361 /* for each known color terminal */
362 for (i = 0; i < COUNT_OF(terms); i++)
363 {
364 /* we found a supported term? */
365 if (0 == strcmp(terms[i], term))
366 {
367 LogDoColor = 1;
368 break;
369 }
370 }
371 }
372 }
373}
374
375void DebugLogSetLevel(const int level)
376{
377 LogLevel = level;
378 switch (level)
379 {
380 case PCSC_LOG_CRITICAL:
381 case PCSC_LOG_ERROR:
382 /* do not log anything */
383 break;
384
385 case PCSC_LOG_INFO:
386 Log1(PCSC_LOG_INFO, "debug level=info");
387 break;
388
389 case PCSC_LOG_DEBUG:
390 Log1(PCSC_LOG_DEBUG, "debug level=debug");
391 break;
392
393 default:
394 LogLevel = PCSC_LOG_INFO;
395 Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
396 level);
397 }
398}
399
400INTERNAL void DebugLogSetCategory(const int dbginfo)
401{
402 /* use a negative number to UNset
403 * typically use ~DEBUG_CATEGORY_APDU
404 */
405 if (dbginfo < 0)
406 LogCategory &= dbginfo;
407 else
408 LogCategory |= dbginfo;
409
410 if (LogCategory & DEBUG_CATEGORY_APDU)
411 Log1(PCSC_LOG_INFO, "Debug options: APDU");
412}
413
414INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
415 const int len)
416{
417 if ((category & DEBUG_CATEGORY_APDU)
418 && (LogCategory & DEBUG_CATEGORY_APDU))
419 log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
420
421 if ((category & DEBUG_CATEGORY_SW)
422 && (LogCategory & DEBUG_CATEGORY_APDU))
423 log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
424}
425
426/*
427 * old function supported for backward object code compatibility
428 * defined only for pcscd
429 */
430#ifdef PCSCD
431void debug_msg(const char *fmt, ...);
432void debug_msg(const char *fmt, ...)
433{
434 char DebugBuffer[DEBUG_BUF_SIZE];
435 va_list argptr;
436
437 if (DEBUGLOG_NO_DEBUG == LogMsgType)
438 return;
439
440 va_start(argptr, fmt);
441 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
442 va_end(argptr);
443
444 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
445 syslog(LOG_INFO, "%s", DebugBuffer);
446 else
447 puts(DebugBuffer);
448} /* debug_msg */
449
450void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
451void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
452{
453 log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
454} /* debug_xxd */
455#endif
456
457#endif /* NO_LOG */
458
static char LogLevel
default level
Definition debuglog.c:109
#define DEBUG_BUF_SIZE
Max string size dumping a maximum of 2 lines of 80 characters.
Definition debuglog.c:103
static signed char LogDoColor
no color by default
Definition debuglog.c:111
This handles debugging.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition pcsclite.h:113
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition pcsclite.h:109
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition pcsclite.h:125
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition pcsclite.h:216
#define SCARD_W_UNRESPONSIVE_CARD
The smart card is not responding to a reset.
Definition pcsclite.h:212
#define SCARD_E_PROTO_MISMATCH
The requested protocols are incompatible with the protocol currently in use with the smart card.
Definition pcsclite.h:137
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition pcsclite.h:201
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition pcsclite.h:129
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition pcsclite.h:145
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition pcsclite.h:127
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition pcsclite.h:218
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition pcsclite.h:123
#define SCARD_E_NO_SMARTCARD
The operation requires a Smart Card, but no Smart Card is currently in the device.
Definition pcsclite.h:131
#define SCARD_E_NOT_TRANSACTED
An attempt was made to end a non-existent transaction.
Definition pcsclite.h:151
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition pcsclite.h:153
#define SCARD_W_UNPOWERED_CARD
Power has been removed from the smart card, so that further communication is not possible.
Definition pcsclite.h:214
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
Definition pcsclite.h:171
This keeps a list of defines for pcsc-lite.
This handles abstract system level calls.