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

mendersoftware / mender-mcu / 1710574815

11 Mar 2025 10:59AM UTC coverage: 25.348%. Remained the same
1710574815

push

gitlab-ci

vpodzime
feat: Introduce default inventory

To make the devices using a default build appear nicer in UI.

Ticket: MEN-7687
Changelog: none
Signed-off-by: Vratislav Podzimek <vratislav.podzimek+auto-signed@northern.tech>

711 of 2805 relevant lines covered (25.35%)

12.58 hits per line

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

0.0
/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
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
36
#include "inventory.h"
37
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
38

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

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

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

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

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

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

77
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
78

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

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

100
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_DBG
101
/* This is only needed for debug messages. */
102
static const char *update_state_str[N_MENDER_UPDATE_STATES + 1] = {
103
    "MENDER_UPDATE_STATE_DOWNLOAD",
104
    "MENDER_UPDATE_STATE_INSTALL",
105
    "MENDER_UPDATE_STATE_REBOOT",
106
    "MENDER_UPDATE_STATE_VERIFY_REBOOT",
107
    "MENDER_UPDATE_STATE_COMMIT",
108
    "MENDER_UPDATE_STATE_CLEANUP",
109
    "MENDER_UPDATE_STATE_ROLLBACK",
110
    "MENDER_UPDATE_STATE_ROLLBACK_REBOOT",
111
    "MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT",
112
    "MENDER_UPDATE_STATE_FAILURE",
113
    "MENDER_UPDATE_STATE_END",
114
};
115
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) {
×
239
    assert(NULL != config);
×
240
    assert(NULL != callbacks);
×
241
    assert(NULL != callbacks->restart);
×
242

243
    /* Either all allocation functions set or none. */
244
    assert(
×
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) {
×
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();
×
254
    }
255

256
    {
257
        cJSON_Hooks cjson_alloc_funcs = { mender_malloc, mender_free };
×
258
        cJSON_InitHooks(&cjson_alloc_funcs);
×
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;
×
263
    if (IS_NULL_OR_EMPTY(mender_client_config.device_type)) {
×
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);
×
269

270
    if ((NULL != config->host) && (strlen(config->host) > 0)) {
×
271
        mender_client_config.host = config->host;
×
272
    } else {
273
        mender_client_config.host = CONFIG_MENDER_SERVER_HOST;
×
274
    }
275
    if ((NULL == mender_client_config.host) || (0 == strlen(mender_client_config.host))) {
×
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]) {
×
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)) {
×
286
        mender_client_config.tenant_token = config->tenant_token;
×
287
    } else {
288
        mender_client_config.tenant_token = CONFIG_MENDER_SERVER_TENANT_TOKEN;
×
289
    }
290
    if ((NULL != mender_client_config.tenant_token) && (0 == strlen(mender_client_config.tenant_token))) {
×
291
        mender_client_config.tenant_token = NULL;
×
292
    }
293
    if (0 != config->update_poll_interval) {
×
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;
×
297
    }
298
    mender_client_config.recommissioning = config->recommissioning;
×
299

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

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

332
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
333
    if (MENDER_OK != (ret = mender_inventory_init(mender_client_config.inventory_update_interval, mender_client_config.device_type))) {
334
        mender_log_error("Failed to initialize the inventory functionality");
335
        goto END;
336
    }
337
    if (MENDER_OK != mender_inventory_add_default_callbacks()) {
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 */
342

343
END:
×
344

345
    return ret;
×
346
}
347

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

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

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

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

372
    return ret;
×
373
}
374

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

381
    return mender_client_network_connect();
×
382
}
383

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

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

398
    mender_client_network_connected = true;
×
399

400
    return MENDER_OK;
×
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_exit(void) {
×
423
    bool some_error = false;
×
424

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

432
        if (MENDER_OK != mender_os_scheduler_work_delete(mender_client_work)) {
×
433
            mender_log_error("Failed to delete main work");
×
434
            /* keep going on, we want to do as much cleanup as possible */
435
            some_error = true;
×
436
        } else {
437
            mender_client_work = NULL;
×
438
        }
439
    }
440

