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

mendersoftware / mender-mcu / 1642941481

27 Jan 2025 04:43PM UTC coverage: 25.951% (+0.3%) from 25.63%
1642941481

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>

70 of 185 new or added lines in 12 files covered. (37.84%)

2 existing lines in 2 files now uncovered.

737 of 2840 relevant lines covered (25.95%)

8.85 hits per line

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

71.84
/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) {
145✔
124
    assert(NULL != str);
145✔
125

126
    size_t str_len = strlen(str);
145✔
127
    return mender_utils_strndup(str, str_len);
145✔
128
}
129

130
char *
131
mender_utils_strndup(const char *str, size_t n) {
147✔
132
    assert(NULL != str);
147✔
133

134
    char *dup = mender_malloc(n + 1);
147✔
135
    if (NULL == dup) {
147✔
NEW
136
        return dup;
×
137
    }
138
    dup[n] = '\0';
147✔
139
    return memcpy(dup, str, n);
147✔
140
}
141

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

146
    va_list ap;
147
    int     ret;
148

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

NEW
153
    return ret;
×
154
}
155

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

160
    int     len;
161
    va_list ap_copy;
162

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

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

NEW
183
    return len;
×
184
}
185

186
bool
187
mender_utils_strbeginswith(const char *s1, const char *s2) {
178✔
188

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

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

198
bool
199
mender_utils_strendswith(const char *s1, const char *s2) {
68✔
200

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

206
    const size_t len1 = strlen(s1);
57✔
207
    const size_t len2 = strlen(s2);
57✔
208

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

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

217
char *
218
mender_utils_deployment_status_to_string(mender_deployment_status_t deployment_status) {
6✔
219

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

235
    return NULL;
×
236
}
237

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

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

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

266
mender_keystore_t *
267
mender_utils_keystore_new(size_t length) {
2✔
268

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

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

279
    return keystore;
2✔
280
}
281

282
mender_err_t
283
mender_utils_keystore_copy(mender_keystore_t **dst_keystore, mender_keystore_t *src_keystore) {
×
284

285
    assert(NULL != dst_keystore);
×
286
    mender_err_t ret = MENDER_OK;
×
287

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

302
END:
×
303

304
    return ret;
×
305
}
306

307
mender_err_t
308
mender_utils_keystore_from_json(mender_keystore_t **keystore, cJSON *object) {
1✔
309

310
    assert(NULL != keystore);
1✔
311
    mender_err_t ret;
312

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

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

349
    return ret;
1✔
350
}
351

352
mender_err_t
353
mender_utils_keystore_to_json(mender_keystore_t *keystore, cJSON **object) {
1✔
354

355
    assert(NULL != object);
1✔
356

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

371
    return MENDER_OK;
1✔
372
}
373

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

377
    assert(NULL != keystore);
4✔
378

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

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

397
    return MENDER_OK;
4✔
398
}
399

400
size_t
401
mender_utils_keystore_length(mender_keystore_t *keystore) {
1✔
402

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

411
    return length;
1✔
412
}
413

414
mender_err_t
415
mender_utils_keystore_delete(mender_keystore_t *keystore) {
3✔
416

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

432
    return MENDER_OK;
3✔
433
}
434

435
mender_err_t
436
mender_utils_identity_to_json(const mender_identity_t *identity, cJSON **object) {
×
437

438
    assert(NULL != object);
×
439

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

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

468
    assert(NULL != type);
31✔
469
    assert(NULL != value);
31✔
470
    assert(NULL != list);
31✔
471

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

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

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

490
    item->next = *list;
31✔
491
    *list      = item;
31✔
492

493
    return MENDER_OK;
31✔
494

495
ERROR:
×
496
    mender_utils_key_value_list_free(item);
×
497
    return MENDER_FAIL;
×
498
}
499

500
mender_err_t
501
mender_utils_key_value_list_to_string(mender_key_value_list_t *list, char **key_value_str) {
1✔
502

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

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

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

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

537
    return MENDER_OK;
1✔
538
}
539

540
mender_err_t
541
mender_utils_string_to_key_value_list(const char *key_value_str, mender_key_value_list_t **list) {
1✔
542

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

550
    assert(NULL != key_value_str);
1✔
551
    assert(NULL != list);
1✔
552

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

561
    mender_err_t ret = MENDER_FAIL;
1✔
562

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

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

585
mender_err_t
586
mender_utils_key_value_list_append(mender_key_value_list_t **list1, mender_key_value_list_t **list2) {
1✔
587

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

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

606
mender_err_t
607
mender_utils_key_value_list_append_unique(mender_key_value_list_t **list1, mender_key_value_list_t **list2) {
1✔
608

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

617
    mender_key_value_list_t *prev_item2 = NULL;
1✔
618
    mender_key_value_list_t *item2      = *list2;
1✔
619

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

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

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

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

659
    return MENDER_OK;
1✔
660
}
661

662
mender_err_t
663
mender_utils_key_value_list_delete_node(mender_key_value_list_t **list, const char *key) {
1✔
664

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

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

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

694
    assert(NULL != str);
28✔
695
    assert(NULL != wildcard_str);
28✔
696
    assert(NULL != match);
28✔
697

698
    const char *to_match = str;
28✔
699
    const char *boundary = wildcard_str;
28✔
700

701
    char *ptr = strchr(boundary, '*');
28✔
702

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

709
    *match = true;
21✔
710

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

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

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

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

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

747
    return MENDER_OK;
19✔
748
}
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