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

mendersoftware / mender-mcu / 1642966090

27 Jan 2025 05:00PM UTC coverage: 25.951% (+0.3%) from 25.63%
1642966090

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

0.0
/core/src/mender-client.c
1
/**
2
 * @file      mender-client.c
3
 * @brief     Mender MCU client implementation
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-alloc.h"
22
#include "mender-api.h"
23
#include "mender-client.h"
24
#include "mender-artifact.h"
25
#include "mender-artifact-download.h"
26
#include "mender-log.h"
27
#include "mender-scheduler.h"
28
#include "mender-storage.h"
29
#include "mender-tls.h"
30
#include "mender-update-module.h"
31
#include "mender-utils.h"
32
#include "mender-deployment-data.h"
33
#include "mender-error-counters.h"
34

35
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
36
#include "mender-inventory.h"
37
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
38

39
/**
40
 * @brief Default host
41
 */
42
#ifndef CONFIG_MENDER_SERVER_HOST
43
#define CONFIG_MENDER_SERVER_HOST "https://hosted.mender.io"
44
#endif /* CONFIG_MENDER_SERVER_HOST */
45

46
/**
47
 * @brief Default tenant token
48
 */
49
#ifndef CONFIG_MENDER_SERVER_TENANT_TOKEN
50
#define CONFIG_MENDER_SERVER_TENANT_TOKEN NULL
51
#endif /* CONFIG_MENDER_SERVER_TENANT_TOKEN */
52

53
/**
54
 * @brief Default device type
55
 */
56
#ifndef CONFIG_MENDER_DEVICE_TYPE
57
#define CONFIG_MENDER_DEVICE_TYPE NULL
58
#endif /* CONFIG_MENDER_DEVICE_TYPE */
59

60
/**
61
 * @brief Default update poll interval (seconds)
62
 */
63
#ifndef CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL
64
#define CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL (1800)
65
#endif /* CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL */
66

67
/**
68
 * @brief Mender client configuration
69
 */
70
static mender_client_config_t mender_client_config;
71

72
/**
73
 * @brief Mender client callbacks
74
 */
75
mender_client_callbacks_t mender_client_callbacks = { 0 };
76

77
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
78

79
struct mender_update_state_transition_s {
80
    mender_update_state_t success;
81
    mender_update_state_t failure;
82
};
83

84
/**
85
 * @brief Mender Update (module) state transitions
86
 */
87
static const struct mender_update_state_transition_s update_state_transitions[N_MENDER_UPDATE_STATES] = {
88
    /* MENDER_UPDATE_STATE_DOWNLOAD               */ { MENDER_UPDATE_STATE_INSTALL, MENDER_UPDATE_STATE_CLEANUP },
89
    /* MENDER_UPDATE_STATE_INSTALL                */ { MENDER_UPDATE_STATE_REBOOT, MENDER_UPDATE_STATE_FAILURE },
90
    /* MENDER_UPDATE_STATE_REBOOT                 */ { MENDER_UPDATE_STATE_VERIFY_REBOOT, MENDER_UPDATE_STATE_ROLLBACK },
91
    /* MENDER_UPDATE_STATE_VERIFY_REBOOT          */ { MENDER_UPDATE_STATE_COMMIT, MENDER_UPDATE_STATE_ROLLBACK },
92
    /* MENDER_UPDATE_STATE_COMMIT                 */ { MENDER_UPDATE_STATE_CLEANUP, MENDER_UPDATE_STATE_ROLLBACK },
93
    /* MENDER_UPDATE_STATE_CLEANUP                */ { MENDER_UPDATE_STATE_END, MENDER_UPDATE_STATE_END },
94
    /* MENDER_UPDATE_STATE_ROLLBACK               */ { MENDER_UPDATE_STATE_ROLLBACK_REBOOT, MENDER_UPDATE_STATE_FAILURE },
95
    /* MENDER_UPDATE_STATE_ROLLBACK_REBOOT        */ { MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT, MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT },
96
    /* MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT */ { MENDER_UPDATE_STATE_FAILURE, MENDER_UPDATE_STATE_ROLLBACK_REBOOT },
97
    /* MENDER_UPDATE_STATE_FAILURE                */ { MENDER_UPDATE_STATE_CLEANUP, MENDER_UPDATE_STATE_CLEANUP },
98
};
99

100
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_DBG
101
/* This is only needed for debug messages. */
102
static const char *update_state_str[N_MENDER_UPDATE_STATES + 1] = {
103
    "MENDER_UPDATE_STATE_DOWNLOAD",
104
    "MENDER_UPDATE_STATE_INSTALL",
105
    "MENDER_UPDATE_STATE_REBOOT",
106
    "MENDER_UPDATE_STATE_VERIFY_REBOOT",
107
    "MENDER_UPDATE_STATE_COMMIT",
108
    "MENDER_UPDATE_STATE_CLEANUP",
109
    "MENDER_UPDATE_STATE_ROLLBACK",
110
    "MENDER_UPDATE_STATE_ROLLBACK_REBOOT",
111
    "MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT",
112
    "MENDER_UPDATE_STATE_FAILURE",
113
    "MENDER_UPDATE_STATE_END",
114
};
115
#endif
116

117
/**
118
 * @brief Flag to know if network connection was requested or not
119
 */
