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

mendersoftware / mender-mcu / 1564701830

28 Nov 2024 04:29PM UTC coverage: 9.088%. Remained the same
1564701830

push

gitlab-ci

vpodzime
fix: Detect hanging in PENDING_REBOOT state

If reboot was requested, but it hasn't come in a pre-defined
number of iterations to wait, we need to fail the deployment and
resume normal operation.

This also means we need to tell the scheduler to run the work
function even if it is just waiting for a reboot and has nothing
to do. Nothing else than checking if it has not been waiting for
too long.

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

0 of 28 new or added lines in 2 files covered. (0.0%)

222 existing lines in 1 file now uncovered.

251 of 2762 relevant lines covered (9.09%)

0.65 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-api.h"
22
#include "mender-client.h"
23
#include "mender-artifact.h"
24
#include "mender-artifact-download.h"
25
#include "mender-log.h"
26
#include "mender-scheduler.h"
27
#include "mender-storage.h"
28
#include "mender-tls.h"
29
#include "mender-update-module.h"
30
#include "mender-utils.h"
31
#include "mender-deployment-data.h"
32
#include "mender-error-counters.h"
33

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

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

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

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

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

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

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

76
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
77

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

223
char *
UNCOV
224
mender_client_version(void) {
×
225

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

230
mender_err_t
231
mender_client_init(mender_client_config_t *config, mender_client_callbacks_t *callbacks) {
×
232

UNCOV
233
    assert(NULL != config);
×
234
    assert(NULL != callbacks);
×
UNCOV
235
    assert(NULL != callbacks->restart);
×
236
    mender_err_t ret;
237

238
    /* Prefer client config over Kconfig */
UNCOV
239
    mender_client_config.device_type = IS_NULL_OR_EMPTY(config->device_type) ? CONFIG_MENDER_DEVICE_TYPE : config->device_type;
×
240
    if (IS_NULL_OR_EMPTY(mender_client_config.device_type)) {
×
241
        mender_log_error("Invalid device type configuration, can't be null or empty");
×
242
        ret = MENDER_FAIL;
×
UNCOV
243
        goto END;
×
244
    }
UNCOV
245
    mender_log_info("Device type: [%s]", mender_client_config.device_type);
×
246

247
    if ((NULL != config->host) && (strlen(config->host) > 0)) {
×
248
        mender_client_config.host = config->host;
×
249
    } else {
250
        mender_client_config.host = CONFIG_MENDER_SERVER_HOST;
×
251
    }
252
    if ((NULL == mender_client_config.host) || (0 == strlen(mender_client_config.host))) {
×
UNCOV
253
        mender_log_error("Invalid server host configuration, can't be null or empty");
×
254
        ret = MENDER_FAIL;
×
255
        goto END;
×
256
    }
257
    if ('/' == mender_client_config.host[strlen(mender_client_config.host) - 1]) {
×
UNCOV
258
        mender_log_error("Invalid server host configuration, trailing '/' is not allowed");
×
259
        ret = MENDER_FAIL;
×
260
        goto END;
×
261
    }
262
    if ((NULL != config->tenant_token) && (strlen(config->tenant_token) > 0)) {
×
UNCOV
263
        mender_client_config.tenant_token = config->tenant_token;
×
264
    } else {
265
        mender_client_config.tenant_token = CONFIG_MENDER_SERVER_TENANT_TOKEN;
×
266
    }
267
    if ((NULL != mender_client_config.tenant_token) && (0 == strlen(mender_client_config.tenant_token))) {
×
UNCOV
268
        mender_client_config.tenant_token = NULL;
×
269
    }
270
    if (0 != config->update_poll_interval) {
×
UNCOV
271
        mender_client_config.update_poll_interval = config->update_poll_interval;
×
272
    } else {
UNCOV
273
        mender_client_config.update_poll_interval = CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL;
×
274
    }
275
    mender_client_config.recommissioning = config->recommissioning;
×
276

277
    /* Save callbacks */
278
    memcpy(&mender_client_callbacks, callbacks, sizeof(mender_client_callbacks_t));
×
279

280
    /* Initializations */
281
    // TODO: what to do with the authentication interval?
282
    if (MENDER_OK != (ret = mender_scheduler_init())) {
×
UNCOV
283
        mender_log_error("Unable to initialize scheduler");
×
UNCOV
284
        goto END;
×
285
    }
UNCOV
286
    if (MENDER_OK != (ret = mender_log_init())) {
×
UNCOV
287
        mender_log_error("Unable to initialize log");
×
UNCOV
288
        goto END;
×
289
    }
290
    if (MENDER_OK != (ret = mender_storage_init())) {
×
291
        mender_log_error("Unable to initialize storage");
×
UNCOV
292
        goto END;
×
293
    }
294
    if (MENDER_OK != (ret = mender_tls_init())) {
×
295
        mender_log_error("Unable to initialize TLS");
×
UNCOV
296
        goto END;
×
297
    }
298
    mender_api_config_t mender_api_config = {
×
299
        .device_type  = mender_client_config.device_type,
×
UNCOV
300
        .host         = mender_client_config.host,
×
301
        .tenant_token = mender_client_config.tenant_token,
×
302
        .identity_cb  = callbacks->get_identity,
×
303
    };
UNCOV
304
    if (MENDER_OK != (ret = mender_api_init(&mender_api_config))) {
×
305
        mender_log_error("Unable to initialize API");
×
306
        goto END;
×
307
    }
308

309
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
310
    if (MENDER_OK != (ret = mender_inventory_init(mender_client_config.inventory_update_interval))) {
311
        mender_log_error("Failed to initialize the inventory functionality");
312
        goto END;
313
    }
314
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
315

UNCOV
316
END:
×
317

UNCOV
318
    return ret;
×
319
}
320

321
mender_err_t
UNCOV
322
mender_client_activate(void) {
×
323
    mender_err_t ret;
324

325
    mender_scheduler_work_params_t work_params = {
×
326
        .function = mender_client_work_function,
UNCOV
327
        .period   = mender_client_config.update_poll_interval,
×
328
        .name     = "mender_client_main",
329
    };
330

UNCOV
331
    if ((MENDER_OK != (ret = mender_scheduler_work_create(&work_params, &mender_client_work)))
×
332
        || (MENDER_OK != (ret = mender_scheduler_work_activate(mender_client_work)))) {
×
UNCOV
333
        mender_log_error("Unable to activate the main work");
×
334
        return ret;
×
335
    }
336

337
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
338
    /* Activate inventory work */
339
    if (MENDER_OK != (ret = mender_inventory_activate())) {
340
        mender_log_error("Unable to activate the inventory functionality");
341
        return ret;
342
    }
343
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
344

UNCOV
345
    return ret;
×
346
}
347

348
mender_err_t
UNCOV
349
mender_client_ensure_connected(void) {
×
UNCOV
350
    if (mender_client_network_connected) {
×
UNCOV
351
        return MENDER_DONE;
×
352
    }
353

UNCOV
354
    return mender_client_network_connect();
×
355
}
356

357
static mender_err_t
358
mender_client_network_connect(void) {
×
UNCOV
359
    if (mender_client_network_connected) {
×
UNCOV
360
        return MENDER_OK;
×
361
    }
362

363
    /* Request network access */
UNCOV
364
    if (NULL != mender_client_callbacks.network_connect) {
×
365
        if (MENDER_OK != mender_client_callbacks.network_connect()) {
×
366
            mender_log_error("Unable to connect network");
×
367
            return MENDER_FAIL;
×
368
        }
369
    }
370

371
    mender_client_network_connected = true;
×
372

373
    return MENDER_OK;
×
374
}
375

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

382
    /* Release network access */
UNCOV
383
    if (NULL != mender_client_callbacks.network_release) {
×
384
        if (MENDER_OK != mender_client_callbacks.network_release()) {
×
385
            mender_log_error("Unable to release network");
×
386
            return MENDER_FAIL;
×
387
        }
388
    }
UNCOV
389
    mender_client_network_connected = false;
×
390

391
    return MENDER_OK;
×
392
}
393

