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

mendersoftware / mender-mcu / 2111356208

21 Oct 2025 10:51AM UTC coverage: 61.258% (+4.4%) from 56.866%
2111356208

push

gitlab-ci

danielskinstad
build: support warning/failing on artifact sizes

Add support for specifying size limits for Mender
Artifacts during a build. This uses the feature implemented in
mender-artifact 4.2.0. The limits can be configured through the Kconfig,
    or by enabling `MENDER_ARTIFACT_SIZE_LIMITS` and setting
    `MENDER_ARTIFACT_WARN_SIZE` and or `MENDER_ARTIFACT_MAX_SIZE`.

Ticket: MEN-8584

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

2473 of 4037 relevant lines covered (61.26%)

70.55 hits per line

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

67.61
/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_SERVER_DORMANT_CERTIFICATES
36
#include "certs.h"
37
#endif /* CONFIG_MENDER_SERVER_DORMANT_CERTIFICATES */
38

39
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
40
#include "inventory.h"
41
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
42

43
/**
44
 * @brief Default host
45
 */
46
#ifndef CONFIG_MENDER_SERVER_HOST
47
#define CONFIG_MENDER_SERVER_HOST "https://hosted.mender.io"
48
#endif /* CONFIG_MENDER_SERVER_HOST */
49

50
/**
51
 * @brief Default tenant token
52
 */
53
#ifndef CONFIG_MENDER_SERVER_TENANT_TOKEN
54
#define CONFIG_MENDER_SERVER_TENANT_TOKEN NULL
55
#endif /* CONFIG_MENDER_SERVER_TENANT_TOKEN */
56

57
/**
58
 * @brief Default device tier
59
 */
60
#ifndef CONFIG_MENDER_DEVICE_TIER
61
#define CONFIG_MENDER_DEVICE_TIER MENDER_DEVICE_TIER_STANDARD
62
#endif /* CONFIG_MENDER_DEVICE_TIER */
63

64
/**
65
 * @brief Default device type
66
 */
67
#ifndef CONFIG_MENDER_DEVICE_TYPE
68
#define CONFIG_MENDER_DEVICE_TYPE NULL
69
#endif /* CONFIG_MENDER_DEVICE_TYPE */
70

71
/**
72
 * @brief Default update poll interval (seconds)
73
 */
74
#ifndef CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL
75
#define CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL (86400)
76
#endif /* CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL */
77

78
/**
79
 * @brief Default backoff interval (seconds)
80
 */
81
#ifndef CONFIG_MENDER_RETRY_ERROR_BACKOFF
82
#define CONFIG_MENDER_RETRY_ERROR_BACKOFF (60)
83
#endif /* CONFIG_MENDER_RETRY_ERROR_BACKOFF */
84

85
/**
86
 * @brief Default max backoff interval interval (seconds)
87
 */
88
#ifndef CONFIG_MENDER_RETRY_ERROR_MAX_BACKOFF
89
#define CONFIG_MENDER_RETRY_ERROR_MAX_BACKOFF (540)
90
#endif /* CONFIG_MENDER_RETRY_ERROR_MAX_BACKOFF */
91

92
/**
93
 * @brief Mender client configuration
94
 */
95
static mender_client_config_t mender_client_config;
96

97
/**
98
 * @brief Mender client callbacks
99
 */
100
mender_client_callbacks_t mender_client_callbacks = { 0 };
101

102
mender_client_state_t mender_client_state = MENDER_CLIENT_STATE_INITIALIZATION;
103

104
struct mender_update_state_transition_s {
105
    mender_update_state_t success;
106
    mender_update_state_t failure;
107
};
108

109
/**
110
 * @brief Mender Update (module) state transitions
111
 */
112
static const struct mender_update_state_transition_s update_state_transitions[N_MENDER_UPDATE_STATES] = {
113
    /* MENDER_UPDATE_STATE_DOWNLOAD               */ { MENDER_UPDATE_STATE_INSTALL, MENDER_UPDATE_STATE_CLEANUP },
114
    /* MENDER_UPDATE_STATE_INSTALL                */ { MENDER_UPDATE_STATE_REBOOT, MENDER_UPDATE_STATE_FAILURE },
115
    /* MENDER_UPDATE_STATE_REBOOT                 */ { MENDER_UPDATE_STATE_VERIFY_REBOOT, MENDER_UPDATE_STATE_ROLLBACK },
116
    /* MENDER_UPDATE_STATE_VERIFY_REBOOT          */ { MENDER_UPDATE_STATE_COMMIT, MENDER_UPDATE_STATE_ROLLBACK },
117
    /* MENDER_UPDATE_STATE_COMMIT                 */ { MENDER_UPDATE_STATE_CLEANUP, MENDER_UPDATE_STATE_ROLLBACK },
118
    /* MENDER_UPDATE_STATE_CLEANUP                */ { MENDER_UPDATE_STATE_END, MENDER_UPDATE_STATE_END },
119
    /* MENDER_UPDATE_STATE_ROLLBACK               */ { MENDER_UPDATE_STATE_ROLLBACK_REBOOT, MENDER_UPDATE_STATE_FAILURE },
120
    /* MENDER_UPDATE_STATE_ROLLBACK_REBOOT        */ { MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT, MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT },
121
    /* MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT */ { MENDER_UPDATE_STATE_FAILURE, MENDER_UPDATE_STATE_ROLLBACK_REBOOT },
122
    /* MENDER_UPDATE_STATE_FAILURE                */ { MENDER_UPDATE_STATE_CLEANUP, MENDER_UPDATE_STATE_CLEANUP },
123
};
124

125
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_DBG
126
/* This is only needed for debug messages. */
127
static const char *update_state_str[N_MENDER_UPDATE_STATES + 1] = {
128
    "MENDER_UPDATE_STATE_DOWNLOAD",
129
    "MENDER_UPDATE_STATE_INSTALL",
130
    "MENDER_UPDATE_STATE_REBOOT",
131
    "MENDER_UPDATE_STATE_VERIFY_REBOOT",
132
    "MENDER_UPDATE_STATE_COMMIT",
133
    "MENDER_UPDATE_STATE_CLEANUP",
134
    "MENDER_UPDATE_STATE_ROLLBACK",
135
    "MENDER_UPDATE_STATE_ROLLBACK_REBOOT",
136
    "MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT",
137
    "MENDER_UPDATE_STATE_FAILURE",
138
    "MENDER_UPDATE_STATE_END",
139
};
140
static const char *client_state_str[N_MENDER_CLIENT_STATES + 1] = {
141
    "MENDER_CLIENT_STATE_INITIALIZATION",
142
    "MENDER_CLIENT_STATE_OPERATIONAL",
143
    "MENDER_CLIENT_STATE_PENDING_REBOOT",
144
};
145

146
#endif
147

148
/**
149
 * @brief Flag to know if network connection was requested or not
150
 */
151
static bool mender_client_network_connected = false;
152

153
/**
154
 * @brief Deployment data. Used to track progress of an update, so that the
155
 *        operation can resume or roll back across reboots
156
 */
157
static mender_deployment_data_t *mender_client_deployment_data = NULL;
158

159
/**
160
 * @brief Update module being used by the current deployment
161
 */
162
static mender_update_module_t *mender_update_module = NULL;
163

164
/**
165
 * @brief The main Mender work item
166
 */
167
static mender_work_t *mender_client_work = NULL;
168

169
/**
170
 * @brief Mender client work function
171
 * @return MENDER_OK if the function succeeds, error code otherwise
172
 */
173
static mender_err_t mender_client_work_function(void);
174

175
/**
176
 * @brief Mender client initialization work function
177
 * @return MENDER_OK if the function succeeds, error code otherwise
178
 */
179
static mender_err_t mender_client_initialization_work_function(void);
180

181
/**
182
 * @brief Function to request network access
183
 * @return MENDER_OK if network is connected following the request, error code otherwise
184
 */
185
static mender_err_t mender_client_network_connect(void);
186

187
/**
188
 * @brief Function to release network access
189
 * @return MENDER_OK if network is released following the request, error code otherwise
190
 */
191
static mender_err_t mender_client_network_release(void);
192

