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

mendersoftware / mender-mcu / 1710276443

11 Mar 2025 08:08AM UTC coverage: 25.348%. Remained the same
1710276443

push

gitlab-ci

web-flow
Merge pull request #166 from danielskinstad/remove-default-server-host

chore: don't set default server host to `...`

711 of 2805 relevant lines covered (25.35%)

12.58 hits per line

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

0.0
/src/core/client.c
1
/**
2
 * @file      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 "alloc.h"
22
#include "api.h"
23
#include "client.h"
24
#include "artifact.h"
25
#include "artifact-download.h"
26
#include "log.h"
27
#include "os.h"
28
#include "storage.h"
29
#include "tls.h"
30
#include "update-module.h"
31
#include "utils.h"
32
#include "deployment-data.h"
33
#include "error-counters.h"
34

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

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

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

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

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

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

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

77
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
78

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

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

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

121
#endif
122

123
/**
124
 * @brief Flag to know if network connection was requested or not
125
 */
126
static bool mender_client_network_connected = false;
127

128
/**
129
 * @brief Deployment data. Used to track progress of an update, so that the
130
 *        operation can resume or roll back across reboots
131
 */
132
static mender_deployment_data_t *mender_client_deployment_data = NULL;
133

134
/**
135
 * @brief Update module being used by the current deployment
136
 */
137
static mender_update_module_t *mender_update_module = NULL;
138

139
/**
140
 * @brief The main Mender work item
141
 */
142
static mender_work_t *mender_client_work = NULL;
143

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

150
/**
151
 * @brief Mender client initialization work function
152
 * @return MENDER_OK if the function succeeds, error code otherwise
153
 */
154
static mender_err_t mender_client_initialization_work_function(void);
155

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

162
/**
163
 * @brief Function to release network access
164
 * @return MENDER_OK if network is released following the request, error code otherwise
165
 */
166
static mender_err_t mender_client_network_release(void);
167

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

200
/**
201
 * @brief Determine the compatiblity of the deployment by: comparing artifact's depend with the stored provides
202
 * @param mender_artifact_ctx Mender artifact context
203
 * @return MENDER_OK if the function succeeds, error code otherwise
204
 */
205
static mender_err_t mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx);
206
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
207
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
208

209
/**
210
 * @brief Mender client update work function
211
 * @return MENDER_OK if the function succeeds, error code otherwise
212
 */
213
static mender_err_t mender_client_update_work_function(void);
214

215
/**
216
 * @brief Publish deployment status of the device to the mender-server and invoke deployment status callback
217
 * @param id ID of the deployment
218
 * @param deployment_status Deployment status
219
 * @return MENDER_OK if the function succeeds, error code otherwise
220
 */
221
static mender_err_t mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status);
222

223
/**
224
 * @brief Set state in deployment data and store it in permanent storage
225
 * @param state State to set and store
226
 * @return MENDER_OK in case of success, error code otherwise
227
 */
228
static mender_err_t set_and_store_state(const mender_update_state_t state);
229

230
const char *
231
mender_client_version(void) {
×
232

233
    /* Return version as string */
234
    return MENDER_CLIENT_VERSION;
×
235
}
236

237
mender_err_t
238
mender_client_init(mender_client_config_t *config, mender_client_callbacks_t *callbacks) {
×
239
    assert(NULL != config);
×
240
    assert(NULL != callbacks);
×
241
    assert(NULL != callbacks->restart);
×
242

243
    /* Either all allocation functions set or none. */
244
    assert(
×
245
        ((NULL == config->allocation_funcs.malloc_func) && (NULL == config->allocation_funcs.realloc_func) && (NULL == config->allocation_funcs.free_func))
246
        || ((NULL != config->allocation_funcs.malloc_func) && (NULL != config->allocation_funcs.realloc_func) && (NULL != config->allocation_funcs.free_func)));
247

248
    mender_err_t ret;
249

250
    if (NULL != config->allocation_funcs.malloc_func) {
×
251
        mender_set_allocation_funcs(config->allocation_funcs.malloc_func, config->allocation_funcs.realloc_func, config->allocation_funcs.free_func);
×
252
    } else {
253
        mender_set_platform_allocation_funcs();
×
254
    }
255

256
    {
257
        cJSON_Hooks cjson_alloc_funcs = { mender_malloc, mender_free };
×
258
        cJSON_InitHooks(&cjson_alloc_funcs);
×
259
    }
260

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

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

300
    /* Save callbacks */
301
    memcpy(&mender_client_callbacks, callbacks, sizeof(mender_client_callbacks_t));
×
302

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

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

339
END:
×
340

341
    return ret;
×
342
}
343