394
mender_err_t
UNCOV
395
mender_client_exit(void) {
×
396
    bool some_error = false;
×
397

398
    if (MENDER_OK != mender_scheduler_work_deactivate(mender_client_work)) {
×
UNCOV
399
        mender_log_error("Failed to deactivate main work");
×
400
        /* keep going on, we want to do as much cleanup as possible */
UNCOV
401
        some_error = true;
×
402
    }
403

UNCOV
404
    if (MENDER_OK != mender_scheduler_work_delete(mender_client_work)) {
×
405
        mender_log_error("Failed to delete main work");
×
406
        /* keep going on, we want to do as much cleanup as possible */
UNCOV
407
        some_error = true;
×
408
    } else {
UNCOV
409
        mender_client_work = NULL;
×
410
    }
411

412
    /* Stop scheduling new work */
UNCOV
413
    mender_scheduler_exit();
×
414

415
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
416
    if (MENDER_OK != mender_inventory_exit()) {
417
        mender_log_error("Unable to cleanup after the inventory functionality");
418
        /* keep going on, we want to do as much cleanup as possible */
419
        some_error = true;
420
    }
421
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
422

423
    /* Release all modules */
UNCOV
424
    mender_api_exit();
×
UNCOV
425
    mender_tls_exit();
×
UNCOV
426
    mender_storage_exit();
×
UNCOV
427
    mender_log_exit();
×
UNCOV
428
    mender_client_network_release();
×
429

430
    /* Release memory */
431
    mender_client_config.device_type          = NULL;
×
432
    mender_client_config.host                 = NULL;
×
433
    mender_client_config.tenant_token         = NULL;
×
434
    mender_client_config.update_poll_interval = 0;
×
435
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
436

UNCOV
437
    mender_update_module_unregister_all();
×
438

439
    return some_error ? MENDER_FAIL : MENDER_OK;
×
440
}
441