120
static bool mender_client_network_connected = false;
121

122
/**
123
 * @brief Deployment data. Used to track progress of an update, so that the
124
 *        operation can resume or roll back across reboots
125
 */
126
static mender_deployment_data_t *mender_client_deployment_data = NULL;
127

128
/**
129
 * @brief Update module being used by the current deployment
130
 */
131
static mender_update_module_t *mender_update_module = NULL;
132

133
/**
134
 * @brief The main Mender work item
135
 */
136
static mender_work_t *mender_client_work = NULL;
137

138
/**
139
 * @brief Mender client work function
140
 * @return MENDER_OK if the function succeeds, error code otherwise
141
 */
142
static mender_err_t mender_client_work_function(void);
143

144
/**
145
 * @brief Mender client initialization work function
146
 * @return MENDER_OK if the function succeeds, error code otherwise
147
 */
148
static mender_err_t mender_client_initialization_work_function(void);
149

150
/**
151
 * @brief Function to request network access
152
 * @return MENDER_OK if network is connected following the request, error code otherwise
153
 */
154
static mender_err_t mender_client_network_connect(void);
155

156
/**
157
 * @brief Function to release network access
158
 * @return MENDER_OK if network is released following the request, error code otherwise
159
 */
160
static mender_err_t mender_client_network_release(void);
161

162
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
163
/**
164
 * @brief Compare artifact, device and deployment device types
165
 * @param device_type_artifact Device type of artifact
166
 * @param device_type_device Device type of configuration
167
 * @param device_type_deployment Device types of deployment
168
 * @param device_type_deployment_size Deployment device types size
169
 * @return MENDER_OK if the function succeeds, error code otherwise
170
 */
171
static mender_err_t mender_compare_device_types(const char  *device_type_artifact,
172
                                                const char  *device_type_device,
173
                                                const char **device_type_deployment,
174
                                                const size_t device_type_deployment_size);
175
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
176
/**
177
 * @brief Filter provides and merge the two lists
178
 * @param mender_artifact_ctx Mender artifact context
179
 * @param new_provides New provides list
180
 * @param stored_provides Stored provides list
181
 * @return MENDER_OK if the function succeeds, error code otherwise
182
 */
183
static mender_err_t mender_filter_provides(mender_artifact_ctx_t    *mender_artifact_ctx,
184
                                           mender_key_value_list_t **new_provides,
185
                                           mender_key_value_list_t **stored_provides);
186
/**
187
 * @brief Prepare the new provides data to be commited on a successful deployment
188
 * @param mender_artifact_ctx Mender artifact context
189
 * @param provides Provies data to be written
190
 * @return MENDER_OK if the function succeeds, error code otherwise
191
 */
192
static mender_err_t mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **provides, const char **artifact_name);
193

194
/**
195
 * @brief Determine the compatiblity of the deployment by: comparing artifact's depend with the stored provides
196
 * @param mender_artifact_ctx Mender artifact context
197
 * @return MENDER_OK if the function succeeds, error code otherwise
198
 */
199
static mender_err_t mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx);
200
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
201
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
202

203
/**
204
 * @brief Mender client update work function
205
 * @return MENDER_OK if the function succeeds, error code otherwise
206
 */
207
static mender_err_t mender_client_update_work_function(void);
208

209
/**
210
 * @brief Publish deployment status of the device to the mender-server and invoke deployment status callback
211
 * @param id ID of the deployment
212
 * @param deployment_status Deployment status
213
 * @return MENDER_OK if the function succeeds, error code otherwise
214
 */
215
static mender_err_t mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status);
216

217
/**
218
 * @brief Set state in deployment data and store it in permanent storage
219
 * @param state State to set and store
220
 * @return MENDER_OK in case of success, error code otherwise
221
 */
222
static mender_err_t set_and_store_state(const mender_update_state_t state);
223

224
char *
225
mender_client_version(void) {
×
226

227
    /* Return version as string */
228
    return MENDER_CLIENT_VERSION;
×
229
}
230

