pcsc-lite 2.4.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-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
37
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;
111
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);
177 CASE(SCARD_E_NO_SERVICE);
184 CASE(SCARD_E_TIMEOUT);
187 CASE(SCARD_F_COMM_ERROR);
190 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 __GLIBC__
268#define THREAD_FORMAT "%lu"
269#else
270#define THREAD_FORMAT "%p"
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 LogMsgType = dbgtype;
345 break;
346 case DEBUGLOG_STDOUT_COLOR_DEBUG:
347 LogMsgType = dbgtype;
348 LogDoColor = true;
349 break;
350 default:
351 Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
352 dbgtype);
353 LogMsgType = DEBUGLOG_STDOUT_DEBUG;
354 }
355
356 /* log to stdout and stdout is a tty? */
357 if (DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
358 {
359 const char *term;
360
361 term = SYS_GetEnv("TERM");
362 if (term)
363 {
364 const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
365 unsigned int i;
366
367 /* for each known color terminal */
368 for (i = 0; i < COUNT_OF(terms); i++)
369 {
370 /* we found a supported term? */
371 if (0 == strcmp(terms[i], term))
372 {
373 LogDoColor = true;
374 break;
375 }
376 }
377 }
378 }
379}
380
381void DebugLogSetLevel(const int level)
382{
383 LogLevel = level;
384 switch (level)
385 {
386 case PCSC_LOG_CRITICAL:
387 case PCSC_LOG_ERROR:
388 /* do not log anything */
389 break;
390
391 case PCSC_LOG_INFO:
392 Log1(PCSC_LOG_INFO, "debug level=info");
393 break;
394
395 case PCSC_LOG_DEBUG:
396 Log1(PCSC_LOG_DEBUG, "debug level=debug");
397 break;
398
399 default:
400 LogLevel = PCSC_LOG_INFO;
401 Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
402 level);
403 }
404}
405
406INTERNAL void DebugLogSetCategory(const int dbginfo)
407{
408 /* use a negative number to UNset
409 * typically use ~DEBUG_CATEGORY_APDU
410 */
411 if (dbginfo < 0)
412 LogCategory &= dbginfo;
413 else
414 LogCategory |= dbginfo;
415
416 if (LogCategory & DEBUG_CATEGORY_APDU)
417 Log1(PCSC_LOG_INFO, "Debug options: APDU");
418}
419
420INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
421 const int len)
422{
423 if ((category & DEBUG_CATEGORY_APDU)
424 && (LogCategory & DEBUG_CATEGORY_APDU))
425 log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
426
427 if ((category & DEBUG_CATEGORY_SW)
428 && (LogCategory & DEBUG_CATEGORY_APDU))
429 log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
430}
431
432/*
433 * old function supported for backward object code compatibility
434 * defined only for pcscd
435 */
436#ifdef PCSCD
437void debug_msg(const char *fmt, ...);
438void debug_msg(const char *fmt, ...)
439{
440 char DebugBuffer[DEBUG_BUF_SIZE];
441 va_list argptr;
442
443 if (DEBUGLOG_NO_DEBUG == LogMsgType)
444 return;
445
446 va_start(argptr, fmt);
447 vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
448 va_end(argptr);
449
450 if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
451 syslog(LOG_INFO, "%s", DebugBuffer);
452 else
453 puts(DebugBuffer);
454} /* debug_msg */
455
456void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
457void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
458{
459 log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
460} /* debug_xxd */
461#endif
462
463#endif /* NO_LOG */
464
static char LogLevel
default level is quiet to avoid polluting fd 2 (possibly NOT stderr)
Definition debug.c:65
static signed char LogDoColor
no color by default
Definition debug.c:67
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_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition pcsclite.h:167
#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