• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-mcu / 1642556678

27 Jan 2025 01:30PM UTC coverage: 25.749%. First build
1642556678

push

gitlab-ci

vpodzime
feat: Support platform-specific or custom allocators

And use Zephyr-specific allocation functions on Zephyr by
default, using either a separate heap (default) or the system
heap.

This means we have to use our memory management functions instead
of the standard ones everywhere, even if they can actually just
call the standard ones.

Ticket: MEN-7808
Changelog: none
Signed-off-by: Vratislav Podzimek <vratislav.podzimek@northern.tech>

64 of 184 new or added lines in 12 files covered. (34.78%)

731 of 2839 relevant lines covered (25.75%)

8.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.32
/core/src/mender-utils.c
1
/**
2
 * @file      mender-utils.c
3
 * @brief     Mender utility functions
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 * Copyright Northern.tech AS
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
#include "mender-log.h"
22

23
/* ASCII unit separator */
24
#define MENDER_KEY_VALUE_DELIMITER "\x1F"
25
/* ASCII record separator */
26
#define MENDER_KEY_VALUE_SEPARATOR "\x1E"
27

28
const char *
29
mender_utils_http_status_to_string(int status) {
×
30

31
    /* Definition of status strings */
32
    static const struct {
33
        uint16_t    status;
34
        const char *str;
35
    } desc[] = { { 100, "Continue" },
36
                 { 101, "Switching Protocols" },
37
                 { 103, "Early Hints" },
38
                 { 200, "OK" },
39
                 { 201, "Created" },
40
                 { 202, "Accepted" },
41
                 { 203, "Non-Authoritative Information" },
42
                 { 204, "No Content" },
43
                 { 205, "Reset Content" },
44
                 { 206, "Partial Content" },
45
                 { 300, "Multiple Choices" },
46
                 { 301, "Moved Permanently" },
47
                 { 302, "Found" },
48
                 { 303, "See Other" },
49
                 { 304, "Not Modified" },
50
                 { 307, "Temporary Redirect" },
51
                 { 308, "Permanent Redirect" },
52
                 { 400, "Bad Request" },
53
                 { 401, "Unauthorized" },
54
                 { 402, "Payment Required" },
55
                 { 403, "Forbidden" },
56
                 { 404, "Not Found" },
57
                 { 405, "Method Not Allowed" },
58
                 { 406, "Not Acceptable" },
59
                 { 407, "Proxy Authentication Required" },
60
                 { 408, "Request Timeout" },
61
                 { 409, "Conflict" },
62
                 { 410, "Gone" },
63
                 { 411, "Length Required" },
64
                 { 412, "Precondition Failed" },
65
                 { 413, "Payload Too Large" },
66
                 { 414, "URI Too Long" },
67
                 { 415, "Unsupported Media Type" },
68
                 { 416, "Range Not Satisfiable" },
69
                 { 417, "Expectation Failed" },
70
                 { 418, "I'm a teapot" },
71
                 { 422, "Unprocessable Entity" },
72
                 { 425, "Too Early" },
73
                 { 426, "Upgrade Required" },
74
                 { 428, "Precondition Required" },
75
                 { 429, "Too Many Requests" },
76
                 { 431, "Request Header Fields Too Large" },
77
                 { 451, "Unavailable For Legal Reasons" },
78
                 { 500, "Internal Server Error" },
79
                 { 501, "Not Implemented" },
80
                 { 502, "Bad Gateway" },
81
                 { 503, "Service Unavailable" },
82
                 { 504, "Gateway Timeout" },
83
                 { 505, "HTTP Version Not Supported" },
84
                 { 506, "Variant Also Negotiates" },
85
                 { 507, "Insufficient Storage" },
86
                 { 508, "Loop Detected" },
87
                 { 510, "Not Extended" },
88
                 { 511, "Network Authentication Required" } };
89

90
    /* Return HTTP status as string */
91
    for (size_t index = 0; index < sizeof(desc) / sizeof(desc[0]); index++) {
×
92
        if (desc[index].status == status) {
×
93
            return desc[index].str;
×
94
        }
95
    }
96

97
    return NULL;
×
98
}
99

