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

mendersoftware / mender-mcu / 1565513544

29 Nov 2024 09:19AM UTC coverage: 9.235%. Remained the same
1565513544

push

gitlab-ci

danielskinstad
fix: fail deployment when it's aborted

Changelog: Title
Ticket: MEN-7693

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

0 of 11 new or added lines in 3 files covered. (0.0%)

219 existing lines in 3 files now uncovered.

251 of 2718 relevant lines covered (9.23%)

0.66 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

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

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

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

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

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

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

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

75
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
76

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

215
char *
216
mender_client_version(void) {
×
217

218
    /* Return version as string */
219
    return MENDER_CLIENT_VERSION;
×
220
}
221

222
mender_err_t
223
mender_client_init(mender_client_config_t *config, mender_client_callbacks_t *callbacks) {
×
224

225
    assert(NULL != config);
×
226
    assert(NULL != callbacks);
×
227
    assert(NULL != callbacks->restart);
×
228
    mender_err_t ret;
229

230
    /* Prefer client config over Kconfig */
231
    mender_client_config.device_type = IS_NULL_OR_EMPTY(config->device_type) ? CONFIG_MENDER_DEVICE_TYPE : config->device_type;
×
232
    if (IS_NULL_OR_EMPTY(mender_client_config.device_type)) {
×
233
        mender_log_error("Invalid device type configuration, can't be null or empty");
×
234
        ret = MENDER_FAIL;
×
235
        goto END;
×
236
    }
237
    mender_log_info("Device type: [%s]", mender_client_config.device_type);
×
238

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

269
    /* Save callbacks */
270
    memcpy(&mender_client_callbacks, callbacks, sizeof(mender_client_callbacks_t));
×
271

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

301
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
302
    if (MENDER_OK != (ret = mender_inventory_init(mender_client_config.inventory_update_interval))) {
303
        mender_log_error("Failed to initialize the inventory functionality");
304
        goto END;
305
    }
306
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
307

308
END:
×
309

310
    return ret;
×
311
}
312

313
mender_err_t
314
mender_client_activate(void) {
×
315
    mender_err_t ret;
316

317
    mender_scheduler_work_params_t work_params = {
×
318
        .function = mender_client_work_function,
319
        .period   = mender_client_config.update_poll_interval,
×
320
        .name     = "mender_client_main",
321
    };
322

323
    if ((MENDER_OK != (ret = mender_scheduler_work_create(&work_params, &mender_client_work)))
×
324
        || (MENDER_OK != (ret = mender_scheduler_work_activate(mender_client_work)))) {
×
325
        mender_log_error("Unable to activate the main work");
×
326
        return ret;
×
327
    }
328

329
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
330
    /* Activate inventory work */
331
    if (MENDER_OK != (ret = mender_inventory_activate())) {
332
        mender_log_error("Unable to activate the inventory functionality");
333
        return ret;
334
    }
335
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
336

337
    return ret;
×
338
}
339

340
mender_err_t
341
mender_client_ensure_connected(void) {
×
342
    if (mender_client_network_connected) {
×
343
        return MENDER_DONE;
×
344
    }
345

346
    return mender_client_network_connect();
×
347
}
348

349
static mender_err_t
350
mender_client_network_connect(void) {
×
351
    if (mender_client_network_connected) {
×
352
        return MENDER_OK;
×
353
    }
354

355
    /* Request network access */
356
    if (NULL != mender_client_callbacks.network_connect) {
×
357
        if (MENDER_OK != mender_client_callbacks.network_connect()) {
×
358
            mender_log_error("Unable to connect network");
×
359
            return MENDER_FAIL;
×
360
        }
361
    }
362

363
    mender_client_network_connected = true;
×
364

365
    return MENDER_OK;
×
366
}
367

