pcsc-lite 2.0.1
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 pthread_mutex_t LastTimeMutex = PTHREAD_MUTEX_INITIALIZER;
114
115static void log_line(const int priority, const char *DebugBuffer,
116 unsigned int rv);
117
118/*
119 * log a message with the RV value returned by the daemon
120 */
121void log_msg_rv(const int priority, unsigned int rv, const char *fmt, ...)
122{
123 char DebugBuffer[DEBUG_BUF_SIZE];
124 va_list argptr;
125
126 if ((priority < LogLevel) /* log priority lower than threshold? */
127 || (DEBUGLOG_NO_DEBUG == LogMsgType))
128 return;
129
130 va_start(argptr, fmt);
131 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
132 va_end(argptr);
133
134 log_line(priority, DebugBuffer, rv);
135}
136
137void log_msg(const int priority, const char *fmt, ...)
138{
139 char DebugBuffer[DEBUG_BUF_SIZE];
140 va_list argptr;
141
142 if ((priority < LogLevel) /* log priority lower than threshold? */
143 || (DEBUGLOG_NO_DEBUG == LogMsgType))
144 return;
145
146 va_start(argptr, fmt);
147 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
148 va_end(argptr);
149
150 log_line(priority, DebugBuffer, -1);
151} /* log_msg */
152
153/* convert from integer rv value to a string value
154 * SCARD_S_SUCCESS -> "SCARD_S_SUCCESS"
155 */
156const char * rv2text(unsigned int rv)
157{
158 const char *rv_text = NULL;
159 static __thread char strError[30];
160
161#define CASE(x) \
162 case x: \
163 rv_text = "rv=" #x; \
164 break
165
166 if (rv != (unsigned int)-1)
167 {
168 switch (rv)
169 {
170 CASE(SCARD_S_SUCCESS);
171 CASE(SCARD_E_CANCELLED);
176 CASE(SCARD_E_NO_MEMORY);
177 CASE(SCARD_E_NO_SERVICE);
183 CASE(SCARD_E_TIMEOUT);
186 CASE(SCARD_F_COMM_ERROR);
189 CASE(SCARD_W_RESET_CARD);
193
194 default:
195 (void)snprintf(strError, sizeof(strError)-1,
196 "Unknown error: 0x%08X", rv);
197 rv_text = strError;
198 }
199 }
200
201 return rv_text;
202}
203
204static void log_line(const int priority, const char *DebugBuffer,
205 unsigned int rv)
206{
207 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
208 syslog(LOG_INFO, "%s", DebugBuffer);
209 else
210 {
211 static struct timeval last_time = { 0, 0 };
212 struct timeval new_time = { 0, 0 };
213 struct timeval tmp;
214 int delta;
215 pthread_t thread_id;
216 const char *rv_text = NULL;
217
218 (void)pthread_mutex_lock(&LastTimeMutex);
219 gettimeofday(&new_time, NULL);
220 if (0 == last_time.tv_sec)
221 last_time = new_time;
222
223 tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
224 tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
225 if (tmp.tv_usec < 0)
226 {
227 tmp.tv_sec--;
228 tmp.tv_usec += 1000000;
229 }
230 if (tmp.tv_sec < 100)
231 delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
232 else
233 delta = 99999999;
234
235 last_time = new_time;
236 (void)pthread_mutex_unlock(&LastTimeMutex);
237
238 thread_id = pthread_self();
239
240 rv_text = rv2text(rv);
241
242 if (LogDoColor)
243 {
244 const char *color_pfx = "", *color_sfx = "\33[0m";
245 const char *time_pfx = "\33[36m", *time_sfx = color_sfx;
246
247 switch (priority)
248 {
249 case PCSC_LOG_CRITICAL:
250 color_pfx = "\33[01;31m"; /* bright + Red */
251 break;
252
253 case PCSC_LOG_ERROR:
254 color_pfx = "\33[35m"; /* Magenta */
255 break;
256
257 case PCSC_LOG_INFO:
258 color_pfx = "\33[34m"; /* Blue */
259 break;
260
261 case PCSC_LOG_DEBUG:
262 color_pfx = ""; /* normal (black) */
263 color_sfx = "";
264 break;
265 }
266
267#ifdef __APPLE__
268#define THREAD_FORMAT "%p"
269#else
270#define THREAD_FORMAT "%lu"
271#endif
272 if (rv_text)
273 {
274 const char * rv_pfx = "", * rv_sfx = "";
275 if (rv != SCARD_S_SUCCESS)
276 {
277 rv_pfx = "\33[31m"; /* Red */
278 rv_sfx = "\33[0m";
279 }
280
281 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s, %s%s%s\n",
282 time_pfx, delta, time_sfx, thread_id,
283 color_pfx, DebugBuffer, color_sfx,
284 rv_pfx, rv_text, rv_sfx);
285 }
286 else
287 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s\n",
288 time_pfx, delta, time_sfx, thread_id,
289 color_pfx, DebugBuffer, color_sfx);
290 }
291 else
292 {
293 if (rv_text)
294 printf("%.8d %s, %s\n", delta, DebugBuffer, rv_text);
295 else
296 printf("%.8d %s\n", delta, DebugBuffer);
297 }
298 fflush(stdout);
299 }
300} /* log_line */
301
302static void log_xxd_always(const int priority, const char *msg,
303 const unsigned char *buffer, const int len)
304{
305 char DebugBuffer[len*3 + strlen(msg) +1];
306 int i;
307 char *c;
308
309 /* DebugBuffer is always big enough for msg */
310 strcpy(DebugBuffer, msg);
311 c = DebugBuffer + strlen(DebugBuffer);
312
313 for (i = 0; (i < len); ++i)
314 {
315 /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
316 snprintf(c, 4, "%02X ", buffer[i]);
317 c += 3;
318 }
319
320 log_line(priority, DebugBuffer, -1);
321} /* log_xxd_always */
322
323void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
324 const int len)
325{
326 if ((priority < LogLevel) /* log priority lower than threshold? */
327 || (DEBUGLOG_NO_DEBUG == LogMsgType))
328 return;
329
330 /* len is an error value? */
331 if (len < 0)
332 return;
333
334 log_xxd_always(priority, msg, buffer, len);
335} /* log_xxd */
336
337void DebugLogSetLogType(const int dbgtype)
338{
339 switch (dbgtype)
340 {
341 case DEBUGLOG_NO_DEBUG:
342 case DEBUGLOG_SYSLOG_DEBUG:
343 case DEBUGLOG_STDOUT_DEBUG:
344 case DEBUGLOG_STDOUT_COLOR_DEBUG:
345 LogMsgType = dbgtype;
346 break;
347 default:
348 Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
349 dbgtype);
350 LogMsgType = DEBUGLOG_STDOUT_DEBUG;
351 }
352
353 /* log to stdout and stdout is a tty? */
354 if ((DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
355 || (DEBUGLOG_STDOUT_COLOR_DEBUG == LogMsgType))
356 {
357 char *term;
358
359 term = getenv("TERM");
360 if (term)
361 {
362 const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
363 unsigned int i;
364
365 /* for each known color terminal */
366 for (i = 0; i < COUNT_OF(terms); i++)
367 {
368 /* we found a supported term? */
369 if (0 == strcmp(terms[i], term))
370 {
371 LogDoColor = 1;
372 break;
373 }
374 }
375 }
376 }
377}
378
379void DebugLogSetLevel(const int level)
380{
381 LogLevel = level;
382 switch (level)
383 {
384 case PCSC_LOG_CRITICAL:
385 case PCSC_LOG_ERROR:
386 /* do not log anything */
387 break;
388
389 case PCSC_LOG_INFO:
390 Log1(PCSC_LOG_INFO, "debug level=info");
391 break;
392
393 case PCSC_LOG_DEBUG:
394 Log1(PCSC_LOG_DEBUG, "debug level=debug");
395 break;
396
397 default:
398 LogLevel = PCSC_LOG_INFO;
399 Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
400 level);
401 }
402}
403
404INTERNAL void DebugLogSetCategory(const int dbginfo)
405{
406 /* use a negative number to UNset
407 * typically use ~DEBUG_CATEGORY_APDU
408 */
409 if (dbginfo < 0)
410 LogCategory &= dbginfo;
411 else
412 LogCategory |= dbginfo;
413
414 if (LogCategory & DEBUG_CATEGORY_APDU)
415 Log1(PCSC_LOG_INFO, "Debug options: APDU");
416}
417
418INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
419 const int len)
420{
421 if ((category & DEBUG_CATEGORY_APDU)
422 && (LogCategory & DEBUG_CATEGORY_APDU))
423 log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
424
425 if ((category & DEBUG_CATEGORY_SW)
426 && (LogCategory & DEBUG_CATEGORY_APDU))
427 log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
428}
429
430/*
431 * old function supported for backward object code compatibility
432 * defined only for pcscd
433 */
434#ifdef PCSCD
435void debug_msg(const char *fmt, ...);
436void debug_msg(const char *fmt, ...)
437{
438 char DebugBuffer[DEBUG_BUF_SIZE];
439 va_list argptr;
440
441 if (DEBUGLOG_NO_DEBUG == LogMsgType)
442 return;
443
444 va_start(argptr, fmt);
445 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
446 va_end(argptr);
447
448 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
449 syslog(LOG_INFO, "%s", DebugBuffer);
450 else
451 puts(DebugBuffer);
452} /* debug_msg */
453
454void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
455void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
456{
457 log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
458} /* debug_xxd */
459#endif
460
461#endif /* NO_LOG */
462
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.