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

mendersoftware / mender-mcu / 1564463470

28 Nov 2024 02:08PM UTC coverage: 9.171% (-0.05%) from 9.221%
1564463470

push

gitlab-ci

vpodzime
chore: Try to detect too many network issues and reset network

Instead of being stuck in the non-working setup.

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

0 of 25 new or added lines in 4 files covered. (0.0%)

403 existing lines in 3 files now uncovered.

251 of 2737 relevant lines covered (9.17%)

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
#include "mender-error-counters.h"
33

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

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

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

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

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

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

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

76
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
77

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

216
char *
UNCOV
217
mender_client_version(void) {
×
218

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

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

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

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

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

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

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

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

UNCOV
309
END:
×
310

UNCOV
311
    return ret;
×
312
}
313

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

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

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

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

UNCOV
338
    return ret;
×
339
}
340

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

UNCOV
347
    return mender_client_network_connect();
×
348
}
349

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

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

UNCOV
364
    mender_client_network_connected = true;
×
365

UNCOV
366
    return MENDER_OK;
×
367
}
368

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

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

UNCOV
384
    return MENDER_OK;
×
385
}
386

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

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

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

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

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

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

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

UNCOV
430
    mender_update_module_unregister_all();
×
431

UNCOV
432
    return some_error ? MENDER_FAIL : MENDER_OK;
×
433
}
434

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

UNCOV
440
    switch (mender_client_state) {
×
UNCOV
441
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
×
442
            mender_log_info("Waiting for a reboot");
×
443
            /* nothing to do */
444
            return MENDER_DONE;
×
UNCOV
445
        case MENDER_CLIENT_STATE_INITIALIZATION:
×
446
            /* Perform initialization of the client */
447
            if (MENDER_DONE != mender_client_initialization_work_function()) {
×
UNCOV
448
                return MENDER_FAIL;
×
449
            }
450
            mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
451
            /* fallthrough */
452
        case MENDER_CLIENT_STATE_OPERATIONAL:
×
NEW
453
            ret = mender_client_update_work_function();
×
NEW
454
            if (MENDER_FAIL == ret) {
×
NEW
455
                if (MENDER_FAIL == mender_err_count_net_check()) {
×
456
                    /* Try to release network so that it gets set up again next
457
                       time. */
NEW
458
                    mender_client_network_release();
×
459
                }
460
            }
NEW
461
            return ret;
×
462
    }
463

464
    /* This should never be reached, all the cases should be covered in the
465
       above switch and they all return. */
UNCOV
466
    return MENDER_FAIL;
×
467
}
468

469
static mender_err_t
UNCOV
470
mender_client_initialization_work_function(void) {
×
471

UNCOV
472
    mender_err_t ret = MENDER_DONE;
×
473

474
    /* Retrieve or generate authentication keys */
UNCOV
475
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
×
476
        mender_log_error("Unable to retrieve or generate authentication keys");
×
UNCOV
477
        goto END;
×
478
    }
479

480
    /* Retrieve deployment data if it is found (following an update) */
UNCOV
481
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
×
482
        if (MENDER_NOT_FOUND != ret) {
×
UNCOV
483
            mender_log_error("Unable to get deployment data");
×
UNCOV
484
            goto REBOOT;
×
485
        }
486
    }
487

UNCOV
488
    mender_log_info("Initialization done");
×
489

UNCOV
490
    return MENDER_DONE;
×
491

492
END:
×
493

494
    return ret;
×
495

UNCOV
496
REBOOT:
×
497

498
    mender_log_info("Rebooting...");
×
499

500
    /* Delete pending deployment */
UNCOV
501
    mender_storage_delete_deployment_data();
×
502

503
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
504
    if (NULL != mender_client_callbacks.restart) {
×
UNCOV
505
        mender_client_callbacks.restart();
×
506
    }
507

508
    return ret;
×
509
}
510

511
static mender_err_t
UNCOV
512
mender_commit_artifact_data(void) {
×
513

514
    assert(NULL != mender_client_deployment_data);
×
515

516
    const char *artifact_name;
UNCOV
517
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
518
        mender_log_error("Unable to get artifact name from the deployment data");
×
UNCOV
519
        return MENDER_FAIL;
×
520
    }
521

522
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
UNCOV
523
        mender_log_error("Unable to set artifact name");
×
524
        return MENDER_FAIL;
×
525
    }
526

527
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
528
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
529
    /* Get provides from the deployment data */
530
    const char *provides;
UNCOV
531
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
×
532
        mender_log_error("Unable to get new_provides from the deployment data");
×
533
        return MENDER_FAIL;
×
534
    }
535

536
    /* Parse provides */
UNCOV
537
    mender_key_value_list_t *new_provides = NULL;
×
UNCOV
538
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
×
UNCOV
539
        mender_log_error("Unable to parse provides from the deployment data");
×
UNCOV
540
        return MENDER_FAIL;
×
541
    }
542
    /* Replace the stored provides with the new provides */
543
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
×
UNCOV
544
        mender_log_error("Unable to set provides");
×
UNCOV
545
        mender_utils_key_value_list_free(new_provides);
×
UNCOV
546
        return MENDER_FAIL;
×
547
    }
548
    mender_utils_key_value_list_free(new_provides);
×
549
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
550
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
551

UNCOV
552
    return MENDER_OK;
×
553
}
554

555
static mender_err_t
556
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
UNCOV
557
    if (NULL != deployment) {
×
558
        free(deployment->id);
×
UNCOV
559
        free(deployment->artifact_name);
×
UNCOV
560
        free(deployment->uri);
×
UNCOV
561
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
562
            free(deployment->device_types_compatible[i]);
×
563
        }
UNCOV
564
        free(deployment->device_types_compatible);
×
UNCOV
565
        free(deployment);
×
566
    }
567
    return MENDER_OK;
×
568
}
569

570
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
571
static mender_err_t
572
mender_compare_device_types(const char  *device_type_artifact,
×
573
                            const char  *device_type_device,
574
                            const char **device_type_deployment,
575
                            const size_t device_type_deployment_size) {
576

577
    assert(NULL != device_type_artifact);
×
UNCOV
578
    assert(NULL != device_type_deployment);
×
UNCOV
579
    assert(NULL != device_type_device);
×
UNCOV
580
    assert(0 < device_type_deployment_size);
×
581

582
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
UNCOV
583
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
UNCOV
584
        return MENDER_FAIL;
×
585
    }
586

587
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
588
    for (size_t i = 0; i < device_type_deployment_size; i++) {
×
589
        if (StringEqual(device_type_deployment[i], device_type_device)) {
×
590
            return MENDER_OK;
×
591
        }
592
    }
593
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
594
    return MENDER_FAIL;
×
595
}
596

597
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
598
static mender_err_t
599
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
600

UNCOV
601
    mender_err_t ret = MENDER_FAIL;
×
602
    /* Clears provides */
603
    bool matches;
604
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
UNCOV
605
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
×
UNCOV
606
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
×
UNCOV
607
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
×
UNCOV
608
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
609
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
UNCOV
610
                    goto END;
×
611
                }
UNCOV
612
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
UNCOV
613
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
614
                    goto END;
×
615
                }
616
            }
617
        }
618
    }
619

620
    /* Combine the stored provides with the new ones */
UNCOV
621
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
622
        mender_log_error("Unable to merge provides");
×
623
        goto END;
×
624
    }
625

626
    /* Make sure the artifact name is not in the new provides */
UNCOV
627
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
UNCOV
628
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
UNCOV
629
        goto END;
×
630
    }
631

632
    ret = MENDER_OK;
×
633

UNCOV
634
END:
×
635

UNCOV
636
    mender_utils_key_value_list_free(*stored_provides);
×
637
    return ret;
×
638
}
639

640
static mender_err_t
UNCOV
641
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
642

UNCOV
643
    assert(NULL != artifact_name);
×
644
    assert(NULL != mender_artifact_ctx);
×
645

646
    /* Load the currently stored provides */
647
    mender_key_value_list_t *stored_provides = NULL;
×
UNCOV
648
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
UNCOV
649
        mender_log_error("Unable to get provides");
×
UNCOV
650
        return MENDER_FAIL;
×
651
    }
652

653
    mender_key_value_list_t *provides = NULL;
×
654
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
UNCOV
655
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
UNCOV
656
            mender_log_error("Unable to merge provides");
×
657
            mender_utils_key_value_list_free(stored_provides);
×
658
            return MENDER_FAIL;
×
659
        }
660
    }
661

662
    /* Get artifact name from provides */
663
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
664
        if (StringEqual("artifact_name", item->key)) {
×
665
            *artifact_name = item->value;
×
666
            break;
×
667
        }
668
    }
669

UNCOV
670
    if (NULL == *artifact_name) {
×
UNCOV
671
        mender_log_error("No artifact name found in provides");
×
UNCOV
672
        mender_utils_key_value_list_free(stored_provides);
×
673
        return MENDER_FAIL;
×
674
    }