344
mender_err_t
345
mender_client_activate(void) {
×
346
    mender_err_t ret;
347

348
    mender_os_scheduler_work_params_t work_params = {
×
349
        .function = mender_client_work_function,
350
        .period   = mender_client_config.update_poll_interval,
×
351
        .name     = "mender_client_main",
352
    };
353

354
    if ((MENDER_OK != (ret = mender_os_scheduler_work_create(&work_params, &mender_client_work)))
×
355
        || (MENDER_OK != (ret = mender_os_scheduler_work_activate(mender_client_work)))) {
×
356
        mender_log_error("Unable to activate the main work");
×
357
        return ret;
×
358
    }
359

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

368
    return ret;
×
369
}
370

371
mender_err_t
372
mender_client_ensure_connected(void) {
×
373
    if (mender_client_network_connected) {
×
374
        return MENDER_DONE;
×
375
    }
376

377
    return mender_client_network_connect();
×
378
}
379

380
static mender_err_t
381
mender_client_network_connect(void) {
×
382
    if (mender_client_network_connected) {
×
383
        return MENDER_OK;
×
384
    }
385

386
    /* Request network access */
387
    if (NULL != mender_client_callbacks.network_connect) {
×
388
        if (MENDER_OK != mender_client_callbacks.network_connect()) {
×
389
            mender_log_error("Unable to connect network");
×
390
            return MENDER_FAIL;
×
391
        }
392
    }
393

394
    mender_client_network_connected = true;
×
395

396
    return MENDER_OK;
×
397
}
398

399
static mender_err_t
400
mender_client_network_release(void) {
×
401
    if (!mender_client_network_connected) {
×
402
        return MENDER_OK;
×
403
    }
404

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

414
    return MENDER_OK;
×
415
}
416

417
mender_err_t
418
mender_client_exit(void) {
×
419
    bool some_error = false;
×
420

421
    if (NULL != mender_client_work) {
×
422
        if (MENDER_OK != mender_os_scheduler_work_deactivate(mender_client_work)) {
×
423
            mender_log_error("Failed to deactivate main work");
×
424
            /* keep going on, we want to do as much cleanup as possible */
425
            some_error = true;
×
426
        }
427

428
        if (MENDER_OK != mender_os_scheduler_work_delete(mender_client_work)) {
×
429
            mender_log_error("Failed to delete main work");
×
430
            /* keep going on, we want to do as much cleanup as possible */
431
            some_error = true;
×
432
        } else {
433
            mender_client_work = NULL;
×
434
        }
435
    }
436

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

445
    /* Stop scheduling new work */
446
    mender_os_scheduler_exit();
×
447

448
    /* Release all modules */
449
    mender_api_exit();
×
450
    mender_tls_exit();
×
451
    mender_storage_exit();
×
452
    mender_log_exit();
×
453
    mender_client_network_release();
×
454

455
    /* Release memory */
456
    mender_client_config.device_type          = NULL;
×
457
    mender_client_config.host                 = NULL;
×
458
    mender_client_config.tenant_token         = NULL;
×
459
    mender_client_config.update_poll_interval = 0;
×
460
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
461

462
    mender_update_module_unregister_all();
×
463

464
    return some_error ? MENDER_FAIL : MENDER_OK;
×
465
}
466

467
static mender_err_t
468
mender_client_work_function(void) {
×
469
    mender_err_t ret;
470
    mender_log_debug("Inside work function [state: %s]", client_state_str[mender_client_state]);
471

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

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

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

528
                /* We don't want to tell the scheduler we are done because
529
                   otherwise we won't have a chance to detect that we are
530
                   waiting for a reboot forever. */
531
                ret = MENDER_OK;
×
532
            }
533
            return ret;
×
534
    }
535

536
    /* This should never be reached, all the cases should be covered in the
537
       above switch and they all return. */
538
    return MENDER_FAIL;
×
539
}
540

541
static mender_err_t
542
mender_client_initialization_work_function(void) {
×
543

544
    mender_err_t ret = MENDER_DONE;
×
545

546
    /* Retrieve or generate authentication keys */
547
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
×
548
        mender_log_error("Unable to retrieve or generate authentication keys");
×
549
        goto END;
×
550
    }