368
static mender_err_t
369
mender_client_network_release(void) {
×
370
    if (!mender_client_network_connected) {
×
371
        return MENDER_OK;
×
372
    }
373

374
    /* Release network access */
375
    if (NULL != mender_client_callbacks.network_release) {
×
376
        if (MENDER_OK != mender_client_callbacks.network_release()) {
×
377
            mender_log_error("Unable to release network");
×
378
            return MENDER_FAIL;
×
379
        }
380
    }
381
    mender_client_network_connected = false;
×
382

383
    return MENDER_OK;
×
384
}
385

386
mender_err_t
387
mender_client_exit(void) {
×
388
    bool some_error = false;
×
389

390
    if (MENDER_OK != mender_scheduler_work_deactivate(mender_client_work)) {
×
391
        mender_log_error("Failed to deactivate main work");
×
392
        /* keep going on, we want to do as much cleanup as possible */
393
        some_error = true;
×
394
    }
395

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

404
    /* Stop scheduling new work */
405
    mender_scheduler_exit();
×
406

407
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
408
    if (MENDER_OK != mender_inventory_exit()) {
409
        mender_log_error("Unable to cleanup after the inventory functionality");
410
        /* keep going on, we want to do as much cleanup as possible */
411
        some_error = true;
412
    }
413
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
414

415
    /* Release all modules */
416
    mender_api_exit();
×
417
    mender_tls_exit();
×
418
    mender_storage_exit();
×
419
    mender_log_exit();
×
420
    mender_client_network_release();
×
421

422
    /* Release memory */
423
    mender_client_config.device_type          = NULL;
×
424
    mender_client_config.host                 = NULL;
×
425
    mender_client_config.tenant_token         = NULL;
×
426
    mender_client_config.update_poll_interval = 0;
×
427
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
428

429
    mender_update_module_unregister_all();
×
430

431
    return some_error ? MENDER_FAIL : MENDER_OK;
×
432
}
433

434
static mender_err_t
435
mender_client_work_function(void) {
×
436
    mender_log_debug("Inside work function [state: %d]", mender_client_state);
437

438
    switch (mender_client_state) {
×
439
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
×
440
            mender_log_info("Waiting for a reboot");
×
441
            /* nothing to do */
442
            return MENDER_OK;
×
443
        case MENDER_CLIENT_STATE_INITIALIZATION:
×
444
            /* Perform initialization of the client */
445
            if (MENDER_DONE != mender_client_initialization_work_function()) {
×
446
                return MENDER_FAIL;
×
447
            }
448
            mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
449
            /* fallthrough */
450
        case MENDER_CLIENT_STATE_OPERATIONAL:
×
451
            return mender_client_update_work_function();
×
452
    }
453

454
    /* This should never be reached, all the cases should be covered in the
455
       above switch and they all return. */
456
    return MENDER_FAIL;
×
457
}
458

459
static mender_err_t
460
mender_client_initialization_work_function(void) {
×
461

462
    mender_err_t ret = MENDER_DONE;
×
463

464
    /* Retrieve or generate authentication keys */
465
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
×
466
        mender_log_error("Unable to retrieve or generate authentication keys");
×
467
        goto END;
×
468
    }
469

470
    /* Retrieve deployment data if it is found (following an update) */
471
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
×
472
        if (MENDER_NOT_FOUND != ret) {
×
473
            mender_log_error("Unable to get deployment data");
×
474
            goto REBOOT;
×
475
        }
476
    }
477

478
    mender_log_info("Initialization done");
×
479

480
    return MENDER_DONE;
×
481

482
END:
×
483

484
    return ret;
×
485

486
REBOOT:
×
487

488
    mender_log_info("Rebooting...");
×
489

490
    /* Delete pending deployment */
491
    mender_storage_delete_deployment_data();
×
492

493
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
494
    if (NULL != mender_client_callbacks.restart) {
×
495
        mender_client_callbacks.restart();
×
496
    }
497

498
    return ret;
×
499
}
500

501
static mender_err_t
502
mender_commit_artifact_data(void) {
×
503

504
    assert(NULL != mender_client_deployment_data);
×
505

506
    const char *artifact_name;
507
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
508
        mender_log_error("Unable to get artifact name from the deployment data");
×
509
        return MENDER_FAIL;
×
510
    }
