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