442
static mender_err_t
UNCOV
443
mender_client_work_function(void) {
×
444
    mender_err_t ret;
445
    mender_log_debug("Inside work function [state: %d]", mender_client_state);
446

UNCOV
447
    switch (mender_client_state) {
×
UNCOV
448
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
×
UNCOV
449
            mender_log_info("Waiting for a reboot");
×
NEW
450
            if (MENDER_OK != mender_err_count_reboot_inc()) {
×
451
                /* It appears we are stuck in this state. The only thing we can do is to mark the
452
                   deployment as failed and revert to normal operation. */
NEW
453
                mender_log_error("Waiting for reboot for too long, giving up");
×
454

NEW
455
                if (NULL == mender_client_deployment_data) {
×
NEW
456
                    mender_log_error("No deployment data to use for deployment abortion");
×
457
                } else {
458
                    mender_update_state_t update_state;
NEW
459
                    if (MENDER_OK != mender_deployment_data_get_state(mender_client_deployment_data, &update_state)) {
×
NEW
460
                        mender_log_error("Failed to get current update state, going to ROLLBACK state");
×
NEW
461
                        update_state = MENDER_UPDATE_STATE_ROLLBACK;
×
462
                    } else {
NEW
463
                        update_state = update_state_transitions[update_state].failure;
×
464
                    }
NEW
465
                    if (MENDER_OK != set_and_store_state(update_state)) {
×
NEW
466
                        mender_log_error("Failed to save new state");
×
467
                    }
468
                }
469

NEW
470
                mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
471
            }
472
            /* else:
473
               Nothing to do, but let's make sure we have a chance to detect we are stuck in this
474
               state (i.e. MENDER_OK, not MENDER_DONE which would tell the scheduler we are
475
               done and don't need to run again). */
NEW
476
            return MENDER_OK;
×
UNCOV
477
        case MENDER_CLIENT_STATE_INITIALIZATION:
×
478
            /* Perform initialization of the client */
NEW
479
            mender_err_count_reboot_reset();
×
480
            if (MENDER_DONE != mender_client_initialization_work_function()) {
×
481
                return MENDER_FAIL;
×
482
            }
483
            mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
484
            /* fallthrough */
UNCOV
485
        case MENDER_CLIENT_STATE_OPERATIONAL:
×
NEW
486
            mender_err_count_reboot_reset();
×
NEW
487
            ret = mender_client_update_work_function();
×
NEW
488
            if (MENDER_FAIL == ret) {
×
489
                if (MENDER_FAIL == mender_err_count_net_check()) {
×
490
                    /* Try to release network so that it gets set up again next
491
                       time. */
UNCOV
492
                    mender_client_network_release();
×
493
                }
494
            }
NEW
495
            if (MENDER_DONE == ret) {
×
496
                /* We should only be done when waiting for a reboot. */
NEW
497
                assert(MENDER_CLIENT_STATE_PENDING_REBOOT == mender_client_state);
×
498

499
                /* We don't want to tell the scheduler we are done because
500
                   otherwise we won't have a chance to detect that we are
501
                   waiting for a reboot forever. */
NEW
502
                ret = MENDER_OK;
×
503
            }
504
            return ret;
×
505
    }
506

507
    /* This should never be reached, all the cases should be covered in the
508
       above switch and they all return. */
509
    return MENDER_FAIL;
×
510
}
511