551

552
    /* Retrieve deployment data if it is found (following an update) */
553
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
×
554
        if (MENDER_NOT_FOUND != ret) {
×
555
            mender_log_error("Unable to get deployment data");
×
556
            goto REBOOT;
×
557
        }
558
    }
559

560
    mender_log_info("Initialization done");
×
561

562
    return MENDER_DONE;
×
563

564
END:
×
565

566
    return ret;
×
567

568
REBOOT:
×
569

570
    mender_log_info("Rebooting...");
×
571

572
    /* Delete pending deployment */
573
    mender_storage_delete_deployment_data();
×
574

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

583
    return ret;
×
584
}
585

586
static mender_err_t
587
mender_commit_artifact_data(void) {
×
588

589
    assert(NULL != mender_client_deployment_data);
×
590

591
    const char *artifact_name;
592
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
×
593
        mender_log_error("Unable to get artifact name from the deployment data");
×
594
        return MENDER_FAIL;
×
595
    }
596

597
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
×
598
        mender_log_error("Unable to set artifact name");
×
599
        return MENDER_FAIL;
×
600
    }
601

602
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
603
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
604
    /* Get provides from the deployment data */
605
    const char *provides;
606
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
×
607
        mender_log_error("Unable to get new_provides from the deployment data");
×
608
        return MENDER_FAIL;
×
609
    }
610

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

627
    return MENDER_OK;
×
628
}
629

630
static mender_err_t
631
deployment_destroy(mender_api_deployment_data_t *deployment) {
×
632
    if (NULL != deployment) {
×
633
        mender_free(deployment->id);
×
634
        mender_free(deployment->artifact_name);
×
635
        mender_free(deployment->uri);
×
636
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
×
637
            mender_free(deployment->device_types_compatible[i]);
×
638
        }
639
        mender_free(deployment->device_types_compatible);
×
640
        mender_free(deployment);
×
641
    }
642
    return MENDER_OK;
×
643
}
644

645
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
646
static mender_err_t
647
mender_compare_device_types(const char  *device_type_artifact,
×
648
                            const char  *device_type_device,
649
                            const char **device_type_deployment,
650
                            const size_t device_type_deployment_size) {
651

652
    assert(NULL != device_type_artifact);
×
653
    assert(NULL != device_type_deployment);
×
654
    assert(NULL != device_type_device);
×
655
    assert(0 < device_type_deployment_size);
×
656

657
    if (!StringEqual(device_type_artifact, device_type_device)) {
×
658
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
659
        return MENDER_FAIL;
×
660
    }
661

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

672
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
673
static mender_err_t
674
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
×
675

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

695
    /* Combine the stored provides with the new ones */
696
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
×
697
        mender_log_error("Unable to merge provides");
×
698
        goto END;
×
699
    }
700

701
    /* Make sure the artifact name is not in the new provides */
702
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
×
703
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
704
        goto END;
×
705
    }
706

707
    ret = MENDER_OK;
×
708

709
END:
×
710

711
    mender_utils_key_value_list_free(*stored_provides);
×
712
    return ret;
×
713
}
714

715
static mender_err_t
716
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
×
717

718
    assert(NULL != artifact_name);
×
719
    assert(NULL != mender_artifact_ctx);
×
720

721
    /* Load the currently stored provides */
722
    mender_key_value_list_t *stored_provides = NULL;
×
723
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
724
        mender_log_error("Unable to get provides");
×
725
        return MENDER_FAIL;
×
726
    }
727

728
    mender_key_value_list_t *provides = NULL;
×
729
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
730
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
×
731
            mender_log_error("Unable to merge provides");
×
732
            mender_utils_key_value_list_free(stored_provides);
×
733
            return MENDER_FAIL;
×
734
        }
735
    }
736

737
    /* Get artifact name from provides */
738
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
×
739
        if (StringEqual("artifact_name", item->key)) {
×
740
            *artifact_name = item->value;
×
741
            break;
×
742
        }
743
    }
744

745
    if (NULL == *artifact_name) {
×
746
        mender_log_error("No artifact name found in provides");
×
747
        mender_utils_key_value_list_free(stored_provides);
×
748
        return MENDER_FAIL;
×
749
    }
750

751
    /* Filter provides */
