#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <stdbool.h>
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <glib.h>
#include <hal-common.h>
#include "common.h"
+#include "hal-api-list.h"
#include "hal-api-compatibility-checker-object.h"
#include "hal-api-compatibility-checker-parser.h"
#include "hal-api-compatibility-checker-util.h"
-struct callback_data {
- hal_common_backend_compatibility_cb func;
- void *user_data;
+#define HAL_COMMON_DEFAULT_HAL_INFO_INI "/hal/etc/hal-info.ini"
+#define HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_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)
+
+struct compatibility_info {
+ enum hal_module module;
+ char module_name[COMPAT_INFO_MODULE_NAME_MAX];
+ enum hal_common_backend_compatibility compat;
+ char compat_desc[COMPAT_INFO_COMPAT_DESC_MAX];
};
+static struct compatibility_info g_compatibility_info[HAL_MODULE_END];
+static bool g_compatibility_info_loaded = false;
+
+static void set_compatibility_info_compat(enum hal_module module,
+ enum hal_common_backend_compatibility compat, const char *desc)
+{
+ if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END)
+ return;
+
+ g_compatibility_info[module].compat = compat;
+
+ if (!desc)
+ return;
+
+ snprintf(g_compatibility_info[module].compat_desc,
+ COMPAT_INFO_COMPAT_DESC_MAX, "%s", desc);
+}
+
+static void init_compatibility_info(enum hal_module module)
+{
+ if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END)
+ return;
+
+ g_compatibility_info[module].module = module;
+ snprintf(g_compatibility_info[module].module_name, COMPAT_INFO_MODULE_NAME_MAX,
+ "%s", g_hal_module_info[module].module_name ? : "Not defined");
+ set_compatibility_info_compat(module, HAL_COMMON_BACKEND_COMPATIBILITY_UNKNOWN,
+ "Manifest hasn't specified the module");
+}
+
+static int write_compatibility_info(int fd, enum hal_module module)
+{
+ char buffer[COMPAT_INFO_FILE_ALIGN_BYTE] = { 0 , };
+ struct compatibility_info *ci = NULL;
+ ssize_t ret;
+ int len = 0;
+
+ if (fd == -1)
+ return -EINVAL;
+
+ if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END)
+ return -EINVAL;
+
+ ci = &g_compatibility_info[module];
+
+ len = snprintf(buffer, sizeof(buffer), "%d:%s:%d:%s\n",
+ ci->module, ci->module_name, ci->compat, ci->compat_desc);
+
+ ret = write(fd, buffer, len);
+ if (ret == -1)
+ return -errno;
+
+ return 0;
+}
+
static int parse_directory(const char *manifest_dir, halcc_manifest *manifest)
{
DIR *dir;
dir = opendir(manifest_dir);
if (!dir) {
- printf("Failed to opendir '%s', %m\n", manifest_dir);
+ _E("Failed to opendir '%s', %m\n", manifest_dir);
return -errno;
}
fd = openat(dfd, entry->d_name, O_RDONLY);
if (fd < 0) {
- printf("Failed to openat(), %m\n");
+ _E("Failed to openat(), %m\n");
continue;
}
ret = halcc_parse_fd(fd, manifest);
if (ret < 0) {
- printf("Failed to parse xml, ret=%d\n", ret);
+ _E("Failed to parse xml, ret=%d\n", ret);
close(fd);
continue;
}
return 0;
}
-static enum hal_common_backend_compatibility is_compatible(int platform_major, int platform_minor,
+static enum hal_common_backend_compatibility is_compatible(int manifest_major, int manifest_minor,
int backend_major, int backend_minor)
{
- if (platform_major != backend_major)
+ if (manifest_major != backend_major)
return HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
- if (platform_minor < backend_minor)
+ if (manifest_minor < backend_minor)
return HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
return HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE;
}
-static void foreach_hal(void *data, void *user_data)
+static void make_compatibility_info(void *data, void *user_data)
{
- struct callback_data *callback_data = NULL;
enum hal_module module;
halcc_hal *hal;
const char *hal_name = NULL;
- int major, minor;
+ int manifest_major, manifest_minor;
+ int backend_major, backend_minor;
halcc_dependency_state_e state;
- enum hal_common_backend_compatibility compatible = HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
+ int ret;
+ enum hal_common_backend_compatibility compat = HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE;
hal = (halcc_hal *) data;
- callback_data = (struct callback_data *) user_data;
assert(hal);
- assert(callback_data);
- assert(callback_data->func);
if (halcc_hal_get_name(hal, &hal_name) < 0 || hal_name == NULL)
return;
- if (halcc_hal_get_version(hal, &major, &minor, NULL) < 0)
- return;
-
- if (halcc_hal_get_dependency_state(hal, &state) != 0)
- return;
-
- if (state != HALCC_DEPENDENCY_STATE_SUCCESS)
- return;
-
for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) {
char module_name[128] = { 0 , };
- int backend_major, backend_minor;
- int ret;
ret = hal_common_get_backend_module_name(module, module_name, sizeof(module_name));
if (ret < 0)
continue;
ret = strncmp(hal_name, module_name, strlen(hal_name) + 1);
- if (ret != 0)
- continue;
+ if (ret == 0)
+ break;
+ }
- ret = hal_common_get_backend_version(module, &backend_major, &backend_minor);
- if (ret != 0)
- continue;
+ if (module >= HAL_MODULE_END) {
+ _E("Unknown hal module: %s\n", hal_name);
+ return;
+ }
- compatible = is_compatible(major, minor, backend_major, backend_minor);
- break;
+ if (halcc_hal_get_dependency_state(hal, &state) != 0) {
+ set_compatibility_info_compat(module,
+ HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE,
+ "Manifest failed to resolve dependency");
+ return;
}
- if (module >= HAL_MODULE_END) {
- printf("Unknown hal module: %s\n", hal_name);
+ if (halcc_hal_get_version(hal, &manifest_major, &manifest_minor, NULL) < 0) {
+ set_compatibility_info_compat(module,
+ HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE,
+ "Manifest has invalid version");
return;
}
- printf("%s: %s\n", hal_name, compatible ? "Compatible" : "Incompatible");
+ ret = hal_common_get_backend_version(module, &backend_major, &backend_minor);
+ if (ret != 0) {
+ set_compatibility_info_compat(module,
+ HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE,
+ "Backend has invalid version");
+ return;
+ }
- callback_data->func(module, compatible, callback_data->user_data);
+ compat = is_compatible(manifest_major, manifest_minor, backend_major, backend_minor);
+ if (compat == HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE)
+ set_compatibility_info_compat(module,
+ HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE,
+ "Compatible");
+ else
+ set_compatibility_info_compat(module,
+ HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE,
+ "Backend has incompatible version");
}
-EXPORT
-int hal_common_check_backend_compatibility(const char *hal_api_manifest_dir,
- hal_common_backend_compatibility_cb callback, void *user_data)
+static int get_tizen_hal_version(int *major, int *minor)
{
- halcc_manifest *manifest = NULL;
- struct callback_data callback_data = { 0 , };
- int ret = 0;
+ FILE *fp = NULL;
+ char *line = NULL;
+ size_t len = 0;
+ int found = 0;
- if (!hal_api_manifest_dir)
+ assert(major);
+ assert(minor);
+
+ fp = fopen(HAL_COMMON_DEFAULT_HAL_INFO_INI, "r");
+ if (!fp) {
+ _E("Failed to open %s, %m\n", HAL_COMMON_DEFAULT_HAL_INFO_INI);
+ return -errno;
+ }
+
+ while (getline(&line, &len, fp) != EOF) {
+ if (fscanf(fp, "Model=Tizen%d.%d", major, minor) == 2) {
+ found = 1;
+ break;
+ }
+ }
+
+ fclose(fp);
+ fp = NULL;
+ free(line);
+ line = NULL;
+
+ return found ? 0 : -EINVAL;
+}
+
+static int build_compatibility_manifest_dir(char *manifest_dir, int len)
+{
+ int manifest_major = 0;
+ int manifest_minor = 0;
+ int ret;
+
+ if (!manifest_dir || len <= 0)
return -EINVAL;
- if (!callback)
+ ret = get_tizen_hal_version(&manifest_major, &manifest_minor);
+ if (ret != 0) {
+ _E("Failed to get hal version, ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = snprintf(manifest_dir, len, "/etc/hal/%d.%d", manifest_major, manifest_minor);
+ if (ret >= len) {
+ _E("Buffer is too small for manifest directory\n");
+ return -EOVERFLOW;
+ }
+
+ return 0;
+}
+
+static int set_owner(int fd)
+{
+ static uid_t uid_system_fw = -1;
+ static gid_t gid_system_fw = -1;
+
+ if (fd == -1)
return -EINVAL;
+ if (uid_system_fw == -1) {
+ struct passwd *p = getpwnam("system_fw");
+ if (!p)
+ return -errno;
+
+ uid_system_fw = p->pw_uid;
+ }
+
+ if (gid_system_fw == -1) {
+ struct group *g = getgrnam("system_fw");
+ if (!g)
+ return -errno;
+
+ gid_system_fw = g->gr_gid;
+ }
+
+ return fchown(fd, uid_system_fw, gid_system_fw);
+}
+
+static void store_backend_compatibility_to_storage(void)
+{
+ int fd = -1;
+ int ret;
+
+ assert(g_compatibility_info_loaded);
+
+ fd = open(HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return;
+
+ ret = set_owner(fd); // system_fw:system_fw
+ if (ret != 0) {
+ close(fd);
+ return;
+ }
+
+ for (enum hal_module module = 0; module < HAL_MODULE_END; ++module)
+ write_compatibility_info(fd, module);
+
+ close(fd);
+}
+
+static int load_backend_compatibility_from_manifest(void)
+{
+ char manifest_dir[64] = { 0, };
+ halcc_manifest *manifest = NULL;
+ int ret = 0;
+
+ ret = build_compatibility_manifest_dir(manifest_dir, sizeof(manifest_dir));
+ if (ret != 0)
+ return ret;
+
ret = halcc_manifest_new(&manifest);
if (ret < 0)
return ret;
- ret = parse_directory(hal_api_manifest_dir, manifest);
+ ret = parse_directory(manifest_dir, manifest);
if (ret < 0)
goto out;
halcc_manifest_validate_hal_dependency(manifest);
- callback_data = (struct callback_data) { callback, user_data };
+ g_compatibility_info_loaded = false;
+
+ for (enum hal_module module = 0; module < HAL_MODULE_END; ++module)
+ init_compatibility_info(module);
+ halcc_manifest_foreach_hal(manifest, make_compatibility_info, NULL);
- halcc_manifest_foreach_hal(manifest, foreach_hal, &callback_data);
+ g_compatibility_info_loaded = true;
out:
if (manifest)
return ret;
}
+
+static int load_backend_compatibility_from_storage(void)
+{
+ FILE *fp = NULL;
+ char *line = NULL;
+ size_t len = 0;
+ enum hal_module module;
+ int ret;
+
+ if (g_compatibility_info_loaded)
+ return 0;
+
+ fp = fopen(HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH, "r");
+ if (!fp)
+ return -errno;
+
+ for (module = 0; module < HAL_MODULE_END; ++module)
+ init_compatibility_info(module);
+
+ module = 0;
+ while (getline(&line, &len, fp) != EOF) {
+ struct compatibility_info *ci = NULL;
+
+ if (module >= HAL_MODULE_END)
+ break;
+
+ ci = &g_compatibility_info[module++];
+ ret = sscanf(line, "%d:%63[^:]:%d:%63s",
+ (int *) &ci->module, ci->module_name, (int *) &ci->compat, ci->compat_desc);
+ if (ret != 4)
+ _E("Failed to load %d module", module);
+ }
+
+ free(line);
+ line = NULL;
+ fclose(fp);
+ fp = NULL;
+
+ g_compatibility_info_loaded = true;
+
+ return 0;
+}
+
+EXPORT
+int hal_common_check_backend_compatibility_all(enum hal_common_backend_compatibility **arr_compatibility, int *len)
+{
+ enum hal_common_backend_compatibility *arr = NULL;
+
+ if (g_compatibility_info_loaded)
+ goto load_success;
+
+ load_backend_compatibility_from_storage();
+ if (g_compatibility_info_loaded)
+ goto load_success;
+
+ load_backend_compatibility_from_manifest();
+ if (g_compatibility_info_loaded)
+ goto load_success;
+
+ return -ENODATA;
+
+load_success:
+ if (access(HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH, F_OK) != 0)
+ store_backend_compatibility_to_storage();
+
+ if (!arr_compatibility)
+ return 0;
+
+ if (!len)
+ return -EINVAL;
+
+ arr = calloc(HAL_MODULE_END, sizeof(enum hal_common_backend_compatibility));
+ if (!arr)
+ return -ENOMEM;
+
+ for (int i = 0; i < HAL_MODULE_END; ++i)
+ arr[i] = g_compatibility_info[i].compat;
+
+ *len = HAL_MODULE_END;
+ *arr_compatibility = arr;
+ arr = NULL;
+
+ return 0;
+}
enum {
OPT_START = 0,
OPT_HELP = OPT_START,
- OPT_PLATFORM,
OPT_SKIP_IF_RESULT_EXIST,
OPT_REDIRECT_ALL,
OPT_REDIRECT_STDOUT,
[OPT_HELP]
= { "help", no_argument, NULL, 'h' },
- [OPT_PLATFORM]
- = { "platform", required_argument, NULL, 'p' },
-
[OPT_SKIP_IF_RESULT_EXIST]
= { "skip-if-result-exist", optional_argument, NULL, 0 },
return found ? 0 : -EINVAL;
}
-static const char* default_platform_manifest_dir(void)
-{
- static char dirpath[HCC_BUF_MAX] = { 0 , };
- int major;
- int minor;
- int ret;
-
- ret = get_tizen_hal_version(&major, &minor);
- if (ret != 0)
- return NULL;
-
- snprintf(dirpath, sizeof(dirpath), DEFAULT_PLATFORM_MANIFEST_DIR"/%d.%d", major, minor);
-
- return dirpath;
-}
-
// check result is exist, return true on exist.
static bool result_exist(const char *dir)
{
"\t-h, --help\n"
"\t\tshow this help.\n"
"\n"
- "\t-p, --platform=DIRECTORY\n"
- "\t\tspecify directory that holds platform manifest xml\n"
- "\t\twhen it is not specified, use default path: %s\n"
- "\n"
"\t--skip-if-result-exist[=DIRECTORY]\n"
"\t\tskip compatibility check if there exists a result of compatibility.\n"
"\t\tif DIRECTORY is given, locate a result based on the given DIRECTORY.\n"
"\n"
"\t--redirect-stderr=FILE|dlog\n"
"\t\tredirect stderr to FILE or dlog with tag "LOG_TAG_HAL_COMPATIBILITY_CHECKER".\n"
- , default_platform_manifest_dir()
);
}
-static void compatibility_cb(enum hal_module module,
- enum hal_common_backend_compatibility is_compatible, void *user_data)
-{
- // do something
-}
-
int main(int argc, char *argv[])
{
int opt;
const char *errfile = NULL;
for (;;) {
- opt = getopt_long(argc, argv, "hp:", long_option, &index);
+ opt = getopt_long(argc, argv, "h", long_option, &index);
if (opt == -1)
break;
case 'h':
help = 1;
break;
- case 'p':
- platform_manifest_dir = optarg;
- break;
case 0: // long-only options
{
switch (index) {
return 0;
}
- if (!platform_manifest_dir)
- platform_manifest_dir = default_platform_manifest_dir();
-
- hal_common_check_backend_compatibility(platform_manifest_dir, compatibility_cb, NULL);
+ // Not for getting result, but for storing result to backing storage
+ hal_common_check_backend_compatibility_all(NULL, NULL);
return 0;
}