193
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
194
/**
195
 * @brief Compare artifact, device and deployment device types
196
 * @param device_type_artifact Device type of artifact
197
 * @param device_type_device Device type of configuration
198
 * @param device_type_deployment Device types of deployment
199
 * @param device_type_deployment_size Deployment device types size
200
 * @return MENDER_OK if the function succeeds, error code otherwise
201
 */
202
static mender_err_t mender_compare_device_types(const char  *device_type_artifact,
203
                                                const char  *device_type_device,
204
                                                const char **device_type_deployment,
205
                                                const size_t device_type_deployment_size);
206
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
207
/**
208
 * @brief Filter provides and merge the two lists
209
 * @param mender_artifact_ctx Mender artifact context
210
 * @param new_provides New provides list
211
 * @param stored_provides Stored provides list
212
 * @return MENDER_OK if the function succeeds, error code otherwise
213
 */
214
static mender_err_t mender_filter_provides(mender_artifact_ctx_t    *mender_artifact_ctx,
215
                                           mender_key_value_list_t **new_provides,
216
                                           mender_key_value_list_t **stored_provides);
217
/**
218
 * @brief Prepare the new provides data to be commited on a successful deployment
219
 * @param mender_artifact_ctx Mender artifact context
220
 * @param provides Provies data to be written
221
 * @return MENDER_OK if the function succeeds, error code otherwise
222
 */
223
static mender_err_t mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **provides, const char **artifact_name);
224

225
/**
226
 * @brief Determine the compatiblity of the deployment by: comparing artifact's depend with the stored provides
227
 * @param mender_artifact_ctx Mender artifact context
228
 * @return MENDER_OK if the function succeeds, error code otherwise
229
 */
230
static mender_err_t mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx);
231
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
232
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
233

234
/**
235
 * @brief Mender client update work function
236
 * @return MENDER_OK if the function succeeds, error code otherwise
237
 */
238
static mender_err_t mender_client_update_work_function(void);
239

240
/**
241
 * @brief Publish deployment status of the device to the mender-server and invoke deployment status callback
242
 * @param id ID of the deployment
243
 * @param deployment_status Deployment status
244
 * @return MENDER_OK if the function succeeds, error code otherwise
245
 */
246
static mender_err_t mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status);
247

248
/**
249
 * @brief Set state in deployment data and store it in permanent storage
250
 * @param state State to set and store
251
 * @return MENDER_OK in case of success, error code otherwise
252
 */
253
static mender_err_t set_and_store_state(const mender_update_state_t state);
254

255
mender_err_t
256
mender_client_validate_device_tier(const char *device_tier) {
48✔
257
    if (NULL == device_tier) {
48✔
258
        mender_log_error("Device tier cannot be NULL");
1✔
259
        return MENDER_FAIL;
1✔
260
    }
261

262
    if (StringEqual(device_tier, MENDER_DEVICE_TIER_STANDARD) || StringEqual(device_tier, MENDER_DEVICE_TIER_MICRO)) {
47✔
263
        return MENDER_OK;
38✔
264
    }
265

266
    mender_log_error("Invalid device tier '%s'. Valid tiers are '%s' and '%s'", device_tier, MENDER_DEVICE_TIER_STANDARD, MENDER_DEVICE_TIER_MICRO);
9✔
267
    return MENDER_FAIL;
9✔
268
}
269

270
const char *
271
mender_client_version(void) {
×
272

273
    /* Return version as string */
274
    return MENDER_CLIENT_VERSION;
×
275
}
276

277
mender_err_t
278
mender_client_init(mender_client_config_t *config, mender_client_callbacks_t *callbacks) {
35✔
279
    assert(NULL != config);
35✔
280
    assert(NULL != callbacks);
35✔
281
    assert(NULL != callbacks->restart);
35✔
282

283
    /* Either all allocation functions set or none. */
284
    assert(
35✔
285
        ((NULL == config->allocation_funcs.malloc_func) && (NULL == config->allocation_funcs.realloc_func) && (NULL == config->allocation_funcs.free_func))
286
        || ((NULL != config->allocation_funcs.malloc_func) && (NULL != config->allocation_funcs.realloc_func) && (NULL != config->allocation_funcs.free_func)));
287

288
    mender_err_t ret;
289

290
    if (NULL != config->allocation_funcs.malloc_func) {
35✔
291
        mender_set_allocation_funcs(config->allocation_funcs.malloc_func, config->allocation_funcs.realloc_func, config->allocation_funcs.free_func);
×
292
    } else {
293
        mender_set_platform_allocation_funcs();
35✔
294
    }
295

296
    {
297
        cJSON_Hooks cjson_alloc_funcs = { mender_malloc, mender_free };
35✔
298
        cJSON_InitHooks(&cjson_alloc_funcs);
35✔
299
    }
300

301
    /* Prefer client config over Kconfig */
302
    mender_client_config.device_type = IS_NULL_OR_EMPTY(config->device_type) ? CONFIG_MENDER_DEVICE_TYPE : config->device_type;
35✔
303
    if (IS_NULL_OR_EMPTY(mender_client_config.device_type)) {
35✔
304
        mender_log_error("Invalid device type configuration, can't be null or empty");
×
305
        ret = MENDER_FAIL;
×
306
        goto END;
×
307
    }
308
    mender_log_info("Device type: [%s]", mender_client_config.device_type);
35✔
309

310
    if ((NULL != config->host) && (strlen(config->host) > 0)) {
35✔
311
        mender_client_config.host = config->host;
×
312
    } else {
313
        mender_client_config.host = CONFIG_MENDER_SERVER_HOST;
35✔
314
    }
315
    if ((NULL == mender_client_config.host) || (0 == strlen(mender_client_config.host))) {
35✔
316
        mender_log_error("Invalid server host configuration, can't be null or empty");
×
317
        ret = MENDER_FAIL;
×
318
        goto END;
×
319
    }
320
    if ('/' == mender_client_config.host[strlen(mender_client_config.host) - 1]) {
35✔
321
        mender_log_error("Invalid server host configuration, trailing '/' is not allowed");
×
322
        ret = MENDER_FAIL;
×
323
        goto END;
×
324
    }
325
    if ((NULL != config->tenant_token) && (strlen(config->tenant_token) > 0)) {
35✔
326
        mender_client_config.tenant_token = config->tenant_token;
×
327
    } else {
328
        mender_client_config.tenant_token = CONFIG_MENDER_SERVER_TENANT_TOKEN;
35✔
329
    }
330
    if (!IS_NULL_OR_EMPTY(config->device_tier)) {
35✔
331
        if (MENDER_OK != (ret = mender_client_validate_device_tier(config->device_tier))) {
3✔
332
            /* Error logged in mender_client_validate_device_tier */
333
            goto END;
1✔
334
        }
335
        mender_client_config.device_tier = config->device_tier;
2✔
336
    } else {
337
        if (MENDER_OK != (ret = mender_client_validate_device_tier(CONFIG_MENDER_DEVICE_TIER))) {
32✔
338
            /* Error logged in mender_client_validate_device_tier */
339
            goto END;
×
340
        }
341
        mender_client_config.device_tier = CONFIG_MENDER_DEVICE_TIER;
32✔
342
    }
343
    if ((NULL != mender_client_config.tenant_token) && (0 == strlen(mender_client_config.tenant_token))) {
34✔
344
        mender_client_config.tenant_token = NULL;
×
345
    }
346
    if (0 != config->update_poll_interval) {
34✔
347
        mender_client_config.update_poll_interval = config->update_poll_interval;
×
348
    } else {
349
        mender_client_config.update_poll_interval = CONFIG_MENDER_CLIENT_UPDATE_POLL_INTERVAL;
34✔
350
    }
351
    if (0 != config->backoff_interval) {
34✔
352
        mender_client_config.backoff_interval = config->backoff_interval;
×
353
    } else {
354
        mender_client_config.backoff_interval = CONFIG_MENDER_RETRY_ERROR_BACKOFF;
34✔
355
    }
356
    if (0 != config->max_backoff_interval) {
34✔
357
        mender_client_config.max_backoff_interval = config->max_backoff_interval;
×
358
    } else {
359
        mender_client_config.max_backoff_interval = CONFIG_MENDER_RETRY_ERROR_MAX_BACKOFF;
34✔
360
    }
361
    mender_client_config.recommissioning = config->recommissioning;
34✔
362

363
    /* Save callbacks */
364
    memcpy(&mender_client_callbacks, callbacks, sizeof(mender_client_callbacks_t));
34✔
365

366
    /* Initializations */
367
    // TODO: what to do with the authentication interval?
368
    if (MENDER_OK != (ret = mender_os_scheduler_init())) {
34✔
369
        mender_log_error("Unable to initialize scheduler");
×
370
        goto END;
×
371
    }
372
    if (MENDER_OK != (ret = mender_log_init())) {
34✔
373
        mender_log_error("Unable to initialize log");
×
374
        goto END;
×
375
    }
376
    if (MENDER_OK != (ret = mender_storage_init())) {
34✔
377
        mender_log_error("Unable to initialize storage");
×
378
        goto END;
×
379
    }
380
    if (MENDER_OK != (ret = mender_tls_init())) {
34✔
381
        mender_log_error("Unable to initialize TLS");
×
382
        goto END;
×
383
    }
384
    mender_api_config_t mender_api_config = {
34✔
385
        .device_type  = mender_client_config.device_type,
34✔
386
        .host         = mender_client_config.host,
34✔
387
        .tenant_token = mender_client_config.tenant_token,
34✔
388
        .device_tier  = mender_client_config.device_tier,
34✔
389
        .identity_cb  = callbacks->get_identity,
34✔
390
    };
391
    if (MENDER_OK != (ret = mender_api_init(&mender_api_config))) {
34✔
392
        mender_log_error("Unable to initialize API");
×
393
        goto END;
×
394
    }
395

396
#ifdef CONFIG_MENDER_SERVER_DORMANT_CERTIFICATES
397
    if (MENDER_OK != (ret = mender_add_dormant_certs())) {
29✔
398
        /* error logged in function */
399
        goto END;
400
    }
401
    mender_log_debug("Added dormant certificate");
29✔
402
#endif
403

404
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
405
    if (MENDER_OK
34✔
406
        != (ret = mender_inventory_init(mender_client_config.inventory_update_interval,
34✔
407
                                        mender_client_config.device_type,
408
                                        mender_client_config.backoff_interval,
34✔
409
                                        mender_client_config.max_backoff_interval))) {
34✔
410
        mender_log_error("Failed to initialize the inventory functionality");
×
411
        goto END;
×
412
    }
413
    if (MENDER_OK != mender_inventory_add_default_callbacks()) {
34✔
414
        mender_log_error("Failed to enable default inventory");
×
415
        /* unlikely to happen and not a fatal issue, keep going */
416
    }
417
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
418

419
END:
34✔
420

421
    return ret;
35✔
422
}
423

