pcsc-lite 2.3.3
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-2024
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#include <syslog.h>
40#include <unistd.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <stdarg.h>
45#include <assert.h>
46#include <sys/types.h>
47#include <sys/time.h>
48#include <time.h>
49#include <pthread.h>
50#include <stdbool.h>
51
52#include "pcsclite.h"
53#include "misc.h"
54#include "debuglog.h"
55#include "sys_generic.h"
56
57#ifdef NO_LOG
58
59void log_msg(const int priority, const char *fmt, ...)
60{
61 (void)priority;
62 (void)fmt;
63}
64
65void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
66 const int len)
67{
68 (void)priority;
69 (void)msg;
70 (void)buffer;
71 (void)len;
72}
73
74void DebugLogSetLogType(const int dbgtype)
75{
76 (void)dbgtype;
77}
78
79void DebugLogSetLevel(const int level)
80{
81 (void)level;
82}
83
84INTERNAL void DebugLogSetCategory(const int dbginfo)
85{
86 (void)dbginfo;
87}
88
89INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
90 const int len)
91{
92 (void)category;
93 (void)buffer;
94 (void)len;
95}
96
97#else
98
102#define DEBUG_BUF_SIZE 2048
103
104static char LogMsgType = DEBUGLOG_NO_DEBUG;
105static char LogCategory = DEBUG_CATEGORY_NOTHING;
106
108static char LogLevel = PCSC_LOG_ERROR;
109
110static bool LogDoColor = false;
112static pthread_mutex_t LastTimeMutex = PTHREAD_MUTEX_INITIALIZER;
113
114static void log_line(const int priority, const char *DebugBuffer,
115 unsigned int rv);
116
117/*
118 * log a message with the RV value returned by the daemon
119 */
120void log_msg_rv(const int priority, unsigned int rv, const char *fmt, ...)
121{
122 char DebugBuffer[DEBUG_BUF_SIZE];
123 va_list argptr;
124
125 if ((priority < LogLevel) /* log priority lower than threshold? */
126 || (DEBUGLOG_NO_DEBUG == LogMsgType))
127 return;
128
129 va_start(argptr, fmt);
130 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
131 va_end(argptr);
132
133 log_line(priority, DebugBuffer, rv);
134}
135
136void log_msg(const int priority, const char *fmt, ...)
137{
138 char DebugBuffer[DEBUG_BUF_SIZE];
139 va_list argptr;
140
141 if ((priority < LogLevel) /* log priority lower than threshold? */
142 || (DEBUGLOG_NO_DEBUG == LogMsgType))
143 return;
144
145 va_start(argptr, fmt);
146 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
147 va_end(argptr);
148
149 log_line(priority, DebugBuffer, -1);
150} /* log_msg */
151
152/* convert from integer rv value to a string value
153 * SCARD_S_SUCCESS -> "SCARD_S_SUCCESS"
154 */
155const char * rv2text(unsigned int rv)
156{
157 const char *rv_text = NULL;
158 static __thread char strError[30];
159
160#define CASE(x) \
161 case x: \
162 rv_text = "rv=" #x; \
163 break
164
165 if (rv != (unsigned int)-1)
166 {
167 switch (rv)
168 {
169 CASE(SCARD_S_SUCCESS);
170 CASE(SCARD_E_CANCELLED);
175 CASE(SCARD_E_NO_MEMORY);
176 CASE(SCARD_E_NO_SERVICE);
182 CASE(SCARD_E_TIMEOUT);
185 CASE(SCARD_F_COMM_ERROR);
188 CASE(SCARD_W_RESET_CARD);
192
193 default:
194 (void)snprintf(strError, sizeof(strError)-1,
195 "Unknown error: 0x%08X", rv);
196 rv_text = strError;
197 }
198 }
199
200 return rv_text;
201}
202
203static void log_line(const int priority, const char *DebugBuffer,
204 unsigned int rv)
205{
206 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
207 syslog(LOG_INFO, "%s", DebugBuffer);
208 else
209 {
210 static struct timeval last_time = { 0, 0 };
211 struct timeval new_time = { 0, 0 };
212 struct timeval tmp;
213 int delta;
214 pthread_t thread_id;
215 const char *rv_text = NULL;
216
217 (void)pthread_mutex_lock(&LastTimeMutex);
218 gettimeofday(&new_time, NULL);
219 if (0 == last_time.tv_sec)
220 last_time = new_time;
221
222 tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
223 tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
224 if (tmp.tv_usec < 0)
225 {
226 tmp.tv_sec--;
227 tmp.tv_usec += 1000000;
228 }
229 if (tmp.tv_sec < 100)
230 delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
231 else
232 delta = 99999999;
233
234 last_time = new_time;
235 (void)pthread_mutex_unlock(&LastTimeMutex);
236
237 thread_id = pthread_self();
238
239 rv_text = rv2text(rv);
240
241 if (LogDoColor)
242 {
243 const char *color_pfx = "", *color_sfx = "\33[0m";
244 const char *time_pfx = "\33[36m", *time_sfx = color_sfx;
245
246 switch (priority)
247 {
248 case PCSC_LOG_CRITICAL:
249 color_pfx = "\33[01;31m"; /* bright + Red */
250 break;
251
252 case PCSC_LOG_ERROR:
253 color_pfx = "\33[35m"; /* Magenta */
254 break;
255
256 case PCSC_LOG_INFO:
257 color_pfx = "\33[34m"; /* Blue */
258 break;
259
260 case PCSC_LOG_DEBUG:
261 color_pfx = ""; /* normal (black) */
262 color_sfx = "";
263 break;
264 }
265
266#ifdef __GLIBC__
267#define THREAD_FORMAT "%lu"
268#else
269#define THREAD_FORMAT "%p"
270#endif
271 if (rv_text)
272 {
273 const char * rv_pfx = "", * rv_sfx = "";
274 if (rv != SCARD_S_SUCCESS)
275 {
276 rv_pfx = "\33[31m"; /* Red */
277 rv_sfx = "\33[0m";
278 }
279
280 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s, %s%s%s\n",
281 time_pfx, delta, time_sfx, thread_id,
282 color_pfx, DebugBuffer, color_sfx,
283 rv_pfx, rv_text, rv_sfx);
284 }
285 else
286 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s\n",
287 time_pfx, delta, time_sfx, thread_id,
288 color_pfx, DebugBuffer, color_sfx);
289 }
290 else
291 {
292 if (rv_text)
293 printf("%.8d %s, %s\n", delta, DebugBuffer, rv_text);
294 else
295 printf("%.8d %s\n", delta, DebugBuffer);
296 }
297 fflush(stdout);
298 }
299} /* log_line */
300
301static void log_xxd_always(const int priority, const char *msg,
302 const unsigned char *buffer, const int len)
303{
304 char DebugBuffer[len*3 + strlen(msg) +1];
305 int i;
306 char *c;
307
308 /* DebugBuffer is always big enough for msg */
309 strcpy(DebugBuffer, msg);
310 c = DebugBuffer + strlen(DebugBuffer);
311
312 for (i = 0; (i < len); ++i)
313 {
314 /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
315 snprintf(c, 4, "%02X ", buffer[i]);
316 c += 3;
317 }
318
319 log_line(priority, DebugBuffer, -1);
320} /* log_xxd_always */
321
322void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
323 const int len)
324{
325 if ((priority < LogLevel) /* log priority lower than threshold? */
326 || (DEBUGLOG_NO_DEBUG == LogMsgType))
327 return;
328
329 /* len is an error value? */
330 if (len < 0)
331 return;
332
333 log_xxd_always(priority, msg, buffer, len);
334} /* log_xxd */
335
336void DebugLogSetLogType(const int dbgtype)
337{
338 switch (dbgtype)
339 {
340 case DEBUGLOG_NO_DEBUG:
341 case DEBUGLOG_SYSLOG_DEBUG:
342 case DEBUGLOG_STDOUT_DEBUG:
343 LogMsgType = dbgtype;
344 break;
345 case DEBUGLOG_STDOUT_COLOR_DEBUG:
346 LogMsgType = dbgtype;
347 LogDoColor = true;
348 break;
349 default:
350 Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
351 dbgtype);
352 LogMsgType = DEBUGLOG_STDOUT_DEBUG;
353 }
354
355 /* log to stdout and stdout is a tty? */
356 if (DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
357 {
358 const char *term;
359
360 term = SYS_GetEnv("TERM");
361 if (term)
362 {
363 const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
364 unsigned int i;
365
366 /* for each known color terminal */
367 for (i = 0; i < COUNT_OF(terms); i++)
368 {
369 /* we found a supported term? */
370 if (0 == strcmp(terms[i], term))
371 {
372 LogDoColor = true;
373 break;
374 }
375 }
376 }
377 }
378}
379
380void DebugLogSetLevel(const int level)
381{
382 LogLevel = level;
383 switch (level)
384 {
385 case PCSC_LOG_CRITICAL:
386 case PCSC_LOG_ERROR:
387 /* do not log anything */
388 break;
389
390 case PCSC_LOG_INFO:
391 Log1(PCSC_LOG_INFO, "debug level=info");
392 break;
393
394 case PCSC_LOG_DEBUG:
395 Log1(PCSC_LOG_DEBUG, "debug level=debug");
396 break;
397
398 default:
399 LogLevel = PCSC_LOG_INFO;
400 Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
401 level);
402 }
403}
404
405INTERNAL void DebugLogSetCategory(const int dbginfo)
406{
407 /* use a negative number to UNset
408 * typically use ~DEBUG_CATEGORY_APDU
409 */
410 if (dbginfo < 0)
411 LogCategory &= dbginfo;
412 else
413 LogCategory |= dbginfo;
414
415 if (LogCategory & DEBUG_CATEGORY_APDU)
416 Log1(PCSC_LOG_INFO, "Debug options: APDU");
417}
418
419INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
420 const int len)
421{
422 if ((category & DEBUG_CATEGORY_APDU)
423 && (LogCategory & DEBUG_CATEGORY_APDU))
424 log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
425
426 if ((category & DEBUG_CATEGORY_SW)
427 && (LogCategory & DEBUG_CATEGORY_APDU))
428 log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
429}
430
431/*
432 * old function supported for backward object code compatibility
433 * defined only for pcscd
434 */
435#ifdef PCSCD
436void debug_msg(const char *fmt, ...);
437void debug_msg(const char *fmt, ...)
438{
439 char DebugBuffer[DEBUG_BUF_SIZE];
440 va_list argptr;
441
442 if (DEBUGLOG_NO_DEBUG == LogMsgType)
443 return;
444
445 va_start(argptr, fmt);
446 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
447 va_end(argptr);
448
449 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
450 syslog(LOG_INFO, "%s", DebugBuffer);
451 else
452 puts(DebugBuffer);
453} /* debug_msg */
454
455void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
456void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
457{
458 log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
459} /* debug_xxd */
460#endif
461
462#endif /* NO_LOG */
463
static char LogLevel
default level
Definition debuglog.c:108
#define DEBUG_BUF_SIZE
Max string size dumping a maximum of 2 lines of 80 characters.
Definition debuglog.c:102
static bool LogDoColor
no color by default
Definition debuglog.c:110
This handles debugging.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
#define SCARD_W_UNRESPONSIVE_CARD
The smart card is not responding to a reset.
#define SCARD_E_PROTO_MISMATCH
The requested protocols are incompatible with the protocol currently in use with the smart card.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
#define SCARD_S_SUCCESS
No error was encountered.
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
#define SCARD_E_NO_SMARTCARD
The operation requires a Smart Card, but no Smart Card is currently in the device.
#define SCARD_E_NOT_TRANSACTED
An attempt was made to end a non-existent transaction.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
#define SCARD_W_UNPOWERED_CARD
Power has been removed from the smart card, so that further communication is not possible.
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition sys_unix.c:168