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

mendersoftware / mender-mcu / 1652801795

03 Feb 2025 08:48AM UTC coverage: 25.939% (+0.3%) from 25.682%
1652801795

push

gitlab-ci

danielskinstad
chore: explicit error for no files in zephyr-image-update-module

Check if the aritfact has a payload file by adding a boolean that's set
when the download artifact flash callback is called.

Ticket: MEN-7804

Signed-off-by: Daniel Skinstad Drabitzius <daniel.drabitzius@northern.tech>

739 of 2849 relevant lines covered (25.94%)

8.56 hits per line

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

0.0
/core/src/mender-client.c
1
/**
2
 * @file      mender-client.c
3
 * @brief     Mender MCU client implementation
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 * Copyright Northern.tech AS
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
#include "mender-alloc.h"
22
#include "mender-api.h"
23
#include "mender-client.h"
24
#include "mender-artifact.h"
25
#include "mender-artifact-download.h"
26
#include "mender-log.h"
27
#include "mender-scheduler.h"
28
#include "mender-storage.h"
29
#include "mender-tls.h"
30
#include "mender-update-module.h"
31
#include "mender-utils.h"
32
#include "mender-deployment-data.h"
33
#include "mender-error-counters.h"
34

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

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

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

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

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

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

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

77
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
78

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

224
char *
225
mender_client_version(void) {
×
226

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

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

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

243
    mender_err_t ret;
244

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

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

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

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

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

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

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

335
END:
×
336

337
    return ret;
×
338
}
339

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

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

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

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

364
    return ret;
×
365
}
366

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

373
    return mender_client_network_connect();
×
374
}
375

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

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

390
    mender_client_network_connected = true;
×
391

392
    return MENDER_OK;
×
393
}
394

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

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

410
    return MENDER_OK;
×
411
}
412

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

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

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

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

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

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

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

456
    mender_update_module_unregister_all();
×
457

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

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

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

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

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

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

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

535
static mender_err_t
536
mender_client_initialization_work_function(void) {
×
537

538
    mender_err_t ret = MENDER_DONE;
×
539

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

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

554
    mender_log_info("Initialization done");
×
555

556
    return MENDER_DONE;
×
557

558
END:
×
559

560
    return ret;
×
561

562
REBOOT:
×
563

564
    mender_log_info("Rebooting...");
×
565

566
    /* Delete pending deployment */
567
    mender_storage_delete_deployment_data();
×
568

569
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
570
    /* Set the client's state to PENDING_REBOOT so that we can potentially
571
       detect a failure to reboot (i.e. waiting for reboot taking too long).  */
572
    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
573
    if (NULL != mender_client_callbacks.restart) {
×
574
        mender_client_callbacks.restart();
×
575
    }
576

577
    return ret;
×
578
}
579

580
static mender_err_t
581
mender_commit_artifact_data(void) {
×
582

583
    assert(NULL != mender_client_deployment_data);
×
584

585
    const char *artifact_name;
586
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
587
        mender_log_error("Unable to get artifact name from the deployment data");
×
588
        return MENDER_FAIL;
×
589
    }
590

591
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
592
        mender_log_error("Unable to set artifact name");
×
593
        return MENDER_FAIL;
×
594
    }
595

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

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

621
    return MENDER_OK;
×
622
}
623

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

639
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
640
static mender_err_t
641
mender_compare_device_types(const char  *device_type_artifact,
×
642
                            const char  *device_type_device,
643
                            const char **device_type_deployment,
644
                            const size_t device_type_deployment_size) {
645

646
    assert(NULL != device_type_artifact);
×
647
    assert(NULL != device_type_deployment);
×
648
    assert(NULL != device_type_device);
×
649
    assert(0 < device_type_deployment_size);
×
650

651
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
652
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
653
        return MENDER_FAIL;
×
654
    }
655

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

666
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
667
static mender_err_t
668
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
669

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

689
    /* Combine the stored provides with the new ones */
690
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
691
        mender_log_error("Unable to merge provides");
×
692
        goto END;
×
693
    }
694

695
    /* Make sure the artifact name is not in the new provides */
696
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
697
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
698
        goto END;
×
699
    }
700

701
    ret = MENDER_OK;
×
702

703
END:
×
704

705
    mender_utils_key_value_list_free(*stored_provides);
×
706
    return ret;
×
707
}
708

709
static mender_err_t
710
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
711

712
    assert(NULL != artifact_name);
×
713
    assert(NULL != mender_artifact_ctx);
×
714

715
    /* Load the currently stored provides */
716
    mender_key_value_list_t *stored_provides = NULL;
×
717
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
718
        mender_log_error("Unable to get provides");
×
719
        return MENDER_FAIL;
×
720
    }
721

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

731
    /* Get artifact name from provides */
732
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
733
        if (StringEqual("artifact_name", item->key)) {
×
734
            *artifact_name = item->value;
×
735
            break;
×
736
        }
737
    }
738

739
    if (NULL == *artifact_name) {
×
740
        mender_log_error("No artifact name found in provides");
×
741
        mender_utils_key_value_list_free(stored_provides);
×
742
        return MENDER_FAIL;
×
743
    }
744

745
    /* Filter provides */
746
    /* `stored_provides` is freed in `mender_filter_provides` */
747
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
748
        return MENDER_FAIL;
×
749
    }
750

751
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
752
        return MENDER_FAIL;
×
753
    }
754

755
    return MENDER_OK;
×
756
}
757

758
static mender_err_t
759
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
760

761
    /* We need to load the stored provides */
762
    mender_key_value_list_t *stored_provides = NULL;
×
763
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
764
        return MENDER_FAIL;
×
765
    }
766

767
    mender_err_t ret = MENDER_FAIL;
×
768

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

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

801
    ret = MENDER_OK;
×
802

803
END:
×
804
    mender_utils_key_value_list_free(stored_provides);
×
805
    return ret;
×
806
}
807
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
808
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
809

810
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
811
static mender_err_t
812
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
813
    mender_err_t ret;
814

815
    /* Retrieve device type from artifact */
816
    const char *device_type_artifact = NULL;
×
817
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
818
        mender_log_error("Unable to get device type from artifact");
×
819
        return ret;
×
820
    }
821

822
    mender_log_debug("Checking device type compatibility");
823

824
    /* Match device type  */
825
    if (MENDER_OK
×
826
        != (ret = mender_compare_device_types(device_type_artifact,
×
827
                                              mender_client_config.device_type,
×
828
                                              (const char **)deployment->device_types_compatible,
×
829
                                              deployment->device_types_compatible_size))) {
830
        return ret;
×
831
    }
832

833
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
834
    /* Compare Artifact's depends with the stored provides */
835
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
836
        return ret;
×
837
    }
838
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
839

840
    /* Check artifact integrity by comparing computed checksums with those
841
     * listed in the artifacts manifest */
842
    if (MENDER_OK != mender_artifact_check_integrity(mender_artifact_ctx)) {
×
843
        return MENDER_FAIL;
×
844
    }
845

846
    return MENDER_OK;
×
847
}
848
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
849

850
static mender_err_t
851
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
852
    assert(NULL != deployment_data);
×
853

854
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
855
        /* network errors logged already */
856
        mender_log_error("Cannot check for new deployment");
×
857
        return MENDER_FAIL;
×
858
    }
859

860
    if (NULL == (*deployment_data = mender_calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
861
        mender_log_error("Unable to allocate memory for deployment data");
×
862
        return MENDER_FAIL;
×
863
    }
864

865
    mender_api_deployment_data_t *deployment = *deployment_data;
×
866

867
    mender_err_t ret = MENDER_OK;
×
868

869
    mender_log_info("Checking for deployment...");
×
870
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
871
        mender_log_info("No deployment available");
×
872
        return MENDER_DONE;
×
873
    } else if (MENDER_OK != ret) {
×
874
        mender_log_error("Unable to check for deployment");
×
875
        return MENDER_FAIL;
×
876
    }
877

878
    /* Check if deployment is valid */
879
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
880
        mender_log_error("Invalid deployment data");
×
881
        return MENDER_FAIL;
×
882
    }
883

884
    /* Create deployment data */