424
mender_err_t
425
mender_client_activate(void) {
29✔
426
    mender_err_t ret;
427

428
    mender_os_scheduler_backoff_t backoff = {
29✔
429
        .interval     = mender_client_config.backoff_interval,
29✔
430
        .max_interval = mender_client_config.max_backoff_interval,
29✔
431
    };
432

433
    mender_os_scheduler_work_params_t work_params = {
29✔
434
        .function = mender_client_work_function,
435
        .period   = mender_client_config.update_poll_interval,
29✔
436
        .name     = "mender_client_main",
437
        .backoff  = backoff,
438
    };
439

440
    if ((MENDER_OK != (ret = mender_os_scheduler_work_create(&work_params, &mender_client_work)))
29✔
441
        || (MENDER_OK != (ret = mender_os_scheduler_work_activate(mender_client_work)))) {
29✔
442
        mender_log_error("Unable to activate the main work");
×
443
        return ret;
×
444
    }
445

446
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
447
    /* Activate inventory work */
448
    if (MENDER_OK != (ret = mender_inventory_activate())) {
29✔
449
        mender_log_error("Unable to activate the inventory functionality");
×
450
        return ret;
×
451
    }
452
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
453

454
    return ret;
29✔
455
}
456

457
mender_err_t
458
mender_client_ensure_connected(void) {
121✔
459
    if (mender_client_network_connected) {
121✔
460
        return MENDER_DONE;
93✔
461
    }
462

463
    return mender_client_network_connect();
28✔
464
}
465

466
static mender_err_t
467
mender_client_network_connect(void) {
28✔
468
    if (mender_client_network_connected) {
28✔
469
        return MENDER_OK;
×
470
    }
471

472
    /* Request network access */
473
    if (NULL != mender_client_callbacks.network_connect) {
28✔
474
        if (MENDER_OK != mender_client_callbacks.network_connect()) {
28✔
475
            mender_log_error("Unable to connect network");
×
476
            return MENDER_FAIL;
×
477
        }
478
    }
479

480
    mender_client_network_connected = true;
28✔
481

482
    return MENDER_OK;
28✔
483
}
484

485
static mender_err_t
486
mender_client_network_release(void) {
5✔
487
    if (!mender_client_network_connected) {
5✔
488
        return MENDER_OK;
5✔
489
    }
490

491
    /* Release network access */
492
    if (NULL != mender_client_callbacks.network_release) {
×
493
        if (MENDER_OK != mender_client_callbacks.network_release()) {
×
494
            mender_log_error("Unable to release network");
×
495
            return MENDER_FAIL;
×
496
        }
497
    }
498
    mender_client_network_connected = false;
×
499

500
    return MENDER_OK;
×
501
}
502

503
mender_err_t
504
mender_client_deactivate(void) {
5✔
505
    mender_err_t ret;
506

507
    if (NULL != mender_client_work) {
5✔
508
        if (MENDER_OK != (ret = mender_os_scheduler_work_deactivate(mender_client_work))) {
×
509
            mender_log_error("Failed to deactivate main work");
×
510
            return ret;
×
511
        }
512
    }
513
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
514
    if (MENDER_OK != (ret = mender_inventory_deactivate())) {
5✔
515
        /* error already logged */
516
        return ret;
×
517
    }
518
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
519

520
    return MENDER_OK;
5✔
521
}
522

523
mender_err_t
524
mender_client_exit(void) {
5✔
525
    bool some_error = false;
5✔
526

527
    if (MENDER_OK != mender_client_deactivate()) {
5✔
528
        /* error already logged; keep going on, we want to do as much cleanup as possible */
529
        some_error = true;
×
530
    }
531

532
    if (NULL != mender_client_work) {
5✔
533
        if (MENDER_OK != mender_os_scheduler_work_delete(mender_client_work)) {
×
534
            mender_log_error("Failed to delete main work");
×
535
            /* keep going on, we want to do as much cleanup as possible */
536
            some_error = true;
×
537
        } else {
538
            mender_client_work = NULL;
×
539
        }
540
    }
541

542
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
543
    if (MENDER_OK != mender_inventory_exit()) {
5✔
544
        mender_log_error("Unable to cleanup after the inventory functionality");
×
545
        /* keep going on, we want to do as much cleanup as possible */
546
        some_error = true;
×
547
    }
548
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
549

550
    /* Stop scheduling new work */
551
    mender_os_scheduler_exit();
5✔
552

553
    /* Release all modules */
554
    mender_api_exit();
5✔
555
    mender_tls_exit();
5✔
556
    mender_storage_exit();
5✔
557
    mender_log_exit();
5✔
558
    mender_client_network_release();
5✔
559

560
    /* Release memory */
561
    mender_client_config.device_type          = NULL;
5✔
562
    mender_client_config.host                 = NULL;
5✔
563
    mender_client_config.tenant_token         = NULL;
5✔
564
    mender_client_config.update_poll_interval = 0;
5✔
565
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
5✔
566

567
    mender_update_module_unregister_all();
5✔
568

569
    return some_error ? MENDER_FAIL : MENDER_OK;
5✔
570
}
571