231
mender_err_t
232
mender_client_init(mender_client_config_t *config, mender_client_callbacks_t *callbacks) {
×
UNCOV
233
    assert(NULL != config);
×
234
    assert(NULL != callbacks);
×
235
    assert(NULL != callbacks->restart);
×
236

237
    /* Either all allocation functions set or none. */
NEW
238
    assert(((NULL == config->allocation_funcs.mender_malloc_func) && (NULL == config->allocation_funcs.mender_realloc_func)
×
239
            && (NULL == config->allocation_funcs.free_func))
240
           || ((NULL != config->allocation_funcs.mender_malloc_func) && (NULL != config->allocation_funcs.mender_realloc_func)
241
               && (NULL != config->allocation_funcs.free_func)));
242

243
    mender_err_t ret;
244

NEW
245
    if (NULL != config->allocation_funcs.mender_malloc_func) {
×
NEW
246
        mender_set_allocation_funcs(
×
247
            config->allocation_funcs.mender_malloc_func, config->allocation_funcs.mender_realloc_func, config->allocation_funcs.free_func);
248
    } else {
NEW
249
        mender_set_platform_allocation_funcs();
×
250
    }
251

252
    {
NEW
253
        cJSON_Hooks cjson_alloc_funcs = { mender_malloc, mender_free };
×
NEW
254
        cJSON_InitHooks(&cjson_alloc_funcs);
×
255
    }
256

257
    /* Prefer client config over Kconfig */
258
    mender_client_config.device_type = IS_NULL_OR_EMPTY(config->device_type) ? CONFIG_MENDER_DEVICE_TYPE : config->device_type;
×
259
    if (IS_NULL_OR_EMPTY(mender_client_config.device_type)) {
×
260
        mender_log_error("Invalid device type configuration, can't be null or empty");
×
261
        ret = MENDER_FAIL;
×
262
        goto END;
×
263
    }
264
    mender_log_info("Device type: [%s]", mender_client_config.device_type);
×
265

266
    if ((NULL != config->host) && (strlen(config->host) > 0)) {
×
267
        mender_client_config.host = config->host;
×
268
    } else {
269
        mender_client_config.host = CONFIG_MENDER_SERVER_HOST;
×
270
    }
271
    if ((NULL == mender_client_config.host) || (0 == strlen(mender_client_config.host))) {
×
272
        mender_log_error("Invalid server host configuration, can't be null or empty");
×
273
        ret = MENDER_FAIL;
×
274
        goto END;
×
275
    }
276
    if ('/' == mender_client_config.host[strlen(mender_client_config.host) - 1]) {
×
277
        mender_log_error("Invalid server host configuration, trailing '/' is not allowed");
×
278
        ret = MENDER_FAIL;
×
279
        goto END;
×
280
    }
281
    if ((NULL != config->tenant_token) && (strlen(config->tenant_token) > 0)) {
×
282
        mender_client_config.tenant_token = config->tenant_token;
×
283
    } else {
284
        mender_client_config.tenant_token = CONFIG_MENDER_SERVER_TENANT_TOKEN;
×
285
    }
286
    if ((NULL != mender_client_config.tenant_token) && (0 == strlen(mender_client_config.tenant_token))) {
×
287
        mender_client_config.tenant_token = NULL;
×
288
    }
289
    if (0 != config->update_poll_interval) {
×
290
        mender_client_config.update_poll_interval = config->update_poll_interval;
×
291
    } else {
292
        mender_client_config.update_poll_interval = CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL;
×
293
    }
294
    mender_client_config.recommissioning = config->recommissioning;
×
295

296
    /* Save callbacks */
297
    memcpy(&mender_client_callbacks, callbacks, sizeof(mender_client_callbacks_t));
×
298

299
    /* Initializations */
300
    // TODO: what to do with the authentication interval?
301
    if (MENDER_OK != (ret = mender_scheduler_init())) {
×
302
        mender_log_error("Unable to initialize scheduler");
×
303
        goto END;
×
304
    }
305
    if (MENDER_OK != (ret = mender_log_init())) {
×
306
        mender_log_error("Unable to initialize log");
×
307
        goto END;
×
308
    }
309
    if (MENDER_OK != (ret = mender_storage_init())) {
×
310
        mender_log_error("Unable to initialize storage");
×
311
        goto END;
×
312
    }
313
    if (MENDER_OK != (ret = mender_tls_init())) {
×
314
        mender_log_error("Unable to initialize TLS");
×
315
        goto END;
×
316
    }
317
    mender_api_config_t mender_api_config = {
×
318
        .device_type  = mender_client_config.device_type,
×
319
        .host         = mender_client_config.host,
×
320
        .tenant_token = mender_client_config.tenant_token,
×
321
        .identity_cb  = callbacks->get_identity,
×
322
    };
323
    if (MENDER_OK != (ret = mender_api_init(&mender_api_config))) {
×
324
        mender_log_error("Unable to initialize API");
×
325
        goto END;
×
326
    }
327

328
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
329
    if (MENDER_OK != (ret = mender_inventory_init(mender_client_config.inventory_update_interval))) {
330
        mender_log_error("Failed to initialize the inventory functionality");
331
        goto END;
332
    }
333
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
334

335
END:
×
336

337
    return ret;
×
338
}
339

340
mender_err_t
341
mender_client_activate(void) {
×
342
    mender_err_t ret;
343

344
    mender_scheduler_work_params_t work_params = {
×
345
        .function = mender_client_work_function,
346
        .period   = mender_client_config.update_poll_interval,
×
347
        .name     = "mender_client_main",
348
    };
349

350
    if ((MENDER_OK != (ret = mender_scheduler_work_create(&work_params, &mender_client_work)))
×
351
        || (MENDER_OK != (ret = mender_scheduler_work_activate(mender_client_work)))) {
×
352
        mender_log_error("Unable to activate the main work");
×
353
        return ret;
×
354
    }
355

356
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
357
    /* Activate inventory work */
358
    if (MENDER_OK != (ret = mender_inventory_activate())) {
359
        mender_log_error("Unable to activate the inventory functionality");
360
        return ret;
361
    }
362
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
363

364
    return ret;
×
365
}
366

367
mender_err_t
368
mender_client_ensure_connected(void) {
×
369
    if (mender_client_network_connected) {
×
370
        return MENDER_DONE;
×
371
    }
372

373
    return mender_client_network_connect();
×
374
}
375