100
char *
101
mender_utils_strrstr(const char *haystack, const char *needle) {
81✔
102

103
    assert(NULL != haystack);
81✔
104
    assert(NULL != needle);
81✔
105

106
    char *r = NULL;
81✔
107

108
    if (!needle[0]) {
81✔
109
        return (char *)haystack + strlen(haystack);
1✔
110
    }
111

112
    while (1) {
54✔
113
        char *p = strstr(haystack, needle);
134✔
114
        if (!p) {
134✔
115
            return r;
80✔
116
        }
117
        r        = p;
54✔
118
        haystack = p + 1;
54✔
119
    }
120
}
121

122
char *
123
mender_utils_strdup(const char *str) {
144✔
124
    char *dup = mender_malloc(strlen(str) + 1);
144✔
125
    if (NULL == dup) {
144✔
NEW
126
        return dup;
×
127
    }
128
    return strcpy(dup, str);
144✔
129
}
130

131
char *
NEW
132
mender_utils_strndup(const char *str, size_t n) {
×
NEW
133
    char *dup = mender_malloc(n + 1);
×
NEW
134
    if (NULL == dup) {
×
NEW
135
        return dup;
×
136
    }
NEW
137
    return strncpy(dup, str, n);
×
138
}
139

140
int
NEW
141
mender_utils_asprintf(char **result, const char *fmt, ...) {
×
NEW
142
    assert(NULL != result);
×
143

144
    va_list ap;
145
    int     ret;
146

NEW
147
    va_start(ap, fmt);
×
NEW
148
    ret = mender_utils_vasprintf(result, fmt, ap);
×
NEW
149
    va_end(ap);
×
150

NEW
151
    return ret;
×
152
}
153

154
int
NEW
155
mender_utils_vasprintf(char **result, const char *fmt, va_list ap) {
×
NEW
156
    assert(NULL != result);
×
157

158
    int     len;
159
    va_list ap_copy;
160

161
    /* We need to create a copy to not mess the original ap for the second
162
       use (because we cannot use va_start() in this function). */
NEW
163
    va_copy(ap_copy, ap);
×
164

165
    /* First, run vsnprintf() in a way that it tells us how much space it needs,
166
       then allocate the appropriate buffer and then run vsnprintf() again to
167
       actually format the string into the buffer. */
NEW
168
    len = vsnprintf(NULL, 0, fmt, ap_copy);
×
NEW
169
    va_end(ap_copy);
×
NEW
170
    if (len <= 0) {
×
NEW
171
        return len;
×
172
    }
NEW
173
    *result = mender_malloc((size_t)len + 1);
×
NEW
174
    if (NULL == *result) {
×
NEW
175
        return -1;
×
176
    }
NEW
177
    va_copy(ap_copy, ap);
×
NEW
178
    len = vsnprintf(*result, len + 1, fmt, ap_copy);
×
NEW
179
    va_end(ap_copy);
×
180

NEW
181
    return len;
×
182
}
183

184
bool
185
mender_utils_strbeginswith(const char *s1, const char *s2) {
178✔
186

187
    /* Check parameters */
188
    if ((NULL == s1) || (NULL == s2)) {
178✔
189
        return false;
11✔
190
    }
191

192
    /* Compare the beginning of the string */
193
    return (0 == strncmp(s1, s2, strlen(s2)));
167✔
194
}
195

196
bool
197
mender_utils_strendswith(const char *s1, const char *s2) {
68✔
198

199
    /* Check parameters */
200
    if ((NULL == s1) || (NULL == s2)) {
68✔
201
        return false;
11✔
202
    }
203

204
    const size_t len1 = strlen(s1);
57✔
205
    const size_t len2 = strlen(s2);
57✔
206

207
    if (len1 < len2) {
57✔
208
        return false;
1✔
209
    }
210

211
    /* Compare the end of the string */
212
    return (0 == strncmp(s1 + len1 - len2, s2, len2));
56✔
213
}
214