572
static mender_err_t
573
mender_client_work_function(void) {
74✔
574
    mender_err_t ret;
575
    mender_log_debug("Inside work function [state: %s]", client_state_str[mender_client_state]);
74✔
576

577
    switch (mender_client_state) {
74✔
578
        case MENDER_CLIENT_STATE_PENDING_REBOOT:
14✔
579
            mender_log_info("Waiting for a reboot");
14✔
580
            if (MENDER_OK != mender_err_count_reboot_inc()) {
14✔
581
                /* It appears we are stuck in this state. The only thing we can do is to mark the
582
                   deployment as failed and revert to normal operation. */
583
                mender_log_error("Waiting for reboot for too long, trying unconditional reboot");
×
584
                mender_os_reboot();
×
585

586
                mender_log_error("Failed to reboot unconditionally, trying to resume operations");
×
587
                if (NULL == mender_client_deployment_data) {
×
588
                    mender_log_error("No deployment data to use for deployment abortion");
×
589
                } else {
590
                    mender_update_state_t update_state;
591
                    if (MENDER_OK != mender_deployment_data_get_state(mender_client_deployment_data, &update_state)) {
×
592
                        mender_log_error("Failed to get current update state, going to ROLLBACK state");
×
593
                        update_state = MENDER_UPDATE_STATE_ROLLBACK;
×
594
                    } else {
595
                        update_state = update_state_transitions[update_state].failure;
×
596
                    }
597
                    if (MENDER_OK != set_and_store_state(update_state)) {
×
598
                        mender_log_error("Failed to save new state");
×
599
                    }
600
                }
601

602
                mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
×
603
            }
604
            /* else:
605
               Nothing to do, but let's make sure we have a chance to detect we are stuck in this
606
               state (i.e. MENDER_OK, not MENDER_DONE which would tell the scheduler we are
607
               done and don't need to run again). */
608
            return MENDER_OK;
14✔
609
        case MENDER_CLIENT_STATE_INITIALIZATION:
29✔
610
            /* Perform initialization of the client */
611
            mender_err_count_reboot_reset();
29✔
612
            if (MENDER_DONE != mender_client_initialization_work_function()) {
29✔
613
                return MENDER_FAIL;
×
614
            }
615
            mender_client_state = MENDER_CLIENT_STATE_OPERATIONAL;
29✔
616
            /* fallthrough */
617
        case MENDER_CLIENT_STATE_OPERATIONAL:
60✔
618
            mender_err_count_reboot_reset();
60✔
619
            ret = mender_client_update_work_function();
60✔
620
            if (MENDER_FAIL == ret) {
45✔
621
                if (MENDER_FAIL == mender_err_count_net_check()) {
×
622
                    /* Try to release network so that it gets set up again next
623
                       time. */
624
                    mender_client_network_release();
×
625
                }
626
            } else if (!MENDER_IS_ERROR(ret)) {
45✔
627
                mender_err_count_net_reset();
45✔
628
            }
629
            if (MENDER_DONE == ret) {
45✔
630
                /* We should only be done when waiting for a reboot. */
631
                assert(MENDER_CLIENT_STATE_PENDING_REBOOT == mender_client_state);
14✔
632

633
                /* We don't want to tell the scheduler we are done because
634
                   otherwise we won't have a chance to detect that we are
635
                   waiting for a reboot forever. */
636
                ret = MENDER_OK;
14✔
637
            }
638
            return ret;
45✔
639
    }
640

641
    /* This should never be reached, all the cases should be covered in the
642
       above switch and they all return. */
643
    return MENDER_FAIL;
×
644
}
645

646
/* Flag to indicate whether a deployment has had a spontaneous reboot */
647
static bool spontaneous_reboot;
648

649
static mender_err_t
650
mender_client_initialization_work_function(void) {
29✔
651

652
    mender_err_t ret   = MENDER_DONE;
29✔
653
    spontaneous_reboot = false;
29✔
654

655
    /* Retrieve or generate authentication keys */
656
    if (MENDER_OK != (ret = mender_tls_init_authentication_keys(mender_client_callbacks.get_user_provided_keys, mender_client_config.recommissioning))) {
29✔
657
        mender_log_error("Unable to retrieve or generate authentication keys");
×
658
        goto END;
×
659
    }
660

661
    /* Retrieve deployment data if it is found (following an update) */
662
    if (MENDER_OK != (ret = mender_get_deployment_data(&mender_client_deployment_data))) {
29✔
663
        if (MENDER_NOT_FOUND != ret) {
13✔
664
            mender_log_error("Unable to get deployment data");
×
665
            goto REBOOT;
×
666
        }
667
    }
668

669
    /* Handle spontaneous reboots in  MENDER_UPDATE_STATE_INSTALL and MENDER_UPDATE_STATE_COMMIT
670
     See https://docs.mender.io/artifact-creation/state-scripts#power-loss */
671
    mender_update_state_t update_state;
672
    if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state))) {
29✔
673
        if ((MENDER_UPDATE_STATE_INSTALL == update_state) || (MENDER_UPDATE_STATE_COMMIT == update_state)) {
16✔
674
            mender_log_debug("Spontaneous reboot detected in state %s", update_state_str[update_state]);
2✔
675
            spontaneous_reboot = true;
2✔
676
        }
677
    }
678

679
    mender_log_info("Initialization done");
29✔
680

681
    return MENDER_DONE;
29✔
682

683
END:
×
684

685
    return ret;
×
686

687
REBOOT:
×
688

689
    mender_log_info("Rebooting...");
×
690

691
    /* Delete pending deployment */
692
    mender_storage_delete_deployment_data();
×
693

694
    /* Invoke restart callback, application is responsible to shutdown properly and restart the system */
695
    /* Set the client's state to PENDING_REBOOT so that we can potentially
696
       detect a failure to reboot (i.e. waiting for reboot taking too long).  */
697
    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
×
698
    if (NULL != mender_client_callbacks.restart) {
×
699
        mender_client_callbacks.restart();
×
700
    }
701

702
    return ret;
×
703
}
704

705
static mender_err_t
706
mender_commit_artifact_data(void) {
5✔
707

708
    assert(NULL != mender_client_deployment_data);
5✔
709

710
    const char *artifact_name;
711
    if (MENDER_OK != mender_deployment_data_get_artifact_name(mender_client_deployment_data, &artifact_name)) {
5✔
712
        mender_log_error("Unable to get artifact name from the deployment data");
×
713
        return MENDER_FAIL;
×
714
    }
715

716
    if (MENDER_OK != mender_storage_set_artifact_name(artifact_name)) {
5✔
717
        mender_log_error("Unable to set artifact name");
×
718
        return MENDER_FAIL;
×
719
    }
720

721
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
722
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
723
    /* Get provides from the deployment data */
724
    const char *provides;
725
    if (MENDER_OK != mender_deployment_data_get_provides(mender_client_deployment_data, &provides)) {
5✔
726
        mender_log_error("Unable to get new_provides from the deployment data");
×
727
        return MENDER_FAIL;
×
728
    }
729

730
    /* Parse provides */
731
    mender_key_value_list_t *new_provides = NULL;
5✔
732
    if (MENDER_OK != mender_utils_string_to_key_value_list(provides, &new_provides)) {
5✔
733
        mender_log_error("Unable to parse provides from the deployment data");
×
734
        return MENDER_FAIL;
×
735
    }
736
    /* Replace the stored provides with the new provides */
737
    if (MENDER_OK != mender_storage_set_provides(new_provides)) {
5✔
738
        mender_log_error("Unable to set provides");
×
739
        mender_utils_key_value_list_free(new_provides);
×
740
        return MENDER_FAIL;
×
741
    }
742
    mender_utils_key_value_list_free(new_provides);
5✔
743
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
744
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
745

746
    return MENDER_OK;
5✔
747
}
748

749
static mender_err_t
750
deployment_destroy(mender_api_deployment_data_t *deployment) {
45✔
751
    if (NULL != deployment) {
45✔
752
        mender_free(deployment->id);
30✔
753
        mender_free(deployment->artifact_name);
30✔
754
        mender_free(deployment->uri);
30✔
755
        for (size_t i = 0; i < deployment->device_types_compatible_size; ++i) {
40✔
756
            mender_free(deployment->device_types_compatible[i]);
10✔
757
        }
758
        mender_free(deployment->device_types_compatible);
30✔
759
        mender_free(deployment);
30✔
760
    }
761
    return MENDER_OK;
45✔
762
}
763