511

512
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
513
        mender_log_error("Unable to set artifact name");
×
514
        return MENDER_FAIL;
×
515
    }
516

517
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
518
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
519
    /* Get provides from the deployment data */
520
    const char *provides;
521
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
×
522
        mender_log_error("Unable to get new_provides from the deployment data");
×
523
        return MENDER_FAIL;
×
524
    }
525

526
    /* Parse provides */
527
    mender_key_value_list_t *new_provides = NULL;
×
528
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
×
529
        mender_log_error("Unable to parse provides from the deployment data");
×
530
        return MENDER_FAIL;
×
531
    }
532
    /* Replace the stored provides with the new provides */
533
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
×
534
        mender_log_error("Unable to set provides");
×
535
        mender_utils_key_value_list_free(new_provides);
×
536
        return MENDER_FAIL;
×
537
    }
538
    mender_utils_key_value_list_free(new_provides);
×
539
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
540
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
541

542
    return MENDER_OK;
×
543
}
544

545
static mender_err_t
546
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
547
    if (NULL != deployment) {
×
548
        free(deployment->id);
×
549
        free(deployment->artifact_name);
×
550
        free(deployment->uri);
×
551
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
552
            free(deployment->device_types_compatible[i]);
×
553
        }
554
        free(deployment->device_types_compatible);
×
555
        free(deployment);
×
556
    }
557
    return MENDER_OK;
×
558
}
559

560
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
561
static mender_err_t
562
mender_compare_device_types(const char  *device_type_artifact,
×
563
                            const char  *device_type_device,
564
                            const char **device_type_deployment,
565
                            const size_t device_type_deployment_size) {
566

567
    assert(NULL != device_type_artifact);
×
568
    assert(NULL != device_type_deployment);
×
569
    assert(NULL != device_type_device);
×
570
    assert(0 < device_type_deployment_size);
×
571

572
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
573
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
574
        return MENDER_FAIL;
×
575
    }
576

577
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
578
    for (size_t i = 0; i < device_type_deployment_size; i++) {
×
579
        if (StringEqual(device_type_deployment[i], device_type_device)) {
×
580
            return MENDER_OK;
×
581
        }
582
    }
583
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
584
    return MENDER_FAIL;
×
585
}
586

587
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
588
static mender_err_t
589
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
590

591
    mender_err_t ret = MENDER_FAIL;
×
592
    /* Clears provides */
593
    bool matches;
594
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
595
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
×
596
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
×
597
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
×
598
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
599
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
600
                    goto END;
×
601
                }
602
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
603
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
604
                    goto END;
×
605
                }
606
            }
607
        }
608
    }
609

610
    /* Combine the stored provides with the new ones */
611
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
612
        mender_log_error("Unable to merge provides");
×
613
        goto END;
×
614
    }
615

616
    /* Make sure the artifact name is not in the new provides */
617
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
618
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
619
        goto END;
×
620
    }
621

622
    ret = MENDER_OK;
×
623

624
END:
×
625

626
    mender_utils_key_value_list_free(*stored_provides);
×
627
    return ret;
×
628
}
629

630
static mender_err_t
631
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
632

633
    assert(NULL != artifact_name);
×
634
    assert(NULL != mender_artifact_ctx);
×
635

636
    /* Load the currently stored provides */
637
    mender_key_value_list_t *stored_provides = NULL;
×
638
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
639
        mender_log_error("Unable to get provides");
×
640
        return MENDER_FAIL;
×
641
    }
642

643
    mender_key_value_list_t *provides = NULL;
×
644
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
645
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
646
            mender_log_error("Unable to merge provides");
×
647
            mender_utils_key_value_list_free(stored_provides);
×
648
            return MENDER_FAIL;
×
649
        }
650
    }
651

652
    /* Get artifact name from provides */
653
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
654
        if (StringEqual("artifact_name", item->key)) {
×
655
            *artifact_name = item->value;
×
656
            break;
×
657
        }