376
static mender_err_t
377
mender_client_network_connect(void) {
×
378
    if (mender_client_network_connected) {
×
379
        return MENDER_OK;
×
380
    }
381

382
    /* Request network access */
383
    if (NULL != mender_client_callbacks.network_connect) {
×
384
        if (MENDER_OK != mender_client_callbacks.network_connect()) {
×
385
            mender_log_error("Unable to connect network");
×
386
            return MENDER_FAIL;
×
387
        }
388
    }
389

390
    mender_client_network_connected = true;
×
391

392
    return MENDER_OK;
×
393
}
394

395
static mender_err_t
396
mender_client_network_release(void) {
×
397
    if (!mender_client_network_connected) {
×
398
        return MENDER_OK;
×
399
    }
400

401
    /* Release network access */
402
    if (NULL != mender_client_callbacks.network_release) {
×
403
        if (MENDER_OK != mender_client_callbacks.network_release()) {
×
404
            mender_log_error("Unable to release network");
×
405
            return MENDER_FAIL;
×
406
        }
407
    }
408
    mender_client_network_connected = false;
×
409

410
    return MENDER_OK;
×
411
}
412

413
mender_err_t
414
mender_client_exit(void) {
×
415
    bool some_error = false;
×
416

417
    if (MENDER_OK != mender_scheduler_work_deactivate(mender_client_work)) {
×
418
        mender_log_error("Failed to deactivate main work");
×
419
        /* keep going on, we want to do as much cleanup as possible */
420
        some_error = true;
×
421
    }
422

423
    if (MENDER_OK != mender_scheduler_work_delete(mender_client_work)) {
×
424
        mender_log_error("Failed to delete main work");
×
425
        /* keep going on, we want to do as much cleanup as possible */
426
        some_error = true;
×
427
    } else {
428
        mender_client_work = NULL;
×
429
    }
430

431
    /* Stop scheduling new work */
432
    mender_scheduler_exit();
×
433

434
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
435
    if (MENDER_OK != mender_inventory_exit()) {
436
        mender_log_error("Unable to cleanup after the inventory functionality");
437
        /* keep going on, we want to do as much cleanup as possible */
438
        some_error = true;
439
    }
440
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
441

442
    /* Release all modules */
443
    mender_api_exit();
×
444
    mender_tls_exit();
×
445
    mender_storage_exit();
×
446
    mender_log_exit();
×
447
    mender_client_network_release();
×
448

449
    /* Release memory */
450
    mender_client_config.device_type          = NULL;
×
451
    mender_client_config.host                 = NULL;
×
452
    mender_client_config.tenant_token         = NULL;
×
453
    mender_client_config.update_poll_interval = 0;
×
454
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
455

456
    mender_update_module_unregister_all();
×
457

458
    return some_error ? MENDER_FAIL : MENDER_OK;
×
459
}
460

461
static mender_err_t
462
mender_client_work_function(void) {
×
463
    mender_err_t ret;
464
    mender_log_debug("Inside work function [state: %d]", mender_client_state);
465

466
    switch (mender_client_state) {
×
467
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
×
468
            mender_log_info("Waiting for a reboot");
×
469
            if (MENDER_OK != mender_err_count_reboot_inc()) {
×
470
                /* It appears we are stuck in this state. The only thing we can do is to mark the
471
                   deployment as failed and revert to normal operation. */
472
                mender_log_error("Waiting for reboot for too long, giving up");
×
473

474
                if (NULL == mender_client_deployment_data) {
×
475
                    mender_log_error("No deployment data to use for deployment abortion");
×
476
                } else {
477
                    mender_update_state_t update_state;
478
                    if (MENDER_OK != mender_deployment_data_get_state(mender_client_deployment_data, &update_state)) {
×
479
                        mender_log_error("Failed to get current update state, going to ROLLBACK state");
×
480
                        update_state = MENDER_UPDATE_STATE_ROLLBACK;
×
481
                    } else {
482
                        update_state = update_state_transitions[update_state].failure;
×
483
                    }
484
                    if (MENDER_OK != set_and_store_state(update_state)) {
×
485
                        mender_log_error("Failed to save new state");
×
486
                    }
487
                }
488

489
                mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
490
            }
491
            /* else:
492
               Nothing to do, but let's make sure we have a chance to detect we are stuck in this
493
               state (i.e. MENDER_OK, not MENDER_DONE which would tell the scheduler we are
494
               done and don't need to run again). */
495
            return MENDER_OK;
×
496
        case MENDER_CLIENT_STATE_INITIALIZATION:
×
497
            /* Perform initialization of the client */
498
            mender_err_count_reboot_reset();
×
499
            if (MENDER_DONE != mender_client_initialization_work_function()) {
×
500
                return MENDER_FAIL;
×
501
            }
502
            mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
503
            /* fallthrough */
504
        case MENDER_CLIENT_STATE_OPERATIONAL:
×
505
            mender_err_count_reboot_reset();
×
506
            ret = mender_client_update_work_function();
×
507
            if (MENDER_FAIL == ret) {
×
508
                if (MENDER_FAIL == mender_err_count_net_check()) {
×
509
                    /* Try to release network so that it gets set up again next
510
                       time. */
511
                    mender_client_network_release();
×
512
                }
513
            } else if (!MENDER_IS_ERROR(ret)) {
×
514
                mender_err_count_net_reset();
×
515
            }
516
            if (MENDER_DONE == ret) {
×
517
                /* We should only be done when waiting for a reboot. */
518
                assert(MENDER_CLIENT_STATE_PENDING_REBOOT == mender_client_state);
×
519

520
                /* We don't want to tell the scheduler we are done because
521
                   otherwise we won't have a chance to detect that we are
522
                   waiting for a reboot forever. */
523
                ret = MENDER_OK;
×
524
            }
525
            return ret;
×
526
    }
527

528
    /* This should never be reached, all the cases should be covered in the
529
       above switch and they all return. */
530
    return MENDER_FAIL;
×
531
}
532

533
static mender_err_t
534
mender_client_initialization_work_function(void) {
×
535

536
    mender_err_t ret = MENDER_DONE;
×
537

538
    /* Retrieve or generate authentication keys */
539
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
×
540
        mender_log_error("Unable to retrieve or generate authentication keys");
×
541
        goto END;
×
542
    }
543

544
    /* Retrieve deployment data if it is found (following an update) */
545
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
×
546
        if (MENDER_NOT_FOUND != ret) {
×
547
            mender_log_error("Unable to get deployment data");
×
548
            goto REBOOT;
×
549
        }
550
    }
551

552
    mender_log_info("Initialization done");
×
553

554
    return MENDER_DONE;
×
555

556
END:
×
557

558
    return ret;
×
559

560
REBOOT:
×
561

562
    mender_log_info("Rebooting...");
×
563

564
    /* Delete pending deployment */
565
    mender_storage_delete_deployment_data();
×
566

567
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
568
    if (NULL != mender_client_callbacks.restart) {
×
569
        mender_client_callbacks.restart();
×
570
    }
571

572
    return ret;
×
573
}
574

575
static mender_err_t
576
mender_commit_artifact_data(void) {
×
577

578
    assert(NULL != mender_client_deployment_data);
×
579

580
    const char *artifact_name;
581
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
582
        mender_log_error("Unable to get artifact name from the deployment data");
×
583
        return MENDER_FAIL;
×
584
    }
585

586
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
587
        mender_log_error("Unable to set artifact name");
×
588
        return MENDER_FAIL;
×
589
    }
590

591
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
592
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
593
    /* Get provides from the deployment data */
594
    const char *provides;
595
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
×
596
        mender_log_error("Unable to get new_provides from the deployment data");
×
597
        return MENDER_FAIL;
×
598
    }
599

600
    /* Parse provides */
601
    mender_key_value_list_t *new_provides = NULL;
×
602
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
×
603
        mender_log_error("Unable to parse provides from the deployment data");
×
604
        return MENDER_FAIL;
×
605
    }
606
    /* Replace the stored provides with the new provides */
607
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
×
608
        mender_log_error("Unable to set provides");
×
609
        mender_utils_key_value_list_free(new_provides);
×
610
        return MENDER_FAIL;
×
611
    }
612
    mender_utils_key_value_list_free(new_provides);
×
613
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
614
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
615

616
    return MENDER_OK;
×
617
}
618

619
static mender_err_t
620
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
621
    if (NULL != deployment) {
×
NEW
622
        mender_free(deployment->id);
×
NEW
623
        mender_free(deployment->artifact_name);
×
NEW
624
        mender_free(deployment->uri);
×
625
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
NEW
626
            mender_free(deployment->device_types_compatible[i]);
×
627
        }
NEW
628
        mender_free(deployment->device_types_compatible);
×
NEW
629
        mender_free(deployment);
×
630
    }
631
    return MENDER_OK;
×
632
}
633

634
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
635
static mender_err_t
636
mender_compare_device_types(const char  *device_type_artifact,
×
637
                            const char  *device_type_device,
638
                            const char **device_type_deployment,
639
                            const size_t device_type_deployment_size) {
640

641
    assert(NULL != device_type_artifact);
×
642
    assert(NULL != device_type_deployment);
×
643
    assert(NULL != device_type_device);
×
644
    assert(0 < device_type_deployment_size);
×
645

646
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
647
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
648
        return MENDER_FAIL;
×
649
    }
650

651
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
652
    for (size_t i = 0; i < device_type_deployment_size; i++) {
×
653
        if (StringEqual(device_type_deployment[i], device_type_device)) {
×
654
            return MENDER_OK;
×
655
        }
656
    }
657
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
658
    return MENDER_FAIL;
×
659
}
660

661
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
662
static mender_err_t
663
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
664

665
    mender_err_t ret = MENDER_FAIL;
×
666
    /* Clears provides */
667
    bool matches;
668
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
669
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
×
670
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
×
671
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
×
672
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
673
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
674
                    goto END;
×
675
                }
676
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
677
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
678
                    goto END;
×
679
                }
680
            }
681
        }
682
    }
683

684
    /* Combine the stored provides with the new ones */
685
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
686
        mender_log_error("Unable to merge provides");
×
687
        goto END;
×
688
    }
689

690
    /* Make sure the artifact name is not in the new provides */
691
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
692
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
693
        goto END;
×
694
    }
695

696
    ret = MENDER_OK;
×
697

698
END:
×
699

700
    mender_utils_key_value_list_free(*stored_provides);
×
701
    return ret;
×
702
}
703

704
static mender_err_t
705
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
706

707
    assert(NULL != artifact_name);