764
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
765
static mender_err_t
766
mender_compare_device_types(const char  *device_type_artifact,
11✔
767
                            const char  *device_type_device,
768
                            const char **device_type_deployment,
769
                            const size_t device_type_deployment_size) {
770

771
    assert(NULL != device_type_artifact);
11✔
772
    assert(NULL != device_type_deployment);
11✔
773
    assert(NULL != device_type_device);
11✔
774
    assert(0 < device_type_deployment_size);
11✔
775

776
    if (!StringEqual(device_type_artifact, device_type_device)) {
11✔
777
        mender_log_error("Device type from artifact '%s' is not compatible with device '%s'", device_type_artifact, device_type_device);
×
778
        return MENDER_FAIL;
×
779
    }
780

781
    /* Return MENDER_OK if one of the devices in the deployment are compatible with the device */
782
    for (size_t i = 0; i < device_type_deployment_size; i++) {
11✔
783
        if (StringEqual(device_type_deployment[i], device_type_device)) {
11✔
784
            return MENDER_OK;
11✔
785
        }
786
    }
787
    mender_log_error("None of the device types from the deployment are compatible with device '%s'", device_type_device);
×
788
    return MENDER_FAIL;
×
789
}
790

791
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
792
static mender_err_t
793
mender_filter_provides(mender_artifact_ctx_t *mender_artifact_ctx, mender_key_value_list_t **new_provides, mender_key_value_list_t **stored_provides) {
11✔
794

795
    mender_err_t ret = MENDER_FAIL;
11✔
796
    /* Clears provides */
797
    bool matches;
798
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
22✔
799
        for (size_t j = 0; j < mender_artifact_ctx->payloads.values[i].clears_provides_size; j++) {
22✔
800
            const char *to_clear = mender_artifact_ctx->payloads.values[i].clears_provides[j];
11✔
801
            for (mender_key_value_list_t *item = *stored_provides; NULL != item; item = item->next) {
11✔
802
                if (MENDER_OK != mender_utils_compare_wildcard(item->key, to_clear, &matches)) {
×
803
                    mender_log_error("Unable to compare wildcard %s with key %s", to_clear, item->key);
×
804
                    goto END;
×
805
                }
806
                if (matches && MENDER_OK != mender_utils_key_value_list_delete_node(stored_provides, item->key)) {
×
807
                    mender_log_error("Unable to delete node containing key %s", item->key);
×
808
                    goto END;
×
809
                }
810
            }
811
        }
812
    }
813

814
    /* Combine the stored provides with the new ones */
815
    if (MENDER_OK != mender_utils_key_value_list_append_unique(new_provides, stored_provides)) {
11✔
816
        mender_log_error("Unable to merge provides");
×
817
        goto END;
×
818
    }
819

820
    /* Make sure the artifact name is not in the new provides */
821
    if (MENDER_OK != mender_utils_key_value_list_delete_node(new_provides, "artifact_name")) {
11✔
822
        mender_log_error("Unable to delete node containing key 'artifact_name'");
×
823
        goto END;
×
824
    }
825

826
    ret = MENDER_OK;
11✔
827

828
END:
11✔
829

830
    mender_utils_key_value_list_free(*stored_provides);
11✔
831
    return ret;
11✔
832
}
833

834
static mender_err_t
835
mender_prepare_new_provides(mender_artifact_ctx_t *mender_artifact_ctx, char **new_provides, const char **artifact_name) {
11✔
836

837
    assert(NULL != artifact_name);
11✔
838
    assert(NULL != mender_artifact_ctx);
11✔
839

840
    /* Load the currently stored provides */
841
    mender_key_value_list_t *stored_provides = NULL;
11✔
842
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
11✔
843
        mender_log_error("Unable to get provides");
×
844
        return MENDER_FAIL;
×
845
    }
846

847
    mender_key_value_list_t *provides = NULL;
11✔
848
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
22✔
849
        if (MENDER_OK != mender_utils_key_value_list_append(&provides, &mender_artifact_ctx->payloads.values[i].provides)) {
11✔
850
            mender_log_error("Unable to merge provides");
×
851
            mender_utils_key_value_list_free(stored_provides);
×
852
            return MENDER_FAIL;
×
853
        }
854
    }
855

856
    /* Get artifact name from provides */
857
    for (mender_key_value_list_t *item = mender_artifact_ctx->artifact_info.provides; NULL != item; item = item->next) {
11✔
858
        if (StringEqual("artifact_name", item->key)) {
11✔
859
            *artifact_name = item->value;
11✔
860
            break;
11✔
861
        }
862
    }
863

864
    if (NULL == *artifact_name) {
11✔
865
        mender_log_error("No artifact name found in provides");
×
866
        mender_utils_key_value_list_free(stored_provides);
×
867
        return MENDER_FAIL;
×
868
    }
869

870
    /* Filter provides */
871
    /* `stored_provides` is freed in `mender_filter_provides` */
872
    if (MENDER_OK != mender_filter_provides(mender_artifact_ctx, &provides, &stored_provides)) {
11✔
873
        return MENDER_FAIL;
×
874
    }
875

876
    if (MENDER_OK != mender_utils_key_value_list_to_string(provides, new_provides)) {
11✔
877
        mender_utils_key_value_list_free(provides);
×
878
        return MENDER_FAIL;
×
879
    }
880

881
    mender_utils_key_value_list_free(provides);
11✔
882
    return MENDER_OK;
11✔
883
}
884

885
static mender_err_t
886
mender_check_device_compatibility(mender_artifact_ctx_t *mender_artifact_ctx) {
11✔
887

888
    /* We need to load the stored provides */
889
    mender_key_value_list_t *stored_provides = NULL;
11✔
890
    if (MENDER_FAIL == mender_storage_get_provides(&stored_provides)) {
11✔
891
        return MENDER_FAIL;
×
892
    }
893

894
    mender_err_t ret = MENDER_FAIL;
11✔
895

896
    /* Get depends */
897
    mender_key_value_list_t *depends = NULL;
11✔
898
    for (size_t i = 0; i < mender_artifact_ctx->payloads.size; i++) {
22✔
899
        if (MENDER_OK != mender_utils_key_value_list_append(&depends, &mender_artifact_ctx->payloads.values[i].depends)) {
11✔
900
            mender_log_error("Unable to append depends");
×
901
            goto END;
×
902
        }
903
    }
904

905
    /* Match depends from artifact with device's provides */
906
    for (mender_key_value_list_t *depends_item = depends; NULL != depends_item; depends_item = depends_item->next) {
11✔
907
        bool matches = false;
×
908
        for (mender_key_value_list_t *provides_item = stored_provides; NULL != provides_item; provides_item = provides_item->next) {
×
909
            /* Match key-value from depends with provides */
910
            if (StringEqual(depends_item->key, provides_item->key)) {
×
911
                if (!StringEqual(depends_item->value, provides_item->value)) {
×
912
                    mender_log_error("Value mismatch for key '%s': depends-value '%s' does not match provides-value '%s'",
×
913
                                     depends_item->key,
914
                                     depends_item->value,
915
                                     provides_item->value);
916
                    break;
×
917
                }
918
                matches = true;
×
919
                break;
×
920
            }
921
        }
922
        if (!matches) {
×
923
            mender_log_error("Missing '%s:%s' in provides, required by artifact depends", depends_item->key, depends_item->value);
×
924
            goto END;
×
925
        }
926
    }
927

928
    ret = MENDER_OK;
11✔
929

930
END:
11✔
931
    mender_utils_key_value_list_free(stored_provides);
11✔
932
    return ret;
11✔
933
}
934
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
935
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
936

