Alon Bar-Lev | 38fcb66 | 2019-05-31 18:55:38 +0300 | [diff] [blame] | 1 | #ifdef HAVE_CONFIG_H |
| 2 | #include <config.h> |
| 3 | #endif |
| 4 | |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 5 | #include <string.h> |
| 6 | #include <stdio.h> |
| 7 | #include <stdarg.h> |
| 8 | #include <stdlib.h> |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 9 | #include <ctype.h> |
Philip Tricca | 391e889 | 2017-02-08 13:15:27 -0800 | [diff] [blame] | 10 | |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 11 | #define LOGMODULE log |
Philip Tricca | a7c51ce | 2018-03-10 18:28:25 -0800 | [diff] [blame] | 12 | #include "log.h" |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 13 | |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 14 | #include <android-base/logging.h> |
| 15 | |
dantpm | 293b4fa | 2018-04-11 10:31:46 -0700 | [diff] [blame] | 16 | #if !defined(_MSC_VER) || defined(__INTEL_COMPILER) |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 17 | #define likely(x) __builtin_expect(!!(x), 1) |
| 18 | #define unlikely(x) __builtin_expect(!!(x), 0) |
dantpm | 293b4fa | 2018-04-11 10:31:46 -0700 | [diff] [blame] | 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 |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 24 | |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 25 | extern "C" { |
| 26 | |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 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. |
Tadeusz Struk | ca2fa21 | 2018-09-13 12:37:02 -0700 | [diff] [blame] | 31 | * |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 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 |
Peter Huewe | b0986cb | 2019-02-19 22:26:57 +0100 | [diff] [blame] | 36 | * of the strings and compares them bytewise. |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 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 | */ |
Tadeusz Struk | ca2fa21 | 2018-09-13 12:37:02 -0700 | [diff] [blame] | 47 | static int |
| 48 | case_insensitive_strncmp(const char *string1, |
| 49 | const char *string2, |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 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 | } |
Peter Huewe | b0986cb | 2019-02-19 22:26:57 +0100 | [diff] [blame] | 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 | } |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 67 | |
Peter Huewe | b0986cb | 2019-02-19 22:26:57 +0100 | [diff] [blame] | 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; |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 76 | } |
| 77 | |
Peter Huewe | 04fcab5 | 2019-04-16 15:12:45 +0200 | [diff] [blame] | 78 | static log_level |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 79 | getLogLevel(const char *module, log_level logdefault); |
| 80 | |
| 81 | void |
| 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, ...) |
Philip Tricca | 391e889 | 2017-02-08 13:15:27 -0800 | [diff] [blame] | 86 | { |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 87 | if (unlikely(*status == LOGLEVEL_UNDEFINED)) |
| 88 | *status = getLogLevel(module, logdefault); |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 89 | if (loglevel > *status) |
| 90 | return; |
| 91 | |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 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, |
Tadeusz Struk | ccc62f3 | 2020-02-28 14:24:25 -0800 | [diff] [blame] | 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 | } |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | void |
| 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 | |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 166 | int size = snprintf(NULL, 0, "%s:%s:%s:%d:%s() %s ", |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 167 | log_strings[loglevel], module, file, line, func, msg); |
| 168 | char fmt[size+1]; |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 169 | snprintf(fmt, sizeof(fmt), "%s:%s:%s:%d:%s() %s ", |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 170 | log_strings[loglevel], module, file, line, func, msg); |
| 171 | |
| 172 | va_list vaargs; |
| 173 | va_start(vaargs, msg); |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 174 | int complete_size = vsnprintf(NULL, 0, fmt, vaargs); |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 175 | va_end(vaargs); |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 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 | } |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 208 | } |
| 209 | |
Peter Huewe | 04fcab5 | 2019-04-16 15:12:45 +0200 | [diff] [blame] | 210 | static log_level |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 211 | log_stringlevel(const char *n) |
| 212 | { |
Fabrice Fontaine | 9de349b | 2019-12-14 18:42:26 +0100 | [diff] [blame] | 213 | log_level i; |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 214 | for(i = (log_level) 0; i < sizeof(log_strings)/sizeof(log_strings[0]); i = (log_level) ((int) i + 1)) { |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 215 | if (case_insensitive_strncmp(log_strings[i], n, strlen(log_strings[i])) == 0) { |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 216 | return i; |
Philip Tricca | 391e889 | 2017-02-08 13:15:27 -0800 | [diff] [blame] | 217 | } |
| 218 | } |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 219 | return LOGLEVEL_UNDEFINED; |
Philip Tricca | 391e889 | 2017-02-08 13:15:27 -0800 | [diff] [blame] | 220 | } |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 221 | |
Peter Huewe | 04fcab5 | 2019-04-16 15:12:45 +0200 | [diff] [blame] | 222 | static log_level |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 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; |
Philip Tricca | 5981455 | 2018-01-20 21:22:02 -0800 | [diff] [blame] | 230 | while ((i = strchr(i, '+')) != NULL) { |
Tadeusz Struk | ca2fa21 | 2018-09-13 12:37:02 -0700 | [diff] [blame] | 231 | if ((envlevel <= i - strlen("all") && |
| 232 | case_insensitive_strncmp(i - 3, "all", 3) == 0) || |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 233 | (envlevel <= i - strlen(module) && |
Lukas Jäger | 35fc427 | 2018-08-28 13:53:03 +0200 | [diff] [blame] | 234 | case_insensitive_strncmp(i - strlen(module), module, strlen(module)) == 0)) { |
Andreas Fuchs | bc49076 | 2018-01-03 14:36:38 +0100 | [diff] [blame] | 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 | } |
A. Cody Schuffelen | 1365217 | 2020-03-16 19:32:45 -0700 | [diff] [blame] | 243 | |
| 244 | } // extern "C" |