pcsc-lite 2.3.0
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
51#include "pcsclite.h"
52#include "misc.h"
53#include "debuglog.h"
54#include "sys_generic.h"
55
56#ifdef NO_LOG
57
58void log_msg(const int priority, const char *fmt, ...)
59{
60 (void)priority;
61 (void)fmt;
62}
63
64void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
65 const int len)
66{
67 (void)priority;
68 (void)msg;
69 (void)buffer;
70 (void)len;
71}
72
73void DebugLogSetLogType(const int dbgtype)
74{
75 (void)dbgtype;
76}
77
78void DebugLogSetLevel(const int level)
79{
80 (void)level;
81}
82
83INTERNAL void DebugLogSetCategory(const int dbginfo)
84{
85 (void)dbginfo;
86}
87
88INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
89 const int len)
90{
91 (void)category;
92 (void)buffer;
93 (void)len;
94}
95
96#else
97
101#define DEBUG_BUF_SIZE 2048
102
103static char LogMsgType = DEBUGLOG_NO_DEBUG;
104static char LogCategory = DEBUG_CATEGORY_NOTHING;
105
107static char LogLevel = PCSC_LOG_ERROR;
108
109static signed char LogDoColor = 0;
111static pthread_mutex_t LastTimeMutex = PTHREAD_MUTEX_INITIALIZER;
112
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 (void)pthread_mutex_lock(&LastTimeMutex);
217 gettimeofday(&new_time, NULL);
218 if (0 == last_time.tv_sec)
219 last_time = new_time;
220
221 tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
222 tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
223 if (tmp.tv_usec < 0)
224 {
225 tmp.tv_sec--;
226 tmp.tv_usec += 1000000;
227 }
228 if (tmp.tv_sec < 100)
229 delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
230 else
231 delta = 99999999;
232
233 last_time = new_time;
234 (void)pthread_mutex_unlock(&LastTimeMutex);
235
236 thread_id = pthread_self();
237
238 rv_text = rv2text(rv);
239
240 if (LogDoColor)
241 {
242 const char *color_pfx = "", *color_sfx = "\33[0m";
243 const char *time_pfx = "\33[36m", *time_sfx = color_sfx;
244
245 switch (priority)
246 {
247 case PCSC_LOG_CRITICAL:
248 color_pfx = "\33[01;31m"; /* bright + Red */
249 break;
250
251 case PCSC_LOG_ERROR:
252 color_pfx = "\33[35m"; /* Magenta */
253 break;
254
255 case PCSC_LOG_INFO:
256 color_pfx = "\33[34m"; /* Blue */
257 break;
258
259 case PCSC_LOG_DEBUG:
260 color_pfx = ""; /* normal (black) */
261 color_sfx = "";
262 break;
263 }
264
265#ifdef __GLIBC__
266#define THREAD_FORMAT "%lu"
267#else
268#define THREAD_FORMAT "%p"
269#endif
270 if (rv_text)
271 {
272 const char * rv_pfx = "", * rv_sfx = "";
273 if (rv != SCARD_S_SUCCESS)
274 {
275 rv_pfx = "\33[31m"; /* Red */
276 rv_sfx = "\33[0m";
277 }
278
279 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s, %s%s%s\n",
280 time_pfx, delta, time_sfx, thread_id,
281 color_pfx, DebugBuffer, color_sfx,
282 rv_pfx, rv_text, rv_sfx);
283 }
284 else
285 printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s\n",
286 time_pfx, delta, time_sfx, thread_id,
287 color_pfx, DebugBuffer, color_sfx);
288 }
289 else
290 {
291 if (rv_text)
292 printf("%.8d %s, %s\n", delta, DebugBuffer, rv_text);
293 else
294 printf("%.8d %s\n", delta, DebugBuffer);
295 }
296 fflush(stdout);
297 }
298} /* log_line */
299
300static void log_xxd_always(const int priority, const char *msg,
301 const unsigned char *buffer, const int len)
302{
303 char DebugBuffer[len*3 + strlen(msg) +1];
304 int i;
305 char *c;
306
307 /* DebugBuffer is always big enough for msg */
308 strcpy(DebugBuffer, msg);
309 c = DebugBuffer + strlen(DebugBuffer);
310
311 for (i = 0; (i < len); ++i)
312 {
313 /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
314 snprintf(c, 4, "%02X ", buffer[i]);
315 c += 3;
316 }
317
318 log_line(priority, DebugBuffer, -1);
319} /* log_xxd_always */
320
321void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
322 const int len)
323{
324 if ((priority < LogLevel) /* log priority lower than threshold? */
325 || (DEBUGLOG_NO_DEBUG == LogMsgType))
326 return;
327
328 /* len is an error value? */
329 if (len < 0)
330 return;
331
332 log_xxd_always(priority, msg, buffer, len);
333} /* log_xxd */
334
335void DebugLogSetLogType(const int dbgtype)
336{
337 switch (dbgtype)
338 {
339 case DEBUGLOG_NO_DEBUG:
340 case DEBUGLOG_SYSLOG_DEBUG:
341 case DEBUGLOG_STDOUT_DEBUG:
342 case DEBUGLOG_STDOUT_COLOR_DEBUG:
343 LogMsgType = dbgtype;
344 break;
345 default:
346 Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
347 dbgtype);
348 LogMsgType = DEBUGLOG_STDOUT_DEBUG;
349 }
350
351 /* log to stdout and stdout is a tty? */
352 if ((DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
353 || (DEBUGLOG_STDOUT_COLOR_DEBUG == LogMsgType))
354 {
355 const char *term;
356
357 term = SYS_GetEnv("TERM");
358 if (term)
359 {
360 const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
361 unsigned int i;
362
363 /* for each known color terminal */
364 for (i = 0; i < COUNT_OF(terms); i++)
365 {
366 /* we found a supported term? */
367 if (0 == strcmp(terms[i], term))
368 {
369 LogDoColor = 1;
370 break;
371 }
372 }
373 }
374 }
375}
376
377void DebugLogSetLevel(const int level)
378{
379 LogLevel = level;
380 switch (level)
381 {
382 case PCSC_LOG_CRITICAL:
383 case PCSC_LOG_ERROR:
384 /* do not log anything */
385 break;
386
387 case PCSC_LOG_INFO:
388 Log1(PCSC_LOG_INFO, "debug level=info");
389 break;
390
391 case PCSC_LOG_DEBUG:
392 Log1(PCSC_LOG_DEBUG, "debug level=debug");
393 break;
394
395 default:
396 LogLevel = PCSC_LOG_INFO;
397 Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
398 level);
399 }
400}
401
402INTERNAL void DebugLogSetCategory(const int dbginfo)
403{
404 /* use a negative number to UNset
405 * typically use ~DEBUG_CATEGORY_APDU
406 */
407 if (dbginfo < 0)
408 LogCategory &= dbginfo;
409 else
410 LogCategory |= dbginfo;
411
412 if (LogCategory & DEBUG_CATEGORY_APDU)
413 Log1(PCSC_LOG_INFO, "Debug options: APDU");
414}
415
416INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
417 const int len)
418{
419 if ((category & DEBUG_CATEGORY_APDU)
420 && (LogCategory & DEBUG_CATEGORY_APDU))
421 log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
422
423 if ((category & DEBUG_CATEGORY_SW)
424 && (LogCategory & DEBUG_CATEGORY_APDU))
425 log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
426}
427
428/*
429 * old function supported for backward object code compatibility
430 * defined only for pcscd
431 */
432#ifdef PCSCD
433void debug_msg(const char *fmt, ...);
434void debug_msg(const char *fmt, ...)
435{
436 char DebugBuffer[DEBUG_BUF_SIZE];
437 va_list argptr;
438
439 if (DEBUGLOG_NO_DEBUG == LogMsgType)
440 return;
441
442 va_start(argptr, fmt);
443 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
444 va_end(argptr);
445
446 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
447 syslog(LOG_INFO, "%s", DebugBuffer);
448 else
449 puts(DebugBuffer);
450} /* debug_msg */
451
452void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
453void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
454{
455 log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
456} /* debug_xxd */
457#endif
458
459#endif /* NO_LOG */
460
static char LogLevel
default level
Definition debuglog.c:107
#define DEBUG_BUF_SIZE
Max string size dumping a maximum of 2 lines of 80 characters.
Definition debuglog.c:101
static signed char LogDoColor
no color by default
Definition debuglog.c:109
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:217
#define SCARD_W_UNRESPONSIVE_CARD
The smart card is not responding to a reset.
Definition pcsclite.h:213
#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:202
#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:219
#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:215
#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.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition sys_unix.c:168