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

mendersoftware / mender-mcu / 1746237572

01 Apr 2025 09:23AM UTC coverage: 56.718% (+56.7%) from 0.0%
1746237572

push

gitlab-ci

web-flow
Merge pull request #186 from lluiscampos/MEN-7548-inventory-not-optional

MEN-7548: Make inventory "feature" hard to disable

2115 of 3729 relevant lines covered (56.72%)

66.96 hits per line

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

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

35
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
36
#include "inventory.h"
37
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
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
static const char *client_state_str[N_MENDER_CLIENT_STATES + 1] = {
116
    "MENDER_CLIENT_STATE_INITIALIZATION",
117
    "MENDER_CLIENT_STATE_OPERATIONAL",
118
    "MENDER_CLIENT_STATE_PENDING_REBOOT",
119
};
120

121
#endif
122

123
/**
124
 * @brief Flag to know if network connection was requested or not
125
 */
126
static bool mender_client_network_connected = false;
127

128
/**
129
 * @brief Deployment data. Used to track progress of an update, so that the
130
 *        operation can resume or roll back across reboots
131
 */
132
static mender_deployment_data_t *mender_client_deployment_data = NULL;
133

134
/**
135
 * @brief Update module being used by the current deployment
136
 */
137
static mender_update_module_t *mender_update_module = NULL;
138

139
/**
140
 * @brief The main Mender work item
141
 */
142
static mender_work_t *mender_client_work = NULL;
143

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

150
/**
151
 * @brief Mender client initialization work function
152
 * @return MENDER_OK if the function succeeds, error code otherwise
153
 */
154
static mender_err_t mender_client_initialization_work_function(void);
155

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

162
/**
163
 * @brief Function to release network access
164
 * @return MENDER_OK if network is released following the request, error code otherwise
165
 */
166
static mender_err_t mender_client_network_release(void);
167

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

200
/**
201
 * @brief Determine the compatiblity of the deployment by: comparing artifact's depend with the stored provides
202
 * @param mender_artifact_ctx Mender artifact context
203
 * @return MENDER_OK if the function succeeds, error code otherwise
204
 */
205
static mender_err_t mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx);
206
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
207
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
208

209
/**
210
 * @brief Mender client update work function
211
 * @return MENDER_OK if the function succeeds, error code otherwise
212
 */
213
static mender_err_t mender_client_update_work_function(void);
214

215
/**
216
 * @brief Publish deployment status of the device to the mender-server and invoke deployment status callback
217
 * @param id ID of the deployment
218
 * @param deployment_status Deployment status
219
 * @return MENDER_OK if the function succeeds, error code otherwise
220
 */
221
static mender_err_t mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status);
222

223
/**
224
 * @brief Set state in deployment data and store it in permanent storage
225
 * @param state State to set and store
226
 * @return MENDER_OK in case of success, error code otherwise
227
 */
228
static mender_err_t set_and_store_state(const mender_update_state_t state);
229

230
const char *
231
mender_client_version(void) {
×
232

233
    /* Return version as string */
234
    return MENDER_CLIENT_VERSION;
×
235
}
236

237
mender_err_t
238
mender_client_init(mender_client_config_t *config, mender_client_callbacks_t *callbacks) {
29✔
239
    assert(NULL != config);
29✔
240
    assert(NULL != callbacks);
29✔
241
    assert(NULL != callbacks->restart);
29✔
242

243
    /* Either all allocation functions set or none. */
244
    assert(
29✔
245
        ((NULL == config->allocation_funcs.malloc_func) && (NULL == config->allocation_funcs.realloc_func) && (NULL == config->allocation_funcs.free_func))
246
        || ((NULL != config->allocation_funcs.malloc_func) && (NULL != config->allocation_funcs.realloc_func) && (NULL != config->allocation_funcs.free_func)));
247

248
    mender_err_t ret;
249

250
    if (NULL != config->allocation_funcs.malloc_func) {
29✔
251
        mender_set_allocation_funcs(config->allocation_funcs.malloc_func, config->allocation_funcs.realloc_func, config->allocation_funcs.free_func);
×
252
    } else {
253
        mender_set_platform_allocation_funcs();
29✔
254
    }
255

256
    {
257
        cJSON_Hooks cjson_alloc_funcs = { mender_malloc, mender_free };
29✔
258
        cJSON_InitHooks(&cjson_alloc_funcs);
29✔
259
    }
260

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

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

300
    /* Save callbacks */
301
    memcpy(&mender_client_callbacks, callbacks, sizeof(mender_client_callbacks_t));
29✔
302

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

332
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
333
    if (MENDER_OK != (ret = mender_inventory_init(mender_client_config.inventory_update_interval, mender_client_config.device_type))) {
29✔
334
        mender_log_error("Failed to initialize the inventory functionality");
×
335
        goto END;
×
336
    }
337
    if (MENDER_OK != mender_inventory_add_default_callbacks()) {
29✔
338
        mender_log_error("Failed to enable default inventory");
×
339
        /* unlikely to happen and not a fatal issue, keep going */
340
    }
341
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
342

343
END:
29✔
344

345
    return ret;
29✔
346
}
347