512
static mender_err_t
UNCOV
513
mender_client_initialization_work_function(void) {
×
514

UNCOV
515
    mender_err_t ret = MENDER_DONE;
×
516

517
    /* Retrieve or generate authentication keys */
UNCOV
518
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
×
UNCOV
519
        mender_log_error("Unable to retrieve or generate authentication keys");
×
520
        goto END;
×
521
    }
522

523
    /* Retrieve deployment data if it is found (following an update) */
524
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
×
525
        if (MENDER_NOT_FOUND != ret) {
×
UNCOV
526
            mender_log_error("Unable to get deployment data");
×
527
            goto REBOOT;
×
528
        }
529
    }
530

531
    mender_log_info("Initialization done");
×
532

533
    return MENDER_DONE;
×
534

UNCOV
535
END:
×
536

UNCOV
537
    return ret;
×
538

539
REBOOT:
×
540

541
    mender_log_info("Rebooting...");
×
542

543
    /* Delete pending deployment */
UNCOV
544
    mender_storage_delete_deployment_data();
×
545

546
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
UNCOV
547
    if (NULL != mender_client_callbacks.restart) {
×
548
        mender_client_callbacks.restart();
×
549
    }
550

UNCOV
551
    return ret;
×
552
}
553

554
static mender_err_t
UNCOV
555
mender_commit_artifact_data(void) {
×
556

557
    assert(NULL != mender_client_deployment_data);
×
558

559
    const char *artifact_name;
UNCOV
560
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
UNCOV
561
        mender_log_error("Unable to get artifact name from the deployment data");
×
562
        return MENDER_FAIL;
×
563
    }
564

UNCOV
565
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
UNCOV
566
        mender_log_error("Unable to set artifact name");
×
UNCOV
567
        return MENDER_FAIL;
×
568
    }
569

570
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
571
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
572
    /* Get provides from the deployment data */
573
    const char *provides;
UNCOV
574
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
×
575
        mender_log_error("Unable to get new_provides from the deployment data");
×
UNCOV
576
        return MENDER_FAIL;
×
577
    }
578

579
    /* Parse provides */
UNCOV
580
    mender_key_value_list_t *new_provides = NULL;
×
581
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
×
UNCOV
582
        mender_log_error("Unable to parse provides from the deployment data");
×
583
        return MENDER_FAIL;
×
584
    }
585
    /* Replace the stored provides with the new provides */
UNCOV
586
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
×
UNCOV
587
        mender_log_error("Unable to set provides");
×
588
        mender_utils_key_value_list_free(new_provides);
×
UNCOV
589
        return MENDER_FAIL;
×
590
    }
591
    mender_utils_key_value_list_free(new_provides);
×
592
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
593
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
594

595
    return MENDER_OK;
×
596
}
597

598
static mender_err_t
599
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
UNCOV
600
    if (NULL != deployment) {
×
601
        free(deployment->id);
×
UNCOV
602
        free(deployment->artifact_name);
×
UNCOV
603
        free(deployment->uri);
×
604
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
605
            free(deployment->device_types_compatible[i]);
×
606
        }
UNCOV
607
        free(deployment->device_types_compatible);
×
UNCOV
608
        free(deployment);
×
609
    }
610
    return MENDER_OK;
×
611
}
612

613
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
614
static mender_err_t
UNCOV
615
mender_compare_device_types(const char  *device_type_artifact,
×
616
                            const char  *device_type_device,
617
                            const char **device_type_deployment,
618
                            const size_t device_type_deployment_size) {
619

620
    assert(NULL != device_type_artifact);
×
UNCOV
621
    assert(NULL != device_type_deployment);
×
UNCOV
622
    assert(NULL != device_type_device);
×
UNCOV
623
    assert(0 < device_type_deployment_size);
×
624

625
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
626
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
627
        return MENDER_FAIL;
×
628
    }
629

630
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
631
    for (size_t i = 0; i < device_type_deployment_size; i++) {
×
632
        if (StringEqual(device_type_deployment[i], device_type_device)) {
×
633
            return MENDER_OK;
×
634
        }
635
    }
UNCOV
636
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
UNCOV
637
    return MENDER_FAIL;
×
638
}
639

640
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
641
static mender_err_t
UNCOV
642
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
643

644
    mender_err_t ret = MENDER_FAIL;
×
645
    /* Clears provides */
646
    bool matches;
647
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
648
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
×
649
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
×
UNCOV
650
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
×
651
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
652
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
UNCOV
653
                    goto END;
×
654
                }