441
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
442
    if (MENDER_OK != mender_inventory_exit()) {
443
        mender_log_error("Unable to cleanup after the inventory functionality");
444
        /* keep going on, we want to do as much cleanup as possible */
445
        some_error = true;
446
    }
447
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
448

449
    /* Stop scheduling new work */
450
    mender_os_scheduler_exit();
×
451

452
    /* Release all modules */
453
    mender_api_exit();
×
454
    mender_tls_exit();
×
455
    mender_storage_exit();
×
456
    mender_log_exit();
×
457
    mender_client_network_release();
×
458

459
    /* Release memory */
460
    mender_client_config.device_type          = NULL;
×
461
    mender_client_config.host                 = NULL;
×
462
    mender_client_config.tenant_token         = NULL;
×
463
    mender_client_config.update_poll_interval = 0;
×
464
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
465

466
    mender_update_module_unregister_all();
×
467

468
    return some_error ? MENDER_FAIL : MENDER_OK;
×
469
}
470

471
static mender_err_t
472
mender_client_work_function(void) {
×
473
    mender_err_t ret;
474
    mender_log_debug("Inside work function [state: %s]", client_state_str[mender_client_state]);
475

476
    switch (mender_client_state) {
×
477
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
×
478
            mender_log_info("Waiting for a reboot");
×
479
            if (MENDER_OK != mender_err_count_reboot_inc()) {
×
480
                /* It appears we are stuck in this state. The only thing we can do is to mark the
481
                   deployment as failed and revert to normal operation. */
482
                mender_log_error("Waiting for reboot for too long, trying unconditional reboot");
×
483
                mender_os_reboot();
×
484

485
                mender_log_error("Failed to reboot unconditionally, trying to resume operations");
×
486
                if (NULL == mender_client_deployment_data) {
×
487
                    mender_log_error("No deployment data to use for deployment abortion");
×
488
                } else {
489
                    mender_update_state_t update_state;
490
                    if (MENDER_OK != mender_deployment_data_get_state(mender_client_deployment_data, &update_state)) {
×
491
                        mender_log_error("Failed to get current update state, going to ROLLBACK state");
×
492
                        update_state = MENDER_UPDATE_STATE_ROLLBACK;
×
493
                    } else {
494
                        update_state = update_state_transitions[update_state].failure;
×
495
                    }
496
                    if (MENDER_OK != set_and_store_state(update_state)) {
×
497
                        mender_log_error("Failed to save new state");
×
498
                    }
499
                }
500

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

532
                /* We don't want to tell the scheduler we are done because
533
                   otherwise we won't have a chance to detect that we are
534
                   waiting for a reboot forever. */
535
                ret = MENDER_OK;
×
536
            }
537
            return ret;
×
538
    }
539

540
    /* This should never be reached, all the cases should be covered in the
541
       above switch and they all return. */
542
    return MENDER_FAIL;
×
543
}
544

545
static mender_err_t
546
mender_client_initialization_work_function(void) {
×
547

548
    mender_err_t ret = MENDER_DONE;
×
549

550
    /* Retrieve or generate authentication keys */
551
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
×
552
        mender_log_error("Unable to retrieve or generate authentication keys");
×
553
        goto END;
×
554
    }
555

556
    /* Retrieve deployment data if it is found (following an update) */
557
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
×
558
        if (MENDER_NOT_FOUND != ret) {
×
559
            mender_log_error("Unable to get deployment data");
×
560
            goto REBOOT;
×
561
        }
562
    }
563

564
    mender_log_info("Initialization done");
×
565

566
    return MENDER_DONE;
×
567

568
END:
×
569

570
    return ret;
×
571

572
REBOOT:
×
573

574
    mender_log_info("Rebooting...");
×
575

576
    /* Delete pending deployment */
577
    mender_storage_delete_deployment_data();
×
578

579
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
580
    /* Set the client's state to PENDING_REBOOT so that we can potentially
581
       detect a failure to reboot (i.e. waiting for reboot taking too long).  */
582
    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
583
    if (NULL != mender_client_callbacks.restart) {
×
584
        mender_client_callbacks.restart();
×
585
    }
586

587
    return ret;