348
mender_err_t
349
mender_client_activate(void) {
29✔
350
    mender_err_t ret;
351

352
    mender_os_scheduler_work_params_t work_params = {
29✔
353
        .function = mender_client_work_function,
354
        .period   = mender_client_config.update_poll_interval,
29✔
355
        .name     = "mender_client_main",
356
    };
357

358
    if ((MENDER_OK != (ret = mender_os_scheduler_work_create(&work_params, &mender_client_work)))
29✔
359
        || (MENDER_OK != (ret = mender_os_scheduler_work_activate(mender_client_work)))) {
29✔
360
        mender_log_error("Unable to activate the main work");
×
361
        return ret;
×
362
    }
363

364
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
365
    /* Activate inventory work */
366
    if (MENDER_OK != (ret = mender_inventory_activate())) {
29✔
367
        mender_log_error("Unable to activate the inventory functionality");
×
368
        return ret;
×
369
    }
370
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
371

372
    return ret;
29✔
373
}
374

375
mender_err_t
376
mender_client_ensure_connected(void) {
110✔
377
    if (mender_client_network_connected) {
110✔
378
        return MENDER_DONE;
82✔
379
    }
380

381
    return mender_client_network_connect();
28✔
382
}
383

384
static mender_err_t
385
mender_client_network_connect(void) {
28✔
386
    if (mender_client_network_connected) {
28✔
387
        return MENDER_OK;
×
388
    }
389

390
    /* Request network access */
391
    if (NULL != mender_client_callbacks.network_connect) {
28✔
392
        if (MENDER_OK != mender_client_callbacks.network_connect()) {
28✔
393
            mender_log_error("Unable to connect network");
×
394
            return MENDER_FAIL;
×
395
        }
396
    }
397

398
    mender_client_network_connected = true;
28✔
399

400
    return MENDER_OK;
28✔
401
}
402

403
static mender_err_t
404
mender_client_network_release(void) {
×
405
    if (!mender_client_network_connected) {
×
406
        return MENDER_OK;
×
407
    }
408

409
    /* Release network access */
410
    if (NULL != mender_client_callbacks.network_release) {
×
411
        if (MENDER_OK != mender_client_callbacks.network_release()) {
×
412
            mender_log_error("Unable to release network");
×
413
            return MENDER_FAIL;
×
414
        }
415
    }
416
    mender_client_network_connected = false;
×
417

418
    return MENDER_OK;
×
419
}
420

421
mender_err_t
422
mender_client_deactivate(void) {
×
423
    mender_err_t ret;
424

425
    if (NULL != mender_client_work) {
×
426
        if (MENDER_OK != (ret = mender_os_scheduler_work_deactivate(mender_client_work))) {
×
427
            mender_log_error("Failed to deactivate main work");
×
428
            return ret;
×
429
        }
430
    }
431
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
432
    if (MENDER_OK != (ret = mender_inventory_deactivate())) {
×
433
        /* error already logged */
434
        return ret;
×
435
    }
436
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
437

438
    return MENDER_OK;
×
439
}
440

441
mender_err_t
442
mender_client_exit(void) {
×
443
    bool some_error = false;
×
444

445
    if (MENDER_OK != mender_client_deactivate()) {
×
446
        /* error already logged; keep going on, we want to do as much cleanup as possible */
447
        some_error = true;
×
448
    }
449

450
    if (NULL != mender_client_work) {
×
451
        if (MENDER_OK != mender_os_scheduler_work_delete(mender_client_work)) {
×
452
            mender_log_error("Failed to delete main work");
×
453
            /* keep going on, we want to do as much cleanup as possible */
454
            some_error = true;
×
455
        } else {
456
            mender_client_work = NULL;
×
457
        }
458
    }
459

460
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
461
    if (MENDER_OK != mender_inventory_exit()) {
×
462
        mender_log_error("Unable to cleanup after the inventory functionality");
×
463
        /* keep going on, we want to do as much cleanup as possible */
464
        some_error = true;
×
465
    }
466
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
467

468
    /* Stop scheduling new work */
469
    mender_os_scheduler_exit();
×
470

471
    /* Release all modules */
472
    mender_api_exit();
×
473
    mender_tls_exit();
×
474
    mender_storage_exit();
×
475
    mender_log_exit();
×
476
    mender_client_network_release();
×
477

478
    /* Release memory */
479
    mender_client_config.device_type          = NULL;
×
480
    mender_client_config.host                 = NULL;
×
481
    mender_client_config.tenant_token         = NULL;
×
482
    mender_client_config.update_poll_interval = 0;
×
483
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
484

485
    mender_update_module_unregister_all();
×
486

487
    return some_error ? MENDER_FAIL : MENDER_OK;
×
488
}
489

