#include <hal-common.h>
#include "common.h"
-#include "hal-api-list.h"
#include "hal-api-conf.h"
#include "hal-api-compatibility-checker.h"
#include "hal-api-compatibility-checker-object.h"
#include "hal-api-compatibility-checker-parser.h"
-#define HAL_CC_DEFAULT_HAL_INFO_INI_PATH "/hal/etc/hal-info.ini"
#define HAL_CC_DEFAULT_HAL_MANIFEST_DIR "/etc/hal-manifest"
#define HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH "/opt/etc/hal/.hal-backend-compatibility"
#define COMPAT_INFO_MODULE_NAME_MAX 64
-#define COMPAT_INFO_COMPAT_DESC_MAX 64
-#define COMPAT_INFO_FILE_ALIGN_BYTE ((COMPAT_INFO_MODULE_NAME_MAX + COMPAT_INFO_COMPAT_DESC_MAX) + 32)
-
-#define HAL_CC_VERSION_UNINITIALIZED (-1)
-
-#define LOAD_FLAG_NO_RELOAD (1 << 0)
-#define STORE_FLAG_NO_OVERWRITE (1 << 0)
struct compatibility_info {
- enum hal_module module;
char module_name[COMPAT_INFO_MODULE_NAME_MAX];
- int major_version;
- int minor_version;
- const char *error_desc;
+ int version_list[HALCC_NUM_VERSION_LIST_MAX][2];
+ int num_version_list;
+ enum hal_common_backend_compatibility compatibility;
};
-static struct compatibility_info g_compatibility_manifest_info[HAL_MODULE_END];
-static bool g_compatibility_manifest_info_loaded = false;
-
-static struct compatibility_info g_compatibility_backend_info[HAL_MODULE_END];
-static bool g_compatibility_backend_info_loaded = false;
-
-static enum hal_common_backend_compatibility g_compatibility_result[HAL_MODULE_END];
-static bool g_compatibility_result_synced = false;
-
-static enum hal_common_backend_compatibility
-is_manifest_backend_version_compatible(int manifest_major, int manifest_minor,
- int backend_major, int backend_minor)
-{
- if (manifest_major == HAL_CC_VERSION_UNINITIALIZED
- || manifest_minor == HAL_CC_VERSION_UNINITIALIZED
- || backend_major == HAL_CC_VERSION_UNINITIALIZED
- || backend_minor == HAL_CC_VERSION_UNINITIALIZED)
- return HAL_COMMON_BACKEND_COMPATIBILITY_UNKNOWN;
-
- if (manifest_major != backend_major)
- return HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
-
- if (manifest_minor < backend_minor)
- return HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
-
- return HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE;
-}
-
-static void init_compatibility_info(struct compatibility_info *info)
-{
- assert(info);
-
- for (enum hal_module module = 0; module < HAL_MODULE_END; ++module) {
- info[module].module = module;
- snprintf(info[module].module_name, COMPAT_INFO_MODULE_NAME_MAX,
- "%s", g_hal_module_info[module].module_name ? : "Not defined");
- info[module].major_version = HAL_CC_VERSION_UNINITIALIZED;
- info[module].minor_version = HAL_CC_VERSION_UNINITIALIZED;
- info[module].error_desc = "Uninitialized module";
- }
-}
-
static int parse_manifest_directory(const char *manifest_dir, halcc_manifest *manifest)
{
DIR *dir;
return 0;
}
-static void make_compatibility_manifest_info(void *data, void *user_data)
+static int get_module_by_name(const char *name, enum hal_module *module)
{
- enum hal_module module;
- halcc_hal *hal;
- const char *hal_name = NULL;
- int manifest_major, manifest_minor;
int ret;
- const char *error_desc = NULL;
- struct compatibility_info *manifest_info = NULL;
-
- hal = (halcc_hal *) data;
- manifest_info = (struct compatibility_info *) user_data;
-
- assert(hal);
- assert(manifest_info);
- if (halcc_hal_get_name(hal, &hal_name) < 0 || hal_name == NULL)
- return;
+ if (!name || !module)
+ return -EINVAL;
- for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) {
+ for (int i = HAL_MODULE_UNKNOWN; i < HAL_MODULE_END; ++i) {
char module_name[128] = { 0 , };
- ret = hal_common_get_backend_module_name(module, module_name, sizeof(module_name));
+ ret = hal_common_get_backend_module_name(i, module_name, sizeof(module_name));
if (ret < 0)
continue;
- ret = strncmp(hal_name, module_name, strlen(hal_name) + 1);
- if (ret == 0)
- break;
- }
+ ret = strncmp(name, module_name, strlen(name) + 1);
+ if (ret != 0)
+ continue;
- if (module >= HAL_MODULE_END) {
- _E("Unknown hal module: %s\n", hal_name);
- return;
- }
+ *module = i;
- if (halcc_hal_get_version(hal, &manifest_major, &manifest_minor) < 0) {
- error_desc = "Invalid manifest version";
- goto out;
+ return 0;
}
- manifest_info[module].major_version = manifest_major;
- manifest_info[module].minor_version = manifest_minor;
-
-out:
- manifest_info[module].error_desc = error_desc;
+ return -EINVAL;
}
static int set_owner(int fd)
return fchown(fd, uid_system_fw, gid_system_fw);
}
-static int store_hal_backend_compatibility(struct compatibility_info *manifest_info,
- struct compatibility_info *backend_info,
- enum hal_common_backend_compatibility *backend_compatibilities,
- int store_flag)
+static void __convert_hal_to_info(void *data_hal, void *data_info, bool skip_version_check)
{
- int fd = -1;
- int flag = O_WRONLY | O_CREAT | O_TRUNC;
+ halcc_hal *hal;
+ struct compatibility_info *info;
+ enum hal_module module;
+ const char *hal_name = NULL;
+ unsigned int major, minor;
int ret;
- assert(g_compatibility_manifest_info_loaded);
- assert(g_compatibility_backend_info_loaded);
+ hal = (halcc_hal *) data_hal;
+ info = (struct compatibility_info *) data_info;
- if (store_flag & STORE_FLAG_NO_OVERWRITE)
- flag |= O_EXCL;
-
- fd = open(HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH, flag, 0644);
- if (fd == -1)
- return (errno == EEXIST) ? 0 : -errno;
-
- ret = set_owner(fd); // system_fw:system_fw
- if (ret < 0) {
- close(fd);
- return ret;
- }
-
- for (enum hal_module module = 0; module < HAL_MODULE_END; ++module) {
- char buffer[COMPAT_INFO_FILE_ALIGN_BYTE] = { 0 , };
- ssize_t ret2;
- int length = 0;
- enum hal_common_backend_compatibility compatibility;
- const char *compatibility_desc = NULL;
-
- compatibility = backend_compatibilities[module];
- compatibility_desc = (compatibility == HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE) ?
- "Compatible" : "Incompatible";
-
- length = snprintf(buffer, sizeof(buffer), "%d:%s:%d.%d:%d.%d:%s:%s:%s\n",
- module,
- manifest_info[module].module_name,
- manifest_info[module].major_version, manifest_info[module].minor_version,
- backend_info[module].major_version, backend_info[module].minor_version,
- manifest_info[module].error_desc ?: "-",
- backend_info[module].error_desc ?: "-",
- compatibility_desc);
-
- ret2 = write(fd, buffer, length);
- if (ret2 < 0)
- _W("Failed to write compatibility result(%d)", -errno);
- }
-
- close(fd);
-
- return 0;
-}
-
-static int load_hal_manifest(struct compatibility_info *manifest_info, int load_flag)
-{
- halcc_manifest *manifest = NULL;
- int ret = 0;
-
- if (!manifest_info)
- return -EINVAL;
+ assert(hal);
+ assert(info);
- if ((load_flag & LOAD_FLAG_NO_RELOAD) && g_compatibility_manifest_info_loaded)
- return 0;
+ ret = halcc_hal_get_name(hal, &hal_name);
+ if (ret < 0)
+ return;
- init_compatibility_info(manifest_info);
- g_compatibility_manifest_info_loaded = false;
+ ret = get_module_by_name(hal_name, &module);
+ if (ret < 0)
+ return;
- g_compatibility_result_synced = false;
+ assert(module >= HAL_MODULE_UNKNOWN);
+ assert(module < HAL_MODULE_END);
- ret = halcc_manifest_new(&manifest);
- if (ret < 0)
- return ret;
+ info += module;
- ret = parse_manifest_directory(HAL_CC_DEFAULT_HAL_MANIFEST_DIR, manifest);
+ strncpy(info->module_name, hal_name, COMPAT_INFO_MODULE_NAME_MAX - 1);
+ ret = halcc_hal_get_version_list(hal, info->version_list,
+ sizeof(info->version_list) / sizeof(info->version_list[0]),
+ &info->num_version_list);
if (ret < 0)
- goto out;
-
- halcc_manifest_foreach_hal(manifest, make_compatibility_manifest_info, manifest_info);
+ return;
- g_compatibility_manifest_info_loaded = true;
+ /**
+ * hal_common_get_backend_version() will acquire lock, but this subroutine
+ * might have locked already if was triggered from hal_common_get_backend().
+ *
+ * For such case, here make escape condition not to fall into deadlock.
+ */
+ if (skip_version_check)
+ return;
-out:
- if (manifest)
- halcc_manifest_free(g_steal_pointer(&manifest));
+ info->compatibility = HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
+ ret = hal_common_get_backend_version(module, &major, &minor);
+ if (ret < 0)
+ return;
- return ret;
+ if (halcc_hal_is_compatible_with_version(hal, major, minor))
+ info->compatibility = HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE;
}
-
-static int load_hal_backend_version(struct compatibility_info *backend_info, int load_flag)
+static void convert_hal_to_info(void *data_hal, void *data_info)
{
- enum hal_module module;
- int major_version;
- int minor_version;
- int ret;
-
- if (!backend_info)
- return -EINVAL;
-
- if ((load_flag & LOAD_FLAG_NO_RELOAD) && g_compatibility_backend_info_loaded)
- return 0;
-
- init_compatibility_info(backend_info);
- g_compatibility_backend_info_loaded = false;
-
- g_compatibility_result_synced = false;
-
- for (module = 0; module < HAL_MODULE_END; ++module) {
- ret = hal_common_get_backend_version(module, &major_version, &minor_version);
- if (ret < 0) {
- _W("Failed to get backend(%s) version(%d)", backend_info[module].module_name, ret);
- backend_info[module].error_desc = "Invalid backend version";
- continue;
- }
-
- backend_info[module].major_version = major_version;
- backend_info[module].minor_version = minor_version;
- backend_info[module].error_desc = NULL;
- }
-
- g_compatibility_backend_info_loaded = true;
-
- return 0;
+ __convert_hal_to_info(data_hal, data_info, false);
}
-static int load_hal_manifest_and_hal_backend_version_fallback(struct compatibility_info *manifest_info,
- struct compatibility_info *backend_info, int load_flag)
+static void convert_hal_to_info_skip_version_check(void *data_hal, void *data_info)
{
- int ret;
-
- if (!manifest_info || !backend_info)
- return -EINVAL;
-
- ret = load_hal_manifest(manifest_info, load_flag);
- if (ret < 0)
- return ret;
-
- ret = load_hal_backend_version(backend_info, load_flag);
- if (ret < 0)
- return ret;
-
- return 0;
+ __convert_hal_to_info(data_hal, data_info, true);
}
-static int scanf_hal_backend_compatibility(const char *str,
- enum hal_module *module,
- int *manifest_major, int *manifest_minor,
- int *backend_major, int *backend_minor)
+static bool is_system_generator_context(void)
{
- enum hal_module tmp_module;
- int tmp_manifest_major;
- int tmp_manifest_minor;
- int tmp_backend_major;
- int tmp_backend_minor;
- int ret;
-
- if (!str)
- return -EINVAL;
-
- if (!module
- || !manifest_major || !manifest_minor
- || !backend_major || !backend_minor)
- return -EINVAL;
-
- ret = sscanf(str, "%d:%*[^:]:%d.%d:%d.%d",
- (int *) &tmp_module,
- &tmp_manifest_major, &tmp_manifest_minor,
- &tmp_backend_major, &tmp_backend_minor);
- if (ret != 5)
- return -EINVAL;
-
- if (tmp_module < 0 || tmp_module >= HAL_MODULE_END)
- return -EINVAL;
+ char *systemd_scope = NULL;
+
+ /**
+ * If the generator is invoked from the system service manager this variable
+ * is set to "system"; if invoked from the per-user service manager it is set to "user".
+ *
+ * Added in systemd version 251.
+ */
+ systemd_scope = getenv("SYSTEMD_SCOPE");
+
+ if (!systemd_scope) {
+ _E("Reject to create %s, not a generator context",
+ HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH);
+ return false;
+ }
- *module = tmp_module;
- *manifest_major = tmp_manifest_major;
- *manifest_minor = tmp_manifest_minor;
- *backend_major = tmp_backend_major;
- *backend_minor = tmp_backend_minor;
+ if (strncmp(systemd_scope, "system", sizeof("system")) != 0) {
+ _E("Reject to create %s, only system servie manager is allowed to do it",
+ HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH);
+ return false;
+ }
- return 0;
+ return true;
}
-static int load_hal_backend_compatibility_file(struct compatibility_info *manifest_info,
- struct compatibility_info *backend_info)
+static int write_comaptibility_info(struct compatibility_info *info, int entry_size)
{
- FILE *fp = NULL;
- char *line = NULL;
- size_t len = 0;
+ int fd = -1;
int ret;
+ ssize_t n_write;
- if (!manifest_info || !backend_info)
- return -EINVAL;
-
- fp = fopen(HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH, "r");
- if (!fp)
+ fd = open(HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH,
+ O_WRONLY | O_CREAT | O_EXCL, 0644);
+ if (fd == -1) {
+ _E("Failed to create %s, %m",
+ HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH);
return -errno;
+ }
- init_compatibility_info(manifest_info);
- g_compatibility_manifest_info_loaded = false;
-
- init_compatibility_info(backend_info);
- g_compatibility_backend_info_loaded = false;
-
- g_compatibility_result_synced = false;
-
- while (getline(&line, &len, fp) != EOF) {
- enum hal_module module;
- int manifest_major_version = HAL_CC_VERSION_UNINITIALIZED;
- int manifest_minor_version = HAL_CC_VERSION_UNINITIALIZED;
- int backend_major_version = HAL_CC_VERSION_UNINITIALIZED;
- int backend_minor_version = HAL_CC_VERSION_UNINITIALIZED;
-
- ret = scanf_hal_backend_compatibility(line,
- &module,
- &manifest_major_version, &manifest_minor_version,
- &backend_major_version, &backend_minor_version);
- if (ret < 0)
- continue;
-
- if (manifest_info) {
- manifest_info[module].major_version = manifest_major_version;
- manifest_info[module].minor_version = manifest_minor_version;
- }
-
- if (backend_info) {
- backend_info[module].major_version = backend_major_version;
- backend_info[module].minor_version = backend_minor_version;
- }
+ ret = set_owner(fd); // system_fw:system_fw
+ if (ret < 0) {
+ _E("Failed to set owner");
+ close(fd);
+ return ret;
}
- free(line);
- line = NULL;
- fclose(fp);
- fp = NULL;
+ n_write = write(fd, info, sizeof(struct compatibility_info) * entry_size);
+ if (n_write == -1) {
+ _E("Failed to write info, %m");
+ close(fd);
+ return -errno;
+ }
- g_compatibility_manifest_info_loaded = true;
- g_compatibility_backend_info_loaded = true;
+ close(fd);
return 0;
}
-static int load_hal_manifest_and_hal_backend_version(struct compatibility_info *manifest_info,
- struct compatibility_info *backend_info, int load_flag)
+static int load_module_compatibility_info(enum hal_module module,
+ struct compatibility_info *info)
{
- int ret;
+ int fd = -1;
+ size_t n_read = -1;
+ off_t offset;
- if (!manifest_info || !backend_info)
+ if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END)
return -EINVAL;
- if ((load_flag & LOAD_FLAG_NO_RELOAD)
- && g_compatibility_manifest_info_loaded
- && g_compatibility_backend_info_loaded)
- return 0;
-
- ret = load_hal_backend_compatibility_file(manifest_info, backend_info);
- if (ret < 0)
- return load_hal_manifest_and_hal_backend_version_fallback(manifest_info,
- backend_info, load_flag);
-
- return 0;
-}
-
-static int check_hal_backend_compatibility(const struct compatibility_info *manifest_info,
- const struct compatibility_info *backend_info,
- enum hal_common_backend_compatibility *backend_compatibilities)
-{
- assert(manifest_info);
- assert(backend_info);
- assert(backend_compatibilities);
+ if (!info)
+ return -EINVAL;
- if (g_compatibility_result_synced)
- return 0;
+ fd = open(HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH, O_RDONLY, 0);
+ if (fd == -1)
+ return -errno;
- for (enum hal_module module = 0; module < HAL_MODULE_END; ++module)
- backend_compatibilities[module] = is_manifest_backend_version_compatible(
- manifest_info[module].major_version, manifest_info[module].minor_version,
- backend_info[module].major_version, backend_info[module].minor_version);
+ offset = sizeof(struct compatibility_info) * module;
+ n_read = pread(fd, info, sizeof(*info), offset);
+ if (n_read == -1) {
+ close(fd);
+ return -errno;
+ }
- g_compatibility_result_synced = true;
+ close(fd);
return 0;
}
-static int check_backend_compatibility_all(
- const enum hal_common_backend_compatibility **backend_compatibilities)
+static int load_module_compatibility_info_fallback(enum hal_module module,
+ struct compatibility_info *info, bool skip_version_check)
{
+ halcc_manifest *manifest = NULL;
+ struct compatibility_info infos[HAL_MODULE_END] = { 0 , };
int ret;
- if (!backend_compatibilities)
- return -EINVAL;
+ assert(module >= HAL_MODULE_UNKNOWN);
+ assert(module < HAL_MODULE_END);
+ assert(info);
- ret = load_hal_manifest_and_hal_backend_version(g_compatibility_manifest_info,
- g_compatibility_backend_info, LOAD_FLAG_NO_RELOAD);
+ ret = halcc_manifest_new(&manifest);
if (ret < 0)
return ret;
- ret = check_hal_backend_compatibility(g_compatibility_manifest_info,
- g_compatibility_backend_info, g_compatibility_result);
- if (ret < 0)
+ ret = parse_manifest_directory(HAL_CC_DEFAULT_HAL_MANIFEST_DIR, manifest);
+ if (ret < 0) {
+ halcc_manifest_free(manifest);
return ret;
+ }
- ret = store_hal_backend_compatibility(g_compatibility_manifest_info,
- g_compatibility_backend_info, g_compatibility_result, STORE_FLAG_NO_OVERWRITE);
- if (ret < 0)
- return ret;
+ if (skip_version_check)
+ halcc_manifest_foreach_hal(manifest, convert_hal_to_info_skip_version_check, infos);
+ else
+ halcc_manifest_foreach_hal(manifest, convert_hal_to_info, infos);
+
+ *info = infos[module];
- *backend_compatibilities = g_compatibility_result;
+ halcc_manifest_free(manifest);
+ manifest = NULL;
+
+ /* Writing result is only allowed on system generator context */
+ if (!is_system_generator_context())
+ return 0;
+
+ /* Incomplete data, no versions. Don't write it */
+ if (skip_version_check)
+ return 0;
+
+ write_comaptibility_info(infos, HAL_MODULE_END);
return 0;
}
enum hal_common_backend_compatibility *backend_compatibility)
{
int ret;
- const enum hal_common_backend_compatibility *backend_compatibilities = NULL;
+ struct compatibility_info info = { 0 , };
if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END)
return -EINVAL;
if (!backend_compatibility)
return -EINVAL;
- ret = check_backend_compatibility_all(&backend_compatibilities);
- if (ret < 0)
- return ret;
-
- assert(backend_compatibilities);
+ ret = load_module_compatibility_info(module, &info);
+ if (ret < 0) {
+ ret = load_module_compatibility_info_fallback(module, &info, false);
+ if (ret < 0)
+ return ret;
+ }
- *backend_compatibility = backend_compatibilities[module];
+ *backend_compatibility = info.compatibility;
return 0;
}
int hal_api_cc_check_backend_compatibility_by_version(enum hal_module module,
- int backend_major, int backend_minor,
+ unsigned int major, unsigned int minor,
enum hal_common_backend_compatibility *backend_compatibility)
{
int ret;
+ struct compatibility_info info = { 0 , };
if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END)
return -EINVAL;
if (!backend_compatibility)
return -EINVAL;
- ret = load_hal_manifest(g_compatibility_manifest_info, LOAD_FLAG_NO_RELOAD);
- if (ret < 0)
- return ret;
+ ret = load_module_compatibility_info(module, &info);
+ if (ret < 0) {
+ ret = load_module_compatibility_info_fallback(module, &info, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ *backend_compatibility = HAL_COMMON_BACKEND_COMPATIBILITY_UNKNOWN;
+
+ if (info.num_version_list == 0)
+ return 0;
+
+ for (int i = 0; i < info.num_version_list; ++i) {
+ if (info.version_list[i][0] != major)
+ continue;
+
+ if (info.version_list[i][1] < minor)
+ continue;
+
+ *backend_compatibility = HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE;
+ return 0;
+ }
- *backend_compatibility = is_manifest_backend_version_compatible(
- g_compatibility_manifest_info[module].major_version,
- g_compatibility_manifest_info[module].minor_version,
- backend_major,
- backend_minor);
+ *backend_compatibility = HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
return 0;
}