×
588
}
589

590
static mender_err_t
591
mender_commit_artifact_data(void) {
×
592

593
    assert(NULL != mender_client_deployment_data);
×
594

595
    const char *artifact_name;
596
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
597
        mender_log_error("Unable to get artifact name from the deployment data");
×
598
        return MENDER_FAIL;
×
599
    }
600

601
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
602
        mender_log_error("Unable to set artifact name");
×
603
        return MENDER_FAIL;
×
604
    }
605

606
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
607
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
608
    /* Get provides from the deployment data */
609
    const char *provides;
610
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
×
611
        mender_log_error("Unable to get new_provides from the deployment data");
×
612
        return MENDER_FAIL;
×
613
    }
614

615
    /* Parse provides */
616
    mender_key_value_list_t *new_provides = NULL;
×
617
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
×
618
        mender_log_error("Unable to parse provides from the deployment data");
×
619
        return MENDER_FAIL;
×
620
    }
621
    /* Replace the stored provides with the new provides */
622
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
×
623
        mender_log_error("Unable to set provides");
×
624
        mender_utils_key_value_list_free(new_provides);
×
625
        return MENDER_FAIL;
×
626
    }
627
    mender_utils_key_value_list_free(new_provides);
×
628
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
629
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
630

631
    return MENDER_OK;
×
632
}
633

634
static mender_err_t
635
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
636
    if (NULL != deployment) {
×
637
        mender_free(deployment->id);
×
638
        mender_free(deployment->artifact_name);
×
639
        mender_free(deployment->uri);
×
640
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
641
            mender_free(deployment->device_types_compatible[i]);
×
642
        }
643
        mender_free(deployment->device_types_compatible);
×
644
        mender_free(deployment);
×
645
    }
646
    return MENDER_OK;
×
647
}
648

649
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
650
static mender_err_t
651
mender_compare_device_types(const char  *device_type_artifact,
×
652
                            const char  *device_type_device,
653
                            const char **device_type_deployment,
654
                            const size_t device_type_deployment_size) {
655

656
    assert(NULL != device_type_artifact);
×
657
    assert(NULL != device_type_deployment);
×
658
    assert(NULL != device_type_device);
×
659
    assert(0 < device_type_deployment_size);
×
660

661
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
662
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
663
        return MENDER_FAIL;
×
664
    }
665

666
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
667
    for (size_t i = 0; i < device_type_deployment_size; i++) {
×
668
        if (StringEqual(device_type_deployment[i], device_type_device)) {
×
669
            return MENDER_OK;
×
670
        }
671
    }
672
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
673
    return MENDER_FAIL;
×
674
}
675

676
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
677
static mender_err_t
678
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
679

680
    mender_err_t ret = MENDER_FAIL;
×
681
    /* Clears provides */
682
    bool matches;
683
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
684
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
×
685
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
×
686
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
×
687
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
688
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
689
                    goto END;
×
690
                }
691
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
692
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
693
                    goto END;
×
694
                }
695
            }
696
        }
697
    }
698

699
    /* Combine the stored provides with the new ones */
700
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
701
        mender_log_error("Unable to merge provides");
×
702
        goto END;
×
703
    }
704

705
    /* Make sure the artifact name is not in the new provides */
706
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
707
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
708
        goto END;
×
709
    }
710

711
    ret = MENDER_OK;
×
712

713
END:
×
714

715
    mender_utils_key_value_list_free(*stored_provides);
×
716
    return ret;
×
717
}
718

719
static mender_err_t
720
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
721

722
    assert(NULL != artifact_name);
×
723
    assert(NULL != mender_artifact_ctx);
×
724

725
    /* Load the currently stored provides */
726
    mender_key_value_list_t *stored_provides = NULL;
×
727
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
728
        mender_log_error("Unable to get provides");
×
729
        return MENDER_FAIL;
×
730
    }
731

732
    mender_key_value_list_t *provides = NULL;
×
733
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
734
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
735
            mender_log_error("Unable to merge provides");
×
736
            mender_utils_key_value_list_free(stored_provides);
×
737
            return MENDER_FAIL;
×
738
        }
739
    }
740