490
static mender_err_t
491
mender_client_work_function(void) {
69✔
492
    mender_err_t ret;
493
    mender_log_debug("Inside work function [state: %s]", client_state_str[mender_client_state]);
69✔
494

495
    switch (mender_client_state) {
69✔
496
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
14✔
497
            mender_log_info("Waiting for a reboot");
14✔
498
            if (MENDER_OK != mender_err_count_reboot_inc()) {
14✔
499
                /* It appears we are stuck in this state. The only thing we can do is to mark the
500
                   deployment as failed and revert to normal operation. */
501
                mender_log_error("Waiting for reboot for too long, trying unconditional reboot");
×
502
                mender_os_reboot();
×
503

504
                mender_log_error("Failed to reboot unconditionally, trying to resume operations");
×
505
                if (NULL == mender_client_deployment_data) {
×
506
                    mender_log_error("No deployment data to use for deployment abortion");
×
507
                } else {
508
                    mender_update_state_t update_state;
509
                    if (MENDER_OK != mender_deployment_data_get_state(mender_client_deployment_data, &update_state)) {
×
510
                        mender_log_error("Failed to get current update state, going to ROLLBACK state");
×
511
                        update_state = MENDER_UPDATE_STATE_ROLLBACK;
×
512
                    } else {
513
                        update_state = update_state_transitions[update_state].failure;
×
514
                    }
515
                    if (MENDER_OK != set_and_store_state(update_state)) {
×
516
                        mender_log_error("Failed to save new state");
×
517
                    }
518
                }
519

520
                mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
521
            }
522
            /* else:
523
               Nothing to do, but let's make sure we have a chance to detect we are stuck in this
524
               state (i.e. MENDER_OK, not MENDER_DONE which would tell the scheduler we are
525
               done and don't need to run again). */
526
            return MENDER_OK;
14✔
527
        case MENDER_CLIENT_STATE_INITIALIZATION:
29✔
528
            /* Perform initialization of the client */
529
            mender_err_count_reboot_reset();
29✔
530
            if (MENDER_DONE != mender_client_initialization_work_function()) {
29✔
531
                return MENDER_FAIL;
×
532
            }
533
            mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
29✔
534
            /* fallthrough */
535
        case MENDER_CLIENT_STATE_OPERATIONAL:
55✔
536
            mender_err_count_reboot_reset();
55✔
537
            ret = mender_client_update_work_function();
55✔
538
            if (MENDER_FAIL == ret) {
40✔
539
                if (MENDER_FAIL == mender_err_count_net_check()) {
×
540
                    /* Try to release network so that it gets set up again next
541
                       time. */
542
                    mender_client_network_release();
×
543
                }
544
            } else if (!MENDER_IS_ERROR(ret)) {
40✔
545
                mender_err_count_net_reset();
40✔
546
            }
547
            if (MENDER_DONE == ret) {
40✔
548
                /* We should only be done when waiting for a reboot. */
549
                assert(MENDER_CLIENT_STATE_PENDING_REBOOT == mender_client_state);
14✔
550

551
                /* We don't want to tell the scheduler we are done because
552
                   otherwise we won't have a chance to detect that we are
553
                   waiting for a reboot forever. */
554
                ret = MENDER_OK;
14✔
555
            }
556
            return ret;
40✔
557
    }
558

559
    /* This should never be reached, all the cases should be covered in the
560
       above switch and they all return. */
561
    return MENDER_FAIL;
×
562
}
563

564
/* Flag to indicate whether a deployment has had a spontaneous reboot */
565
static bool spontaneous_reboot;
566

567
static mender_err_t
568
mender_client_initialization_work_function(void) {
29✔
569

570
    mender_err_t ret   = MENDER_DONE;
29✔
571
    spontaneous_reboot = false;
29✔
572

573
    /* Retrieve or generate authentication keys */
574
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
29✔
575
        mender_log_error("Unable to retrieve or generate authentication keys");
×
576
        goto END;
×
577
    }
578

579
    /* Retrieve deployment data if it is found (following an update) */
580
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
29✔
581
        if (MENDER_NOT_FOUND != ret) {
13✔
582
            mender_log_error("Unable to get deployment data");
×
583
            goto REBOOT;
×
584
        }
585
    }
586

587
    /* Handle spontaneous reboots in  MENDER_UPDATE_STATE_INSTALL and MENDER_UPDATE_STATE_COMMIT
588
     See https://docs.mender.io/artifact-creation/state-scripts#power-loss */
589
    mender_update_state_t update_state;
590
    if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state))) {
29✔
591
        if ((MENDER_UPDATE_STATE_INSTALL == update_state) || (MENDER_UPDATE_STATE_COMMIT == update_state)) {
16✔
592
            mender_log_debug("Spontaneous reboot detected in state %s", update_state_str[update_state]);
2✔
593
            spontaneous_reboot = true;
2✔
594
        }
595
    }