215
char *
216
mender_utils_deployment_status_to_string(mender_deployment_status_t deployment_status) {
6✔
217

218
    /* Return deployment status as string */
219
    if (MENDER_DEPLOYMENT_STATUS_DOWNLOADING == deployment_status) {
6✔
220
        return "downloading";
1✔
221
    } else if (MENDER_DEPLOYMENT_STATUS_INSTALLING == deployment_status) {
5✔
222
        return "installing";
1✔
223
    } else if (MENDER_DEPLOYMENT_STATUS_REBOOTING == deployment_status) {
4✔
224
        return "rebooting";
1✔
225
    } else if (MENDER_DEPLOYMENT_STATUS_SUCCESS == deployment_status) {
3✔
226
        return "success";
1✔
227
    } else if (MENDER_DEPLOYMENT_STATUS_FAILURE == deployment_status) {
2✔
228
        return "failure";
1✔
229
    } else if (MENDER_DEPLOYMENT_STATUS_ALREADY_INSTALLED == deployment_status) {
1✔
230
        return "already-installed";
1✔
231
    }
232

233
    return NULL;
×
234
}
235

236
static inline unsigned char
237
hexdigit_value(char digit) {
1,466✔
238
    if (digit < 'a') {
1,466✔
239
        return digit - '0';
947✔
240
    } else {
241
        return digit - 'a' + 10;
519✔
242
    }
243
}
244

245
bool
246
mender_utils_hexdump_to_bytes(const char *hexdump, unsigned char *bytes, size_t n_bytes) {
25✔
247
    if (NULL == hexdump) {
25✔
248
        mender_log_error("Hexdump is NULL");
1✔
249
        return false;
1✔
250
    }
251

252
    for (size_t i = 0; i < n_bytes; i++) {
757✔
253
        size_t idx = 2 * i;
734✔
254
        if (!(((hexdump[idx] >= '0') && (hexdump[idx] <= '9')) || ((hexdump[idx] >= 'a') && (hexdump[idx] <= 'f')))
734✔
255
            || !(((hexdump[idx + 1] >= '0') && (hexdump[idx + 1] <= '9')) || ((hexdump[idx + 1] >= 'a') && (hexdump[idx + 1] <= 'f')))) {
733✔
256
            mender_log_error("Invalid hex byte: %c%c", hexdump[idx], hexdump[idx + 1]);
1✔
257
            return false;
1✔
258
        }
259
        bytes[i] = (hexdigit_value(hexdump[idx]) << 4) + hexdigit_value(hexdump[idx + 1]);
733✔
260
    }
261
    return true;
23✔
262
}
263

264
mender_keystore_t *
265
mender_utils_keystore_new(size_t length) {
2✔
266

267
    /* Allocate memory */
268
    mender_keystore_t *keystore = (mender_keystore_t *)mender_malloc((length + 1) * sizeof(mender_item_t));
2✔
269
    if (NULL == keystore) {
2✔
270
        mender_log_error("Unable to allocate memory");
×
271
        return NULL;
×
272
    }
273

274
    /* Initialize keystore */
275
    memset(keystore, 0, (length + 1) * sizeof(mender_item_t));
2✔
276

277
    return keystore;
2✔
278
}
279

280
mender_err_t
281
mender_utils_keystore_copy(mender_keystore_t **dst_keystore, mender_keystore_t *src_keystore) {
×
282

283
    assert(NULL != dst_keystore);
×
284
    mender_err_t ret = MENDER_OK;
×
285

286
    /* Copy the new keystore */
287
    size_t length = mender_utils_keystore_length(src_keystore);
×
288
    if (NULL == (*dst_keystore = mender_utils_keystore_new(length))) {
×
289
        mender_log_error("Unable to allocate memory");
×
290
        ret = MENDER_FAIL;
×
291
        goto END;
×
292
    }
293
    for (size_t index = 0; index < length; index++) {
×
294
        if (MENDER_OK != (ret = mender_utils_keystore_set_item(*dst_keystore, index, src_keystore[index].name, src_keystore[index].value))) {
×
295
            mender_log_error("Unable to allocate memory");
×
296
            goto END;
×
297
        }
298
    }
299

300
END:
×
301

302
    return ret;
×
303
}
304