675

676
    /* Filter provides */
677
    /* `stored_provides` is freed in `mender_filter_provides` */
UNCOV
678
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
UNCOV
679
        return MENDER_FAIL;
×
680
    }
681

682
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
683
        return MENDER_FAIL;
×
684
    }
685

UNCOV
686
    return MENDER_OK;
×
687
}
688

689
static mender_err_t
UNCOV
690
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
691

692
    /* We need to load the stored provides */
693
    mender_key_value_list_t *stored_provides = NULL;
×
UNCOV
694
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
UNCOV
695
        return MENDER_FAIL;
×
696
    }
697

UNCOV
698
    mender_err_t ret = MENDER_FAIL;
×
699

700
    /* Get depends */
UNCOV
701
    mender_key_value_list_t *depends = NULL;
×
UNCOV
702
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
703
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
704
            mender_log_error("Unable to append depends");
×
705
            goto END;
×
706
        }
707
    }
708

709
    /* Match depends from artifact with device's provides */
UNCOV
710
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
×
711
        bool matches = false;
×
712
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
713
            /* Match key-value from depends with provides */
714
            if (StringEqual(depends_item->key, provides_item->key)) {
×
715
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
UNCOV
716
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
717
                                     depends_item->key,
718
                                     depends_item->value,
719
                                     provides_item->value);
720
                    break;
×
721
                }
722
                matches = true;
×
UNCOV
723
                break;
×
724
            }
725
        }
726
        if (!matches) {
×
UNCOV
727
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
UNCOV
728
            goto END;
×
729
        }
730
    }
731

732
    ret = MENDER_OK;
×
733

UNCOV
734
END:
×
UNCOV
735
    mender_utils_key_value_list_free(stored_provides);
×
736
    return ret;
×
737
}
738
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
739
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
740

741
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
742
static mender_err_t
UNCOV
743
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
744
    mender_err_t ret;
745

746
    /* Retrieve device type from artifact */
UNCOV
747
    const char *device_type_artifact = NULL;
×
UNCOV
748
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
UNCOV
749
        mender_log_error("Unable to get device type from artifact");
×
UNCOV
750
        return ret;
×
751
    }
752

753
    mender_log_debug("Checking device type compatibility");
754

755
    /* Match device type  */
UNCOV
756
    if (MENDER_OK
×
757
        != (ret = mender_compare_device_types(device_type_artifact,
×
758
                                              mender_client_config.device_type,
×
759
                                              (const char **)deployment->device_types_compatible,
×
760
                                              deployment->device_types_compatible_size))) {
UNCOV
761
        return ret;
×
762
    }
763

764
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
765
    /* Compare Artifact's depends with the stored provides */
766
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
767
        return ret;
×
768
    }
769
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
770

771
    /* Check artifact integrity by comparing computed checksums with those
772
     * listed in the artifacts manifest */
UNCOV
773
    if (MENDER_OK != mender_artifact_check_integrity(mender_artifact_ctx)) {
×
UNCOV
774
        return MENDER_FAIL;
×
775
    }
776

777
    return MENDER_OK;
×
778
}
779
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
780

781
static mender_err_t
UNCOV
782
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
783
    assert(NULL != deployment_data);
×
784

UNCOV
785
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
786
        /* network errors logged already */
787
        mender_log_error("Cannot check for new deployment");
×
UNCOV
788
        return MENDER_FAIL;
×
789
    }
790

UNCOV
791
    if (NULL == (*deployment_data = calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
792
        mender_log_error("Unable to allocate memory for deployment data");
×
793
        return MENDER_FAIL;
×
794
    }
795

UNCOV
796
    mender_api_deployment_data_t *deployment = *deployment_data;
×
797

798
    mender_err_t ret = MENDER_OK;
×
799

UNCOV
800
    mender_log_info("Checking for deployment...");
×
801
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
802
        mender_log_info("No deployment available");
×
803
        return MENDER_DONE;
×
UNCOV
804
    } else if (MENDER_OK != ret) {
×
UNCOV
805
        mender_log_error("Unable to check for deployment");
×
806
        return MENDER_FAIL;
×
807
    }
808

809
    /* Check if deployment is valid */
810
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
811
        mender_log_error("Invalid deployment data");
×
812
        return MENDER_FAIL;
×
813
    }
814

815
    /* Create deployment data */