×
708
    assert(NULL != mender_artifact_ctx);
×
709

710
    /* Load the currently stored provides */
711
    mender_key_value_list_t *stored_provides = NULL;
×
712
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
713
        mender_log_error("Unable to get provides");
×
714
        return MENDER_FAIL;
×
715
    }
716

717
    mender_key_value_list_t *provides = NULL;
×
718
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
719
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
720
            mender_log_error("Unable to merge provides");
×
721
            mender_utils_key_value_list_free(stored_provides);
×
722
            return MENDER_FAIL;
×
723
        }
724
    }
725

726
    /* Get artifact name from provides */
727
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
728
        if (StringEqual("artifact_name", item->key)) {
×
729
            *artifact_name = item->value;
×
730
            break;
×
731
        }
732
    }
733

734
    if (NULL == *artifact_name) {
×
735
        mender_log_error("No artifact name found in provides");
×
736
        mender_utils_key_value_list_free(stored_provides);
×
737
        return MENDER_FAIL;
×
738
    }
739

740
    /* Filter provides */
741
    /* `stored_provides` is freed in `mender_filter_provides` */
742
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
743
        return MENDER_FAIL;
×
744
    }
745

746
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
747
        return MENDER_FAIL;
×
748
    }
749

750
    return MENDER_OK;
×
751
}
752

753
static mender_err_t
754
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
755

756
    /* We need to load the stored provides */
757
    mender_key_value_list_t *stored_provides = NULL;
×
758
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
759
        return MENDER_FAIL;
×
760
    }
761

762
    mender_err_t ret = MENDER_FAIL;
×
763

764
    /* Get depends */
765
    mender_key_value_list_t *depends = NULL;
×
766
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
767
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
768
            mender_log_error("Unable to append depends");
×
769
            goto END;
×
770
        }
771
    }
772

773
    /* Match depends from artifact with device's provides */
774
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
×
775
        bool matches = false;
×
776
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
777
            /* Match key-value from depends with provides */
778
            if (StringEqual(depends_item->key, provides_item->key)) {
×
779
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
780
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
781
                                     depends_item->key,
782
                                     depends_item->value,
783
                                     provides_item->value);
784
                    break;
×
785
                }
786
                matches = true;
×
787
                break;
×
788
            }
789
        }
790
        if (!matches) {
×
791
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
792
            goto END;
×
793
        }
794
    }
795

796
    ret = MENDER_OK;
×
797

798
END:
×
799
    mender_utils_key_value_list_free(stored_provides);
×
800
    return ret;
×
801
}
802
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
803
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
804

805
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
806
static mender_err_t
807
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
808
    mender_err_t ret;
809

810
    /* Retrieve device type from artifact */
811
    const char *device_type_artifact = NULL;
×
812
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
813
        mender_log_error("Unable to get device type from artifact");
×
814
        return ret;
×
815
    }
816

817
    mender_log_debug("Checking device type compatibility");
818

819
    /* Match device type  */
820
    if (MENDER_OK
×
821
        != (ret = mender_compare_device_types(device_type_artifact,
×
822
                                              mender_client_config.device_type,
×
823
                                              (const char **)deployment->device_types_compatible,
×
824
                                              deployment->device_types_compatible_size))) {
825
        return ret;
×
826
    }
827

828
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
829
    /* Compare Artifact's depends with the stored provides */
830
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
831
        return ret;
×
832
    }
833
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
834

835
    /* Check artifact integrity by comparing computed checksums with those
836
     * listed in the artifacts manifest */
837
    if (MENDER_OK != mender_artifact_check_integrity(mender_artifact_ctx)) {
×
838
        return MENDER_FAIL;
×
839
    }
840

841
    return MENDER_OK;
×
842
}
843
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
844

845
static mender_err_t
846
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
847
    assert(NULL != deployment_data);
×
848

849
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
850
        /* network errors logged already */
851
        mender_log_error("Cannot check for new deployment");
×
852
        return MENDER_FAIL;
×
853
    }
854

NEW
855
    if (NULL == (*deployment_data = mender_calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
856
        mender_log_error("Unable to allocate memory for deployment data");
×
857
        return MENDER_FAIL;
×
858
    }
859

860
    mender_api_deployment_data_t *deployment = *deployment_data;
×
861

862
    mender_err_t ret = MENDER_OK;
×
863

864
    mender_log_info("Checking for deployment...");
×
865
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
866
        mender_log_info("No deployment available");
×
867
        return MENDER_DONE;
×
868
    } else if (MENDER_OK != ret) {
×
869
        mender_log_error("Unable to check for deployment");
×
870
        return MENDER_FAIL;
×
871
    }
872

873
    /* Check if deployment is valid */
874
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
875
        mender_log_error("Invalid deployment data");
×
876
        return MENDER_FAIL;
×
877
    }
878

879
    /* Create deployment data */
880
    if (NULL != mender_client_deployment_data) {
×
881
        mender_log_warning("Unexpected stale deployment data");
×
882
        mender_delete_deployment_data(mender_client_deployment_data);
×
883
    }
884
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
885
        /* Error already logged */
886
        return MENDER_FAIL;
×
887
    }
888

889
    return MENDER_OK;
×
890
}
891