305
mender_err_t
306
mender_utils_keystore_from_json(mender_keystore_t **keystore, cJSON *object) {
1✔
307

308
    assert(NULL != keystore);
1✔
309
    mender_err_t ret;
310

311
    /* Release previous keystore */
312
    if (MENDER_OK != (ret = mender_utils_keystore_delete(*keystore))) {
1✔
313
        mender_log_error("Unable to delete keystore");
×
314
        return ret;
×
315
    }
316
    *keystore = NULL;
1✔
317

318
    /* Set key-store */
319
    if (NULL != object) {
1✔
320
        size_t length       = 0;
1✔
321
        cJSON *current_item = object->child;
1✔
322
        while (NULL != current_item) {
3✔
323
            if ((NULL != current_item->string) && (NULL != current_item->valuestring)) {
2✔
324
                length++;
2✔
325
            }
326
            current_item = current_item->next;
2✔
327
        }
328
        if (NULL != (*keystore = mender_utils_keystore_new(length))) {
1✔
329
            size_t index = 0;
1✔
330
            current_item = object->child;
1✔
331
            while (NULL != current_item) {
3✔
332
                if ((NULL != current_item->string) && (NULL != current_item->valuestring)) {
2✔
333
                    if (MENDER_OK != (ret = mender_utils_keystore_set_item(*keystore, index, current_item->string, current_item->valuestring))) {
2✔
334
                        mender_log_error("Unable to allocate memory");
×
335
                        return ret;
×
336
                    }
337
                    index++;
2✔
338
                }
339
                current_item = current_item->next;
2✔
340
            }
341
        } else {
342
            mender_log_error("Unable to allocate memory");
×
343
            ret = MENDER_FAIL;
×
344
        }
345
    }
346

347
    return ret;
1✔
348
}
349

350
mender_err_t
351
mender_utils_keystore_to_json(mender_keystore_t *keystore, cJSON **object) {
1✔
352

353
    assert(NULL != object);
1✔
354

355
    /* Format data */
356
    *object = cJSON_CreateObject();
1✔
357
    if (NULL == *object) {
1✔
358
        mender_log_error("Unable to allocate memory");
×
359
        return MENDER_FAIL;
×
360
    }
361
    if (NULL != keystore) {
1✔
362
        size_t index = 0;
1✔
363
        while ((NULL != keystore[index].name) && (NULL != keystore[index].value)) {
3✔
364
            cJSON_AddStringToObject(*object, keystore[index].name, keystore[index].value);
2✔
365
            index++;
2✔
366
        }
367
    }
368

369
    return MENDER_OK;
1✔
370
}
371

372
mender_err_t
373
mender_utils_keystore_set_item(mender_keystore_t *keystore, size_t index, char *name, char *value) {
4✔
374

375
    assert(NULL != keystore);
4✔
376

377
    /* Release memory */
378
    FREE_AND_NULL(keystore[index].name);
4✔
379
    FREE_AND_NULL(keystore[index].value);
4✔
380

381
    /* Copy name and value */
382
    if (NULL != name) {
4✔
383
        if (NULL == (keystore[index].name = mender_utils_strdup(name))) {
4✔
384
            mender_log_error("Unable to allocate memory");
×
385
            return MENDER_FAIL;
×
386
        }
387
    }
388
    if (NULL != value) {
4✔
389
        if (NULL == (keystore[index].value = mender_utils_strdup(value))) {
4✔
390
            mender_log_error("Unable to allocate memory");
×
391
            return MENDER_FAIL;
×
392
        }
393
    }
394

395
    return MENDER_OK;
4✔
396
}
397

398
size_t
399
mender_utils_keystore_length(mender_keystore_t *keystore) {
1✔
400

401
    /* Compute key-store length */
402
    size_t length = 0;
1✔
403
    if (NULL != keystore) {
1✔
404
        while ((NULL != keystore[length].name) && (NULL != keystore[length].value)) {
3✔
405
            length++;
2✔
406
        }
407
    }
408

409
    return length;
1✔
410
}
411

412
mender_err_t
413
mender_utils_keystore_delete(mender_keystore_t *keystore) {
3✔
414

415
    /* Release memory */
416
    if (NULL != keystore) {
3✔
417
        size_t index = 0;
2✔
418
        while ((NULL != keystore[index].name) || (NULL != keystore[index].value)) {
6✔
419
            if (NULL != keystore[index].name) {
4✔
420
                mender_free(keystore[index].name);
4✔
421
            }
422
            if (NULL != keystore[index].value) {
4✔
423
                mender_free(keystore[index].value);
4✔
424
            }
425
            index++;
4✔
426
        }
427
        mender_free(keystore);
2✔
428
    }
429

430
    return MENDER_OK;
3✔
431
}
432

