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

mendersoftware / mender-mcu / 1526166760

04 Nov 2024 01:32PM UTC coverage: 1.176% (+0.001%) from 1.175%
1526166760

push

gitlab-ci

vpodzime
fix: Only return MENDER_DONE from update_work_function() when rebooting

Returning `MENDER_DONE` from
`mender_client_update_work_function()` signals it's done and
should not be scheduled again. And we only want to do that when
waiting for a reboot (if we have to wait).

`mender_client_check_deployment()` returns `MENDER_DONE` in case
there is no deployment so we need to translate that to
`MENDER_OK` signalling we are ok to proceed and check again next
time.

Ticket: MEN-7536
Changelog: none
Signed-off-by: Vratislav Podzimek <vratislav.podzimek@northern.tech>

0 of 3 new or added lines in 1 file covered. (0.0%)

142 existing lines in 2 files now uncovered.

31 of 2637 relevant lines covered (1.18%)

0.32 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
    };
295
    if (MENDER_OK != (ret = mender_api_init(&mender_api_config))) {
×
296
        mender_log_error("Unable to initialize API");
×
297
        goto END;
×
298
    }
299

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

307
END:
×
308

309
    return ret;
×
310
}
311

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

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

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

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

336
    return ret;
×
337
}
338

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

345
    return mender_client_network_connect();
×
346
}
347

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

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

362
    mender_client_network_connected = true;
×
363

364
    return MENDER_OK;
×
365
}
366

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

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

382
    return MENDER_OK;
×
383
}
384

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

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

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

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

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

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

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

428
    mender_update_module_unregister_all();
×
429

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

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

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

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

458
static mender_err_t
459
mender_client_initialization_work_function(void) {
×
460

461
    mender_err_t ret = MENDER_DONE;
×
462

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

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

477
    mender_log_info("Initialization done");
×
478

479
    return MENDER_DONE;
×
480

481
END:
×
482

483
    return ret;
×
484

485
REBOOT:
×
486

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

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

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

497
    return ret;
×
498
}
499

500
static mender_err_t
501
mender_commit_artifact_data(void) {
×
502

503
    assert(NULL != mender_client_deployment_data);
×
504

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

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

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

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

541
    return MENDER_OK;
×
542
}
543

544
mender_err_t
545
mender_client_ensure_authenticated(void) {
×
546
    if (mender_api_is_authenticated()) {
×
547
        return MENDER_DONE;
×
548
    }
549

550
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
551
        return MENDER_FAIL;
×
552
    }
553

554
    /* Perform authentication with the mender server */
555
    if (MENDER_OK != mender_api_perform_authentication(mender_client_callbacks.get_identity)) {
×
556
        mender_log_error("Authentication failed");
×
557
        return MENDER_FAIL;
×
558
    }
559

560
    mender_log_debug("Authenticated successfully");
561
    return MENDER_OK;
×
562
}
563

564
static mender_err_t
565
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
566
    if (NULL != deployment) {
×
567
        free(deployment->id);
×
568
        free(deployment->artifact_name);
×
569
        free(deployment->uri);
×
570
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
571
            free(deployment->device_types_compatible[i]);
×
572
        }
573
        free(deployment->device_types_compatible);
×
574
        free(deployment);
×
575
    }
576
    return MENDER_OK;
×
577
}
578

579
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
580
static mender_err_t
581
mender_compare_device_types(const char  *device_type_artifact,
×
582
                            const char  *device_type_device,
583
                            const char **device_type_deployment,
584
                            const size_t device_type_deployment_size) {
585

586
    assert(NULL != device_type_artifact);
×
587
    assert(NULL != device_type_deployment);
×
588
    assert(NULL != device_type_device);
×
589
    assert(0 < device_type_deployment_size);
×
590

591
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
592
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
593
        return MENDER_FAIL;
×
594
    }
595