596

597
    mender_log_info("Initialization done");
29✔
598

599
    return MENDER_DONE;
29✔
600

601
END:
×
602

603
    return ret;
×
604

605
REBOOT:
×
606

607
    mender_log_info("Rebooting...");
×
608

609
    /* Delete pending deployment */
610
    mender_storage_delete_deployment_data();
×
611

612
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
613
    /* Set the client's state to PENDING_REBOOT so that we can potentially
614
       detect a failure to reboot (i.e. waiting for reboot taking too long).  */
615
    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
616
    if (NULL != mender_client_callbacks.restart) {
×
617
        mender_client_callbacks.restart();
×
618
    }
619

620
    return ret;
×
621
}
622

623
static mender_err_t
624
mender_commit_artifact_data(void) {
5✔
625

626
    assert(NULL != mender_client_deployment_data);
5✔
627

628
    const char *artifact_name;
629
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
5✔
630
        mender_log_error("Unable to get artifact name from the deployment data");
×
631
        return MENDER_FAIL;
×
632
    }
633

634
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
5✔
635
        mender_log_error("Unable to set artifact name");
×
636
        return MENDER_FAIL;
×
637
    }
638

639
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
640
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
641
    /* Get provides from the deployment data */
642
    const char *provides;
643
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
5✔
644
        mender_log_error("Unable to get new_provides from the deployment data");
×
645
        return MENDER_FAIL;
×
646
    }
647

648
    /* Parse provides */
649
    mender_key_value_list_t *new_provides = NULL;
5✔
650
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
5✔
651
        mender_log_error("Unable to parse provides from the deployment data");
×
652
        return MENDER_FAIL;
×
653
    }
654
    /* Replace the stored provides with the new provides */
655
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
5✔
656
        mender_log_error("Unable to set provides");
×
657
        mender_utils_key_value_list_free(new_provides);
×
658
        return MENDER_FAIL;
×
659
    }
660
    mender_utils_key_value_list_free(new_provides);
5✔
661
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
662
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
663

664
    return MENDER_OK;
5✔
665
}
666

667
static mender_err_t
668
deployment_destroy(mender_api_deployment_data_t *deployment) {
40✔
669
    if (NULL != deployment) {
40✔
670
        mender_free(deployment->id);
25✔
671
        mender_free(deployment->artifact_name);
25✔
672
        mender_free(deployment->uri);
25✔
673
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
35✔
674
            mender_free(deployment->device_types_compatible[i]);
10✔
675
        }
676
        mender_free(deployment->device_types_compatible);
25✔
677
        mender_free(deployment);
25✔
678
    }
679
    return MENDER_OK;
40✔
680
}
681

682
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
683
static mender_err_t
684
mender_compare_device_types(const char  *device_type_artifact,
11✔
685
                            const char  *device_type_device,
686
                            const char **device_type_deployment,
687
                            const size_t device_type_deployment_size) {
688

689
    assert(NULL != device_type_artifact);
11✔
690
    assert(NULL != device_type_deployment);
11✔
691
    assert(NULL != device_type_device);
11✔
692
    assert(0 < device_type_deployment_size);
11✔
693

694
    if (!StringEqual(device_type_artifact, device_type_device)) {
11✔
695
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
696
        return MENDER_FAIL;
×
697
    }
698

699
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
700
    for (size_t i = 0; i < device_type_deployment_size; i++) {
11✔
701
        if (StringEqual(device_type_deployment[i], device_type_device)) {
11✔
702
            return MENDER_OK;
11✔
703
        }
704
    }
705
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
706
    return MENDER_FAIL;
×
707
}
708

709
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
710
static mender_err_t
711
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
11✔
712

713
    mender_err_t ret = MENDER_FAIL;
11✔
714
    /* Clears provides */
715
    bool matches;
716
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
22✔
717
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
22✔
718
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
11✔
719
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
11✔
720
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
721
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
722
                    goto END;
×
723
                }
724
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
725
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
726
                    goto END;
×
727
                }
728
            }
729
        }
730
    }
731

732
    /* Combine the stored provides with the new ones */
733
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
11✔
734
        mender_log_error("Unable to merge provides");
×
735
        goto END;
×
736
    }
737

738
    /* Make sure the artifact name is not in the new provides */
739
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
11✔
740
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
741
        goto END;
×
742
    }
743

744
    ret = MENDER_OK;
11✔
745

746
END:
11✔
747

748
    mender_utils_key_value_list_free(*stored_provides);
11✔
749
    return ret;
11✔
750
}
751

752
static mender_err_t
753
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
11✔
754

755
    assert(NULL != artifact_name);
11✔
756
    assert(NULL != mender_artifact_ctx);
11✔
757

758
    /* Load the currently stored provides */
759
    mender_key_value_list_t *stored_provides = NULL;