433
mender_err_t
434
mender_utils_identity_to_json(const mender_identity_t *identity, cJSON **object) {
×
435

436
    assert(NULL != object);
×
437

438
    /* Format data */
439
    *object = cJSON_CreateObject();
×
440
    if (NULL == *object) {
×
441
        mender_log_error("Unable to allocate memory");
×
442
        return MENDER_FAIL;
×
443
    }
444
    if (NULL == cJSON_AddStringToObject(*object, identity->name, identity->value)) {
×
445
        mender_log_error("Unable to add identity to JSON object");
×
446
        return MENDER_FAIL;
×
447
    }
448
    return MENDER_OK;
×
449
}
450

451
mender_err_t
452
mender_utils_key_value_list_free(mender_key_value_list_t *list) {
43✔
453
    mender_key_value_list_t *item = list;
43✔
454
    while (NULL != item) {
73✔
455
        mender_key_value_list_t *next = item->next;
30✔
456
        mender_free(item->key);
30✔
457
        mender_free(item->value);
30✔
458
        mender_free(item);
30✔
459
        item = next;
30✔
460
    }
461
    return MENDER_OK;
43✔
462
}
463
mender_err_t
464
mender_utils_key_value_list_create_node(const char *type, const char *value, mender_key_value_list_t **list) {
31✔
465

466
    assert(NULL != type);
31✔
467
    assert(NULL != value);
31✔
468
    assert(NULL != list);
31✔
469

470
    mender_key_value_list_t *item = (mender_key_value_list_t *)mender_calloc(1, sizeof(mender_key_value_list_t));
31✔
471
    if (NULL == item) {
31✔
472
        mender_log_error("Unable to allocate memory for linked list node");
×
473
        return MENDER_FAIL;
×
474
    }
475

476
    item->key = mender_utils_strdup(type);
31✔
477
    if (NULL == item->key) {
31✔
478
        mender_log_error("Unable to allocate memory for type");
×
479
        goto ERROR;
×
480
    }
481

482
    item->value = mender_utils_strdup(value);
31✔
483
    if (NULL == item->value) {
31✔
484
        mender_log_error("Unable to allocate memory for value");
×
485
        goto ERROR;
×
486
    }
487

488
    item->next = *list;
31✔
489
    *list      = item;
31✔
490

491
    return MENDER_OK;
31✔
492

493
ERROR:
×
494
    mender_utils_key_value_list_free(item);
×
495
    return MENDER_FAIL;
×
496
}
497

498
mender_err_t
499
mender_utils_key_value_list_to_string(mender_key_value_list_t *list, char **key_value_str) {
1✔
500

501
    /*
502
     * Converts key-value linked list to string of format :
503
     *      "key<\x1F>value<\x1E>...key<\x1Fvalue<\x1E>"
504
     *  Where \x1F is the ASCII unit separator and \x1E is the ASCII record separator
505
     * */
506

507
    /* Start with 1 for the null terminator */
508
    size_t total_len = 1;
1✔
509
    for (mender_key_value_list_t *item = list; NULL != item; item = item->next) {
4✔
510
        if (NULL != item->key && NULL != item->value) {
3✔
511
            total_len += strlen(item->key) + strlen(item->value) + 3; // key=value<space>
3✔
512
        }
513
    }
514

515
    *key_value_str = (char *)mender_calloc(1, total_len);
1✔
516
    if (NULL == *key_value_str) {
1✔
517
        mender_log_error("Unable to allocate memory for string");
×
518
        return MENDER_FAIL;
×
519
    }
520

521
    /* Pointer to key_value_str pointer */
522
    char *str_ptr = *key_value_str;
1✔
523
    for (mender_key_value_list_t *item = list; NULL != item; item = item->next) {
4✔
524
        if (NULL != item->key && NULL != item->value) {
3✔
525
            int ret = snprintf(
3✔
526
                str_ptr, total_len - (str_ptr - *key_value_str), "%s" MENDER_KEY_VALUE_DELIMITER "%s" MENDER_KEY_VALUE_SEPARATOR, item->key, item->value);
3✔
527
            if (0 > ret) {
3✔
528
                mender_log_error("Unable to write to string");
×
529
                return MENDER_FAIL;
×
530
            }
531
            str_ptr += ret;
3✔
532
        }
533
    }
534

535
    return MENDER_OK;
1✔
536
}
537