816
    if (NULL != mender_client_deployment_data) {
×
UNCOV
817
        mender_log_warning("Unexpected stale deployment data");
×
UNCOV
818
        mender_delete_deployment_data(mender_client_deployment_data);
×
819
    }
820
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
821
        /* Error already logged */
822
        return MENDER_FAIL;
×
823
    }
824

UNCOV
825
    return MENDER_OK;
×
826
}
827

828
static mender_err_t
UNCOV
829
set_and_store_state(const mender_update_state_t state) {
×
830

831
    /*
832
     * Set the state in `mender_client_deployment_data` and write it to the nvs
833
     */
834

835
    mender_err_t ret = MENDER_OK;
×
836

837
    /* Set state in deployment data */
UNCOV
838
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
839
        mender_log_error("Failed to set deployment data state");
×
UNCOV
840
        return ret;
×
841
    }
842

843
    /* Store deployment data */
UNCOV
844
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
845
        mender_log_error("Failed to store deployment data");
×
UNCOV
846
        return ret;
×
847
    }
848
    return ret;
×
849
}
850

851
static mender_err_t
UNCOV
852
mender_client_update_work_function(void) {
×
UNCOV
853
    mender_err_t ret = MENDER_OK;
×
854

855
    /* Ensure that the context is initialized to NULL before goto END */
856
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
857

858
    /* Check for deployment */
UNCOV
859
    mender_api_deployment_data_t *deployment    = NULL;
×
UNCOV
860
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
UNCOV
861
    const char                   *deployment_id = NULL;
×
862

863
    /* reset the currently used update module */
UNCOV
864
    mender_update_module = NULL;
×
865

866
    if (NULL != mender_client_deployment_data) {
×
UNCOV
867
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
868
    }
869

870
    {
871
        const char           *artifact_type;
872
        mender_update_state_t update_state_resume;
UNCOV
873
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
×
874
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
×
UNCOV
875
            update_state = update_state_resume;
×
876
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
877
            mender_update_module = mender_update_module_get(artifact_type);
×
UNCOV
878
            if (NULL == mender_update_module) {
×
879
                /* The artifact_type from the saved state does not match any update module */
UNCOV
880
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
UNCOV
881
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
UNCOV
882
                mender_storage_delete_deployment_data();
×
883
                goto END;
×
884
            }
885
        }
886
    }
887

888
    /* Skip the block below if we just resume from a saved state. */
889

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

UNCOV
917
    while (MENDER_UPDATE_STATE_END != update_state) {
×
UNCOV
918
        switch (update_state) {
×
UNCOV
919
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
920

921
                /* Check for deployment */
UNCOV
922
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
923
                    /* No deployment available, but we are not done, we need to keep checking. */
UNCOV
924
                    if (MENDER_DONE == ret) {
×
UNCOV
925
                        ret = MENDER_OK;
×
926
                    }
927
                    goto END;
×
928
                }
929

930
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
UNCOV
931
                if (strlen(deployment->id) > 10) {
×
932
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
933
                } else {
934
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
935
                }
936
#endif
937
                mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
938

939
                /* Set deployment_id */
UNCOV
940
                deployment_id = deployment->id;
×
941

942
                if (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module))) {
×
UNCOV
943
                    assert(NULL != mender_update_module);
×
944

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

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

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

1023
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
UNCOV
1024
                assert(mender_update_module->requires_reboot);
×
1025
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1026
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1027
                }
UNCOV
1028
                NEXT_STATE;
×
1029
                /* fallthrough */
1030

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

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

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

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

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

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

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

1110
                NEXT_STATE;
×
1111
                /* fallthrough */
1112

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

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

UNCOV
1130
    ret = MENDER_OK;
×
1131

UNCOV
1132
END:
×
1133
    /* Release memory */
UNCOV
1134
    deployment_destroy(deployment);
×
1135
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
UNCOV
1136
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1137

UNCOV
1138
    return ret;
×
1139
}
1140

1141
static mender_err_t
1142
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
UNCOV
1143
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1144
        /* connection errors logged already */
1145
        mender_log_error("Cannot publish deployment status");
×
1146
        return MENDER_FAIL;
×
1147
    }
1148

1149
    mender_err_t ret;
1150

UNCOV
1151
    if (NULL == id) {
×
1152
        mender_log_error("Cannot publish deployment status: unknown status");
×
1153
        return MENDER_FAIL;
×
1154
    }
1155

1156
    /* Publish status to the mender server */
UNCOV
1157
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1158

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

UNCOV
1164
    return ret;
×
1165
}
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