752
    /* `stored_provides` is freed in `mender_filter_provides` */
753
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
×
754
        return MENDER_FAIL;
×
755
    }
756

757
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
×
758
        mender_utils_key_value_list_free(provides);
×
759
        return MENDER_FAIL;
×
760
    }
761

762
    mender_utils_key_value_list_free(provides);
×
763
    return MENDER_OK;
×
764
}
765

766
static mender_err_t
767
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
×
768

769
    /* We need to load the stored provides */
770
    mender_key_value_list_t *stored_provides = NULL;
×
771
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
×
772
        return MENDER_FAIL;
×
773
    }
774

775
    mender_err_t ret = MENDER_FAIL;
×
776

777
    /* Get depends */
778
    mender_key_value_list_t *depends = NULL;
×
779
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
×
780
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
×
781
            mender_log_error("Unable to append depends");
×
782
            goto END;
×
783
        }
784
    }
785

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

809
    ret = MENDER_OK;
×
810

811
END:
×
812
    mender_utils_key_value_list_free(stored_provides);
×
813
    return ret;
×
814
}
815
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
816
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
817

818
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
819
static mender_err_t
820
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
×
821
    mender_err_t ret;
822

823
    /* Retrieve device type from artifact */
824
    const char *device_type_artifact = NULL;
×
825
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
×
826
        mender_log_error("Unable to get device type from artifact");
×
827
        return ret;
×
828
    }
829

830
    mender_log_debug("Checking device type compatibility");
831

832
    /* Match device type  */
833
    if (MENDER_OK
×
834
        != (ret = mender_compare_device_types(device_type_artifact,
×
835
                                              mender_client_config.device_type,
×
836
                                              (const char **)deployment->device_types_compatible,
×
837
                                              deployment->device_types_compatible_size))) {
838
        return ret;
×
839
    }
840

841
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
842
    /* Compare Artifact's depends with the stored provides */
843
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
×
844
        return ret;
×
845
    }
846
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
847

848
    /* Check payload integrity by comparing computed checksum(s) with those
849
     * listed in the artifact manifest */
850
    if (MENDER_OK != mender_artifact_check_integrity_remaining(mender_artifact_ctx)) {
×
851
        return MENDER_FAIL;
×
852
    }
853

854
    return MENDER_OK;
×
855
}
856
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
857

858
static mender_err_t
859
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
×
860
    assert(NULL != deployment_data);
×
861

862
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
863
        /* network errors logged already */
864
        mender_log_error("Cannot check for new deployment");
×
865
        return MENDER_FAIL;
×
866
    }
867

868
    if (NULL == (*deployment_data = mender_calloc(1, sizeof(mender_api_deployment_data_t)))) {
×
869
        mender_log_error("Unable to allocate memory for deployment data");
×
870
        return MENDER_FAIL;
×
871
    }
872

873
    mender_api_deployment_data_t *deployment = *deployment_data;
×
874

875
    mender_err_t ret = MENDER_OK;
×
876

877
    mender_log_info("Checking for deployment...");
×
878
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
×
879
        mender_log_info("No deployment available");
×
880
        return MENDER_DONE;
×
881
    } else if (MENDER_OK != ret) {
×
882
        mender_log_error("Unable to check for deployment");
×
883
        return MENDER_FAIL;
×
884
    }
885

886
    /* Check if deployment is valid */
887
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
×
888
        mender_log_error("Invalid deployment data");
×
889
        return MENDER_FAIL;
×
890
    }
891

892
    /* Create deployment data */
893
    if (NULL != mender_client_deployment_data) {
×
894
        mender_log_warning("Unexpected stale deployment data");
×
895
        mender_delete_deployment_data(mender_client_deployment_data);
×
896
    }
897
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
×
898
        /* Error already logged */
899
        return MENDER_FAIL;
×
900
    }
901

902
    return MENDER_OK;
×
903
}
904

905
static mender_err_t
906
set_and_store_state(const mender_update_state_t state) {
×
907

908
    /*
909
     * Set the state in `mender_client_deployment_data` and write it to the nvs
910
     */
911

912
    mender_err_t ret = MENDER_OK;
×
913

914
    /* Set state in deployment data */
915
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
×
916
        mender_log_error("Failed to set deployment data state");
×
917
        return ret;
×
918
    }
919

920
    /* Store deployment data */
921
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
×
922
        mender_log_error("Failed to store deployment data");