885
    if (NULL != mender_client_deployment_data) {
×
886
        mender_log_warning("Unexpected stale deployment data");
×
887
        mender_delete_deployment_data(mender_client_deployment_data);
×
888
    }
889
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
890
        /* Error already logged */
891
        return MENDER_FAIL;
×
892
    }
893

894
    return MENDER_OK;
×
895
}
896

897
static mender_err_t
898
set_and_store_state(const mender_update_state_t state) {
×
899

900
    /*
901
     * Set the state in `mender_client_deployment_data` and write it to the nvs
902
     */
903

904
    mender_err_t ret = MENDER_OK;
×
905

906
    /* Set state in deployment data */
907
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
908
        mender_log_error("Failed to set deployment data state");
×
909
        return ret;
×
910
    }
911

912
    /* Store deployment data */
913
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
914
        mender_log_error("Failed to store deployment data");
×
915
        return ret;
×
916
    }
917
    return ret;
×
918
}
919

920
static mender_err_t
921
mender_client_update_work_function(void) {
×
922
    mender_err_t ret = MENDER_OK;
×
923

924
    /* Ensure that the context is initialized to NULL before goto END */
925
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
926

927
    /* Check for deployment */
928
    mender_api_deployment_data_t *deployment    = NULL;
×
929
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
930
    const char                   *deployment_id = NULL;
×
931

932
    /* reset the currently used update module */
933
    mender_update_module = NULL;
×
934

935
    if (NULL != mender_client_deployment_data) {
×
936
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
937
    }
938

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

957
    /* Skip the block below if we just resume from a saved state. */
958

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

986
    while (MENDER_UPDATE_STATE_END != update_state) {
×
987
        switch (update_state) {
×
988
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
989

990
                /* Check for deployment */
991
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
992
                    /* No deployment available, but we are not done, we need to keep checking. */
993
                    if (MENDER_DONE == ret) {
×
994
                        ret = MENDER_OK;
×
995
                    }
996
                    goto END;
×
997
                }
998

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

1009
                /* Check ret to see if the deployment is aborted */
1010
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
1011
                if ((MENDER_ABORTED != ret)
×
1012
                    && (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module)))) {
×
1013
                    assert(NULL != mender_update_module);
×
1014

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

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

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

1095
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1096
                assert(mender_update_module->requires_reboot);
×
1097
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1098
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1099
                }
1100
                NEXT_STATE;
×
1101
                /* fallthrough */
1102

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

1132
            case MENDER_UPDATE_STATE_CLEANUP:
1133
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1134
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1135
                }
1136
                NEXT_STATE;
×
1137
                mender_storage_delete_deployment_data();
×
1138
                break; /* below is the failure path */
×
1139

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

1150
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1151
                /* Save the next state before running the reboot callback (see
1152
                 * STATE_REBOOT for details). */
1153
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
1154
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1155

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

1167
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1168
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1169
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1170
                }
1171

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

1182
                NEXT_STATE;
×
1183
                /* fallthrough */
1184

1185
            case MENDER_UPDATE_STATE_FAILURE:
1186
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1187
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1188
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1189
                }
1190
                NEXT_STATE;
×
1191
                break; /* end of the failure path */
×
1192

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

1202
    ret = MENDER_OK;
×
1203

1204
END:
×
1205
    /* Release memory */
1206
    deployment_destroy(deployment);
×
1207
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
1208
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1209

1210
    return ret;
×
1211
}
1212

1213
static mender_err_t
1214
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
1215
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1216
        /* connection errors logged already */
1217
        mender_log_error("Cannot publish deployment status");
×
1218
        return MENDER_FAIL;
×
1219
    }
1220

1221
    mender_err_t ret;
1222

1223
    if (NULL == id) {
×
1224
        mender_log_error("Cannot publish deployment status: unknown status");
×
1225
        return MENDER_FAIL;
×
1226
    }
1227

1228
    /* Publish status to the mender server */
1229
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1230

1231
    /* Invoke deployment status callback if defined */
1232
    if (NULL != mender_client_callbacks.deployment_status) {
×
1233
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1234
    }
1235

1236
    return ret;
×
1237
}
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