658
    }
659

660
    if (NULL == *artifact_name) {
×
661
        mender_log_error("No artifact name found in provides");
×
662
        mender_utils_key_value_list_free(stored_provides);
×
663
        return MENDER_FAIL;
×
664
    }
665

666
    /* Filter provides */
667
    /* `stored_provides` is freed in `mender_filter_provides` */
668
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
669
        return MENDER_FAIL;
×
670
    }
671

672
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
673
        return MENDER_FAIL;
×
674
    }
675

676
    return MENDER_OK;
×
677
}
678

679
static mender_err_t
680
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
681

682
    /* We need to load the stored provides */
683
    mender_key_value_list_t *stored_provides = NULL;
×
684
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
685
        return MENDER_FAIL;
×
686
    }
687

688
    mender_err_t ret = MENDER_FAIL;
×
689

690
    /* Get depends */
691
    mender_key_value_list_t *depends = NULL;
×
692
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
693
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
694
            mender_log_error("Unable to append depends");
×
695
            goto END;
×
696
        }
697
    }
698

699
    /* Match depends from artifact with device's provides */
700
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
×
701
        bool matches = false;
×
702
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
703
            /* Match key-value from depends with provides */
704
            if (StringEqual(depends_item->key, provides_item->key)) {
×
705
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
706
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
707
                                     depends_item->key,
708
                                     depends_item->value,
709
                                     provides_item->value);
710
                    break;
×
711
                }
712
                matches = true;
×
713
                break;
×
714
            }
715
        }
716
        if (!matches) {
×
717
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
718
            goto END;
×
719
        }
720
    }
721

722
    ret = MENDER_OK;
×
723

724
END:
×
725
    mender_utils_key_value_list_free(stored_provides);
×
726
    return ret;
×
727
}
728
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
729
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
730

731
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
732
static mender_err_t
733
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
734
    mender_err_t ret;
735

736
    /* Retrieve device type from artifact */
737
    const char *device_type_artifact = NULL;
×
738
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
739
        mender_log_error("Unable to get device type from artifact");
×
740
        return ret;
×
741
    }
742

743
    mender_log_debug("Checking device type compatibility");
744

745
    /* Match device type  */
746
    if (MENDER_OK
×
747
        != (ret = mender_compare_device_types(device_type_artifact,
×
748
                                              mender_client_config.device_type,
×
749
                                              (const char **)deployment->device_types_compatible,
×
750
                                              deployment->device_types_compatible_size))) {
751
        return ret;
×
752
    }
753

754
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
755
    /* Compare Artifact's depends with the stored provides */
756
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
757
        return ret;
×
758
    }
759
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
760

761
    /* Check artifact integrity by comparing computed checksums with those
762
     * listed in the artifacts manifest */
763
    if (MENDER_OK != mender_artifact_check_integrity(mender_artifact_ctx)) {
×
764
        return MENDER_FAIL;
×
765
    }
766

767
    return MENDER_OK;
×
768
}
769
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
770

771
static mender_err_t
772
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
773
    assert(NULL != deployment_data);
×
774

775
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
776
        /* network errors logged already */
777
        mender_log_error("Cannot check for new deployment");
×
778
        return MENDER_FAIL;
×
779
    }
780

781
    if (NULL == (*deployment_data = calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
782
        mender_log_error("Unable to allocate memory for deployment data");
×
783
        return MENDER_FAIL;
×
784
    }
785

786
    mender_api_deployment_data_t *deployment = *deployment_data;
×
787

788
    mender_err_t ret = MENDER_OK;
×
789

790
    mender_log_info("Checking for deployment...");
×
791
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
792
        mender_log_info("No deployment available");
×
793
        return MENDER_DONE;
×
794
    } else if (MENDER_OK != ret) {
×
795
        mender_log_error("Unable to check for deployment");
×
796
        return MENDER_FAIL;
×
797
    }
798

799
    /* Check if deployment is valid */
