diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | host/lib/chromeos_config.c | 108 | ||||
-rw-r--r-- | host/lib/include/chromeos_config.h | 56 | ||||
-rw-r--r-- | tests/chromeos_config_tests.c | 158 |
4 files changed, 325 insertions, 0 deletions
@@ -442,6 +442,7 @@ UTILLIB_SRCS = \ cgpt/cgpt_show.c \ futility/dump_kernel_config_lib.c \ host/arch/${ARCH}/lib/crossystem_arch.c \ + host/lib/chromeos_config.c \ host/lib/crossystem.c \ host/lib/file_keys.c \ host/lib/fmap.c \ @@ -498,6 +499,7 @@ HOSTLIB_SRCS = \ firmware/stub/vboot_api_stub_init.c \ futility/dump_kernel_config_lib.c \ host/arch/${ARCH}/lib/crossystem_arch.c \ + host/lib/chromeos_config.c \ host/lib/crossystem.c \ host/lib/extract_vmlinuz.c \ host/lib/fmap.c \ @@ -661,6 +663,7 @@ TEST_OBJS += ${TESTLIB_OBJS} # And some compiled tests. TEST_NAMES = \ + tests/chromeos_config_tests \ tests/cgptlib_test \ tests/sha_benchmark \ tests/subprocess_tests \ diff --git a/host/lib/chromeos_config.c b/host/lib/chromeos_config.c new file mode 100644 index 00000000..6307318c --- /dev/null +++ b/host/lib/chromeos_config.c @@ -0,0 +1,108 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "2common.h" +#include "2return_codes.h" +#include "chromeos_config.h" +#include "host_misc.h" + +#define CHROMEOS_CONFIG_BASE "/run/chromeos-config/v1" + +vb2_error_t chromeos_config_get_string(const char *path, const char *property, + char **val_out) +{ + vb2_error_t rv; + uint32_t size; + char filepath[PATH_MAX]; + + *val_out = NULL; + + if (!path || path[0] != '/') { + VB2_DEBUG("Path parameter must begin with /"); + return VB2_ERROR_INVALID_PARAMETER; + } + + if (strstr(path, "//")) { + VB2_DEBUG("Path cannot contain //"); + return VB2_ERROR_INVALID_PARAMETER; + } + + if (strchr(property, '/')) { + VB2_DEBUG("Property cannot contain /"); + return VB2_ERROR_INVALID_PARAMETER; + } + + snprintf(filepath, sizeof(filepath), CHROMEOS_CONFIG_BASE "%s/%s", path, + property); + rv = vb2_read_file(filepath, (uint8_t **)val_out, &size); + + if (rv == VB2_SUCCESS) { + *val_out = realloc(*val_out, size + 1); + (*val_out)[size] = '\0'; + } + + return rv; +} + +vb2_error_t chromeos_config_get_boolean(const char *path, const char *property, + bool *val_out) +{ + char *val_string; + vb2_error_t rv; + + *val_out = false; + if ((rv = chromeos_config_get_string(path, property, &val_string)) != + VB2_SUCCESS) + return rv; + + if (!strcmp(val_string, "false")) + goto exit; + + if (!strcmp(val_string, "true")) { + *val_out = true; + goto exit; + } + + VB2_DEBUG("Config entry is not a boolean: %s:%s", path, property); + rv = VB2_ERROR_INVALID_PARAMETER; + + exit: + free(val_string); + return rv; +} + +vb2_error_t chromeos_config_get_integer(const char *path, const char *property, + int *val_out) +{ + char *endptr; + char *val_string; + vb2_error_t rv; + + *val_out = -1; + if ((rv = chromeos_config_get_string(path, property, &val_string)) != + VB2_SUCCESS) + goto exit; + + errno = 0; + *val_out = strtol(val_string, &endptr, 10); + if (errno || endptr) { + VB2_DEBUG("Config entry is not an integer: %s:%s", path, + property); + rv = VB2_ERROR_INVALID_PARAMETER; + goto exit; + } + + exit: + free(val_string); + return rv; +} diff --git a/host/lib/include/chromeos_config.h b/host/lib/include/chromeos_config.h new file mode 100644 index 00000000..e83570e5 --- /dev/null +++ b/host/lib/include/chromeos_config.h @@ -0,0 +1,56 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef VBOOT_REFERENCE_CHROMEOS_CONFIG_H_ +#define VBOOT_REFERENCE_CHROMEOS_CONFIG_H_ + +#include <stdbool.h> +#include <stdint.h> + +#include "2common.h" +#include "2return_codes.h" + +/** + * Get a value from the model configuration on the device as a string. + * + * Note: this function allocates memory by its use of vb2_read_file, and relies + * on the caller to free the allocated memory. The output parameter will be set + * to NULL upon failure, so free can be safely called on this parameter. + * + * @param path The path in the config schema to the object containing + * the requested property. + * @param property The name of the requested property. + * @param val_out Output parameter which gets assigned to a + * null-terminated string. + * @return VB2_SUCCESS on success, or a relevant error upon error. + */ +vb2_error_t chromeos_config_get_string(const char *path, const char *property, + char **val_out); + +/** + * Get a value from the model configuration on the device as a boolean. + * + * @param path The path in the config schema to the object containing + * the requested property. + * @param property The name of the requested property. + * @param val_out Output parameter which gets assigned to a boolean. + * @return VB2_SUCCESS on success, or a relevant error upon error. + */ +vb2_error_t chromeos_config_get_boolean(const char *path, const char *property, + bool *val_out); + +/** + * Get a value from the model configuration on the device as an integer. + * + * @param path The path in the config schema to the object containing + * the requested property. + * @param property The name of the requested property. + * @param val_out Output parameter which gets assigned to an integer. + * @return VB2_SUCCESS on success, or a relevant error upon error. + */ +vb2_error_t chromeos_config_get_integer(const char *path, const char *property, + int *val_out); + +#endif /* VBOOT_REFERENCE_CHROMEOS_CONFIG_H_ */ diff --git a/tests/chromeos_config_tests.c b/tests/chromeos_config_tests.c new file mode 100644 index 00000000..2408d8ce --- /dev/null +++ b/tests/chromeos_config_tests.c @@ -0,0 +1,158 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "2common.h" +#include "2return_codes.h" +#include "chromeos_config.h" +#include "host_misc.h" +#include "test_common.h" + +static struct { + const char *path; + const char *data; +} fakefs[] = { + {"/run/chromeos-config/v1/name", "bleh_model"}, + {"/run/chromeos-config/v1/brand-code", "ZZCR"}, + {"/run/chromeos-config/v1/identity/sku-id", "7"}, + {"/run/chromeos-config/v1/firmware/image-name", "bloop"}, + {"/run/chromeos-config/v1/auto-night-light", "true"}, + {"/run/chromeos-config/v1/hardware-properties/is-lid-convertible", + "false"}, +}; + +vb2_error_t vb2_read_file(const char *filepath, uint8_t **data_ptr, + uint32_t *size_ptr) +{ + *data_ptr = NULL; + *size_ptr = 0; + + for (size_t i = 0; i < ARRAY_SIZE(fakefs); i++) { + if (!strcmp(fakefs[i].path, filepath)) { + *size_ptr = strlen(fakefs[i].data); + *data_ptr = malloc(*size_ptr); + + if (!*data_ptr) + return VB2_ERROR_READ_FILE_ALLOC; + + memcpy(*data_ptr, fakefs[i].data, *size_ptr); + return VB2_SUCCESS; + } + } + + return VB2_ERROR_READ_FILE_OPEN; +} + +static void test_get_string(void) +{ + char *val_out; + + TEST_EQ(chromeos_config_get_string("/firmware", "image-name", &val_out), + VB2_SUCCESS, "Reading a string is successful"); + TEST_STR_EQ(val_out, "bloop", "The string is the correct value"); + free(val_out); +} + +static void test_get_boolean_true(void) +{ + bool val_out; + + TEST_EQ(chromeos_config_get_boolean("/", "auto-night-light", &val_out), + VB2_SUCCESS, "Reading a true boolean is successful"); + TEST_EQ(val_out, true, "The resulting boolean is true"); +} + +static void test_get_boolean_false(void) +{ + bool val_out; + + TEST_EQ(chromeos_config_get_boolean("/hardware-properties", + "is-lid-convertible", &val_out), + VB2_SUCCESS, "Reading a false boolean is successful"); + TEST_EQ(val_out, false, "The resulting boolean is false"); +} + +static void test_get_integer(void) +{ + int val_out; + + TEST_EQ(chromeos_config_get_integer("/identity", "sku-id", &val_out), + VB2_SUCCESS, "Reading an integer is successful"); + TEST_EQ(val_out, 7, "The resulting integer is correct"); +} + +static void test_get_no_exist(void) +{ + char *val_out; + + TEST_NEQ( + chromeos_config_get_string("/this/does", "not-exist", &val_out), + VB2_SUCCESS, "Reading non-existent property fails"); + free(val_out); +} + +static void test_get_bad_path(void) +{ + char *val_out; + + TEST_NEQ(chromeos_config_get_string("name", "name", &val_out), + VB2_SUCCESS, "Reading bad path fails"); + free(val_out); +} + +static void test_get_bad_path2(void) +{ + char *val_out; + + TEST_NEQ(chromeos_config_get_string("//name", "name", &val_out), + VB2_SUCCESS, "Reading bad path fails"); + free(val_out); +} + +static void test_get_bad_property(void) +{ + char *val_out; + + TEST_NEQ(chromeos_config_get_string("/firmware", "/image-name", + &val_out), + VB2_SUCCESS, "Reading bad property fails"); + free(val_out); +} + +static void test_get_not_boolean(void) +{ + bool val_out; + + TEST_NEQ(chromeos_config_get_boolean("/identity", "sku-id", &val_out), + VB2_SUCCESS, "Reading integer as boolean fails"); +} + +static void test_get_not_integer(void) +{ + int val_out; + + TEST_NEQ(chromeos_config_get_integer("/", "brand-code", &val_out), + VB2_SUCCESS, "Reading string as integer fails"); +} + +int main(int argc, char *argv[]) +{ + test_get_string(); + test_get_boolean_true(); + test_get_boolean_false(); + test_get_integer(); + test_get_no_exist(); + test_get_bad_path(); + test_get_bad_path2(); + test_get_bad_property(); + test_get_not_boolean(); + test_get_not_integer(); + + return gTestSuccess ? 0 : 255; +} |