741
    /* Get artifact name from provides */
742
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
743
        if (StringEqual("artifact_name", item->key)) {
×
744
            *artifact_name = item->value;
×
745
            break;
×
746
        }
747
    }
748

749
    if (NULL == *artifact_name) {
×
750
        mender_log_error("No artifact name found in provides");
×
751
        mender_utils_key_value_list_free(stored_provides);
×
752
        return MENDER_FAIL;
×
753
    }
754

755
    /* Filter provides */
756
    /* `stored_provides` is freed in `mender_filter_provides` */
757
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
758
        return MENDER_FAIL;
×
759
    }
760

761
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
762
        mender_utils_key_value_list_free(provides);
×
763
        return MENDER_FAIL;
×
764
    }
765

766
    mender_utils_key_value_list_free(provides);
×
767
    return MENDER_OK;
×
768
}
769

770
static mender_err_t
771
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
772

773
    /* We need to load the stored provides */
774
    mender_key_value_list_t *stored_provides = NULL;
×
775
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
776
        return MENDER_FAIL;
×
777
    }
778

779
    mender_err_t ret = MENDER_FAIL;
×
780

781
    /* Get depends */
782
    mender_key_value_list_t *depends = NULL;
×
783
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
784
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
785
            mender_log_error("Unable to append depends");
×
786
            goto END;
×
787
        }
788
    }
789

790
    /* Match depends from artifact with device's provides */
791
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
×
792
        bool matches = false;
×
793
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
794
            /* Match key-value from depends with provides */
795
            if (StringEqual(depends_item->key, provides_item->key)) {
×
796
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
797
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
798
                                     depends_item->key,
799
                                     depends_item->value,
800
                                     provides_item->value);
801
                    break;
×
802
                }
803
                matches = true;
×
804
                break;
×
805
            }
806
        }
807
        if (!matches) {
×
808
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
809
            goto END;
×
810
        }
811
    }
812

813
    ret = MENDER_OK;
×
814

815
END:
×
816
    mender_utils_key_value_list_free(stored_provides);
×
817
    return ret;
×
818
}
819
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
820
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
821

822
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
823
static mender_err_t
824
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
825
    mender_err_t ret;
826

827
    /* Retrieve device type from artifact */
828
    const char *device_type_artifact = NULL;
×
829
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
830
        mender_log_error("Unable to get device type from artifact");
×
831
        return ret;
×
832
    }
833

834
    mender_log_debug("Checking device type compatibility");
835

836
    /* Match device type  */
837
    if (MENDER_OK
×
838
        != (ret = mender_compare_device_types(device_type_artifact,
×
839
                                              mender_client_config.device_type,
×
840
                                              (const char **)deployment->device_types_compatible,
×
841
                                              deployment->device_types_compatible_size))) {
842
        return ret;
×
843
    }
844

845
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
846
    /* Compare Artifact's depends with the stored provides */
847
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
848
        return ret;
×
849
    }
850
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
851

852
    /* Check payload integrity by comparing computed checksum(s) with those
853
     * listed in the artifact manifest */
854
    if (MENDER_OK != mender_artifact_check_integrity_remaining(mender_artifact_ctx)) {
×
855
        return MENDER_FAIL;
×
856
    }
857

858
    return MENDER_OK;
×
859
}
860
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
861

862
static mender_err_t
863
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
864
    assert(NULL != deployment_data);
×
865

866
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
867
        /* network errors logged already */
868
        mender_log_error("Cannot check for new deployment");
×
869
        return MENDER_FAIL;
×
870
    }
871

872
    if (NULL == (*deployment_data = mender_calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
873
        mender_log_error("Unable to allocate memory for deployment data");
×
874
        return MENDER_FAIL;
×
875
    }
876

877
    mender_api_deployment_data_t *deployment = *deployment_data;
×
878

879
    mender_err_t ret = MENDER_OK;
×
880

881
    mender_log_info("Checking for deployment...");
×
882
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
883
        mender_log_info("No deployment available");
×
884
        return MENDER_DONE;
×
885
    } else if (MENDER_OK != ret) {
×
886
        mender_log_error("Unable to check for deployment");
×
887
        return MENDER_FAIL;
×
888
    }
