1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <string.h>
6 #include <stdio.h>
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10
11 #define LOGMODULE log
12 #include "log.h"
13
14 #include <android-base/logging.h>
15
16 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
17 #define likely(x) __builtin_expect(!!(x), 1)
18 #define unlikely(x) __builtin_expect(!!(x), 0)
19 #else
20 /* Microsoft Visual Studio gives internal error C1001 with _builtin_expect */
21 #define likely(x) (x)
22 #define unlikely(x) (x)
23 #endif
24
25 extern "C" {
26
27 /**
28 * Compares two strings byte by byte and ignores the
29 * character's case. Stops at the n-th byte of both
30 * strings.
31 *
32 * This is basically a replacement of the POSIX-function
33 * _strncasecmp_. Since tpm2-tss is supposed to be compatible
34 * with ISO C99 and not with POSIX, _strncasecmp_ had to be
35 * replaced. This function creates lowercase representations
36 * of the strings and compares them bytewise.
37 *
38 * @param string1 The first of the two strings to compare
39 * @param string2 The second of the two strings to compare
40 * @param n The maximum number of bytes to compare
41 * @return 0 if both strings are equal (case insensitive),
42 * an integer greater than zero if string1 is greater than
43 * string 2 and an integer smaller than zero if string1 is
44 * smaller than string2
45 *
46 */
47 static int
case_insensitive_strncmp(const char * string1,const char * string2,size_t n)48 case_insensitive_strncmp(const char *string1,
49 const char *string2,
50 size_t n)
51 {
52 if ((string1 == NULL) && (string2 == NULL)) {
53 return 0;
54 }
55 if ((string1 == NULL) && (string2 != NULL)) {
56 return -1;
57 }
58 if ((string1 != NULL) && (string2 == NULL)) {
59 return 1;
60 }
61 if (n == 0) { // Zero bytes are always equal
62 return 0;
63 }
64 if (string1 == string2) { // return equal if they point to same location
65 return 0;
66 }
67
68 int result;
69 do {
70 result = tolower((unsigned char) *string1) - tolower((unsigned char) *string2);
71 if (result != 0) {
72 break;
73 }
74 } while (*string1++ != '\0' && *string2++ != '\0' && --n );
75 return result;
76 }
77
78 static log_level
79 getLogLevel(const char *module, log_level logdefault);
80
81 void
doLogBlob(log_level loglevel,const char * module,log_level logdefault,log_level * status,const char * file,const char * func,int line,const uint8_t * blob,size_t size,const char * fmt,...)82 doLogBlob(log_level loglevel, const char *module, log_level logdefault,
83 log_level *status,
84 const char *file, const char *func, int line,
85 const uint8_t *blob, size_t size, const char *fmt, ...)
86 {
87 if (unlikely(*status == LOGLEVEL_UNDEFINED))
88 *status = getLogLevel(module, logdefault);
89 if (loglevel > *status)
90 return;
91
92 va_list vaargs;
93 va_start(vaargs, fmt);
94 /* TODO: Unfortunately, vsnprintf(NULL, 0, ...) do not behave the same as
95 snprintf(NULL, 0, ...). Until there is an alternative, messages on
96 logblob are restricted to 255 characters
97 int msg_len = vsnprintf(NULL, 0, fmt, vaargs); */
98 int msg_len = 255;
99 char msg[msg_len+1];
100 vsnprintf(msg, sizeof(msg), fmt, vaargs);
101 va_end(vaargs);
102
103 doLog(loglevel, module, logdefault, status, file, func, line,
104 "%s (size=%zi):", msg, size);
105
106 unsigned int i, y, x, off, off2;
107 unsigned int width = 16;
108 #define LINE_LEN 64
109 char buffer[LINE_LEN];
110
111 for (i = 1, off = 0, off2 = 0; i <= size; i++) {
112 if (i == 1) {
113 sprintf(&buffer[off], "%04x: ", i - 1);
114 off += 6;
115 }
116
117 /* data output */
118 sprintf(&buffer[off], "%02x", blob[i-1]);
119 off += 2;
120
121 /* ASCII output */
122 if ((i % width == 0 && i > 1) || i == size) {
123 sprintf(&buffer[off], " ");
124 off += 2;
125 /* Align to the right */
126 for (x = off; x < width * 2 + 8; x++) {
127 sprintf(&buffer[off], " ");
128 off++;
129 }
130
131 /* Account for a line that is not 'full' */
132 unsigned int less = width - (i % width);
133 if (less == width)
134 less = 0;
135
136 for (y = 0; y < width - less; y++) {
137 if (isgraph(blob[off2 + y])) {
138 sprintf(&buffer[y + off], "%c", blob[off2 + y]);
139 } else {
140 sprintf(&buffer[y + off], "%c", '.');
141 }
142 }
143 /* print the line and restart */
144 fprintf (stderr, "%s\n", buffer);
145 off2 = i;
146 off = 0;
147 memset(buffer, '\0', LINE_LEN);
148 sprintf(&buffer[off], "%04x: ", i);
149 off += 6;
150 }
151 }
152 }
153
154 void
doLog(log_level loglevel,const char * module,log_level logdefault,log_level * status,const char * file,const char * func,int line,const char * msg,...)155 doLog(log_level loglevel, const char *module, log_level logdefault,
156 log_level *status,
157 const char *file, const char *func, int line,
158 const char *msg, ...)
159 {
160 if (unlikely(*status == LOGLEVEL_UNDEFINED))
161 *status = getLogLevel(module, logdefault);
162
163 if (loglevel > *status)
164 return;
165
166 int size = snprintf(NULL, 0, "%s:%s:%s:%d:%s() %s ",
167 log_strings[loglevel], module, file, line, func, msg);
168 char fmt[size+1];
169 snprintf(fmt, sizeof(fmt), "%s:%s:%s:%d:%s() %s ",
170 log_strings[loglevel], module, file, line, func, msg);
171
172 va_list vaargs;
173 va_start(vaargs, msg);
174 int complete_size = vsnprintf(NULL, 0, fmt, vaargs);
175 va_end(vaargs);
176
177 va_start(vaargs, msg);
178 char complete[complete_size+1];
179 vsnprintf(complete, sizeof(complete), fmt, vaargs);
180 va_end(vaargs);
181
182 fprintf(stderr, "%s\n", complete);
183
184 switch (loglevel) {
185 case LOGLEVEL_NONE:
186 LOG(ERROR) << complete;
187 break;
188 case LOGLEVEL_ERROR:
189 LOG(ERROR) << complete;
190 break;
191 case LOGLEVEL_WARNING:
192 LOG(WARNING) << complete;
193 break;
194 case LOGLEVEL_INFO:
195 LOG(INFO) << complete;
196 break;
197 case LOGLEVEL_DEBUG:
198 LOG(DEBUG) << complete;
199 break;
200 case LOGLEVEL_TRACE:
201 LOG(VERBOSE) << complete;
202 break;
203 case LOGLEVEL_UNDEFINED:
204 default:
205 LOG(WARNING) << complete;
206 break;
207 }
208 }
209
210 static log_level
log_stringlevel(const char * n)211 log_stringlevel(const char *n)
212 {
213 log_level i;
214 for(i = (log_level) 0; i < sizeof(log_strings)/sizeof(log_strings[0]); i = (log_level) ((int) i + 1)) {
215 if (case_insensitive_strncmp(log_strings[i], n, strlen(log_strings[i])) == 0) {
216 return i;
217 }
218 }
219 return LOGLEVEL_UNDEFINED;
220 }
221
222 static log_level
getLogLevel(const char * module,log_level logdefault)223 getLogLevel(const char *module, log_level logdefault)
224 {
225 log_level loglevel = logdefault;
226 char *envlevel = getenv("TSS2_LOG");
227 char *i = envlevel;
228 if (envlevel == NULL)
229 return loglevel;
230 while ((i = strchr(i, '+')) != NULL) {
231 if ((envlevel <= i - strlen("all") &&
232 case_insensitive_strncmp(i - 3, "all", 3) == 0) ||
233 (envlevel <= i - strlen(module) &&
234 case_insensitive_strncmp(i - strlen(module), module, strlen(module)) == 0)) {
235 log_level tmp = log_stringlevel(i+1);
236 if (tmp != LOGLEVEL_UNDEFINED)
237 loglevel = tmp;
238 }
239 i = i + 1;
240 }
241 return loglevel;
242 }
243
244 } // extern "C"
245