Line data Source code
1 : /*
2 : * SPDX license identifier: MPL-2.0
3 : *
4 : * Copyright (C) 2015 Intel Corporation
5 : *
6 : * This file is part of COVESA Project DLT - Diagnostic Log and Trace.
7 : *
8 : * This Source Code Form is subject to the terms of the
9 : * Mozilla Public License (MPL), v. 2.0.
10 : * If a copy of the MPL was not distributed with this file,
11 : * You can obtain one at http://mozilla.org/MPL/2.0/.
12 : *
13 : * For further information see http://www.covesa.org/.
14 : */
15 :
16 : /*!
17 : * \author Stefan Vacek <stefan.vacek@intel.com> Intel Corporation
18 : *
19 : * \copyright Copyright © 2015 Intel Corporation. \n
20 : * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
21 : *
22 : * \file dlt_env_ll.c
23 : */
24 :
25 : #include "dlt_user.h"
26 : #include <string.h>
27 : #include <stdlib.h>
28 :
29 : #define DLT_ENV_LL_SET_INCREASE 10
30 :
31 :
32 : /* a generic entry looks like:
33 : * ll_item ::= apid:ctid:ll
34 : * ll_set ::= ll_item |
35 : * ll_set;ll_item
36 : */
37 :
38 : /**
39 : * @brief extract id out of given string
40 : *
41 : * Extract 4-byte string out of given environment string, the pointer of the
42 : * environment string is moved to the next un-used character and the extracted
43 : * id is copied into \param id
44 : *
45 : * Example:
46 : * env[] = "abcd:1234:3"
47 : * char res[4u];
48 : * char * tmp = &env[0];
49 : * int ret = extract_id(&tmp, res);
50 : * assert(ret == 0);
51 : * assert(*tmp == ':');
52 : * assert(res[3] == 'd');
53 : *
54 : * @param env Environment variable
55 : * @param id Extracted ID
56 : * @return 0 if successful, -1 else
57 : */
58 0 : int dlt_env_extract_id(char **const env, char *id)
59 : {
60 : int i;
61 :
62 0 : if (!env || !id) {
63 : return -1;
64 : }
65 :
66 0 : if (!(*env)) {
67 : return -1;
68 : }
69 :
70 : memset(id, 0, 4);
71 :
72 0 : for (i = 0; (i < 4) && (**env != ':') && (**env != 0); ++i) {
73 0 : *id++ = *((*env)++);
74 : }
75 :
76 : /* the next/last character must be ':' */
77 0 : if ((0 != **env) && (':' == **env)) {
78 0 : return 0;
79 : }
80 :
81 : return -1;
82 : }
83 :
84 :
85 : /**
86 : * @brief convert a given string to lower-case
87 : *
88 : * Stops end of string or if ';' is detected
89 : */
90 0 : int dlt_env_helper_to_lower(char **const env, char *result, int const res_len)
91 : {
92 : int count = 0;
93 : char ch;
94 :
95 0 : if (!env || !result) {
96 : return -1;
97 : }
98 :
99 0 : if (!(*env)) {
100 : return -1;
101 : }
102 :
103 0 : ch = *(*env);
104 :
105 0 : while (ch && (count < res_len - 1) && (ch != ';')) {
106 0 : if ((ch >= 'A') && (ch <= 'Z')) {
107 0 : result[count] = ch + 'a' - 'A';
108 : } else {
109 0 : result[count] = ch;
110 : }
111 :
112 0 : ch = *(++(*env));
113 0 : ++count;
114 : }
115 :
116 0 : result[count] = 0;
117 :
118 0 : if (!ch || (ch == ';')) { /* full input was parsed */
119 : return 0;
120 : } else {
121 0 : return -1;
122 : }
123 : }
124 :
125 :
126 0 : int dlt_env_extract_symbolic_ll(char **const env, int8_t *ll)
127 0 : {
128 : char result[strlen("verbose") + 1];
129 :
130 0 : if (!env || !ll) {
131 : return -1;
132 : }
133 :
134 0 : if (!(*env)) {
135 : return -1;
136 : }
137 :
138 0 : if (dlt_env_helper_to_lower(env, &result[0], sizeof(result)) == 0) {
139 0 : if (strncmp("default", result, sizeof(result)) == 0) {
140 0 : *ll = -1;
141 0 : } else if (strncmp("off", result, sizeof(result)) == 0) {
142 0 : *ll = 0;
143 0 : } else if (strncmp("fatal", result, sizeof(result)) == 0) {
144 0 : *ll = 1;
145 0 : } else if (strncmp("error", result, sizeof(result)) == 0) {
146 0 : *ll = 2;
147 0 : } else if (strncmp("warning", result, sizeof(result)) == 0) {
148 0 : *ll = 3;
149 0 : } else if (strncmp("info", result, sizeof(result)) == 0) {
150 0 : *ll = 4;
151 0 : } else if (strncmp("debug", result, sizeof(result)) == 0) {
152 0 : *ll = 5;
153 0 : } else if (strncmp("verbose", result, sizeof(result)) == 0) {
154 0 : *ll = 6;
155 : } else {
156 : return -1;
157 : }
158 :
159 0 : if (**env != 0) {
160 0 : (*env)++;
161 : }
162 :
163 0 : return 0;
164 : } else {
165 : return -1;
166 : }
167 : }
168 :
169 :
170 : /**
171 : * @brief extract log-level out of given string
172 : *
173 : * A valid log-level is a numeric value in the range of -1 .. 6, with:
174 : * -1: default
175 : * 0: off
176 : * 1: fatal
177 : * 2: error
178 : * 3: warning
179 : * 4: info
180 : * 5: debug
181 : * 6: verbose
182 : * During parsing, the environment string is moved to the next un-used character and the extracted
183 : * log-level is written into \param ll
184 : *
185 : * Example:
186 : * env[] = "abcd:1234:6"
187 : * int ll;
188 : * char ** tmp = &env[10]; // tmp points to '6'!
189 : * int ret = extract_ll(&tmp, &ll);
190 : * assert(ret == 0);
191 : * assert(*tmp == NULL);
192 : * assert(ll == 6);
193 : *
194 : * @param env Environment variable
195 : * @param ll Extracted log level
196 : * @return 0 if successful, -1 else
197 : */
198 0 : int dlt_env_extract_ll(char **const env, int8_t *ll)
199 : {
200 0 : if (!env || !ll) {
201 : return -1;
202 : }
203 :
204 0 : if (!(*env)) {
205 : return -1;
206 : }
207 :
208 : /* extract number */
209 0 : if (**env == '-') {
210 0 : (*env)++;
211 :
212 0 : if (**env == '1') {
213 0 : *ll = -1;
214 0 : (*env)++;
215 : }
216 : } else {
217 0 : if ((**env >= '0') && (**env < '7')) {
218 0 : *ll = **env - '0';
219 0 : (*env)++;
220 0 : } else if (dlt_env_extract_symbolic_ll(env, ll) != 0) {
221 : return -1;
222 : }
223 : }
224 :
225 : /* check end, either next char is NULL or ';' */
226 0 : if ((**env == ';') || (**env == 0)) {
227 0 : return 0;
228 : }
229 :
230 : return -1;
231 : }
232 :
233 :
234 : /**
235 : * @brief extract one item out of string
236 : *
237 : * @return 0 if successful, -1 else
238 : */
239 0 : int dlt_env_extract_ll_item(char **const env, dlt_env_ll_item *const item)
240 : {
241 : int ret = -1;
242 :
243 0 : if (!env || !item) {
244 : return -1;
245 : }
246 :
247 0 : if (!(*env)) {
248 : return -1;
249 : }
250 :
251 : memset(item, 0, sizeof(dlt_env_ll_item));
252 0 : ret = dlt_env_extract_id(env, item->appId);
253 :
254 0 : if (ret == -1) {
255 : return -1;
256 : }
257 :
258 0 : (*env)++;
259 0 : ret = dlt_env_extract_id(env, item->ctxId);
260 :
261 0 : if (ret == -1) {
262 : return -1;
263 : }
264 :
265 0 : (*env)++;
266 0 : ret = dlt_env_extract_ll(env, &item->ll);
267 :
268 0 : if (ret == -1) {
269 0 : return -1;
270 : }
271 :
272 : return 0;
273 : }
274 :
275 :
276 : /**
277 : * @brief initialize ll_set
278 : *
279 : * Must call release_ll_set before exit to release all memory
280 : *
281 : * @return -1 if memory could not be allocated
282 : * @return 0 on success
283 : */
284 0 : int dlt_env_init_ll_set(dlt_env_ll_set *const ll_set)
285 : {
286 0 : if (!ll_set) {
287 : return -1;
288 : }
289 :
290 0 : ll_set->array_size = DLT_ENV_LL_SET_INCREASE;
291 0 : ll_set->item = (dlt_env_ll_item *)malloc(sizeof(dlt_env_ll_item) * ll_set->array_size);
292 :
293 0 : if (!ll_set->item) {
294 : /* should trigger a warning: no memory left */
295 0 : ll_set->array_size = 0;
296 0 : return -1;
297 : }
298 :
299 0 : ll_set->num_elem = 0u;
300 0 : return 0;
301 : }
302 :
303 :
304 : /**
305 : * @brief release ll_set
306 : */
307 18475 : void dlt_env_free_ll_set(dlt_env_ll_set *const ll_set)
308 : {
309 18475 : if (!ll_set) {
310 : return;
311 : }
312 :
313 18475 : if (ll_set->item != NULL) {
314 0 : free(ll_set->item);
315 0 : ll_set->item = NULL;
316 : }
317 :
318 18475 : ll_set->array_size = 0u;
319 18475 : ll_set->num_elem = 0u;
320 : }
321 :
322 :
323 : /**
324 : * @brief increase size of ll_set by LL_SET_INCREASE elements
325 : *
326 : * @return -1 if memory could not be allocated
327 : * @return 0 on success
328 : */
329 0 : int dlt_env_increase_ll_set(dlt_env_ll_set *const ll_set)
330 : {
331 : dlt_env_ll_item *old_set;
332 : size_t old_size;
333 :
334 0 : if (!ll_set) {
335 : return -1;
336 : }
337 :
338 0 : old_set = ll_set->item;
339 0 : old_size = ll_set->array_size;
340 :
341 0 : ll_set->array_size += DLT_ENV_LL_SET_INCREASE;
342 0 : ll_set->item = (dlt_env_ll_item *)malloc(sizeof(dlt_env_ll_item) * ll_set->array_size);
343 :
344 0 : if (!ll_set->item) {
345 : /* should trigger a warning: no memory left */
346 0 : ll_set->array_size -= DLT_ENV_LL_SET_INCREASE;
347 0 : return -1;
348 : } else {
349 0 : memcpy(ll_set->item, old_set, sizeof(dlt_env_ll_item) * old_size);
350 0 : free(old_set);
351 0 : return 0;
352 : }
353 : }
354 :
355 :
356 : /**
357 : * @brief extract all items out of string
358 : *
359 : * The given set is initialized within this function (memory is allocated).
360 : * Make sure, that the caller frees this memory when it is no longer needed!
361 : *
362 : * @return 0 if successful, -1 else
363 : */
364 0 : int dlt_env_extract_ll_set(char **const env, dlt_env_ll_set *const ll_set)
365 : {
366 0 : if (!env || !ll_set) {
367 : return -1;
368 : }
369 :
370 0 : if (!(*env)) {
371 : return -1;
372 : }
373 :
374 0 : if (dlt_env_init_ll_set(ll_set) == -1) {
375 : return -1;
376 : }
377 :
378 : do {
379 0 : if (ll_set->num_elem == ll_set->array_size) {
380 0 : if (dlt_env_increase_ll_set(ll_set) == -1) {
381 : return -1;
382 : }
383 : }
384 :
385 0 : if (dlt_env_extract_ll_item(env, &ll_set->item[ll_set->num_elem++]) == -1) {
386 : return -1;
387 : }
388 :
389 0 : if (**env == ';') {
390 0 : (*env)++;
391 : }
392 0 : } while (**env != 0);
393 :
394 : return 0;
395 : }
396 :
397 :
398 : /**
399 : * @brief check if two ids match
400 : *
401 : * @return 1 if matching, 0 if not
402 : */
403 0 : int dlt_env_ids_match(char const *const a, char const *const b)
404 : {
405 0 : if (a[0] != b[0]) {
406 : return 0;
407 : }
408 :
409 0 : if (a[1] != b[1]) {
410 : return 0;
411 : }
412 :
413 0 : if (a[2] != b[2]) {
414 : return 0;
415 : }
416 :
417 0 : if (a[3] != b[3]) {
418 0 : return 0;
419 : }
420 :
421 : return 1;
422 : }
423 :
424 :
425 : /**
426 : * @brief check if (and how) apid and ctid match with given item
427 : *
428 : * Resulting priorities:
429 : * - no apid, no ctid only ll given in item: use ll with prio 1
430 : * - no apid, ctid matches: use ll with prio 2
431 : * - no ctid, apid matches: use ll with prio 3
432 : * - apid, ctid matches: use ll with prio 4
433 : *
434 : * In case of error, -1 is returned.
435 : */
436 0 : int dlt_env_ll_item_get_matching_prio(dlt_env_ll_item const *const item,
437 : char const *const apid,
438 : char const *const ctid)
439 : {
440 0 : if ((!item) || (!apid) || (!ctid)) {
441 : return -1;
442 : }
443 :
444 0 : if (item->appId[0] == 0) {
445 0 : if (item->ctxId[0] == 0) {
446 : return 1;
447 0 : } else if (dlt_env_ids_match(item->ctxId, ctid)) {
448 0 : return 2;
449 : }
450 0 : } else if (dlt_env_ids_match(item->appId, apid)) {
451 0 : if (item->ctxId[0] == 0) {
452 : return 3;
453 0 : } else if (dlt_env_ids_match(item->ctxId, ctid)) {
454 0 : return 4;
455 : }
456 : }
457 :
458 : return 0;
459 : }
460 :
461 :
462 : /**
463 : * @brief adjust log-level based on values given through environment
464 : *
465 : * Iterate over the set of items, and find the best match (\see ll_item_get_matching_prio)
466 : * For any item that matches, the one with the highest priority is selected and that
467 : * log-level is returned.
468 : *
469 : * If no item matches or in case of error, the original log-level (\param ll) is returned
470 : */
471 205 : int dlt_env_adjust_ll_from_env(dlt_env_ll_set const *const ll_set,
472 : char const *const apid,
473 : char const *const ctid,
474 : int const ll)
475 : {
476 205 : if ((!ll_set) || (!apid) || (!ctid)) {
477 : return ll;
478 : }
479 :
480 : int res = ll;
481 : int prio = 0; /* no match so far */
482 : size_t i;
483 :
484 205 : for (i = 0; i < ll_set->num_elem; ++i) {
485 0 : int p = dlt_env_ll_item_get_matching_prio(&ll_set->item[i], apid, ctid);
486 :
487 0 : if (p > prio) {
488 : prio = p;
489 0 : res = ll_set->item[i].ll;
490 :
491 0 : if (p == 4) { /* maximum reached, immediate return */
492 0 : return res;
493 : }
494 : }
495 : }
496 :
497 : return res;
498 : }
499 :
500 :
|