800
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
801
        mender_log_error("Invalid deployment data");
×
802
        return MENDER_FAIL;
×
803
    }
804

805
    /* Create deployment data */
806
    if (NULL != mender_client_deployment_data) {
×
807
        mender_log_warning("Unexpected stale deployment data");
×
808
        mender_delete_deployment_data(mender_client_deployment_data);
×
809
    }
810
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
811
        /* Error already logged */
812
        return MENDER_FAIL;
×
813
    }
814

815
    return MENDER_OK;
×
816
}
817

818
static mender_err_t
819
set_and_store_state(const mender_update_state_t state) {
×
820

821
    /*
822
     * Set the state in `mender_client_deployment_data` and write it to the nvs
823
     */
824

825
    mender_err_t ret = MENDER_OK;
×
826

827
    /* Set state in deployment data */
828
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
829
        mender_log_error("Failed to set deployment data state");
×
830
        return ret;
×
831
    }
832

833
    /* Store deployment data */
834
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
835
        mender_log_error("Failed to store deployment data");
×
836
        return ret;
×
837
    }
838
    return ret;
×
839
}
840

841
static mender_err_t
842
mender_client_update_work_function(void) {
×
843
    mender_err_t ret = MENDER_OK;
×
844

845
    /* Ensure that the context is initialized to NULL before goto END */
846
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
847

848
    /* Check for deployment */
849
    mender_api_deployment_data_t *deployment    = NULL;
×
850
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
851
    const char                   *deployment_id = NULL;
×
852

853
    /* reset the currently used update module */
854
    mender_update_module = NULL;
×
855

856
    if (NULL != mender_client_deployment_data) {
×
857
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
858
    }
859

860
    {
861
        const char           *artifact_type;
862
        mender_update_state_t update_state_resume;
863
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
×
864
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
×
865
            update_state = update_state_resume;
×
866
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
867
            mender_update_module = mender_update_module_get(artifact_type);
×
868
            if (NULL == mender_update_module) {
×
869
                /* The artifact_type from the saved state does not match any update module */
870
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
871
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
872
                mender_storage_delete_deployment_data();
×
873
                goto END;
×
874
            }
875
        }
876
    }
877

878
    /* Skip the block below if we just resume from a saved state. */
879

880
/* A macro to advance to the next state -- on success we just keep going to the
881
 * code below the macro invocation (fallthrough to the next case), on error we
882
 * go to the beginning of the loop (the switch statement) again using 'continue'
883
 * (see below).
884
 *
885
 * mender_update_module is guaranteed be not NULL since the first
886
 * successful transition (from the DOWNLOAD state). */
887
#define NEXT_STATE                                                             \
888
    if (MENDER_OK == ret) {                                                    \
889
        update_state = update_state_transitions[update_state].success;         \
890
        assert(NULL != mender_update_module);                                  \
891
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
892
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
893
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
894
        }                                                                      \
895
    } else {                                                                   \
896
        update_state = update_state_transitions[update_state].failure;         \
897
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
898
        if (NULL != mender_update_module) {                                    \
899
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
900
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
901
            }                                                                  \
902
        }                                                                      \
903
        ret = MENDER_OK;                                                       \
904
        continue;                                                              \
905
    }
906

907
    while (MENDER_UPDATE_STATE_END != update_state) {
×
908
        switch (update_state) {
×
909
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
910

911
                /* Check for deployment */
912
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
913
                    /* No deployment available, but we are not done, we need to keep checking. */
914
                    if (MENDER_DONE == ret) {
×
915
                        ret = MENDER_OK;
×
916
                    }
917
                    goto END;
×
918
                }
919

920
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
921
                if (strlen(deployment->id) > 10) {
×
922
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
923
                } else {
924
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
925
                }
926
#endif
927
                /* Set deployment_id */
928
                deployment_id = deployment->id;
×
929

930
                /* Check ret to see if the deployment is aborted */
NEW
931
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
NEW
932
                if ((MENDER_ABORTED != ret)
×
NEW
933
                    && (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module)))) {
×
934
                    assert(NULL != mender_update_module);
×
935

936
                    /* Get artifact context if artifact download succeeded */
UNCOV
937
                    if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) {
×
938
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
UNCOV
939
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
×
940
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
941
                            /* Add the new provides to the deployment data (we need the artifact context) */
UNCOV
942
                            char       *new_provides  = NULL;
×
943
                            const char *artifact_name = NULL;
×
944
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
×
945
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
×
946
                                    mender_log_error("Failed to set deployment data provides");
×
947
                                }