937
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
938
static mender_err_t
939
mender_check_artifact_requirements(mender_artifact_ctx_t *mender_artifact_ctx, mender_api_deployment_data_t *deployment) {
11✔
940
    mender_err_t ret;
941

942
    /* Retrieve device type from artifact */
943
    const char *device_type_artifact = NULL;
11✔
944
    if (MENDER_OK != (ret = mender_artifact_get_device_type(mender_artifact_ctx, &device_type_artifact))) {
11✔
945
        mender_log_error("Unable to get device type from artifact");
×
946
        return ret;
×
947
    }
948

949
    mender_log_debug("Checking device type compatibility");
11✔
950

951
    /* Match device type  */
952
    if (MENDER_OK
11✔
953
        != (ret = mender_compare_device_types(device_type_artifact,
11✔
954
                                              mender_client_config.device_type,
955
                                              (const char **)deployment->device_types_compatible,
11✔
956
                                              deployment->device_types_compatible_size))) {
957
        return ret;
×
958
    }
959

960
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
961
    /* Compare Artifact's depends with the stored provides */
962
    if (MENDER_OK != (ret = mender_check_device_compatibility(mender_artifact_ctx))) {
11✔
963
        return ret;
×
964
    }
965
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
966

967
    /* Check payload integrity by comparing computed checksum(s) with those
968
     * listed in the artifact manifest */
969
    if (MENDER_OK != mender_artifact_check_integrity_remaining(mender_artifact_ctx)) {
11✔
970
        return MENDER_FAIL;
×
971
    }
972

973
    return MENDER_OK;
11✔
974
}
975
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
976

977
static mender_err_t
978
mender_client_check_deployment(mender_api_deployment_data_t **deployment_data) {
44✔
979
    assert(NULL != deployment_data);
44✔
980

981
    if (MENDER_FAIL == mender_client_ensure_connected()) {
44✔
982
        /* network errors logged already */
983
        mender_log_error("Cannot check for new deployment");
×
984
        return MENDER_FAIL;
×
985
    }
986

987
    if (NULL == (*deployment_data = mender_calloc(1, sizeof(mender_api_deployment_data_t)))) {
44✔
988
        mender_log_error("Unable to allocate memory for deployment data");
×
989
        return MENDER_FAIL;
×
990
    }
991

992
    mender_api_deployment_data_t *deployment = *deployment_data;
44✔
993

994
    mender_err_t ret = MENDER_OK;
44✔
995

996
    mender_log_info("Checking for deployment...");
44✔
997
    if (MENDER_NOT_FOUND == (ret = mender_api_check_for_deployment(deployment))) {
44✔
998
        mender_log_info("No deployment available");
20✔
999
        return MENDER_DONE;
20✔
1000
    } else if (MENDER_OK != ret) {
12✔
1001
        mender_log_error("Unable to check for deployment");
×
1002
        return ret;
×
1003
    }
1004

1005
    /* Check if deployment is valid */
1006
    if ((NULL == deployment->id) || (NULL == deployment->artifact_name) || (NULL == deployment->uri) || (NULL == deployment->device_types_compatible)) {
12✔
1007
        mender_log_error("Invalid deployment data");
×
1008
        return MENDER_FAIL;
×
1009
    }
1010

1011
    /* Create deployment data */
1012
    if (NULL != mender_client_deployment_data) {
12✔
1013
        mender_log_warning("Unexpected stale deployment data");
×
1014
        mender_delete_deployment_data(mender_client_deployment_data);
×
1015
    }
1016
    if (MENDER_OK != (mender_create_deployment_data(deployment->id, deployment->artifact_name, &mender_client_deployment_data))) {
12✔
1017
        /* Error already logged */
1018
        return MENDER_FAIL;
×
1019
    }
1020

1021
    return MENDER_OK;
12✔
1022
}
1023

1024
static mender_err_t
1025
set_and_store_state(const mender_update_state_t state) {
79✔
1026

1027
    /*
1028
     * Set the state in `mender_client_deployment_data` and write it to the nvs
1029
     */
1030

1031
    mender_err_t ret = MENDER_OK;
79✔
1032

1033
    /* Set state in deployment data */
1034
    if (MENDER_OK != (ret = mender_deployment_data_set_state(mender_client_deployment_data, state))) {
79✔
1035
        mender_log_error("Failed to set deployment data state");
×
1036
        return ret;
×
1037
    }
1038

1039
    /* Store deployment data */
1040
    if (MENDER_OK != (ret = mender_set_deployment_data(mender_client_deployment_data))) {
79✔
1041
        mender_log_error("Failed to store deployment data");
1✔
1042
        return ret;
1✔
1043
    }
1044
    return ret;
78✔
1045
}
1046

