Check errors aggressively
[platform/core/system/stability-monitor.git] / src / config.c
1 /*
2  * This file is part of stability-monitor
3  * 
4  * Copyright © 2019 Samsung Electronics
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <json-c/json.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <dirent.h>
23 #include <sys/stat.h>
24 #include <limits.h>
25
26 #include "log.h"
27 #include "process.h"
28 #include "utils.h"
29 #include "data_source.h"
30 #include "config.h"
31
32 static struct json_object *config = NULL;
33
34
35 int config_is_empty(void) {
36     return config == NULL;
37 }
38
39 struct json_object *config_get(void)
40 {
41     return config;
42 }
43
44 int config_load(const char *config_file)
45 {
46     config = json_object_from_file(config_file);
47     if (!config)
48         return -EINVAL;
49
50     _D("Loaded config %s\n", config_file);
51
52     return 0;
53 }
54
55 static int config_load_merge(const char *config_file)
56 {
57     struct json_object *obj;
58     int ret;
59
60     obj = json_object_from_file(config_file);
61     if (!obj) {
62         _E("Unable to parse config %s", config_file);
63         return -EINVAL;
64     }
65
66     json_object_object_foreach(obj, key, val) {
67         ret = _json_object_object_merge(config, key, val);
68         if (ret) {
69             json_object_put(obj);
70             return ret;
71         }
72     }
73
74     _D("Loaded config %s\n", config_file);
75
76     return 0;
77 }
78
79 static int is_regular_file(const char *path)
80 {
81     struct stat st;
82
83     if (stat(path, &st) < 0)
84       return 0;
85
86     return S_ISREG(st.st_mode);
87 }
88
89 int config_load_dir(const char *config_dir)
90 {
91     int n;
92     struct dirent **filelist;
93     char full_path[PATH_MAX];
94
95     n = scandir(config_dir, &filelist, NULL, alphasort);
96     if (n < 0) {
97         _W("Unable to load user config from %s: %m", config_dir);
98         return n;
99     }
100
101     for (int i = 0; i < n; i++) {
102         if (snprintf(full_path, PATH_MAX, "%s/%s", config_dir, filelist[i]->d_name) == -1)
103             _W("Unable to format dir path: %m");
104         else if (is_regular_file(full_path))
105             config_load_merge(full_path);
106
107         free(filelist[i]);
108     }
109
110     free(filelist);
111     return 0;
112 }
113
114 void config_print(void)
115 {
116     _D("Config tree:\n\n%s\n",
117         json_object_to_json_string_ext(config, JSON_C_TO_STRING_PRETTY));
118 }
119
120 static void _read_params(json_object *obj, struct proc_info *process)
121 {
122     struct data_source *ds;
123
124     json_object_object_foreach(obj, key, val) {
125         if (strcmp(key, "monitor") == 0) {
126             process->monitor = json_object_get_int(val) ? 1 : 0;
127             continue;
128         }
129
130         if (strcmp(key, "kill") == 0) {
131             process->kill = json_object_get_int(val) ? 1 : 0;
132             continue;
133         }
134
135         if (strcmp(key, "report") == 0) {
136             process->report = json_object_get_int(val) ? 1 : 0;
137             continue;
138         }
139
140         if (strcmp(key, "print_current") == 0) {
141             process->print_current = json_object_get_int(val) ? 1 : 0;
142             continue;
143         }
144
145         if (strcmp(key, "sampling_rate") == 0) {
146             process->sampling_rate = json_object_get_double(val);
147             continue;
148         }
149
150         if (strcmp(key, "apply_to_children") == 0) {
151             process->apply_to_children = json_object_get_int(val) ? 1 : 0;
152             continue;
153         }
154
155         for (int i = 0; i < data_sources_get_n(); i++) {
156             ds = &(process->data_sources[i]);
157             if (ds->apply_config(ds, key, val) == 0)
158                 break;
159         }
160     }
161 }
162
163 int config_read_per_process(struct proc_info *process)
164 {
165     const char *class_str = process_class_to_string(process->class);
166     struct json_object *obj;
167
168     if (!config) {
169         _E("There is no config");
170         return -EINVAL;
171     }
172
173     /* Global */
174     if (!json_object_object_get_ex(config, "global", &obj))
175         _E("There is no 'global' section in config");
176     else
177         _read_params(obj, process);
178
179     /* Class related config */
180     if (!json_object_object_get_ex(config, class_str, &obj))
181         _W("There is no '%s' section in config", class_str);
182     else
183         _read_params(obj, process);
184
185     /* Process by name */
186     if (json_object_object_get_ex(config, process->name, &obj)) {
187         _read_params(obj, process);
188     }
189
190     return 0;
191 }