11✔
760
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
11✔
761
        mender_log_error("Unable to get provides");
×
762
        return MENDER_FAIL;
×
763
    }
764

765
    mender_key_value_list_t *provides = NULL;
11✔
766
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
22✔
767
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
11✔
768
            mender_log_error("Unable to merge provides");
×
769
            mender_utils_key_value_list_free(stored_provides);
×
770
            return MENDER_FAIL;
×
771
        }
772
    }
773

774
    /* Get artifact name from provides */
775
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
11✔
776
        if (StringEqual("artifact_name", item->key)) {
11✔
777
            *artifact_name = item->value;
11✔
778
            break;
11✔
779
        }
780
    }
781

782
    if (NULL == *artifact_name) {
11✔
783
        mender_log_error("No artifact name found in provides");
×
784
        mender_utils_key_value_list_free(stored_provides);
×
785
        return MENDER_FAIL;
×
786
    }
787

788
    /* Filter provides */
789
    /* `stored_provides` is freed in `mender_filter_provides` */
790
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
11✔
791
        return MENDER_FAIL;
×
792
    }
793

794
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
11✔
795
        mender_utils_key_value_list_free(provides);
×
796
        return MENDER_FAIL;
×
797
    }
798

799
    mender_utils_key_value_list_free(provides);
11✔
800
    return MENDER_OK;
11✔
801
}
802

803
static mender_err_t
804
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
11✔
805

806
    /* We need to load the stored provides */
807
    mender_key_value_list_t *stored_provides = NULL;
11✔
808
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
11✔
809
        return MENDER_FAIL;
×
810
    }
811

812
    mender_err_t ret = MENDER_FAIL;
11✔
813

814
    /* Get depends */
815
    mender_key_value_list_t *depends = NULL;
11✔
816
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
22✔
817
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
11✔
818
            mender_log_error("Unable to append depends");
×
819
            goto END;
×
820
        }
821
    }
822

823
    /* Match depends from artifact with device's provides */
824
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
11✔
825
        bool matches = false;
×
826
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
827
            /* Match key-value from depends with provides */
828
            if (StringEqual(depends_item->key, provides_item->key)) {
×
829
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
830
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
831
                                     depends_item->key,
832
                                     depends_item->value,
833
                                     provides_item->value);
834
                    break;
×
835
                }
836
                matches = true;
×
837
                break;
×
838
            }
839
        }
840
        if (!matches) {
×
841
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
842
            goto END;
×
843
        }
844
    }
845

846
    ret = MENDER_OK;
11✔
847

848
END:
11✔
849
    mender_utils_key_value_list_free(stored_provides);
11✔
850
    return ret;
11✔
851
}
852
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
853
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
854

855
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
856
static mender_err_t
857
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
11✔
858
    mender_err_t ret;
859

860
    /* Retrieve device type from artifact */
861
    const char *device_type_artifact = NULL;
11✔
862
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
11✔
863
        mender_log_error("Unable to get device type from artifact");
×
864
        return ret;
×
865
    }
866

867
    mender_log_debug("Checking device type compatibility");
11✔
868

869
    /* Match device type  */
870
    if (MENDER_OK
11✔
871
        != (ret = mender_compare_device_types(device_type_artifact,
11✔
872
                                              mender_client_config.device_type,
11✔
873
                                              (const char **)deployment->device_types_compatible,
11✔
874
                                              deployment->device_types_compatible_size))) {
875
        return ret;
×
876
    }
877

878
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
879
    /* Compare Artifact's depends with the stored provides */
880
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
11✔
881
        return ret;
×
882
    }
883
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
884

885
    /* Check payload integrity by comparing computed checksum(s) with those
886
     * listed in the artifact manifest */
887
    if (MENDER_OK != mender_artifact_check_integrity_remaining(mender_artifact_ctx)) {
11✔
888
        return MENDER_FAIL;
×
889
    }
890

891
    return MENDER_OK;
11✔
892
}
893
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
894

895
static mender_err_t
896
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
39✔
897
    assert(NULL != deployment_data);
39✔
898

899
    if (MENDER_FAIL == mender_client_ensure_connected()) {
39✔
900
        /* network errors logged already */
901
        mender_log_error("Cannot check for new deployment");
×
902
        return MENDER_FAIL;
×
903
    }
904

905
    if (NULL == (*deployment_data = mender_calloc(1, sizeof(mender_api_deployment_data_t)))) {
39✔
906
        mender_log_error("Unable to allocate memory for deployment data");
×
907
        return MENDER_FAIL;
×
908
    }
909

910
    mender_api_deployment_data_t *deployment = *deployment_data;
39✔
911

912
    mender_err_t ret = MENDER_OK;
39✔
913

914
    mender_log_info("Checking for deployment...");
39✔
915
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
39✔
916
        mender_log_info("No deployment available");
15✔
917
        return MENDER_DONE;