×
923
        return ret;
×
924
    }
925
    return ret;
×
926
}
927

928
static mender_err_t
929
mender_client_update_work_function(void) {
×
930
    mender_err_t ret = MENDER_OK;
×
931

932
    /* Ensure that the context is initialized to NULL before goto END */
933
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
×
934

935
    /* Check for deployment */
936
    mender_api_deployment_data_t *deployment    = NULL;
×
937
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
×
938
    const char                   *deployment_id = NULL;
×
939

940
    /* reset the currently used update module */
941
    mender_update_module = NULL;
×
942

943
    if (NULL != mender_client_deployment_data) {
×
944
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
×
945
    }
946

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

965
    /* Skip the block below if we just resume from a saved state. */
966

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

994
    while (MENDER_UPDATE_STATE_END != update_state) {
×
995
        switch (update_state) {
×
996
            case MENDER_UPDATE_STATE_DOWNLOAD:
×
997
                /* This is usually logged in the NEXT_STATE macro, but since nothing
998
                 * transitions to this state, we log it here */
999
                mender_log_debug("Entering state %s", update_state_str[update_state]);
1000

1001
                /* Check for deployment */
1002
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
×
1003
                    /* No deployment available, but we are not done, we need to keep checking. */
1004
                    if (MENDER_DONE == ret) {
×
1005
                        ret = MENDER_OK;
×
1006
                    }
1007
                    goto END;
×
1008
                }
1009

1010
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
1011
                if (strlen(deployment->id) > 10) {
×
1012
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
1013
                } else {
1014
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
1015
                }
1016
#endif
1017
                /* Set deployment_id */
1018
                deployment_id = deployment->id;
×
1019

1020
                /* Check ret to see if the deployment is aborted */
1021
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
×
1022
                if ((MENDER_ABORTED != ret)
×
1023
                    && (MENDER_OK == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module)))) {
×
1024
                    assert(NULL != mender_update_module);
×
1025

1026
                    /* Get artifact context if artifact download succeeded */
1027
                    if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) {
×
1028
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
1029
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
×
1030
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
1031
                            /* Add the new provides to the deployment data (we need the artifact context) */
1032
                            char       *new_provides  = NULL;
×
1033
                            const char *artifact_name = NULL;
×
1034
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
×
1035
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
×
1036
                                    mender_log_error("Failed to set deployment data provides");
×
1037
                                }
1038
                                /* Replace artifact_name with the one from provides */
1039
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
×
1040
                                    mender_log_error("Failed to set deployment data artifact name");
×
1041
                                }
1042
                                mender_free(new_provides);
×
1043
                            } else {
1044
                                mender_log_error("Unable to prepare new provides");
×
1045
                            }
1046
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
1047
                        } else {
1048
                            mender_log_error("Artifact check failed");
×
1049
                        }
1050
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1051
                    } else {
1052
                        mender_log_error("Unable to get artifact type and context");
×
1053
                    }
1054
                } else {
1055
                    mender_log_error("Unable to download artifact");
×
1056
                    /* Error logged in mender_client_download_artifact_callback() */
1057
                    ret = MENDER_FAIL;
×
1058
                }
1059
                if (MENDER_OK != ret) {
×
1060
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1061
                }
1062
                NEXT_STATE;
×
1063
                /* fallthrough */
1064

1065
            case MENDER_UPDATE_STATE_INSTALL:
1066
                mender_log_info("Download done, installing artifact");
×
1067
                /* Check ret to see if the deployment is aborted */
1068
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
×
1069
                if ((MENDER_ABORTED != ret) && (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
                if ((MENDER_OK == ret) && !mender_update_module->requires_reboot) {
×
1073
                    /* skip reboot */
1074
                    update_state = MENDER_UPDATE_STATE_COMMIT;
×
1075
                    mender_log_debug("Entering state %s", update_state_str[update_state]);
1076
                    set_and_store_state(update_state);
×
1077
                    continue;
×
1078
                }
1079
                /* else continue to the next successful/failure state */
1080
                NEXT_STATE;
×
1081
                /* fallthrough */
1082

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

1109
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1110
                assert(mender_update_module->requires_reboot);
×
1111
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1112
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1113
                }
1114
                NEXT_STATE;
×
1115
                /* fallthrough */
1116

1117
            case MENDER_UPDATE_STATE_COMMIT:
1118
                /* Check for pending deployment */
1119
                if (NULL == mender_client_deployment_data) {
×
1120
                    mender_log_error("No deployment data found on commit");
×
1121
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1122
                    goto END;
×
1123
                }
1124
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1125
                if (MENDER_OK != mender_api_drop_authentication_data()) {
×
1126
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1127
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1128
                       much to about it. */
1129
                }
1130
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
×
1131
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1132
                }