UNCOV
655
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
UNCOV
656
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
UNCOV
657
                    goto END;
×
658
                }
659
            }
660
        }
661
    }
662

663
    /* Combine the stored provides with the new ones */
664
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
665
        mender_log_error("Unable to merge provides");
×
666
        goto END;
×
667
    }
668

669
    /* Make sure the artifact name is not in the new provides */
670
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
671
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
UNCOV
672
        goto END;
×
673
    }
674

675
    ret = MENDER_OK;
×
676

677
END:
×
678

UNCOV
679
    mender_utils_key_value_list_free(*stored_provides);
×
680
    return ret;
×
681
}
682

683
static mender_err_t
UNCOV
684
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
685

686
    assert(NULL != artifact_name);
×
UNCOV
687
    assert(NULL != mender_artifact_ctx);
×
688

689
    /* Load the currently stored provides */
UNCOV
690
    mender_key_value_list_t *stored_provides = NULL;
×
691
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
692
        mender_log_error("Unable to get provides");
×
693
        return MENDER_FAIL;
×
694
    }
695

696
    mender_key_value_list_t *provides = NULL;
×
697
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
UNCOV
698
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
699
            mender_log_error("Unable to merge provides");
×
700
            mender_utils_key_value_list_free(stored_provides);
×
701
            return MENDER_FAIL;
×
702
        }
703
    }
704

705
    /* Get artifact name from provides */
UNCOV
706
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
UNCOV
707
        if (StringEqual("artifact_name", item->key)) {
×
708
            *artifact_name = item->value;
×
709
            break;
×
710
        }
711
    }
712

UNCOV
713
    if (NULL == *artifact_name) {
×
714
        mender_log_error("No artifact name found in provides");
×
715
        mender_utils_key_value_list_free(stored_provides);
×
716
        return MENDER_FAIL;
×
717
    }
718

719
    /* Filter provides */
720
    /* `stored_provides` is freed in `mender_filter_provides` */
721
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
UNCOV
722
        return MENDER_FAIL;
×
723
    }
724

UNCOV
725
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
UNCOV
726
        return MENDER_FAIL;
×
727
    }
728

UNCOV
729
    return MENDER_OK;
×
730
}
731

732
static mender_err_t
UNCOV
733
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
734

735
    /* We need to load the stored provides */
736
    mender_key_value_list_t *stored_provides = NULL;
×
737
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
UNCOV
738
        return MENDER_FAIL;
×
739
    }
740

741
    mender_err_t ret = MENDER_FAIL;
×
742

743
    /* Get depends */
744
    mender_key_value_list_t *depends = NULL;
×
745
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
UNCOV
746
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
UNCOV
747
            mender_log_error("Unable to append depends");
×
UNCOV
748
            goto END;
×
749
        }
750
    }
751

752
    /* Match depends from artifact with device's provides */
753
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
×
UNCOV
754
        bool matches = false;
×
UNCOV
755
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
756
            /* Match key-value from depends with provides */
757
            if (StringEqual(depends_item->key, provides_item->key)) {
×
758
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
759
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
760
                                     depends_item->key,
761
                                     depends_item->value,
762
                                     provides_item->value);
UNCOV
763
                    break;
×
764
                }
765
                matches = true;
×
766
                break;
×
767
            }
768
        }
769
        if (!matches) {
×
770
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
UNCOV
771
            goto END;
×
772
        }
773
    }
774

UNCOV
775
    ret = MENDER_OK;
×
776

777
END:
×
UNCOV
778
    mender_utils_key_value_list_free(stored_provides);
×
UNCOV
779
    return ret;
×
780
}
781
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
782
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
783

784
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
785
static mender_err_t
UNCOV
786
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
787
    mender_err_t ret;
788

789
    /* Retrieve device type from artifact */
790
    const char *device_type_artifact = NULL;
×
791
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
792
        mender_log_error("Unable to get device type from artifact");
×
UNCOV
793
        return ret;
×
794
    }
795

796
    mender_log_debug("Checking device type compatibility");
797

798
    /* Match device type  */
799
    if (MENDER_OK
×
UNCOV
800
        != (ret = mender_compare_device_types(device_type_artifact,
×
801
                                              mender_client_config.device_type,
×
802
                                              (const char **)deployment->device_types_compatible,
×
803
                                              deployment->device_types_compatible_size))) {
UNCOV
804
        return ret;
×
805
    }
806

807
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
808
    /* Compare Artifact's depends with the stored provides */
809
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
810
        return ret;
×
811
    }
812
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
813

