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

mendersoftware / mender-mcu / 1570959687

03 Dec 2024 01:28PM UTC coverage: 25.126% (-0.4%) from 25.487%
1570959687

push

gitlab-ci

danielskinstad
test: unit tests for mender-artifact

Ticket: MEN-7683

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

697 of 2774 relevant lines covered (25.13%)

6.13 hits per line

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

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

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

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

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

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

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

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

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

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

76
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
77

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

223
char *
224
mender_client_version(void) {
×
225

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

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

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

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

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

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

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

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

316
END:
×
317

318
    return ret;
×
319
}
320

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

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

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

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

345
    return ret;
×
346
}
347

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

354
    return mender_client_network_connect();
×
355
}
356

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

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

371
    mender_client_network_connected = true;
×
372

373
    return MENDER_OK;
×
374
}
375

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

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

391
    return MENDER_OK;
×
392
}
393

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

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

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

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

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

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

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

437
    mender_update_module_unregister_all();
×
438

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

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

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

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

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

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

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

514
static mender_err_t
515
mender_client_initialization_work_function(void) {
×
516

517
    mender_err_t ret = MENDER_DONE;
×
518

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

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

533
    mender_log_info("Initialization done");
×
534

535
    return MENDER_DONE;
×
536

537
END:
×
538

539
    return ret;
×
540

541
REBOOT:
×
542

543
    mender_log_info("Rebooting...");
×
544

545
    /* Delete pending deployment */
546
    mender_storage_delete_deployment_data();
×
547

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

553
    return ret;
×
554
}
555

556
static mender_err_t
557
mender_commit_artifact_data(void) {
×
558

559
    assert(NULL != mender_client_deployment_data);
×
560

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

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

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

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

597
    return MENDER_OK;
×
598
}
599

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

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

622
    assert(NULL != device_type_artifact);
×
623
    assert(NULL != device_type_deployment);
×
624
    assert(NULL != device_type_device);
×
625
    assert(0 < device_type_deployment_size);
×
626

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

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

642
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
643
static mender_err_t
644
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
645

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

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

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

677
    ret = MENDER_OK;
×
678

679
END:
×
680

681
    mender_utils_key_value_list_free(*stored_provides);
×
682
    return ret;
×
683
}
684

685
static mender_err_t
686
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
687

688
    assert(NULL != artifact_name);
×
689
    assert(NULL != mender_artifact_ctx);
×
690

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

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

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

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

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

727
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
728
        return MENDER_FAIL;
×
729
    }
730

731
    return MENDER_OK;
×
732
}
733

734
static mender_err_t
735
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
736

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

743
    mender_err_t ret = MENDER_FAIL;
×
744

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

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

777
    ret = MENDER_OK;
×
778

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

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

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

798
    mender_log_debug("Checking device type compatibility");
799

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

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

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

822
    return MENDER_OK;
×
823
}
824
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
825

826
static mender_err_t
827
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
828
    assert(NULL != deployment_data);
×
829

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

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

841
    mender_api_deployment_data_t *deployment = *deployment_data;
×
842

843
    mender_err_t ret = MENDER_OK;
×
844

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

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

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

870
    return MENDER_OK;
×
871
}
872

873
static mender_err_t
874
set_and_store_state(const mender_update_state_t state) {
×
875

876
    /*
877
     * Set the state in `mender_client_deployment_data` and write it to the nvs
878
     */
879

880
    mender_err_t ret = MENDER_OK;
×
881

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

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

896
static mender_err_t
897
mender_client_update_work_function(void) {
×
898
    mender_err_t ret = MENDER_OK;
×
899

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

903
    /* Check for deployment */
904
    mender_api_deployment_data_t *deployment    = NULL;
×
905
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
906
    const char                   *deployment_id = NULL;
×
907

908
    /* reset the currently used update module */
909
    mender_update_module = NULL;
×
910

911
    if (NULL != mender_client_deployment_data) {
×
912
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
913
    }
914

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

933
    /* Skip the block below if we just resume from a saved state. */
934

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

962
    while (MENDER_UPDATE_STATE_END != update_state) {
×
963
        switch (update_state) {
×
964
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
965

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

975
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
976
                if (strlen(deployment->id) > 10) {
×
977
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
978
                } else {
979
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
980
                }
981
#endif
982
                /* Set deployment_id */
983
                deployment_id = deployment->id;
×
984

985
                /* Check ret to see if the deployment is aborted */
986
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
987
                if ((MENDER_ABORTED != ret)
×
988
                    && (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module)))) {
×
989
                    assert(NULL != mender_update_module);
×
990

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

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

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

1071
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1072
                assert(mender_update_module->requires_reboot);
×
1073
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1074
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1075
                }
1076
                NEXT_STATE;
×
1077
                /* fallthrough */
1078

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

1108
            case MENDER_UPDATE_STATE_CLEANUP:
1109
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1110
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1111
                }
1112
                NEXT_STATE;
×
1113
                mender_storage_delete_deployment_data();
×
1114
                break; /* below is the failure path */
×
1115

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

1126
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1127
                /* Save the next state before running the reboot callback (see
1128
                 * STATE_REBOOT for details). */
1129
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
1130
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1131

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

1143
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1144
                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

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

1158
                NEXT_STATE;
×
1159
                /* fallthrough */
1160

1161
            case MENDER_UPDATE_STATE_FAILURE:
1162
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1163
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1164
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1165
                }
1166
                NEXT_STATE;
×
1167
                break; /* end of the failure path */
×
1168

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

1178
    ret = MENDER_OK;
×
1179

1180
END:
×
1181
    /* Release memory */
1182
    deployment_destroy(deployment);
×
1183
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
1184
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1185

1186
    return ret;
×
1187
}
1188

1189
static mender_err_t
1190
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
1191
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1192
        /* connection errors logged already */
1193
        mender_log_error("Cannot publish deployment status");
×
1194
        return MENDER_FAIL;
×
1195
    }
1196

1197
    mender_err_t ret;
1198

1199
    if (NULL == id) {
×
1200
        mender_log_error("Cannot publish deployment status: unknown status");
×
1201
        return MENDER_FAIL;
×
1202
    }
1203

1204
    /* Publish status to the mender server */
1205
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1206

1207
    /* Invoke deployment status callback if defined */
1208
    if (NULL != mender_client_callbacks.deployment_status) {
×
1209
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1210
    }
1211

1212
    return ret;
×
1213
}
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