538
mender_err_t
539
mender_utils_string_to_key_value_list(const char *key_value_str, mender_key_value_list_t **list) {
1✔
540

541
    /*
542
     * Converts of format:
543
     *      "key<\x1F>value<\x1E>...key<\x1Fvalue<\x1E>"
544
     *  to key-value linked list
545
     *  Where \x1F is the ASCII unit separator and \x1E is the ASCII record separator
546
     * */
547

548
    assert(NULL != key_value_str);
1✔
549
    assert(NULL != list);
1✔
550

551
    char *str = mender_utils_strdup(key_value_str);
1✔
552
    if (NULL == str) {
1✔
553
        mender_log_error("Unable to allocate memory for string");
×
554
        return MENDER_FAIL;
×
555
    }
556
    char *saveptr;
557
    char *token = strtok_r(str, MENDER_KEY_VALUE_SEPARATOR, &saveptr);
1✔
558

559
    mender_err_t ret = MENDER_FAIL;
1✔
560

561
    char *delimiter_pos = NULL;
1✔
562
    while (NULL != token) {
4✔
563
        delimiter_pos = strchr(token, MENDER_KEY_VALUE_DELIMITER[0]);
3✔
564
        if (NULL == delimiter_pos) {
3✔
565
            mender_log_error("Invalid key-value string");
×
566
            goto END;
×
567
        }
568
        /* Add null terminator to split key and value to get the key from the token */
569
        token[delimiter_pos - token] = '\0';
3✔
570
        if (MENDER_OK != mender_utils_key_value_list_create_node(token, delimiter_pos + 1, list)) {
3✔
571
            mender_log_error("Unable to create key-value node");
×
572
            goto END;
×
573
        }
574
        token = strtok_r(NULL, MENDER_KEY_VALUE_SEPARATOR, &saveptr);
3✔
575
    }
576

577
    ret = MENDER_OK;
1✔
578
END:
1✔
579
    mender_free(str);
1✔
580
    return ret;
1✔
581
}
582

583
mender_err_t
584
mender_utils_key_value_list_append(mender_key_value_list_t **list1, mender_key_value_list_t **list2) {
1✔
585

586
    /* Combine two linked lists by pointing the last element of the first list
587
     * to the first element of the second list
588
     * Sets list2 to NULL
589
     * */
590

591
    mender_key_value_list_t *item = *list1;
1✔
592
    if (NULL != item) {
1✔
593
        while (NULL != item->next) {
2✔
594
            item = item->next;
1✔
595
        }
596
        item->next = *list2;
1✔
597
    } else {
598
        *list1 = *list2;
×
599
    }
600
    *list2 = NULL;
1✔
601
    return MENDER_OK;
1✔
602
}
603