889

890
    /* Check if deployment is valid */
891
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
892
        mender_log_error("Invalid deployment data");
×
893
        return MENDER_FAIL;
×
894
    }
895

896
    /* Create deployment data */
897
    if (NULL != mender_client_deployment_data) {
×
898
        mender_log_warning("Unexpected stale deployment data");
×
899
        mender_delete_deployment_data(mender_client_deployment_data);
×
900
    }
901
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
902
        /* Error already logged */
903
        return MENDER_FAIL;
×
904
    }
905

906
    return MENDER_OK;
×
907
}
908

909
static mender_err_t
910
set_and_store_state(const mender_update_state_t state) {
×
911

912
    /*
913
     * Set the state in `mender_client_deployment_data` and write it to the nvs
914
     */
915

916
    mender_err_t ret = MENDER_OK;
×
917

918
    /* Set state in deployment data */
919
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
920
        mender_log_error("Failed to set deployment data state");
×
921
        return ret;
×
922
    }
923

924
    /* Store deployment data */
925
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
926
        mender_log_error("Failed to store deployment data");
×
927
        return ret;
×
928
    }
929
    return ret;
×
930
}
931

932
static mender_err_t
933
mender_client_update_work_function(void) {
×
934
    mender_err_t ret = MENDER_OK;
×
935

936
    /* Ensure that the context is initialized to NULL before goto END */
937
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
938

939
    /* Check for deployment */
940
    mender_api_deployment_data_t *deployment    = NULL;
×
941
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
942
    const char                   *deployment_id = NULL;
×
943

944
    /* reset the currently used update module */
945
    mender_update_module = NULL;
×
946

947
    if (NULL != mender_client_deployment_data) {
×
948
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
949
    }
950

951
    {
952
        const char           *artifact_type;
953
        mender_update_state_t update_state_resume;
954
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
×
955
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
×
956
            update_state = update_state_resume;
×
957
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
958
            mender_update_module = mender_update_module_get(artifact_type);
×
959
            if (NULL == mender_update_module) {
×
960
                /* The artifact_type from the saved state does not match any update module */
961
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
962
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
963
                mender_storage_delete_deployment_data();
×
964
                goto END;
×
965
            }
966
        }
967
    }
968

969
    /* Skip the block below if we just resume from a saved state. */
970

971
/* A macro to advance to the next state -- on success we just keep going to the
972
 * code below the macro invocation (fallthrough to the next case), on error we
973
 * go to the beginning of the loop (the switch statement) again using 'continue'
974
 * (see below).
975
 *
976
 * mender_update_module is guaranteed be not NULL since the first
977
 * successful transition (from the DOWNLOAD state). */
978
#define NEXT_STATE                                                             \
979
    if (MENDER_OK == ret) {                                                    \
980
        update_state = update_state_transitions[update_state].success;         \
981
        assert(NULL != mender_update_module);                                  \
982
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
983
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
984
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
985
        }                                                                      \
986
    } else {                                                                   \
987
        update_state = update_state_transitions[update_state].failure;         \
988
        if (NULL != mender_update_module) {                                    \
989
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
990
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
991
            }                                                                  \
992
        }                                                                      \
993
        ret = MENDER_OK;                                                       \
994
        continue;                                                              \
995
    }
996

997
    while (MENDER_UPDATE_STATE_END != update_state) {
×
998
        mender_log_debug("Entering state %s", update_state_str[update_state]);
999
        switch (update_state) {
×
1000
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
1001

1002
                /* Check for deployment */
1003
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
1004
                    /* No deployment available, but we are not done, we need to keep checking. */
1005
                    if (MENDER_DONE == ret) {
×
1006
                        ret = MENDER_OK;
×
1007
                    }
1008
                    goto END;
×
1009
                }
1010

1011
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
1012
                if (strlen(deployment->id) > 10) {
×
1013
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
1014
                } else {
1015
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
1016
                }
1017
#endif
1018
                /* Set deployment_id */
1019
                deployment_id = deployment->id;
×
1020

1021
                /* Check ret to see if the deployment is aborted */
1022
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
1023
                if ((MENDER_ABORTED != ret)
×
1024
                    && (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module)))) {
×
1025
                    assert(NULL != mender_update_module);
×
1026

1027
                    /* Get artifact context if artifact download succeeded */
1028
                    if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) {
×
1029
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
1030
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
×
1031
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
1032
                            /* Add the new provides to the deployment data (we need the artifact context) */
1033
                            char       *new_provides  = NULL;
×
1034
                            const char *artifact_name = NULL;
×
1035
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
×
1036
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
×
1037
                                    mender_log_error("Failed to set deployment data provides");
×
1038
                                }