948
                                /* Replace artifact_name with the one from provides */
UNCOV
949
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
×
950
                                    mender_log_error("Failed to set deployment data artifact name");
×
951
                                }
UNCOV
952
                                free(new_provides);
×
953
                            } else {
UNCOV
954
                                mender_log_error("Unable to prepare new provides");
×
955
                            }
956
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
957
                        }
958
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
959
                    } else {
UNCOV
960
                        mender_log_error("Unable to get artifact type and context");
×
961
                    }
962
                } else {
UNCOV
963
                    mender_log_error("Unable to download artifact");
×
964
                    if (NULL == mender_update_module) {
×
965
                        /* Error logged in mender_client_download_artifact_callback() */
UNCOV
966
                        mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
967
                        goto END;
×
968
                    }
969
                }
UNCOV
970
                NEXT_STATE;
×
971
                /* fallthrough */
972

973
            case MENDER_UPDATE_STATE_INSTALL:
UNCOV
974
                mender_log_info("Download done, installing artifact");
×
975
                /* Check ret to see if the deployment is aborted */
NEW
976
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
×
NEW
977
                if ((MENDER_ABORTED != ret) && NULL != mender_update_module->callbacks[update_state]) {
×
978
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
979
                }
980
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
×
981
                    /* skip reboot */
982
                    update_state = MENDER_UPDATE_STATE_COMMIT;
×
UNCOV
983
                    set_and_store_state(update_state);
×
984
                    continue;
×
985
                }
986
                /* else continue to the next successful/failure state */
UNCOV
987
                NEXT_STATE;
×
988
                /* fallthrough */
989

990
            case MENDER_UPDATE_STATE_REBOOT:
UNCOV
991
                assert(mender_update_module->requires_reboot);
×
UNCOV
992
                mender_log_info("Artifact installation done, rebooting");
×
993
                /* Check ret to see if the deployment is aborted */
NEW
994
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
×
NEW
995
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
996
                    /* Save the next state before running the reboot callback --
997
                     * if there is an interrupt (power, crash,...) right after,
998
                     * it will reboot anyway so after the new boot, reboot
999
                     * verification should happen anyway, the callback in that
1000
                     * state should be able to see if things went well or
1001
                     * wrong. */
UNCOV
1002
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
×
UNCOV
1003
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
UNCOV
1004
                    if (MENDER_OK == ret) {
×
1005
                        /* now we need to get outside of the loop so that a
1006
                         * potential asynchronous reboot has a chance to kick in
1007
                         * after a proper cleanup below */
UNCOV
1008
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
UNCOV
1009
                        ret                 = MENDER_DONE;
×
UNCOV
1010
                        goto END;
×
1011
                    }
1012
                }
1013
                NEXT_STATE;
×
1014
                /* fallthrough */
1015

1016
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
UNCOV
1017
                assert(mender_update_module->requires_reboot);
×
UNCOV
1018
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1019
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1020
                }
1021
                NEXT_STATE;
×
1022
                /* fallthrough */
1023

1024
            case MENDER_UPDATE_STATE_COMMIT:
1025
                /* Check for pending deployment */
UNCOV
1026
                if (NULL == mender_client_deployment_data) {
×
UNCOV
1027
                    mender_log_error("No deployment data found on commit");
×
UNCOV
1028
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1029
                    goto END;
×
1030
                }
1031
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1032
                if (MENDER_OK != mender_api_drop_authentication_data()) {
×
UNCOV
1033
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1034
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1035
                       much to about it. */
1036
                }