604
mender_err_t
605
mender_utils_key_value_list_append_unique(mender_key_value_list_t **list1, mender_key_value_list_t **list2) {
1✔
606

607
    /* Get the last item of list1 */
608
    mender_key_value_list_t *last_item1 = *list1;
1✔
609
    if (NULL != last_item1) {
1✔
610
        while (NULL != last_item1->next) {
2✔
611
            last_item1 = last_item1->next;
1✔
612
        }
613
    }
614

615
    mender_key_value_list_t *prev_item2 = NULL;
1✔
616
    mender_key_value_list_t *item2      = *list2;
1✔
617

618
    while (NULL != item2) {
2✔
619
        bool unique = true;
1✔
620
        /* Check if the item2 key is unique in list1 */
621
        for (mender_key_value_list_t *item1 = *list1; item1 != NULL; item1 = item1->next) {
1✔
622
            if (StringEqual(item1->key, item2->key)) {
1✔
623
                unique = false;
1✔
624
                break;
1✔
625
            }
626
        }
627

628
        /* If unique, append item2 to list1 */
629
        if (unique) {
1✔
630
            /* Detach item2 from list2 */
631
            if (NULL != prev_item2) {
×
632
                prev_item2->next = item2->next;
×
633
            } else {
634
                *list2 = item2->next;
×
635
            }
636

637
            /* Append item2 to list1 */
638
            if (NULL != last_item1) {
×
639
                last_item1->next = item2;
×
640
            } else {
641
                *list1 = item2;
×
642
            }
643

644
            /* Update the last_item1 to the newly added node */
645
            last_item1 = item2;
×
646
            /* Move to the next item in list2 */
647
            item2 = item2->next;
×
648
            /* Ensure the last node of list1 has next set to NULL */
649
            last_item1->next = NULL;
×
650
        } else {
651
            /* Move to the next item in list2 */
652
            prev_item2 = item2;
1✔
653
            item2      = item2->next;
1✔
654
        }
655
    }
656

657
    return MENDER_OK;
1✔
658
}
659

660
mender_err_t
661
mender_utils_key_value_list_delete_node(mender_key_value_list_t **list, const char *key) {
1✔
662

663
    mender_key_value_list_t *to_free = NULL;
1✔
664
    mender_key_value_list_t *prev    = NULL;
1✔
665
    mender_key_value_list_t *item    = *list;
1✔
666
    while (NULL != item) {
1✔
667
        if (StringEqual(item->key, key)) {
1✔
668
            to_free = item;
1✔
669
            if (NULL == prev) {
1✔
670
                *list = item->next;
1✔
671
                break;
1✔
672
            } else {
673
                prev->next = item->next;
×
674
            }
675
            break;
×
676
        }
677
        prev = item;
×
678
        item = item->next;
×
679
    }
680

681
    if (NULL != to_free) {
1✔
682
        mender_free(to_free->key);
1✔
683
        mender_free(to_free->value);
1✔
684
        mender_free(to_free);
1✔
685
    }
686
    return MENDER_OK;
1✔
687
}
688

689
mender_err_t
690
mender_utils_compare_wildcard(const char *str, const char *wildcard_str, bool *match) {
28✔
691

692
    assert(NULL != str);
28✔
693
    assert(NULL != wildcard_str);
28✔
694
    assert(NULL != match);
28✔
695

696
    const char *to_match = str;
28✔
697
    const char *boundary = wildcard_str;
28✔
698

699
    char *ptr = strchr(boundary, '*');
28✔
700

701
    /* Check if the wildcard contains wildcard, else compare strings */
702
    if (NULL == ptr) {
28✔
703
        *match = (StringEqual(str, wildcard_str));
7✔
704
        return MENDER_OK;
7✔
705
    }
706

707
    *match = true;
21✔
708

709
    /* Check if the wildcard string starts with wildcard */
710
    if (to_match[0] != '*') {
21✔
711
        if (0 != strncmp(wildcard_str, str, ptr - boundary)) {
21✔
712
            *match = false;
2✔
713
            return MENDER_OK;
2✔
714
        }
715
    }
716

717
    /*
718
     * Iterate over substrings separated by wildcard *
719
     * Attempt to find the substring in the string
720
     */
721
    while (NULL != (ptr = strchr(boundary, '*'))) {
54✔
722
        const size_t len          = (size_t)(ptr - boundary);
37✔
723
        const size_t to_match_len = strlen(to_match);
37✔
724
        const char  *find         = NULL;
37✔
725

726
        for (size_t i = 0; i <= to_match_len - len; i++) {
74✔
727
            if (0 == memcmp(to_match + i, boundary, len)) {
72✔
728
                find = to_match + i;
35✔
729
                break;
35✔
730
            }
731
        }
732

733
        if (NULL == find) {
37✔
734
            *match = false;
2✔
735
            break;
2✔
736
        }
737
        to_match = find + len;
35✔
738
        boundary = ptr + 1;
35✔
739
    }
740

741
    if (NULL == strstr(to_match, boundary)) {
19✔
742
        *match = false;
5✔
743
    }
744

745
    return MENDER_OK;
19✔
746
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc