#include "hal-api-compatibility-checker-parser.h"
#define HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH "/opt/etc/hal/.hal-backend-compatibility"
+#define HAL_CC_DEFAULT_COMPATIBILITY_LOADED_PATH "/opt/etc/hal/.hal-backend-compatibility-loaded"
#define COMPAT_INFO_MODULE_NAME_MAX 64
static struct compatibility_info g_compatibility_info[HAL_MODULE_END];
static const char *compatibility_result_path = HAL_CC_DEFAULT_COMPATIBILITY_RESULT_PATH;
+static const char *compatibility_loaded_path = HAL_CC_DEFAULT_COMPATIBILITY_LOADED_PATH;
#ifdef HAL_API_COMMON_UNITTEST
void hal_api_cc_set_compatibility_result_path(const char *path)
{
memset(g_compatibility_info, 0, sizeof(g_compatibility_info));
}
+
+void hal_api_cc_set_compatibility_loaded_path(const char *path)
+{
+ if (!path)
+ return;
+
+ compatibility_loaded_path = path;
+}
+
+void hal_api_cc_unset_compatibility_loaded_path(void)
+{
+ compatibility_loaded_path = HAL_CC_DEFAULT_COMPATIBILITY_LOADED_PATH;
+}
#endif /* HAL_API_COMMON_UNITTEST */
static int get_module_by_name(const char *name, enum hal_module *module)
return -EINVAL;
}
-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 pwd;
- struct passwd *result;
- char *buf = NULL;
- size_t bufsize = 1024;
- int ret;
-
- buf = malloc(bufsize);
- if (!buf)
- return -ENOMEM;
-
- errno = 0;
-
- while ((ret = getpwnam_r("system_fw", &pwd, buf, bufsize, &result)) == ERANGE) {
- char *tmp;
-
- bufsize *= 2;
- tmp = realloc(buf, bufsize);
- if (!tmp) {
- free(buf);
- return -ENOMEM;
- }
-
- buf = tmp;
- }
-
- if (!result) {
- free(buf);
- if (ret == 0)
- return -ENOENT;
- else
- return -errno;
- }
-
- uid_system_fw = pwd.pw_uid;
-
- free(buf);
- }
-
- if (gid_system_fw == -1) {
- struct group grp;
- struct group *result;
- char *buf = NULL;
- size_t bufsize = 1024;
- int ret;
-
- buf = malloc(bufsize);
- if (!buf)
- return -ENOMEM;
-
- errno = 0;
-
- while ((ret = getgrnam_r("system_fw", &grp, buf, bufsize, &result)) == ERANGE) {
- char *tmp;
-
- bufsize *= 2;
- tmp = realloc(buf, bufsize);
- if (!tmp) {
- free(buf);
- return -ENOMEM;
- }
-
- buf = tmp;
- }
-
- if (!result) {
- free(buf);
- if (ret == 0)
- return -ENOENT;
- else
- return -errno;
- }
-
- gid_system_fw = grp.gr_gid;
-
- free(buf);
- }
-
- return fchown(fd, uid_system_fw, gid_system_fw);
-}
-
static void __convert_hal_to_info(void *data_hal, void *data_info, bool skip_version_check)
{
halcc_hal *hal;
__convert_hal_to_info(data_hal, data_info, true);
}
-static int mkdir_one(const char *dir, mode_t mode)
-{
- if (!dir)
- return -EINVAL;
-
- if (access(dir, F_OK) == 0)
- return 0;
-
- return mkdir(dir, mode);
-}
-
-static int create_directory(const char *path)
+static int open_result_file(const char *path, int *fd_out)
{
- char directory_path[PATH_MAX] = { 0 , };
- char *p;
int ret;
+ int fd_result = -1;
+ int fd_loaded = -1;
+ int flags = O_RDWR;
- if (!path)
- return -EINVAL;
-
- if (path[0] != '/')
+ if (!fd_out)
return -EINVAL;
- if (strlen(path) > PATH_MAX - 1)
- return -ENAMETOOLONG;
-
- // copy path except the last filename
- strncpy(directory_path, path, strrchr(path, '/') - path);
-
- if (access(directory_path, F_OK) == 0)
- return 0;
-
- p = strchr(directory_path + 1, '/');
- for (;;) {
- if (!p)
- break;
-
- *p = '\0';
- ret = mkdir_one(directory_path, 0755);
- if (ret < 0)
- return ret;
- *p = '/';
-
- p = strchr(p + 1, '/');
- }
-
- return mkdir_one(directory_path, 0755);
-
-}
-
-static int open_result_file(const char *path, int *fd_out, bool reset, const char *module_name)
-{
- int ret;
- int fd;
- mode_t mode = O_WRONLY | O_CREAT;
-
- if (reset)
- mode |= O_TRUNC;
- else
- mode |= O_EXCL;
-
- ret = create_directory(path);
- if (ret < 0) {
- errno = -ret;
- _E("%s: Failed to create directory for %s, %m", module_name, path);
- return ret;
- }
-
- fd = open(path, mode, 0644);
- if (fd == -1) {
- if (errno == EEXIST) {
- /* file exists and reset is false: use that one */
- fd = open(path, O_WRONLY, 0);
- if (fd == -1)
- return -errno;
-
- *fd_out = fd;
- return 0;
- }
+ /* If it is the first access to this file, reset the file. */
+ if (access(compatibility_loaded_path, F_OK) != 0)
+ flags |= O_TRUNC;
+ /**
+ * The file must be there at this moment with proper credentials(onwer,smack)
+ * as it must have been generated by systemd-tmpfiles.
+ *
+ * See hal-compatibility-checker.conf.
+ */
+ fd_result = open(path, flags, 0);
+ if (fd_result == -1) {
ret = -errno;
- _E("%s: Failed to create %s, %m", module_name, path);
+ _E("Failed to open %s, %m", path);
return ret;
}
- /* set a new file size */
- ret = ftruncate(fd, sizeof(struct compatibility_info) * HAL_MODULE_END);
+ /* set the file size */
+ ret = ftruncate(fd_result, sizeof(struct compatibility_info) * HAL_MODULE_END);
if (ret < 0) {
ret = -errno;
- _E("%s: Failed to ftruncate %s, %m", module_name, path);
- close(fd);
+ _E("Failed to ftruncate %s, %m", path);
+ close(fd_result);
return ret;
}
- /* system_fw:system_fw */
- ret = set_owner(fd);
- if (ret < 0) {
- errno = -ret;
- _E("%s: Failed to set owner, ret=%d, %m\n", module_name, ret);
- close(fd);
- return ret;
+
+ /* create file that makes following call not to truncate result file */
+ fd_loaded = open(compatibility_loaded_path, O_RDWR | O_CREAT, 0755);
+ if (fd_loaded < 0) {
+ _E("Failed to create %s, compatibility info will be incomplete, %m",
+ compatibility_loaded_path);
+ close(fd_result);
+ fd_result = -1;
+ return -errno;
}
- *fd_out = fd;
+ close(fd_loaded);
+ fd_loaded = -1;
+
+ *fd_out = fd_result;
return 0;
}
-static int write_module_comaptibility_info(enum hal_module module,
+static int write_module_comaptibility_info(int fd, enum hal_module module,
struct compatibility_info *info)
{
- int fd = -1;
int ret;
ssize_t n_write;
off_t offset;
- ret = open_result_file(compatibility_result_path, &fd, false, info->module_name);
- if (ret < 0) {
- _E("Failed to create open result file %s", compatibility_result_path);
- return ret;
- }
+ assert(fd > 0);
offset = sizeof(struct compatibility_info) * module;
n_write = pwrite(fd, info, sizeof(*info), offset);
if (n_write == -1) {
ret = -errno;
_E("%s: Failed to write info, %m", info->module_name);
- close(fd);
return ret;
}
- close(fd);
-
return 0;
}
return 0;
}
- fd = open(compatibility_result_path, O_RDONLY, 0);
- if (fd == -1)
- return -errno;
+ ret = open_result_file(compatibility_result_path, &fd);
+ if (ret < 0)
+ return ret;
offset = sizeof(struct compatibility_info) * module;
n_read = pread(fd, info, sizeof(*info), offset);
halcc_manifest *manifest = NULL;
struct compatibility_info infos[HAL_MODULE_END] = { 0 , };
struct __hal_module_info *module_info = NULL;
+ int fd = -1;
int ret;
assert(info);
return 0;
/* Write all available(initialized) info */
+ ret = open_result_file(compatibility_result_path, &fd);
+ if (ret < 0) {
+ _E("Failed to create open result file %s", compatibility_result_path);
+ return ret;
+ }
+
for (enum hal_module index = HAL_MODULE_UNKNOWN + 1; index < HAL_MODULE_END; ++index) {
if (!infos[index].initialized)
continue;
- write_module_comaptibility_info(index, &infos[index]);
+ write_module_comaptibility_info(fd, index, &infos[index]);
memcpy(&g_compatibility_info[module], &infos[index], sizeof(struct compatibility_info));
}
+ close(fd);
+ fd = -1;
+
return 0;
}