596
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
597
    for (size_t i = 0; i < device_type_deployment_size; i++) {
×
598
        if (StringEqual(device_type_deployment[i], device_type_device)) {
×
599
            return MENDER_OK;
×
600
        }
601
    }
602
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
603
    return MENDER_FAIL;
×
604
}
605

606
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
607
static mender_err_t
608
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
609

610
    mender_err_t ret = MENDER_FAIL;
×
611
    /* Clears provides */
612
    bool matches;
613
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
614
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
×
615
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
×
616
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
×
617
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
618
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
619
                    goto END;
×
620
                }
621
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
622
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
623
                    goto END;
×
624
                }
625
            }
626
        }
627
    }
628

629
    /* Combine the stored provides with the new ones */
630
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
631
        mender_log_error("Unable to merge provides");
×
632
        goto END;
×
633
    }
634

635
    /* Make sure the artifact name is not in the new provides */
636
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
637
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
638
        goto END;
×
639
    }
640

641
    ret = MENDER_OK;
×
642

643
END:
×
644

645
    mender_utils_free_linked_list(*stored_provides);
×
646
    return ret;
×
647
}
648

649
static mender_err_t
650
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
651

652
    assert(NULL != artifact_name);
×
653
    assert(NULL != mender_artifact_ctx);
×
654

655
    /* Load the currently stored provides */
656
    mender_key_value_list_t *stored_provides = NULL;
×
657
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
658
        mender_log_error("Unable to get provides");
×
659
        return MENDER_FAIL;
×
660
    }
661

662
    mender_key_value_list_t *provides = NULL;
×
663
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
664
        if (MENDER_OK != mender_utils_append_list(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
665
            mender_log_error("Unable to merge provides");
×
666
            mender_utils_free_linked_list(stored_provides);
×
667
            return MENDER_FAIL;
×
668
        }
669
    }
670

671
    /* Get artifact name from provides */
672
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
673
        if (StringEqual("artifact_name", item->key)) {
×
674
            *artifact_name = item->value;
×
675
            break;
×
676
        }
677
    }
678

679
    if (NULL == *artifact_name) {
×
680
        mender_log_error("No artifact name found in provides");
×
681
        mender_utils_free_linked_list(stored_provides);
×
682
        return MENDER_FAIL;
×
683
    }
684

685
    /* Filter provides */
686
    /* `stored_provides` is freed in `mender_filter_provides` */
687
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
688
        return MENDER_FAIL;
×
689
    }
690

691
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
692
        return MENDER_FAIL;
×
693
    }
694

695
    return MENDER_OK;
×
696
}
697

698
static mender_err_t
699
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
700

701
    /* We need to load the stored provides */
702
    mender_key_value_list_t *stored_provides = NULL;
×
703
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
704
        return MENDER_FAIL;
×
705
    }
706

707
    mender_err_t ret = MENDER_FAIL;
×
708

709
    /* Get depends */
710
    mender_key_value_list_t *depends = NULL;
×
711
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
712
        if (MENDER_OK != mender_utils_append_list(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
713
            mender_log_error("Unable to append depends");
×
714
            goto END;
×
715
        }
716
    }
717

718
    /* Match depends from artifact with device's provides */
719
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
×
720
        bool matches = false;
×
721
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
722
            /* Match key-value from depends with provides */
723
            if (StringEqual(depends_item->key, provides_item->key)) {
×
724
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
725
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
726
                                     depends_item->key,
727
                                     depends_item->value,
728
                                     provides_item->value);
729
                    break;
×
730
                }
731
                matches = true;
×
732
                break;
×
733
            }
734
        }
735
        if (!matches) {
×
736
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
737
            goto END;
×
738
        }
739
    }
740

741
    ret = MENDER_OK;
×
742

743
END:
×
744
    mender_utils_free_linked_list(stored_provides);
×
745
    return ret;
×
746
}
747
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
748
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
749

750
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
751
static mender_err_t
752
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
753
    mender_err_t ret;
754

755
    /* Retrieve device type from artifact */
