halcc: Introduce halcc library
[platform/hal/api/common.git] / halcc / src / hal-compatibility-checker.c
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <assert.h>
22 #include <fcntl.h>
23 #include <glib.h>
24
25 #include <halcc/hal-compatibility-checker.h>
26 #include <hal-common.h>
27
28 #include "halcc-object.h"
29 #include "halcc-parser.h"
30 #include "halcc-util.h"
31
32 struct callback_data {
33         halcc_compatibility_cb func;
34         void *user_data;
35 };
36
37 static int parse_directory(const char *manifest_dir, halcc_manifest *manifest)
38 {
39         DIR *dir;
40         int dfd;
41         struct dirent *entry;
42
43         if (!manifest_dir || !manifest)
44                 return -EINVAL;
45
46         dir = opendir(manifest_dir);
47         if (!dir) {
48                 printf("Failed to opendir '%s', %m\n", manifest_dir);
49                 return -errno;
50         }
51
52         dfd = dirfd(dir);
53
54         while ((entry = readdir(dir))) {
55                 int fd = -1;
56                 int ret;
57
58                 if (entry->d_type != DT_REG)
59                         continue;
60
61                 fd = openat(dfd, entry->d_name, O_RDONLY);
62                 if (fd < 0) {
63                         printf("Failed to openat(), %m\n");
64                         continue;
65                 }
66
67                 ret = halcc_parse_fd(fd, manifest);
68                 if (ret < 0) {
69                         printf("Failed to parse xml, ret=%d\n", ret);
70                         close(fd);
71                         continue;
72                 }
73
74                 close(fd);
75         }
76
77         closedir(dir);
78
79         return 0;
80 }
81
82 static halcc_compatibility_e is_compatible(int major, int minor, unsigned int abi_version)
83 {
84         if (abi_version == HAL_ABI_VERSION_UNKNOWN)
85                 return HALCC_INCOMPATIBLE;
86
87         return HALCC_COMPATIBLE;
88 }
89
90 static void foreach_hal(void *data, void *user_data)
91 {
92         struct callback_data *callback_data = NULL;
93         enum hal_module module;
94         halcc_hal *hal;
95         const char *hal_name = NULL;
96         int major, minor;
97         halcc_compatibility_e compatible = HALCC_INCOMPATIBLE;
98
99         hal = (halcc_hal *) data;
100         callback_data = (struct callback_data *) user_data;
101
102         assert(hal);
103         assert(callback_data);
104         assert(callback_data->func);
105
106         if (halcc_hal_get_name(hal, &hal_name) < 0 || hal_name == NULL)
107                 return;
108
109         if (halcc_hal_get_version(hal, &major, &minor, NULL) < 0)
110                 return;
111
112         for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) {
113                 char module_name[128] = { 0 , };
114                 unsigned int abi_version;
115                 int ret;
116
117                 ret = hal_common_get_backend_module_name(module, module_name, sizeof(module_name));
118                 if (ret < 0)
119                         continue;
120
121                 ret = strncmp(hal_name, module_name, strlen(hal_name) + 1);
122                 if (ret != 0)
123                         continue;
124
125                 abi_version = hal_common_get_backend_abi_version(module);
126                 if (abi_version == HAL_ABI_VERSION_UNKNOWN)
127                         break;
128
129                 compatible = is_compatible(major, minor, abi_version);
130                 break;
131         }
132
133         if (module >= HAL_MODULE_END) {
134                 printf("Unknown hal module: %s\n", hal_name);
135                 return;
136         }
137
138         printf("%s: %s\n", hal_name, compatible ? "Compatible" : "Incompatible");
139
140         callback_data->func(module, compatible, callback_data->user_data);
141 }
142
143 EXPORT
144 int halcc_check_compatibility(const char *hal_api_manifest_dir,
145         halcc_compatibility_cb callback, void *user_data)
146 {
147         halcc_manifest *manifest = NULL;
148         struct callback_data callback_data = { 0 , };
149         int ret = 0;
150
151         if (!hal_api_manifest_dir)
152                 return -EINVAL;
153
154         if (!callback)
155                 return -EINVAL;
156
157         ret = halcc_manifest_new(&manifest);
158         if (ret < 0)
159                 return ret;
160
161         ret = parse_directory(hal_api_manifest_dir, manifest);
162         if (ret < 0)
163                 goto out;
164
165         callback_data = (struct callback_data) { callback, user_data };
166
167         halcc_manifest_foreach_hal(manifest, foreach_hal, &callback_data);
168
169 out:
170         if (manifest)
171                 halcc_manifest_free(g_steal_pointer(&manifest));
172
173         return ret;
174 }