15✔
918
    } else if (MENDER_OK != ret) {
12✔
919
        mender_log_error("Unable to check for deployment");
×
920
        return MENDER_FAIL;
×
921
    }
922

923
    /* Check if deployment is valid */
924
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
12✔
925
        mender_log_error("Invalid deployment data");
×
926
        return MENDER_FAIL;
×
927
    }
928

929
    /* Create deployment data */
930
    if (NULL != mender_client_deployment_data) {
12✔
931
        mender_log_warning("Unexpected stale deployment data");
×
932
        mender_delete_deployment_data(mender_client_deployment_data);
×
933
    }
934
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
12✔
935
        /* Error already logged */
936
        return MENDER_FAIL;
×
937
    }
938

939
    return MENDER_OK;
12✔
940
}
941

942
static mender_err_t
943
set_and_store_state(const mender_update_state_t state) {
78✔
944

945
    /*
946
     * Set the state in `mender_client_deployment_data` and write it to the nvs
947
     */
948

949
    mender_err_t ret = MENDER_OK;
78✔
950

951
    /* Set state in deployment data */
952
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
78✔
953
        mender_log_error("Failed to set deployment data state");
×
954
        return ret;
×
955
    }
956

957
    /* Store deployment data */
958
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
78✔
959
        mender_log_error("Failed to store deployment data");
1✔
960
        return ret;
1✔
961
    }
962
    return ret;
77✔
963
}
964

965
static mender_err_t
966
mender_client_update_work_function(void) {
55✔
967
    mender_err_t ret = MENDER_OK;
55✔
968

969
    /* Ensure that the context is initialized to NULL before goto END */
970
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
55✔
971

972
    /* Check for deployment */
973
    mender_api_deployment_data_t *deployment    = NULL;
55✔
974
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
55✔
975
    const char                   *deployment_id = NULL;
55✔
976

977
    /* reset the currently used update module */
978
    mender_update_module = NULL;
55✔
979

980
    if (NULL != mender_client_deployment_data) {
55✔
981
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
16✔
982
    }
983

984
    {
985
        const char           *artifact_type;
986
        mender_update_state_t update_state_resume;
987
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
55✔
988
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
16✔
989
            update_state = update_state_resume;
16✔
990
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
16✔
991
            mender_update_module = mender_update_module_get(artifact_type);
16✔
992
            if (NULL == mender_update_module) {
16✔
993
                /* The artifact_type from the saved state does not match any update module */
994
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
995
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
996
                mender_storage_delete_deployment_data();
×
997
                goto END;
×
998
            }
999
        }
1000
    }
1001

1002
    /* Skip the block below if we just resume from a saved state. */
1003

1004
/* A macro to advance to the next state -- on success we just keep going to the
1005
 * code below the macro invocation (fallthrough to the next case), on error we
1006
 * go to the beginning of the loop (the switch statement) again using 'continue'
1007
 * (see below).
1008
 *
1009
 * mender_update_module is guaranteed be not NULL since the first
1010
 * successful transition (from the DOWNLOAD state). */
1011
#define NEXT_STATE                                                             \
1012
    if (MENDER_OK == ret) {                                                    \
1013
        update_state = update_state_transitions[update_state].success;         \
1014
        assert(NULL != mender_update_module);                                  \
1015
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
1016
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
1017
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
1018
        }                                                                      \
1019
    } else {                                                                   \
1020
        update_state = update_state_transitions[update_state].failure;         \
1021
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
1022
        if (NULL != mender_update_module) {                                    \
1023
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
1024
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
1025
            }                                                                  \
1026
        }                                                                      \
1027
        ret = MENDER_OK;                                                       \
1028
        continue;                                                              \
1029
    }
1030

1031
    if (spontaneous_reboot) {
55✔
1032
        mender_log_error("Failing deployment, spontaneous reboot detected");
2✔
1033
        spontaneous_reboot = false;
2✔
1034
        update_state       = update_state_transitions[update_state].failure;
2✔
1035
        mender_log_debug("Entering state %s", update_state_str[update_state]);
2✔
1036
    }