1047
static mender_err_t
1048
mender_client_update_work_function(void) {
60✔
1049
    mender_err_t ret = MENDER_OK;
60✔
1050

1051
    /* Ensure that the context is initialized to NULL before goto END */
1052
    mender_artifact_ctx_t *mender_artifact_ctx = NULL;
60✔
1053

1054
    /* Check for deployment */
1055
    mender_api_deployment_data_t *deployment    = NULL;
60✔
1056
    mender_update_state_t         update_state  = MENDER_UPDATE_STATE_DOWNLOAD;
60✔
1057
    const char                   *deployment_id = NULL;
60✔
1058

1059
    /* reset the currently used update module */
1060
    mender_update_module = NULL;
60✔
1061

1062
    if (NULL != mender_client_deployment_data) {
60✔
1063
        mender_deployment_data_get_id(mender_client_deployment_data, &deployment_id);
16✔
1064
    }
1065

1066
    {
1067
        const char           *artifact_type;
1068
        mender_update_state_t update_state_resume;
1069
        if (MENDER_OK == (ret = mender_deployment_data_get_state(mender_client_deployment_data, &update_state_resume))
60✔
1070
            && MENDER_OK == mender_deployment_data_get_payload_type(mender_client_deployment_data, &artifact_type)) {
16✔
1071
            update_state = update_state_resume;
16✔
1072
            mender_log_debug("Resuming from state %s", update_state_str[update_state]);
16✔
1073

1074
#ifdef CONFIG_MENDER_DEPLOYMENT_LOGS
1075
            if (MENDER_UPDATE_STATE_DOWNLOAD != update_state) {
16✔
1076
                if (MENDER_OK != mender_deployment_logs_activate()) {
16✔
1077
                    mender_log_error("Failed to activate deployment logs saving");
1078
                    /* Not a fatal issue to abort the deployment, keep going. */
1079
                }
1080
            }
1081
#endif /* CONFIG_MENDER_DEPLOYMENT_LOGS */
1082

1083
            mender_update_module = mender_update_module_get(artifact_type);
16✔
1084
            if (NULL == mender_update_module) {
16✔
1085
                /* The artifact_type from the saved state does not match any update module */
1086
                mender_log_error("No update module found for artifact type '%s'", artifact_type);
×
1087
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1088
                mender_storage_delete_deployment_data();
×
1089
                goto END;
×
1090
            }
1091
        }
1092
    }
1093

1094
    /* Skip the block below if we just resume from a saved state. */
1095

1096
/* A macro to advance to the next state -- on success we just keep going to the
1097
 * code below the macro invocation (fallthrough to the next case), on error we
1098
 * go to the beginning of the loop (the switch statement) again using 'continue'
1099
 * (see below).
1100
 *
1101
 * mender_update_module is guaranteed be not NULL since the first
1102
 * successful transition (from the DOWNLOAD state). */
1103
#define NEXT_STATE                                                             \
1104
    if (MENDER_OK == ret) {                                                    \
1105
        update_state = update_state_transitions[update_state].success;         \
1106
        assert(NULL != mender_update_module);                                  \
1107
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
1108
        if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {       \
1109
            update_state = MENDER_UPDATE_STATE_FAILURE;                        \
1110
        }                                                                      \
1111
    } else {                                                                   \
1112
        update_state = update_state_transitions[update_state].failure;         \
1113
        mender_log_debug("Entering state %s", update_state_str[update_state]); \
1114
        if (NULL != mender_update_module) {                                    \
1115
            if (MENDER_LOOP_DETECTED == set_and_store_state(update_state)) {   \
1116
                update_state = MENDER_UPDATE_STATE_FAILURE;                    \
1117
            }                                                                  \
1118
        }                                                                      \
1119
        ret = MENDER_OK;                                                       \
1120
        continue;                                                              \
1121
    }
1122

1123
    if (spontaneous_reboot) {
60✔
1124
        mender_log_error("Failing deployment, spontaneous reboot detected");
2✔
1125
        spontaneous_reboot = false;
2✔
1126
        update_state       = update_state_transitions[update_state].failure;
2✔
1127
        mender_log_debug("Entering state %s", update_state_str[update_state]);
2✔
1128
    }
1129
    while (MENDER_UPDATE_STATE_END != update_state) {
161✔
1130
        switch (update_state) {
90✔
1131
            case MENDER_UPDATE_STATE_DOWNLOAD:
44✔
1132
                /* This is usually logged in the NEXT_STATE macro, but since nothing
1133
                 * transitions to this state, we log it here */
1134
                mender_log_debug("Entering state %s", update_state_str[update_state]);
44✔
1135

1136
                /* Check for deployment */
1137
                if (MENDER_OK != (ret = mender_client_check_deployment(&deployment))) {
44✔
1138
                    /* No deployment available, but we are not done, we need to keep checking. */
1139
                    if (MENDER_DONE == ret) {
20✔
1140
                        ret = MENDER_OK;
20✔
1141
                    }
1142
                    goto END;
20✔
1143
                }
1144

1145
#ifdef CONFIG_MENDER_DEPLOYMENT_LOGS
1146
                if (MENDER_OK != mender_storage_deployment_log_clear()) {
12✔
1147
                    mender_log_error("Failed to clean old deployment logs");
1148
                    /* Not a fatal issue to abort the deployment, keep going. */
1149
                }
1150
                if (MENDER_OK != mender_deployment_logs_activate()) {
12✔
1151
                    mender_log_error("Failed to activate deployment logs saving");
1152
                    /* Not a fatal issue to abort the deployment, keep going. */
1153
                }
1154
#endif /* CONFIG_MENDER_DEPLOYMENT_LOGS */
1155

1156
#if CONFIG_MENDER_LOG_LEVEL >= MENDER_LOG_LEVEL_INF
1157
                if (strlen(deployment->id) > 10) {
12✔
1158
                    mender_log_info("Downloading artifact with id '%.7s...', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
12✔
1159
                } else {
1160
                    mender_log_info("Downloading artifact with id '%s', name '%s', uri '%s'", deployment->id, deployment->artifact_name, deployment->uri);
×
1161
                }
1162
#endif
1163
                /* Set deployment_id */
1164
                deployment_id = deployment->id;
12✔
1165

1166
                /* Check ret to see if the deployment is aborted */
1167
                ret = mender_client_publish_deployment_status(deployment->id, MENDER_DEPLOYMENT_STATUS_DOWNLOADING);
12✔
1168
                if ((MENDER_ABORTED != ret)
12✔
1169
                    && (MENDER_OK
12✔
1170
                        == (ret = mender_download_artifact(deployment->uri, mender_client_deployment_data, &mender_update_module, &mender_artifact_ctx)))) {
12✔
1171
                    assert(NULL != mender_update_module);
11✔
1172
                    assert(NULL != mender_artifact_ctx);
11✔
1173

1174
                    /* Get artifact context if artifact download succeeded */
1175
                    if ((NULL != mender_update_module) && (NULL != mender_artifact_ctx)) {
11✔
1176
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
1177
                        if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) {
22✔
1178
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
1179
                            /* Add the new provides to the deployment data (we need the artifact context) */
1180
                            char       *new_provides  = NULL;
11✔
1181
                            const char *artifact_name = NULL;
11✔
1182
                            if (MENDER_OK == (ret = mender_prepare_new_provides(mender_artifact_ctx, &new_provides, &artifact_name))) {
11✔
1183
                                if (MENDER_OK != (ret = mender_deployment_data_set_provides(mender_client_deployment_data, new_provides))) {
11✔
1184
                                    mender_log_error("Failed to set deployment data provides");
×
1185
                                }
1186
                                /* Replace artifact_name with the one from provides */
1187
                                else if (MENDER_OK != (ret = mender_deployment_data_set_artifact_name(mender_client_deployment_data, artifact_name))) {
11✔
1188
                                    mender_log_error("Failed to set deployment data artifact name");
×
1189
                                }
1190
                                mender_free(new_provides);
11✔
1191
                            } else {
1192
                                mender_log_error("Unable to prepare new provides");
×
1193
                            }
1194
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
1195
                        } else {
1196
                            mender_log_error("Artifact check failed");
×
1197
                        }
1198
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
1199
                    } else {
1200
                        mender_log_error("Unable to get artifact type and context");
×
1201
                    }
1202
                } else {
1203
                    mender_log_error("Unable to download artifact");
1✔
1204
                    /* Error logged in mender_client_download_artifact_callback() */
1205
                    ret = MENDER_FAIL;
1✔
1206
                }
1207
                if (MENDER_OK != ret) {
12✔
1208
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
1✔
1209
                }
1210
                NEXT_STATE;
12✔
1211
                /* fallthrough */
1212

1213
            case MENDER_UPDATE_STATE_INSTALL:
1214
                mender_log_info("Download done, installing artifact");
11✔
1215
                /* Check ret to see if the deployment is aborted */
1216
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING);
11✔
1217
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
10✔
1218
                    if (mender_update_module->requires_reboot) {
9✔
1219
                        /* Save the next state before running the install callback.
1220
                         * If there is a spontaneous reboot right after the callback
1221
                         * we assure that we don't get stuck in a potential pending image in slot 1 */
1222
                        set_and_store_state(MENDER_UPDATE_STATE_REBOOT);
8✔
1223
                    }
1224
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
9✔
1225
                }
1226
                if (MENDER_OK == ret) {
10✔
1227
                    if (mender_update_module->requires_reboot) {
8✔
1228
                        update_state = MENDER_UPDATE_STATE_REBOOT;
7✔
1229
                        mender_log_debug("Entering state %s", update_state_str[update_state]);
7✔
1230
                        /* State already stored */
1231
                        continue;
7✔
1232
                    } else {
1233
                        /* skip reboot */
1234
                        update_state = MENDER_UPDATE_STATE_COMMIT;
1✔
1235
                        mender_log_debug("Entering state %s", update_state_str[update_state]);
1✔
1236
                        set_and_store_state(update_state);
1✔
1237
                        continue;
1✔
1238
                    }
1239
                }
1240
                /* else continue to the next successful/failure state */
1241
                NEXT_STATE;
2✔
1242
                /* fallthrough */
1243

1244
            case MENDER_UPDATE_STATE_REBOOT:
1245
                assert(mender_update_module->requires_reboot);
7✔
1246
                mender_log_info("Artifact installation done, rebooting");
7✔
1247
                /* Check ret to see if the deployment is aborted */
1248
                ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_REBOOTING);
7✔
1249
                if ((MENDER_ABORTED != ret) && (NULL != mender_update_module->callbacks[update_state])) {
7✔
1250
                    /* Save the next state before running the reboot callback --
1251
                     * if there is an interrupt (power, crash,...) right after,
1252
                     * it will reboot anyway so after the new boot, reboot
1253
                     * verification should happen anyway, the callback in that
1254
                     * state should be able to see if things went well or
1255
                     * wrong. */
1256
                    set_and_store_state(MENDER_UPDATE_STATE_VERIFY_REBOOT);
7✔
1257
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1258
                    if (MENDER_OK == ret) {
7✔
1259
                        /* now we need to get outside of the loop so that a
1260
                         * potential asynchronous reboot has a chance to kick in
1261
                         * after a proper cleanup below */
1262
                        mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
7✔
1263
                        ret                 = MENDER_DONE;
7✔
1264
                        goto END;
7✔
1265
                    }
1266
                }
1267
                NEXT_STATE;
×
1268
                /* fallthrough */
1269

1270
            case MENDER_UPDATE_STATE_VERIFY_REBOOT:
1271
                assert(mender_update_module->requires_reboot);
7✔
1272
                if (NULL != mender_update_module->callbacks[update_state]) {
7✔
1273
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1274
                }
1275
                NEXT_STATE;
7✔
1276
                /* fallthrough */
1277

1278
            case MENDER_UPDATE_STATE_COMMIT:
1279
                /* Check for pending deployment */