814
    /* Check artifact integrity by comparing computed checksums with those
815
     * listed in the artifacts manifest */
UNCOV
816
    if (MENDER_OK != mender_artifact_check_integrity(mender_artifact_ctx)) {
×
UNCOV
817
        return MENDER_FAIL;
×
818
    }
819

UNCOV
820
    return MENDER_OK;
×
821
}
822
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
823

824
static mender_err_t
UNCOV
825
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
UNCOV
826
    assert(NULL != deployment_data);
×
827

UNCOV
828
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
829
        /* network errors logged already */
830
        mender_log_error("Cannot check for new deployment");
×
UNCOV
831
        return MENDER_FAIL;
×
832
    }
833

834
    if (NULL == (*deployment_data = calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
835
        mender_log_error("Unable to allocate memory for deployment data");
×
836
        return MENDER_FAIL;
×
837
    }
838

UNCOV
839
    mender_api_deployment_data_t *deployment = *deployment_data;
×
840

UNCOV
841
    mender_err_t ret = MENDER_OK;
×
842

843
    mender_log_info("Checking for deployment...");
×
844
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
845
        mender_log_info("No deployment available");
×
846
        return MENDER_DONE;
×
UNCOV
847
    } else if (MENDER_OK != ret) {
×
848
        mender_log_error("Unable to check for deployment");
×
UNCOV
849
        return MENDER_FAIL;
×
850
    }
851

852
    /* Check if deployment is valid */
853
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
854
        mender_log_error("Invalid deployment data");
×
UNCOV
855
        return MENDER_FAIL;
×
856
    }
857

858
    /* Create deployment data */
UNCOV
859
    if (NULL != mender_client_deployment_data) {
×
860
        mender_log_warning("Unexpected stale deployment data");
×
861
        mender_delete_deployment_data(mender_client_deployment_data);
×
862
    }
UNCOV
863
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
864
        /* Error already logged */
UNCOV
865
        return MENDER_FAIL;
×
866
    }
867

UNCOV
868
    return MENDER_OK;
×
869
}
870

871
static mender_err_t
872
set_and_store_state(const mender_update_state_t state) {
×
873

874
    /*
875
     * Set the state in `mender_client_deployment_data` and write it to the nvs
876
     */
877

878
    mender_err_t ret = MENDER_OK;
×
879

880
    /* Set state in deployment data */
UNCOV
881
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
UNCOV
882
        mender_log_error("Failed to set deployment data state");
×
883
        return ret;
×
884
    }
885

886
    /* Store deployment data */
887
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
888
        mender_log_error("Failed to store deployment data");
×
889
        return ret;
×
890
    }
891
    return ret;
×
892
}
893

894
static mender_err_t
UNCOV
895
mender_client_update_work_function(void) {
×
UNCOV
896
    mender_err_t ret = MENDER_OK;
×
897

898
    /* Ensure that the context is initialized to NULL before goto END */
899
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
900

901
    /* Check for deployment */
UNCOV
902
    mender_api_deployment_data_t *deployment    = NULL;
×
903
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
904
    const char                   *deployment_id = NULL;
×
905

906
    /* reset the currently used update module */
907
    mender_update_module = NULL;
×
908

909
    if (NULL != mender_client_deployment_data) {
×
UNCOV
910
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
911
    }
912

913
    {
914
        const char           *artifact_type;
915
        mender_update_state_t update_state_resume;
916
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
×
UNCOV
917
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
×
UNCOV
918
            update_state = update_state_resume;
×
919
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
UNCOV
920
            mender_update_module = mender_update_module_get(artifact_type);
×
UNCOV
921
            if (NULL == mender_update_module) {
×
922
                /* The artifact_type from the saved state does not match any update module */
UNCOV
923
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
UNCOV
924
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
925
                mender_storage_delete_deployment_data();
×
926
                goto END;
×
927
            }
928
        }
929
    }
930

931
    /* Skip the block below if we just resume from a saved state. */
932

933
/* A macro to advance to the next state -- on success we just keep going to the
934
 * code below the macro invocation (fallthrough to the next case), on error we
935
 * go to the beginning of the loop (the switch statement) again using 'continue'
936
 * (see below).
937
 *
938
 * mender_update_module is guaranteed be not NULL since the first
939
 * successful transition (from the DOWNLOAD state). */
940
#define NEXT_STATE                                                             \
941
    if (MENDER_OK == ret) {                                                    \
942
        update_state = update_state_transitions[update_state].success;         \
943
        assert(NULL != mender_update_module);                                  \
944
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
945
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
946
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
947
        }                                                                      \