1039
                                /* Replace artifact_name with the one from provides */
1040
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
×
1041
                                    mender_log_error("Failed to set deployment data artifact name");
×
1042
                                }
1043
                                mender_free(new_provides);
×
1044
                            } else {
1045
                                mender_log_error("Unable to prepare new provides");
×
1046
                            }
1047
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
1048
                        } else {
1049
                            mender_log_error("Artifact check failed");
×
1050
                        }
1051
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1052
                    } else {
1053
                        mender_log_error("Unable to get artifact type and context");
×
1054
                    }
1055
                } else {
1056
                    mender_log_error("Unable to download artifact");
×
1057
                    /* Error logged in mender_client_download_artifact_callback() */
1058
                    ret = MENDER_FAIL;
×
1059
                }
1060
                if (MENDER_OK != ret) {
×
1061
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1062
                }
1063
                NEXT_STATE;
×
1064
                /* fallthrough */
1065

1066
            case MENDER_UPDATE_STATE_INSTALL:
1067
                mender_log_info("Download done, installing artifact");
×
1068
                /* Check ret to see if the deployment is aborted */
1069
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
×
1070
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1071
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1072
                }
1073
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
×
1074
                    /* skip reboot */
1075
                    update_state = MENDER_UPDATE_STATE_COMMIT;
×
1076
                    set_and_store_state(update_state);
×
1077
                    continue;
×
1078
                }
1079
                /* else continue to the next successful/failure state */
1080
                NEXT_STATE;
×
1081
                /* fallthrough */
1082

1083
            case MENDER_UPDATE_STATE_REBOOT:
1084
                assert(mender_update_module->requires_reboot);
×
1085
                mender_log_info("Artifact installation done, rebooting");
×
1086
                /* Check ret to see if the deployment is aborted */
1087
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
×
1088
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1089
                    /* Save the next state before running the reboot callback --
1090
                     * if there is an interrupt (power, crash,...) right after,
1091
                     * it will reboot anyway so after the new boot, reboot
1092
                     * verification should happen anyway, the callback in that
1093
                     * state should be able to see if things went well or
1094
                     * wrong. */
1095
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
×
1096
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1097
                    if (MENDER_OK == ret) {
×
1098
                        /* now we need to get outside of the loop so that a
1099
                         * potential asynchronous reboot has a chance to kick in
1100
                         * after a proper cleanup below */
1101
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1102
                        ret                 = MENDER_DONE;
×
1103
                        goto END;
×
1104
                    }
1105
                }
1106
                NEXT_STATE;
×
1107
                /* fallthrough */
1108

1109
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1110
                assert(mender_update_module->requires_reboot);
×
1111
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1112
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1113
                }
1114
                NEXT_STATE;
×
1115
                /* fallthrough */
1116

1117
            case MENDER_UPDATE_STATE_COMMIT:
1118
                /* Check for pending deployment */
1119
                if (NULL == mender_client_deployment_data) {
×
1120
                    mender_log_error("No deployment data found on commit");
×
1121
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1122
                    goto END;
×
1123
                }
1124
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1125
                if (MENDER_OK != mender_api_drop_authentication_data()) {
×
1126
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1127
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1128
                       much to about it. */
1129
                }
1130
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
×
1131
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1132
                }
1133
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
1134
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
×
1135
                    mender_log_error("Unable to commit artifact data");
×
1136
                }
1137
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1138
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1139
                }