756
    const char *device_type_artifact = NULL;
×
757
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
758
        mender_log_error("Unable to get device type from artifact");
×
759
        return ret;
×
760
    }
761

762
    mender_log_debug("Checking device type compatibility");
763

764
    /* Match device type  */
765
    if (MENDER_OK
×
766
        != (ret = mender_compare_device_types(device_type_artifact,
×
767
                                              mender_client_config.device_type,
×
768
                                              (const char **)deployment->device_types_compatible,
×
769
                                              deployment->device_types_compatible_size))) {
770
        return ret;
×
771
    }
772

773
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
774
    /* Compare Artifact's depends with the stored provides */
775
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
776
        return ret;
×
777
    }
778
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
779

780
    /* Check artifact integrity by comparing computed checksums with those
781
     * listed in the artifacts manifest */
782
    if (MENDER_OK != mender_artifact_check_integrity(mender_artifact_ctx)) {
×
783
        return MENDER_FAIL;
×
784
    }
785

786
    return MENDER_OK;
×
787
}
788
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
789

790
static mender_err_t
791
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
792
    assert(NULL != deployment_data);
×
793

794
    if (MENDER_FAIL == mender_client_ensure_authenticated()) {
×
795
        /* authentication errors logged already */
796
        mender_log_error("Cannot check for new deployment");
×
797
        return MENDER_FAIL;
×
798
    }
799

800
    if (NULL == (*deployment_data = calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
801
        mender_log_error("Unable to allocate memory for deployment data");
×
802
        return MENDER_FAIL;
×
803
    }
804

805
    mender_api_deployment_data_t *deployment = *deployment_data;
×
806

807
    mender_err_t ret = MENDER_OK;
×
808

809
    mender_log_info("Checking for deployment...");
×
810
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
811
        mender_log_info("No deployment available");
×
812
        return MENDER_DONE;
×
813
    } else if (MENDER_OK != ret) {
×
814
        mender_log_error("Unable to check for deployment");
×
815
        return MENDER_FAIL;
×
816
    }
817

818
    /* Check if deployment is valid */
819
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
820
        mender_log_error("Invalid deployment data");
×
821
        return MENDER_FAIL;
×
822
    }
823

824
    /* Create deployment data */
825
    if (NULL != mender_client_deployment_data) {
×
826
        mender_log_warning("Unexpected stale deployment data");
×
827
        mender_delete_deployment_data(mender_client_deployment_data);
×
828
    }
829
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
830
        /* Error already logged */
831
        return MENDER_FAIL;
×
832
    }
833

834
    return MENDER_OK;
×
835
}
836

837
static mender_err_t
838
set_and_store_state(const mender_update_state_t state) {
×
839

840
    /*
841
     * Set the state in `mender_client_deployment_data` and write it to the nvs
842
     */
843

844
    mender_err_t ret = MENDER_OK;
×
845

846
    /* Set state in deployment data */
847
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
848
        mender_log_error("Failed to set deployment data state");
×
849
        return ret;
×
850
    }
851

852
    /* Store deployment data */
853
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
854
        mender_log_error("Failed to store deployment data");
×
855
        return ret;
×
856
    }
857
    return ret;
×
858
}
859

860
static mender_err_t
861
mender_client_update_work_function(void) {
×
862
    mender_err_t ret = MENDER_OK;
×
863

864
    /* Ensure that the context is initialized to NULL before goto END */
865
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
866

867
    /* Check for deployment */
868
    mender_api_deployment_data_t *deployment    = NULL;
×
869
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
870
    const char                   *deployment_id = NULL;
×
871

872
    /* reset the currently used update module */
873
    mender_update_module = NULL;
×
874

875
    if (NULL != mender_client_deployment_data) {
×
876
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
877
    }
878

879
    {
880
        const char           *artifact_type;
881
        mender_update_state_t update_state_resume;
882
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
×
883
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
×
884
            update_state = update_state_resume;
×
885
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
886
            mender_update_module = mender_update_module_get(artifact_type);
×
887
            if (NULL == mender_update_module) {
×
888
                /* The artifact_type from the saved state does not match any update module */
889
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
890
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
891
                mender_storage_delete_deployment_data();
×
892
                goto END;
×
893
            }
894
        }
895
    }