892
static mender_err_t
893
set_and_store_state(const mender_update_state_t state) {
×
894

895
    /*
896
     * Set the state in `mender_client_deployment_data` and write it to the nvs
897
     */
898

899
    mender_err_t ret = MENDER_OK;
×
900

901
    /* Set state in deployment data */
902
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
903
        mender_log_error("Failed to set deployment data state");
×
904
        return ret;
×
905
    }
906

907
    /* Store deployment data */
908
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
909
        mender_log_error("Failed to store deployment data");
×
910
        return ret;
×
911
    }
912
    return ret;
×
913
}
914

915
static mender_err_t
916
mender_client_update_work_function(void) {
×
917
    mender_err_t ret = MENDER_OK;
×
918

919
    /* Ensure that the context is initialized to NULL before goto END */
920
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
921

922
    /* Check for deployment */
923
    mender_api_deployment_data_t *deployment    = NULL;
×
924
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
925
    const char                   *deployment_id = NULL;
×
926

927
    /* reset the currently used update module */
928
    mender_update_module = NULL;
×
929

930
    if (NULL != mender_client_deployment_data) {
×
931
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
932
    }
933

934
    {
935
        const char           *artifact_type;
936
        mender_update_state_t update_state_resume;
937
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
×
938
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
×
939
            update_state = update_state_resume;
×
940
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
941
            mender_update_module = mender_update_module_get(artifact_type);
×
942
            if (NULL == mender_update_module) {
×
943
                /* The artifact_type from the saved state does not match any update module */
944
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
945
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
946
                mender_storage_delete_deployment_data();
×
947
                goto END;
×
948
            }
949
        }
950
    }
951

952
    /* Skip the block below if we just resume from a saved state. */
953

954
/* A macro to advance to the next state -- on success we just keep going to the
955
 * code below the macro invocation (fallthrough to the next case), on error we
956
 * go to the beginning of the loop (the switch statement) again using 'continue'
957
 * (see below).
958
 *
959
 * mender_update_module is guaranteed be not NULL since the first
960
 * successful transition (from the DOWNLOAD state). */
961
#define NEXT_STATE                                                             \
962
    if (MENDER_OK == ret) {                                                    \
963
        update_state = update_state_transitions[update_state].success;         \
964
        assert(NULL != mender_update_module);                                  \
965
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
966
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
967
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
968
        }                                                                      \
969
    } else {                                                                   \
970
        update_state = update_state_transitions[update_state].failure;         \
971
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
972
        if (NULL != mender_update_module) {                                    \
973
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
974
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
975
            }                                                                  \
976
        }                                                                      \
977
        ret = MENDER_OK;                                                       \
978
        continue;                                                              \
979
    }
980

981
    while (MENDER_UPDATE_STATE_END != update_state) {
×
982
        switch (update_state) {
×
983
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
984

985
                /* Check for deployment */
986
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
987
                    /* No deployment available, but we are not done, we need to keep checking. */
988
                    if (MENDER_DONE == ret) {
×
989
                        ret = MENDER_OK;
×
990
                    }
991
                    goto END;
×
992
                }
993

994
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
995
                if (strlen(deployment->id) > 10) {
×
996
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
997
                } else {
998
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
999
                }
1000
#endif
1001
                /* Set deployment_id */
1002
                deployment_id = deployment->id;
×
1003

1004
                /* Check ret to see if the deployment is aborted */
1005
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
1006
                if ((MENDER_ABORTED != ret)
×
1007
                    && (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module)))) {
×
1008
                    assert(NULL != mender_update_module);
×
1009

1010
                    /* Get artifact context if artifact download succeeded */
1011
                    if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) {
×
1012
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
1013
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
×
1014
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
1015
                            /* Add the new provides to the deployment data (we need the artifact context) */
1016
                            char       *new_provides  = NULL;
×
1017
                            const char *artifact_name = NULL;
×
1018
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
×
1019
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
×
1020
                                    mender_log_error("Failed to set deployment data provides");
×
1021
                                }
1022
                                /* Replace artifact_name with the one from provides */
1023
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
×
1024
                                    mender_log_error("Failed to set deployment data artifact name");
×
1025
                                }
NEW
1026
                                mender_free(new_provides);
×
1027
                            } else {
1028
                                mender_log_error("Unable to prepare new provides");
×
1029
                            }
1030
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
1031
                        }
1032
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1033
                    } else {
1034
                        mender_log_error("Unable to get artifact type and context");
×
1035
                    }
1036
                } else {
1037
                    mender_log_error("Unable to download artifact");
×
1038
                    if (NULL == mender_update_module) {
×
1039
                        /* Error logged in mender_client_download_artifact_callback() */
1040
                        mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1041
                        goto END;
×
1042
                    }
1043
                }
1044
                NEXT_STATE;
×
1045
                /* fallthrough */
1046

1047
            case MENDER_UPDATE_STATE_INSTALL:
1048
                mender_log_info("Download done, installing artifact");
×
1049
                /* Check ret to see if the deployment is aborted */
1050
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
×
1051
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1052
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1053
                }
1054
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
×
1055
                    /* skip reboot */
1056
                    update_state = MENDER_UPDATE_STATE_COMMIT;
×
1057
                    set_and_store_state(update_state);
×
1058
                    continue;
×
1059
                }