1133
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
1134
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
×
1135
                    mender_log_error("Unable to commit artifact data");
×
1136
                }
1137
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
×
1138
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1139
                }
1140
                if (!MENDER_IS_ERROR(ret)) {
×
1141
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
×
1142
                }
1143
                NEXT_STATE;
×
1144
                /* fallthrough */
1145

1146
            case MENDER_UPDATE_STATE_CLEANUP:
1147
                if (NULL != mender_update_module) {
×
1148
                    if (NULL != mender_update_module->callbacks[update_state]) {
×
1149
                        ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1150
                    }
1151
                } else {
1152
                    ret = MENDER_FAIL;
×
1153
                }
1154
                NEXT_STATE;
×
1155
                mender_storage_delete_deployment_data();
×
1156
                break; /* below is the failure path */
×
1157

1158
            case MENDER_UPDATE_STATE_ROLLBACK:
×
1159
                if (!mender_update_module->supports_rollback) {
×
1160
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
×
1161
                    ret = MENDER_FAIL;
×
1162
                } else if (NULL != mender_update_module->callbacks[update_state]) {
×
1163
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1164
                }
1165
                NEXT_STATE;
×
1166
                /* fallthrough */
1167

1168
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1169
                /* Save the next state before running the reboot callback (see
1170
                 * STATE_REBOOT for details). */
1171
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
×
1172
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1173

1174
                if (MENDER_OK == ret) {
×
1175
                    /* now we need to get outside of the loop so that a
1176
                     * potential asynchronous reboot has a chance to kick in
1177
                     * after a proper cleanup below */
1178
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
1179
                    ret                 = MENDER_DONE;
×
1180
                    goto END;
×
1181
                }
1182
                NEXT_STATE;
×
1183
                /* fallthrough */
1184

1185
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1186
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1187
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1188
                }
1189

1190
                if (MENDER_OK != ret) {
×
1191
                    /* If the rollback verify reboot fails,
1192
                     * we will retry the rollback reboot.
1193
                     *
1194
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1195
                     * loop is broken when a state loop is detected
1196
                     */
1197
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
×
1198
                }
1199

1200
                NEXT_STATE;
×
1201
                /* fallthrough */
1202

1203
            case MENDER_UPDATE_STATE_FAILURE:
1204
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1205
                if (NULL != mender_update_module->callbacks[update_state]) {
×
1206
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1207
                }
1208
                NEXT_STATE;
×
1209
                break; /* end of the failure path */
×
1210

1211
            case MENDER_UPDATE_STATE_END:
×
1212
                /* This is only here to cover all possible values of the
1213
                 * update_state enum, there is nothing to do here, the while
1214
                 * loop shall stop when we get here. */
1215
                break;
×
1216
        }
1217
    }
1218
#undef NEXT_STATE /* should not be used anywhere else */
1219

1220
    ret = MENDER_OK;
×
1221

1222
END:
×
1223
    /* Release memory */
1224
    deployment_destroy(deployment);
×
1225
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
×
1226
    mender_artifact_release_ctx(mender_artifact_ctx);
×
1227

1228
    return ret;
×
1229
}
1230

1231
static mender_err_t
1232
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
1233
    if (MENDER_FAIL == mender_client_ensure_connected()) {
×
1234
        /* connection errors logged already */
1235
        mender_log_error("Cannot publish deployment status");
×
1236
        return MENDER_FAIL;
×
1237
    }
1238

1239
    mender_err_t ret;
1240

1241
    if (NULL == id) {
×
1242
        mender_log_error("Cannot publish deployment status: unknown status");
×
1243
        return MENDER_FAIL;
×
1244
    }
1245

1246
    /* Publish status to the mender server */
1247
    ret = mender_api_publish_deployment_status(id, deployment_status);
×
1248

1249
    /* Invoke deployment status callback if defined */
1250
    if (NULL != mender_client_callbacks.deployment_status) {
×
1251
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
×
1252
    }
1253

1254
    return ret;
×
1255
}
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