1280
                if (NULL == mender_client_deployment_data) {
6✔
1281
                    mender_log_error("No deployment data found on commit");
×
1282
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
×
1283
                    goto END;
×
1284
                }
1285
#ifdef CONFIG_MENDER_COMMIT_REQUIRE_AUTH
1286
                if (MENDER_OK != mender_api_drop_authentication_data()) {
6✔
1287
                    mender_log_error("Failed to drop authentication data before artifact commit");
×
1288
                    /* Unlikely (practically impossible?) to happen and if it does, we don't have
1289
                       much to about it. */
1290
                }
1291
                if (MENDER_IS_ERROR(ret = mender_api_ensure_authenticated())) {
6✔
1292
                    mender_log_error("Failed to authenticate before commit, rejecting the update");
×
1293
                }
1294

1295
                /* Try to update the deployment status one last time before
1296
                   commit so that we have a chance to detect an aborted
1297
                   deployment before it's too late. */
1298
                if (!MENDER_IS_ERROR(ret)
5✔
1299
                    && (MENDER_OK != (ret = mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_INSTALLING)))) {
5✔
1300
                    if (MENDER_ABORTED == ret) {
×
1301
                        mender_log_info("Aborted deployment, not committing");
×
1302
                    } else {
1303
                        mender_log_error("Failed to check deployment status before commit, rejecting the update");
×
1304
                    }
1305
                }
1306
#endif /* CONFIG_MENDER_COMMIT_REQUIRE_AUTH */
1307
                if (!MENDER_IS_ERROR(ret) && (MENDER_OK != (ret = mender_commit_artifact_data()))) {
5✔
1308
                    mender_log_error("Unable to commit artifact data");
×
1309
                }
1310
                if (!MENDER_IS_ERROR(ret) && (NULL != mender_update_module->callbacks[update_state])) {
5✔
1311
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
5✔
1312
                }
1313
#ifndef CONFIG_MENDER_CLIENT_INVENTORY_DISABLE
1314
                /* If there was no reboot, we need to tell inventory to refresh
1315
                   the persistent data (because the deployment must have changed
1316
                   artifact name, at least) and we should trigger an inventory
1317
                   submission to refresh the data on the server. */
1318
                if (!mender_update_module->requires_reboot) {
5✔
1319
                    if (MENDER_OK != (ret = mender_inventory_reset_persistent())) {
1✔
1320
                        mender_log_error("Failed to reset persistent inventory after deployment commit with no reboot");
×
1321
                    } else if (MENDER_OK != (ret = mender_inventory_execute())) {
1✔
1322
                        mender_log_error("Failed to trigger inventory refresh after deployment commit with no reboot");
×
1323
                    }
1324
                }
1325
#endif /* CONFIG_MENDER_CLIENT_INVENTORY_DISABLE */
1326
                if (!MENDER_IS_ERROR(ret)) {
5✔
1327
                    mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_SUCCESS);
2✔
1328
                }
1329
                NEXT_STATE;
5✔
1330
                /* fallthrough */
1331

1332
            case MENDER_UPDATE_STATE_CLEANUP:
1333
                if (NULL != mender_update_module) {
11✔
1334
                    if (NULL != mender_update_module->callbacks[update_state]) {
10✔
1335
                        ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
×
1336
                    }
1337
                } else {
1338
                    ret = MENDER_FAIL;
1✔
1339
                }
1340
                NEXT_STATE;
11✔
1341
                mender_storage_delete_deployment_data();
10✔
1342
                break; /* below is the failure path */
10✔
1343

1344
            case MENDER_UPDATE_STATE_ROLLBACK:
6✔
1345
                if (!mender_update_module->supports_rollback) {
6✔
1346
                    mender_log_warning("Rollback not supported for artifacts of type '%s'", mender_update_module->artifact_type);
1✔
1347
                    ret = MENDER_FAIL;
1✔
1348
                } else if (NULL != mender_update_module->callbacks[update_state]) {
5✔
1349
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
5✔
1350
                }
1351
                NEXT_STATE;
6✔
1352
                /* fallthrough */
1353

1354
            case MENDER_UPDATE_STATE_ROLLBACK_REBOOT:
1355
                /* Save the next state before running the reboot callback (see
1356
                 * STATE_REBOOT for details). */
1357
                set_and_store_state(MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT);
7✔
1358
                ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1359

1360
                if (MENDER_OK == ret) {
7✔
1361
                    /* now we need to get outside of the loop so that a
1362
                     * potential asynchronous reboot has a chance to kick in
1363
                     * after a proper cleanup below */
1364
                    mender_client_state = MENDER_CLIENT_STATE_PENDING_REBOOT;
7✔
1365
                    ret                 = MENDER_DONE;
7✔
1366
                    goto END;
7✔
1367
                }
1368
                NEXT_STATE;
×
1369
                /* fallthrough */
1370

1371
            case MENDER_UPDATE_STATE_ROLLBACK_VERIFY_REBOOT:
1372
                if (NULL != mender_update_module->callbacks[update_state]) {
7✔
1373
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
7✔
1374
                }
1375

1376
                if (MENDER_OK != ret) {
7✔
1377
                    /* If the rollback verify reboot fails,
1378
                     * we will retry the rollback reboot.
1379
                     *
1380
                     * The `rollback-reboot -> rollback-verify-reboot -> rollback-reboot -> ...`
1381
                     * loop is broken when a state loop is detected
1382
                     */
1383
                    mender_log_error("Rollback verify reboot failed. Retry rollback reboot");
4✔
1384
                }
1385

1386
                NEXT_STATE;
7✔
1387
                /* fallthrough */
1388

1389
            case MENDER_UPDATE_STATE_FAILURE:
1390
                mender_client_publish_deployment_status(deployment_id, MENDER_DEPLOYMENT_STATUS_FAILURE);
9✔
1391
                if (NULL != mender_update_module->callbacks[update_state]) {
8✔
1392
                    ret = mender_update_module->callbacks[update_state](update_state, (mender_update_state_data_t)NULL);
8✔
1393
                }
1394
                NEXT_STATE;
8✔
1395
                break; /* end of the failure path */
8✔
1396

1397
            case MENDER_UPDATE_STATE_END:
×
1398
                /* This is only here to cover all possible values of the
1399
                 * update_state enum, there is nothing to do here, the while
1400
                 * loop shall stop when we get here. */
1401
                break;
×
1402
        }
1403
    }
1404
#undef NEXT_STATE /* should not be used anywhere else */
1405

1406
    ret = MENDER_OK;
11✔
1407

1408
END:
45✔
1409
    /* Release memory */
1410
    deployment_destroy(deployment);
45✔
1411
    DESTROY_AND_NULL(mender_delete_deployment_data, mender_client_deployment_data);
45✔
1412
    mender_artifact_release_ctx(mender_artifact_ctx);
45✔
1413

1414
#ifdef CONFIG_MENDER_DEPLOYMENT_LOGS
1415
    mender_deployment_logs_deactivate();
45✔
1416
#endif /* CONFIG_MENDER_DEPLOYMENT_LOGS */
1417

1418
    return ret;
45✔
1419
}
1420

1421
static mender_err_t
1422
mender_client_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
47✔
1423
    if (MENDER_FAIL == mender_client_ensure_connected()) {
47✔
1424
        /* connection errors logged already */
1425
        mender_log_error("Cannot publish deployment status");
×
1426
        return MENDER_FAIL;
×
1427
    }
1428

1429
    mender_err_t ret;
1430

1431
    if (NULL == id) {
47✔
1432
        mender_log_error("Cannot publish deployment status: unknown status");
×
1433
        return MENDER_FAIL;
×
1434
    }
1435

1436
    /* Publish status to the mender server */
1437
    ret = mender_api_publish_deployment_status(id, deployment_status);
47✔
1438

1439
    /* Invoke deployment status callback if defined */
1440
    if (NULL != mender_client_callbacks.deployment_status) {
45✔
1441
        mender_client_callbacks.deployment_status(deployment_status, mender_utils_deployment_status_to_string(deployment_status));
45✔
1442
    }
1443

1444
    return ret;
45✔
1445
}
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