948
    } else {                                                                   \
949
        update_state = update_state_transitions[update_state].failure;         \
950
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
951
        if (NULL != mender_update_module) {                                    \
952
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
953
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
954
            }                                                                  \
955
        }                                                                      \
956
        ret = MENDER_OK;                                                       \
957
        continue;                                                              \
958
    }
959

960
    while (MENDER_UPDATE_STATE_END != update_state) {
×
961
        switch (update_state) {
×
962
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
963

964
                /* Check for deployment */
965
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
966
                    /* No deployment available, but we are not done, we need to keep checking. */
967
                    if (MENDER_DONE == ret) {
×
968
                        ret = MENDER_OK;
×
969
                    }
970
                    goto END;
×
971
                }
972

973
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
UNCOV
974
                if (strlen(deployment->id) > 10) {
×
UNCOV
975
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
976
                } else {
UNCOV
977
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
978
                }
979
#endif
UNCOV
980
                mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
981

982
                /* Set deployment_id */
UNCOV
983
                deployment_id = deployment->id;
×
984

UNCOV
985
                if (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module))) {
×
UNCOV
986
                    assert(NULL != mender_update_module);
×
987

988
                    /* Get artifact context if artifact download succeeded */
UNCOV
989
                    if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) {
×
990
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
UNCOV
991
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
×
992
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
993
                            /* Add the new provides to the deployment data (we need the artifact context) */
UNCOV
994
                            char       *new_provides  = NULL;
×
UNCOV
995
                            const char *artifact_name = NULL;
×
UNCOV
996
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
×
UNCOV
997
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
×
UNCOV
998
                                    mender_log_error("Failed to set deployment data provides");
×
999
                                }
1000
                                /* Replace artifact_name with the one from provides */
UNCOV
1001
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
×
UNCOV
1002
                                    mender_log_error("Failed to set deployment data artifact name");
×
1003
                                }
1004
                                free(new_provides);
×
1005
                            } else {
1006
                                mender_log_error("Unable to prepare new provides");
×
1007
                            }
1008
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
1009
                        }
1010
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1011
                    } else {
1012
                        mender_log_error("Unable to get artifact type and context");
×
1013
                    }
1014
                } else {
UNCOV
1015
                    mender_log_error("Unable to download artifact");
×
UNCOV
1016
                    if (NULL == mender_update_module) {
×
1017
                        /* Error logged in mender_client_download_artifact_callback() */
1018
                        mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1019
                        goto END;
×
1020
                    }
1021
                }
UNCOV
1022
                NEXT_STATE;
×
1023
                /* fallthrough */
1024

1025
            case MENDER_UPDATE_STATE_INSTALL:
UNCOV
1026
                mender_log_info("Download done, installing artifact");
×
1027
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
×
UNCOV
1028
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1029
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1030
                }
UNCOV
1031
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
×
1032
                    /* skip reboot */
1033
                    update_state = MENDER_UPDATE_STATE_COMMIT;
×
UNCOV
1034
                    set_and_store_state(update_state);
×
1035
                    continue;
×
1036
                }
1037
                /* else continue to the next successful/failure state */
1038
                NEXT_STATE;
×
1039
                /* fallthrough */
1040

1041
            case MENDER_UPDATE_STATE_REBOOT:
1042
                assert(mender_update_module->requires_reboot);
×
UNCOV
1043
                mender_log_info("Artifact installation done, rebooting");
×
UNCOV
1044
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
×
1045
                if ((MENDER_OK == ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1046
                    /* Save the next state before running the reboot callback --
1047
                     * if there is an interrupt (power, crash,...) right after,
1048
                     * it will reboot anyway so after the new boot, reboot
1049
                     * verification should happen anyway, the callback in that
1050
                     * state should be able to see if things went well or
1051
                     * wrong. */
UNCOV
1052
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
×
UNCOV
1053
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
UNCOV
1054
                    if (MENDER_OK == ret) {
×
1055
                        /* now we need to get outside of the loop so that a
1056
                         * potential asynchronous reboot has a chance to kick in
1057
                         * after a proper cleanup below */
UNCOV
1058
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1059
                        ret                 = MENDER_DONE;
×
1060
                        goto END;
×
1061
                    }
1062
                }
1063
                NEXT_STATE;
×
1064
                /* fallthrough */
1065

1066
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
UNCOV
1067
                assert(mender_update_module->requires_reboot);
×
UNCOV
1068
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1069
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1070
                }