1037
    while (MENDER_UPDATE_STATE_END != update_state) {
144✔
1038
        switch (update_state) {
78✔
1039
            case MENDER_UPDATE_STATE_DOWNLOAD:
39✔
1040
                /* This is usually logged in the NEXT_STATE macro, but since nothing
1041
                 * transitions to this state, we log it here */
1042
                mender_log_debug("Entering state %s", update_state_str[update_state]);
39✔
1043

1044
                /* Check for deployment */
1045
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
39✔
1046
                    /* No deployment available, but we are not done, we need to keep checking. */
1047
                    if (MENDER_DONE == ret) {
15✔
1048
                        ret = MENDER_OK;
15✔
1049
                    }
1050
                    goto END;
15✔
1051
                }
1052

1053
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
1054
                if (strlen(deployment->id) > 10) {
12✔
1055
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
12✔
1056
                } else {
1057
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
1058
                }
1059
#endif
1060
                /* Set deployment_id */
1061
                deployment_id = deployment->id;
12✔
1062

1063
                /* Check ret to see if the deployment is aborted */
1064
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
12✔
1065
                if ((MENDER_ABORTED != ret)
12✔
1066
                    && (MENDER_OK
12✔
1067
                        == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module, &mender_artifact_ctx)))) {
12✔
1068
                    assert(NULL != mender_update_module);
11✔
1069
                    assert(NULL != mender_artifact_ctx);
11✔
1070

1071
                    /* Get artifact context if artifact download succeeded */
1072
                    if ((NULL != mender_update_module) && (NULL != mender_artifact_ctx)) {
11✔
1073
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
1074
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
22✔
1075
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
1076
                            /* Add the new provides to the deployment data (we need the artifact context) */
1077
                            char       *new_provides  = NULL;
11✔
1078
                            const char *artifact_name = NULL;
11✔
1079
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
11✔
1080
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
11✔
1081
                                    mender_log_error("Failed to set deployment data provides");
×
1082
                                }
1083
                                /* Replace artifact_name with the one from provides */
1084
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
11✔
1085
                                    mender_log_error("Failed to set deployment data artifact name");
×
1086
                                }
1087
                                mender_free(new_provides);
11✔
1088
                            } else {
1089
                                mender_log_error("Unable to prepare new provides");
×
1090
                            }
1091
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
1092
                        } else {
1093
                            mender_log_error("Artifact check failed");
×
1094
                        }
1095
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1096
                    } else {
1097
                        mender_log_error("Unable to get artifact type and context");
×
1098
                    }
1099
                } else {
1100
                    mender_log_error("Unable to download artifact");
1✔
1101
                    /* Error logged in mender_client_download_artifact_callback() */
1102
                    ret = MENDER_FAIL;
1✔
1103
                }
1104
                if (MENDER_OK != ret) {
12✔
1105
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
1✔
1106
                }
1107
                NEXT_STATE;
12✔
1108
                /* fallthrough */
1109

1110
            case MENDER_UPDATE_STATE_INSTALL:
1111
                mender_log_info("Download done, installing artifact");
11✔
1112
                /* Check ret to see if the deployment is aborted */
1113
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
11✔
1114
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
10✔
1115
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
9✔
1116
                }
1117
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
10✔
1118
                    /* skip reboot */
1119
                    update_state = MENDER_UPDATE_STATE_COMMIT;
1✔
1120
                    mender_log_debug("Entering state %s", update_state_str[update_state]);
1✔
1121
                    set_and_store_state(update_state);
1✔
1122
                    continue;
1✔
1123
                }
1124
                /* else continue to the next successful/failure state */
1125
                NEXT_STATE;
9✔
1126
                /* fallthrough */
1127

1128
            case MENDER_UPDATE_STATE_REBOOT:
1129
                assert(mender_update_module->requires_reboot);
7✔
1130
                mender_log_info("Artifact installation done, rebooting");
7✔
1131
                /* Check ret to see if the deployment is aborted */
1132
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
7✔
1133
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
7✔
1134
                    /* Save the next state before running the reboot callback --
1135
                     * if there is an interrupt (power, crash,...) right after,
1136
                     * it will reboot anyway so after the new boot, reboot
1137
                     * verification should happen anyway, the callback in that
1138
                     * state should be able to see if things went well or
1139
                     * wrong. */
1140
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
7✔
1141
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1142
                    if (MENDER_OK == ret) {
7✔
1143
                        /* now we need to get outside of the loop so that a
1144
                         * potential asynchronous reboot has a chance to kick in
1145
                         * after a proper cleanup below */
1146
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
7✔
1147
                        ret                 = MENDER_DONE;
7✔
1148
                        goto END;
7✔
1149
                    }
1150
                }
1151
                NEXT_STATE;
×
1152
                /* fallthrough */
1153

1154
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1155
                assert(mender_update_module->requires_reboot);
7✔
1156
                if (NULL != mender_update_module->callbacks[update_state]) {
7✔
1157
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1158
                }
1159
                NEXT_STATE;
7✔
1160
                /* fallthrough */
1161

1162
            case MENDER_UPDATE_STATE_COMMIT:
1163
                /* Check for pending deployment */
1164
                if (NULL == mender_client_deployment_data) {
6✔
1165
                    mender_log_error("No deployment data found on commit");
×
1166
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1167
                    goto END;
×
1168
                }
1169
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1170
                if (MENDER_OK != mender_api_drop_authentication_data()) {
6✔
1171
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1172
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1173
                       much to about it. */
1174
                }
1175
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
6✔
1176
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1177
                }
1178
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
1179
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
5✔
1180
                    mender_log_error("Unable to commit artifact data");
×
1181
                }
1182
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
5✔
1183
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
5✔
1184
                }