1060
                /* else continue to the next successful/failure state */
1061
                NEXT_STATE;
×
1062
                /* fallthrough */
1063

1064
            case MENDER_UPDATE_STATE_REBOOT:
1065
                assert(mender_update_module->requires_reboot);
×
1066
                mender_log_info("Artifact installation done, rebooting");
×
1067
                /* Check ret to see if the deployment is aborted */
1068
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
×
1069
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1070
                    /* Save the next state before running the reboot callback --
1071
                     * if there is an interrupt (power, crash,...) right after,
1072
                     * it will reboot anyway so after the new boot, reboot
1073
                     * verification should happen anyway, the callback in that
1074
                     * state should be able to see if things went well or
1075
                     * wrong. */
1076
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
×
1077
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1078
                    if (MENDER_OK == ret) {
×
1079
                        /* now we need to get outside of the loop so that a
1080
                         * potential asynchronous reboot has a chance to kick in
1081
                         * after a proper cleanup below */
1082
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1083
                        ret                 = MENDER_DONE;
×
1084
                        goto END;
×
1085
                    }
1086
                }
1087
                NEXT_STATE;
×
1088
                /* fallthrough */
1089

1090
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1091
                assert(mender_update_module->requires_reboot);
×
1092
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1093
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1094
                }
1095
                NEXT_STATE;
×
1096
                /* fallthrough */
1097

1098
            case MENDER_UPDATE_STATE_COMMIT:
1099
                /* Check for pending deployment */
1100
                if (NULL == mender_client_deployment_data) {
×
1101
                    mender_log_error("No deployment data found on commit");
×
1102
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1103
                    goto END;
×
1104
                }
1105
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1106
                if (MENDER_OK != mender_api_drop_authentication_data()) {
×
1107
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1108
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1109
                       much to about it. */
1110
                }
1111
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
×
1112
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1113
                }
1114
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
1115
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
×
1116
                    mender_log_error("Unable to commit artifact data");
×
1117
                }
1118
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1119
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1120
                }
1121
                if (!MENDER_IS_ERROR(ret)) {
×
1122
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
×
1123
                }
1124
                NEXT_STATE;
×
1125
                /* fallthrough */
1126

1127
            case MENDER_UPDATE_STATE_CLEANUP:
1128
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1129
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1130
                }
1131
                NEXT_STATE;
×
1132
                mender_storage_delete_deployment_data();
×
1133
                break; /* below is the failure path */
×
1134

1135
            case MENDER_UPDATE_STATE_ROLLBACK:
×
1136
                if (!mender_update_module->supports_rollback) {
×
1137
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
×
1138
                    ret = MENDER_FAIL;
×
1139
                } else if (NULL != mender_update_module->callbacks[update_state]) {
×
1140
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1141
                }
1142
                NEXT_STATE;
×
1143
                /* fallthrough */
1144

1145
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1146
                /* Save the next state before running the reboot callback (see
1147
                 * STATE_REBOOT for details). */
1148
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
1149
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1150

1151
                if (MENDER_OK == ret) {
×
1152
                    /* now we need to get outside of the loop so that a
1153
                     * potential asynchronous reboot has a chance to kick in
1154
                     * after a proper cleanup below */
1155
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1156
                    ret                 = MENDER_DONE;
×
1157
                    goto END;
×
1158
                }
1159
                NEXT_STATE;
×
1160
                /* fallthrough */
1161

1162
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1163
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1164
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1165
                }
1166

1167
                if (MENDER_OK != ret) {
×
1168
                    /* If the rollback verify reboot fails,
1169
                     * we will retry the rollback reboot.
1170
                     *
1171
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1172
                     * loop is broken when a state loop is detected
1173
                     */
1174
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
×
1175
                }
1176

1177
                NEXT_STATE;
×
1178
                /* fallthrough */
1179

1180
            case MENDER_UPDATE_STATE_FAILURE:
1181
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1182
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1183
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1184
                }
1185
                NEXT_STATE;
×
1186
                break; /* end of the failure path */
×
1187

1188
            case MENDER_UPDATE_STATE_END:
×
1189
                /* This is only here to cover all possible values of the
1190
                 * update_state enum, there is nothing to do here, the while
1191
                 * loop shall stop when we get here. */
1192
                break;
×
1193
        }
1194
    }
1195
#undef NEXT_STATE /* should not be used anywhere else */
1196

1197
    ret = MENDER_OK;
×
1198

1199
END:
×
1200
    /* Release memory */
1201
    deployment_destroy(deployment);
×
1202
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
1203
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1204

1205
    return ret;
×
1206
}
1207

1208
static mender_err_t
1209
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
1210
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1211
        /* connection errors logged already */
1212
        mender_log_error("Cannot publish deployment status");
×
1213
        return MENDER_FAIL;
×
1214
    }
1215

1216
    mender_err_t ret;
1217

1218
    if (NULL == id) {
×
1219
        mender_log_error("Cannot publish deployment status: unknown status");
×
1220
        return MENDER_FAIL;
×
1221
    }
1222

1223
    /* Publish status to the mender server */
1224
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1225

1226
    /* Invoke deployment status callback if defined */
1227
    if (NULL != mender_client_callbacks.deployment_status) {
×
1228
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1229
    }
1230

1231
    return ret;
×
1232
}
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