1140
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
1141
                /* If there was no reboot, we need to tell inventory to refresh
1142
                   the persistent data (because the deployment must have changed
1143
                   artifact name, at least) and we should trigger an inventory
1144
                   submission to refresh the data on the server. */
1145
                if (!mender_update_module->requires_reboot) {
1146
                    if (MENDER_OK != (ret = mender_inventory_reset_persistent())) {
1147
                        mender_log_error("Failed to reset persistent inventory after deployment commit with no reboot");
1148
                    } else if (MENDER_OK != (ret = mender_inventory_execute())) {
1149
                        mender_log_error("Failed to trigger inventory refresh after deployment commit with no reboot");
1150
                    }
1151
                }
1152
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
1153
                if (!MENDER_IS_ERROR(ret)) {
×
1154
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
×
1155
                }
1156
                NEXT_STATE;
×
1157
                /* fallthrough */
1158

1159
            case MENDER_UPDATE_STATE_CLEANUP:
1160
                if (NULL != mender_update_module) {
×
1161
                    if (NULL != mender_update_module->callbacks[update_state]) {
×
1162
                        ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1163
                    }
1164
                } else {
1165
                    ret = MENDER_FAIL;
×
1166
                }
1167
                NEXT_STATE;
×
1168
                mender_storage_delete_deployment_data();
×
1169
                break; /* below is the failure path */
×
1170

1171
            case MENDER_UPDATE_STATE_ROLLBACK:
×
1172
                if (!mender_update_module->supports_rollback) {
×
1173
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
×
1174
                    ret = MENDER_FAIL;
×
1175
                } else if (NULL != mender_update_module->callbacks[update_state]) {
×
1176
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1177
                }
1178
                NEXT_STATE;
×
1179
                /* fallthrough */
1180

1181
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1182
                /* Save the next state before running the reboot callback (see
1183
                 * STATE_REBOOT for details). */
1184
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
1185
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1186

1187
                if (MENDER_OK == ret) {
×
1188
                    /* now we need to get outside of the loop so that a
1189
                     * potential asynchronous reboot has a chance to kick in
1190
                     * after a proper cleanup below */
1191
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1192
                    ret                 = MENDER_DONE;
×
1193
                    goto END;
×
1194
                }
1195
                NEXT_STATE;
×
1196
                /* fallthrough */
1197

1198
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1199
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1200
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1201
                }
1202

1203
                if (MENDER_OK != ret) {
×
1204
                    /* If the rollback verify reboot fails,
1205
                     * we will retry the rollback reboot.
1206
                     *
1207
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1208
                     * loop is broken when a state loop is detected
1209
                     */
1210
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
×
1211
                }
1212

1213
                NEXT_STATE;
×
1214
                /* fallthrough */
1215

1216
            case MENDER_UPDATE_STATE_FAILURE:
1217
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1218
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1219
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1220
                }
1221
                NEXT_STATE;
×
1222
                break; /* end of the failure path */
×
1223

1224
            case MENDER_UPDATE_STATE_END:
×
1225
                /* This is only here to cover all possible values of the
1226
                 * update_state enum, there is nothing to do here, the while
1227
                 * loop shall stop when we get here. */
1228
                break;
×
1229
        }
1230
    }
1231
#undef NEXT_STATE /* should not be used anywhere else */
1232

1233
    ret = MENDER_OK;
×
1234

1235
END:
×
1236
    /* Release memory */
1237
    deployment_destroy(deployment);
×
1238
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
1239
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1240

1241
    return ret;
×
1242
}
1243

1244
static mender_err_t
1245
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
1246
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1247
        /* connection errors logged already */
1248
        mender_log_error("Cannot publish deployment status");
×
1249
        return MENDER_FAIL;
×
1250
    }
1251

1252
    mender_err_t ret;
1253

1254
    if (NULL == id) {
×
1255
        mender_log_error("Cannot publish deployment status: unknown status");
×
1256
        return MENDER_FAIL;
×
1257
    }
1258

1259
    /* Publish status to the mender server */
1260
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1261

1262
    /* Invoke deployment status callback if defined */
1263
    if (NULL != mender_client_callbacks.deployment_status) {
×
1264
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1265
    }
1266

1267
    return ret;
×
1268
}
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