1071
                NEXT_STATE;
×
1072
                /* fallthrough */
1073

1074
            case MENDER_UPDATE_STATE_COMMIT:
1075
                /* Check for pending deployment */
UNCOV
1076
                if (NULL == mender_client_deployment_data) {
×
1077
                    mender_log_error("No deployment data found on commit");
×
1078
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1079
                    goto END;
×
1080
                }
1081
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1082
                if (MENDER_OK != mender_api_drop_authentication_data()) {
×
UNCOV
1083
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1084
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1085
                       much to about it. */
1086
                }
1087
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
×
1088
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1089
                }
1090
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
UNCOV
1091
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
×
UNCOV
1092
                    mender_log_error("Unable to commit artifact data");
×
1093
                }
UNCOV
1094
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
UNCOV
1095
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1096
                }
1097
                if (!MENDER_IS_ERROR(ret)) {
×
1098
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
×
1099
                }
UNCOV
1100
                NEXT_STATE;
×
1101
                /* fallthrough */
1102

1103
            case MENDER_UPDATE_STATE_CLEANUP:
1104
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1105
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1106
                }
1107
                NEXT_STATE;
×
UNCOV
1108
                mender_storage_delete_deployment_data();
×
UNCOV
1109
                break; /* below is the failure path */
×
1110

1111
            case MENDER_UPDATE_STATE_ROLLBACK:
×
1112
                if (!mender_update_module->supports_rollback) {
×
1113
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
×
UNCOV
1114
                    ret = MENDER_FAIL;
×
1115
                } else if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1116
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1117
                }
UNCOV
1118
                NEXT_STATE;
×
1119
                /* fallthrough */
1120

1121
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1122
                /* Save the next state before running the reboot callback (see
1123
                 * STATE_REBOOT for details). */
UNCOV
1124
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
UNCOV
1125
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1126

1127
                if (MENDER_OK == ret) {
×
1128
                    /* now we need to get outside of the loop so that a
1129
                     * potential asynchronous reboot has a chance to kick in
1130
                     * after a proper cleanup below */
1131
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1132
                    ret                 = MENDER_DONE;
×
UNCOV
1133
                    goto END;
×
1134
                }
1135
                NEXT_STATE;
×
1136
                /* fallthrough */
1137

1138
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1139
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1140
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1141
                }
1142

UNCOV
1143
                if (MENDER_OK != ret) {
×
1144
                    /* If the rollback verify reboot fails,
1145
                     * we will retry the rollback reboot.
1146
                     *
1147
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1148
                     * loop is broken when a state loop is detected
1149
                     */
UNCOV
1150
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
×
1151
                }
1152

1153
                NEXT_STATE;
×
1154
                /* fallthrough */
1155

1156
            case MENDER_UPDATE_STATE_FAILURE:
1157
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1158
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1159
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1160
                }
UNCOV
1161
                NEXT_STATE;
×
1162
                break; /* end of the failure path */
×
1163

UNCOV
1164
            case MENDER_UPDATE_STATE_END:
×
1165
                /* This is only here to cover all possible values of the
1166
                 * update_state enum, there is nothing to do here, the while
1167
                 * loop shall stop when we get here. */
1168
                break;
×
1169
        }
1170
    }
1171
#undef NEXT_STATE /* should not be used anywhere else */
1172

UNCOV
1173
    ret = MENDER_OK;
×
1174

1175
END:
×
1176
    /* Release memory */
1177
    deployment_destroy(deployment);
×
UNCOV
1178
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
1179
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1180

UNCOV
1181
    return ret;
×
1182
}
1183

1184
static mender_err_t
UNCOV
1185
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
UNCOV
1186
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1187
        /* connection errors logged already */
UNCOV
1188
        mender_log_error("Cannot publish deployment status");
×
UNCOV
1189
        return MENDER_FAIL;
×
1190
    }
1191

1192
    mender_err_t ret;
1193

1194
    if (NULL == id) {
×
UNCOV
1195
        mender_log_error("Cannot publish deployment status: unknown status");
×
UNCOV
1196
        return MENDER_FAIL;
×
1197
    }
1198

1199
    /* Publish status to the mender server */
UNCOV
1200
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1201

1202
    /* Invoke deployment status callback if defined */
1203
    if (NULL != mender_client_callbacks.deployment_status) {
×
UNCOV
1204
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1205
    }
1206

UNCOV
1207
    return ret;
×
1208
}
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