UNCOV
1037
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
×
UNCOV
1038
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1039
                }
1040
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
1041
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
×
UNCOV
1042
                    mender_log_error("Unable to commit artifact data");
×
1043
                }
1044
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1045
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1046
                }
1047
                if (!MENDER_IS_ERROR(ret)) {
×
1048
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
×
1049
                }
1050
                NEXT_STATE;
×
1051
                /* fallthrough */
1052

1053
            case MENDER_UPDATE_STATE_CLEANUP:
UNCOV
1054
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1055
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1056
                }
1057
                NEXT_STATE;
×
1058
                mender_storage_delete_deployment_data();
×
UNCOV
1059
                break; /* below is the failure path */
×
1060

1061
            case MENDER_UPDATE_STATE_ROLLBACK:
×
1062
                if (!mender_update_module->supports_rollback) {
×
UNCOV
1063
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
×
1064
                    ret = MENDER_FAIL;
×
1065
                } else if (NULL != mender_update_module->callbacks[update_state]) {
×
1066
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1067
                }
1068
                NEXT_STATE;
×
1069
                /* fallthrough */
1070

1071
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1072
                /* Save the next state before running the reboot callback (see
1073
                 * STATE_REBOOT for details). */
UNCOV
1074
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
UNCOV
1075
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1076

1077
                if (MENDER_OK == ret) {
×
1078
                    /* now we need to get outside of the loop so that a
1079
                     * potential asynchronous reboot has a chance to kick in
1080
                     * after a proper cleanup below */
UNCOV
1081
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
UNCOV
1082
                    ret                 = MENDER_DONE;
×
UNCOV
1083
                    goto END;
×
1084
                }
1085
                NEXT_STATE;
×
1086
                /* fallthrough */
1087

1088
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
UNCOV
1089
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1090
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1091
                }
1092

1093
                if (MENDER_OK != ret) {
×
1094
                    /* If the rollback verify reboot fails,
1095
                     * we will retry the rollback reboot.
1096
                     *
1097
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1098
                     * loop is broken when a state loop is detected
1099
                     */
UNCOV
1100
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
×
1101
                }
1102

1103
                NEXT_STATE;
×
1104
                /* fallthrough */
1105

1106
            case MENDER_UPDATE_STATE_FAILURE:
UNCOV
1107
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
UNCOV
1108
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1109
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1110
                }
1111
                NEXT_STATE;
×
1112
                break; /* end of the failure path */
×
1113

1114
            case MENDER_UPDATE_STATE_END:
×
1115
                /* This is only here to cover all possible values of the
1116
                 * update_state enum, there is nothing to do here, the while
1117
                 * loop shall stop when we get here. */
UNCOV
1118
                break;
×
1119
        }
1120
    }
1121
#undef NEXT_STATE /* should not be used anywhere else */
1122

UNCOV
1123
    ret = MENDER_OK;
×
1124

UNCOV
1125
END:
×
1126
    /* Release memory */
UNCOV
1127
    deployment_destroy(deployment);
×
1128
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
UNCOV
1129
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1130

1131
    return ret;
×
1132
}
1133

1134
static mender_err_t
UNCOV
1135
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
UNCOV
1136
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1137
        /* connection errors logged already */
1138
        mender_log_error("Cannot publish deployment status");
×
1139
        return MENDER_FAIL;
×
1140
    }
1141

1142
    mender_err_t ret;
1143

UNCOV
1144
    if (NULL == id) {
×
UNCOV
1145
        mender_log_error("Cannot publish deployment status: unknown status");
×
UNCOV
1146
        return MENDER_FAIL;
×
1147
    }
1148

1149
    /* Publish status to the mender server */
UNCOV
1150
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1151

1152
    /* Invoke deployment status callback if defined */
1153
    if (NULL != mender_client_callbacks.deployment_status) {
×
UNCOV
1154
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1155
    }
1156

1157
    return ret;
×
1158
}
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