1185
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
1186
                /* If there was no reboot, we need to tell inventory to refresh
1187
                   the persistent data (because the deployment must have changed
1188
                   artifact name, at least) and we should trigger an inventory
1189
                   submission to refresh the data on the server. */
1190
                if (!mender_update_module->requires_reboot) {
5✔
1191
                    if (MENDER_OK != (ret = mender_inventory_reset_persistent())) {
1✔
1192
                        mender_log_error("Failed to reset persistent inventory after deployment commit with no reboot");
×
1193
                    } else if (MENDER_OK != (ret = mender_inventory_execute())) {
1✔
1194
                        mender_log_error("Failed to trigger inventory refresh after deployment commit with no reboot");
×
1195
                    }
1196
                }
1197
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
1198
                if (!MENDER_IS_ERROR(ret)) {
5✔
1199
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
2✔
1200
                }
1201
                NEXT_STATE;
5✔
1202
                /* fallthrough */
1203

1204
            case MENDER_UPDATE_STATE_CLEANUP:
1205
                if (NULL != mender_update_module) {
11✔
1206
                    if (NULL != mender_update_module->callbacks[update_state]) {
10✔
1207
                        ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1208
                    }
1209
                } else {
1210
                    ret = MENDER_FAIL;
1✔
1211
                }
1212
                NEXT_STATE;
11✔
1213
                mender_storage_delete_deployment_data();
10✔
1214
                break; /* below is the failure path */
10✔
1215

1216
            case MENDER_UPDATE_STATE_ROLLBACK:
6✔
1217
                if (!mender_update_module->supports_rollback) {
6✔
1218
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
1✔
1219
                    ret = MENDER_FAIL;
1✔
1220
                } else if (NULL != mender_update_module->callbacks[update_state]) {
5✔
1221
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
5✔
1222
                }
1223
                NEXT_STATE;
6✔
1224
                /* fallthrough */
1225

1226
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1227
                /* Save the next state before running the reboot callback (see
1228
                 * STATE_REBOOT for details). */
1229
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
7✔
1230
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1231

1232
                if (MENDER_OK == ret) {
7✔
1233
                    /* now we need to get outside of the loop so that a
1234
                     * potential asynchronous reboot has a chance to kick in
1235
                     * after a proper cleanup below */
1236
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
7✔
1237
                    ret                 = MENDER_DONE;
7✔
1238
                    goto END;
7✔
1239
                }
1240
                NEXT_STATE;
×
1241
                /* fallthrough */
1242

1243
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1244
                if (NULL != mender_update_module->callbacks[update_state]) {
7✔
1245
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1246
                }
1247

1248
                if (MENDER_OK != ret) {
7✔
1249
                    /* If the rollback verify reboot fails,
1250
                     * we will retry the rollback reboot.
1251
                     *
1252
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1253
                     * loop is broken when a state loop is detected
1254
                     */
1255
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
4✔
1256
                }
1257

1258
                NEXT_STATE;
7✔
1259
                /* fallthrough */
1260

1261
            case MENDER_UPDATE_STATE_FAILURE:
1262
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
9✔
1263
                if (NULL != mender_update_module->callbacks[update_state]) {
8✔
1264
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
8✔
1265
                }
1266
                NEXT_STATE;
8✔
1267
                break; /* end of the failure path */
8✔
1268

1269
            case MENDER_UPDATE_STATE_END:
×
1270
                /* This is only here to cover all possible values of the
1271
                 * update_state enum, there is nothing to do here, the while
1272
                 * loop shall stop when we get here. */
1273
                break;
×
1274
        }
1275
    }
1276
#undef NEXT_STATE /* should not be used anywhere else */
1277

1278
    ret = MENDER_OK;
11✔
1279

1280
END:
40✔
1281
    /* Release memory */
1282
    deployment_destroy(deployment);
40✔
1283
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
40✔
1284
    mender_artifact_release_ctx(mender_artifact_ctx);
40✔
1285

1286
    return ret;
40✔
1287
}
1288

1289
static mender_err_t
1290
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
42✔
1291
    if (MENDER_FAIL == mender_client_ensure_connected()) {
42✔
1292
        /* connection errors logged already */
1293
        mender_log_error("Cannot publish deployment status");
×
1294
        return MENDER_FAIL;
×
1295
    }
1296

1297
    mender_err_t ret;
1298

1299
    if (NULL == id) {
42✔
1300
        mender_log_error("Cannot publish deployment status: unknown status");
×
1301
        return MENDER_FAIL;
×
1302
    }
1303

1304
    /* Publish status to the mender server */
1305
    ret = mender_api_publish_deployment_status(id, deployment_status);
42✔
1306

1307
    /* Invoke deployment status callback if defined */
1308
    if (NULL != mender_client_callbacks.deployment_status) {
40✔
1309
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
40✔
1310
    }
1311

1312
    return ret;
40✔
1313
}
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

© 2026 Coveralls, Inc