896

897
    /* Skip the block below if we just resume from a saved state. */
898

899
/* A macro to advance to the next state -- on success we just keep going to the
900
 * code below the macro invocation (fallthrough to the next case), on error we
901
 * go to the beginning of the loop (the switch statement) again using 'continue'
902
 * (see below).
903
 *
904
 * mender_update_module is guaranteed be not NULL since the first
905
 * successful transition (from the DOWNLOAD state). */
906
#define NEXT_STATE                                                             \
907
    if (MENDER_OK == ret) {                                                    \
908
        update_state = update_state_transitions[update_state].success;         \
909
        assert(NULL != mender_update_module);                                  \
910
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
911
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
912
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
913
        }                                                                      \
914
    } else {                                                                   \
915
        update_state = update_state_transitions[update_state].failure;         \
916
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
917
        if (NULL != mender_update_module) {                                    \
918
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
919
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
920
            }                                                                  \
921
        }                                                                      \
922
        ret = MENDER_OK;                                                       \
923
        continue;                                                              \
924
    }
925

926
    while (MENDER_UPDATE_STATE_END != update_state) {
×
927
        switch (update_state) {
×
928
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
929

930
                /* Check for deployment */
931
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
932
                    /* No deployment available, but we are not done, we need to keep checking. */
NEW
933
                    if (MENDER_DONE == ret) {
×
NEW
934
                        ret = MENDER_OK;
×
935
                    }
936
                    goto END;
×
937
                }
938

939
                mender_log_info("Downloading deployment artifact with id '%s', artifact name '%s' and uri '%s'",
×
940
                                deployment->id,
941
                                deployment->artifact_name,
942
                                deployment->uri);
UNCOV
943
                mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
944

945
                /* Set deployment_id */
946
                deployment_id = deployment->id;
×
947

UNCOV
948
                if (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module))) {
×
949
                    assert(NULL != mender_update_module);
×
950

951
                    /* Get artifact context if artifact download succeeded */
952
                    if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) {
×
953
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
UNCOV
954
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
×
955
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
956
                            /* Add the new provides to the deployment data (we need the artifact context) */
957
                            char       *new_provides  = NULL;
×
UNCOV
958
                            const char *artifact_name = NULL;
×
UNCOV
959
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
×
960
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
×
961
                                    mender_log_error("Failed to set deployment data provides");
×
962
                                }
963
                                /* Replace artifact_name with the one from provides */
964
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
×
UNCOV
965
                                    mender_log_error("Failed to set deployment data artifact name");
×
966
                                }
967
                                free(new_provides);
×
968
                            } else {
UNCOV
969
                                mender_log_error("Unable to prepare new provides");
×
970
                            }
971
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
972
                        }
973
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
974
                    } else {
UNCOV
975
                        mender_log_error("Unable to get artifact type and context");
×
976
                    }
977
                } else {
978
                    mender_log_error("Unable to download artifact");
×
UNCOV
979
                    if (NULL == mender_update_module) {
×
980
                        /* Error logged in mender_client_download_artifact_callback() */
981
                        mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
982
                        goto END;
×
983
                    }
984
                }
985
                NEXT_STATE;
×
986
                /* fallthrough */
987

988
            case MENDER_UPDATE_STATE_INSTALL:
UNCOV
989
                mender_log_info("Download done, installing artifact");
×
UNCOV
990
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
×
UNCOV
991
                if (NULL != mender_update_module->callbacks[update_state]) {
×
992
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
993
                }
994
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
×
995
                    /* skip reboot */
