4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
27 #include "config-parser.h"
28 #include "proc-common.h"
30 #define MAX_SECTION 64
31 #define CPU_INIT_PRIO 100
33 static GSList *app_conf_info_list;
34 static GSList *service_conf_info_list;
36 static struct proc_conf_info* process_exist(const char *name, enum proc_type proc_type)
40 struct proc_conf_info *pci = NULL;
42 if (proc_type != APP_TYPE && proc_type != SERVICE_TYPE)
45 gslist_for_each_item(iter,
46 proc_type == APP_TYPE ? app_conf_info_list : service_conf_info_list) {
47 pci = (struct proc_conf_info *)iter->data;
48 if (!strncmp(pci->name, name, strlen(name)+1)) {
60 static int vendor_config(struct parse_result *result, void *user_data)
62 int *config_type = (int *)user_data;
63 static struct proc_conf_info *pci = NULL;
65 if (!result || !user_data)
66 return RESOURCED_ERROR_INVALID_PARAMETER;
68 if (strncmp(result->section, PER_PROCESS_SECTION_CONF, strlen(PER_PROCESS_SECTION_CONF)+1))
69 return RESOURCED_ERROR_NONE;
71 if (!strncmp(result->name, SERVICE_NAME_CONF, strlen(SERVICE_NAME_CONF)+1) ||
72 !strncmp(result->name, APP_NAME_CONF, strlen(APP_NAME_CONF)+1)) {
73 pci = process_exist(result->value, result->name[0] == 'A' ? APP_TYPE : SERVICE_TYPE);
75 pci = (struct proc_conf_info *)calloc(1, sizeof(struct proc_conf_info));
77 _E("Failed to allocate memory during parsing vendor configurations");
78 return RESOURCED_ERROR_OUT_OF_MEMORY;
80 if (result->name[0] == 'A') {
81 pci->proc_type = APP_TYPE;
82 app_conf_info_list = g_slist_prepend(app_conf_info_list, (gpointer)pci);
85 pci->proc_type = SERVICE_TYPE;
86 service_conf_info_list = g_slist_prepend(service_conf_info_list, (gpointer)pci);
88 pci->mem_type = CGROUP_TOP;
89 pci->cpu_type = CGROUP_TOP;
90 pci->cpu_priority = CPU_INIT_PRIO;
91 strncpy(pci->name, result->value, sizeof(pci->name)-1);
94 else if (!strncmp(result->name, CPU_CGROUP_NAME_CONF, strlen(CPU_CGROUP_NAME_CONF)+1) &&
95 *config_type == LIMITER_CONFIG) {
97 _E("process configuration information pointer should not be NULL");
98 return RESOURCED_ERROR_FAIL;
101 if (!strncmp(result->value, CGROUP_VIP_VALUE_CONF,
102 strlen(CGROUP_VIP_VALUE_CONF) +1)) {
103 pci->cpu_type = CGROUP_VIP;
105 else if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF,
106 strlen(CGROUP_HIGH_VALUE_CONF) +1)) {
107 pci->cpu_type = CGROUP_HIGH;
109 else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF,
110 strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) {
111 pci->cpu_type = CGROUP_MEDIUM;
113 else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF,
114 strlen(CGROUP_LOW_VALUE_CONF) +1)) {
115 pci->cpu_type = CGROUP_LOW;
118 _E("invalid parameter (%s)", result->value);
119 return RESOURCED_ERROR_INVALID_PARAMETER;
122 else if (!strncmp(result->name, MEM_CGROUP_NAME_CONF, strlen(MEM_CGROUP_NAME_CONF)+1) &&
123 *config_type == LIMITER_CONFIG) {
125 _E("process configuration information pointer should not be NULL");
126 return RESOURCED_ERROR_FAIL;
129 if (!strncmp(result->value, CGROUP_VIP_VALUE_CONF,
130 strlen(CGROUP_VIP_VALUE_CONF) +1)) {
131 pci->mem_type = CGROUP_VIP;
133 else if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF,
134 strlen(CGROUP_HIGH_VALUE_CONF) +1)) {
135 pci->mem_type = CGROUP_HIGH;
137 else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF,
138 strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) {
139 pci->mem_type = CGROUP_MEDIUM;
141 else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF,
142 strlen(CGROUP_LOW_VALUE_CONF) +1)) {
143 pci->mem_type = CGROUP_LOW;
146 _E("invalid parameter (%s)", result->value);
147 return RESOURCED_ERROR_INVALID_PARAMETER;
150 else if (!strncmp(result->name, MEM_LIMIT_ACTION_NAME_CONF,
151 strlen(MEM_LIMIT_ACTION_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
153 _E("process configuration information pointer should not be NULL");
154 return RESOURCED_ERROR_FAIL;
157 char *ptr = strchr(result->value, ',');
159 _E("Cannot find ',' in the string (%s)", result->value);
160 return RESOURCED_ERROR_FAIL;
163 char *second_value = ptr + 1;
166 if (result->value > (ptr - 2)) {
167 _E("Size of string should be larger than 2");
168 return RESOURCED_ERROR_FAIL;
171 if (*(ptr - 1) == 'B') {
176 pci->mem_action.memory = GBYTE_TO_MBYTE(atoi(result->value));
178 else if (temp == 'M') {
179 pci->mem_action.memory = atoi(result->value);
181 else if (temp == 'K') {
182 pci->mem_action.memory = KBYTE_TO_MBYTE(atoi(result->value));
184 else if (temp == ' ') {
185 pci->mem_action.memory = BYTE_TO_MBYTE(atoi(result->value));
188 _E("Memory size unit should be GB or MB or KB or B");
189 return RESOURCED_ERROR_FAIL;
192 if (!strncmp(second_value, ACTION_BROADCAST_VALUE_CONF,
193 strlen(ACTION_BROADCAST_VALUE_CONF)+1))
194 pci->mem_action.action = PROC_ACTION_BROADCAST;
195 else if (!strncmp(second_value, ACTION_RECLAIM_VALUE_CONF,
196 strlen(ACTION_RECLAIM_VALUE_CONF)+1))
197 pci->mem_action.action = PROC_ACTION_RECLAIM;
198 else if (!strncmp(second_value, ACTION_KILL_VALUE_CONF,
199 strlen(ACTION_KILL_VALUE_CONF)+1))
200 pci->mem_action.action = PROC_ACTION_KILL;
202 _E("action (%s) is not supported", second_value);
203 return RESOURCED_ERROR_FAIL;
207 _E("Memory size unit should be XB");
208 return RESOURCED_ERROR_FAIL;
211 else if (!strncmp(result->name, CPU_PRIORITY_NAME_CONF, strlen(CPU_PRIORITY_NAME_CONF)+1) &&
212 *config_type == LIMITER_CONFIG) {
214 _E("process configuration information pointer should not be NULL");
215 return RESOURCED_ERROR_FAIL;
217 pci->cpu_priority = atoi(result->value);
219 else if (!strncmp(result->name, ACTION_ON_FAILURE_NAME_CONF,
220 strlen(ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
222 _E("process configuration information pointer should not be NULL");
223 return RESOURCED_ERROR_FAIL;
226 if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF,
227 strlen(ACTION_REBOOT_VALUE_CONF) +1)) {
228 pci->fail_action = PROC_ACTION_REBOOT;
231 _E("invalid parameter (%s)", result->value);
232 return RESOURCED_ERROR_INVALID_PARAMETER;
235 else if (!strncmp(result->name, WATCHDOG_ACTION_NAME_CONF,
236 strlen(WATCHDOG_ACTION_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
238 _E("process configuration information pointer should not be NULL");
239 return RESOURCED_ERROR_FAIL;
242 if (!strncmp(result->value, ACTION_IGNORE_VALUE_CONF,
243 strlen(ACTION_IGNORE_VALUE_CONF) +1)) {
244 pci->watchdog_action = PROC_ACTION_IGNORE;
246 else if (!strncmp(result->value, ACTION_KILL_VALUE_CONF,
247 strlen(ACTION_KILL_VALUE_CONF) +1)) {
248 pci->watchdog_action = PROC_ACTION_KILL;
251 _E("invalid parameter (%s)", result->value);
252 return RESOURCED_ERROR_INVALID_PARAMETER;
256 _E("Unknown configuration name (%s) and value (%s) on section (%s)",
257 result->name, result->value, result->section);
260 return RESOURCED_ERROR_NONE;
263 static void load_per_vendor_configs(const char *dir, int func(struct parse_result *result,
264 void *user_data), void *user_data)
268 struct dirent **namelist;
270 if ((count = scandir(dir, &namelist, NULL, alphasort)) == -1) {
271 _W("failed to opendir (%s)", dir);
275 for (idx = 0; idx < count; idx++) {
276 char path[PATH_MAX] = {0, };
278 if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX))
281 snprintf(path, sizeof(path), "%s/%s", dir, namelist[idx]->d_name);
282 config_parse(path, func, user_data);
289 void resourced_parse_vendor_configs(void)
293 config_type = LIMITER_CONFIG;
294 load_per_vendor_configs(CGROUP_VIP_LIST_DIR, vendor_config, &config_type);
296 config_type = PROCESS_CONFIG;
297 load_per_vendor_configs(PROC_CONF_DIR, vendor_config, &config_type);
301 gslist_for_each_item(iter, service_conf_info_list) {
302 struct proc_conf_info *pci = (struct proc_conf_info *)iter->data;
303 _I("[CONFIG] name: %s", pci->name);
304 _I("[CONFIG] mem cgroup: %d", pci->mem_type);
305 _I("[CONFIG] cpu cgroup: %d", pci->cpu_type);
306 _I("[CONFIG] cpu priority: %d", pci->cpu_priority);
307 _I("[CONFIG] watchdog_flag: %x", pci->watchdog_action);
308 _I("[CONFIG] fail_flag: %x", pci->fail_action);
309 _I("[CONFIG] memory: %lu MB", pci->mem_action.memory);
310 _I("[CONFIG] action: %d", pci->mem_action.action);
313 gslist_for_each_item(iter, app_conf_info_list) {
314 struct proc_conf_info *pci = (struct proc_conf_info *)iter->data;
315 _I("[CONFIG] name: %s", pci->name);
316 _I("[CONFIG] mem cgroup: %d", pci->mem_type);
317 _I("[CONFIG] cpu cgroup: %d", pci->cpu_type);
318 _I("[CONFIG] cpu priority: %d", pci->cpu_priority);
319 _I("[CONFIG] watchdog_flag: %x", pci->watchdog_action);
320 _I("[CONFIG] fail_flag: %x", pci->fail_action);
321 _I("[CONFIG] memory: %lu MB", pci->mem_action.memory);
322 _I("[CONFIG] action: %d", pci->mem_action.action);
326 int config_parse(const char *file_name, int cb(struct parse_result *result,
327 void *user_data), void *user_data)
330 struct parse_result result;
331 /* use stack for parsing */
333 char section[MAX_SECTION];
334 char *start, *end, *name, *value;
335 int lineno = 0, ret = 0;
337 if (!file_name || !cb) {
343 f = fopen(file_name, "r");
345 _E("Failed to open file %s", file_name);
350 /* parsing line by line */
351 while (fgets(line, LINE_MAX, f) != NULL) {
356 start = strstrip(start);
358 if (*start == COMMENT) {
360 } else if (*start == '[') {
362 end = strchr(start, ']');
363 if (!end || *end != ']') {
369 strncpy(section, start + 1, sizeof(section)-1);
370 section[MAX_SECTION-1] = '\0';
372 /* parse name & value */
373 end = strchr(start, '=');
374 if (!end || *end != '=') {
379 name = strstrip(start);
380 value = strstrip(end + 1);
381 end = strchr(value, COMMENT);
382 if (end && *end == COMMENT) {
384 value = strstrip(value);
387 result.section = section;
389 result.value = value;
390 /* callback with parse result */
391 ret = cb(&result, user_data);
403 _E("Failed to read %s:%d!", file_name, lineno);
407 static int config_table_lookup(void *table,
410 ConfigParserCallback *func,
422 for (t = table; t->lvalue; t++) {
424 if (!streq(lvalue, t->lvalue))
427 if (!streq_ptr(section, t->section))
439 /* Run the user supplied parser for an assignment */
440 static int config_parse_table(const char *filename,
447 ConfigParserCallback cb = NULL;
457 r = config_table_lookup(table,
478 int config_parse_new(const char *filename, void *table)
480 _cleanup_fclose_ FILE *f = NULL;
481 char *sections[MAX_SECTION] = { 0 };
482 char *section = NULL, *n, *e, l[LINE_MAX];
484 int i, r, num_section = 0;
490 f = fopen(filename, "r");
492 const int saved_errno = errno;
493 _E("Failed to open file %s", filename); // can modify errno
498 _cleanup_free_ char *lvalue = NULL, *rvalue = NULL;
501 if (fgets(l, LINE_MAX, f) == NULL) {
505 _E("Failed to parse configuration file '%s': %m", filename);
513 if (strchr(COMMENTS NEWLINE, *l))
518 if (l[len-1] != ']') {
519 _E("Error: Invalid section header: %s", l);
524 n = strndup(l+1, len-2);
531 for (i = 0; i < num_section; i++) {
532 if (streq(n, sections[i])) {
533 section = sections[i];
544 sections[num_section] = n;
546 if (num_section > MAX_SECTION) {
547 _E("Error: max number of section reached: %d", num_section);
560 _D("Warning: config: no '=' character in line '%s'.", l);
564 lvalue = strndup(l, e-l);
581 r = config_parse_table(filename,
594 for (i = 0; i < num_section; i++)
601 int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data)
603 _cleanup_closedir_ DIR *d = NULL;
608 _E("Failed to open dir: %s", dir);
612 for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) {
617 } else if (streq(de->d_name, ".") || streq(de->d_name, "..")) {
621 _cleanup_free_ char *path = NULL;
624 if (de->d_type != DT_REG)
627 r = asprintf(&path, "%s/%s", dir, de->d_name);
632 /* Do not just break loop until parse all file of
633 * dir. Just only put log */
635 _D("Failed to parse config: %s", de->d_name);
641 int config_parse_bool(const char *filename,
657 k = parse_boolean(rvalue);
659 _E("Failed to parse boolean value, ignoring: %s", rvalue);
668 #define DEFINE_PARSER(type, vartype, conv_func) \
669 int config_parse_##type( \
670 const char *filename, \
672 const char *section, \
673 const char *lvalue, \
675 const char *rvalue, \
685 *i = conv_func(rvalue); \
689 DEFINE_PARSER(int, int, atoi)
690 DEFINE_PARSER(float, float, atof)
691 DEFINE_PARSER(long, long, atol)
693 int config_parse_string(const char *filename,
708 if (is_empty(rvalue))
722 int config_parse_bytes(const char *filename,
738 if (is_empty(rvalue))
741 r = parse_bytes(rvalue, s);
749 int config_parse_strv(const char *filename,
758 char **o = NULL, **v = NULL, **vv = NULL;
766 if (is_empty(rvalue))
769 r = str_to_strv(rvalue, &v, WHITESPACE);
775 r = strv_attach(o, v, &vv, true);