resource-manager: Fix license Apache to MIT
[platform/core/system/libsyscommon.git] / src / resource-manager / resource-manager.c
1 /* MIT License
2  *
3  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is furnished
10  * to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21  * THE SOFTWARE. */
22
23 #include <glib.h>
24 #include <stdio.h>
25 #include <json.h>
26 #include <sys/time.h>
27 #include <pthread.h>
28
29 #include "resource-manager.h"
30 #include "resource-type.h"
31
32 #define BIT64_INDEX(id)                         (63 - __builtin_clzll(id))
33 #define RESOURCE_ATTR_INDEX(id)                 BIT64_INDEX(id)
34 #define RESOURCE_CTRL_INDEX(id)                 BIT64_INDEX(id)
35 #define RESOURCE_FLAG_VISIBILITY_MASK           (SYSCOMMON_RESMAN_RESOURCE_FLAG_PRIVATE \
36                                                 | SYSCOMMON_RESMAN_RESOURCE_FLAG_PUBLIC)
37 #define RESOURCE_ATTR_FLAG_VISIBILITY_MASK      (SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PRIVATE \
38                                                 | SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC)
39
40 struct syscommon_resman_resource {
41         char *name;
42         int id;
43         const struct syscommon_resman_resource_driver *driver;
44         int type;
45
46         int num_attrs;
47         const struct syscommon_resman_resource_attribute *attrs;
48         struct syscommon_resman_resource_attribute_value *attrs_value;
49         int num_ctrls;
50         const struct syscommon_resman_resource_control *ctrls;
51
52         u_int64_t flag;
53
54         void *priv;
55
56         u_int64_t attr_interest;
57         u_int64_t attr_supported;
58 };
59
60 static int unset_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
61 static bool is_resource_attr_interested(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
62
63 static GList *g_resource_driver_head;
64 static GHashTable *g_resource_hash_table;
65
66 static int clear_sign_bit(unsigned int val)
67 {
68         return (int)((val << 1) >> 1);
69 }
70
71 static int init_resource_id(void)
72 {
73         int val;
74         struct timeval tv;
75
76         gettimeofday(&tv, NULL);
77         val = tv.tv_sec * 1000 + tv.tv_usec / 1000;
78         return clear_sign_bit(val);
79 }
80
81 static int alloc_resource_id(void)
82 {
83         static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
84         static int resource_id = -1;
85         int ret;
86
87         pthread_mutex_lock(&lock);
88
89         if (resource_id < 0)
90                 resource_id = init_resource_id();
91
92         ret = resource_id;
93         resource_id = clear_sign_bit(resource_id + 1);
94
95         pthread_mutex_unlock(&lock);
96
97         return ret;
98 }
99
100 static void free_resource(struct syscommon_resman_resource *resource)
101 {
102         free(resource->name);
103         resource->name = NULL;
104
105         unset_resource_attr_interest(resource, resource->attr_interest);
106         free(resource->attrs_value);
107         resource->attrs_value = NULL;
108
109         resource->attrs = NULL;
110         resource->num_attrs = 0;
111
112         free(resource);
113 }
114
115 static void delete_resource(void *data)
116 {
117         struct syscommon_resman_resource *resource = (struct syscommon_resman_resource *) data;
118
119         if (!resource)
120                 return;
121
122         if (resource->driver && resource->driver->ops.delete)
123                 resource->driver->ops.delete(resource->id);
124
125         free_resource(resource);
126 }
127
128 static int add_resource(struct syscommon_resman_resource *resource)
129 {
130         if (!resource)
131                 return -EINVAL;
132
133         if (!g_resource_hash_table) {
134                 g_resource_hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, delete_resource);
135                 if (!g_resource_hash_table)
136                         return -ENOMEM;
137         }
138
139         g_hash_table_insert(g_resource_hash_table, GINT_TO_POINTER(resource->id), resource);
140
141         return 0;
142 }
143
144 static struct syscommon_resman_resource * find_resource(int id)
145 {
146         if (!g_resource_hash_table)
147                 return NULL;
148
149         return g_hash_table_lookup(g_resource_hash_table, GINT_TO_POINTER(id));
150 }
151
152 static gint __compare_resource_type(gconstpointer data, gconstpointer input)
153 {
154         struct syscommon_resman_resource_driver *driver;
155         int type = *(int *)input;
156
157         driver = (struct syscommon_resman_resource_driver *)data;
158
159         if (driver && driver->type == type)
160                 return 0;
161         return -1;
162 }
163
164 const struct syscommon_resman_resource_driver *
165 syscommon_resman_find_resource_driver(int resource_type)
166 {
167         GList *node;
168
169         node = g_list_find_custom(g_resource_driver_head,
170                         &resource_type, __compare_resource_type);
171
172         if (!node)
173                 return NULL;
174         return (struct syscommon_resman_resource_driver *)node->data;
175 }
176
177 void
178 syscommon_resman_add_resource_driver(const struct syscommon_resman_resource_driver *driver)
179 {
180         if (!driver)
181                 return;
182
183         g_resource_driver_head =
184                         g_list_append(g_resource_driver_head, (gpointer)driver);
185 }
186
187 void
188 syscommon_resman_remove_resource_driver(const struct syscommon_resman_resource_driver *driver)
189 {
190         if (!driver)
191                 return;
192
193         g_resource_driver_head =
194                         g_list_remove(g_resource_driver_head, (gpointer)driver);
195 }
196
197 void syscommon_resman_delete_resource(int resource_id)
198 {
199         if (!g_resource_hash_table)
200                 return;
201
202         g_hash_table_remove(g_resource_hash_table, GINT_TO_POINTER(resource_id));
203 }
204
205 int
206 syscommon_resman_create_resource(int *resource_id, int resource_type)
207 {
208         const struct syscommon_resman_resource_driver *driver = NULL;
209         struct syscommon_resman_resource *resource = NULL;
210         int i, ret;
211
212         if (!resource_id)
213                 return -EINVAL;
214
215         driver = syscommon_resman_find_resource_driver(resource_type);
216         if (!driver)
217                 return -EINVAL;
218
219         resource = calloc(1, sizeof(*resource));
220         if (!resource)
221                 return -ENOMEM;
222
223         resource->id = alloc_resource_id();
224         resource->type = resource_type;
225         resource->name = g_strdup(driver->name);
226         resource->driver = driver;
227         resource->num_attrs = driver->num_attrs;
228         resource->attrs = driver->attrs;
229         resource->attrs_value = calloc(resource->num_attrs,
230                                         sizeof(*resource->attrs_value));
231         if (!resource->attrs_value) {
232                 free_resource(resource);
233                 return -ENOMEM;
234         }
235
236         ret = add_resource(resource);
237         if (ret < 0) {
238                 free_resource(resource);
239                 return ret;
240         }
241
242         for (i = 0; i < resource->num_attrs; i++)
243                 resource->attrs_value[i].type = driver->attrs[i].type;
244
245         resource->ctrls = driver->ctrls;
246         resource->num_ctrls = driver->num_ctrls;
247         resource->flag = SYSCOMMON_RESMAN_RESOURCE_FLAG_PRIVATE;
248
249         if (driver->ops.create) {
250                 ret = driver->ops.create(resource->id);
251                 if (ret < 0) {
252                         free_resource(resource);
253                         return ret;
254                 }
255         }
256
257         *resource_id = resource->id;
258
259         return 0;
260 }
261
262 int
263 syscommon_resman_set_resource_flag(int resource_id, u_int64_t flag_mask)
264 {
265         struct syscommon_resman_resource *resource = find_resource(resource_id);
266
267         if (!resource)
268                 return -EINVAL;
269
270         resource->flag = flag_mask;
271         return 0;
272 }
273
274 int
275 syscommon_resman_set_resource_control(int resource_id, u_int64_t ctrl_id, const void *data)
276 {
277         const struct syscommon_resman_resource_control *ctrl;
278         int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id);
279         int ret;
280         struct syscommon_resman_resource *resource = find_resource(resource_id);
281
282         if (!resource || ctrl_index < 0 || ctrl_index >= resource->num_ctrls)
283                 return -EINVAL;
284
285         ctrl = &resource->ctrls[ctrl_index];
286         if (!ctrl->ops.set)
287                 return -ENOTSUP;
288
289         ret = ctrl->ops.set(resource_id, ctrl, data);
290         if (ret < 0)
291                 return ret;
292
293         return 0;
294 }
295
296 const char *
297 syscommon_resman_get_resource_control_name(int resource_id, u_int64_t ctrl_id)
298 {
299         const struct syscommon_resman_resource_control *ctrl;
300         int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id);
301         struct syscommon_resman_resource *resource = find_resource(resource_id);
302
303         if (!resource || ctrl_index < 0 || ctrl_index >= resource->num_ctrls)
304                 return NULL;
305
306         ctrl = &resource->ctrls[ctrl_index];
307
308         return ctrl->name;
309 }
310
311 static int
312 monitor_update_resource_attr(struct syscommon_resman_resource *resource,
313                      u_int64_t attr_id)
314 {
315         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
316         const struct syscommon_resman_resource_attribute *attr = NULL;
317         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
318         int ret;
319
320         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
321                 return -EINVAL;
322
323         attr = &resource->attrs[attr_index];
324
325         if (!attr->monitor_ops.get)
326                 return -EINVAL;
327
328         attr_value = &resource->attrs_value[attr_index];
329
330         ret = attr->monitor_ops.get(resource->id, attr, attr_value->data);
331         if (ret < 0)
332                 return ret;
333
334         return 0;
335 }
336
337 int
338 syscommon_resman_monitor_update_resource_attrs(int resource_id)
339 {
340         int i, ret;
341         struct syscommon_resman_resource *resource = find_resource(resource_id);
342
343         if (!resource || !resource->type)
344                 return -EINVAL;
345
346         if (resource->driver && resource->driver->ops.prepare_update) {
347                 ret = resource->driver->ops.prepare_update(resource->id);
348                 if (ret < 0)
349                         return ret;
350         }
351
352         for (i = 0; i < resource->num_attrs; i++) {
353                 if (!(resource->attrs[i].id & resource->attr_interest))
354                         continue;
355                 monitor_update_resource_attr(resource, resource->attrs[i].id);
356         }
357
358         return 0;
359 }
360
361 static const struct syscommon_resman_resource_attribute *
362 get_resource_attr(struct syscommon_resman_resource *resource, u_int64_t attr_id)
363 {
364         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
365
366         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
367                 return NULL;
368
369         return &resource->attrs[attr_index];
370 }
371
372 const struct syscommon_resman_resource_attribute *
373 syscommon_resman_get_resource_attr(int resource_id, u_int64_t attr_id)
374 {
375         struct syscommon_resman_resource *resource = find_resource(resource_id);
376
377         return get_resource_attr(resource, attr_id);
378 }
379
380
381 static struct syscommon_resman_resource_attribute_value *
382 get_resource_attr_value(struct syscommon_resman_resource *resource, u_int64_t attr_id)
383 {
384         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
385
386         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs)
387                 return NULL;
388
389         return &resource->attrs_value[attr_index];
390 }
391
392 struct syscommon_resman_resource_attribute_value *
393 syscommon_resman_get_resource_attr_value(int resource_id, u_int64_t attr_id)
394 {
395         struct syscommon_resman_resource *resource = find_resource(resource_id);
396
397         return get_resource_attr_value(resource, attr_id);
398 }
399
400 static int monitor_is_resource_attr_supported(struct syscommon_resman_resource *resource, u_int64_t attr_id, bool *supported)
401 {
402         const struct syscommon_resman_resource_attribute *attr = NULL;
403         int attr_index = RESOURCE_ATTR_INDEX(attr_id);
404         int ret;
405         bool is_supported = false;
406
407         if (!resource || attr_index < 0 || attr_index >= resource->num_attrs) {
408                 *supported = false;
409                 return -EINVAL;
410         }
411
412         attr = &resource->attrs[attr_index];
413
414         if (attr->id & resource->attr_supported) {
415                 is_supported = true;
416         } else if (attr->monitor_ops.is_supported) {
417                 is_supported = attr->monitor_ops.is_supported(resource->id, attr);
418         } else if (attr->monitor_ops.get) {
419                 /*
420                  * Optionally, if .is_supported ops is not implemented,
421                  * use .get ops in order to check whether the resource attribute
422                  * is supported or not.
423                  */
424                 char data[SYSCOMMON_RESMAN_BUFF_MAX] = {0, };
425
426                 ret = attr->monitor_ops.get(resource->id, attr, (void *)data);
427                 is_supported = (ret < 0) ? false :  true;
428         }
429
430         if (is_supported)
431                 resource->attr_supported |= attr->id;
432
433         *supported = is_supported;
434
435         return 0;
436 }
437
438 int
439 syscommon_resman_monitor_is_resource_attr_supported(int resource_id, u_int64_t attr_id, bool *supported)
440 {
441         struct syscommon_resman_resource *resource = find_resource(resource_id);
442
443         return monitor_is_resource_attr_supported(resource, attr_id, supported);
444 }
445
446 static bool
447 check_attr_validate(struct syscommon_resman_resource *resource,
448                     u_int64_t attr_id, int type)
449 {
450         const struct syscommon_resman_resource_attribute *attr;
451
452         attr = get_resource_attr(resource, attr_id);
453         if (!attr)
454                 return false;
455
456         if (attr->type != type)
457                 return false;
458
459         if (!(attr->id & resource->attr_interest))
460                 return false;
461
462         return true;
463 }
464
465 static json_object *
466 _get_resource_attr_json(const struct syscommon_resman_resource_attribute *attr,
467                         const struct syscommon_resman_resource_attribute_value *attr_value)
468 {
469         json_object *jobj_attr, *jobj_attr_name, *jobj_attr_type, *jobj_attr_value, *jobj_temp;
470         struct syscommon_resman_array_value *array;
471         int i;
472
473         switch (attr->type) {
474         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
475                 jobj_attr_value = json_object_new_int(*((int32_t *)attr_value->data));
476                 break;
477         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
478                 jobj_attr_value = json_object_new_int(*((u_int32_t *)attr_value->data));
479                 break;
480         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
481                 jobj_attr_value = json_object_new_int64(*((int64_t *)attr_value->data));
482                 break;
483         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
484                 jobj_attr_value = json_object_new_uint64(*((u_int64_t *)attr_value->data));
485                 break;
486         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
487                 jobj_attr_value = json_object_new_double(*((double *)attr_value->data));
488                 break;
489         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
490                 jobj_attr_value = json_object_new_string((char *)attr_value->data);
491                 break;
492         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
493                 array = attr_value->data;
494
495                 jobj_attr_value = json_object_new_array();
496
497                 switch (array->type) {
498                 case SYSCOMMON_RESMAN_DATA_TYPE_INT:
499                         for (i = 0; i < array->length; i++) {
500                                 int32_t *item = array->data;
501
502                                 jobj_temp = json_object_new_int(item[i]);
503                                 json_object_array_add(jobj_attr_value, jobj_temp);
504                         }
505                         break;
506                 case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
507                         for (i = 0; i < array->length; i++) {
508                                 u_int32_t *item = array->data;
509
510                                 jobj_temp = json_object_new_int(item[i]);
511                                 json_object_array_add(jobj_attr_value, jobj_temp);
512                         }
513                         break;
514                 case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
515                         for (i = 0; i < array->length; i++) {
516                                 int64_t *item = array->data;
517
518                                 jobj_temp = json_object_new_int64(item[i]);
519                                 json_object_array_add(jobj_attr_value, jobj_temp);
520                         }
521                         break;
522                 case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
523                         for (i = 0; i < array->length; i++) {
524                                 u_int64_t *item = array->data;
525
526                                 jobj_temp = json_object_new_uint64(item[i]);
527                                 json_object_array_add(jobj_attr_value, jobj_temp);
528                         }
529                         break;
530                 case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
531                         for (i = 0; i < array->length; i++) {
532                                 double *item = array->data;
533
534                                 jobj_temp = json_object_new_double(item[i]);
535                                 json_object_array_add(jobj_attr_value, jobj_temp);
536                         }
537                         break;
538                 case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
539                         for (i = 0; i < array->length; i++) {
540                                 char **item = array->data;
541
542                                 jobj_temp = json_object_new_string(item[i]);
543                                 json_object_array_add(jobj_attr_value, jobj_temp);
544                         }
545                         break;
546                 default:
547                         json_object_put(jobj_attr_value);
548                         jobj_attr_value = json_object_new_null();
549                 }
550                 break;
551         default:
552                 jobj_attr_value = json_object_new_null();
553         }
554         jobj_attr = json_object_new_object();
555
556         jobj_attr_name = json_object_new_string(attr->name);
557         /*
558          * Since actually JSON format has no data type limitation itself, in many
559          * cases except converting JSON into json-c, type is not required. So,
560          * for the case of converting JSON generated here to json-c object again
561          * json_type is stored in each attributes.
562          */
563         jobj_attr_type = json_object_new_int(json_object_get_type(jobj_attr_value));
564
565         json_object_object_add(jobj_attr, "name", jobj_attr_name);
566         json_object_object_add(jobj_attr, "json_type", jobj_attr_type);
567         json_object_object_add(jobj_attr, "value", jobj_attr_value);
568
569         return jobj_attr;
570 }
571
572 static void _put_resource_attr_json(json_object *jobj_attr)
573 {
574         json_object *jobj_attr_value;
575
576         json_object_object_del(jobj_attr, "name");
577         json_object_object_del(jobj_attr, "json_type");
578
579         if (json_object_object_get_ex(jobj_attr, "value", &jobj_attr_value) &&
580                         json_object_is_type(jobj_attr_value, json_type_array))
581                 json_object_array_del_idx(jobj_attr_value, 0,
582                                           json_object_array_length(jobj_attr_value));
583
584         json_object_object_del(jobj_attr, "value");
585 }
586
587 int
588 syscommon_resman_monitor_get_resource_attrs_json(int resource_id, char **json_string)
589 {
590         json_object *jobj_root, *jobj_res_name, *jobj_res_type, *jobj_res_attrs, *jobj_attr;
591         const struct syscommon_resman_resource_attribute *attr;
592         const struct syscommon_resman_resource_attribute_value *attr_value;
593         struct syscommon_resman_resource *resource = find_resource(resource_id);
594         int i;
595
596         if (!resource || !resource->type)
597                 return -EINVAL;
598
599         jobj_root = json_object_new_object();
600
601         jobj_res_name = json_object_new_string(resource->name);
602         jobj_res_type = json_object_new_int(resource->type);
603         jobj_res_attrs = json_object_new_array();
604
605         for (i = 0; i < resource->num_attrs; i++) {
606                 if (!(resource->attrs[i].id & resource->attr_interest))
607                         continue;
608
609                 attr = &resource->attrs[i];
610                 attr_value = &resource->attrs_value[i];
611
612                 jobj_attr = _get_resource_attr_json(attr, attr_value);
613
614                 json_object_array_add(jobj_res_attrs, jobj_attr);
615         }
616
617         json_object_object_add(jobj_root, "res_name", jobj_res_name);
618         json_object_object_add(jobj_root, "res_type", jobj_res_type);
619         json_object_object_add(jobj_root, "res_attrs", jobj_res_attrs);
620
621         *json_string = strdup(json_object_to_json_string(jobj_root));
622
623         for (i = 0; i < json_object_array_length(jobj_res_attrs); i++) {
624                 jobj_attr = json_object_array_get_idx(jobj_res_attrs, i);
625                 _put_resource_attr_json(jobj_attr);
626         }
627         json_object_array_del_idx(jobj_res_attrs, 0, json_object_array_length(jobj_res_attrs));
628
629         json_object_object_del(jobj_root, "res_attrs");
630         json_object_object_del(jobj_root, "res_type");
631         json_object_object_del(jobj_root, "res_name");
632         json_object_put(jobj_root);
633
634         return 0;
635 }
636
637 int
638 syscommon_resman_monitor_get_resource_attr_json(int resource_id, u_int64_t attr_id, char **json_string)
639 {
640         const struct syscommon_resman_resource_attribute *attr;
641         const struct syscommon_resman_resource_attribute_value *attr_value;
642         json_object *jobj_attr;
643         struct syscommon_resman_resource *resource = find_resource(resource_id);
644
645         attr = get_resource_attr(resource, attr_id);
646         attr_value = get_resource_attr_value(resource, attr_id);
647
648         if (!attr || !attr_value)
649                 return -EINVAL;
650
651         jobj_attr = _get_resource_attr_json(attr, attr_value);
652
653         *json_string = strdup(json_object_to_json_string(jobj_attr));
654
655         _put_resource_attr_json(jobj_attr);
656
657         return 0;
658 }
659
660 static json_object *
661 get_resource_driver_json(const struct syscommon_resman_resource_driver *driver)
662 {
663         json_object *jobj_drv, *jobj_drv_name, *jobj_drv_type;
664         json_object *jobj_drv_attrs_array, *jobj_drv_attr, *jobj_drv_ctrls_array, *jobj_drv_ctrl;
665         json_object *jobj_drv_attr_name, *jobj_drv_attr_type, *jobj_drv_attr_id;
666         json_object *jobj_drv_ctrl_name, *jobj_drv_ctrl_id;
667         const struct syscommon_resman_resource_attribute *attr;
668         const struct syscommon_resman_resource_control *ctrl;
669         int i;
670
671         jobj_drv = json_object_new_object();
672
673         jobj_drv_name = json_object_new_string(driver->name);
674         jobj_drv_type = json_object_new_int(driver->type);
675
676         jobj_drv_attrs_array = json_object_new_array();
677
678         for (i = 0; i < driver->num_attrs; i++) {
679                 attr = &driver->attrs[i];
680
681                 jobj_drv_attr = json_object_new_object();
682
683                 jobj_drv_attr_name = json_object_new_string(attr->name);
684                 jobj_drv_attr_type = json_object_new_int(attr->type);
685                 jobj_drv_attr_id = json_object_new_uint64(attr->id);
686
687                 json_object_object_add(jobj_drv_attr, "name", jobj_drv_attr_name);
688                 json_object_object_add(jobj_drv_attr, "type", jobj_drv_attr_type);
689                 json_object_object_add(jobj_drv_attr, "id", jobj_drv_attr_id);
690
691                 json_object_array_add(jobj_drv_attrs_array, jobj_drv_attr);
692         }
693
694         jobj_drv_ctrls_array = json_object_new_array();
695
696         for (i = 0; i < driver->num_ctrls; i++) {
697                 ctrl = &driver->ctrls[i];
698
699                 jobj_drv_ctrl = json_object_new_object();
700
701                 jobj_drv_ctrl_name = json_object_new_string(ctrl->name);
702                 jobj_drv_ctrl_id = json_object_new_uint64(ctrl->id);
703
704                 json_object_object_add(jobj_drv_ctrl, "name", jobj_drv_ctrl_name);
705                 json_object_object_add(jobj_drv_ctrl, "id", jobj_drv_ctrl_id);
706
707                 json_object_array_add(jobj_drv_ctrls_array, jobj_drv_ctrl);
708         }
709
710         json_object_object_add(jobj_drv, "name", jobj_drv_name);
711         json_object_object_add(jobj_drv, "type", jobj_drv_type);
712         json_object_object_add(jobj_drv, "attrs", jobj_drv_attrs_array);
713         json_object_object_add(jobj_drv, "ctrls", jobj_drv_ctrls_array);
714
715         return jobj_drv;
716 }
717
718 static void put_resource_driver_json(json_object *jobj_drv)
719 {
720         json_object *jobj_array, *jobj_obj;
721         int i;
722
723         if (json_object_object_get_ex(jobj_drv, "ctrls", &jobj_array)) {
724                 for (i = 0; i < json_object_array_length(jobj_array); i++) {
725                         jobj_obj = json_object_array_get_idx(jobj_array, i);
726
727                         json_object_object_del(jobj_obj, "id");
728                         json_object_object_del(jobj_obj, "name");
729                 }
730                 json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array));
731         }
732
733         if (json_object_object_get_ex(jobj_drv, "attrs", &jobj_array)) {
734                 for (i = 0; i < json_object_array_length(jobj_array); i++) {
735                         jobj_obj = json_object_array_get_idx(jobj_array, i);
736
737                         json_object_object_del(jobj_obj, "id");
738                         json_object_object_del(jobj_obj, "type");
739                         json_object_object_del(jobj_obj, "name");
740                 }
741                 json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array));
742         }
743
744         json_object_object_del(jobj_drv, "ctrls");
745         json_object_object_del(jobj_drv, "attrs");
746         json_object_object_del(jobj_drv, "type");
747         json_object_object_del(jobj_drv, "name");
748 }
749
750 int syscommon_resman_get_resource_list_json(char **json_string)
751 {
752         const struct syscommon_resman_resource_driver *driver;
753         json_object *jobj_root, *jobj_drvs_array, *jobj_drv;
754         int i;
755
756         jobj_root = json_object_new_object();
757         jobj_drvs_array = json_object_new_array();
758
759         for (i = 0; i < g_list_length(g_resource_driver_head); i++) {
760                 driver = g_list_nth(g_list_first(g_resource_driver_head), i)->data;
761
762                 jobj_drv = get_resource_driver_json(driver);
763                 json_object_array_add(jobj_drvs_array, jobj_drv);
764         }
765
766         json_object_object_add(jobj_root, "resources", jobj_drvs_array);
767
768         *json_string = strdup(json_object_to_json_string(jobj_root));
769
770         for (i = 0; i < json_object_array_length(jobj_drvs_array); i++) {
771                 jobj_drv = json_object_array_get_idx(jobj_drvs_array, i);
772
773                 put_resource_driver_json(jobj_drv);
774         }
775         json_object_array_del_idx(jobj_drvs_array, 0, json_object_array_length(jobj_drvs_array));
776
777         json_object_object_del(jobj_root, "resources");
778         json_object_put(jobj_root);
779
780         return 0;
781 }
782
783 static int
784 get_resource_attr_value_data(int resource_id, u_int64_t attr_id, enum syscommon_resman_data_type type, void *data)
785 {
786         struct syscommon_resman_resource_attribute_value *attr_value = NULL;
787         struct syscommon_resman_resource *resource = find_resource(resource_id);
788
789         if (!check_attr_validate(resource, attr_id, type))
790                 return -EINVAL;
791
792         attr_value = get_resource_attr_value(resource, attr_id);
793         if (!attr_value)
794                 return -EINVAL;
795
796         switch (type) {
797         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
798                 *(int *) data = *((int32_t *) attr_value->data);
799                 break;
800         case  SYSCOMMON_RESMAN_DATA_TYPE_INT64:
801                 *(int64_t *) data = *((int64_t *) attr_value->data);
802                 break;
803         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
804                 *(u_int32_t *) data = *((u_int32_t *)attr_value->data);
805                 break;
806         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
807                 *(u_int64_t *) data = *((u_int64_t *)attr_value->data);
808                 break;
809         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
810                 *(double *) data = *((double *)attr_value->data);
811                 break;
812         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
813                 strncpy(data, (char *)attr_value->data, SYSCOMMON_RESMAN_BUFF_MAX);
814                 break;
815         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
816                 *(struct syscommon_resman_array_value **) data = (struct syscommon_resman_array_value *)attr_value->data;
817                 break;
818         case SYSCOMMON_RESMAN_DATA_TYPE_PTR:
819                 *(void **) data = attr_value->data;
820                 break;
821         case SYSCOMMON_RESMAN_DATA_TYPE_BOOLEAN:
822         case SYSCOMMON_RESMAN_DATA_TYPE_NUM:
823         default:
824                 return -EINVAL;
825         }
826
827         return 0;
828 }
829
830 int
831 syscommon_resman_monitor_get_resource_attr_int(int resource_id, u_int64_t attr_id, int32_t *data)
832 {
833         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_INT, data);
834 }
835
836 int
837 syscommon_resman_monitor_get_resource_attr_int64(int resource_id, u_int64_t attr_id, int64_t *data)
838 {
839         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_INT64, data);
840 }
841
842 int
843 syscommon_resman_monitor_get_resource_attr_uint(int resource_id, u_int64_t attr_id, u_int32_t *data)
844 {
845         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_UINT, data);
846 }
847
848 int
849 syscommon_resman_monitor_get_resource_attr_uint64(int resource_id, u_int64_t attr_id, u_int64_t *data)
850 {
851         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_UINT64, data);
852 }
853
854 int
855 syscommon_resman_monitor_get_resource_attr_double(int resource_id, u_int64_t attr_id, double *data)
856 {
857         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE, data);
858 }
859
860 int
861 syscommon_resman_monitor_get_resource_attr_string(int resource_id, u_int64_t attr_id, char *data)
862 {
863         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_STRING, data);
864 }
865
866 int
867 syscommon_resman_monitor_get_resource_attr_array(int resource_id, u_int64_t attr_id, struct syscommon_resman_array_value **data)
868 {
869         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_ARRAY, data);
870 }
871
872 int
873 syscommon_resman_monitor_get_resource_attr_ptr(int resource_id, u_int64_t attr_id, void **data)
874 {
875         return get_resource_attr_value_data(resource_id, attr_id, SYSCOMMON_RESMAN_DATA_TYPE_PTR, data);
876 }
877
878 static inline bool
879 is_resource_attr_visible(struct syscommon_resman_resource *resource,
880                          const struct syscommon_resman_resource_attribute *attr)
881 {
882         u_int64_t res_visibility, attr_visibility;
883
884         res_visibility = resource->flag & RESOURCE_FLAG_VISIBILITY_MASK;
885         attr_visibility = attr->flag & RESOURCE_ATTR_FLAG_VISIBILITY_MASK;
886
887         /* bigger visibility means smaller privilege */
888         if (res_visibility > attr_visibility)
889                 return false;
890
891         return true;
892 }
893
894 int
895 syscommon_resman_set_resource_attr_interest(int resource_id, u_int64_t interest_mask)
896 {
897         struct syscommon_resman_resource_attribute_value *attr_value;
898         int i, ret;
899         bool supported;
900         struct syscommon_resman_resource *resource = find_resource(resource_id);
901
902         if (!resource)
903                 return -EINVAL;
904
905         for (i = 0; i < resource->num_attrs; i++) {
906                 if (!(resource->attrs[i].id & interest_mask))
907                         continue;
908
909                 ret = monitor_is_resource_attr_supported(resource,
910                                                          resource->attrs[i].id,
911                                                          &supported);
912                 if (ret < 0) {
913                         goto err;
914                 } else if (!supported) {
915                         ret = -ENOTSUP;
916                         goto err;
917                 }
918
919                 if (!is_resource_attr_visible(resource, &resource->attrs[i])) {
920                         ret = -EACCES;
921                         goto err;
922                 }
923
924                 attr_value = get_resource_attr_value(resource, resource->attrs[i].id);
925                 if (!attr_value) {
926                         ret = -EINVAL;
927                         goto err;
928                 }
929
930                 if (resource->attrs[i].listener_ops.init) {
931                         ret = resource->attrs[i].listener_ops.init(resource_id, &resource->attrs[i]);
932                         if (ret < 0)
933                                 goto err;
934                 }
935
936                 /*
937                  * In resource monitor, each resource has a lot of attributes, but
938                  * only updated attributes are selected by clients on demand. So,
939                  * instead of allocating memory at the resource creation, allocate
940                  * at the set interest.
941                  */
942                 if (!attr_value->data) {
943                         switch (attr_value->type) {
944                         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
945                                 attr_value->data = calloc(1, sizeof(int32_t));
946                                 break;
947                         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
948                                 attr_value->data = calloc(1, sizeof(int64_t));
949                                 break;
950                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
951                                 attr_value->data = calloc(1, sizeof(u_int32_t));
952                                 break;
953                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
954                                 attr_value->data = calloc(1, sizeof(u_int64_t));
955                                 break;
956                         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
957                                 attr_value->data = calloc(1, sizeof(double));
958                                 break;
959                         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
960                                 attr_value->data = calloc(SYSCOMMON_RESMAN_BUFF_MAX, sizeof(char));
961                                 break;
962                         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
963                                 attr_value->data = calloc(1, sizeof(struct syscommon_resman_array_value));
964                                 break;
965                         default:
966                                 ret = -EINVAL;
967                                 goto err;
968                         }
969
970                         if (!attr_value->data) {
971                                 ret = -ENOMEM;
972                                 goto err;
973                         }
974                 }
975         }
976
977         resource->attr_interest |= interest_mask;
978
979         return 0;
980
981 err:
982         for (; i >= 0;  i--) {
983                 if (!(resource->attrs[i].id & interest_mask))
984                         continue;
985
986                 if (resource->attrs[i].listener_ops.exit)
987                         resource->attrs[i].listener_ops.exit(resource_id, &resource->attrs[i]);
988
989                 attr_value = get_resource_attr_value(resource, resource->attrs[i].id);
990                 if (!attr_value)
991                         continue;
992
993                 if (attr_value->data) {
994                         free(attr_value->data);
995                         attr_value->data = NULL;
996                 }
997         }
998
999         return ret;
1000 }
1001
1002 static int
1003 unset_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask)
1004 {
1005         struct syscommon_resman_resource_attribute_value *attr_value;
1006         int i;
1007
1008         if (!resource)
1009                 return -EINVAL;
1010
1011         if (!is_resource_attr_interested(resource, interest_mask))
1012                 return -EINVAL;
1013
1014         for (i = 0; i < resource->num_attrs; i++) {
1015                 if (!(resource->attrs[i].id & interest_mask))
1016                         continue;
1017
1018                 if (resource->attrs[i].listener_ops.exit)
1019                         resource->attrs[i].listener_ops.exit(resource->id, &resource->attrs[i]);
1020
1021                 attr_value = get_resource_attr_value(resource, resource->attrs[i].id);
1022                 if (!attr_value)
1023                         return -EINVAL;
1024
1025                 if (attr_value->data) {
1026                         switch (attr_value->type) {
1027                         case SYSCOMMON_RESMAN_DATA_TYPE_ARRAY:
1028                         {
1029                                 struct syscommon_resman_array_value *array = attr_value->data;
1030
1031                                 if (array->data) {
1032                                         free(array->data);
1033                                         array->data = NULL;
1034                                 }
1035                                 /* fall through */
1036                         }
1037                         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
1038                         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
1039                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
1040                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
1041                         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
1042                         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
1043                                 free(attr_value->data);
1044                                 attr_value->data = NULL;
1045                                 break;
1046                         default:
1047                                 return -EINVAL;
1048                         }
1049                 }
1050         }
1051
1052         resource->attr_interest &= ~interest_mask;
1053
1054         return 0;
1055 }
1056
1057 int
1058 syscommon_resman_unset_resource_attr_interest(int resource_id, u_int64_t interest_mask)
1059 {
1060         struct syscommon_resman_resource *resource = find_resource(resource_id);
1061
1062         return unset_resource_attr_interest(resource, interest_mask);
1063 }
1064
1065 static bool
1066 is_resource_attr_interested(struct syscommon_resman_resource *resource,
1067                                              u_int64_t interest_mask)
1068 {
1069         if (!resource)
1070                 return false;
1071
1072         if (resource->attr_interest != (resource->attr_interest | interest_mask))
1073                 return false;
1074
1075         return true;
1076 }
1077
1078 bool
1079 syscommon_resman_is_resource_attr_interested(int resource_id, u_int64_t interest_mask)
1080 {
1081         struct syscommon_resman_resource *resource = find_resource(resource_id);
1082
1083         return is_resource_attr_interested(resource, interest_mask);
1084 }
1085
1086 const char *
1087 syscommon_resman_get_resource_attr_name(int resource_id, u_int64_t attr_id)
1088 {
1089         const struct syscommon_resman_resource_attribute *attr;
1090         struct syscommon_resman_resource *resource = find_resource(resource_id);
1091
1092         attr = get_resource_attr(resource, attr_id);
1093         if (!attr)
1094                 return NULL;
1095
1096         return attr->name;
1097 }
1098
1099 const char
1100 *syscommon_resman_get_resource_name(int resource_id)
1101 {
1102         struct syscommon_resman_resource *resource = find_resource(resource_id);
1103
1104         return resource ? resource->name : NULL;
1105 }
1106
1107 void *
1108 syscommon_resman_get_resource_privdata(int resource_id)
1109 {
1110         struct syscommon_resman_resource *resource = find_resource(resource_id);
1111
1112         return resource ? resource->priv : NULL;
1113 }
1114
1115 int
1116 syscommon_resman_get_resource_type(int resource_id)
1117 {
1118         struct syscommon_resman_resource *resource = find_resource(resource_id);
1119
1120         return resource ? resource->type : -EINVAL;
1121 }
1122
1123 int
1124 syscommon_resman_set_resource_privdata(int resource_id, void *priv)
1125 {
1126         struct syscommon_resman_resource *resource = find_resource(resource_id);
1127
1128         if (!resource)
1129                 return -EINVAL;
1130
1131         resource->priv = priv;
1132
1133         return 0;
1134 }
1135
1136 static void init_resource_driver(gpointer data, gpointer udata)
1137 {
1138         struct syscommon_resman_resource_driver *driver = (struct syscommon_resman_resource_driver *) data;
1139         int ret = 0;
1140
1141         if (driver && driver->ops.init) {
1142                 ret = driver->ops.init();
1143                 if (ret < 0)
1144                         syscommon_resman_remove_resource_driver(driver);
1145         }
1146 }
1147
1148 static void exit_resource_driver(gpointer data, gpointer udata)
1149 {
1150         struct syscommon_resman_resource_driver *driver = (struct syscommon_resman_resource_driver *) data;
1151
1152         if (driver && driver->ops.exit)
1153                 driver->ops.exit();
1154 }
1155
1156 void syscommon_resman_init_resource_drivers(void)
1157 {
1158         g_list_foreach(g_resource_driver_head, init_resource_driver, NULL);
1159 }
1160
1161 void syscommon_resman_exit_resource_drivers(void)
1162 {
1163         g_list_foreach(g_resource_driver_head, exit_resource_driver, NULL);
1164 }