UNCOV
996
                    update_state = MENDER_UPDATE_STATE_COMMIT;
×
997
                    set_and_store_state(update_state);
×
UNCOV
998
                    continue;
×
999
                }
1000
                /* else continue to the next successful/failure state */
1001
                NEXT_STATE;
×
1002
                /* fallthrough */
1003

1004
            case MENDER_UPDATE_STATE_REBOOT:
UNCOV
1005
                assert(mender_update_module->requires_reboot);
×
UNCOV
1006
                mender_log_info("Artifact installation done, rebooting");
×
UNCOV
1007
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
×
1008
                if ((MENDER_OK == ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1009
                    /* Save the next state before running the reboot callback --
1010
                     * if there is an interrupt (power, crash,...) right after,
1011
                     * it will reboot anyway so after the new boot, reboot
1012
                     * verification should happen anyway, the callback in that
1013
                     * state should be able to see if things went well or
1014
                     * wrong. */
UNCOV
1015
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
×
UNCOV
1016
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
UNCOV
1017
                    if (MENDER_OK == ret) {
×
1018
                        /* now we need to get outside of the loop so that a
1019
                         * potential asynchronous reboot has a chance to kick in
1020
                         * after a proper cleanup below */
UNCOV
1021
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
UNCOV
1022
                        ret                 = MENDER_DONE;
×
UNCOV
1023
                        goto END;
×
1024
                    }
1025
                }
1026
                NEXT_STATE;
×
1027
                /* fallthrough */
1028

1029
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
UNCOV
1030
                assert(mender_update_module->requires_reboot);
×
UNCOV
1031
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1032
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1033
                }
1034
                NEXT_STATE;
×
1035
                /* fallthrough */
1036

1037
            case MENDER_UPDATE_STATE_COMMIT:
1038
                /* Check for pending deployment */
UNCOV
1039
                if (NULL == mender_client_deployment_data) {
×
UNCOV
1040
                    mender_log_error("No deployment data found on commit");
×
UNCOV
1041
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1042
                    goto END;
×
1043
                }
1044
                if (MENDER_OK != mender_commit_artifact_data()) {
×
1045
                    mender_log_error("Unable to commit artifact data");
×
UNCOV
1046
                    ret = MENDER_FAIL;
×
1047
                }
1048
                if ((MENDER_OK == ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1049
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1050
                }
1051
                if (MENDER_OK == ret) {
×
1052
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
×
1053
                }
1054
                NEXT_STATE;
×
1055
                /* fallthrough */
1056

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

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

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

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

1092
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
UNCOV
1093
                if (NULL != mender_update_module->callbacks[update_state]) {
×
UNCOV
1094
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1095
                }
1096

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

1107
                NEXT_STATE;
×
1108
                /* fallthrough */
1109

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

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

NEW
1127
    ret = MENDER_OK;
×
1128

UNCOV
1129
END:
×
1130
    /* Release memory */
UNCOV
1131
    deployment_destroy(deployment);
×
1132
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
UNCOV
1133
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1134

1135
    return ret;
×
1136
}
1137

1138
static mender_err_t
UNCOV
1139
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
UNCOV
1140
    if (MENDER_FAIL == mender_client_ensure_authenticated()) {
×
1141
        /* authentication errors logged already */
1142
        mender_log_error("Cannot publish deployment status");
×
1143
        return MENDER_FAIL;
×
1144
    }
1145

1146
    mender_err_t ret;
1147

UNCOV
1148
    if (NULL == id) {
×
UNCOV
1149
        mender_log_error("Cannot publish deployment status: unknown status");
×
UNCOV
1150
        return MENDER_FAIL;
×
1151
    }
1152

1153
    /* Publish status to the mender server */
UNCOV
1154
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1155

1156
    /* Invoke deployment status callback if defined */
1157
    if (NULL != mender_client_callbacks.deployment_status) {
×
UNCOV
1158
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1159
    }
1160

1161
    return ret;
×
1162
}
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